Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > c0394d3068b44395994f031447c8052d > files > 64

net-snmp-5.3.2.2-7.el5_4.2.src.rpm

426355: Cannot set source agent address for SNMP traps

Author: Jan Safranek <jsafrane@redhat.com>

Introduce "v1trapaddress" snmpd config option, which defines agent address
set in SNMPv1 traps, i.e. inside the SNMPv1 TRAP-PDU, not UDP packet
source address. The agent sets arbitrary local address to the TRAP PDU
when this option is ommited.

diff -up net-snmp-5.3.2.2/agent/agent_read_config.c.trap-agent-addr net-snmp-5.3.2.2/agent/agent_read_config.c
--- net-snmp-5.3.2.2/agent/agent_read_config.c.trap-agent-addr	2008-08-05 15:07:57.000000000 +0200
+++ net-snmp-5.3.2.2/agent/agent_read_config.c	2008-08-05 15:07:57.000000000 +0200
@@ -240,6 +240,9 @@ init_agent_read_config(const char *app)
                                 snmpd_free_trapcommunity,
                                 "community-string");
 #endif /* support for community based SNMP */
+    netsnmp_ds_register_config(ASN_OCTET_STR, app, "v1trapaddress", 
+                               NETSNMP_DS_APPLICATION_ID, 
+                               NETSNMP_DS_AGENT_TRAP_ADDR);
 #ifdef HAVE_UNISTD_H
     register_app_config_handler("agentuser",
                                 snmpd_set_agent_user, NULL, "userid");
diff -up net-snmp-5.3.2.2/agent/agent_trap.c.trap-agent-addr net-snmp-5.3.2.2/agent/agent_trap.c
--- net-snmp-5.3.2.2/agent/agent_trap.c.trap-agent-addr	2007-03-12 20:40:42.000000000 +0100
+++ net-snmp-5.3.2.2/agent/agent_trap.c	2008-08-05 15:07:57.000000000 +0200
@@ -58,6 +58,7 @@
 #include <net-snmp/utilities.h>
 
 #include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
 #include <net-snmp/agent/agent_trap.h>
 #include <net-snmp/agent/snmp_agent.h>
 #include <net-snmp/agent/agent_callbacks.h>
@@ -632,6 +633,8 @@ netsnmp_send_traps(int trap, int specifi
     in_addr_t             *pdu_in_addr_t;
     u_long                 uptime;
     struct trap_sink *sink;
+    const char            *v1trapaddress;
+    int                    res;
 
     DEBUGMSGTL(( "trap", "send_trap %d %d ", trap, specific));
     DEBUGMSGOID(("trap", enterprise, enterprise_length));
@@ -785,7 +788,18 @@ netsnmp_send_traps(int trap, int specifi
      * Ensure that the v1 trap PDU includes the local IP address
      */
        pdu_in_addr_t = (in_addr_t *) template_v1pdu->agent_addr;
-      *pdu_in_addr_t = get_myaddr();
+       v1trapaddress = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
+                                      NETSNMP_DS_AGENT_TRAP_ADDR);
+       if (v1trapaddress != NULL) {
+           /* "v1trapaddress" was specified in config, try to resolve it */
+           res = netsnmp_gethostbyname_v4(v1trapaddress, pdu_in_addr_t);
+       }
+       if (v1trapaddress == NULL || res < 0) {
+           /* "v1trapaddress" was not specified in config or the resolution failed,
+            * try any local address */
+           *pdu_in_addr_t = get_myaddr();
+       }
+
     }
 
 
diff -up net-snmp-5.3.2.2/apps/snmptrap.c.trap-agent-addr net-snmp-5.3.2.2/apps/snmptrap.c
--- net-snmp-5.3.2.2/apps/snmptrap.c.trap-agent-addr	2005-04-01 00:42:20.000000000 +0200
+++ net-snmp-5.3.2.2/apps/snmptrap.c	2008-08-05 15:07:57.000000000 +0200
@@ -104,26 +104,6 @@ snmp_input(int operation,
     return 1;
 }
 
