diff options
Diffstat (limited to 'freebsd/contrib/libpcap/nametoaddr.c')
-rw-r--r-- | freebsd/contrib/libpcap/nametoaddr.c | 440 |
1 files changed, 332 insertions, 108 deletions
diff --git a/freebsd/contrib/libpcap/nametoaddr.c b/freebsd/contrib/libpcap/nametoaddr.c index 7ef8f4cc..1d47ff9d 100644 --- a/freebsd/contrib/libpcap/nametoaddr.c +++ b/freebsd/contrib/libpcap/nametoaddr.c @@ -22,12 +22,10 @@ * * Name to id translation routines used by the scanner. * These functions are not time critical. - * - * $FreeBSD$ */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include <config.h> #endif #ifdef DECNETLIB @@ -36,62 +34,99 @@ #endif #ifdef _WIN32 -#include <pcap-stdinc.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. pcap-stdinc.h - * includes Ws2tcpip.h, so we don't need to include it ourselves. - */ -#include <Wspiapi.h> -#endif - + #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> /* 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> + #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> @@ -115,11 +150,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) @@ -145,7 +179,6 @@ pcap_nametoaddr(const char *name) return 0; } -#ifdef INET6 struct addrinfo * pcap_nametoaddrinfo(const char *name) { @@ -162,23 +195,17 @@ 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 - struct netent *np; - - if ((np = getnetbyname(name)) != NULL) - return np->n_net; - else - return 0; -#else +#ifdef _WIN32 /* * There's no "getnetbyname()" on Windows. * @@ -192,7 +219,66 @@ pcap_nametonetaddr(const char *name) * of *UN*X* machines.) */ return 0; -#endif +#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; + + 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; + } + #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R) + /* + * We have Solaris's and IRIX's reentrant getnetbyname_r(). + */ + 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 */ } /* @@ -203,20 +289,111 @@ 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) { + /* + * 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) { + /* + * 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; @@ -295,12 +472,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 @@ -320,18 +547,14 @@ struct eproto { * 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[] = { -#if 0 - /* The FreeBSD elf linker generates a request to copy this array - * (including its size) when you link with -lpcap. In order to - * not bump the major version number of this libpcap.so, we need - * to ensure that the array stays the same size. Since PUP is - * likely never seen in real life any more, it's the first to - * be sacrificed (in favor of ip6). - */ { "pup", ETHERTYPE_PUP }, -#endif { "xns", ETHERTYPE_NS }, { "ip", ETHERTYPE_IP }, #ifdef INET6 @@ -393,17 +616,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 @@ -414,7 +636,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'; @@ -462,7 +684,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) @@ -483,7 +705,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) { @@ -515,17 +741,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) { @@ -542,10 +761,13 @@ pcap_ether_hostton(const char *name) } #endif +/* + * XXX - not guaranteed to be thread-safe! + */ int +#ifdef DECNETLIB __pcap_nametodnaddr(const char *name, u_short *res) { -#ifdef DECNETLIB struct nodeent *getnodebyname(); struct nodeent *nep; @@ -556,6 +778,8 @@ __pcap_nametodnaddr(const char *name, u_short *res) memcpy((char *)res, (char *)nep->n_addr, sizeof(unsigned short)); return(1); #else +__pcap_nametodnaddr(const char *name _U_, u_short *res _U_) +{ return(0); #endif } |