00001 #include <net-snmp/net-snmp-config.h>
00002
00003 #ifdef SNMP_TRANSPORT_UDPIPV6_DOMAIN
00004
00005
00006
00007
00008 #if defined(cygwin)
00009 #undef HAVE_UNISTD_H
00010 #undef HAVE_NETINET_IN_H
00011 #undef HAVE_ARPA_INET_H
00012 #undef HAVE_NET_IF_H
00013 #undef HAVE_NETDB_H
00014 #undef HAVE_SYS_PARAM_H
00015 #undef HAVE_SYS_SELECT_H
00016 #undef HAVE_SYS_SOCKET_H
00017 #undef HAVE_IN_ADDR_T
00018 #endif
00019
00020 #include <stdio.h>
00021 #include <sys/types.h>
00022 #include <ctype.h>
00023 #include <errno.h>
00024
00025 #if HAVE_STRING_H
00026 #include <string.h>
00027 #else
00028 #include <strings.h>
00029 #endif
00030 #if HAVE_STDLIB_H
00031 #include <stdlib.h>
00032 #endif
00033 #if HAVE_UNISTD_H
00034 #include <unistd.h>
00035 #endif
00036 #if HAVE_SYS_SOCKET_H
00037 #include <sys/socket.h>
00038 #endif
00039
00040 #if defined(HAVE_WINSOCK_H) || defined(cygwin)
00041
00042
00043
00044 #include <winsock2.h>
00045 #include <ws2tcpip.h>
00046 #undef HAVE_IF_NAMETOINDEX
00047
00048 extern int inet_pton(int, const char*, void*);
00049 extern const char *inet_ntop(int, const void*, char*, size_t);
00050 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
00051 #endif
00052
00053 #if HAVE_NETINET_IN_H
00054 #include <netinet/in.h>
00055 #endif
00056 #if HAVE_ARPA_INET_H
00057 #include <arpa/inet.h>
00058 #endif
00059 #if HAVE_NETDB_H
00060 #include <netdb.h>
00061 #endif
00062 #if HAVE_NET_IF_H
00063 #include <net/if.h>
00064 #endif
00065
00066 #if HAVE_DMALLOC_H
00067 #include <dmalloc.h>
00068 #endif
00069
00070 #include <net-snmp/types.h>
00071 #include <net-snmp/output_api.h>
00072 #include <net-snmp/config_api.h>
00073
00074 #include <net-snmp/library/snmp_transport.h>
00075 #include <net-snmp/library/snmpUDPIPv6Domain.h>
00076
00077 oid netsnmp_UDPIPv6Domain[] = { TRANSPORT_DOMAIN_UDP_IPV6 };
00078 static netsnmp_tdomain udp6Domain;
00079
00080
00081
00082
00083
00084 extern void _netsnmp_udp_sockopt_set(int fd, int server);
00085
00086
00087
00088
00089
00090
00091 static char *
00092 netsnmp_udp6_fmtaddr(netsnmp_transport *t, void *data, int len)
00093 {
00094 struct sockaddr_in6 *to = NULL;
00095
00096 DEBUGMSGTL(("netsnmp_udp6", "fmtaddr: t = %p, data = %p, len = %d\n", t,
00097 data, len));
00098 if (data != NULL && len == sizeof(struct sockaddr_in6)) {
00099 to = (struct sockaddr_in6 *) data;
00100 } else if (t != NULL && t->data != NULL) {
00101 to = (struct sockaddr_in6 *) t->data;
00102 }
00103 if (to == NULL) {
00104 return strdup("UDP/IPv6: unknown");
00105 } else {
00106 char addr[INET6_ADDRSTRLEN];
00107 char tmp[INET6_ADDRSTRLEN + 18];
00108
00109 sprintf(tmp, "UDP/IPv6: [%s]:%hu",
00110 inet_ntop(AF_INET6, (void *) &(to->sin6_addr), addr,
00111 INET6_ADDRSTRLEN), ntohs(to->sin6_port));
00112 return strdup(tmp);
00113 }
00114 }
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 static int
00125 netsnmp_udp6_recv(netsnmp_transport *t, void *buf, int size,
00126 void **opaque, int *olength)
00127 {
00128 int rc = -1;
00129 socklen_t fromlen = sizeof(struct sockaddr_in6);
00130 struct sockaddr *from;
00131
00132 if (t != NULL && t->sock >= 0) {
00133 from = (struct sockaddr *) malloc(sizeof(struct sockaddr_in6));
00134 if (from == NULL) {
00135 *opaque = NULL;
00136 *olength = 0;
00137 return -1;
00138 } else {
00139 memset(from, 0, fromlen);
00140 }
00141
00142 while (rc < 0) {
00143 rc = recvfrom(t->sock, buf, size, 0, from, &fromlen);
00144 if (rc < 0 && errno != EINTR) {
00145 break;
00146 }
00147 }
00148
00149 if (rc >= 0) {
00150 char *str = netsnmp_udp6_fmtaddr(NULL, from, fromlen);
00151 DEBUGMSGTL(("netsnmp_udp6",
00152 "recvfrom fd %d got %d bytes (from %s)\n", t->sock,
00153 rc, str));
00154 free(str);
00155 } else {
00156 DEBUGMSGTL(("netsnmp_udp6", "recvfrom fd %d err %d (\"%s\")\n",
00157 t->sock, errno, strerror(errno)));
00158 }
00159 *opaque = (void *) from;
00160 *olength = sizeof(struct sockaddr_in6);
00161 }
00162 return rc;
00163 }
00164
00165
00166
00167 static int
00168 netsnmp_udp6_send(netsnmp_transport *t, void *buf, int size,
00169 void **opaque, int *olength)
00170 {
00171 int rc = -1;
00172 struct sockaddr *to = NULL;
00173
00174 if (opaque != NULL && *opaque != NULL &&
00175 *olength == sizeof(struct sockaddr_in6)) {
00176 to = (struct sockaddr *) (*opaque);
00177 } else if (t != NULL && t->data != NULL &&
00178 t->data_length == sizeof(struct sockaddr_in6)) {
00179 to = (struct sockaddr *) (t->data);
00180 }
00181
00182 if (to != NULL && t != NULL && t->sock >= 0) {
00183 char *str = netsnmp_udp6_fmtaddr(NULL, (void *)to,
00184 sizeof(struct sockaddr_in6));
00185 DEBUGMSGTL(("netsnmp_udp6", "send %d bytes from %p to %s on fd %d\n",
00186 size, buf, str, t->sock));
00187 free(str);
00188 while (rc < 0) {
00189 rc = sendto(t->sock, buf, size, 0, to,sizeof(struct sockaddr_in6));
00190 if (rc < 0 && errno != EINTR) {
00191 break;
00192 }
00193 }
00194 }
00195 return rc;
00196 }
00197
00198
00199
00200 static int
00201 netsnmp_udp6_close(netsnmp_transport *t)
00202 {
00203 int rc = -1;
00204 if (t != NULL && t->sock >= 0) {
00205 DEBUGMSGTL(("netsnmp_udp6", "close fd %d\n", t->sock));
00206 #ifndef HAVE_CLOSESOCKET
00207 rc = close(t->sock);
00208 #else
00209 rc = closesocket(t->sock);
00210 #endif
00211 t->sock = -1;
00212 }
00213 return rc;
00214 }
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224 netsnmp_transport *
00225 netsnmp_udp6_transport(struct sockaddr_in6 *addr, int local)
00226 {
00227 netsnmp_transport *t = NULL;
00228 int rc = 0;
00229 char *str = NULL;
00230
00231 if (addr == NULL || addr->sin6_family != AF_INET6) {
00232 return NULL;
00233 }
00234
00235 t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
00236 if (t == NULL) {
00237 return NULL;
00238 }
00239
00240 str = netsnmp_udp6_fmtaddr(NULL, (void *) addr,
00241 sizeof(struct sockaddr_in6));
00242 DEBUGMSGTL(("netsnmp_udp6", "open %s %s\n", local ? "local" : "remote",
00243 str));
00244 free(str);
00245
00246 memset(t, 0, sizeof(netsnmp_transport));
00247
00248 t->domain = netsnmp_UDPIPv6Domain;
00249 t->domain_length =
00250 sizeof(netsnmp_UDPIPv6Domain) / sizeof(netsnmp_UDPIPv6Domain[0]);
00251
00252 t->sock = socket(PF_INET6, SOCK_DGRAM, 0);
00253 if (t->sock < 0) {
00254 netsnmp_transport_free(t);
00255 return NULL;
00256 }
00257
00258 _netsnmp_udp_sockopt_set(t->sock, local);
00259
00260 if (local) {
00261
00262
00263
00264
00265
00266
00267 #ifdef IPV6_V6ONLY
00268
00269 {
00270 int one=1;
00271 if (setsockopt(t->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) != 0) {
00272 DEBUGMSGTL(("netsnmp_udp6", "couldn't set IPV6_V6ONLY to %d bytes: %s\n", one, strerror(errno)));
00273 }
00274 }
00275 #endif
00276
00277 rc = bind(t->sock, (struct sockaddr *) addr,
00278 sizeof(struct sockaddr_in6));
00279 if (rc != 0) {
00280 netsnmp_udp6_close(t);
00281 netsnmp_transport_free(t);
00282 return NULL;
00283 }
00284 t->local = malloc(18);
00285 if (t->local == NULL) {
00286 netsnmp_udp6_close(t);
00287 netsnmp_transport_free(t);
00288 return NULL;
00289 }
00290 memcpy(t->local, addr->sin6_addr.s6_addr, 16);
00291 t->local[16] = (addr->sin6_port & 0xff00) >> 8;
00292 t->local[17] = (addr->sin6_port & 0x00ff) >> 0;
00293 t->local_length = 18;
00294 t->data = NULL;
00295 t->data_length = 0;
00296 } else {
00297
00298
00299
00300
00301
00302 t->data = malloc(sizeof(struct sockaddr_in6));
00303 if (t->data == NULL) {
00304 netsnmp_udp6_close(t);
00305 netsnmp_transport_free(t);
00306 return NULL;
00307 }
00308 memcpy(t->data, addr, sizeof(struct sockaddr_in6));
00309 t->data_length = sizeof(struct sockaddr_in6);
00310 t->remote = malloc(18);
00311 if (t->remote == NULL) {
00312 netsnmp_udp6_close(t);
00313 netsnmp_transport_free(t);
00314 return NULL;
00315 }
00316 memcpy(t->remote, addr->sin6_addr.s6_addr, 16);
00317 t->remote[16] = (addr->sin6_port & 0xff00) >> 8;
00318 t->remote[17] = (addr->sin6_port & 0x00ff) >> 0;
00319 t->remote_length = 18;
00320 }
00321
00322
00323
00324
00325
00326 t->msgMaxSize = 0xffff - 8 - 40;
00327 t->f_recv = netsnmp_udp6_recv;
00328 t->f_send = netsnmp_udp6_send;
00329 t->f_close = netsnmp_udp6_close;
00330 t->f_accept = NULL;
00331 t->f_fmtaddr = netsnmp_udp6_fmtaddr;
00332
00333 return t;
00334 }
00335
00336
00337
00338 int
00339 netsnmp_sockaddr_in6(struct sockaddr_in6 *addr,
00340 const char *inpeername, int remote_port)
00341 {
00342 char *cp = NULL, *peername = NULL;
00343 char debug_addr[INET6_ADDRSTRLEN];
00344 #if HAVE_GETADDRINFO
00345 struct addrinfo *addrs = NULL;
00346 struct addrinfo hint;
00347 int err;
00348 #elif HAVE_GETIPNODEBYNAME
00349 struct hostent *hp = NULL;
00350 int err;
00351 #elif HAVE_GETHOSTBYNAME
00352 struct hostent *hp = NULL;
00353 #endif
00354 int portno;
00355
00356 if (addr == NULL) {
00357 return 0;
00358 }
00359
00360 DEBUGMSGTL(("netsnmp_sockaddr_in6", "addr %p, peername \"%s\"\n",
00361 addr, inpeername ? inpeername : "[NIL]"));
00362
00363 memset(addr, 0, sizeof(struct sockaddr_in6));
00364 addr->sin6_family = AF_INET6;
00365 addr->sin6_addr = in6addr_any;
00366
00367 if (remote_port > 0) {
00368 addr->sin6_port = htons(remote_port);
00369 } else if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
00370 NETSNMP_DS_LIB_DEFAULT_PORT) > 0) {
00371 addr->sin6_port = htons(netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
00372 NETSNMP_DS_LIB_DEFAULT_PORT));
00373 } else {
00374 addr->sin6_port = htons(SNMP_PORT);
00375 }
00376
00377 if (inpeername != NULL) {
00378
00379
00380
00381
00382
00383 peername = strdup(inpeername);
00384 if (peername == NULL) {
00385 return 0;
00386 }
00387
00388 for (cp = peername; *cp && isdigit((int) *cp); cp++);
00389 if (!*cp && atoi(peername) != 0) {
00390
00391
00392
00393 int port = atoi(peername);
00394 DEBUGMSGTL(("netsnmp_sockaddr_in6", "totally numeric: %d\n",
00395 port));
00396 if (port > 0 && port < 65536) {
00397 addr->sin6_port = htons(port);
00398 }
00399 else {
00400 snmp_log(LOG_WARNING,
00401 "Invalid port number: %d, using default %d\n",
00402 port, ntohs(addr->sin6_port));
00403 }
00404 goto resolved;
00405 }
00406
00407
00408
00409
00410
00411 if (*peername == '[') {
00412 cp = strchr(peername, ']');
00413 if (cp != NULL) {
00414
00415
00416
00417
00418
00419
00420
00421 char *scope_id;
00422 #ifdef HAVE_IF_NAMETOINDEX
00423 unsigned int if_index = 0;
00424 #endif
00425 *cp = '\0';
00426 scope_id = strchr(peername + 1, '%');
00427 if (scope_id != NULL) {
00428 *scope_id = '\0';
00429 #ifdef HAVE_IF_NAMETOINDEX
00430 if_index = if_nametoindex(scope_id + 1);
00431 #endif
00432 }
00433 if (*(cp + 1) == ':') {
00434 if (atoi(cp + 2) != 0 &&
00435 inet_pton(AF_INET6, peername + 1,
00436 (void *) &(addr->sin6_addr))) {
00437 int port = atoi(cp + 2);
00438 DEBUGMSGTL(("netsnmp_sockaddr_in6",
00439 "IPv6 address with port suffix :%d\n",
00440 port));
00441 if (port > 0 && port < 65536) {
00442 addr->sin6_port = htons(port);
00443 }
00444 else {
00445 snmp_log(LOG_WARNING,
00446 "Invalid port number: %d, using default %d\n",
00447 port, ntohs(addr->sin6_port));
00448 }
00449 #if defined(HAVE_IF_NAMETOINDEX) && defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID)
00450 addr->sin6_scope_id = if_index;
00451 #endif
00452 goto resolved;
00453 }
00454 } else {
00455 if (inet_pton
00456 (AF_INET6, peername + 1,
00457 (void *) &(addr->sin6_addr))) {
00458 DEBUGMSGTL(("netsnmp_sockaddr_in6",
00459 "IPv6 address with square brankets\n"));
00460 portno = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
00461 NETSNMP_DS_LIB_DEFAULT_PORT);
00462 if (portno <= 0)
00463 portno = SNMP_PORT;
00464 addr->sin6_port = htons(portno);
00465 #if defined(HAVE_IF_NAMETOINDEX) && defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID)
00466 addr->sin6_scope_id = if_index;
00467 #endif
00468 goto resolved;
00469 }
00470 }
00471 if (scope_id != NULL) {
00472 *scope_id = '%';
00473 }
00474 *cp = ']';
00475 }
00476 }
00477
00478 cp = strrchr(peername, ':');
00479 if (cp != NULL) {
00480 char *scope_id;
00481 #ifdef HAVE_IF_NAMETOINDEX
00482 unsigned int if_index = 0;
00483 #endif
00484 *cp = '\0';
00485 scope_id = strchr(peername + 1, '%');
00486 if (scope_id != NULL) {
00487 *scope_id = '\0';
00488 #ifdef HAVE_IF_NAMETOINDEX
00489 if_index = if_nametoindex(scope_id + 1);
00490 #endif
00491 }
00492 if (atoi(cp + 1) != 0 &&
00493 inet_pton(AF_INET6, peername,
00494 (void *) &(addr->sin6_addr))) {
00495 int port = atoi(cp + 1);
00496 DEBUGMSGTL(("netsnmp_sockaddr_in6",
00497 "IPv6 address with port suffix :%d\n",
00498 port));
00499 if (port > 0 && port < 65536) {
00500 addr->sin6_port = htons(port);
00501 }
00502 else {
00503 snmp_log(LOG_WARNING,
00504 "Invalid port number: %d, using default %d\n",
00505 port, ntohs(addr->sin6_port));
00506 }
00507 #if defined(HAVE_IF_NAMETOINDEX) && defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID)
00508 addr->sin6_scope_id = if_index;
00509 #endif
00510 goto resolved;
00511 }
00512 if (scope_id != NULL) {
00513 *scope_id = '%';
00514 }
00515 *cp = ':';
00516 }
00517
00518
00519
00520
00521 if (inet_pton(AF_INET6, peername, (void *) &(addr->sin6_addr))) {
00522 DEBUGMSGTL(("netsnmp_sockaddr_in6", "just IPv6 address\n"));
00523 goto resolved;
00524 }
00525
00526
00527
00528
00529
00530
00531 cp = strrchr(peername, ':');
00532 if (cp != NULL) {
00533 *cp = '\0';
00534 if (atoi(cp + 1) != 0) {
00535 int port = atoi(cp + 1);
00536 DEBUGMSGTL(("netsnmp_sockaddr_in6",
00537 "hostname(?) with port suffix :%d\n",
00538 port));
00539 if (port > 0 && port < 65536) {
00540 addr->sin6_port = htons(port);
00541 }
00542 else {
00543 snmp_log(LOG_WARNING,
00544 "Invalid port number: %d, using default %d\n",
00545 port, ntohs(addr->sin6_port));
00546 }
00547 } else {
00548
00549
00550
00551
00552 *cp = ':';
00553 DEBUGMSGTL(("netsnmp_sockaddr_in6",
00554 "hostname(?) with embedded ':'?\n"));
00555 }
00556
00557
00558
00559 }
00560 #if HAVE_GETADDRINFO
00561 memset(&hint, 0, sizeof hint);
00562 hint.ai_flags = 0;
00563 hint.ai_family = PF_INET6;
00564 hint.ai_socktype = SOCK_DGRAM;
00565 hint.ai_protocol = 0;
00566
00567 err = getaddrinfo(peername, NULL, &hint, &addrs);
00568 if (err != 0) {
00569 #if HAVE_GAI_STRERROR
00570 snmp_log(LOG_ERR, "getaddrinfo: %s %s\n", peername,
00571 gai_strerror(err));
00572 #else
00573 snmp_log(LOG_ERR, "getaddrinfo: %s (error %d)\n", peername, err);
00574 #endif
00575 free(peername);
00576 return 0;
00577 }
00578 if (addrs != NULL) {
00579 DEBUGMSGTL(("netsnmp_sockaddr_in6", "hostname (resolved okay)\n"));
00580 memcpy(&addr->sin6_addr,
00581 &((struct sockaddr_in6 *) addrs->ai_addr)->sin6_addr,
00582 sizeof(struct in6_addr));
00583 freeaddrinfo(addrs);
00584 }
00585 else {
00586 DEBUGMSGTL(("netsnmp_sockaddr_in6", "Failed to resolve IPv6 hostname\n"));
00587 }
00588 #elif HAVE_GETIPNODEBYNAME
00589 hp = getipnodebyname(peername, AF_INET6, 0, &err);
00590 if (hp == NULL) {
00591 DEBUGMSGTL(("netsnmp_sockaddr_in6",
00592 "hostname (couldn't resolve = %d)\n", err));
00593 free(peername);
00594 return 0;
00595 }
00596 DEBUGMSGTL(("netsnmp_sockaddr_in6", "hostname (resolved okay)\n"));
00597 memcpy(&(addr->sin6_addr), hp->h_addr, hp->h_length);
00598 #elif HAVE_GETHOSTBYNAME
00599 hp = gethostbyname(peername);
00600 if (hp == NULL) {
00601 DEBUGMSGTL(("netsnmp_sockaddr_in6",
00602 "hostname (couldn't resolve)\n"));
00603 free(peername);
00604 return 0;
00605 } else {
00606 if (hp->h_addrtype != AF_INET6) {
00607 DEBUGMSGTL(("netsnmp_sockaddr_in6",
00608 "hostname (not AF_INET6!)\n"));
00609 free(peername);
00610 return 0;
00611 } else {
00612 DEBUGMSGTL(("netsnmp_sockaddr_in6",
00613 "hostname (resolved okay)\n"));
00614 memcpy(&(addr->sin6_addr), hp->h_addr, hp->h_length);
00615 }
00616 }
00617 #else
00618
00619
00620
00621 snmp_log(LOG_ERR,
00622 "no getaddrinfo()/getipnodebyname()/gethostbyname()\n");
00623 free(peername);
00624 return 0;
00625 #endif
00626 } else {
00627 DEBUGMSGTL(("netsnmp_sockaddr_in6", "NULL peername"));
00628 return 0;
00629 }
00630
00631 resolved:
00632 DEBUGMSGTL(("netsnmp_sockaddr_in6", "return { AF_INET6, [%s]:%hu }\n",
00633 inet_ntop(AF_INET6, &addr->sin6_addr, debug_addr,
00634 sizeof(debug_addr)), ntohs(addr->sin6_port)));
00635 free(peername);
00636 return 1;
00637 }
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654 int
00655 inet_make_mask_addr(int pf, void *dst, int masklength)
00656 {
00657
00658 unsigned long Mask = 0;
00659 int maskBit = 0x80000000L;
00660 unsigned char mask = 0;
00661 unsigned char maskbit = 0x80L;
00662 int i, j, jj;
00663
00664
00665 switch (pf) {
00666 case PF_INET:
00667 if (masklength < 0 || masklength > 32)
00668 return -1;
00669
00670 ((struct in_addr *) dst)->s_addr = 0;
00671
00672 while (masklength--) {
00673 Mask |= maskBit;
00674 maskBit >>= 1;
00675 }
00676 ((struct in_addr *) dst)->s_addr = htonl(Mask);
00677 break;
00678
00679 case PF_INET6:
00680 if (masklength < 0 || masklength > 128)
00681 return -1;
00682
00683
00684 for (i = 0; i < 16; i++) {
00685 (*(u_char *) (&((struct in6_addr *) dst)->s6_addr[i])) = 0x00;
00686 }
00687
00688 j = (int) masklength / 8;
00689 jj = masklength % 8;
00690
00691 for (i = 0; i < j; i++) {
00692 (*(u_char *) (&((struct in6_addr *) dst)->s6_addr[i])) = 0xff;
00693 }
00694 while (jj--) {
00695 mask |= maskbit;
00696 maskbit >>= 1;
00697 }
00698 (*(u_char *) (&((struct in6_addr *) dst)->s6_addr[j])) = mask;
00699 break;
00700 default:
00701 return -1;
00702 }
00703 return 0;
00704 }
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717 int
00718 inet_addr_complement(int pf, void *src, void *dst)
00719 {
00720
00721 int i;
00722
00723 if (sizeof(src) != sizeof(dst))
00724 return -1;
00725
00726 switch (pf) {
00727 case PF_INET:
00728 ((struct in_addr *) dst)->s_addr =
00729 ~((struct in_addr *) src)->s_addr;
00730 break;
00731 case PF_INET6:
00732 for (i = 0; i < 16; i++) {
00733 (*(u_char *) (&((struct in6_addr *) dst)->s6_addr[i])) =
00734 (~(*(u_char *) (&((struct in6_addr *) src)->s6_addr[i])))
00735 & 0xff;
00736 }
00737 break;
00738 default:
00739 return -1;
00740 }
00741 return 0;
00742 }
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754 int
00755 inet_addr_and(int pf, void *src1, void *src2, void *dst)
00756 {
00757 int i;
00758
00759 if (sizeof(src1) != sizeof(src2) || sizeof(src2) != sizeof(dst))
00760 return -1;
00761
00762 switch (pf) {
00763 case PF_INET:
00764 ((struct in_addr *) dst)->s_addr =
00765 ((struct in_addr *) src1)->s_addr & ((struct in_addr *) src2)->
00766 s_addr;
00767 break;
00768
00769 case PF_INET6:
00770 for (i = 0; i < 16; i++) {
00771 (*(u_char *) (&((struct in6_addr *) dst)->s6_addr[i])) =
00772 (*(u_char *) (&((struct in6_addr *) src1)->s6_addr[i])) &
00773 (*(u_char *) (&((struct in6_addr *) src2)->s6_addr[i]));
00774 }
00775 break;
00776 default:
00777 return -1;
00778 }
00779 return 0;
00780 }
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799 int
00800 inet_addrs_consistence(int pf, void *net, void *mask)
00801 {
00802 struct sockaddr_in *tmp, *dst;
00803 struct sockaddr_in6 *tmp6, *dst6;
00804 int ret;
00805
00806 switch (pf) {
00807 case PF_INET:
00808 tmp = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in));
00809 if (!tmp) {
00810 config_perror("Resource failure in inet_addr_consistence()");
00811 return -1;
00812 }
00813 memset(tmp, 0, sizeof(*tmp));
00814 tmp->sin_family = PF_INET;
00815 if (inet_addr_complement
00816 (PF_INET, (struct in_addr *) mask, &tmp->sin_addr) != 0) {
00817 config_perror("Fail in function of inet_addr_complement()");
00818 free(tmp);
00819 return -1;
00820 }
00821 dst = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in));
00822 if (!dst) {
00823 config_perror("Resource failure in inet_addr_consistence()");
00824 free(tmp);
00825 return -1;
00826 }
00827 memset(dst, 0, sizeof(*dst));
00828 dst->sin_family = PF_INET;
00829 if (inet_addr_and
00830 (PF_INET, (struct in_addr *) net, &tmp->sin_addr,
00831 &dst->sin_addr) != 0) {
00832 config_perror("Fail in function of inet_addr_and()");
00833 free(dst);
00834 free(tmp);
00835 return -1;
00836 }
00837 ret = ((dst->sin_addr.s_addr == INADDR_ANY) ? 0 : -1);
00838 free(dst);
00839 free(tmp);
00840 break;
00841 case PF_INET6:
00842 tmp6 = (struct sockaddr_in6 *) malloc(sizeof(struct sockaddr_in6));
00843 if (!tmp6) {
00844 config_perror("Resource failure in inet_addr_consistence()");
00845 return -1;
00846 }
00847 memset(tmp6, 0, sizeof(*tmp6));
00848 tmp6->sin6_family = PF_INET6;
00849 if (inet_addr_complement
00850 (PF_INET6, (struct in6_addr *) mask, &tmp6->sin6_addr) != 0) {
00851 config_perror("Fail in function of inet_addr_complement()");
00852 free(tmp6);
00853 return -1;
00854 }
00855 dst6 = (struct sockaddr_in6 *) malloc(sizeof(struct sockaddr_in6));
00856 if (!dst6) {
00857 config_perror("Resource failure in inet_addr_consistence()");
00858 free(tmp6);
00859 return -1;
00860 }
00861 memset(dst6, 0, sizeof(*dst6));
00862 dst6->sin6_family = PF_INET6;
00863 if (inet_addr_and
00864 (PF_INET6, (struct in6_addr *) net, &tmp6->sin6_addr,
00865 &dst6->sin6_addr)) {
00866 config_perror("Fail in function of inet_addr_and()");
00867 free(dst6);
00868 free(tmp6);
00869 return -1;
00870 }
00871 ret = (IN6_IS_ADDR_UNSPECIFIED(&dst6->sin6_addr) == 1 ? 0 : -1);
00872 free(dst6);
00873 free(tmp6);
00874 break;
00875 default:
00876 return -1;
00877 }
00878 return ret;
00879 }
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901 int
00902 masked_address_are_equal(int af, struct sockaddr_storage *from,
00903 struct sockaddr_storage *mask,
00904 struct sockaddr_storage *network)
00905 {
00906
00907 struct sockaddr_storage ss;
00908 memset(&ss, 0, sizeof(ss));
00909
00910 switch (af) {
00911 case PF_INET:
00912 if (mask->ss_family != PF_INET || network->ss_family != PF_INET) {
00913 return -1;
00914 }
00915 ss.ss_family = PF_INET;
00916 inet_addr_and(PF_INET,
00917 &((struct sockaddr_in *) from)->sin_addr,
00918 &((struct sockaddr_in *) mask)->sin_addr,
00919 &((struct sockaddr_in *) &ss)->sin_addr);
00920 if (((struct sockaddr_in *) &ss)->sin_addr.s_addr ==
00921 ((struct sockaddr_in *) network)->sin_addr.s_addr) {
00922 return 0;
00923 } else {
00924 return -1;
00925 }
00926 break;
00927 case PF_INET6:
00928 if (mask->ss_family != PF_INET6 || network->ss_family != PF_INET6) {
00929 return -1;
00930 }
00931 ss.ss_family = PF_INET6;
00932 inet_addr_and(PF_INET6,
00933 &((struct sockaddr_in6 *) from)->sin6_addr,
00934 &((struct sockaddr_in6 *) mask)->sin6_addr,
00935 &((struct sockaddr_in6 *) &ss)->sin6_addr);
00936 #ifndef IN6_ARE_ADDR_EQUAL
00937 #define IN6_ARE_ADDR_EQUAL(a,b) IN6_ADDR_EQUAL(a,b)
00938 #endif
00939 if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *) &ss)->sin6_addr,
00940 &((struct sockaddr_in6 *) network)->
00941 sin6_addr) == 1) {
00942 return 0;
00943 } else {
00944 return -1;
00945 }
00946 break;
00947 default:
00948 return -1;
00949 }
00950 }
00951
00952 #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
00953
00954
00955
00956
00957
00958 #define EXAMPLE_NETWORK "NETWORK"
00959 #define EXAMPLE_COMMUNITY "COMMUNITY"
00960
00961 typedef struct _com2Sec6Entry {
00962 char community[COMMUNITY_MAX_LEN];
00963 struct sockaddr_in6 network;
00964 struct sockaddr_in6 mask;
00965 char secName[VACMSTRINGLEN];
00966 char contextName[VACMSTRINGLEN];
00967 struct _com2Sec6Entry *next;
00968 } com2Sec6Entry;
00969
00970 com2Sec6Entry *com2Sec6List = NULL, *com2Sec6ListLast = NULL;
00971
00972
00973 void
00974 memmove_com2Sec6Entry(com2Sec6Entry * c,
00975 char *secName,
00976 char *community,
00977 struct sockaddr_in6 net, struct sockaddr_in6 mask,
00978 char *contextName)
00979 {
00980 snprintf(c->secName, strlen(secName) + 1, "%s", secName);
00981 snprintf(c->contextName, strlen(contextName) + 1, "%s", contextName);
00982 snprintf(c->community, strlen(community) + 1, "%s", community);
00983 memmove(&c->network, &net, sizeof(net));
00984 memmove(&c->mask, &mask, sizeof(mask));
00985 c->next = NULL;
00986 }
00987
00988
00989 #ifndef IPV6_STRING_LEN
00990 #define IPV6_STRING_LEN 55
00991 #endif
00992
00993 void
00994 netsnmp_udp6_parse_security(const char *token, char *param)
00995 {
00996 char secName[VACMSTRINGLEN];
00997 char contextName[VACMSTRINGLEN];
00998 char community[COMMUNITY_MAX_LEN];
00999 char source[IPV6_STRING_LEN];
01000 char *cp = NULL, *strnetwork = NULL, *strmask = NULL;
01001 com2Sec6Entry *e = NULL;
01002 struct sockaddr_in6 net, mask;
01003 struct sockaddr_in tmp;
01004
01005 memset(&net, 0, sizeof(net));
01006 memset(&mask, 0, sizeof(mask));
01007 memset(&tmp, 0, sizeof(tmp));
01008 net.sin6_family = AF_INET6;
01009 mask.sin6_family = AF_INET6;
01010 tmp.sin_family = AF_INET;
01011
01012
01013
01014
01015
01016 cp = copy_nword( param, secName, sizeof(secName));
01017 if (strcmp(secName, "-Cn") == 0) {
01018 if (!cp) {
01019 config_perror("missing CONTEXT_NAME parameter");
01020 return;
01021 }
01022 cp = copy_nword( cp, contextName, sizeof(contextName));
01023 cp = copy_nword( cp, secName, sizeof(secName));
01024 } else {
01025 contextName[0] = '\0';
01026 }
01027 if (secName[0] == '\0') {
01028 config_perror("missing NAME parameter");
01029 return;
01030 } else if (strlen(secName) > (VACMSTRINGLEN - 1)) {
01031 config_perror("security name too long");
01032 return;
01033 }
01034 cp = copy_nword( cp, source, sizeof(source));
01035 if (source[0] == '\0') {
01036 config_perror("missing SOURCE parameter");
01037 return;
01038 } else if (strncmp(source, EXAMPLE_NETWORK, strlen(EXAMPLE_NETWORK)) ==
01039 0) {
01040 config_perror("example config NETWORK not properly configured");
01041 return;
01042 }
01043 cp = copy_nword( cp, community, sizeof(community));
01044 if (community[0] == '\0') {
01045 config_perror("missing COMMUNITY parameter\n");
01046 return;
01047 } else
01048 if (strncmp
01049 (community, EXAMPLE_COMMUNITY, strlen(EXAMPLE_COMMUNITY))
01050 == 0) {
01051 config_perror("example config COMMUNITY not properly configured");
01052 return;
01053 } else if (strlen(community) > (COMMUNITY_MAX_LEN - 1)) {
01054 config_perror("community name too long");
01055 return;
01056 }
01057
01058
01059
01060
01061 cp = strchr(source, '/');
01062 if (cp != NULL) {
01063
01064
01065
01066 *cp = '\0';
01067 strmask = cp + 1;
01068 }
01069
01070
01071
01072
01073 if ((strcmp(source, "default") == 0) || (strcmp(source, "::") == 0)) {
01074 strnetwork = strdup("0::0");
01075 strmask = strdup("0::0");
01076
01077 inet_pton(AF_INET6, strnetwork, &net.sin6_addr);
01078 inet_pton(AF_INET6, strmask, &mask.sin6_addr);
01079
01080 e = (com2Sec6Entry *) malloc(sizeof(com2Sec6Entry));
01081 if (e == NULL) {
01082 config_perror("memory error");
01083 return;
01084 }
01085
01086
01087
01088
01089 if (strmask != NULL && strnetwork != NULL) {
01090 DEBUGMSGTL(("netsnmp_udp6_parse_security",
01091 "<\"%s\", %s/%s> => \"%s\"\n", community,
01092 strnetwork, strmask, secName));
01093 free(strmask);
01094 free(strnetwork);
01095 } else {
01096 DEBUGMSGTL(("netsnmp_udp6_parse_security",
01097 "Couldn't allocate enough memory\n"));
01098 }
01099 memmove_com2Sec6Entry(e, secName, community, net, mask, contextName);
01100 if (com2Sec6ListLast != NULL) {
01101 com2Sec6ListLast->next = e;
01102 com2Sec6ListLast = e;
01103 } else {
01104 com2Sec6ListLast = com2Sec6List = e;
01105 }
01106
01107 } else {
01108
01109
01110
01111 if (inet_pton(AF_INET6, source, &net.sin6_addr) == 1) {
01112 if (strmask == NULL || *strmask == '\0') {
01113 inet_make_mask_addr(PF_INET6, &mask.sin6_addr, 128);
01114 } else {
01115 if (strchr(strmask, ':')) {
01116 if (inet_pton(PF_INET6, strmask, &net.sin6_addr) != 1) {
01117 config_perror("bad mask");
01118 return;
01119 }
01120 } else {
01121 if (inet_make_mask_addr
01122 (PF_INET6, &mask.sin6_addr, atoi(strmask)) != 0) {
01123 config_perror("bad mask");
01124 return;
01125
01126 }
01127 }
01128 }
01129
01130
01131
01132 if (inet_addrs_consistence
01133 (PF_INET6, &net.sin6_addr, &mask.sin6_addr) != 0) {
01134 config_perror("source/mask mismatch");
01135 return;
01136 }
01137
01138 e = (com2Sec6Entry *) malloc(sizeof(com2Sec6Entry));
01139 if (e == NULL) {
01140 config_perror("memory error");
01141 return;
01142 }
01143
01144
01145
01146
01147
01148 if (strmask != NULL && strnetwork != NULL) {
01149 DEBUGMSGTL(("netsnmp_udp6_parse_security",
01150 "<\"%s\", %s/%s> => \"%s\"\n", community,
01151 strnetwork, strmask, secName));
01152 free(strmask);
01153 free(strnetwork);
01154 } else {
01155 DEBUGMSGTL(("netsnmp_udp6_parse_security",
01156 "Couldn't allocate enough memory\n"));
01157 }
01158 memmove_com2Sec6Entry(e, secName, community, net, mask,
01159 contextName);
01160 if (com2Sec6ListLast != NULL) {
01161 com2Sec6ListLast->next = e;
01162 com2Sec6ListLast = e;
01163 } else {
01164 com2Sec6ListLast = com2Sec6List = e;
01165 }
01166
01167 #if HAVE_GETADDRINFO
01168
01169 } else {
01170
01171
01172
01173 struct addrinfo hints, *ai, *res;
01174 char hbuf[NI_MAXHOST];
01175 int gai_error;
01176
01177 memset(&hints, 0, sizeof(hints));
01178 hints.ai_family = PF_INET6;
01179 hints.ai_socktype = SOCK_DGRAM;
01180 if ((gai_error = getaddrinfo(source, NULL, &hints, &res)) != 0) {
01181 config_perror(gai_strerror(gai_error));
01182 return;
01183 }
01184
01185 for (ai = res; ai != NULL; ai = ai->ai_next) {
01186 if (getnameinfo
01187 (ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), NULL,
01188 0, NI_NUMERICHOST)) {
01189 config_perror("getnameinfo failed");
01190 }
01191 memmove(ai->ai_addr, &net, sizeof(struct sockaddr_in6));
01192 inet_make_mask_addr(AF_INET6, &mask.sin6_addr, 127);
01193
01194 e = (com2Sec6Entry *) malloc(sizeof(com2Sec6Entry));
01195 if (e == NULL) {
01196 config_perror("memory error");
01197 return;
01198 }
01199
01200
01201
01202
01203
01204 DEBUGMSGTL(("netsnmp_udp6_parse_security",
01205 "<\"%s\", %s> => \"%s\"\n", community, hbuf,
01206 secName));
01207 memmove_com2Sec6Entry(e, secName, community, net, mask,
01208 contextName);
01209 if (com2Sec6ListLast != NULL) {
01210 com2Sec6ListLast->next = e;
01211 com2Sec6ListLast = e;
01212 } else {
01213 com2Sec6ListLast = com2Sec6List = e;
01214 }
01215 }
01216 if (res != NULL)
01217 freeaddrinfo(res);
01218
01219 #endif
01220
01221 }
01222
01223
01224
01225 }
01226 }
01227
01228 void
01229 netsnmp_udp6_com2Sec6List_free(void)
01230 {
01231 com2Sec6Entry *e = com2Sec6List;
01232 while (e != NULL) {
01233 com2Sec6Entry *tmp = e;
01234 e = e->next;
01235 free(tmp);
01236 }
01237 com2Sec6List = com2Sec6ListLast = NULL;
01238 }
01239
01240 #endif
01241
01242 void
01243 netsnmp_udp6_agent_config_tokens_register(void)
01244 {
01245 #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
01246 register_app_config_handler("com2sec6", netsnmp_udp6_parse_security,
01247 netsnmp_udp6_com2Sec6List_free,
01248 "[-Cn CONTEXT] secName IPv6-network-address[/netmask] community");
01249 #endif
01250 }
01251
01252
01253
01254 #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
01255
01256
01257
01258
01259
01260
01261
01262 int
01263 netsnmp_udp6_getSecName(void *opaque, int olength,
01264 const char *community,
01265 int community_len, char **secName, char **contextName)
01266 {
01267 com2Sec6Entry *c;
01268 struct sockaddr_in6 *from = (struct sockaddr_in6 *) opaque;
01269 char *ztcommunity = NULL;
01270 char str6[INET6_ADDRSTRLEN];
01271
01272 if (secName != NULL) {
01273 *secName = NULL;
01274 }
01275
01276
01277
01278
01279
01280
01281 if (com2Sec6List == NULL) {
01282 DEBUGMSGTL(("netsnmp_udp6_getSecName", "no com2sec entries\n"));
01283 return 0;
01284 }
01285
01286
01287
01288
01289
01290
01291 if (opaque == NULL || olength != sizeof(struct sockaddr_in6)
01292 || from->sin6_family != PF_INET6) {
01293 DEBUGMSGTL(("netsnmp_udp6_getSecName",
01294 "no IPv6 source address in PDU?\n"));
01295 return 1;
01296 }
01297
01298 ztcommunity = (char *) malloc(community_len + 1);
01299 if (ztcommunity != NULL) {
01300 memcpy(ztcommunity, community, community_len);
01301 ztcommunity[community_len] = '\0';
01302 }
01303
01304 inet_ntop(AF_INET6, &from->sin6_addr, str6, sizeof(str6));
01305 DEBUGMSGTL(("netsnmp_udp6_getSecName", "resolve <\"%s\", %s>\n",
01306 ztcommunity ? ztcommunity : "<malloc error>", str6));
01307
01308 for (c = com2Sec6List; c != NULL; c = c->next) {
01309 DEBUGMSGTL(("netsnmp_udp6_getSecName",
01310 "compare <\"%s\", 0x%032/0x%032x>", c->community,
01311 c->network, c->mask));
01312
01313 if ((community_len == (int)strlen(c->community)) &&
01314 (memcmp(community, c->community, community_len) == 0) &&
01315 (masked_address_are_equal(from->sin6_family,
01316 (struct sockaddr_storage *) from,
01317 (struct sockaddr_storage *) &c->mask,
01318 (struct sockaddr_storage *) &c->
01319 network) == 0)) {
01320 DEBUGMSG(("netsnmp_udp6_getSecName", "... SUCCESS\n"));
01321 if (secName != NULL) {
01322 *secName = c->secName;
01323 *contextName = c->contextName;
01324 }
01325 break;
01326 }
01327 DEBUGMSG(("netsnmp_udp6_getSecName", "... nope\n"));
01328 }
01329 if (ztcommunity != NULL) {
01330 free(ztcommunity);
01331 }
01332 return 1;
01333 }
01334 #endif
01335
01336 netsnmp_transport *
01337 netsnmp_udp6_create_tstring(const char *str, int local)
01338 {
01339 struct sockaddr_in6 addr;
01340
01341 if (netsnmp_sockaddr_in6(&addr, str, 0)) {
01342 return netsnmp_udp6_transport(&addr, local);
01343 } else {
01344 return NULL;
01345 }
01346 }
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358 netsnmp_transport *
01359 netsnmp_udp6_create_ostring(const u_char * o, size_t o_len, int local)
01360 {
01361 struct sockaddr_in6 addr;
01362
01363 if (o_len == 18) {
01364 memset((u_char *) & addr, 0, sizeof(struct sockaddr_in6));
01365 addr.sin6_family = AF_INET6;
01366 memcpy((u_char *) & (addr.sin6_addr.s6_addr), o, 16);
01367 addr.sin6_port = (o[16] << 8) + o[17];
01368 return netsnmp_udp6_transport(&addr, local);
01369 }
01370 return NULL;
01371 }
01372
01373
01374 void
01375 netsnmp_udp6_ctor(void)
01376 {
01377 udp6Domain.name = netsnmp_UDPIPv6Domain;
01378 udp6Domain.name_length = sizeof(netsnmp_UDPIPv6Domain) / sizeof(oid);
01379 udp6Domain.f_create_from_tstring = netsnmp_udp6_create_tstring;
01380 udp6Domain.f_create_from_ostring = netsnmp_udp6_create_ostring;
01381 udp6Domain.prefix = calloc(5, sizeof(char *));
01382 udp6Domain.prefix[0] = "udp6";
01383 udp6Domain.prefix[1] = "ipv6";
01384 udp6Domain.prefix[2] = "udpv6";
01385 udp6Domain.prefix[3] = "udpipv6";
01386
01387 netsnmp_tdomain_register(&udp6Domain);
01388 }
01389
01390 #else
01391
01392 #ifdef NETSNMP_DLL
01393
01394 void
01395 netsnmp_udp6_agent_config_tokens_register(void)
01396 { }
01397 #endif
01398
01399 #endif
01400