-in_addr_t
-parse_address(char *address)
-{
-    in_addr_t       addr;
-    struct sockaddr_in saddr;
-    struct hostent *hp;
-
-    if ((addr = inet_addr(address)) != -1)
-        return addr;
-    hp = gethostbyname(address);
-    if (hp == NULL) {
-        fprintf(stderr, "unknown host: %s\n", address);
-        exit(1);
-    } else {
-        memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
-        return saddr.sin_addr.s_addr;
-    }
-
-}
-
 static void
 optProc(int argc, char *const *argv, int opt)
 {
@@ -289,7 +269,11 @@ main(int argc, char *argv[])
         }
         agent = argv[arg];
         if (agent != NULL && strlen(agent) != 0) {
-            *pdu_in_addr_t = parse_address(agent);
+            int ret = netsnmp_gethostbyname_v4(agent, pdu_in_addr_t);
+            if (ret < 0) {
+                fprintf(stderr, "unknown host: %s\n", agent);
+                exit(1);
+            }
         } else {
             *pdu_in_addr_t = get_myaddr();
         }
diff -up net-snmp-5.3.2.2/include/net-snmp/agent/ds_agent.h.trap-agent-addr net-snmp-5.3.2.2/include/net-snmp/agent/ds_agent.h
--- net-snmp-5.3.2.2/include/net-snmp/agent/ds_agent.h.trap-agent-addr	2008-08-05 15:07:57.000000000 +0200
+++ net-snmp-5.3.2.2/include/net-snmp/agent/ds_agent.h	2008-08-05 15:07:57.000000000 +0200
@@ -35,6 +35,7 @@
 #define NETSNMP_DS_AGENT_PERL_INIT_FILE    4    /* used by embedded perl */
 #define NETSNMP_DS_SMUX_SOCKET    5     /* ip:port socket addr */
 #define NETSNMP_DS_NOTIF_LOG_CTX  6     /* "" | "snmptrapd" */
+#define NETSNMP_DS_AGENT_TRAP_ADDR      7     /* used as v1 trap agent addres */
 
 /*
  * integers 
diff -up net-snmp-5.3.2.2/include/net-snmp/library/system.h.trap-agent-addr net-snmp-5.3.2.2/include/net-snmp/library/system.h
--- net-snmp-5.3.2.2/include/net-snmp/library/system.h.trap-agent-addr	2004-10-21 01:52:36.000000000 +0200
+++ net-snmp-5.3.2.2/include/net-snmp/library/system.h	2008-08-05 15:07:57.000000000 +0200
@@ -107,6 +107,11 @@ SOFTWARE.
 
 #include <net-snmp/types.h>     /* For definition of in_addr_t */
 
+    /* Simply resolve a hostname and return first IPv4 address.
+     * Returns -1 on error */
+    int             netsnmp_gethostbyname_v4(const char* name,
+                                             in_addr_t *addr_out);
+
     in_addr_t       get_myaddr(void);
     long            get_uptime(void);
 
diff -up net-snmp-5.3.2.2/man/snmpd.conf.5.def.trap-agent-addr net-snmp-5.3.2.2/man/snmpd.conf.5.def
--- net-snmp-5.3.2.2/man/snmpd.conf.5.def.trap-agent-addr	2008-08-05 15:07:57.000000000 +0200
+++ net-snmp-5.3.2.2/man/snmpd.conf.5.def	2008-08-05 15:07:57.000000000 +0200
@@ -629,6 +629,12 @@ Ordinarily the corresponding MIB
 object (\fCsnmpEnableAuthenTraps.0\fR) is read-write, but specifying
 this directive makes this object read-only, and attempts to set the
 value via SET requests will result in a \fInotWritable\fR error response.
+.RE
+.IP "v1trapaddress HOST"
+defines the agent address, which is inserted into SNMPv1 TRAPs. Arbitrary local 
+IPv4 address is chosen if this option is ommited. This option is useful mainly 
+when the agent is visible from outside world by specific address only (e.g. 
+because of network address translation or firewall).
 .SS "DisMan Event MIB"
 The previous directives can be used to configure where traps should
 be sent, but are not concerned with \fIwhen\fR to send such traps
