diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/Makefile.am | 1 | ||||
-rw-r--r-- | common/snmp-engine.c | 101 | ||||
-rw-r--r-- | common/sock-any.c | 426 | ||||
-rw-r--r-- | common/sock-any.h | 103 |
4 files changed, 69 insertions, 562 deletions
diff --git a/common/Makefile.am b/common/Makefile.am index 61ef9a4..f2bf754 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -8,7 +8,6 @@ libcommon_a_SOURCES = \ hash.h hash.c \ log.h log.c \ server-mainloop.c server-mainloop.h \ - sock-any.h sock-any.c \ snmp-engine.h snmp-engine.c \ usuals.h diff --git a/common/snmp-engine.c b/common/snmp-engine.c index bb5d2fa..96fb812 100644 --- a/common/snmp-engine.c +++ b/common/snmp-engine.c @@ -43,7 +43,6 @@ #include "log.h" #include "server-mainloop.h" #include "snmp-engine.h" -#include "sock-any.h" #include <sys/types.h> #include <sys/socket.h> @@ -80,7 +79,8 @@ struct host { mstime interval; /* Host resolving and book keeping */ - struct sockaddr_any address; + struct sockaddr_storage address; + socklen_t address_len; mstime resolve_interval; mstime last_resolve_try; mstime last_resolved; @@ -113,9 +113,15 @@ resolve_cb (int ecode, struct addrinfo* ai, void* arg) return; } + if (ai->ai_addrlen > sizeof (host->address)) { + log_warnx ("resolved address is too long for host name: %s", + host->hostname); + return; + } + /* A successful resolve */ - memcpy (&SANY_ADDR (host->address), ai->ai_addr, ai->ai_addrlen); - SANY_LEN (host->address) = ai->ai_addrlen; + memcpy (&host->address, ai->ai_addr, ai->ai_addrlen); + host->address_len = ai->ai_addrlen; host->last_resolved = server_get_time (); host->is_resolved = 1; @@ -133,6 +139,7 @@ host_resolve (struct host *host, mstime when) memset (&hints, 0, sizeof (hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICSERV; /* Automatically strips port number */ log_debug ("resolving host: %s", host->hostname); @@ -198,6 +205,7 @@ host_update_interval (struct host *host, mstime interval) static struct host* host_instance (const char *hostname, const char *community, int version, mstime interval) { + struct addrinfo hints, *ai; struct host *host; char key[128]; int r, initialize; @@ -217,19 +225,46 @@ host_instance (const char *hostname, const char *community, int version, mstime host = hsh_get (host_by_key, key, -1); if (!host) { + memset (&hints, 0, sizeof (hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICSERV | AI_NUMERICHOST; + + r = getaddrinfo (hostname, "161", &hints, &ai); + + /* Ignore error and try to resolve again later */ + if (r == EAI_NONAME || r == EAI_AGAIN || r == EAI_MEMORY) { + ai = NULL; + + /* Real errors */ + } else if (r != 0) { + log_warnx ("couldn't parse host address (ignoring): %s: %s", + hostname, gai_strerror (r)); + return NULL; + + /* Strango address */ + } else if (ai->ai_addrlen > sizeof (host->address)) { + log_warnx ("parsed host address is too big (ignoring): %s", hostname); + return NULL; + } + host = calloc (1, sizeof (struct host)); if (!host) { log_errorx ("out of memory"); + if (ai != NULL) + freeaddrinfo (ai); return NULL; } - /* Try and resolve the DNS name */ - r = sock_any_pton (hostname, &host->address, SANY_OPT_DEFPORT(161) | SANY_OPT_DEFLOCAL | - SANY_OPT_NORESOLV); - if (r == -1) { - log_warn ("couldn't parse host address (ignoring): %s", hostname); - free (host); - return NULL; + if (ai != NULL) { + memcpy (&host->address, ai->ai_addr, ai->ai_addrlen); + host->address_len = ai->ai_addrlen; + freeaddrinfo (ai); + host->must_resolve = 0; + host->is_resolved = 1; + } else { + host->must_resolve = 1; + host->is_resolved = 0; } /* And into the hash table */ @@ -244,14 +279,6 @@ host_instance (const char *hostname, const char *community, int version, mstime host->next = host_list; host_list = host; - /* - * If we got back SANY_AF_DNS, then it needs resolving. The actual - * interval and stuff are worked out in once all the hosts, polls etc... - * have been parsed. - */ - host->must_resolve = (r == SANY_AF_DNS); - host->is_resolved = (r != SANY_AF_DNS); - host->version = version; host->hostname = strdup (hostname); host->community = strdup (community); @@ -405,7 +432,7 @@ request_send (struct request* req, mstime when) log_error("couldn't encode snmp buffer"); } else { ret = sendto (snmp_socket, snmp_buffer, b.asn_ptr - snmp_buffer, 0, - &SANY_ADDR (req->host->address), SANY_LEN (req->host->address)); + (struct sockaddr*)&req->host->address, req->host->address_len); if (ret == -1) log_error ("couldn't send snmp packet to: %s", req->host->hostname); else @@ -560,30 +587,32 @@ request_other_dispatch (struct request* req, struct snmp_pdu* pdu) static void request_response (int fd, int type, void* arg) { + struct sockaddr_storage from; char hostname[MAXPATHLEN]; - struct sockaddr_any from; struct snmp_pdu pdu; struct asn_buf b; struct request* req; const char* msg; + socklen_t from_len; int len, ret; int ip, id; ASSERT (snmp_socket == fd); /* Read in the packet */ - - SANY_LEN (from) = sizeof (from); + from_len = sizeof (from); len = recvfrom (snmp_socket, snmp_buffer, sizeof (snmp_buffer), 0, - &SANY_ADDR (from), &SANY_LEN (from)); + (struct sockaddr*)&from, &from_len); if(len < 0) { if(errno != EAGAIN && errno != EWOULDBLOCK) log_error ("error receiving snmp packet from network"); return; } - if (sock_any_ntop (&from, hostname, MAXPATHLEN, 0) == -1) - strcpy(hostname, "[UNKNOWN]"); + if (getnameinfo ((struct sockaddr*)&from, from_len, + hostname, sizeof (hostname), NULL, 0, + NI_NUMERICHOST) != 0) + strcpy (hostname, "[UNKNOWN]"); /* Now parse the packet */ @@ -949,7 +978,8 @@ snmp_engine_sync (const char* host, const char* community, int version, void snmp_engine_init (const char *bindaddr, int retries) { - struct sockaddr_any addr; + struct addrinfo hints, *ai; + int r; snmp_retries = retries; @@ -961,20 +991,27 @@ snmp_engine_init (const char *bindaddr, int retries) if (!snmp_preparing) err (1, "out of memory"); - memset (&addr, 0, sizeof(addr)); if (!bindaddr) bindaddr = "0.0.0.0"; - if (sock_any_pton (bindaddr, &addr, SANY_OPT_DEFPORT (0) | SANY_OPT_DEFANY) < 0) - err (1, "couldn't parse bind address: %s", bindaddr); + memset (&hints, 0, sizeof (hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICSERV; + r = getaddrinfo (bindaddr, "0", &hints, &ai); + if (r != 0) + errx (1, "couldn't resolve bind address: %s: %s", bindaddr, gai_strerror (r)); ASSERT (snmp_socket == -1); - snmp_socket = socket (SANY_TYPE (addr), SOCK_DGRAM, 0); + snmp_socket = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (snmp_socket < 0) err (1, "couldn't open snmp socket"); - if (bind (snmp_socket, &SANY_ADDR (addr), SANY_LEN (addr)) < 0) + if (bind (snmp_socket, ai->ai_addr, ai->ai_addrlen) < 0) err (1, "couldn't listen on port"); + freeaddrinfo (ai); + if (server_watch (snmp_socket, SERVER_READ, request_response, NULL) == -1) err (1, "couldn't listen on socket"); diff --git a/common/sock-any.c b/common/sock-any.c deleted file mode 100644 index 583015f..0000000 --- a/common/sock-any.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright (c) 2004, Stefan Walter - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * * Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * * The names of contributors to this software may not be - * used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * - * CONTRIBUTORS - * Stef Walter <stef@memberwebs.com> - * - */ - -#include "config.h" - -#include <sys/types.h> -#include <sys/socket.h> - -#include <ctype.h> -#include <stdlib.h> -#include <errno.h> -#include <netdb.h> -#include <string.h> -#include <stdio.h> - -#include "sock-any.h" - -#include <arpa/inet.h> - -#define LOCALHOST_ADDR 0x7F000001 - -int sock_any_pton(const char* addr, struct sockaddr_any* any, int opts) -{ - size_t l; - char buf[256]; - char* t; - char* t2; - int defport = (opts & 0xFFFF); - - memset(any, 0, sizeof(*any)); - - /* Just a port? */ - do - { - #define PORT_CHARS "0123456789" - #define PORT_MIN 1 - #define PORT_MAX 5 - - int port = 0; - - l = strspn(addr, PORT_CHARS); - if(l < PORT_MIN || l > PORT_MAX || addr[l] != 0) - break; - - port = strtol(addr, &t2, 10); - if(*t2 || port <= 0 || port >= 65536) - break; - - any->s.in.sin_port = htons(port); - - /* Fill in the type based on defaults */ -#ifdef HAVE_INET6 - if(opts & SANY_OPT_DEFINET6) - any->s.in6.sin6_family = AF_INET6; - else -#endif - any->s.in.sin_family = AF_INET; - - /* Fill in the address based on defaults */ - if(opts & SANY_OPT_DEFLOCAL) - { -#ifdef HAVE_INET6 - if(opts & SANY_OPT_DEFINET6) - memcpy(&(any->s.in6.sin6_addr), &in6addr_loopback, sizeof(struct in6_addr)); - else -#endif - any->s.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - } - - /* - * Note the 'any' option is the default since we zero out - * the entire structure above. - */ - - any->namelen = sizeof(any->s.in); - return AF_INET; - } - while(0); - - /* Look and see if we can parse an ipv4 address */ - do - { - #define IPV4_PORT_CHARS - #define IPV4_CHARS "0123456789." - #define IPV4_MIN 3 - #define IPV4_MAX 21 - - int port = 0; - t = NULL; - - l = strlen(addr); - if(l < IPV4_MIN || l > IPV4_MAX) - break; - - strcpy(buf, addr); - - /* Find the last set that contains just numbers */ - l = strspn(buf, IPV4_CHARS); - if(l < IPV4_MIN) - break; - - /* Either end of string or port */ - if(buf[l] != 0 && buf[l] != ':') - break; - - /* Get the port out */ - if(buf[l] != 0) - { - t = buf + l + 1; - buf[l] = 0; - } - - if(t) - { - port = strtol(t, &t2, 10); - if(*t2 || port <= 0 || port >= 65536) - break; - } - - any->s.in.sin_family = AF_INET; - any->s.in.sin_port = htons((unsigned short)(port <= 0 ? defport : port)); - - if(inet_pton(AF_INET, buf, &(any->s.in.sin_addr)) <= 0) - break; - - any->namelen = sizeof(any->s.in); - return AF_INET; - } - while(0); - -#ifdef HAVE_INET6 - do - { - #define IPV6_CHARS "0123456789:abcdef" - #define IPV6_MIN 3 - #define IPV6_MAX 51 - - int port = -1; - t = NULL; - - l = strlen(addr); - if(l < IPV6_MIN || l > IPV6_MAX) - break; - - /* If it starts with a '[' then we can get port */ - if(addr[0] == '[') - { - port = 0; - addr++; - } - - strcpy(buf, addr); - - /* Find the last set that contains just numbers */ - l = strspn(buf, IPV6_CHARS); - if(l < IPV6_MIN) - break; - - /* Either end of string or port */ - if(buf[l] != 0) - { - /* If had bracket, then needs to end with a bracket */ - if(port != 0 || buf[l] != ']') - break; - - /* Get the port out */ - t = buf + l + 1; - buf[l] = 0; - - if(*t == ':') - t++; - } - - if(t && *t) - { - port = strtol(t, &t, 10); - if(*t || port <= 0 || port >= 65536) - break; - } - - any->s.in6.sin6_family = AF_INET6; - any->s.in6.sin6_port = htons((unsigned short)(port <= 0 ? defport : port)); - - if(inet_pton(AF_INET6, buf, &(any->s.in6.sin6_addr)) < 0) - break; - - any->namelen = sizeof(any->s.in6); - return AF_INET6; - } - while(0); -#endif - - /* A unix socket path */ - do - { - /* No colon and must have a path component */ - if(strchr(addr, ':') || !strchr(addr, '/')) - break; - - l = strlen(addr); - if(l >= sizeof(any->s.un.sun_path)) - { - errno = ENAMETOOLONG; - break; - } - - any->s.un.sun_family = AF_UNIX; - strcpy(any->s.un.sun_path, addr); - - any->namelen = sizeof(any->s.un) - (sizeof(any->s.un.sun_path) - l); - return AF_UNIX; - } - while(0); - - /* A DNS name and a port? */ - do - { - struct addrinfo* res; - int port = 0; - int family = 0; - t = NULL; - - l = strlen(addr); - if(l >= 255 || !isalpha(addr[0])) - { - errno = EINVAL; - break; - } - - /* Some basic illegal character checks */ - if(strcspn(addr, " /\\") != l) - { - errno = EINVAL; - break; - } - - strcpy(buf, addr); - - /* Find the last set that contains just numbers */ - t = strchr(buf, ':'); - if(t) - { - *t = 0; - t++; - } - - if(t) - { - port = strtol(t, &t2, 10); - if(*t2 || port <= 0 || port >= 65536) - { - errno = EDOM; - break; - } - } - - if(!(opts & SANY_OPT_NORESOLV)) - { - /* Try and resolve the domain name */ - if(getaddrinfo(buf, NULL, NULL, &res) != 0 || !res) - break; - - memcpy(&(any->s.a), res->ai_addr, sizeof(struct sockaddr)); - any->namelen = res->ai_addrlen; - family = any->s.a.sa_family; - freeaddrinfo(res); - } - else - { - family = SANY_AF_DNS; -#ifdef HAVE_INET6 - if(opts & SANY_OPT_DEFINET6) - { - any->s.a.sa_family = AF_INET6; - any->namelen = sizeof(any->s.in6); - } - else -#endif - { - any->s.a.sa_family = AF_INET; - any->namelen = sizeof(any->s.in); - } - } - - port = htons((unsigned short)(port <= 0 ? defport : port)); - - switch(any->s.a.sa_family) - { - case PF_INET: - any->s.in.sin_port = port; - break; -#ifdef HAVE_INET6 - case PF_INET6: - any->s.in6.sin6_port = port; - break; -#endif - }; - - return family; - } - while(0); - - return -1; -} - -int sock_any_ntop(const struct sockaddr_any* any, char* addr, size_t addrlen, int opts) -{ - char buf[1024]; - int len = 0; - int port = 0; - const char *address = NULL; - const char *prefix = ""; - const char *suffix = ""; - - switch(any->s.a.sa_family) - { - case AF_UNIX: - address = any->s.un.sun_path; - break; - - case AF_INET: - if(inet_ntop(any->s.a.sa_family, &(any->s.in.sin_addr), buf, sizeof(buf)) == NULL) - return -1; - address = buf; - if(!(opts & SANY_OPT_NOPORT)) - port = ntohs(any->s.in.sin_port); - break; - -#ifdef HAVE_INET6 - case AF_INET6: - if(!(opts & SANY_OPT_NOPORT)) - port = ntohs(any->s.in6.sin6_port); - if(inet_ntop(any->s.a.sa_family, &(any->s.in6.sin6_addr), buf, sizeof(buf)) == NULL) - return -1; - address = buf; - if(port != 0) - { - prefix = "["; - suffix = "]"; - } - break; -#endif - - default: - errno = EAFNOSUPPORT; - return -1; - } - - if(port != 0) - len = snprintf(addr, addrlen, "%s%s%s:%d", prefix, address, suffix, port); - else - len = snprintf(addr, addrlen, "%s%s%s", prefix, address, suffix); - - if(len >= addrlen) - { - errno = ENOSPC; - return -1; - } - - return 0; -} - -int sock_any_cmp(const struct sockaddr_any* a1, const struct sockaddr_any* a2, int opts) -{ - if(a1->s.a.sa_family != a2->s.a.sa_family) - return -1; - - switch(a1->s.a.sa_family) - { - case AF_UNIX: - return strcmp(a1->s.un.sun_path, a2->s.un.sun_path); - - case AF_INET: - if(memcmp(&(a1->s.in.sin_addr), &(a2->s.in.sin_addr), sizeof(a2->s.in.sin_addr)) != 0) - return -1; - if(!(opts && SANY_OPT_NOPORT) && a1->s.in.sin_port != a2->s.in.sin_port) - return -1; - return 0; -#ifdef HAVE_INET6 - case AF_INET6: - if(memcmp(&(a1->s.in6.sin6_addr), &(a2->s.in6.sin6_addr), sizeof(a2->s.in6.sin6_addr)) != 0) - return -1; - if(!(opts && SANY_OPT_NOPORT) && a1->s.in6.sin6_port != a2->s.in6.sin6_port) - return -1; - return 0; -#endif - default: - errno = EAFNOSUPPORT; - return -1; - } -} diff --git a/common/sock-any.h b/common/sock-any.h deleted file mode 100644 index e9b57ef..0000000 --- a/common/sock-any.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2004, Stefan Walter - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * * Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * * The names of contributors to this software may not be - * used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * - * CONTRIBUTORS - * Stef Walter <stef@memberwebs.com> - * - */ - -#ifndef __SOCK_ANY_H__ -#define __SOCK_ANY_H__ - -#include <sys/socket.h> -#include <sys/un.h> -#include <netinet/in.h> - -struct sockaddr_any -{ - union _sockaddr_any - { - /* The header */ - struct sockaddr a; - - /* The different types */ - struct sockaddr_un un; - struct sockaddr_in in; -#ifdef HAVE_INET6 - struct sockaddr_in6 in6; -#endif - } s; - size_t namelen; -}; - -#define SANY_ADDR(any) ((any).s.a) -#define SANY_LEN(any) ((any).namelen) -#define SANY_TYPE(any) ((any).s.a.sa_family) - -/* -------------------------------------------------------------------------- */ - -/* Returns AF_XXX family type or -1 */ -int sock_any_pton(const char* addr, struct sockaddr_any* any, int opts); - -/* The default port to fill in when no IP/IPv6 port specified */ -#define SANY_OPT_DEFPORT(p) (int)((p) & 0xFFFF) - -/* When only port specified default to IPANY */ -#define SANY_OPT_DEFANY 0x00000000 - -/* When only port specified default to LOCALHOST */ -#define SANY_OPT_DEFLOCAL 0x00100000 - -/* When only port specified default to IPv6 */ -#define SANY_OPT_DEFINET6 0x00200000 - -/* Don't resolve host name */ -#define SANY_OPT_NORESOLV 0x01000000 - -/* The family type returned when resolving is needed */ -#define SANY_AF_DNS 0x01000000 - -/* -------------------------------------------------------------------------- */ - -/* Returns -1 when failed */ -int sock_any_ntop(const struct sockaddr_any* any, char* addr, size_t addrlen, int opts); - -/* Don't print or compare the port */ -#define SANY_OPT_NOPORT 0x01000000 - -/* -------------------------------------------------------------------------- */ - -/* Returns 0 for equal */ -int sock_any_cmp(const struct sockaddr_any* a1, const struct sockaddr_any* a2, int opts); - -#endif /* __SOCK_ANY_H__ */ |