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