diff -up net-snmp-5.3.2.2/perl/SNMP/SNMP.xs.trap-agent-addr net-snmp-5.3.2.2/perl/SNMP/SNMP.xs
--- net-snmp-5.3.2.2/perl/SNMP/SNMP.xs.trap-agent-addr	2008-08-05 15:07:57.000000000 +0200
+++ net-snmp-5.3.2.2/perl/SNMP/SNMP.xs	2008-08-05 15:07:57.000000000 +0200
@@ -108,7 +108,6 @@ typedef struct snmp_xs_cb_data {
 
 static void __recalc_timeout _((struct timeval*,struct timeval*,
                                 struct timeval*,struct timeval*, int* ));
-static in_addr_t __parse_address _((char*));
 static int __is_numeric_oid _((char*));
 static int __is_leaf _((struct tree*));
 static int __translate_appl_type _((char*));
@@ -285,26 +284,6 @@ int *block;
    }
 }
 
-static in_addr_t
-__parse_address(address)
-char *address;
-{
-    in_addr_t addr;
-    struct sockaddr_in saddr;
-    struct hostent *hp;
-
-    if ((addr = inet_addr(address)) != -1)
-	return addr;
-    hp = gethostbyname(address);
-    if (hp == NULL){
-        return (-1); /* error value */
-    } else {
-	memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
-	return saddr.sin_addr.s_addr;
-    }
-
-}
-
 static int
 __is_numeric_oid (oidstr)
 char* oidstr;
