00001 #include <net-snmp/net-snmp-config.h> 00002 00003 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN 00004 00005 /* 00006 * hack-o-matic for Cygwin to use winsock2 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 * Windows IPv6 support is part of WinSock2 only 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 * from snmpUDPDomain. not static, but not public, either. 00092 * (ie don't put it in a public header.) 00093 */ 00094 extern void _netsnmp_udp_sockopt_set(int fd, int server); 00095 00096 /* 00097 * Return a string representing the address in data, or else the "far end" 00098 * address if data is NULL. 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 * You can write something into opaque that will subsequently get passed back 00130 * to your send function if you like. For instance, you might want to 00131 * remember where a PDU came from, so that you can send a reply there... 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 * Open a UDP/IPv6-based transport for SNMP. Local is TRUE if addr is the 00230 * local address to bind to (i.e. this is a server-type session); otherwise 00231 * addr is the remote address to send things to. 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 * This session is inteneded as a server, so we must bind on to the 00273 * given IP address, which may include an interface address, or could 00274 * be INADDR_ANY, but certainly includes a port number. 00275 */ 00276 00277 #ifdef IPV6_V6ONLY 00278 /* Try to restrict PF_INET6 socket to IPv6 communications only. */ 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 * This is a client session. Save the address in the 00309 * transport-specific data pointer for later use by netsnmp_udp6_send. 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 * 16-bit length field, 8 byte UDP header, 40 byte IPv6 header. 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 * Not extern but used from here and snmpTCPIPv6Domain.C 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 * Duplicate the peername because we might want to mank around with 00394 * it. 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 * Okay, it looks like JUST a port number. 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 * See if it is an IPv6 address, which covered with square brankets 00416 * with an appended :port. 00417 */ 00418 if (*peername == '[') { 00419 cp = strchr(peername, ']'); 00420 if (cp != NULL) { 00421 /* 00422 * See if it is an IPv6 link-local address with interface 00423 * name as <zone_id>, like fe80::1234%eth0. 00424 * Please refer to the internet draft, IPv6 Scoped Address Architecture 00425 * http://www.ietf.org/internet-drafts/draft-ietf-ipngwg-scoping-arch-04.txt 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 * See if it is JUST an IPv6 address. 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 * Well, it must be a hostname then, possibly with an appended :port. 00533 * Sort that out first. 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 * No idea, looks bogus but we might as well pass the full thing to 00554 * the name resolver below. 00555 */ 00556 *cp = ':'; 00557 DEBUGMSGTL(("netsnmp_sockaddr_in6", 00558 "hostname(?) with embedded ':'?\n")); 00559 } 00560 /* 00561 * Fall through. 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 /*HAVE_GETHOSTBYNAME */ 00630 /* 00631 * There is no name resolving function available. 00632 */ 00633 snmp_log(LOG_ERR, 00634 "no getaddrinfo()/getipnodebyname()/gethostbyname()\n"); 00635 free(peername); 00636 return 0; 00637 #endif /*HAVE_GETHOSTBYNAME */ 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 * int 00663 * inet_make_mask_addr( int pf, void *dst, int masklength ) 00664 * convert from bit length specified masklength to network format, 00665 * which fills 1 from until specified bit length. 00666 * dst is usally the structer of sockaddr_in or sockaddr_in6. 00667 * makelength must be an interger from 0 to 32 if pf is PF_INET, 00668 * or from 0 to 128 if pf is PF_INET6. 00669 * return: 00670 * 0 if the input data, masklength was valid for 00671 * the specified protocol family. 00672 * -1 if the the input data wasn't valid. 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; /* unsupported protocol family */ 00727 } 00728 return 0; 00729 } 00730 00731 /* 00732 * int 00733 * inet_addr_complement( int pf, void *src, void *dst ) 00734 * convert from src to dst, which all bits 00735 * are bit-compliment of src. 00736 * Src, dst are ususally sockaddr_in or sockaddr_in6. 00737 * return: 00738 * 0 if the input data src and dst have the same size 00739 * -1 if the the input data wasn't valid. 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 * int 00771 * inet_addr_and( int pf, void *src1, void *src2, void *dst) 00772 * take AND operation on src1 and src2, and output the result to dst. 00773 * Src1, src2, and dst are ususally sockaddr_in or sockaddr_in6. 00774 * return: 00775 * 0 if the input data src and dst have the same size 00776 * -1 if the the input data are not the same size 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 * int 00810 * inet_addrs_consistence (int pf, void *net, void *mask ) 00811 * This function checks if the network address net is consistent 00812 * with the netmask address, mask. 00813 * Net and mask are ususally sockaddr_in or sockaddr_in6. 00814 * Note: 00815 * Must spefiey protocol family in pf. 00816 * return: 00817 * 0 if there is no consistence with address "net" and "mask". 00818 * -1 if network address is inconsistent with netmask address, for 00819 * instance, network address is 192.168.0.128 in spite of netmask, 00820 * which is 255.255.255.0. 00821 * The case that the size of net and mask are different also returns -1. 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 * int 00908 * masked_address_are_equal (pf, from, mask, network) 00909 * This function takes AND operation on address "from" and "mask", 00910 * and check the result is equal to address "network". 00911 * From, net and mask are ususally sockaddr_in or sockaddr_in6. 00912 * Note: 00913 * Must spefiey protocol family in pf. 00914 * return: 00915 * 0 if address "from" masked by address "mask" is eqaul to 00916 * address "network". 00917 * -1 if address "from" masked by address "mask" isn't eqaul to 00918 * address "network". For instance, address "from" is 00919 * 192.168.0.129 and "mask" is 255.255.255.128. Then, masked 00920 * address is 192.168.0.128. If address "network" is 192.168.0.128, 00921 * return 0, otherwise -1. 00922 * Also retunn -1 if each address family of from, mask, network 00923 * isn't the same. 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 * The following functions provide the "com2sec6" configuration token 00980 * functionality for compatibility. 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 * Get security, source address/netmask and community strings. 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 * Process the source address/netmask string. 01085 */ 01086 cp = strchr(source, '/'); 01087 if (cp != NULL) { 01088 /* 01089 * Mask given. 01090 */ 01091 *cp = '\0'; 01092 strmask = cp + 1; 01093 } 01094 01095 /* 01096 * Deal with the network part first. 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 * Try interpreting as IPv6 address. 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 * Check that the network and mask are consistent. 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 * Everything is okay. Copy the parameters to the structure allocated 01171 * above and add it to END of the list. 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 * Nope, Must be a hostname. 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 * Everything is okay. Copy the parameters to the structure allocated 01227 * above and add it to END of the list. 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 /* HAVE_GETADDRINFO */ 01245 01246 } 01247 /* 01248 * free(strnetwork); 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 /* support for community based SNMP */ 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 /* support for community based SNMP */ 01275 } 01276 01277 01278 01279 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) 01280 /* 01281 * Return 0 if there are no com2sec entries, or return 1 if there ARE com2sec 01282 * entries. On return, if a com2sec entry matched the passed parameters, 01283 * then *secName points at the appropriate security name, or is NULL if the 01284 * parameters did not match any com2sec entry. 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; /* Haven't found anything yet */ 01299 } 01300 01301 /* 01302 * Special case if there are NO entries (as opposed to no MATCHING 01303 * entries). 01304 */ 01305 01306 if (com2Sec6List == NULL) { 01307 DEBUGMSGTL(("netsnmp_udp6_getSecName", "no com2sec entries\n")); 01308 return 0; 01309 } 01310 01311 /* 01312 * If there is no IPv6 source address, 01313 * then there can be no valid security name. 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 /* support for community based SNMP */ 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 * See: 01379 * 01380 * http://www.ietf.org/internet-drafts/draft-ietf-ops-taddress-mib-01.txt 01381 * 01382 * (or newer equivalent) for details of the TC which we are using for 01383 * the mapping here. 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 /* need this hook for win32 MSVC++ DLL build */ 01422 void 01423 netsnmp_udp6_agent_config_tokens_register(void) 01424 { } 01425 #endif 01426 01427 #endif /* NETSNMP_TRANSPORT_UDPIPV6_DOMAIN */ 01428
1.5.7.1
Last modified: Tuesday, 23-Dec-2025 17:22:04 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.