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