@@ -4290,12 +4269,12 @@ snmp_trapV1(sess_ref,enterprise,agent,ge
 		  agent-address field to that.  Otherwise set it to
 		  our address.  */
               if (agent && strlen(agent)) {
-                 if (__parse_address(agent) == -1 && verbose) {
-		   warn("error:trap:invalid agent address: %s", agent);
-		   goto err;
-                 } else {
-		   *((in_addr_t *)pdu->agent_addr) = __parse_address(agent);
-		 }
+                 if (0 > netsnmp_gethostbyname_v4(agent, 
+                                                 (in_addr_t *)pdu->agent_addr)){
+                     if (verbose)
+                         warn("error:trap:invalid agent address: %s", agent);
+                     goto err;
+                 } 
               } else {
                  *((in_addr_t *)pdu->agent_addr) = get_myaddr();
               }
diff -up net-snmp-5.3.2.2/snmplib/snmpUDPDomain.c.trap-agent-addr net-snmp-5.3.2.2/snmplib/snmpUDPDomain.c
--- net-snmp-5.3.2.2/snmplib/snmpUDPDomain.c.trap-agent-addr	2008-08-05 15:07:57.000000000 +0200
+++ net-snmp-5.3.2.2/snmplib/snmpUDPDomain.c	2008-08-05 15:16:08.000000000 +0200
@@ -847,31 +847,14 @@ netsnmp_sockaddr_in(struct sockaddr_in *
             /*
              * Well, it must be a hostname then.  
              */
-#ifdef  HAVE_GETHOSTBYNAME
-            struct hostent *hp = gethostbyname(peername);
-            if (hp == NULL) {
+            int ret;
+            ret = netsnmp_gethostbyname_v4(peername, & addr->sin_addr.s_addr); 
+            if (ret < 0) { 
                 DEBUGMSGTL(("netsnmp_sockaddr_in",
                             "hostname (couldn't resolve)\n"));
                 free(peername);
                 return 0;
-            } else {
-                if (hp->h_addrtype != AF_INET) {
-                    DEBUGMSGTL(("netsnmp_sockaddr_in",
-                                "hostname (not AF_INET!)\n"));
-                    free(peername);
-                    return 0;
-                } else {
-                    DEBUGMSGTL(("netsnmp_sockaddr_in",
-                                "hostname (resolved okay)\n"));
-                    memcpy(&(addr->sin_addr), hp->h_addr, hp->h_length);
-                }
             }
-#else                           /*HAVE_GETHOSTBYNAME */
-            DEBUGMSGTL(("netsnmp_sockaddr_in",
-                        "hostname (no gethostbyname)\n"));
-            free(peername);
-            return 0;
-#endif                          /*HAVE_GETHOSTBYNAME */
         }
     } else {
         DEBUGMSGTL(("netsnmp_sockaddr_in", "NULL peername"));
@@ -994,25 +977,11 @@ netsnmp_udp_parse_security(const char *t
             /*
              * Nope, wasn't a dotted quad.  Must be a hostname.  
              */
-#ifdef  HAVE_GETHOSTBYNAME
-            struct hostent *hp = gethostbyname(source);
-            if (hp == NULL) {
-                config_perror("bad source address");
+            int ret = netsnmp_gethostbyname_v4(source, &network);
+            if (ret < 0) {
+                config_perror("cannot resolve source hostname");
                 return;
-            } else {
-                if (hp->h_addrtype != AF_INET) {
-                    config_perror("no IP address for source hostname");
-                    return;
-                }
-                network = *((in_addr_t *) hp->h_addr);
             }
-#else                           /*HAVE_GETHOSTBYNAME */
-            /*
-             * Oh dear.  
-             */
-            config_perror("cannot resolve source hostname");
-            return;
-#endif                          /*HAVE_GETHOSTBYNAME */
         }
     }
 
diff -up net-snmp-5.3.2.2/snmplib/system.c.trap-agent-addr net-snmp-5.3.2.2/snmplib/system.c
--- net-snmp-5.3.2.2/snmplib/system.c.trap-agent-addr	2005-08-30 02:29:24.000000000 +0200
+++ net-snmp-5.3.2.2/snmplib/system.c	2008-08-05 15:07:57.000000000 +0200
@@ -77,6 +77,10 @@ SOFTWARE.
 #if HAVE_NET_IF_H
 #include <net/if.h>
 #endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
 
 #if HAVE_SYS_SOCKIO_H
 #include <sys/sockio.h>
@@ -802,6 +806,84 @@ get_uptime(void)
 #endif                          /* ! WIN32 */
 /*******************************************************************/
 
+int
+netsnmp_gethostbyname_v4(const char* name, in_addr_t *addr_out)
+{
+
+#if HAVE_GETADDRINFO
+    struct addrinfo *addrs = NULL;
+    struct addrinfo hint;
+    int             err;
+
+    memset(&hint, 0, sizeof hint);
+    hint.ai_flags = 0;
+    hint.ai_family = PF_INET;
+    hint.ai_socktype = SOCK_DGRAM;
+    hint.ai_protocol = 0;
+
+    err = getaddrinfo(name, NULL, &hint, &addrs);
+    if (err != 0) {
+#if HAVE_GAI_STRERROR
+        snmp_log(LOG_ERR, "getaddrinfo: %s %s\n", name,
+                 gai_strerror(err));
+#else
+        snmp_log(LOG_ERR, "getaddrinfo: %s (error %d)\n", name,
+                 err);
+#endif
+        return -1;
+    }
+    if (addrs != NULL) {
+        memcpy(addr_out,
+               &((struct sockaddr_in *) addrs->ai_addr)->sin_addr,
+               sizeof(in_addr_t));
+        freeaddrinfo(addrs);
+    } else {
+        DEBUGMSGTL(("get_thisaddr",
+                    "Failed to resolve IPv4 hostname\n"));
+    }
+    return 0;
+
+#elif HAVE_GETHOSTBYNAME
+    struct hostent *hp = NULL;
+
+    hp = gethostbyname(host);
+    if (hp == NULL) {
+        DEBUGMSGTL(("get_thisaddr",
+                    "hostname (couldn't resolve)\n"));
+        return -1;
+    } else if (hp->h_addrtype != AF_INET) {
+        DEBUGMSGTL(("get_thisaddr",
+                    "hostname (not AF_INET!)\n"));
+        return -1;
+    } else {
+        DEBUGMSGTL(("get_thisaddr",
+                    "hostname (resolved okay)\n"));
+        memcpy(addr_out, hp->h_addr, sizeof(in_addr_t));
+    }
+    return 0;
+
+#elif HAVE_GETIPNODEBYNAME
+    struct hostent *hp = NULL;
+    int             err;
+
+    hp = getipnodebyname(peername, AF_INET, 0, &err);
+    if (hp == NULL) {
+        DEBUGMSGTL(("get_thisaddr",
+                    "hostname (couldn't resolve = %d)\n", err));
+        return -1;
+    }
+    DEBUGMSGTL(("get_thisaddr",
+                "hostname (resolved okay)\n"));
+    memcpy(addr_out, hp->h_addr, sizeof(in_addr_t));
+    return 0;
+
+#else /* HAVE_GETIPNODEBYNAME */
+    return -1;
+#endif
+}
+
+/*******************************************************************/
+
 #ifndef HAVE_STRNCASECMP
 
 /*