snmpUDPIPv6Domain.c

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

net-snmpに対してSat Sep 5 13:14:26 2009に生成されました。  doxygen 1.4.7