diff options
Diffstat (limited to 'nametoaddr.c')
-rw-r--r-- | nametoaddr.c | 459 |
1 files changed, 375 insertions, 84 deletions
diff --git a/nametoaddr.c b/nametoaddr.c index e6483a3..7c48bd3 100644 --- a/nametoaddr.c +++ b/nametoaddr.c @@ -23,7 +23,7 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include <config.h> #endif #ifdef DECNETLIB @@ -31,38 +31,101 @@ #include <netdnet/dnetdb.h> #endif -#ifdef WIN32 -#include <pcap-stdinc.h> - -#else /* WIN32 */ - -#include <sys/param.h> -#include <sys/types.h> /* concession to AIX */ -#include <sys/socket.h> -#include <sys/time.h> - -#include <netinet/in.h> -#endif /* WIN32 */ - -#ifndef WIN32 -#ifdef HAVE_ETHER_HOSTTON -/* - * XXX - do we need any of this if <netinet/if_ether.h> doesn't declare - * ether_hostton()? - */ -#ifdef HAVE_NETINET_IF_ETHER_H -struct mbuf; /* Squelch compiler warnings on some platforms for */ -struct rtentry; /* declarations in <net/if.h> */ -#include <net/if.h> /* for "struct ifnet" in "struct arpcom" on Solaris */ -#include <netinet/if_ether.h> -#endif /* HAVE_NETINET_IF_ETHER_H */ -#ifdef NETINET_ETHER_H_DECLARES_ETHER_HOSTTON -#include <netinet/ether.h> -#endif /* NETINET_ETHER_H_DECLARES_ETHER_HOSTTON */ -#endif /* HAVE_ETHER_HOSTTON */ -#include <arpa/inet.h> -#include <netdb.h> -#endif /* WIN32 */ +#ifdef _WIN32 + #include <winsock2.h> + #include <ws2tcpip.h> + + #ifdef INET6 + /* + * To quote the MSDN page for getaddrinfo() at + * + * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx + * + * "Support for getaddrinfo on Windows 2000 and older versions + * The getaddrinfo function was added to the Ws2_32.dll on Windows XP and + * later. To execute an application that uses this function on earlier + * versions of Windows, then you need to include the Ws2tcpip.h and + * Wspiapi.h files. When the Wspiapi.h include file is added, the + * getaddrinfo function is defined to the WspiapiGetAddrInfo inline + * function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo + * function is implemented in such a way that if the Ws2_32.dll or the + * Wship6.dll (the file containing getaddrinfo in the IPv6 Technology + * Preview for Windows 2000) does not include getaddrinfo, then a + * version of getaddrinfo is implemented inline based on code in the + * Wspiapi.h header file. This inline code will be used on older Windows + * platforms that do not natively support the getaddrinfo function." + * + * We use getaddrinfo(), so we include Wspiapi.h here. + */ + #include <wspiapi.h> + #endif /* INET6 */ +#else /* _WIN32 */ + #include <sys/param.h> + #include <sys/types.h> + #include <sys/socket.h> + #include <sys/time.h> + + #include <netinet/in.h> + + #ifdef HAVE_ETHER_HOSTTON + #if defined(NET_ETHERNET_H_DECLARES_ETHER_HOSTTON) + /* + * OK, just include <net/ethernet.h>. + */ + #include <net/ethernet.h> + #elif defined(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON) + /* + * OK, just include <netinet/ether.h> + */ + #include <netinet/ether.h> + #elif defined(SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON) + /* + * OK, just include <sys/ethernet.h> + */ + #include <sys/ethernet.h> + #elif defined(ARPA_INET_H_DECLARES_ETHER_HOSTTON) + /* + * OK, just include <arpa/inet.h> + */ + #include <arpa/inet.h> + #elif defined(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON) + /* + * OK, include <netinet/if_ether.h>, after all the other stuff we + * need to include or define for its benefit. + */ + #define NEED_NETINET_IF_ETHER_H + #else + /* + * We'll have to declare it ourselves. + * If <netinet/if_ether.h> defines struct ether_addr, include + * it. Otherwise, define it ourselves. + */ + #ifdef HAVE_STRUCT_ETHER_ADDR + #define NEED_NETINET_IF_ETHER_H + #else /* HAVE_STRUCT_ETHER_ADDR */ + struct ether_addr { + unsigned char ether_addr_octet[6]; + }; + #endif /* HAVE_STRUCT_ETHER_ADDR */ + #endif /* what declares ether_hostton() */ + + #ifdef NEED_NETINET_IF_ETHER_H + #include <net/if.h> /* Needed on some platforms */ + #include <netinet/in.h> /* Needed on some platforms */ + #include <netinet/if_ether.h> + #endif /* NEED_NETINET_IF_ETHER_H */ + + #ifndef HAVE_DECL_ETHER_HOSTTON + /* + * No header declares it, so declare it ourselves. + */ + extern int ether_hostton(const char *, struct ether_addr *); + #endif /* !defined(HAVE_DECL_ETHER_HOSTTON) */ + #endif /* HAVE_ETHER_HOSTTON */ + + #include <arpa/inet.h> + #include <netdb.h> +#endif /* _WIN32 */ #include <ctype.h> #include <errno.h> @@ -74,6 +137,7 @@ struct rtentry; /* declarations in <net/if.h> */ #include "gencode.h" #include <pcap/namedb.h> +#include "nametoaddr.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" @@ -84,11 +148,10 @@ struct rtentry; /* declarations in <net/if.h> */ #define NTOHS(x) (x) = ntohs(x) #endif -static inline int xdtoi(int); - /* * Convert host name to internet address. * Return 0 upon failure. + * XXX - not thread-safe; don't use it inside libpcap. */ bpf_u_int32 ** pcap_nametoaddr(const char *name) @@ -114,7 +177,6 @@ pcap_nametoaddr(const char *name) return 0; } -#ifdef INET6 struct addrinfo * pcap_nametoaddrinfo(const char *name) { @@ -131,28 +193,105 @@ pcap_nametoaddrinfo(const char *name) else return res; } -#endif /*INET6*/ /* * Convert net name to internet address. * Return 0 upon failure. + * XXX - not guaranteed to be thread-safe! See below for platforms + * on which it is thread-safe and on which it isn't. */ bpf_u_int32 pcap_nametonetaddr(const char *name) { -#ifndef WIN32 +#ifdef _WIN32 + /* + * There's no "getnetbyname()" on Windows. + * + * XXX - I guess we could use the BSD code to read + * C:\Windows\System32\drivers\etc/networks, assuming + * that's its home on all the versions of Windows + * we use, but that file probably just has the loopback + * network on 127/24 on 99 44/100% of Windows machines. + * + * (Heck, these days it probably just has that on 99 44/100% + * of *UN*X* machines.) + */ + return 0; +#else + /* + * UN*X. + */ struct netent *np; + #if defined(HAVE_LINUX_GETNETBYNAME_R) + /* + * We have Linux's reentrant getnetbyname_r(). + */ + struct netent result_buf; + char buf[1024]; /* arbitrary size */ + int h_errnoval; + int err; - if ((np = getnetbyname(name)) != NULL) - return np->n_net; - else + /* + * Apparently, the man page at + * + * http://man7.org/linux/man-pages/man3/getnetbyname_r.3.html + * + * lies when it says + * + * If the function call successfully obtains a network record, + * then *result is set pointing to result_buf; otherwise, *result + * is set to NULL. + * + * and, in fact, at least in some versions of GNU libc, it does + * *not* always get set if getnetbyname_r() succeeds. + */ + np = NULL; + err = getnetbyname_r(name, &result_buf, buf, sizeof buf, &np, + &h_errnoval); + if (err != 0) { + /* + * XXX - dynamically allocate the buffer, and make it + * bigger if we get ERANGE back? + */ return 0; -#else + } + #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R) /* - * There's no "getnetbyname()" on Windows. + * We have Solaris's and IRIX's reentrant getnetbyname_r(). */ - return 0; -#endif + struct netent result_buf; + char buf[1024]; /* arbitrary size */ + + np = getnetbyname_r(name, &result_buf, buf, (int)sizeof buf); + #elif defined(HAVE_AIX_GETNETBYNAME_R) + /* + * We have AIX's reentrant getnetbyname_r(). + */ + struct netent result_buf; + struct netent_data net_data; + + if (getnetbyname_r(name, &result_buf, &net_data) == -1) + np = NULL; + else + np = &result_buf; + #else + /* + * We don't have any getnetbyname_r(); either we have a + * getnetbyname() that uses thread-specific data, in which + * case we're thread-safe (sufficiently recent FreeBSD, + * sufficiently recent Darwin-based OS, sufficiently recent + * HP-UX, sufficiently recent Tru64 UNIX), or we have the + * traditional getnetbyname() (everything else, including + * current NetBSD and OpenBSD), in which case we're not + * thread-safe. + */ + np = getnetbyname(name); + #endif + if (np != NULL) + return np->n_net; + else + return 0; +#endif /* _WIN32 */ } /* @@ -163,20 +302,113 @@ pcap_nametonetaddr(const char *name) int pcap_nametoport(const char *name, int *port, int *proto) { - struct servent *sp; + struct addrinfo hints, *res, *ai; + int error; + struct sockaddr_in *in4; +#ifdef INET6 + struct sockaddr_in6 *in6; +#endif int tcp_port = -1; int udp_port = -1; /* + * We check for both TCP and UDP in case there are + * ambiguous entries. + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + error = getaddrinfo(NULL, name, &hints, &res); + if (error != 0) { + if (error != EAI_NONAME && + error != EAI_SERVICE) { + /* + * This is a real error, not just "there's + * no such service name". + * XXX - this doesn't return an error string. + */ + return 0; + } + } else { + /* + * OK, we found it. Did it find anything? + */ + for (ai = res; ai != NULL; ai = ai->ai_next) { + /* + * Does it have an address? + */ + if (ai->ai_addr != NULL) { + /* + * Yes. Get a port number; we're done. + */ + if (ai->ai_addr->sa_family == AF_INET) { + in4 = (struct sockaddr_in *)ai->ai_addr; + tcp_port = ntohs(in4->sin_port); + break; + } +#ifdef INET6 + if (ai->ai_addr->sa_family == AF_INET6) { + in6 = (struct sockaddr_in6 *)ai->ai_addr; + tcp_port = ntohs(in6->sin6_port); + break; + } +#endif + } + } + freeaddrinfo(res); + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + error = getaddrinfo(NULL, name, &hints, &res); + if (error != 0) { + if (error != EAI_NONAME && + error != EAI_SERVICE) { + /* + * This is a real error, not just "there's + * no such service name". + * XXX - this doesn't return an error string. + */ + return 0; + } + } else { + /* + * OK, we found it. Did it find anything? + */ + for (ai = res; ai != NULL; ai = ai->ai_next) { + /* + * Does it have an address? + */ + if (ai->ai_addr != NULL) { + /* + * Yes. Get a port number; we're done. + */ + if (ai->ai_addr->sa_family == AF_INET) { + in4 = (struct sockaddr_in *)ai->ai_addr; + udp_port = ntohs(in4->sin_port); + break; + } +#ifdef INET6 + if (ai->ai_addr->sa_family == AF_INET6) { + in6 = (struct sockaddr_in6 *)ai->ai_addr; + udp_port = ntohs(in6->sin6_port); + break; + } +#endif + } + } + freeaddrinfo(res); + } + + /* * We need to check /etc/services for ambiguous entries. - * If we find the ambiguous entry, and it has the + * If we find an ambiguous entry, and it has the * same port number, change the proto to PROTO_UNDEF * so both TCP and UDP will be checked. */ - sp = getservbyname(name, "tcp"); - if (sp != NULL) tcp_port = ntohs(sp->s_port); - sp = getservbyname(name, "udp"); - if (sp != NULL) udp_port = ntohs(sp->s_port); if (tcp_port >= 0) { *port = tcp_port; *proto = IPPROTO_TCP; @@ -255,12 +487,62 @@ pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto) return 1; } +/* + * XXX - not guaranteed to be thread-safe! See below for platforms + * on which it is thread-safe and on which it isn't. + */ int pcap_nametoproto(const char *str) { struct protoent *p; + #if defined(HAVE_LINUX_GETNETBYNAME_R) + /* + * We have Linux's reentrant getprotobyname_r(). + */ + struct protoent result_buf; + char buf[1024]; /* arbitrary size */ + int err; + + err = getprotobyname_r(str, &result_buf, buf, sizeof buf, &p); + if (err != 0) { + /* + * XXX - dynamically allocate the buffer, and make it + * bigger if we get ERANGE back? + */ + return 0; + } + #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R) + /* + * We have Solaris's and IRIX's reentrant getprotobyname_r(). + */ + struct protoent result_buf; + char buf[1024]; /* arbitrary size */ + p = getprotobyname_r(str, &result_buf, buf, (int)sizeof buf); + #elif defined(HAVE_AIX_GETNETBYNAME_R) + /* + * We have AIX's reentrant getprotobyname_r(). + */ + struct protoent result_buf; + struct protoent_data proto_data; + + if (getprotobyname_r(str, &result_buf, &proto_data) == -1) + p = NULL; + else + p = &result_buf; + #else + /* + * We don't have any getprotobyname_r(); either we have a + * getprotobyname() that uses thread-specific data, in which + * case we're thread-safe (sufficiently recent FreeBSD, + * sufficiently recent Darwin-based OS, sufficiently recent + * HP-UX, sufficiently recent Tru64 UNIX, Windows), or we have + * the traditional getprotobyname() (everything else, including + * current NetBSD and OpenBSD), in which case we're not + * thread-safe. + */ p = getprotobyname(str); + #endif if (p != 0) return p->p_proto; else @@ -274,8 +556,19 @@ struct eproto { u_short p; }; -/* Static data base of ether protocol types. */ -struct eproto eproto_db[] = { +/* + * Static data base of ether protocol types. + * tcpdump used to import this, and it's declared as an export on + * Debian, at least, so make it a public symbol, even though we + * don't officially export it by declaring it in a header file. + * (Programs *should* do this themselves, as tcpdump now does.) + * + * We declare it here, right before defining it, to squelch any + * warnings we might get from compilers about the lack of a + * declaration. + */ +PCAP_API struct eproto eproto_db[]; +PCAP_API_DEF struct eproto eproto_db[] = { { "pup", ETHERTYPE_PUP }, { "xns", ETHERTYPE_NS }, { "ip", ETHERTYPE_IP }, @@ -338,17 +631,16 @@ pcap_nametollc(const char *s) return PROTO_UNDEF; } -/* Hex digit to integer. */ -static inline int -xdtoi(c) - register int c; +/* Hex digit to 8-bit unsigned integer. */ +static inline u_char +xdtoi(u_char c) { if (isdigit(c)) - return c - '0'; + return (u_char)(c - '0'); else if (islower(c)) - return c - 'a' + 10; + return (u_char)(c - 'a' + 10); else - return c - 'A' + 10; + return (u_char)(c - 'A' + 10); } int @@ -359,7 +651,7 @@ __pcap_atoin(const char *s, bpf_u_int32 *addr) *addr = 0; len = 0; - while (1) { + for (;;) { n = 0; while (*s && *s != '.') n = n * 10 + *s++ - '0'; @@ -383,7 +675,7 @@ __pcap_atodn(const char *s, bpf_u_int32 *addr) u_int node, area; if (sscanf(s, "%d.%d", &area, &node) != 2) - bpf_error("malformed decnet address '%s'", s); + return(0); *addr = (area << AREASHIFT) & AREAMASK; *addr |= (node & NODEMASK); @@ -407,7 +699,7 @@ u_char * pcap_ether_aton(const char *s) { register u_char *ep, *e; - register u_int d; + register u_char d; e = ep = (u_char *)malloc(6); if (e == NULL) @@ -428,7 +720,11 @@ pcap_ether_aton(const char *s) } #ifndef HAVE_ETHER_HOSTTON -/* Roll our own */ +/* + * Roll our own. + * XXX - not thread-safe, because pcap_next_etherent() isn't thread- + * safe! Needs a mutex or a thread-safe pcap_next_etherent(). + */ u_char * pcap_ether_hostton(const char *name) { @@ -460,17 +756,10 @@ pcap_ether_hostton(const char *name) return (NULL); } #else - -#if !defined(HAVE_DECL_ETHER_HOSTTON) || !HAVE_DECL_ETHER_HOSTTON -#ifndef HAVE_STRUCT_ETHER_ADDR -struct ether_addr { - unsigned char ether_addr_octet[6]; -}; -#endif -extern int ether_hostton(const char *, struct ether_addr *); -#endif - -/* Use the os supplied routines */ +/* + * Use the OS-supplied routine. + * This *should* be thread-safe; the API doesn't have a static buffer. + */ u_char * pcap_ether_hostton(const char *name) { @@ -487,23 +776,25 @@ pcap_ether_hostton(const char *name) } #endif -u_short -__pcap_nametodnaddr(const char *name) -{ +/* + * XXX - not guaranteed to be thread-safe! + */ +int #ifdef DECNETLIB +__pcap_nametodnaddr(const char *name, u_short *res) +{ struct nodeent *getnodebyname(); struct nodeent *nep; - unsigned short res; nep = getnodebyname(name); if (nep == ((struct nodeent *)0)) - bpf_error("unknown decnet host name '%s'\n", name); + return(0); - memcpy((char *)&res, (char *)nep->n_addr, sizeof(unsigned short)); - return(res); + memcpy((char *)res, (char *)nep->n_addr, sizeof(unsigned short)); + return(1); #else - bpf_error("decnet name support not included, '%s' cannot be translated\n", - name); +__pcap_nametodnaddr(const char *name _U_, u_short *res _U_) +{ return(0); #endif } |