snmpUDPDomain.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:32k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /* Portions of this file are subject to the following copyright(s).  See
  2.  * the Net-SNMP's COPYING file for more details and other copyrights
  3.  * that may apply:
  4.  */
  5. /*
  6.  * Portions of this file are copyrighted by:
  7.  * Copyright Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  8.  * Use is subject to license terms specified in the COPYING file
  9.  * distributed with the Net-SNMP package.
  10.  */
  11. #include <net-snmp/net-snmp-config.h>
  12. #include <stdio.h>
  13. #include <sys/types.h>
  14. #include <ctype.h>
  15. #include <errno.h>
  16. #if HAVE_STRING_H
  17. #include <string.h>
  18. #else
  19. #include <strings.h>
  20. #endif
  21. #if HAVE_STDLIB_H
  22. #include <stdlib.h>
  23. #endif
  24. #if HAVE_UNISTD_H
  25. #include <unistd.h>
  26. #endif
  27. #if HAVE_SYS_SOCKET_H
  28. #include <sys/socket.h>
  29. #endif
  30. #if HAVE_NETINET_IN_H
  31. #include <netinet/in.h>
  32. #endif
  33. #if HAVE_ARPA_INET_H
  34. #include <arpa/inet.h>
  35. #endif
  36. #if HAVE_NETDB_H
  37. #include <netdb.h>
  38. #endif
  39. #if HAVE_WINSOCK_H
  40. #include <winsock2.h>
  41. #include <ws2tcpip.h>
  42. #endif
  43. #if HAVE_DMALLOC_H
  44. #include <dmalloc.h>
  45. #endif
  46. #include <net-snmp/types.h>
  47. #include <net-snmp/output_api.h>
  48. #include <net-snmp/config_api.h>
  49. #include <net-snmp/library/snmp_transport.h>
  50. #include <net-snmp/library/snmpUDPDomain.h>
  51. #include <net-snmp/library/system.h>
  52. #include <net-snmp/library/tools.h>
  53. #ifndef INADDR_NONE
  54. #define INADDR_NONE -1
  55. #endif
  56. static netsnmp_tdomain udpDomain;
  57. /*
  58.  * not static, since snmpUDPIPv6Domain needs it, but not public, either.
  59.  * (ie don't put it in a public header.)
  60.  */
  61. void _netsnmp_udp_sockopt_set(int fd, int server);
  62. /*
  63.  * Return a string representing the address in data, or else the "far end"
  64.  * address if data is NULL.  
  65.  */
  66. static char *
  67. netsnmp_udp_fmtaddr(netsnmp_transport *t, void *data, int len)
  68. {
  69.     struct sockaddr_in *to = NULL;
  70.     if (data != NULL && len == sizeof(struct sockaddr_in)) {
  71.         to = (struct sockaddr_in *) data;
  72.     } else if (t != NULL && t->data != NULL) {
  73.         to = (struct sockaddr_in *) t->data;
  74.     }
  75.     if (to == NULL) {
  76.         return strdup("UDP: unknown");
  77.     } else {
  78. char tmp[64];
  79.         sprintf(tmp, "UDP: [%s]:%hd",
  80.                 inet_ntoa(to->sin_addr), ntohs(to->sin_port));
  81.         return strdup(tmp);
  82.     }
  83. }
  84. /*
  85.  * You can write something into opaque that will subsequently get passed back 
  86.  * to your send function if you like.  For instance, you might want to
  87.  * remember where a PDU came from, so that you can send a reply there...  
  88.  */
  89. static int
  90. netsnmp_udp_recv(netsnmp_transport *t, void *buf, int size,
  91.  void **opaque, int *olength)
  92. {
  93.     int             rc = -1;
  94.     socklen_t       fromlen = sizeof(struct sockaddr);
  95.     struct sockaddr *from;
  96.     if (t != NULL && t->sock >= 0) {
  97.         from = (struct sockaddr *) malloc(sizeof(struct sockaddr_in));
  98.         if (from == NULL) {
  99.             *opaque = NULL;
  100.             *olength = 0;
  101.             return -1;
  102.         } else {
  103.             memset(from, 0, fromlen);
  104.         }
  105. while (rc < 0) {
  106.     rc = recvfrom(t->sock, buf, size, 0, from, &fromlen);
  107.     if (rc < 0 && errno != EINTR) {
  108. break;
  109.     }
  110. }
  111.         if (rc >= 0) {
  112.             char *str = netsnmp_udp_fmtaddr(NULL, from, fromlen);
  113.             DEBUGMSGTL(("netsnmp_udp",
  114. "recvfrom fd %d got %d bytes (from %s)n",
  115. t->sock, rc, str));
  116.             free(str);
  117.         } else {
  118.             DEBUGMSGTL(("netsnmp_udp", "recvfrom fd %d err %d ("%s")n",
  119.                         t->sock, errno, strerror(errno)));
  120.         }
  121.         *opaque = (void *)from;
  122.         *olength = sizeof(struct sockaddr_in);
  123.     }
  124.     return rc;
  125. }
  126. static int
  127. netsnmp_udp_send(netsnmp_transport *t, void *buf, int size,
  128.  void **opaque, int *olength)
  129. {
  130.     int rc = -1;
  131.     struct sockaddr *to = NULL;
  132.     if (opaque != NULL && *opaque != NULL &&
  133.         *olength == sizeof(struct sockaddr_in)) {
  134.         to = (struct sockaddr *) (*opaque);
  135.     } else if (t != NULL && t->data != NULL &&
  136.                t->data_length == sizeof(struct sockaddr_in)) {
  137.         to = (struct sockaddr *) (t->data);
  138.     }
  139.     if (to != NULL && t != NULL && t->sock >= 0) {
  140.         char *str = netsnmp_udp_fmtaddr(NULL, (void *) to,
  141. sizeof(struct sockaddr_in));
  142.         DEBUGMSGTL(("netsnmp_udp", "send %d bytes from %p to %s on fd %dn",
  143.                     size, buf, str, t->sock));
  144.         free(str);
  145. while (rc < 0) {
  146.     rc = sendto(t->sock, buf, size, 0, to, sizeof(struct sockaddr));
  147.     if (rc < 0 && errno != EINTR) {
  148. break;
  149.     }
  150. }
  151.     }
  152.     return rc;
  153. }
  154. static int
  155. netsnmp_udp_close(netsnmp_transport *t)
  156. {
  157.     int rc = -1;
  158.     if (t->sock >= 0) {
  159. #ifndef HAVE_CLOSESOCKET
  160.         rc = close(t->sock);
  161. #else
  162.         rc = closesocket(t->sock);
  163. #endif
  164.         t->sock = -1;
  165.     }
  166.     return rc;
  167. }
  168. /*
  169.  * find largest possible buffer between current size and specified size.
  170.  *
  171.  * Try to maximize the current buffer of type "optname"
  172.  * to the maximum allowable size by the OS (as close to
  173.  * size as possible)
  174.  */
  175. static int
  176. _sock_buffer_maximize(int s, int optname, const char *buftype, int size)
  177. {
  178.     int            curbuf = 0, curbuflen = sizeof(int);
  179.     int            lo, mid, hi;
  180.     /*
  181.      * First we need to determine our current buffer
  182.      */
  183.     if ((getsockopt(s, SOL_SOCKET, optname, (void *) &curbuf,
  184.                     &curbuflen) == 0) 
  185.             && (curbuflen == sizeof(int))) {
  186.         DEBUGMSGTL(("verbose:socket:buffer:max", "Current %s is %dn",
  187.                     buftype, curbuf));
  188.         /*
  189.          * Let's not be stupid ... if we were asked for less than what we
  190.          * already have, then forget about it
  191.          */
  192.         if (size <= curbuf) {
  193.             DEBUGMSGTL(("verbose:socket:buffer:max",
  194.                         "Requested %s <= current buffern", buftype));
  195.             return curbuf;
  196.         }
  197.         /*
  198.          * Do a binary search the optimal buffer within 1k of the point of
  199.          * failure. This is rather bruteforce, but simple
  200.          */
  201.         hi = size;
  202.         lo = curbuf;
  203.         while (hi - lo > 1024) {
  204.             mid = (lo + hi) / 2;
  205.             if (setsockopt(s, SOL_SOCKET, optname, (void *) &mid,
  206.                         sizeof(int)) == 0) {
  207.                 lo = mid; /* Success: search between mid and hi */
  208.             } else {
  209.                 hi = mid; /* Failed: search between lo and mid */
  210.             }
  211.         }
  212.         /*
  213.          * Now print if this optimization helped or not
  214.          */
  215.         if (getsockopt(s,SOL_SOCKET, optname, (void *) &curbuf,
  216.                     &curbuflen) == 0) {
  217.             DEBUGMSGTL(("socket:buffer:max", 
  218.                         "Maximized %s: %dn",buftype, curbuf));
  219.         } 
  220.     } else {
  221.         /*
  222.          * There is really not a lot we can do anymore.
  223.          * If the OS doesn't give us the current buffer, then what's the 
  224.          * point in trying to make it better
  225.          */
  226.         DEBUGMSGTL(("socket:buffer:max", "Get %s failed ... giving up!n",
  227.                     buftype));
  228.         curbuf = -1;
  229.     }
  230.     return curbuf;
  231. }
  232. static const char *
  233. _sock_buf_type_get(int optname, int local)
  234. {
  235.     if (optname == SO_SNDBUF) {
  236.         if (local)
  237.             return "server send buffer";
  238.         else
  239.             return "client send buffer";
  240.     } else if (optname == SO_RCVBUF) {
  241.         if (local)
  242.             return "server receive buffer";
  243.         else
  244.             return "client receive buffer";
  245.     }
  246.     return "unknown buffer";
  247. }
  248. /*
  249.  *
  250.  * Get the requested buffersize, based on
  251.  * - sockettype : client (local = 0) or server (local = 1) 
  252.  * - buffertype : send (optname = SO_SNDBUF) or recv (SO_RCVBUF)
  253.  *
  254.  * In case a compile time buffer was specified, then use that one
  255.  * if there was no runtime configuration override
  256.  */
  257. static int
  258. _sock_buffer_size_get(int optname, int local, const char **buftype)
  259. {
  260.     int size;
  261.     if (NULL != buftype)
  262.         *buftype = _sock_buf_type_get(optname, local);
  263.     if (optname == SO_SNDBUF) {
  264.         if (local) {
  265.             size = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
  266.                     NETSNMP_DS_LIB_SERVERSENDBUF);
  267. #ifdef DEFAULT_SERVER_SEND_BUF
  268.             if (size <= 0)
  269.                size = DEFAULT_SERVER_SEND_BUF;
  270. #endif
  271.         } else {
  272.             size = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
  273.                     NETSNMP_DS_LIB_CLIENTSENDBUF);
  274. #ifdef DEFAULT_CLIENT_SEND_BUF
  275.             if (size <= 0)
  276.                size = DEFAULT_CLIENT_SEND_BUF;
  277. #endif
  278.         }
  279.     } else if (optname == SO_RCVBUF) {
  280.         if (local) {
  281.             size = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
  282.                     NETSNMP_DS_LIB_SERVERRECVBUF);
  283. #ifdef DEFAULT_SERVER_RECV_BUF
  284.             if (size <= 0)
  285.                size = DEFAULT_SERVER_RECV_BUF;
  286. #endif
  287.         } else {
  288.             size = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
  289.                     NETSNMP_DS_LIB_CLIENTRECVBUF);
  290. #ifdef DEFAULT_CLIENT_RECV_BUF
  291.             if (size <= 0)
  292.                size = DEFAULT_CLIENT_RECV_BUF;
  293. #endif
  294.         }
  295.     } else {
  296.         size = 0;
  297.     }
  298.     DEBUGMSGTL(("socket:buffer", "Requested %s is %dn",
  299.                 (buftype) ? *buftype : "unknown buffer", size));
  300.     return(size);
  301. }
  302. /*
  303.  * set socket buffer size
  304.  *
  305.  * @param ss     : socket
  306.  * @param optname: SO_SNDBUF or SO_RCVBUF
  307.  * @param local  : 1 for server, 0 for client
  308.  * @param reqbuf : requested size, or 0 for default
  309.  *
  310.  * @retval    -1 : error
  311.  * @retval    >0 : new buffer size
  312.  */
  313. int
  314. netsnmp_sock_buffer_set(int s, int optname, int local, int size)
  315. {
  316. #if ! defined(SO_SNDBUF) && ! defined(SO_RCVBUF)
  317.     DEBUGMSGTL(("socket:buffer", "Changing socket buffer is not supportedn"));
  318.     return -1;
  319. #else
  320.     const char     *buftype;
  321.     int            curbuf = 0, curbuflen = sizeof(int);
  322. #   ifndef  SO_SNDBUF
  323.     if (SO_SNDBUF == optname) {
  324.         DEBUGMSGTL(("socket:buffer",
  325.                     "Changing socket send buffer is not supportedn"));
  326.         return -1;
  327.     }
  328. #   endif                          /*SO_SNDBUF */
  329. #   ifndef  SO_RCVBUF
  330.     if (SO_RCVBUF == optname) {
  331.         DEBUGMSGTL(("socket:buffer",
  332.                     "Changing socket receive buffer is not supportedn"));
  333.         return -1;
  334.     }
  335. #   endif                          /*SO_RCVBUF */
  336.     /*
  337.      * What is the requested buffer size ?
  338.      */
  339.     if (0 == size)
  340.         size = _sock_buffer_size_get(optname, local, &buftype);
  341.     else {
  342.         buftype = _sock_buf_type_get(optname, local);
  343.         DEBUGMSGT(("verbose:socket:buffer", "Requested %s is %dn",
  344.                    buftype, size));
  345.     }
  346.     if ((getsockopt(s, SOL_SOCKET, optname, (void *) &curbuf,
  347.                     &curbuflen) == 0) 
  348.         && (curbuflen == sizeof(int))) {
  349.         
  350.         DEBUGMSGT(("verbose:socket:buffer", "Original %s is %dn",
  351.                    buftype, curbuf));
  352.         if (curbuf >= size) {
  353.             DEBUGMSGT(("verbose:socket:buffer",
  354.                       "New %s size is smaller than original!n", buftype));
  355.         }
  356.     }
  357.     /*
  358.      * If the buffersize was not specified or it was a negative value
  359.      * then don't change the OS buffers at all
  360.      */
  361.     if (size <= 0) {
  362.        DEBUGMSGT(("socket:buffer",
  363.                     "%s not valid or not specified; using OS default(%d)n",
  364.                     buftype,curbuf));
  365.        return curbuf;
  366.     }
  367.     /*
  368.      * Try to set the requested send buffer
  369.      */
  370.     if (setsockopt(s, SOL_SOCKET, optname, (void *) &size, sizeof(int)) == 0) {
  371.         /*
  372.          * Because some platforms lie about the actual buffer that has been 
  373.          * set (Linux will always say it worked ...), we print some 
  374.          * diagnostic output for debugging
  375.          */
  376.         DEBUGIF("socket:buffer") {
  377.             DEBUGMSGT(("socket:buffer", "Set %s to %dn",
  378.                        buftype, size));
  379.             if ((getsockopt(s, SOL_SOCKET, optname, (void *) &curbuf,
  380.                             &curbuflen) == 0) 
  381.                     && (curbuflen == sizeof(int))) {
  382.                 DEBUGMSGT(("verbose:socket:buffer",
  383.                            "Now %s is %dn", buftype, curbuf));
  384.             }
  385.         }
  386.         /*
  387.          * If the new buffer is smaller than the size we requested, we will
  388.          * try to increment the new buffer with 1k increments 
  389.          * (this will sometime allow us to reach a more optimal buffer.)
  390.          *   For example : On Solaris, if the max OS buffer is 100k and you
  391.          *   request 110k, you end up with the default 8k :-(
  392.          */
  393.         if (curbuf < size) {
  394.             curbuf = _sock_buffer_maximize(s, optname, buftype, size);
  395.             if(-1 != curbuf)
  396.                 size = curbuf;
  397.         }
  398.     } else {
  399.         /*
  400.          * Obviously changing the buffer failed, most like like because we 
  401.          * requested a buffer greater than the OS limit.
  402.          * Therefore we need to search for an optimal buffer that is close
  403.          * enough to the point of failure.
  404.          * This will allow us to reach a more optimal buffer.
  405.          *   For example : On Solaris, if the max OS buffer is 100k and you 
  406.          *   request 110k, you end up with the default 8k :-(
  407.          *   After this quick seach we would get 1k close to 100k (the max)
  408.          */
  409.         DEBUGMSGTL(("socket:buffer", "couldn't set %s to %dn",
  410.                     buftype, size));
  411.         curbuf = _sock_buffer_maximize(s, optname, buftype, size);
  412.         if(-1 != curbuf)
  413.             size = curbuf;
  414.     }
  415.     return size;
  416. #endif
  417. }
  418. /*
  419.  * Open a UDP-based transport for SNMP.  Local is TRUE if addr is the local
  420.  * address to bind to (i.e. this is a server-type session); otherwise addr is 
  421.  * the remote address to send things to.  
  422.  */
  423. netsnmp_transport *
  424. netsnmp_udp_transport(struct sockaddr_in *addr, int local)
  425. {
  426.     netsnmp_transport *t = NULL;
  427.     int             rc = 0;
  428.     char           *str = NULL;
  429.     char           *client_socket = NULL;
  430.     if (addr == NULL || addr->sin_family != AF_INET) {
  431.         return NULL;
  432.     }
  433.     t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
  434.     if (t == NULL) {
  435.         return NULL;
  436.     }
  437.     str = netsnmp_udp_fmtaddr(NULL, (void *)addr, 
  438.  sizeof(struct sockaddr_in));
  439.     DEBUGMSGTL(("netsnmp_udp", "open %s %s:%dn", local ? "local" : "remote",
  440.                 str,addr->sin_port));
  441.     free(str);
  442.     memset(t, 0, sizeof(netsnmp_transport));
  443.     t->domain = netsnmpUDPDomain;
  444.     t->domain_length = netsnmpUDPDomain_len;
  445.     t->sock = socket(PF_INET, SOCK_DGRAM, 0);
  446.     if (t->sock < 0) {
  447.         netsnmp_transport_free(t);
  448.         return NULL;
  449.     }
  450.     _netsnmp_udp_sockopt_set(t->sock, local);
  451.     if (local) {
  452.         /*
  453.          * This session is inteneded as a server, so we must bind on to the
  454.          * given IP address, which may include an interface address, or could
  455.          * be INADDR_ANY, but certainly includes a port number.
  456.          */
  457.         t->local = malloc(6);
  458.         if (t->local == NULL) {
  459.             netsnmp_transport_free(t);
  460.             return NULL;
  461.         }
  462.         memcpy(t->local, (u_char *) & (addr->sin_addr.s_addr), 4);
  463.         t->local[4] = (htons(addr->sin_port) & 0xff00) >> 8;
  464.         t->local[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
  465.         t->local_length = 6;
  466.         rc = bind(t->sock, (struct sockaddr *) addr,
  467.                   sizeof(struct sockaddr));
  468.         if (rc != 0) {
  469.             netsnmp_udp_close(t);
  470.             netsnmp_transport_free(t);
  471.             return NULL;
  472.         }
  473.         t->data = NULL;
  474.         t->data_length = 0;
  475.     } else {
  476.         /*
  477.          * This is a client session.  If we've been given a
  478.          * client address to send from, then bind to that.
  479.          * Otherwise the send will use "something sensible".
  480.          */
  481.         client_socket = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
  482.                                               NETSNMP_DS_LIB_CLIENT_ADDR);
  483.         if (client_socket) {
  484.             struct sockaddr_in client_addr;
  485.             netsnmp_sockaddr_in( &client_addr, client_socket, 0);
  486.             client_addr.sin_port = 0;
  487.             bind(t->sock, (struct sockaddr *)&client_addr,
  488.                   sizeof(struct sockaddr));
  489.         }
  490.         /*
  491.          * Save the (remote) address in the
  492.          * transport-specific data pointer for later use by netsnmp_udp_send.
  493.          */
  494.         t->data = malloc(sizeof(struct sockaddr_in));
  495.         t->remote = malloc(6);
  496.         if (t->data == NULL || t->remote == NULL) {
  497.             netsnmp_transport_free(t);
  498.             return NULL;
  499.         }
  500.         memcpy(t->remote, (u_char *) & (addr->sin_addr.s_addr), 4);
  501.         t->remote[4] = (htons(addr->sin_port) & 0xff00) >> 8;
  502.         t->remote[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
  503.         t->remote_length = 6;
  504.         memcpy(t->data, addr, sizeof(struct sockaddr_in));
  505.         t->data_length = sizeof(struct sockaddr_in);
  506.     }
  507.     /*
  508.      * 16-bit length field, 8 byte UDP header, 20 byte IPv4 header  
  509.      */
  510.     t->msgMaxSize = 0xffff - 8 - 20;
  511.     t->f_recv     = netsnmp_udp_recv;
  512.     t->f_send     = netsnmp_udp_send;
  513.     t->f_close    = netsnmp_udp_close;
  514.     t->f_accept   = NULL;
  515.     t->f_fmtaddr  = netsnmp_udp_fmtaddr;
  516.     return t;
  517. }
  518. void
  519. _netsnmp_udp_sockopt_set(int fd, int local)
  520. {
  521. #ifdef  SO_BSDCOMPAT
  522.     /*
  523.      * Patch for Linux.  Without this, UDP packets that fail get an ICMP
  524.      * response.  Linux turns the failed ICMP response into an error message
  525.      * and return value, unlike all other OS's.  
  526.      */
  527.     if (0 == netsnmp_os_prematch("Linux","2.4"))
  528.     {
  529.         int             one = 1;
  530.         DEBUGMSGTL(("socket:option", "setting socket option SO_BSDCOMPATn"));
  531.         setsockopt(fd, SOL_SOCKET, SO_BSDCOMPAT, (void *) &one,
  532.                    sizeof(one));
  533.     }
  534. #endif                          /*SO_BSDCOMPAT */
  535.     /*
  536.      * SO_REUSEADDR will allow multiple apps to open the same port at
  537.      * the same time. Only the last one to open the socket will get
  538.      * data. Obviously, for an agent, this is a bad thing. There should
  539.      * only be one listener.
  540.      */
  541. #ifdef ALLOW_PORT_HIJACKING
  542. #ifdef  SO_REUSEADDR
  543.     /*
  544.      * Allow the same port to be specified multiple times without failing.
  545.      *    (useful for a listener)
  546.      */
  547.     {
  548.         int             one = 1;
  549.         DEBUGMSGTL(("socket:option", "setting socket option SO_REUSEADDRn"));
  550.         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &one,
  551.                    sizeof(one));
  552.     }
  553. #endif                          /*SO_REUSEADDR */
  554. #endif
  555.     /*
  556.      * Try to set the send and receive buffers to a reasonably large value, so
  557.      * that we can send and receive big PDUs (defaults to 8192 bytes (!) on
  558.      * Solaris, for instance).  Don't worry too much about errors -- just
  559.      * plough on regardless.  
  560.      */
  561.     netsnmp_sock_buffer_set(fd, SO_SNDBUF, local, 0);
  562.     netsnmp_sock_buffer_set(fd, SO_RCVBUF, local, 0);
  563. }
  564. int
  565. netsnmp_sockaddr_in(struct sockaddr_in *addr,
  566.                     const char *inpeername, int remote_port)
  567. {
  568.     char           *cp = NULL, *peername = NULL;
  569.     if (addr == NULL) {
  570.         return 0;
  571.     }
  572.     memset(addr, 0, sizeof(struct sockaddr_in));
  573.     DEBUGMSGTL(("netsnmp_sockaddr_in", "addr %p, peername "%s"n",
  574.                 addr, inpeername ? inpeername : "[NIL]"));
  575.     addr->sin_addr.s_addr = htonl(INADDR_ANY);
  576.     addr->sin_family = AF_INET;
  577.     if (remote_port > 0) {
  578.         addr->sin_port = htons((u_short)remote_port);
  579.     } else if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
  580.   NETSNMP_DS_LIB_DEFAULT_PORT) > 0) {
  581.         addr->sin_port = htons((u_short)netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
  582.  NETSNMP_DS_LIB_DEFAULT_PORT));
  583.     } else {
  584.         addr->sin_port = htons(SNMP_PORT);
  585.     }
  586.     if (inpeername != NULL) {
  587.         /*
  588.          * Duplicate the peername because we might want to mank around with
  589.          * it.  
  590.          */
  591.         peername = strdup(inpeername);
  592.         if (peername == NULL) {
  593.             return 0;
  594.         }
  595.         /*
  596.          * Try and extract an appended port number.  
  597.          */
  598.         cp = strchr(peername, ':');
  599.         if (cp != NULL) {
  600.             *cp = '';
  601.             cp++;
  602.             if (atoi(cp) != 0) {
  603.                 DEBUGMSGTL(("netsnmp_sockaddr_in",
  604.                             "port number suffix :%dn", atoi(cp)));
  605.                 addr->sin_port = htons((u_short)atoi(cp));
  606.             }
  607.         }
  608.         for (cp = peername; *cp && isdigit((int) *cp); cp++);
  609.         if (!*cp && atoi(peername) != 0) {
  610.             /*
  611.              * Okay, it looks like just a port number.  
  612.              */
  613.             DEBUGMSGTL(("netsnmp_sockaddr_in", "totally numeric: %dn",
  614.                         atoi(peername)));
  615.             addr->sin_port = htons((u_short)atoi(peername));
  616.         } else if (inet_addr(peername) != INADDR_NONE) {
  617.             /*
  618.              * It looks like an IP address.  
  619.              */
  620.             DEBUGMSGTL(("netsnmp_sockaddr_in", "IP addressn"));
  621.             addr->sin_addr.s_addr = inet_addr(peername);
  622.         } else {
  623.             /*
  624.              * Well, it must be a hostname then.  
  625.              */
  626. #ifdef  HAVE_GETHOSTBYNAME
  627.             struct hostent *hp = gethostbyname(peername);
  628.             if (hp == NULL) {
  629.                 DEBUGMSGTL(("netsnmp_sockaddr_in",
  630.                             "hostname (couldn't resolve)n"));
  631.                 free(peername);
  632.                 return 0;
  633.             } else {
  634.                 if (hp->h_addrtype != AF_INET) {
  635.                     DEBUGMSGTL(("netsnmp_sockaddr_in",
  636.                                 "hostname (not AF_INET!)n"));
  637.                     free(peername);
  638.                     return 0;
  639.                 } else {
  640.                     DEBUGMSGTL(("netsnmp_sockaddr_in",
  641.                                 "hostname (resolved okay)n"));
  642.                     memcpy(&(addr->sin_addr), hp->h_addr, hp->h_length);
  643.                 }
  644.             }
  645. #else                           /*HAVE_GETHOSTBYNAME */
  646.             DEBUGMSGTL(("netsnmp_sockaddr_in",
  647.                         "hostname (no gethostbyname)n"));
  648.             free(peername);
  649.             return 0;
  650. #endif                          /*HAVE_GETHOSTBYNAME */
  651.         }
  652.     } else {
  653.         DEBUGMSGTL(("netsnmp_sockaddr_in", "NULL peername"));
  654.         return 0;
  655.     }
  656.     DEBUGMSGTL(("netsnmp_sockaddr_in", "return { AF_INET, %s:%hu }n",
  657.                 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port)));
  658.     free(peername);
  659.     return 1;
  660. }
  661. #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
  662. /*
  663.  * The following functions provide the "com2sec" configuration token
  664.  * functionality for compatibility.  
  665.  */
  666. #define EXAMPLE_NETWORK "NETWORK"
  667. #define EXAMPLE_COMMUNITY "COMMUNITY"
  668. typedef struct _com2SecEntry {
  669.     char            community[VACMSTRINGLEN];
  670.     unsigned long   network;
  671.     unsigned long   mask;
  672.     char            secName[VACMSTRINGLEN];
  673.     char            contextName[VACMSTRINGLEN];
  674.     struct _com2SecEntry *next;
  675. } com2SecEntry;
  676. com2SecEntry   *com2SecList = NULL, *com2SecListLast = NULL;
  677. void
  678. netsnmp_udp_parse_security(const char *token, char *param)
  679. {
  680.     char            secName[VACMSTRINGLEN];
  681.     char            contextName[VACMSTRINGLEN];
  682.     char            community[VACMSTRINGLEN];
  683.     char            source[SNMP_MAXBUF_SMALL];
  684.     char           *cp = NULL;
  685.     const char     *strmask = NULL;
  686.     com2SecEntry   *e = NULL;
  687.     in_addr_t   network = 0, mask = 0;
  688.     /*
  689.      * Get security, source address/netmask and community strings.  
  690.      */
  691.     cp = copy_nword( param, secName, sizeof(secName));
  692.     if (strcmp(secName, "-Cn") == 0) {
  693.         if (!cp) {
  694.             config_perror("missing CONTEXT_NAME parameter");
  695.             return;
  696.         }
  697.         cp = copy_nword( cp, contextName, sizeof(contextName));
  698.         cp = copy_nword( cp, secName, sizeof(secName));
  699.     } else {
  700.         contextName[0] = '';
  701.     }
  702.     if (secName[0] == '') {
  703.         config_perror("missing NAME parameter");
  704.         return;
  705.     } else if (strlen(secName) > (VACMSTRINGLEN - 1)) {
  706.         config_perror("security name too long");
  707.         return;
  708.     }
  709.     cp = copy_nword( cp, source, sizeof(source));
  710.     if (source[0] == '') {
  711.         config_perror("missing SOURCE parameter");
  712.         return;
  713.     } else if (strncmp(source, EXAMPLE_NETWORK, strlen(EXAMPLE_NETWORK)) ==
  714.                0) {
  715.         config_perror("example config NETWORK not properly configured");
  716.         return;
  717.     }
  718.     cp = copy_nword( cp, community, sizeof(community));
  719.     if (community[0] == '') {
  720.         config_perror("missing COMMUNITY parametern");
  721.         return;
  722.     } else
  723.         if (strncmp
  724.             (community, EXAMPLE_COMMUNITY, strlen(EXAMPLE_COMMUNITY))
  725.             == 0) {
  726.         config_perror("example config COMMUNITY not properly configured");
  727.         return;
  728.     } else if (strlen(community) > (VACMSTRINGLEN - 1)) {
  729.         config_perror("community name too long");
  730.         return;
  731.     }
  732.     /*
  733.      * Process the source address/netmask string.  
  734.      */
  735.     cp = strchr(source, '/');
  736.     if (cp != NULL) {
  737.         /*
  738.          * Mask given.  
  739.          */
  740.         *cp = '';
  741.         strmask = cp + 1;
  742.     }
  743.     /*
  744.      * Deal with the network part first.  
  745.      */
  746.     if ((strcmp(source, "default") == 0)
  747.         || (strcmp(source, "0.0.0.0") == 0)) {
  748.         network = 0;
  749.         strmask = "0.0.0.0";
  750.     } else {
  751.         /*
  752.          * Try interpreting as a dotted quad.  
  753.          */
  754.         network = inet_addr(source);
  755.         if (network == (in_addr_t) -1) {
  756.             /*
  757.              * Nope, wasn't a dotted quad.  Must be a hostname.  
  758.              */
  759. #ifdef  HAVE_GETHOSTBYNAME
  760.             struct hostent *hp = gethostbyname(source);
  761.             if (hp == NULL) {
  762.                 config_perror("bad source address");
  763.                 return;
  764.             } else {
  765.                 if (hp->h_addrtype != AF_INET) {
  766.                     config_perror("no IP address for source hostname");
  767.                     return;
  768.                 }
  769.                 network = *((in_addr_t *) hp->h_addr);
  770.             }
  771. #else                           /*HAVE_GETHOSTBYNAME */
  772.             /*
  773.              * Oh dear.  
  774.              */
  775.             config_perror("cannot resolve source hostname");
  776.             return;
  777. #endif                          /*HAVE_GETHOSTBYNAME */
  778.         }
  779.     }
  780.     /*
  781.      * Now work out the mask.  
  782.      */
  783.     if (strmask == NULL || *strmask == '') {
  784.         /*
  785.          * No mask was given.  Use 255.255.255.255.  
  786.          */
  787.         mask = 0xffffffffL;
  788.     } else {
  789.         if (strchr(strmask, '.')) {
  790.             /*
  791.              * Try to interpret mask as a dotted quad.  
  792.              */
  793.             mask = inet_addr(strmask);
  794.             if (mask == (in_addr_t) -1 &&
  795.                 strncmp(strmask, "255.255.255.255", 15) != 0) {
  796.                 config_perror("bad mask");
  797.                 return;
  798.             }
  799.         } else {
  800.             /*
  801.              * Try to interpret mask as a "number of 1 bits".  
  802.              */
  803.             int             maskLen = atoi(strmask), maskBit = 0x80000000L;
  804.             if (maskLen <= 0 || maskLen > 32) {
  805.                 config_perror("bad mask length");
  806.                 return;
  807.             }
  808.             while (maskLen--) {
  809.                 mask |= maskBit;
  810.                 maskBit >>= 1;
  811.             }
  812.             mask = htonl(mask);
  813.         }
  814.     }
  815.     /*
  816.      * Check that the network and mask are consistent.  
  817.      */
  818.     if (network & ~mask) {
  819.         config_perror("source/mask mismatch");
  820.         return;
  821.     }
  822.     e = (com2SecEntry *) malloc(sizeof(com2SecEntry));
  823.     if (e == NULL) {
  824.         config_perror("memory error");
  825.         return;
  826.     }
  827.     /*
  828.      * Everything is okay.  Copy the parameters to the structure allocated
  829.      * above and add it to END of the list.  
  830.      */
  831.     DEBUGMSGTL(("netsnmp_udp_parse_security",
  832.                 "<"%s", 0x%08x/0x%08x> => "%s"n", community, network,
  833.                 mask, secName));
  834.     strcpy(e->contextName, contextName);
  835.     strcpy(e->secName, secName);
  836.     strcpy(e->community, community);
  837.     e->network = network;
  838.     e->mask = mask;
  839.     e->next = NULL;
  840.     if (com2SecListLast != NULL) {
  841.         com2SecListLast->next = e;
  842.         com2SecListLast = e;
  843.     } else {
  844.         com2SecListLast = com2SecList = e;
  845.     }
  846. }
  847. void
  848. netsnmp_udp_com2SecList_free(void)
  849. {
  850.     com2SecEntry   *e = com2SecList;
  851.     while (e != NULL) {
  852.         com2SecEntry   *tmp = e;
  853.         e = e->next;
  854.         free(tmp);
  855.     }
  856.     com2SecList = com2SecListLast = NULL;
  857. }
  858. #endif /* support for community based SNMP */
  859. void
  860. netsnmp_udp_agent_config_tokens_register(void)
  861. {
  862. #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
  863.     register_app_config_handler("com2sec", netsnmp_udp_parse_security,
  864.                                 netsnmp_udp_com2SecList_free,
  865.                                 "[-Cn CONTEXT] secName IPv4-network-address[/netmask] community");
  866. #endif /* support for community based SNMP */
  867. }
  868. /*
  869.  * Return 0 if there are no com2sec entries, or return 1 if there ARE com2sec 
  870.  * entries.  On return, if a com2sec entry matched the passed parameters,
  871.  * then *secName points at the appropriate security name, or is NULL if the
  872.  * parameters did not match any com2sec entry.  
  873.  */
  874. #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
  875. int
  876. netsnmp_udp_getSecName(void *opaque, int olength,
  877.                        const char *community,
  878.                        size_t community_len, char **secName,
  879.                        char **contextName)
  880. {
  881.     com2SecEntry   *c;
  882.     struct sockaddr_in *from = (struct sockaddr_in *) opaque;
  883.     char           *ztcommunity = NULL;
  884.     if (secName != NULL) {
  885.         *secName = NULL;  /* Haven't found anything yet */
  886.     }
  887.     /*
  888.      * Special case if there are NO entries (as opposed to no MATCHING
  889.      * entries).  
  890.      */
  891.     if (com2SecList == NULL) {
  892.         DEBUGMSGTL(("netsnmp_udp_getSecName", "no com2sec entriesn"));
  893.         return 0;
  894.     }
  895.     /*
  896.      * If there is no IPv4 source address, then there can be no valid security
  897.      * name.  
  898.      */
  899.     if (opaque == NULL || olength != sizeof(struct sockaddr_in) ||
  900.         from->sin_family != AF_INET) {
  901.         DEBUGMSGTL(("netsnmp_udp_getSecName",
  902.     "no IPv4 source address in PDU?n"));
  903.         return 1;
  904.     }
  905.     DEBUGIF("netsnmp_udp_getSecName") {
  906. ztcommunity = (char *)malloc(community_len + 1);
  907. if (ztcommunity != NULL) {
  908.     memcpy(ztcommunity, community, community_len);
  909.     ztcommunity[community_len] = '';
  910. }
  911. DEBUGMSGTL(("netsnmp_udp_getSecName", "resolve <"%s", 0x%08x>n",
  912.     ztcommunity ? ztcommunity : "<malloc error>",
  913.     from->sin_addr.s_addr));
  914.     }
  915.     for (c = com2SecList; c != NULL; c = c->next) {
  916.         DEBUGMSGTL(("netsnmp_udp_getSecName","compare <"%s", 0x%08x/0x%08x>",
  917.     c->community, c->network, c->mask));
  918.         if ((community_len == strlen(c->community)) &&
  919.     (memcmp(community, c->community, community_len) == 0) &&
  920.             ((from->sin_addr.s_addr & c->mask) == c->network)) {
  921.             DEBUGMSG(("netsnmp_udp_getSecName", "... SUCCESSn"));
  922.             if (secName != NULL) {
  923.                 *secName = c->secName;
  924.                 *contextName = c->contextName;
  925.             }
  926.             break;
  927.         }
  928.         DEBUGMSG(("netsnmp_udp_getSecName", "... nopen"));
  929.     }
  930.     if (ztcommunity != NULL) {
  931.         free(ztcommunity);
  932.     }
  933.     return 1;
  934. }
  935. #endif /* support for community based SNMP */
  936. netsnmp_transport *
  937. netsnmp_udp_create_tstring(const char *str, int local)
  938. {
  939.     struct sockaddr_in addr;
  940.     if (netsnmp_sockaddr_in(&addr, str, 0)) {
  941.         return netsnmp_udp_transport(&addr, local);
  942.     } else {
  943.         return NULL;
  944.     }
  945. }
  946. netsnmp_transport *
  947. netsnmp_udp_create_ostring(const u_char * o, size_t o_len, int local)
  948. {
  949.     struct sockaddr_in addr;
  950.     if (o_len == 6) {
  951.         unsigned short porttmp = (o[4] << 8) + o[5];
  952.         addr.sin_family = AF_INET;
  953.         memcpy((u_char *) & (addr.sin_addr.s_addr), o, 4);
  954.         addr.sin_port = htons(porttmp);
  955.         return netsnmp_udp_transport(&addr, local);
  956.     }
  957.     return NULL;
  958. }
  959. void
  960. netsnmp_udp_ctor(void)
  961. {
  962.     udpDomain.name = netsnmpUDPDomain;
  963.     udpDomain.name_length = netsnmpUDPDomain_len;
  964.     udpDomain.prefix = calloc(2, sizeof(char *));
  965.     udpDomain.prefix[0] = "udp";
  966.     udpDomain.f_create_from_tstring = netsnmp_udp_create_tstring;
  967.     udpDomain.f_create_from_ostring = netsnmp_udp_create_ostring;
  968.     netsnmp_tdomain_register(&udpDomain);
  969. }