The only functional change in this patch is that it is now allowed to surround IPv4 addresses and hostnames with square brackets in transport endpoint definitions. --- include/net-snmp/library/snmpIPBaseDomain.h | 16 ++ include/net-snmp/library/snmpIPv4BaseDomain.h | 2 + include/net-snmp/library/snmpIPv6BaseDomain.h | 2 + snmplib/transports/snmpIPBaseDomain.c | 79 +++++++ snmplib/transports/snmpIPv4BaseDomain.c | 92 ++------ snmplib/transports/snmpIPv6BaseDomain.c | 204 ++---------------- win32/libsnmp/Makefile.in | 1 + win32/libsnmp_dll/Makefile.in | 1 + 8 files changed, 134 insertions(+), 263 deletions(-) create mode 100644 include/net-snmp/library/snmpIPBaseDomain.h create mode 100644 snmplib/transports/snmpIPBaseDomain.c
diff --git a/include/net-snmp/library/snmpIPBaseDomain.h b/include/net-snmp/library/snmpIPBaseDomain.h new file mode 100644 index 000000000000..fb79a9365c4e --- /dev/null +++ b/include/net-snmp/library/snmpIPBaseDomain.h @@ -0,0 +1,16 @@ +#ifndef _SNMPIPBASEDOMAIN_H_ +#define _SNMPIPBASEDOMAIN_H_ + +/** + * SNMP endpoint with the network name in ASCII format. + * @addr: Network address or host name as an ASCII string. + * @port: Port number in host byte format. + */ +struct netsnmp_ep_str { + char addr[64]; + uint16_t port; +}; + +int netsnmp_parse_ep_str(struct netsnmp_ep_str *ep_str, const char *endpoint); + +#endif /* _SNMPIPBASEDOMAIN_H_ */ diff --git a/include/net-snmp/library/snmpIPv4BaseDomain.h b/include/net-snmp/library/snmpIPv4BaseDomain.h index cb6a4585cf48..71804e3b1d72 100644 --- a/include/net-snmp/library/snmpIPv4BaseDomain.h +++ b/include/net-snmp/library/snmpIPv4BaseDomain.h @@ -9,6 +9,8 @@ #include <net-snmp/library/snmp_transport.h> +config_require(IPBase) + #ifdef __cplusplus extern "C" { #endif diff --git a/include/net-snmp/library/snmpIPv6BaseDomain.h b/include/net-snmp/library/snmpIPv6BaseDomain.h index 5c7d11cfd560..2f44e6a1b088 100644 --- a/include/net-snmp/library/snmpIPv6BaseDomain.h +++ b/include/net-snmp/library/snmpIPv6BaseDomain.h @@ -7,6 +7,8 @@ #include <netinet/in.h> #endif +config_require(IPBase) + #include <net-snmp/library/snmp_transport.h> #ifdef __cplusplus diff --git a/snmplib/transports/snmpIPBaseDomain.c b/snmplib/transports/snmpIPBaseDomain.c new file mode 100644 index 000000000000..ac94ba73840d --- /dev/null +++ b/snmplib/transports/snmpIPBaseDomain.c @@ -0,0 +1,79 @@ +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/types.h> +#include <net-snmp/library/system.h> +#include <net-snmp/library/snmpIPBaseDomain.h> +#include <ctype.h> +#include <stdlib.h> + +static int isnumber(const char *cp) +{ + while (isdigit((uint8_t)*cp)) + cp++; + return *cp == '\0'; +} + +/** + * Parse a Net-SNMP endpoint name. + * @ep_str: Parsed endpoint name. + * @endpoint: Endpoint specification in the format [<address>]:[<port>] or + * <port>. + * + * Only overwrite those fields of *@ep_str that have been set in + * @endpoint. Returns 1 upon success and 0 upon failure. + */ +int netsnmp_parse_ep_str(struct netsnmp_ep_str *ep_str, const char *endpoint) +{ + char *dup, *cp, *addrstr = NULL, *portstr = NULL; + unsigned port; + + if (!endpoint) + return 0; + + dup = strdup(endpoint); + if (!dup) + return 0; + + cp = dup; + if (isnumber(cp)) { + portstr = cp; + } else { + if (*cp == '[') { + addrstr = cp + 1; + cp = strchr(cp, ']'); + if (cp) { + cp[0] = '\0'; + cp++; + } else { + goto invalid; + } + } else if (*cp != ':') { + addrstr = cp; + cp = strrchr(cp, ':'); + } + if (cp && *cp == ':') { + *cp++ = '\0'; + portstr = cp; + if (!isnumber(cp)) + goto invalid; + } else if (cp && *cp) { + goto invalid; + } + } + + if (addrstr) + strlcpy(ep_str->addr, addrstr, sizeof(ep_str->addr)); + if (portstr) { + port = atoi(portstr); + if (port > 0 && port <= 0xffff) + ep_str->port = port; + else + goto invalid; + } + + free(dup); + return 1; + +invalid: + free(dup); + return 0; +} diff --git a/snmplib/transports/snmpIPv4BaseDomain.c b/snmplib/transports/snmpIPv4BaseDomain.c index 37ef72d4ed42..003e53a49e45 100644 --- a/snmplib/transports/snmpIPv4BaseDomain.c +++ b/snmplib/transports/snmpIPv4BaseDomain.c @@ -4,6 +4,7 @@ #include <net-snmp/net-snmp-config.h> #include <net-snmp/types.h> +#include <net-snmp/library/snmpIPBaseDomain.h> #include <net-snmp/library/snmpIPv4BaseDomain.h> #include <net-snmp/library/snmp_assert.h> @@ -56,6 +57,7 @@ int netsnmp_sockaddr_in2(struct sockaddr_in *addr, const char *inpeername, const char *default_target) { + struct netsnmp_ep_str ep_str; int ret; if (addr == NULL) { @@ -72,106 +74,42 @@ netsnmp_sockaddr_in2(struct sockaddr_in *addr, addr->sin_family = AF_INET; addr->sin_port = htons((u_short)SNMP_PORT); + memset(&ep_str, 0, sizeof(ep_str)); { int port = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DEFAULT_PORT); if (port != 0) { - addr->sin_port = htons((u_short)port); - } else if (default_target != NULL) + ep_str.port = port; + } else if (default_target != NULL) { netsnmp_sockaddr_in2(addr, default_target, NULL); - } - - if (inpeername != NULL && *inpeername != '\0') { - const char *host, *port; - char *peername = NULL; - char *cp; - /* - * Duplicate the peername because we might want to mank around with - * it. - */ - - peername = strdup(inpeername); - if (peername == NULL) { - return 0; - } - - /* - * Try and extract an appended port number. - */ - cp = strchr(peername, ':'); - if (cp != NULL) { - *cp = '\0'; - port = cp + 1; - host = peername; - } else { - host = NULL; - port = peername; + strlcpy(ep_str.addr, inet_ntoa(addr->sin_addr), sizeof(ep_str.addr)); + ep_str.port = ntohs(addr->sin_port); } + } - /* - * Try to convert the user port specifier - */ - if (port && *port == '\0') - port = NULL; - - if (port != NULL) { - long int l; - char* ep; - - DEBUGMSGTL(("netsnmp_sockaddr_in", "check user service %s\n", - port)); - - l = strtol(port, &ep, 10); - if (ep != port && *ep == '\0' && 0 <= l && l <= 0x0ffff) - addr->sin_port = htons((u_short)l); - else { - if (host == NULL) { - DEBUGMSGTL(("netsnmp_sockaddr_in", - "servname not numeric, " - "check if it really is a destination)\n")); - host = port; - port = NULL; - } else { - DEBUGMSGTL(("netsnmp_sockaddr_in", - "servname not numeric\n")); - free(peername); - return 0; - } - } - } - - /* - * Try to convert the user host specifier - */ - if (host && *host == '\0') - host = NULL; - - if (host != NULL) { - DEBUGMSGTL(("netsnmp_sockaddr_in", - "check destination %s\n", host)); - - - if (strcmp(peername, "255.255.255.255") == 0 ) { + if (inpeername && *inpeername != '\0') { + if (netsnmp_parse_ep_str(&ep_str, inpeername)) { + if (ep_str.port) + addr->sin_port = htons(ep_str.port); + if (strcmp(ep_str.addr, "255.255.255.255") == 0 ) { /* * The explicit broadcast address hack */ DEBUGMSGTL(("netsnmp_sockaddr_in", "Explicit UDP broadcast\n")); addr->sin_addr.s_addr = INADDR_NONE; } else { - ret = - netsnmp_gethostbyname_v4(peername, &addr->sin_addr.s_addr); + ret = netsnmp_gethostbyname_v4(ep_str.addr, + &addr->sin_addr.s_addr); if (ret < 0) { DEBUGMSGTL(("netsnmp_sockaddr_in", "couldn't resolve hostname\n")); - free(peername); return 0; } DEBUGMSGTL(("netsnmp_sockaddr_in", "hostname (resolved okay)\n")); } } - free(peername); } /* diff --git a/snmplib/transports/snmpIPv6BaseDomain.c b/snmplib/transports/snmpIPv6BaseDomain.c index b1c1afce3ded..600bc602428b 100644 --- a/snmplib/transports/snmpIPv6BaseDomain.c +++ b/snmplib/transports/snmpIPv6BaseDomain.c @@ -15,6 +15,7 @@ #ifdef NETSNMP_ENABLE_IPV6 #include <net-snmp/types.h> +#include <net-snmp/library/snmpIPBaseDomain.h> #include <net-snmp/library/snmpIPv6BaseDomain.h> #include <net-snmp/library/system.h> #include <net-snmp/library/snmp_assert.h> @@ -247,9 +248,7 @@ int netsnmp_sockaddr_in6_2(struct sockaddr_in6 *addr, const char *inpeername, const char *default_target) { - char *cp = NULL, *peername = NULL; char debug_addr[INET6_ADDRSTRLEN]; - int portno; if (addr == NULL) { return 0; @@ -275,205 +274,38 @@ netsnmp_sockaddr_in6_2(struct sockaddr_in6 *addr, } if (inpeername != NULL) { - /* - * Duplicate the peername because we might want to mank around with - * it. - */ - - peername = strdup(inpeername); - if (peername == NULL) { - return 0; - } - - cp = peername; - if (*cp == ':') cp++; - portno = atoi(cp); - while (*cp && isdigit((unsigned char) *cp)) cp++; - if (!*cp && portno != 0) { - /* - * Okay, it looks like JUST a port number. - */ - DEBUGMSGTL(("netsnmp_sockaddr_in6_2", "totally numeric: %d\n", - portno)); - addr->sin6_port = htons((u_short)portno); - goto resolved; - } - - /* - * See if it is an IPv6 address covered with square brackets. Also check - * for an appended :port. - */ - if (*peername == '[') { - cp = strchr(peername, ']'); - if (cp != NULL) { - /* - * See if it is an IPv6 link-local address with interface - * name as <zone_id>, like fe80::1234%eth0. - * Please refer to the internet draft, IPv6 Scoped Address Architecture - * http://www.ietf.org/internet-drafts/draft-ietf-ipngwg-scoping-arch-04.txt - * - */ - char *scope_id; -#if HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID - unsigned int if_index = 0; -#endif - *cp = '\0'; - scope_id = strchr(peername + 1, '%'); - if (scope_id != NULL) { - *scope_id = '\0'; -#if HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID - if_index = netsnmp_if_nametoindex(scope_id + 1); -#endif - } - if (*(cp + 1) == ':') { - portno = atoi(cp+2); - if (portno != 0 && - inet_pton(AF_INET6, peername + 1, - (void *) &(addr->sin6_addr))) { - DEBUGMSGTL(("netsnmp_sockaddr_in6_2", - "IPv6 address with port suffix :%d\n", - portno)); - if (portno > 0 && portno <= 0xffff) { - addr->sin6_port = htons((u_short)portno); - } else { - DEBUGMSGTL(("netsnmp_sockaddr_in6_2", "invalid port number: %d", portno)); - free(peername); - return 0; - } - -#if defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID) - addr->sin6_scope_id = if_index; -#endif - goto resolved; - } - } else { - if (inet_pton - (AF_INET6, peername + 1, - (void *) &(addr->sin6_addr))) { - DEBUGMSGTL(("netsnmp_sockaddr_in6_2", - "IPv6 address with square brackets\n")); - portno = ntohs(addr->sin6_port); - if (portno == 0) - portno = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, - NETSNMP_DS_LIB_DEFAULT_PORT); - if (portno <= 0) - portno = SNMP_PORT; - addr->sin6_port = htons((u_short)portno); + struct netsnmp_ep_str ep_str; + + memset(&ep_str, 0, sizeof(ep_str)); + if (netsnmp_parse_ep_str(&ep_str, inpeername)) { + DEBUGMSGTL(("netsnmp_sockaddr_in6_2", "split: [%s]:%d", + ep_str.addr, ep_str.port)); + if (ep_str.addr[0]) { + char *scope_id; + + scope_id = strchr(ep_str.addr, '%'); + if (scope_id) { + *scope_id = '0'; #if defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID) - addr->sin6_scope_id = if_index; -#endif - goto resolved; - } - } - if (scope_id != NULL) { - *scope_id = '%'; - } - *cp = ']'; - } - } - - cp = strrchr(peername, ':'); - if (cp != NULL) { - char *scope_id; -#if HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID - unsigned int if_index = 0; -#endif - *cp = '\0'; - scope_id = strchr(peername + 1, '%'); - if (scope_id != NULL) { - *scope_id = '\0'; -#if HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID - if_index = netsnmp_if_nametoindex(scope_id + 1); + addr->sin6_scope_id = netsnmp_if_nametoindex(scope_id + 1); #endif - } - portno = atoi(cp + 1); - if (portno != 0 && - inet_pton(AF_INET6, peername, - (void *) &(addr->sin6_addr))) { - DEBUGMSGTL(("netsnmp_sockaddr_in6_2", - "IPv6 address with port suffix :%d\n", - atoi(cp + 1))); - if (portno > 0 && portno <= 0xffff) { - addr->sin6_port = htons((u_short)portno); - } else { - DEBUGMSGTL(("netsnmp_sockaddr_in6_2", "invalid port number: %d", portno)); - free(peername); - return 0; } - -#if defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID) - addr->sin6_scope_id = if_index; -#endif - goto resolved; - } - if (scope_id != NULL) { - *scope_id = '%'; - } - *cp = ':'; - } - - /* - * See if it is JUST an IPv6 address. - */ - if (inet_pton(AF_INET6, peername, (void *) &(addr->sin6_addr))) { - DEBUGMSGTL(("netsnmp_sockaddr_in6_2", "just IPv6 address\n")); - goto resolved; - } - - /* - * Well, it must be a hostname then, possibly with an appended :port. - * Sort that out first. - */ - - cp = strrchr(peername, ':'); - if (cp != NULL) { - *cp = '\0'; - portno = atoi(cp + 1); - if (portno != 0) { - DEBUGMSGTL(("netsnmp_sockaddr_in6_2", - "hostname(?) with port suffix :%d\n", - portno)); - if (portno > 0 && portno <= 0xffff) { - addr->sin6_port = htons((u_short)portno); - } else { - DEBUGMSGTL(("netsnmp_sockaddr_in6_2", "invalid port number: %d", portno)); - free(peername); + if (!inet_pton(AF_INET6, ep_str.addr, &addr->sin6_addr) && + !netsnmp_resolve_v6_hostname(&addr->sin6_addr, ep_str.addr)) return 0; - } - - } else { - /* - * No idea, looks bogus but we might as well pass the full thing to - * the name resolver below. - */ - *cp = ':'; - DEBUGMSGTL(("netsnmp_sockaddr_in6_2", - "hostname(?) with embedded ':'?\n")); } - /* - * Fall through. - */ + if (ep_str.port) + addr->sin6_port = htons(ep_str.port); } - if (peername[0] == '\0') { - DEBUGMSGTL(("netsnmp_sockaddr_in6_2", "empty hostname\n")); - free(peername); - return 0; - } - if (!netsnmp_resolve_v6_hostname(&addr->sin6_addr, peername)) { - free(peername); - return 0; - } } else { DEBUGMSGTL(("netsnmp_sockaddr_in6_2", "NULL peername")); return 0; } - resolved: DEBUGMSGTL(("netsnmp_sockaddr_in6_2", "return { AF_INET6, [%s]:%hu }\n", inet_ntop(AF_INET6, &addr->sin6_addr, debug_addr, sizeof(debug_addr)), ntohs(addr->sin6_port))); - free(peername); return 1; } diff --git a/win32/libsnmp/Makefile.in b/win32/libsnmp/Makefile.in index d5e173e9a124..88d24533abf6 100644 --- a/win32/libsnmp/Makefile.in +++ b/win32/libsnmp/Makefile.in @@ -55,6 +55,7 @@ LIB32_OBJS= \ "$(INTDIR)\snmp-tc.obj" \ "$(INTDIR)\snmp.obj" \ "$(INTDIR)\snmpCallbackDomain.obj" \ + "$(INTDIR)\snmpIPBaseDomain.obj" \ "$(INTDIR)\snmpIPv4BaseDomain.obj" \ "$(INTDIR)\snmpSocketBaseDomain.obj" \ "$(INTDIR)\snmpTCPBaseDomain.obj" \ diff --git a/win32/libsnmp_dll/Makefile.in b/win32/libsnmp_dll/Makefile.in index 3d05633b8856..bd36672dcdf4 100644 --- a/win32/libsnmp_dll/Makefile.in +++ b/win32/libsnmp_dll/Makefile.in @@ -55,6 +55,7 @@ LINK32_OBJS= \ "$(INTDIR)\snmp-tc.obj" \ "$(INTDIR)\snmp.obj" \ "$(INTDIR)\snmpCallbackDomain.obj" \ + "$(INTDIR)\snmpIPBaseDomain.obj" \ "$(INTDIR)\snmpIPv4BaseDomain.obj" \ "$(INTDIR)\snmpSocketBaseDomain.obj" \ "$(INTDIR)\snmpTCPBaseDomain.obj" \ -- 2.19.1 _______________________________________________ Net-snmp-coders mailing list Net-snmp-coders@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/net-snmp-coders