net-snmp  5.4.1
snmpUDPDomain.c
00001 /* Portions of this file are subject to the following copyright(s).  See
00002  * the Net-SNMP's COPYING file for more details and other copyrights
00003  * that may apply:
00004  */
00005 /*
00006  * Portions of this file are copyrighted by:
00007  * Copyright Copyright 2003 Sun Microsystems, Inc. All rights reserved.
00008  * Use is subject to license terms specified in the COPYING file
00009  * distributed with the Net-SNMP package.
00010  */
00011 
00012 #include <net-snmp/net-snmp-config.h>
00013 
00014 #include <stdio.h>
00015 #include <sys/types.h>
00016 #include <ctype.h>
00017 #include <errno.h>
00018 
00019 #if HAVE_STRING_H
00020 #include <string.h>
00021 #else
00022 #include <strings.h>
00023 #endif
00024 #if HAVE_STDLIB_H
00025 #include <stdlib.h>
00026 #endif
00027 #if HAVE_UNISTD_H
00028 #include <unistd.h>
00029 #endif
00030 #if HAVE_SYS_SOCKET_H
00031 #include <sys/socket.h>
00032 #endif
00033 #if HAVE_NETINET_IN_H
00034 #include <netinet/in.h>
00035 #endif
00036 #if HAVE_ARPA_INET_H
00037 #include <arpa/inet.h>
00038 #endif
00039 #if HAVE_NETDB_H
00040 #include <netdb.h>
00041 #endif
00042 #if HAVE_SYS_UIO_H
00043 #include <sys/uio.h>
00044 #endif
00045 
00046 #if HAVE_WINSOCK_H
00047 #include <winsock2.h>
00048 #include <ws2tcpip.h>
00049 #endif
00050 
00051 #if HAVE_DMALLOC_H
00052 #include <dmalloc.h>
00053 #endif
00054 
00055 #include <net-snmp/types.h>
00056 #include <net-snmp/output_api.h>
00057 #include <net-snmp/config_api.h>
00058 
00059 #include <net-snmp/library/snmp_transport.h>
00060 #include <net-snmp/library/snmpUDPDomain.h>
00061 #include <net-snmp/library/system.h>
00062 #include <net-snmp/library/tools.h>
00063 
00064 #ifndef INADDR_NONE
00065 #define INADDR_NONE     -1
00066 #endif
00067 
00068 static netsnmp_tdomain udpDomain;
00069 
00070 typedef struct netsnmp_udp_addr_pair_s {
00071     struct sockaddr_in remote_addr;
00072     struct in_addr local_addr;
00073 } netsnmp_udp_addr_pair;
00074 
00075 /*
00076  * not static, since snmpUDPIPv6Domain needs it, but not public, either.
00077  * (ie don't put it in a public header.)
00078  */
00079 void _netsnmp_udp_sockopt_set(int fd, int server);
00080 int
00081 netsnmp_sockaddr_in2(struct sockaddr_in *addr,
00082                      const char *inpeername, const char *default_target);
00083 
00084 /*
00085  * Return a string representing the address in data, or else the "far end"
00086  * address if data is NULL.  
00087  */
00088 
00089 static char *
00090 netsnmp_udp_fmtaddr(netsnmp_transport *t, void *data, int len)
00091 {
00092     netsnmp_udp_addr_pair *addr_pair = NULL;
00093 
00094     if (data != NULL && len == sizeof(netsnmp_udp_addr_pair)) {
00095         addr_pair = (netsnmp_udp_addr_pair *) data;
00096     } else if (t != NULL && t->data != NULL) {
00097         addr_pair = (netsnmp_udp_addr_pair *) t->data;
00098     }
00099 
00100     if (addr_pair == NULL) {
00101         return strdup("UDP: unknown");
00102     } else {
00103         struct sockaddr_in *to = NULL;
00104         char tmp[64];
00105         to = (struct sockaddr_in *) &(addr_pair->remote_addr);
00106         if (to == NULL) {
00107             return strdup("UDP: unknown");
00108         }
00109 
00110         sprintf(tmp, "UDP: [%s]:%hu",
00111                 inet_ntoa(to->sin_addr), ntohs(to->sin_port));
00112         return strdup(tmp);
00113     }
00114 }
00115 
00116 
00117 
00118 #if defined(linux) && defined(IP_PKTINFO)
00119 
00120 # define netsnmp_dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))
00121 
00122 static int netsnmp_udp_recvfrom(int s, void *buf, int len, struct sockaddr *from, socklen_t *fromlen, struct in_addr *dstip)
00123 {
00124     int r;
00125     struct iovec iov[1];
00126     char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
00127     struct cmsghdr *cmsgptr;
00128     struct msghdr msg;
00129 
00130     iov[0].iov_base = buf;
00131     iov[0].iov_len = len;
00132 
00133     memset(&msg, 0, sizeof msg);
00134     msg.msg_name = from;
00135     msg.msg_namelen = *fromlen;
00136     msg.msg_iov = iov;
00137     msg.msg_iovlen = 1;
00138     msg.msg_control = &cmsg;
00139     msg.msg_controllen = sizeof(cmsg);
00140 
00141     r = recvmsg(s, &msg, 0);
00142 
00143     if (r == -1) {
00144         return -1;
00145     }
00146     
00147     DEBUGMSGTL(("netsnmp_udp", "got source addr: %s\n", inet_ntoa(((struct sockaddr_in *)from)->sin_addr)));
00148     for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
00149         if (cmsgptr->cmsg_level == SOL_IP && cmsgptr->cmsg_type == IP_PKTINFO) {
00150             memcpy((void *) dstip, netsnmp_dstaddr(cmsgptr), sizeof(struct in_addr));
00151             DEBUGMSGTL(("netsnmp_udp", "got destination (local) addr %s\n",
00152                     inet_ntoa(*dstip)));
00153         }
00154     }
00155     return r;
00156 }
00157 
00158 static int netsnmp_udp_sendto(int fd, struct in_addr *srcip, struct sockaddr *remote,
00159                         void *data, int len)
00160 {
00161     struct iovec iov = { data, len };
00162     struct {
00163         struct cmsghdr cm;
00164         struct in_pktinfo ipi;
00165     } cmsg;
00166     struct msghdr m;
00167 
00168     cmsg.cm.cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
00169     cmsg.cm.cmsg_level = SOL_IP;
00170     cmsg.cm.cmsg_type = IP_PKTINFO;
00171     cmsg.ipi.ipi_ifindex = 0;
00172     cmsg.ipi.ipi_spec_dst.s_addr = (srcip ? srcip->s_addr : INADDR_ANY);
00173 
00174     m.msg_name          = remote;
00175     m.msg_namelen       = sizeof(struct sockaddr_in);
00176     m.msg_iov           = &iov;
00177     m.msg_iovlen        = 1;
00178     m.msg_control       = &cmsg;
00179     m.msg_controllen    = sizeof(cmsg);
00180     m.msg_flags         = 0;
00181 
00182     return sendmsg(fd, &m, MSG_NOSIGNAL|MSG_DONTWAIT);
00183 }
00184 #endif /* linux && IP_PKTINFO */
00185 
00186 /*
00187  * You can write something into opaque that will subsequently get passed back 
00188  * to your send function if you like.  For instance, you might want to
00189  * remember where a PDU came from, so that you can send a reply there...  
00190  */
00191 
00192 static int
00193 netsnmp_udp_recv(netsnmp_transport *t, void *buf, int size,
00194                  void **opaque, int *olength)
00195 {
00196     int             rc = -1;
00197     socklen_t       fromlen = sizeof(struct sockaddr);
00198     netsnmp_udp_addr_pair *addr_pair = NULL;
00199     struct sockaddr *from;
00200 
00201     if (t != NULL && t->sock >= 0) {
00202         addr_pair = (netsnmp_udp_addr_pair *) malloc(sizeof(netsnmp_udp_addr_pair));
00203         if (addr_pair == NULL) {
00204             *opaque = NULL;
00205             *olength = 0;
00206             return -1;
00207         } else {
00208             memset(addr_pair, 0, sizeof(netsnmp_udp_addr_pair));
00209             from = (struct sockaddr *) &(addr_pair->remote_addr);
00210         }
00211 
00212         while (rc < 0) {
00213 #if defined(linux) && defined(IP_PKTINFO)
00214             rc = netsnmp_udp_recvfrom(t->sock, buf, size, from, &fromlen, &(addr_pair->local_addr));
00215 #else
00216             rc = recvfrom(t->sock, buf, size, 0, from, &fromlen);
00217 #endif /* linux && IP_PKTINFO */
00218             if (rc < 0 && errno != EINTR) {
00219                 break;
00220             }
00221         }
00222 
00223         if (rc >= 0) {
00224             char *str = netsnmp_udp_fmtaddr(NULL, addr_pair, sizeof(netsnmp_udp_addr_pair));
00225             DEBUGMSGTL(("netsnmp_udp",
00226                         "recvfrom fd %d got %d bytes (from %s)\n",
00227                         t->sock, rc, str));
00228             free(str);
00229         } else {
00230             DEBUGMSGTL(("netsnmp_udp", "recvfrom fd %d err %d (\"%s\")\n",
00231                         t->sock, errno, strerror(errno)));
00232         }
00233         *opaque = (void *)addr_pair;
00234         *olength = sizeof(netsnmp_udp_addr_pair);
00235     }
00236     return rc;
00237 }
00238 
00239 
00240 
00241 static int
00242 netsnmp_udp_send(netsnmp_transport *t, void *buf, int size,
00243                  void **opaque, int *olength)
00244 {
00245     int rc = -1;
00246     netsnmp_udp_addr_pair *addr_pair = NULL;
00247     struct sockaddr *to = NULL;
00248 
00249     if (opaque != NULL && *opaque != NULL &&
00250         *olength == sizeof(netsnmp_udp_addr_pair)) {
00251         addr_pair = (netsnmp_udp_addr_pair *) (*opaque);
00252     } else if (t != NULL && t->data != NULL &&
00253                 t->data_length == sizeof(netsnmp_udp_addr_pair)) {
00254         addr_pair = (netsnmp_udp_addr_pair *) (t->data);
00255     }
00256 
00257     to = (struct sockaddr *) &(addr_pair->remote_addr);
00258 
00259     if (to != NULL && t != NULL && t->sock >= 0) {
00260         char *str = netsnmp_udp_fmtaddr(NULL, (void *) addr_pair,
00261                                         sizeof(netsnmp_udp_addr_pair));
00262         DEBUGMSGTL(("netsnmp_udp", "send %d bytes from %p to %s on fd %d\n",
00263                     size, buf, str, t->sock));
00264         free(str);
00265         while (rc < 0) {
00266 #if defined(linux) && defined(IP_PKTINFO)
00267             rc = netsnmp_udp_sendto(t->sock, addr_pair ? &(addr_pair->local_addr) : NULL, to, buf, size);
00268 #else
00269             rc = sendto(t->sock, buf, size, 0, to, sizeof(struct sockaddr));
00270 #endif /* linux && IP_PKTINFO */
00271             if (rc < 0 && errno != EINTR) {
00272                 DEBUGMSGTL(("netsnmp_udp", "sendto error, rc %d (errno %d)\n",
00273                             rc, errno));
00274                 break;
00275             }
00276         }
00277     }
00278     return rc;
00279 }
00280 
00281 
00282 
00283 static int
00284 netsnmp_udp_close(netsnmp_transport *t)
00285 {
00286     int rc = -1;
00287     if (t->sock >= 0) {
00288 #ifndef HAVE_CLOSESOCKET
00289         rc = close(t->sock);
00290 #else
00291         rc = closesocket(t->sock);
00292 #endif
00293         t->sock = -1;
00294     }
00295     return rc;
00296 }
00297 
00298 /*
00299  * find largest possible buffer between current size and specified size.
00300  *
00301  * Try to maximize the current buffer of type "optname"
00302  * to the maximum allowable size by the OS (as close to
00303  * size as possible)
00304  */
00305 static int
00306 _sock_buffer_maximize(int s, int optname, const char *buftype, int size)
00307 {
00308     int            curbuf = 0;
00309     size_t         curbuflen = sizeof(int);
00310     int            lo, mid, hi;
00311 
00312     /*
00313      * First we need to determine our current buffer
00314      */
00315     if ((getsockopt(s, SOL_SOCKET, optname, (void *) &curbuf,
00316                     &curbuflen) == 0) 
00317             && (curbuflen == sizeof(int))) {
00318 
00319         DEBUGMSGTL(("verbose:socket:buffer:max", "Current %s is %d\n",
00320                     buftype, curbuf));
00321 
00322         /*
00323          * Let's not be stupid ... if we were asked for less than what we
00324          * already have, then forget about it
00325          */
00326         if (size <= curbuf) {
00327             DEBUGMSGTL(("verbose:socket:buffer:max",
00328                         "Requested %s <= current buffer\n", buftype));
00329             return curbuf;
00330         }
00331 
00332         /*
00333          * Do a binary search the optimal buffer within 1k of the point of
00334          * failure. This is rather bruteforce, but simple
00335          */
00336         hi = size;
00337         lo = curbuf;
00338 
00339         while (hi - lo > 1024) {
00340             mid = (lo + hi) / 2;
00341             if (setsockopt(s, SOL_SOCKET, optname, (void *) &mid,
00342                         sizeof(int)) == 0) {
00343                 lo = mid; /* Success: search between mid and hi */
00344             } else {
00345                 hi = mid; /* Failed: search between lo and mid */
00346             }
00347         }
00348 
00349         /*
00350          * Now print if this optimization helped or not
00351          */
00352         if (getsockopt(s,SOL_SOCKET, optname, (void *) &curbuf,
00353                     &curbuflen) == 0) {
00354             DEBUGMSGTL(("socket:buffer:max", 
00355                         "Maximized %s: %d\n",buftype, curbuf));
00356         } 
00357     } else {
00358         /*
00359          * There is really not a lot we can do anymore.
00360          * If the OS doesn't give us the current buffer, then what's the 
00361          * point in trying to make it better
00362          */
00363         DEBUGMSGTL(("socket:buffer:max", "Get %s failed ... giving up!\n",
00364                     buftype));
00365         curbuf = -1;
00366     }
00367 
00368     return curbuf;
00369 }
00370 
00371 
00372 static const char *
00373 _sock_buf_type_get(int optname, int local)
00374 {
00375     if (optname == SO_SNDBUF) {
00376         if (local)
00377             return "server send buffer";
00378         else
00379             return "client send buffer";
00380     } else if (optname == SO_RCVBUF) {
00381         if (local)
00382             return "server receive buffer";
00383         else
00384             return "client receive buffer";
00385     }
00386 
00387     return "unknown buffer";
00388 }
00389 
00390 /*
00391  *
00392  * Get the requested buffersize, based on
00393  * - sockettype : client (local = 0) or server (local = 1) 
00394  * - buffertype : send (optname = SO_SNDBUF) or recv (SO_RCVBUF)
00395  *
00396  * In case a compile time buffer was specified, then use that one
00397  * if there was no runtime configuration override
00398  */
00399 static int
00400 _sock_buffer_size_get(int optname, int local, const char **buftype)
00401 {
00402     int size;
00403 
00404     if (NULL != buftype)
00405         *buftype = _sock_buf_type_get(optname, local);
00406 
00407     if (optname == SO_SNDBUF) {
00408         if (local) {
00409             size = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
00410                     NETSNMP_DS_LIB_SERVERSENDBUF);
00411 #ifdef NETSNMP_DEFAULT_SERVER_SEND_BUF
00412             if (size <= 0)
00413                size = NETSNMP_DEFAULT_SERVER_SEND_BUF;
00414 #endif
00415         } else {
00416             size = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
00417                     NETSNMP_DS_LIB_CLIENTSENDBUF);
00418 #ifdef NETSNMP_DEFAULT_CLIENT_SEND_BUF
00419             if (size <= 0)
00420                size = NETSNMP_DEFAULT_CLIENT_SEND_BUF;
00421 #endif
00422         }
00423     } else if (optname == SO_RCVBUF) {
00424         if (local) {
00425             size = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
00426                     NETSNMP_DS_LIB_SERVERRECVBUF);
00427 #ifdef NETSNMP_DEFAULT_SERVER_RECV_BUF
00428             if (size <= 0)
00429                size = NETSNMP_DEFAULT_SERVER_RECV_BUF;
00430 #endif
00431         } else {
00432             size = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
00433                     NETSNMP_DS_LIB_CLIENTRECVBUF);
00434 #ifdef NETSNMP_DEFAULT_CLIENT_RECV_BUF
00435             if (size <= 0)
00436                size = NETSNMP_DEFAULT_CLIENT_RECV_BUF;
00437 #endif
00438         }
00439     } else {
00440         size = 0;
00441     }
00442 
00443     DEBUGMSGTL(("socket:buffer", "Requested %s is %d\n",
00444                 (buftype) ? *buftype : "unknown buffer", size));
00445 
00446     return(size);
00447 }
00448 
00449 /*
00450  * set socket buffer size
00451  *
00452  * @param ss     : socket
00453  * @param optname: SO_SNDBUF or SO_RCVBUF
00454  * @param local  : 1 for server, 0 for client
00455  * @param reqbuf : requested size, or 0 for default
00456  *
00457  * @retval    -1 : error
00458  * @retval    >0 : new buffer size
00459  */
00460 int
00461 netsnmp_sock_buffer_set(int s, int optname, int local, int size)
00462 {
00463 #if ! defined(SO_SNDBUF) && ! defined(SO_RCVBUF)
00464     DEBUGMSGTL(("socket:buffer", "Changing socket buffer is not supported\n"));
00465     return -1;
00466 #else
00467     const char     *buftype;
00468     int            curbuf = 0;
00469     size_t         curbuflen = sizeof(int);
00470 
00471 #   ifndef  SO_SNDBUF
00472     if (SO_SNDBUF == optname) {
00473         DEBUGMSGTL(("socket:buffer",
00474                     "Changing socket send buffer is not supported\n"));
00475         return -1;
00476     }
00477 #   endif                          /*SO_SNDBUF */
00478 #   ifndef  SO_RCVBUF
00479     if (SO_RCVBUF == optname) {
00480         DEBUGMSGTL(("socket:buffer",
00481                     "Changing socket receive buffer is not supported\n"));
00482         return -1;
00483     }
00484 #   endif                          /*SO_RCVBUF */
00485 
00486     /*
00487      * What is the requested buffer size ?
00488      */
00489     if (0 == size)
00490         size = _sock_buffer_size_get(optname, local, &buftype);
00491     else {
00492         buftype = _sock_buf_type_get(optname, local);
00493         DEBUGMSGT(("verbose:socket:buffer", "Requested %s is %d\n",
00494                    buftype, size));
00495     }
00496 
00497     if ((getsockopt(s, SOL_SOCKET, optname, (void *) &curbuf,
00498                     &curbuflen) == 0) 
00499         && (curbuflen == sizeof(int))) {
00500         
00501         DEBUGMSGT(("verbose:socket:buffer", "Original %s is %d\n",
00502                    buftype, curbuf));
00503         if (curbuf >= size) {
00504             DEBUGMSGT(("verbose:socket:buffer",
00505                       "New %s size is smaller than original!\n", buftype));
00506         }
00507     }
00508 
00509     /*
00510      * If the buffersize was not specified or it was a negative value
00511      * then don't change the OS buffers at all
00512      */
00513     if (size <= 0) {
00514        DEBUGMSGT(("socket:buffer",
00515                     "%s not valid or not specified; using OS default(%d)\n",
00516                     buftype,curbuf));
00517        return curbuf;
00518     }
00519 
00520     /*
00521      * Try to set the requested send buffer
00522      */
00523     if (setsockopt(s, SOL_SOCKET, optname, (void *) &size, sizeof(int)) == 0) {
00524         /*
00525          * Because some platforms lie about the actual buffer that has been 
00526          * set (Linux will always say it worked ...), we print some 
00527          * diagnostic output for debugging
00528          */
00529         DEBUGIF("socket:buffer") {
00530             DEBUGMSGT(("socket:buffer", "Set %s to %d\n",
00531                        buftype, size));
00532             if ((getsockopt(s, SOL_SOCKET, optname, (void *) &curbuf,
00533                             &curbuflen) == 0) 
00534                     && (curbuflen == sizeof(int))) {
00535 
00536                 DEBUGMSGT(("verbose:socket:buffer",
00537                            "Now %s is %d\n", buftype, curbuf));
00538             }
00539         }
00540         /*
00541          * If the new buffer is smaller than the size we requested, we will
00542          * try to increment the new buffer with 1k increments 
00543          * (this will sometime allow us to reach a more optimal buffer.)
00544          *   For example : On Solaris, if the max OS buffer is 100k and you
00545          *   request 110k, you end up with the default 8k :-(
00546          */
00547         if (curbuf < size) {
00548             curbuf = _sock_buffer_maximize(s, optname, buftype, size);
00549             if(-1 != curbuf)
00550                 size = curbuf;
00551         }
00552 
00553     } else {
00554         /*
00555          * Obviously changing the buffer failed, most like like because we 
00556          * requested a buffer greater than the OS limit.
00557          * Therefore we need to search for an optimal buffer that is close
00558          * enough to the point of failure.
00559          * This will allow us to reach a more optimal buffer.
00560          *   For example : On Solaris, if the max OS buffer is 100k and you 
00561          *   request 110k, you end up with the default 8k :-(
00562          *   After this quick seach we would get 1k close to 100k (the max)
00563          */
00564         DEBUGMSGTL(("socket:buffer", "couldn't set %s to %d\n",
00565                     buftype, size));
00566 
00567         curbuf = _sock_buffer_maximize(s, optname, buftype, size);
00568         if(-1 != curbuf)
00569             size = curbuf;
00570     }
00571 
00572     return size;
00573 #endif
00574 }
00575 
00576 /*
00577  * Open a UDP-based transport for SNMP.  Local is TRUE if addr is the local
00578  * address to bind to (i.e. this is a server-type session); otherwise addr is 
00579  * the remote address to send things to.  
00580  */
00581 
00582 netsnmp_transport *
00583 netsnmp_udp_transport(struct sockaddr_in *addr, int local)
00584 {
00585     netsnmp_transport *t = NULL;
00586     int             rc = 0;
00587     char           *str = NULL;
00588     char           *client_socket = NULL;
00589     netsnmp_udp_addr_pair addr_pair;
00590 
00591     if (addr == NULL || addr->sin_family != AF_INET) {
00592         return NULL;
00593     }
00594 
00595     memset(&addr_pair, 0, sizeof(netsnmp_udp_addr_pair));
00596     memcpy(&(addr_pair.remote_addr), addr, sizeof(struct sockaddr_in));
00597 
00598     t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
00599     if (t == NULL) {
00600         return NULL;
00601     }
00602 
00603     str = netsnmp_udp_fmtaddr(NULL, (void *)&addr_pair,
00604                                  sizeof(netsnmp_udp_addr_pair));
00605     DEBUGMSGTL(("netsnmp_udp", "open %s %s\n", local ? "local" : "remote",
00606                 str));
00607     free(str);
00608 
00609     memset(t, 0, sizeof(netsnmp_transport));
00610 
00611     t->domain = netsnmpUDPDomain;
00612     t->domain_length = netsnmpUDPDomain_len;
00613 
00614     t->sock = socket(PF_INET, SOCK_DGRAM, 0);
00615     if (t->sock < 0) {
00616         netsnmp_transport_free(t);
00617         return NULL;
00618     }
00619 
00620     _netsnmp_udp_sockopt_set(t->sock, local);
00621 
00622     if (local) {
00623         /*
00624          * This session is inteneded as a server, so we must bind on to the
00625          * given IP address, which may include an interface address, or could
00626          * be INADDR_ANY, but certainly includes a port number.
00627          */
00628 
00629       t->local = (u_char *) malloc(6);
00630         if (t->local == NULL) {
00631             netsnmp_transport_free(t);
00632             return NULL;
00633         }
00634         memcpy(t->local, (u_char *) & (addr->sin_addr.s_addr), 4);
00635         t->local[4] = (htons(addr->sin_port) & 0xff00) >> 8;
00636         t->local[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
00637         t->local_length = 6;
00638 
00639 #if defined(linux) && defined(IP_PKTINFO)
00640         { 
00641             int sockopt = 1;
00642             if (setsockopt(t->sock, SOL_IP, IP_PKTINFO, &sockopt, sizeof sockopt) == -1) {
00643                 DEBUGMSGTL(("netsnmp_udp", "couldn't set IP_PKTINFO: %s\n",
00644                     strerror(errno)));
00645                 return NULL;
00646             }
00647             DEBUGMSGTL(("netsnmp_udp", "set IP_PKTINFO\n"));
00648         }
00649 #endif
00650         rc = bind(t->sock, (struct sockaddr *) addr,
00651                   sizeof(struct sockaddr));
00652         if (rc != 0) {
00653             netsnmp_udp_close(t);
00654             netsnmp_transport_free(t);
00655             return NULL;
00656         }
00657         t->data = NULL;
00658         t->data_length = 0;
00659     } else {
00660         /*
00661          * This is a client session.  If we've been given a
00662          * client address to send from, then bind to that.
00663          * Otherwise the send will use "something sensible".
00664          */
00665         client_socket = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
00666                                               NETSNMP_DS_LIB_CLIENT_ADDR);
00667         if (client_socket) {
00668             struct sockaddr_in client_addr;
00669             netsnmp_sockaddr_in2(&client_addr, client_socket, NULL);
00670             client_addr.sin_port = 0;
00671             bind(t->sock, (struct sockaddr *)&client_addr,
00672                   sizeof(struct sockaddr));
00673         }
00674         /*
00675          * Save the (remote) address in the
00676          * transport-specific data pointer for later use by netsnmp_udp_send.
00677          */
00678 
00679         t->data = malloc(sizeof(netsnmp_udp_addr_pair));
00680         t->remote = (u_char *)malloc(6);
00681         if (t->data == NULL || t->remote == NULL) {
00682             netsnmp_transport_free(t);
00683             return NULL;
00684         }
00685         memcpy(t->remote, (u_char *) & (addr->sin_addr.s_addr), 4);
00686         t->remote[4] = (htons(addr->sin_port) & 0xff00) >> 8;
00687         t->remote[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
00688         t->remote_length = 6;
00689         memcpy(t->data, &addr_pair, sizeof(netsnmp_udp_addr_pair));
00690         t->data_length = sizeof(netsnmp_udp_addr_pair);
00691     }
00692 
00693     /*
00694      * 16-bit length field, 8 byte UDP header, 20 byte IPv4 header  
00695      */
00696 
00697     t->msgMaxSize = 0xffff - 8 - 20;
00698     t->f_recv     = netsnmp_udp_recv;
00699     t->f_send     = netsnmp_udp_send;
00700     t->f_close    = netsnmp_udp_close;
00701     t->f_accept   = NULL;
00702     t->f_fmtaddr  = netsnmp_udp_fmtaddr;
00703 
00704     return t;
00705 }
00706 
00707 
00708 void
00709 _netsnmp_udp_sockopt_set(int fd, int local)
00710 {
00711 #ifdef  SO_BSDCOMPAT
00712     /*
00713      * Patch for Linux.  Without this, UDP packets that fail get an ICMP
00714      * response.  Linux turns the failed ICMP response into an error message
00715      * and return value, unlike all other OS's.  
00716      */
00717     if (0 == netsnmp_os_prematch("Linux","2.4"))
00718     {
00719         int             one = 1;
00720         DEBUGMSGTL(("socket:option", "setting socket option SO_BSDCOMPAT\n"));
00721         setsockopt(fd, SOL_SOCKET, SO_BSDCOMPAT, (void *) &one,
00722                    sizeof(one));
00723     }
00724 #endif                          /*SO_BSDCOMPAT */
00725     /*
00726      * SO_REUSEADDR will allow multiple apps to open the same port at
00727      * the same time. Only the last one to open the socket will get
00728      * data. Obviously, for an agent, this is a bad thing. There should
00729      * only be one listener.
00730      */
00731 #ifdef ALLOW_PORT_HIJACKING
00732 #ifdef  SO_REUSEADDR
00733     /*
00734      * Allow the same port to be specified multiple times without failing.
00735      *    (useful for a listener)
00736      */
00737     {
00738         int             one = 1;
00739         DEBUGMSGTL(("socket:option", "setting socket option SO_REUSEADDR\n"));
00740         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &one,
00741                    sizeof(one));
00742     }
00743 #endif                          /*SO_REUSEADDR */
00744 #endif
00745 
00746     /*
00747      * Try to set the send and receive buffers to a reasonably large value, so
00748      * that we can send and receive big PDUs (defaults to 8192 bytes (!) on
00749      * Solaris, for instance).  Don't worry too much about errors -- just
00750      * plough on regardless.  
00751      */
00752     netsnmp_sock_buffer_set(fd, SO_SNDBUF, local, 0);
00753     netsnmp_sock_buffer_set(fd, SO_RCVBUF, local, 0);
00754 }
00755 
00756 int
00757 netsnmp_sockaddr_in2(struct sockaddr_in *addr,
00758                      const char *inpeername, const char *default_target)
00759 {
00760 #if HAVE_GETADDRINFO
00761     struct addrinfo *addrs = NULL;
00762     struct addrinfo hint;
00763     int             err;
00764 #elif HAVE_GETIPNODEBYNAME
00765     struct hostent *hp = NULL;
00766     int             err;
00767 #elif HAVE_GETHOSTBYNAME
00768     struct hostent *hp = NULL;
00769 #endif
00770 
00771     if (addr == NULL) {
00772         return 0;
00773     }
00774 
00775     DEBUGMSGTL(("netsnmp_sockaddr_in",
00776                 "addr %p, inpeername \"%s\", default_target \"%s\"\n",
00777                 addr, inpeername ? inpeername : "[NIL]",
00778                 default_target ? default_target : "[NIL]"));
00779 
00780     memset(addr, 0, sizeof(struct sockaddr_in));
00781     addr->sin_addr.s_addr = htonl(INADDR_ANY);
00782     addr->sin_family = AF_INET;
00783     addr->sin_port = htons((u_short)SNMP_PORT);
00784 
00785     {
00786         int port = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
00787                                       NETSNMP_DS_LIB_DEFAULT_PORT);
00788 
00789         if (port != 0) {
00790             addr->sin_port = htons((u_short)port);
00791         } else if (default_target != NULL)
00792             netsnmp_sockaddr_in2(addr, default_target, NULL);
00793     }
00794 
00795     if (inpeername != NULL && *inpeername != '\0') {
00796         const char     *host, *port;
00797         char           *peername = NULL;
00798         char           *cp;
00799         /*
00800          * Duplicate the peername because we might want to mank around with
00801          * it.  
00802          */
00803 
00804         peername = strdup(inpeername);
00805         if (peername == NULL) {
00806             return 0;
00807         }
00808 
00809         /*
00810          * Try and extract an appended port number.  
00811          */
00812         cp = strchr(peername, ':');
00813         if (cp != NULL) {
00814             *cp = '\0';
00815             port = cp + 1;
00816             host = peername;
00817         } else {
00818             host = NULL;
00819             port = peername;
00820         }
00821 
00822         /*
00823          * Try to convert the user port specifier
00824          */
00825         if (port && *port == '\0')
00826             port = NULL;
00827 
00828         if (port != NULL) {
00829             long int l;
00830             char* ep;
00831 
00832             DEBUGMSGTL(("netsnmp_sockaddr_in", "check user service %s\n",
00833                         port));
00834 
00835             l = strtol(port, &ep, 10);
00836             if (ep != port && *ep == '\0' && 0 <= l && l <= 0x0ffff)
00837                 addr->sin_port = htons((u_short)l);
00838             else {
00839                 if (host == NULL) {
00840                     DEBUGMSGTL(("netsnmp_sockaddr_in",
00841                                 "servname not numeric, "
00842                                 "check if it really is a destination)"));
00843                     host = port;
00844                     port = NULL;
00845                 } else {
00846                     DEBUGMSGTL(("netsnmp_sockaddr_in",
00847                                 "servname not numeric"));
00848                     free(peername);
00849                     return 0;
00850                 }
00851             }
00852         }
00853 
00854         /*
00855          * Try to convert the user host specifier
00856          */
00857         if (host && *host == '\0')
00858             host = NULL;
00859 
00860         if (host != NULL) {
00861             DEBUGMSGTL(("netsnmp_sockaddr_in",
00862                         "check destination %s\n", host));
00863 
00864 #if HAVE_GETADDRINFO
00865             memset(&hint, 0, sizeof hint);
00866             hint.ai_flags = 0;
00867             hint.ai_family = PF_INET;
00868             hint.ai_socktype = SOCK_DGRAM;
00869             hint.ai_protocol = 0;
00870 
00871             err = getaddrinfo(peername, NULL, &hint, &addrs);
00872             if (err != 0) {
00873 #if HAVE_GAI_STRERROR
00874                 snmp_log(LOG_ERR, "getaddrinfo: %s %s\n", peername,
00875                          gai_strerror(err));
00876 #else
00877                 snmp_log(LOG_ERR, "getaddrinfo: %s (error %d)\n", peername,
00878                          err);
00879 #endif
00880                 free(peername);
00881                 return 0;
00882             }
00883             if (addrs != NULL) {
00884                 DEBUGMSGTL(("netsnmp_sockaddr_in",
00885                             "hostname (resolved okay)\n"));
00886                 memcpy(&addr->sin_addr,
00887                        &((struct sockaddr_in *) addrs->ai_addr)->sin_addr,
00888                        sizeof(struct in_addr));
00889                 freeaddrinfo(addrs);
00890             }
00891             else {
00892                 DEBUGMSGTL(("netsnmp_sockaddr_in",
00893                             "Failed to resolve IPv4 hostname\n"));
00894             }
00895 #elif HAVE_GETHOSTBYNAME
00896             hp = gethostbyname(host);
00897             if (hp == NULL) {
00898                 DEBUGMSGTL(("netsnmp_sockaddr_in",
00899                             "hostname (couldn't resolve)\n"));
00900                 free(peername);
00901                 return 0;
00902             } else if (hp->h_addrtype != AF_INET) {
00903                 DEBUGMSGTL(("netsnmp_sockaddr_in",
00904                             "hostname (not AF_INET!)\n"));
00905                 free(peername);
00906                 return 0;
00907             } else {
00908                 DEBUGMSGTL(("netsnmp_sockaddr_in",
00909                             "hostname (resolved okay)\n"));
00910                 memcpy(&addr->sin_addr, hp->h_addr, hp->h_length);
00911             }
00912 #elif HAVE_GETIPNODEBYNAME
00913             hp = getipnodebyname(peername, AF_INET, 0, &err);
00914             if (hp == NULL) {
00915                 DEBUGMSGTL(("netsnmp_sockaddr_in",
00916                             "hostname (couldn't resolve = %d)\n", err));
00917                 free(peername);
00918                 return 0;
00919             }
00920             DEBUGMSGTL(("netsnmp_sockaddr_in",
00921                         "hostname (resolved okay)\n"));
00922             memcpy(&(addr->sin_addr), hp->h_addr, hp->h_length);
00923 #else /* HAVE_GETIPNODEBYNAME */
00924             /*
00925              * There is no name resolving function available.
00926              */
00927             DEBUGMSGTL(("netsnmp_sockaddr_in",
00928                         "no getaddrinfo()/getipnodebyname()/gethostbyname()\n"));
00929             free(peername);
00930             return 0;
00931 #endif /* HAVE_GETHOSTBYNAME */
00932         }
00933         free(peername);
00934     }
00935 
00936     /*
00937      * Finished
00938      */
00939 
00940     DEBUGMSGTL(("netsnmp_sockaddr_in", "return { AF_INET, %s:%hu }\n",
00941                 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port)));
00942     return 1;
00943 }
00944 
00945 
00946 int
00947 netsnmp_sockaddr_in(struct sockaddr_in *addr,
00948                     const char *inpeername, int remote_port)
00949 {
00950     char buf[sizeof(int) * 3 + 2];
00951     sprintf(buf, ":%u", remote_port);
00952     return netsnmp_sockaddr_in2(addr, inpeername, remote_port ? buf : NULL);
00953 }
00954 
00955 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
00956 /*
00957  * The following functions provide the "com2sec" configuration token
00958  * functionality for compatibility.  
00959  */
00960 
00961 #define EXAMPLE_NETWORK         "NETWORK"
00962 #define EXAMPLE_COMMUNITY       "COMMUNITY"
00963 
00964 typedef struct _com2SecEntry {
00965     char            community[COMMUNITY_MAX_LEN];
00966     unsigned long   network;
00967     unsigned long   mask;
00968     char            secName[VACMSTRINGLEN];
00969     char            contextName[VACMSTRINGLEN];
00970     struct _com2SecEntry *next;
00971 } com2SecEntry;
00972 
00973 com2SecEntry   *com2SecList = NULL, *com2SecListLast = NULL;
00974 
00975 void
00976 netsnmp_udp_parse_security(const char *token, char *param)
00977 {
00978     char            secName[VACMSTRINGLEN];
00979     char            contextName[VACMSTRINGLEN];
00980     char            community[COMMUNITY_MAX_LEN];
00981     char            source[SNMP_MAXBUF_SMALL];
00982     char           *cp = NULL;
00983     const char     *strmask = NULL;
00984     com2SecEntry   *e = NULL;
00985     in_addr_t   network = 0, mask = 0;
00986 
00987     /*
00988      * Get security, source address/netmask and community strings.  
00989      */
00990 
00991     cp = copy_nword( param, secName, sizeof(secName));
00992     if (strcmp(secName, "-Cn") == 0) {
00993         if (!cp) {
00994             config_perror("missing CONTEXT_NAME parameter");
00995             return;
00996         }
00997         cp = copy_nword( cp, contextName, sizeof(contextName));
00998         cp = copy_nword( cp, secName, sizeof(secName));
00999     } else {
01000         contextName[0] = '\0';
01001     }
01002     if (secName[0] == '\0') {
01003         config_perror("missing NAME parameter");
01004         return;
01005     } else if (strlen(secName) > (VACMSTRINGLEN - 1)) {
01006         config_perror("security name too long");
01007         return;
01008     }
01009     cp = copy_nword( cp, source, sizeof(source));
01010     if (source[0] == '\0') {
01011         config_perror("missing SOURCE parameter");
01012         return;
01013     } else if (strncmp(source, EXAMPLE_NETWORK, strlen(EXAMPLE_NETWORK)) ==
01014                0) {
01015         config_perror("example config NETWORK not properly configured");
01016         return;
01017     }
01018     cp = copy_nword( cp, community, sizeof(community));
01019     if (community[0] == '\0') {
01020         config_perror("missing COMMUNITY parameter\n");
01021         return;
01022     } else
01023         if (strncmp
01024             (community, EXAMPLE_COMMUNITY, strlen(EXAMPLE_COMMUNITY))
01025             == 0) {
01026         config_perror("example config COMMUNITY not properly configured");
01027         return;
01028     } else if (strlen(community) > (COMMUNITY_MAX_LEN - 1)) {
01029         config_perror("community name too long");
01030         return;
01031     }
01032 
01033     /*
01034      * Process the source address/netmask string.  
01035      */
01036 
01037     cp = strchr(source, '/');
01038     if (cp != NULL) {
01039         /*
01040          * Mask given.  
01041          */
01042         *cp = '\0';
01043         strmask = cp + 1;
01044     }
01045 
01046     /*
01047      * Deal with the network part first.  
01048      */
01049 
01050     if ((strcmp(source, "default") == 0)
01051         || (strcmp(source, "0.0.0.0") == 0)) {
01052         network = 0;
01053         strmask = "0.0.0.0";
01054     } else {
01055         /*
01056          * Try interpreting as a dotted quad.  
01057          */
01058         network = inet_addr(source);
01059 
01060         if (network == (in_addr_t) -1) {
01061             /*
01062              * Nope, wasn't a dotted quad.  Must be a hostname.  
01063              */
01064 #ifdef  HAVE_GETHOSTBYNAME
01065             struct hostent *hp = gethostbyname(source);
01066             if (hp == NULL) {
01067                 config_perror("bad source address");
01068                 return;
01069             } else {
01070                 if (hp->h_addrtype != AF_INET) {
01071                     config_perror("no IP address for source hostname");
01072                     return;
01073                 }
01074                 network = *((in_addr_t *) hp->h_addr);
01075             }
01076 #else                           /*HAVE_GETHOSTBYNAME */
01077             /*
01078              * Oh dear.  
01079              */
01080             config_perror("cannot resolve source hostname");
01081             return;
01082 #endif                          /*HAVE_GETHOSTBYNAME */
01083         }
01084     }
01085 
01086     /*
01087      * Now work out the mask.  
01088      */
01089 
01090     if (strmask == NULL || *strmask == '\0') {
01091         /*
01092          * No mask was given.  Use 255.255.255.255.  
01093          */
01094         mask = 0xffffffffL;
01095     } else {
01096         if (strchr(strmask, '.')) {
01097             /*
01098              * Try to interpret mask as a dotted quad.  
01099              */
01100             mask = inet_addr(strmask);
01101             if (mask == (in_addr_t) -1 &&
01102                 strncmp(strmask, "255.255.255.255", 15) != 0) {
01103                 config_perror("bad mask");
01104                 return;
01105             }
01106         } else {
01107             /*
01108              * Try to interpret mask as a "number of 1 bits".  
01109              */
01110             int             maskLen = atoi(strmask), maskBit = 0x80000000L;
01111             if (maskLen <= 0 || maskLen > 32) {
01112                 config_perror("bad mask length");
01113                 return;
01114             }
01115             while (maskLen--) {
01116                 mask |= maskBit;
01117                 maskBit >>= 1;
01118             }
01119             mask = htonl(mask);
01120         }
01121     }
01122 
01123     /*
01124      * Check that the network and mask are consistent.  
01125      */
01126 
01127     if (network & ~mask) {
01128         config_perror("source/mask mismatch");
01129         return;
01130     }
01131 
01132     e = (com2SecEntry *) malloc(sizeof(com2SecEntry));
01133     if (e == NULL) {
01134         config_perror("memory error");
01135         return;
01136     }
01137 
01138     /*
01139      * Everything is okay.  Copy the parameters to the structure allocated
01140      * above and add it to END of the list.  
01141      */
01142 
01143     DEBUGMSGTL(("netsnmp_udp_parse_security",
01144                 "<\"%s\", 0x%08x/0x%08x> => \"%s\"\n", community, network,
01145                 mask, secName));
01146 
01147     strcpy(e->contextName, contextName);
01148     strcpy(e->secName, secName);
01149     strcpy(e->community, community);
01150     e->network = network;
01151     e->mask = mask;
01152     e->next = NULL;
01153 
01154     if (com2SecListLast != NULL) {
01155         com2SecListLast->next = e;
01156         com2SecListLast = e;
01157     } else {
01158         com2SecListLast = com2SecList = e;
01159     }
01160 }
01161 
01162 
01163 void
01164 netsnmp_udp_com2SecList_free(void)
01165 {
01166     com2SecEntry   *e = com2SecList;
01167     while (e != NULL) {
01168         com2SecEntry   *tmp = e;
01169         e = e->next;
01170         free(tmp);
01171     }
01172     com2SecList = com2SecListLast = NULL;
01173 }
01174 #endif /* support for community based SNMP */
01175 
01176 void
01177 netsnmp_udp_agent_config_tokens_register(void)
01178 {
01179 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
01180     register_app_config_handler("com2sec", netsnmp_udp_parse_security,
01181                                 netsnmp_udp_com2SecList_free,
01182                                 "[-Cn CONTEXT] secName IPv4-network-address[/netmask] community");
01183 #endif /* support for community based SNMP */
01184 }
01185 
01186 
01187 
01188 /*
01189  * Return 0 if there are no com2sec entries, or return 1 if there ARE com2sec 
01190  * entries.  On return, if a com2sec entry matched the passed parameters,
01191  * then *secName points at the appropriate security name, or is NULL if the
01192  * parameters did not match any com2sec entry.  
01193  */
01194 
01195 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
01196 int
01197 netsnmp_udp_getSecName(void *opaque, int olength,
01198                        const char *community,
01199                        size_t community_len, char **secName,
01200                        char **contextName)
01201 {
01202     com2SecEntry   *c;
01203     netsnmp_udp_addr_pair *addr_pair = (netsnmp_udp_addr_pair *) opaque;
01204     struct sockaddr_in *from = (struct sockaddr_in *) &(addr_pair->remote_addr);
01205     char           *ztcommunity = NULL;
01206 
01207     if (secName != NULL) {
01208         *secName = NULL;  /* Haven't found anything yet */
01209     }
01210 
01211     /*
01212      * Special case if there are NO entries (as opposed to no MATCHING
01213      * entries).  
01214      */
01215 
01216     if (com2SecList == NULL) {
01217         DEBUGMSGTL(("netsnmp_udp_getSecName", "no com2sec entries\n"));
01218         return 0;
01219     }
01220 
01221     /*
01222      * If there is no IPv4 source address, then there can be no valid security
01223      * name.  
01224      */
01225 
01226     if (opaque == NULL || olength != sizeof(netsnmp_udp_addr_pair) ||
01227         from->sin_family != AF_INET) {
01228         DEBUGMSGTL(("netsnmp_udp_getSecName",
01229                     "no IPv4 source address in PDU?\n"));
01230         return 1;
01231     }
01232 
01233     DEBUGIF("netsnmp_udp_getSecName") {
01234         ztcommunity = (char *)malloc(community_len + 1);
01235         if (ztcommunity != NULL) {
01236             memcpy(ztcommunity, community, community_len);
01237             ztcommunity[community_len] = '\0';
01238         }
01239 
01240         DEBUGMSGTL(("netsnmp_udp_getSecName", "resolve <\"%s\", 0x%08x>\n",
01241                     ztcommunity ? ztcommunity : "<malloc error>",
01242                     from->sin_addr.s_addr));
01243     }
01244 
01245     for (c = com2SecList; c != NULL; c = c->next) {
01246         DEBUGMSGTL(("netsnmp_udp_getSecName","compare <\"%s\", 0x%08x/0x%08x>",
01247                     c->community, c->network, c->mask));
01248         if ((community_len == strlen(c->community)) &&
01249             (memcmp(community, c->community, community_len) == 0) &&
01250             ((from->sin_addr.s_addr & c->mask) == c->network)) {
01251             DEBUGMSG(("netsnmp_udp_getSecName", "... SUCCESS\n"));
01252             if (secName != NULL) {
01253                 *secName = c->secName;
01254                 *contextName = c->contextName;
01255             }
01256             break;
01257         }
01258         DEBUGMSG(("netsnmp_udp_getSecName", "... nope\n"));
01259     }
01260     if (ztcommunity != NULL) {
01261         free(ztcommunity);
01262     }
01263     return 1;
01264 }
01265 #endif /* support for community based SNMP */
01266 
01267 
01268 netsnmp_transport *
01269 netsnmp_udp_create_tstring(const char *str, int local,
01270                            const char *default_target)
01271 {
01272     struct sockaddr_in addr;
01273 
01274     if (netsnmp_sockaddr_in2(&addr, str, default_target)) {
01275         return netsnmp_udp_transport(&addr, local);
01276     } else {
01277         return NULL;
01278     }
01279 }
01280 
01281 
01282 netsnmp_transport *
01283 netsnmp_udp_create_ostring(const u_char * o, size_t o_len, int local)
01284 {
01285     struct sockaddr_in addr;
01286 
01287     if (o_len == 6) {
01288         unsigned short porttmp = (o[4] << 8) + o[5];
01289         addr.sin_family = AF_INET;
01290         memcpy((u_char *) & (addr.sin_addr.s_addr), o, 4);
01291         addr.sin_port = htons(porttmp);
01292         return netsnmp_udp_transport(&addr, local);
01293     }
01294     return NULL;
01295 }
01296 
01297 
01298 void
01299 netsnmp_udp_ctor(void)
01300 {
01301     udpDomain.name = netsnmpUDPDomain;
01302     udpDomain.name_length = netsnmpUDPDomain_len;
01303     udpDomain.prefix = (const char**)calloc(2, sizeof(char *));
01304     udpDomain.prefix[0] = "udp";
01305 
01306     udpDomain.f_create_from_tstring_new = netsnmp_udp_create_tstring;
01307     udpDomain.f_create_from_ostring = netsnmp_udp_create_ostring;
01308 
01309     netsnmp_tdomain_register(&udpDomain);
01310 }