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 u_int ip_fragttl; 48 static uint64_t ip_tick; 49 50 static uint64_t ipstat_tick; 51 52 static int 53 fetch_ipstat(void) 54 { 55 size_t len; 56 57 len = sizeof(ipstat); 58 if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, NULL, 0) == -1) { 59 syslog(LOG_ERR, "net.inet.ip.stats: %m"); 60 return (-1); 61 } 62 if (len != sizeof(ipstat)) { 63 syslog(LOG_ERR, "net.inet.ip.stats: wrong size"); 64 return (-1); 65 } 66 len = sizeof(ip_idrop); 67 if (sysctlbyname("net.inet.ip.intr_queue_drops", &ip_idrop, &len, NULL, 0) == -1) 68 syslog(LOG_WARNING, "net.inet.ip.intr_queue_drops: %m"); 69 if (len != sizeof(ip_idrop)) { 70 syslog(LOG_WARNING, "net.inet.ip.intr_queue_drops: wrong size"); 71 ip_idrop = 0; 72 } 73 len = sizeof(icmpstat); 74 if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &len, NULL, 0) == -1) { 75 syslog(LOG_ERR, "net.inet.icmp.stats: %m"); 76 return (-1); 77 } 78 if (len != sizeof(icmpstat)) { 79 syslog(LOG_ERR, "net.inet.icmp.stats: wrong size"); 80 return (-1); 81 } 82 83 len = sizeof(ip_fragttl); 84 if (sysctlbyname("net.inet.ip.fragttl", &ip_fragttl, &len, 85 NULL, 0) == -1) { 86 syslog(LOG_ERR, "net.inet.ip.fragttl: %m"); 87 return (-1); 88 } 89 if (len != sizeof(ip_fragttl)) { 90 syslog(LOG_ERR, "net.inet.ip.fragttl: wrong size"); 91 return (-1); 92 } 93 94 ipstat_tick = get_ticks(); 95 return (0); 96 } 97 98 static int 99 fetch_ip(void) 100 { 101 size_t len; 102 103 len = sizeof(ip_forwarding); 104 if (sysctlbyname("net.inet.ip.forwarding", &ip_forwarding, &len, 105 NULL, 0) == -1) { 106 syslog(LOG_ERR, "net.inet.ip.forwarding: %m"); 107 return (-1); 108 } 109 if (len != sizeof(ip_forwarding)) { 110 syslog(LOG_ERR, "net.inet.ip.forwarding: wrong size"); 111 return (-1); 112 } 113 114 len = sizeof(ip_defttl); 115 if (sysctlbyname("net.inet.ip.ttl", &ip_defttl, &len, 116 NULL, 0) == -1) { 117 syslog(LOG_ERR, "net.inet.ip.ttl: %m"); 118 return (-1); 119 } 120 if (len != sizeof(ip_defttl)) { 121 syslog(LOG_ERR, "net.inet.ip.ttl: wrong size"); 122 return (-1); 123 } 124 125 ip_tick = get_ticks(); 126 return (0); 127 } 128 129 static int 130 ip_forward(int forw, int *old) 131 { 132 size_t olen; 133 134 olen = sizeof(*old); 135 if (sysctlbyname("net.inet.ip.forwarding", old, old ? &olen : NULL, 136 &forw, sizeof(forw)) == -1) { 137 syslog(LOG_ERR, "set net.inet.ip.forwarding: %m"); 138 return (-1); 139 } 140 ip_forwarding = forw; 141 return (0); 142 } 143 144 static int 145 ip_setttl(int ttl, int *old) 146 { 147 size_t olen; 148 149 olen = sizeof(*old); 150 if (sysctlbyname("net.inet.ip.ttl", old, old ? &olen : NULL, 151 &ttl, sizeof(ttl)) == -1) { 152 syslog(LOG_ERR, "set net.inet.ip.ttl: %m"); 153 return (-1); 154 } 155 ip_defttl = ttl; 156 return (0); 157 } 158 159 /* 160 * READ/WRITE ip group. 161 */ 162 int 163 op_ip(struct snmp_context *ctx, struct snmp_value *value, 164 u_int sub, u_int idx __unused, enum snmp_op op) 165 { 166 int old = 0; 167 168 switch (op) { 169 170 case SNMP_OP_GETNEXT: 171 abort(); 172 173 case SNMP_OP_GET: 174 break; 175 176 case SNMP_OP_SET: 177 if (ip_tick < this_tick) 178 if (fetch_ip() == -1) 179 return (SNMP_ERR_GENERR); 180 181 switch (value->var.subs[sub - 1]) { 182 183 case LEAF_ipForwarding: 184 ctx->scratch->int1 = ip_forwarding ? 1 : 2; 185 ctx->scratch->int2 = value->v.integer; 186 if (value->v.integer == 1) { 187 if (!ip_forwarding && ip_forward(1, &old)) 188 return (SNMP_ERR_GENERR); 189 ctx->scratch->int1 = old ? 1 : 2; 190 } else if (value->v.integer == 2) { 191 if (ip_forwarding && ip_forward(0, &old)) 192 return (SNMP_ERR_GENERR); 193 ctx->scratch->int1 = old; 194 } else 195 return (SNMP_ERR_WRONG_VALUE); 196 break; 197 198 case LEAF_ipDefaultTTL: 199 ctx->scratch->int1 = ip_defttl; 200 ctx->scratch->int2 = value->v.integer; 201 if (value->v.integer < 1 || value->v.integer > 255) 202 return (SNMP_ERR_WRONG_VALUE); 203 if (ip_defttl != value->v.integer && 204 ip_setttl(value->v.integer, &old)) 205 return (SNMP_ERR_GENERR); 206 ctx->scratch->int1 = old; 207 break; 208 } 209 return (SNMP_ERR_NOERROR); 210 211 case SNMP_OP_ROLLBACK: 212 switch (value->var.subs[sub - 1]) { 213 214 case LEAF_ipForwarding: 215 if (ctx->scratch->int1 == 1) { 216 if (ctx->scratch->int2 == 2) 217 (void)ip_forward(1, NULL); 218 } else { 219 if (ctx->scratch->int2 == 1) 220 (void)ip_forward(0, NULL); 221 } 222 break; 223 224 case LEAF_ipDefaultTTL: 225 if (ctx->scratch->int1 != ctx->scratch->int2) 226 (void)ip_setttl(ctx->scratch->int1, NULL); 227 break; 228 } 229 return (SNMP_ERR_NOERROR); 230 231 case SNMP_OP_COMMIT: 232 return (SNMP_ERR_NOERROR); 233 } 234 235 if (ip_tick < this_tick) 236 if (fetch_ip() == -1) 237 return (SNMP_ERR_GENERR); 238 239 switch (value->var.subs[sub - 1]) { 240 241 case LEAF_ipForwarding: 242 value->v.integer = ip_forwarding ? 1 : 2; 243 break; 244 245 case LEAF_ipDefaultTTL: 246 value->v.integer = ip_defttl; 247 break; 248 } 249 return (SNMP_ERR_NOERROR); 250 } 251 252 /* 253 * READ-ONLY statistics ip group. 254 */ 255 int 256 op_ipstat(struct snmp_context *ctx __unused, struct snmp_value *value, 257 u_int sub, u_int idx __unused, enum snmp_op op) 258 { 259 switch (op) { 260 261 case SNMP_OP_GETNEXT: 262 abort(); 263 264 case SNMP_OP_GET: 265 break; 266 267 case SNMP_OP_SET: 268 return (SNMP_ERR_NOT_WRITEABLE); 269 270 case SNMP_OP_ROLLBACK: 271 case SNMP_OP_COMMIT: 272 abort(); 273 } 274 275 if (ipstat_tick < this_tick) 276 fetch_ipstat(); 277 278 switch (value->var.subs[sub - 1]) { 279 280 case LEAF_ipInReceives: 281 value->v.uint32 = ipstat.ips_total; 282 break; 283 284 case LEAF_ipInHdrErrors: 285 value->v.uint32 = ipstat.ips_badsum + ipstat.ips_tooshort 286 + ipstat.ips_toosmall + ipstat.ips_badhlen 287 + ipstat.ips_badlen + ipstat.ips_badvers + 288 + ipstat.ips_toolong; 289 break; 290 291 case LEAF_ipInAddrErrors: 292 value->v.uint32 = ipstat.ips_cantforward; 293 break; 294 295 case LEAF_ipForwDatagrams: 296 value->v.uint32 = ipstat.ips_forward; 297 break; 298 299 case LEAF_ipInUnknownProtos: 300 value->v.uint32 = ipstat.ips_noproto; 301 break; 302 303 case LEAF_ipInDiscards: 304 value->v.uint32 = ip_idrop; 305 break; 306 307 case LEAF_ipInDelivers: 308 value->v.uint32 = ipstat.ips_delivered; 309 break; 310 311 case LEAF_ipOutRequests: 312 value->v.uint32 = ipstat.ips_localout; 313 break; 314 315 case LEAF_ipOutDiscards: 316 value->v.uint32 = ipstat.ips_odropped; 317 break; 318 319 case LEAF_ipOutNoRoutes: 320 value->v.uint32 = ipstat.ips_noroute; 321 break; 322 323 case LEAF_ipReasmTimeout: 324 value->v.integer = ip_fragttl; 325 break; 326 327 case LEAF_ipReasmReqds: 328 value->v.uint32 = ipstat.ips_fragments; 329 break; 330 331 case LEAF_ipReasmOKs: 332 value->v.uint32 = ipstat.ips_reassembled; 333 break; 334 335 case LEAF_ipReasmFails: 336 value->v.uint32 = ipstat.ips_fragdropped 337 + ipstat.ips_fragtimeout; 338 break; 339 340 case LEAF_ipFragOKs: 341 value->v.uint32 = ipstat.ips_fragmented; 342 break; 343 344 case LEAF_ipFragFails: 345 value->v.uint32 = ipstat.ips_cantfrag; 346 break; 347 348 case LEAF_ipFragCreates: 349 value->v.uint32 = ipstat.ips_ofragments; 350 break; 351 } 352 return (SNMP_ERR_NOERROR); 353 } 354 355 /* 356 * READ-ONLY statistics icmp group. 357 */ 358 int 359 op_icmpstat(struct snmp_context *ctx __unused, struct snmp_value *value, 360 u_int sub, u_int idx __unused, enum snmp_op op) 361 { 362 u_int i; 363 364 switch (op) { 365 366 case SNMP_OP_GETNEXT: 367 abort(); 368 369 case SNMP_OP_GET: 370 break; 371 372 case SNMP_OP_SET: 373 return (SNMP_ERR_NOT_WRITEABLE); 374 375 case SNMP_OP_ROLLBACK: 376 case SNMP_OP_COMMIT: 377 abort(); 378 } 379 380 if (ipstat_tick < this_tick) 381 fetch_ipstat(); 382 383 switch (value->var.subs[sub - 1]) { 384 385 case LEAF_icmpInMsgs: 386 value->v.integer = 0; 387 for (i = 0; i <= ICMP_MAXTYPE; i++) 388 value->v.integer += icmpstat.icps_inhist[i]; 389 value->v.integer += icmpstat.icps_tooshort + 390 icmpstat.icps_checksum; 391 /* missing: bad type and packets on faith */ 392 break; 393 394 case LEAF_icmpInErrors: 395 value->v.integer = icmpstat.icps_tooshort + 396 icmpstat.icps_checksum + 397 icmpstat.icps_badlen + 398 icmpstat.icps_badcode + 399 icmpstat.icps_bmcastecho + 400 icmpstat.icps_bmcasttstamp; 401 break; 402 403 case LEAF_icmpInDestUnreachs: 404 value->v.integer = icmpstat.icps_inhist[ICMP_UNREACH]; 405 break; 406 407 case LEAF_icmpInTimeExcds: 408 value->v.integer = icmpstat.icps_inhist[ICMP_TIMXCEED]; 409 break; 410 411 case LEAF_icmpInParmProbs: 412 value->v.integer = icmpstat.icps_inhist[ICMP_PARAMPROB]; 413 break; 414 415 case LEAF_icmpInSrcQuenchs: 416 value->v.integer = icmpstat.icps_inhist[ICMP_SOURCEQUENCH]; 417 break; 418 419 case LEAF_icmpInRedirects: 420 value->v.integer = icmpstat.icps_inhist[ICMP_REDIRECT]; 421 break; 422 423 case LEAF_icmpInEchos: 424 value->v.integer = icmpstat.icps_inhist[ICMP_ECHO]; 425 break; 426 427 case LEAF_icmpInEchoReps: 428 value->v.integer = icmpstat.icps_inhist[ICMP_ECHOREPLY]; 429 break; 430 431 case LEAF_icmpInTimestamps: 432 value->v.integer = icmpstat.icps_inhist[ICMP_TSTAMP]; 433 break; 434 435 case LEAF_icmpInTimestampReps: 436 value->v.integer = icmpstat.icps_inhist[ICMP_TSTAMPREPLY]; 437 break; 438 439 case LEAF_icmpInAddrMasks: 440 value->v.integer = icmpstat.icps_inhist[ICMP_MASKREQ]; 441 break; 442 443 case LEAF_icmpInAddrMaskReps: 444 value->v.integer = icmpstat.icps_inhist[ICMP_MASKREPLY]; 445 break; 446 447 case LEAF_icmpOutMsgs: 448 value->v.integer = 0; 449 for (i = 0; i <= ICMP_MAXTYPE; i++) 450 value->v.integer += icmpstat.icps_outhist[i]; 451 value->v.integer += icmpstat.icps_badaddr + 452 icmpstat.icps_noroute; 453 break; 454 455 case LEAF_icmpOutErrors: 456 value->v.integer = icmpstat.icps_badaddr + 457 icmpstat.icps_noroute; 458 break; 459 460 case LEAF_icmpOutDestUnreachs: 461 value->v.integer = icmpstat.icps_outhist[ICMP_UNREACH]; 462 break; 463 464 case LEAF_icmpOutTimeExcds: 465 value->v.integer = icmpstat.icps_outhist[ICMP_TIMXCEED]; 466 break; 467 468 case LEAF_icmpOutParmProbs: 469 value->v.integer = icmpstat.icps_outhist[ICMP_PARAMPROB]; 470 break; 471 472 case LEAF_icmpOutSrcQuenchs: 473 value->v.integer = icmpstat.icps_outhist[ICMP_SOURCEQUENCH]; 474 break; 475 476 case LEAF_icmpOutRedirects: 477 value->v.integer = icmpstat.icps_outhist[ICMP_REDIRECT]; 478 break; 479 480 case LEAF_icmpOutEchos: 481 value->v.integer = icmpstat.icps_outhist[ICMP_ECHO]; 482 break; 483 484 case LEAF_icmpOutEchoReps: 485 value->v.integer = icmpstat.icps_outhist[ICMP_ECHOREPLY]; 486 break; 487 488 case LEAF_icmpOutTimestamps: 489 value->v.integer = icmpstat.icps_outhist[ICMP_TSTAMP]; 490 break; 491 492 case LEAF_icmpOutTimestampReps: 493 value->v.integer = icmpstat.icps_outhist[ICMP_TSTAMPREPLY]; 494 break; 495 496 case LEAF_icmpOutAddrMasks: 497 value->v.integer = icmpstat.icps_outhist[ICMP_MASKREQ]; 498 break; 499 500 case LEAF_icmpOutAddrMaskReps: 501 value->v.integer = icmpstat.icps_outhist[ICMP_MASKREPLY]; 502 break; 503 } 504 return (SNMP_ERR_NOERROR); 505 } 506