1 /* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $Begemot: bsnmp/snmp_mibII/mibII_ip.c,v 1.11 2005/05/23 09:03:40 brandt_h Exp $ 30 * 31 * ip group scalars. 32 */ 33 #include "mibII.h" 34 #include "mibII_oid.h" 35 #include <netinet/in_systm.h> 36 #include <netinet/ip.h> 37 #include <netinet/ip_var.h> 38 #include <netinet/ip_icmp.h> 39 #include <netinet/icmp_var.h> 40 41 static struct ipstat ipstat; 42 static u_int ip_idrop; 43 static struct icmpstat icmpstat; 44 45 static int ip_forwarding; 46 static int ip_defttl; 47 static uint64_t ip_tick; 48 49 static uint64_t ipstat_tick; 50 51 static int 52 fetch_ipstat(void) 53 { 54 size_t len; 55 56 len = sizeof(ipstat); 57 if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, NULL, 0) == -1) { 58 syslog(LOG_ERR, "net.inet.ip.stats: %m"); 59 return (-1); 60 } 61 if (len != sizeof(ipstat)) { 62 syslog(LOG_ERR, "net.inet.ip.stats: wrong size"); 63 return (-1); 64 } 65 len = sizeof(ip_idrop); 66 if (sysctlbyname("net.inet.ip.intr_queue_drops", &ip_idrop, &len, NULL, 0) == -1) 67 syslog(LOG_WARNING, "net.inet.ip.intr_queue_drops: %m"); 68 if (len != sizeof(ip_idrop)) { 69 syslog(LOG_WARNING, "net.inet.ip.intr_queue_drops: wrong size"); 70 ip_idrop = 0; 71 } 72 len = sizeof(icmpstat); 73 if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &len, NULL, 0) == -1) { 74 syslog(LOG_ERR, "net.inet.icmp.stats: %m"); 75 return (-1); 76 } 77 if (len != sizeof(icmpstat)) { 78 syslog(LOG_ERR, "net.inet.icmp.stats: wrong size"); 79 return (-1); 80 } 81 82 ipstat_tick = get_ticks(); 83 return (0); 84 } 85 86 static int 87 fetch_ip(void) 88 { 89 size_t len; 90 91 len = sizeof(ip_forwarding); 92 if (sysctlbyname("net.inet.ip.forwarding", &ip_forwarding, &len, 93 NULL, 0) == -1) { 94 syslog(LOG_ERR, "net.inet.ip.forwarding: %m"); 95 return (-1); 96 } 97 if (len != sizeof(ip_forwarding)) { 98 syslog(LOG_ERR, "net.inet.ip.forwarding: wrong size"); 99 return (-1); 100 } 101 102 len = sizeof(ip_defttl); 103 if (sysctlbyname("net.inet.ip.ttl", &ip_defttl, &len, 104 NULL, 0) == -1) { 105 syslog(LOG_ERR, "net.inet.ip.ttl: %m"); 106 return (-1); 107 } 108 if (len != sizeof(ip_defttl)) { 109 syslog(LOG_ERR, "net.inet.ip.ttl: wrong size"); 110 return (-1); 111 } 112 113 ip_tick = get_ticks(); 114 return (0); 115 } 116 117 static int 118 ip_forward(int forw, int *old) 119 { 120 size_t olen; 121 122 olen = sizeof(*old); 123 if (sysctlbyname("net.inet.ip.forwarding", old, old ? &olen : NULL, 124 &forw, sizeof(forw)) == -1) { 125 syslog(LOG_ERR, "set net.inet.ip.forwarding: %m"); 126 return (-1); 127 } 128 ip_forwarding = forw; 129 return (0); 130 } 131 132 static int 133 ip_setttl(int ttl, int *old) 134 { 135 size_t olen; 136 137 olen = sizeof(*old); 138 if (sysctlbyname("net.inet.ip.ttl", old, old ? &olen : NULL, 139 &ttl, sizeof(ttl)) == -1) { 140 syslog(LOG_ERR, "set net.inet.ip.ttl: %m"); 141 return (-1); 142 } 143 ip_defttl = ttl; 144 return (0); 145 } 146 147 /* 148 * READ/WRITE ip group. 149 */ 150 int 151 op_ip(struct snmp_context *ctx, struct snmp_value *value, 152 u_int sub, u_int idx __unused, enum snmp_op op) 153 { 154 int old = 0; 155 156 switch (op) { 157 158 case SNMP_OP_GETNEXT: 159 abort(); 160 161 case SNMP_OP_GET: 162 break; 163 164 case SNMP_OP_SET: 165 if (ip_tick < this_tick) 166 if (fetch_ip() == -1) 167 return (SNMP_ERR_GENERR); 168 169 switch (value->var.subs[sub - 1]) { 170 171 case LEAF_ipForwarding: 172 ctx->scratch->int1 = ip_forwarding ? 1 : 2; 173 ctx->scratch->int2 = value->v.integer; 174 if (value->v.integer == 1) { 175 if (!ip_forwarding && ip_forward(1, &old)) 176 return (SNMP_ERR_GENERR); 177 ctx->scratch->int1 = old ? 1 : 2; 178 } else if (value->v.integer == 2) { 179 if (ip_forwarding && ip_forward(0, &old)) 180 return (SNMP_ERR_GENERR); 181 ctx->scratch->int1 = old; 182 } else 183 return (SNMP_ERR_WRONG_VALUE); 184 break; 185 186 case LEAF_ipDefaultTTL: 187 ctx->scratch->int1 = ip_defttl; 188 ctx->scratch->int2 = value->v.integer; 189 if (value->v.integer < 1 || value->v.integer > 255) 190 return (SNMP_ERR_WRONG_VALUE); 191 if (ip_defttl != value->v.integer && 192 ip_setttl(value->v.integer, &old)) 193 return (SNMP_ERR_GENERR); 194 ctx->scratch->int1 = old; 195 break; 196 } 197 return (SNMP_ERR_NOERROR); 198 199 case SNMP_OP_ROLLBACK: 200 switch (value->var.subs[sub - 1]) { 201 202 case LEAF_ipForwarding: 203 if (ctx->scratch->int1 == 1) { 204 if (ctx->scratch->int2 == 2) 205 (void)ip_forward(1, NULL); 206 } else { 207 if (ctx->scratch->int2 == 1) 208 (void)ip_forward(0, NULL); 209 } 210 break; 211 212 case LEAF_ipDefaultTTL: 213 if (ctx->scratch->int1 != ctx->scratch->int2) 214 (void)ip_setttl(ctx->scratch->int1, NULL); 215 break; 216 } 217 return (SNMP_ERR_NOERROR); 218 219 case SNMP_OP_COMMIT: 220 return (SNMP_ERR_NOERROR); 221 } 222 223 if (ip_tick < this_tick) 224 if (fetch_ip() == -1) 225 return (SNMP_ERR_GENERR); 226 227 switch (value->var.subs[sub - 1]) { 228 229 case LEAF_ipForwarding: 230 value->v.integer = ip_forwarding ? 1 : 2; 231 break; 232 233 case LEAF_ipDefaultTTL: 234 value->v.integer = ip_defttl; 235 break; 236 } 237 return (SNMP_ERR_NOERROR); 238 } 239 240 /* 241 * READ-ONLY statistics ip group. 242 */ 243 int 244 op_ipstat(struct snmp_context *ctx __unused, struct snmp_value *value, 245 u_int sub, u_int idx __unused, enum snmp_op op) 246 { 247 switch (op) { 248 249 case SNMP_OP_GETNEXT: 250 abort(); 251 252 case SNMP_OP_GET: 253 break; 254 255 case SNMP_OP_SET: 256 return (SNMP_ERR_NOT_WRITEABLE); 257 258 case SNMP_OP_ROLLBACK: 259 case SNMP_OP_COMMIT: 260 abort(); 261 } 262 263 if (ipstat_tick < this_tick) 264 fetch_ipstat(); 265 266 switch (value->var.subs[sub - 1]) { 267 268 case LEAF_ipInReceives: 269 value->v.uint32 = ipstat.ips_total; 270 break; 271 272 case LEAF_ipInHdrErrors: 273 value->v.uint32 = ipstat.ips_badsum + ipstat.ips_tooshort 274 + ipstat.ips_toosmall + ipstat.ips_badhlen 275 + ipstat.ips_badlen + ipstat.ips_badvers + 276 + ipstat.ips_toolong; 277 break; 278 279 case LEAF_ipInAddrErrors: 280 value->v.uint32 = ipstat.ips_cantforward; 281 break; 282 283 case LEAF_ipForwDatagrams: 284 value->v.uint32 = ipstat.ips_forward; 285 break; 286 287 case LEAF_ipInUnknownProtos: 288 value->v.uint32 = ipstat.ips_noproto; 289 break; 290 291 case LEAF_ipInDiscards: 292 value->v.uint32 = ip_idrop; 293 break; 294 295 case LEAF_ipInDelivers: 296 value->v.uint32 = ipstat.ips_delivered; 297 break; 298 299 case LEAF_ipOutRequests: 300 value->v.uint32 = ipstat.ips_localout; 301 break; 302 303 case LEAF_ipOutDiscards: 304 value->v.uint32 = ipstat.ips_odropped; 305 break; 306 307 case LEAF_ipOutNoRoutes: 308 value->v.uint32 = ipstat.ips_noroute; 309 break; 310 311 case LEAF_ipReasmTimeout: 312 value->v.integer = IPFRAGTTL; 313 break; 314 315 case LEAF_ipReasmReqds: 316 value->v.uint32 = ipstat.ips_fragments; 317 break; 318 319 case LEAF_ipReasmOKs: 320 value->v.uint32 = ipstat.ips_reassembled; 321 break; 322 323 case LEAF_ipReasmFails: 324 value->v.uint32 = ipstat.ips_fragdropped 325 + ipstat.ips_fragtimeout; 326 break; 327 328 case LEAF_ipFragOKs: 329 value->v.uint32 = ipstat.ips_fragmented; 330 break; 331 332 case LEAF_ipFragFails: 333 value->v.uint32 = ipstat.ips_cantfrag; 334 break; 335 336 case LEAF_ipFragCreates: 337 value->v.uint32 = ipstat.ips_ofragments; 338 break; 339 } 340 return (SNMP_ERR_NOERROR); 341 } 342 343 /* 344 * READ-ONLY statistics icmp group. 345 */ 346 int 347 op_icmpstat(struct snmp_context *ctx __unused, struct snmp_value *value, 348 u_int sub, u_int idx __unused, enum snmp_op op) 349 { 350 u_int i; 351 352 switch (op) { 353 354 case SNMP_OP_GETNEXT: 355 abort(); 356 357 case SNMP_OP_GET: 358 break; 359 360 case SNMP_OP_SET: 361 return (SNMP_ERR_NOT_WRITEABLE); 362 363 case SNMP_OP_ROLLBACK: 364 case SNMP_OP_COMMIT: 365 abort(); 366 } 367 368 if (ipstat_tick < this_tick) 369 fetch_ipstat(); 370 371 switch (value->var.subs[sub - 1]) { 372 373 case LEAF_icmpInMsgs: 374 value->v.integer = 0; 375 for (i = 0; i <= ICMP_MAXTYPE; i++) 376 value->v.integer += icmpstat.icps_inhist[i]; 377 value->v.integer += icmpstat.icps_tooshort + 378 icmpstat.icps_checksum; 379 /* missing: bad type and packets on faith */ 380 break; 381 382 case LEAF_icmpInErrors: 383 value->v.integer = icmpstat.icps_tooshort + 384 icmpstat.icps_checksum + 385 icmpstat.icps_badlen + 386 icmpstat.icps_badcode + 387 icmpstat.icps_bmcastecho + 388 icmpstat.icps_bmcasttstamp; 389 break; 390 391 case LEAF_icmpInDestUnreachs: 392 value->v.integer = icmpstat.icps_inhist[ICMP_UNREACH]; 393 break; 394 395 case LEAF_icmpInTimeExcds: 396 value->v.integer = icmpstat.icps_inhist[ICMP_TIMXCEED]; 397 break; 398 399 case LEAF_icmpInParmProbs: 400 value->v.integer = icmpstat.icps_inhist[ICMP_PARAMPROB]; 401 break; 402 403 case LEAF_icmpInSrcQuenchs: 404 value->v.integer = icmpstat.icps_inhist[ICMP_SOURCEQUENCH]; 405 break; 406 407 case LEAF_icmpInRedirects: 408 value->v.integer = icmpstat.icps_inhist[ICMP_REDIRECT]; 409 break; 410 411 case LEAF_icmpInEchos: 412 value->v.integer = icmpstat.icps_inhist[ICMP_ECHO]; 413 break; 414 415 case LEAF_icmpInEchoReps: 416 value->v.integer = icmpstat.icps_inhist[ICMP_ECHOREPLY]; 417 break; 418 419 case LEAF_icmpInTimestamps: 420 value->v.integer = icmpstat.icps_inhist[ICMP_TSTAMP]; 421 break; 422 423 case LEAF_icmpInTimestampReps: 424 value->v.integer = icmpstat.icps_inhist[ICMP_TSTAMPREPLY]; 425 break; 426 427 case LEAF_icmpInAddrMasks: 428 value->v.integer = icmpstat.icps_inhist[ICMP_MASKREQ]; 429 break; 430 431 case LEAF_icmpInAddrMaskReps: 432 value->v.integer = icmpstat.icps_inhist[ICMP_MASKREPLY]; 433 break; 434 435 case LEAF_icmpOutMsgs: 436 value->v.integer = 0; 437 for (i = 0; i <= ICMP_MAXTYPE; i++) 438 value->v.integer += icmpstat.icps_outhist[i]; 439 value->v.integer += icmpstat.icps_badaddr + 440 icmpstat.icps_noroute; 441 break; 442 443 case LEAF_icmpOutErrors: 444 value->v.integer = icmpstat.icps_badaddr + 445 icmpstat.icps_noroute; 446 break; 447 448 case LEAF_icmpOutDestUnreachs: 449 value->v.integer = icmpstat.icps_outhist[ICMP_UNREACH]; 450 break; 451 452 case LEAF_icmpOutTimeExcds: 453 value->v.integer = icmpstat.icps_outhist[ICMP_TIMXCEED]; 454 break; 455 456 case LEAF_icmpOutParmProbs: 457 value->v.integer = icmpstat.icps_outhist[ICMP_PARAMPROB]; 458 break; 459 460 case LEAF_icmpOutSrcQuenchs: 461 value->v.integer = icmpstat.icps_outhist[ICMP_SOURCEQUENCH]; 462 break; 463 464 case LEAF_icmpOutRedirects: 465 value->v.integer = icmpstat.icps_outhist[ICMP_REDIRECT]; 466 break; 467 468 case LEAF_icmpOutEchos: 469 value->v.integer = icmpstat.icps_outhist[ICMP_ECHO]; 470 break; 471 472 case LEAF_icmpOutEchoReps: 473 value->v.integer = icmpstat.icps_outhist[ICMP_ECHOREPLY]; 474 break; 475 476 case LEAF_icmpOutTimestamps: 477 value->v.integer = icmpstat.icps_outhist[ICMP_TSTAMP]; 478 break; 479 480 case LEAF_icmpOutTimestampReps: 481 value->v.integer = icmpstat.icps_outhist[ICMP_TSTAMPREPLY]; 482 break; 483 484 case LEAF_icmpOutAddrMasks: 485 value->v.integer = icmpstat.icps_outhist[ICMP_MASKREQ]; 486 break; 487 488 case LEAF_icmpOutAddrMaskReps: 489 value->v.integer = icmpstat.icps_outhist[ICMP_MASKREPLY]; 490 break; 491 } 492 return (SNMP_ERR_NOERROR); 493 } 494