net-snmp  5.4.1
snmpUDPIPv6Domain.c
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