diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2002-06-07 03:32:05 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2002-06-07 03:32:05 +0000 |
commit | 7ab586a39aaba2282184b2e377a64b5c3d16ace5 (patch) | |
tree | 435bf7f430d17a473dd290ade0e70f3bd43c3148 | |
parent | e06010752854f5ea2eeb25c2b5694b82be59c2ea (diff) |
support scoped IPv6 address.
no visible API change, old config files work just fine.
now you can use expressions like "ALL: [fe80::%lo0/64]". theo ok
-rw-r--r-- | lib/libwrap/hosts_access.c | 220 | ||||
-rw-r--r-- | lib/libwrap/misc.c | 16 | ||||
-rw-r--r-- | lib/libwrap/socket.c | 177 | ||||
-rw-r--r-- | libexec/tcpd/tcpdchk/scaffold.c | 163 | ||||
-rw-r--r-- | libexec/tcpd/tcpdchk/scaffold.h | 4 | ||||
-rw-r--r-- | libexec/tcpd/tcpdchk/tcpdchk.c | 57 | ||||
-rw-r--r-- | libexec/tcpd/tcpdmatch/tcpdmatch.c | 100 |
7 files changed, 329 insertions, 408 deletions
diff --git a/lib/libwrap/hosts_access.c b/lib/libwrap/hosts_access.c index b1d183b06f6..1043d6d811f 100644 --- a/lib/libwrap/hosts_access.c +++ b/lib/libwrap/hosts_access.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hosts_access.c,v 1.7 2001/12/13 17:44:47 beck Exp $ */ +/* $OpenBSD: hosts_access.c,v 1.8 2002/06/07 03:32:04 itojun Exp $ */ /* * This module implements a simple access control language that is based on @@ -23,7 +23,7 @@ #if 0 static char sccsid[] = "@(#) hosts_access.c 1.21 97/02/12 02:13:22"; #else -static char rcsid[] = "$OpenBSD: hosts_access.c,v 1.7 2001/12/13 17:44:47 beck Exp $"; +static char rcsid[] = "$OpenBSD: hosts_access.c,v 1.8 2002/06/07 03:32:04 itojun Exp $"; #endif #endif @@ -45,12 +45,9 @@ static char rcsid[] = "$OpenBSD: hosts_access.c,v 1.7 2001/12/13 17:44:47 beck E #ifdef NETGROUP #include <netgroup.h> #endif +#include <netdb.h> -#ifndef INADDR_NONE -#define INADDR_NONE (-1) /* XXX should be 0xffffffff */ -#endif - /* Local stuff. */ #include "tcpd.h" @@ -85,16 +82,17 @@ int resident = (-1); /* -1, 0: unknown; +1: yes */ /* Forward declarations. */ -static int table_match(); -static int list_match(); -static int server_match(); -static int client_match(); -static int host_match(); -static int string_match(); -static int masked_match(); -static int masked_match4(); +static int table_match(char *, struct request_info *); +static int list_match(char *, struct request_info *, + int (*)(char *, struct request_info *)); +static int server_match(char *, struct request_info *); +static int client_match(char *, struct request_info *); +static int host_match(char *, struct host_info *); +static int string_match(char *, char *); +static int masked_match(char *, char *, char *); +static int masked_match4(char *, char *, char *); #ifdef INET6 -static int masked_match6(); +static int masked_match6(char *, char *, char *); #endif /* Size of logical line buffer. */ @@ -199,7 +197,7 @@ struct request_info *request; static int list_match(list, request, match_fn) char *list; struct request_info *request; -int (*match_fn) (); +int (*match_fn)(char *, struct request_info *); { char *tok; int l; @@ -333,9 +331,14 @@ char *string; #ifndef INET6 return masked_match4(net_tok, mask_tok, string); #else - if (dot_quad_addr_new(net_tok, NULL) - && dot_quad_addr_new(mask_tok, NULL) - && dot_quad_addr_new(string, NULL)) { + /* + * masked_match4() is kept just for supporting shortened IPv4 address form. + * If we could get rid of shortened IPv4 form, we could just always use + * masked_match6(). + */ + if (dot_quad_addr_new(net_tok, NULL) && + dot_quad_addr_new(mask_tok, NULL) && + dot_quad_addr_new(string, NULL)) { return masked_match4(net_tok, mask_tok, string); } else return masked_match6(net_tok, mask_tok, string); @@ -360,81 +363,152 @@ char *string; if (!dot_quad_addr_new(string, &addr)) return (NO); if (!dot_quad_addr_new(net_tok, &net) || - !dot_quad_addr_new(mask_tok, &mask)) { + !dot_quad_addr_new(mask_tok, &mask)) { tcpd_warn("bad net/mask expression: %s/%s", net_tok, mask_tok); return (NO); /* not tcpd_jump() */ } + + if ((net & ~mask) != 0) + tcpd_warn("host bits not all zero in %s/%s", net_tok, mask_tok); + return ((addr & mask) == net); } #ifdef INET6 -/* Ugly because it covers IPv4 mapped address. I hate mapped addresses. */ static int masked_match6(net_tok, mask_tok, string) char *net_tok; char *mask_tok; char *string; { - struct in6_addr net; - struct in6_addr mask; - struct in6_addr addr; - u_long masklen; - int fail; + union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } net, mask, addr; + struct addrinfo hints, *res; + unsigned long masklen; + char *ep; int i; - int maskoff; - int netaf; - char *p; - const int sizoff64 = sizeof(struct in6_addr) - sizeof(struct in_addr); - - memset(&addr, 0, sizeof(addr)); - if (inet_pton(AF_INET6, string, &addr) == 1) - ; /* okay */ - else if (inet_pton(AF_INET, string, &addr.s6_addr[sizoff64]) == 1) - addr.s6_addr[10] = addr.s6_addr[11] = 0xff; - else - return NO; - - memset(&net, 0, sizeof(net)); - if (inet_pton(AF_INET6, net_tok, &net) == 1) { - netaf = AF_INET6; - maskoff = 0; - } else if (inet_pton(AF_INET, net_tok, &net.s6_addr[sizoff64]) == 1) { - netaf = AF_INET; - maskoff = sizoff64; - net.s6_addr[10] = net.s6_addr[11] = 0xff; + char *np, *mp, *ap; + int alen; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(net_tok, "0", &hints, &res) == 0) { + if (res->ai_addrlen > sizeof(net) || res->ai_next) { + freeaddrinfo(res); + return NO; + } + memcpy(&net, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); } else return NO; - fail = 0; - if (mask_tok[strspn(mask_tok, "0123456789")] == '\0') { - errno = 0; - masklen = strtoul(mask_tok, &p, 10); - if (!*mask_tok || *p || (errno == ERANGE && masklen == ULONG_MAX)) - goto bogusmask; - masklen += maskoff * 8; - if (0 <= masklen && masklen <= 128) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = net.sa.sa_family; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + ep = NULL; + if (getaddrinfo(mask_tok, "0", &hints, &res) == 0) { + if (res->ai_family == AF_INET6 && + ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id) { + freeaddrinfo(res); + return NO; + } + if (res->ai_addrlen > sizeof(mask) || res->ai_next) { + freeaddrinfo(res); + return NO; + } + memcpy(&mask, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + } else { + ep = NULL; + masklen = strtoul(mask_tok, &ep, 10); + if (ep && !*ep) { memset(&mask, 0, sizeof(mask)); - memset(&mask, 0xff, masklen / 8); - if (masklen % 8) { - ((u_char *)&mask)[masklen / 8] = - (0xff00 >> (masklen % 8)) & 0xff; + mask.sa.sa_family = net.sa.sa_family; + mask.sa.sa_len = net.sa.sa_len; + switch (mask.sa.sa_family) { + case AF_INET: + mp = (char *)&mask.sin.sin_addr; + alen = sizeof(mask.sin.sin_addr); + break; + case AF_INET6: + mp = (char *)&mask.sin6.sin6_addr; + alen = sizeof(mask.sin6.sin6_addr); + break; + default: + return NO; } + if (masklen / 8 > alen) + return NO; + memset(mp, 0xff, masklen / 8); + if (masklen % 8) + mp[masklen / 8] = 0xff00 >> (masklen % 8); + } else + return NO; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(string, "0", &hints, &res) == 0) { + if (res->ai_addrlen > sizeof(addr) || res->ai_next) { + freeaddrinfo(res); + return NO; + } + /* special case - IPv4 mapped address */ + if (net.sa.sa_family == AF_INET && res->ai_family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr)) { + memset(&addr, 0, sizeof(addr)); + addr.sa.sa_family = net.sa.sa_family; + addr.sa.sa_len = net.sa.sa_len; + memcpy(&addr.sin.sin_addr, + &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr.s6_addr[12], + sizeof(addr.sin.sin_addr)); } else - fail++; - } else if (netaf == AF_INET6 && inet_pton(AF_INET6, mask_tok, &mask) == 1) - ; /* okay */ - else if (netaf == AF_INET - && inet_pton(AF_INET, mask_tok, &mask.s6_addr[12]) == 1) { - memset(&mask, 0xff, sizoff64); + memcpy(&addr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); } else -bogusmask: - fail++; - if (fail) { - tcpd_warn("bad net/mask expression: %s/%s", net_tok, mask_tok); - return (NO); /* not tcpd_jump() */ + return NO; + + if (net.sa.sa_family != mask.sa.sa_family || + net.sa.sa_family != addr.sa.sa_family) { + return NO; } + + switch (net.sa.sa_family) { + case AF_INET: + np = (char *)&net.sin.sin_addr; + mp = (char *)&mask.sin.sin_addr; + ap = (char *)&addr.sin.sin_addr; + alen = sizeof(net.sin.sin_addr); + break; + case AF_INET6: + np = (char *)&net.sin6.sin6_addr; + mp = (char *)&mask.sin6.sin6_addr; + ap = (char *)&addr.sin6.sin6_addr; + alen = sizeof(net.sin6.sin6_addr); + break; + default: + return NO; + } + + for (i = 0; i < alen; i++) + if (np[i] & ~mp[i]) { + tcpd_warn("host bits not all zero in %s/%s", net_tok, mask_tok); + break; + } + + for (i = 0; i < alen; i++) + ap[i] &= mp[i]; - for (i = 0; i < sizeof(addr); i++) - addr.s6_addr[i] &= mask.s6_addr[i]; - return (memcmp(&addr, &net, sizeof(addr)) == 0); + if (addr.sa.sa_family == AF_INET6 && addr.sin6.sin6_scope_id && + addr.sin6.sin6_scope_id != net.sin6.sin6_scope_id) + return NO; + return (memcmp(ap, np, alen) == 0); } #endif diff --git a/lib/libwrap/misc.c b/lib/libwrap/misc.c index 3ba0caaf023..8c5294cc795 100644 --- a/lib/libwrap/misc.c +++ b/lib/libwrap/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.4 2000/10/14 00:56:15 itojun Exp $ */ +/* $OpenBSD: misc.c,v 1.5 2002/06/07 03:32:04 itojun Exp $ */ /* * Misc routines that are used by tcpd and by tcpdchk. @@ -10,7 +10,7 @@ #if 0 static char sccsic[] = "@(#) misc.c 1.2 96/02/11 17:01:29"; #else -static char rcsid[] = "$OpenBSD: misc.c,v 1.4 2000/10/14 00:56:15 itojun Exp $"; +static char rcsid[] = "$OpenBSD: misc.c,v 1.5 2002/06/07 03:32:04 itojun Exp $"; #endif #endif @@ -23,10 +23,6 @@ static char rcsid[] = "$OpenBSD: misc.c,v 1.4 2000/10/14 00:56:15 itojun Exp $"; #include "tcpd.h" -#ifndef INADDR_NONE -#define INADDR_NONE (-1) /* XXX should be 0xffffffff */ -#endif - /* xgets - fgets() with backslash-newline stripping */ char *xgets(ptr, len, fp) @@ -60,13 +56,6 @@ char *split_at(string, delimiter) char *string; int delimiter; { -#if 0 - char *cp; - - if ((cp = strchr(string, delimiter)) != 0) - *cp++ = 0; - return (cp); -#else char *cp; int bracket; @@ -88,7 +77,6 @@ int delimiter; } } return NULL; -#endif } /* dot_quad_addr_new - convert dotted quad to internal form */ diff --git a/lib/libwrap/socket.c b/lib/libwrap/socket.c index 6e5532f8401..4ca3461c466 100644 --- a/lib/libwrap/socket.c +++ b/lib/libwrap/socket.c @@ -1,4 +1,4 @@ -/* $OpenBSD: socket.c,v 1.4 2001/11/07 18:49:21 deraadt Exp $ */ +/* $OpenBSD: socket.c,v 1.5 2002/06/07 03:32:04 itojun Exp $ */ /* * This module determines the type of socket (datagram, stream), the client @@ -21,7 +21,7 @@ #if 0 static char sccsid[] = "@(#) socket.c 1.15 97/03/21 19:27:24"; #else -static char rcsid[] = "$OpenBSD: socket.c,v 1.4 2001/11/07 18:49:21 deraadt Exp $"; +static char rcsid[] = "$OpenBSD: socket.c,v 1.5 2002/06/07 03:32:04 itojun Exp $"; #endif #endif @@ -43,35 +43,35 @@ static char rcsid[] = "$OpenBSD: socket.c,v 1.4 2001/11/07 18:49:21 deraadt Exp /* Forward declarations. */ -static void sock_sink(); - #ifdef APPEND_DOT +static const char *append_dot(const char *); +#endif +static void sock_sink(int); +#ifdef APPEND_DOT /* * Speed up DNS lookups by terminating the host name with a dot. Should be * done with care. The speedup can give problems with lookups from sources * that lack DNS-style trailing dot magic, such as local files or NIS maps. */ -static struct hostent *gethostbyname_dot(name) -char *name; +static const char * +append_dot(name) +const char *name; { - char dot_name[MAXHOSTNAMELEN + 1]; + static char hbuf[MAXHOSTNAMELEN + 1]; /* * Don't append dots to unqualified names. Such names are likely to come * from local hosts files or from NIS. */ - if (strchr(name, '.') == 0 || strlen(name) >= MAXHOSTNAMELEN - 1) { - return (gethostbyname(name)); - } else { - snprintf(dot_name, sizeof(dot_name), "%s.", name); - return (gethostbyname(dot_name)); - } + if (strchr(name, '.') == 0 || strlen(name) + 2 > sizeof(hbuf)) + strlcpy(hbuf, name, sizeof(hbuf)); + else + snprintf(hbuf, sizeof(hbuf), "%s.", name); + return hbuf; } - -#define gethostbyname gethostbyname_dot #endif /* sock_host - look up endpoint addresses and install conversion methods */ @@ -133,27 +133,12 @@ void sock_hostaddr(host) struct host_info *host; { struct sockaddr *sa = host->sin; - int alen, af; - char *ap; if (!sa) return; - switch (af = sa->sa_family) { - case AF_INET: - ap = (char *)&((struct sockaddr_in *)sa)->sin_addr; - alen = sizeof(struct in_addr); - break; -#ifdef INET6 - case AF_INET6: - ap = (char *)&((struct sockaddr_in6 *)sa)->sin6_addr; - alen = sizeof(struct in6_addr); - break; -#endif - default: - return; - } host->addr[0] = '\0'; - inet_ntop(af, ap, host->addr, sizeof(host->addr)); + getnameinfo(sa, sa->sa_len, host->addr, sizeof(host->addr), + NULL, 0, NI_NUMERICHOST); } /* sock_hostname - map endpoint address to host name */ @@ -161,95 +146,89 @@ struct host_info *host; void sock_hostname(host) struct host_info *host; { - struct sockaddr *sin = host->sin; - struct hostent *hp; - int i; - int af, alen; - char *ap; - char hbuf[MAXHOSTNAMELEN]; + struct sockaddr *sa = host->sin; + char h1[NI_MAXHOST], h2[NI_MAXHOST]; + struct addrinfo hints, *res, *res0; +#ifdef INET6 + struct sockaddr_in tmp; +#endif - /* - * On some systems, for example Solaris 2.3, gethostbyaddr(0.0.0.0) does - * not fail. Instead it returns "INADDR_ANY". Unfortunately, this does - * not work the other way around: gethostbyname("INADDR_ANY") fails. We - * have to special-case 0.0.0.0, in order to avoid false alerts from the - * host name/address checking code below. - */ - if (!sin) + if (!sa) return; - switch (af = sin->sa_family) { - case AF_INET: - if (((struct sockaddr_in *)sin)->sin_addr.s_addr == 0) - return; - ap = (char *)&((struct sockaddr_in *)sin)->sin_addr; - alen = sizeof(struct in_addr); - break; #ifdef INET6 - case AF_INET6: - ap = (char *)&((struct sockaddr_in6 *)sin)->sin6_addr; - alen = sizeof(struct in6_addr); - /* special case on reverse lookup: mapped addr. I hate it */ - if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { - af = AF_INET; - ap += (sizeof(struct in6_addr) - sizeof(struct in_addr)); - alen = sizeof(struct in_addr); - } - break; + /* special case on reverse lookup: mapped addr. I hate it */ + if (sa->sa_family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr)) { + memset(&tmp, 0, sizeof(tmp)); + tmp.sin_family = AF_INET; + tmp.sin_len = sizeof(struct sockaddr_in); + memcpy(&tmp.sin_addr, + &((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[12], 4); + sa = (struct sockaddr *)&tmp; + } #endif - default: + if (getnameinfo(sa, sa->sa_len, h1, sizeof(h1), NULL, 0, + NI_NUMERICHOST) != 0) { return; } - if ((hp = gethostbyaddr(ap, alen, af)) != 0) { - - strlcpy(host->name, hp->h_name, sizeof(host->name)); - + if (getnameinfo(sa, sa->sa_len, host->name, sizeof(host->name), NULL, 0, + NI_NAMEREQD) == 0) { /* * Verify that the address is a member of the address list returned - * by gethostbyname(hostname). + * by getaddrinfo(hostname). * - * Verify also that gethostbyaddr() and gethostbyname() return the same + * Verify also that getnameinfo() and getaddrinfo() return the same * hostname, or rshd and rlogind may still end up being spoofed. * - * On some sites, gethostbyname("localhost") returns "localhost.domain". + * On some sites, getaddrinfo("localhost") returns "localhost.domain". * This is a DNS artefact. We treat it as a special case. When we - * can't believe the address list from gethostbyname("localhost") + * can't believe the address list from getaddrinfo("localhost") * we're in big trouble anyway. */ - - if ((hp = gethostbyname2(host->name, af)) == 0) { - + memset(&hints, 0, sizeof(hints)); + hints.ai_family = sa->sa_family; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_CANONNAME; +#ifdef APPEND_DOT + if (getaddrinfo(append_dot(host->name), "0", &hints, &res0) != 0) +#else + if (getaddrinfo(host->name, "0", &hints, &res0) != 0) +#endif + { /* * Unable to verify that the host name matches the address. This * may be a transient problem or a botched name server setup. */ - tcpd_warn("can't verify hostname: gethostbyname2(%s, %d) failed", - host->name, af); - - } else if (STR_NE(host->name, hp->h_name) - && STR_NE(host->name, "localhost")) { - + tcpd_warn("can't verify hostname: getaddrinfo(%s, %d) failed", + host->name, hints.ai_family); + } else if (res0->ai_canonname && + STR_NE(host->name, res0->ai_canonname) && + STR_NE(host->name, "localhost")) { /* - * The gethostbyaddr() and gethostbyname() calls did not return + * The getnameinfo() and getaddrinfo() calls did not return * the same hostname. This could be a nameserver configuration * problem. It could also be that someone is trying to spoof us. */ - tcpd_warn("host name/name mismatch: %s != %.*s", - host->name, STRING_LENGTH, hp->h_name); - + tcpd_warn("host name/name mismatch: %s != %s", + host->name, res0->ai_canonname); + freeaddrinfo(res0); } else { - /* * The address should be a member of the address list returned by - * gethostbyname(). We should first verify that the h_addrtype - * field is AF_INET, but this program has already caused too much - * grief on systems with broken library code. + * getaddrinfo(). */ - for (i = 0; hp->h_addr_list[i]; i++) { - if (memcmp(hp->h_addr_list[i], (char *) ap, alen) == 0) - return; /* name is good, keep it */ + for (res = res0; res; res = res->ai_next) { + if (getnameinfo(res->ai_addr, res->ai_addrlen, h2, sizeof(h2), + NULL, 0, NI_NUMERICHOST) != 0) { + continue; + } + if (STR_EQ(h1, h2)) { + freeaddrinfo(res0); + return; + } } /* @@ -258,11 +237,11 @@ struct host_info *host; * server. */ - tcpd_warn("host name/address mismatch: %s != %.*s", - inet_ntop(af, ap, hbuf, sizeof(hbuf)), - STRING_LENGTH, hp->h_name); - } + tcpd_warn("host name/address mismatch: %s != %s", h1, + res0->ai_canonname ? res0->ai_canonname : "?"); + freeaddrinfo(res0); + } /* name is bad, clobber it */ strlcpy(host->name, paranoid, sizeof(host->name)); } @@ -274,13 +253,13 @@ static void sock_sink(fd) int fd; { char buf[BUFSIZ]; - struct sockaddr_storage sin; - int size = sizeof(sin); + struct sockaddr_storage ss; + int size = sizeof(ss); /* * Eat up the not-yet received datagram. Some systems insist on a * non-zero source address argument in the recvfrom() call below. */ - (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) & sin, &size); + (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) & ss, &size); } diff --git a/libexec/tcpd/tcpdchk/scaffold.c b/libexec/tcpd/tcpdchk/scaffold.c index 46a4797e1e4..582cea1d173 100644 --- a/libexec/tcpd/tcpdchk/scaffold.c +++ b/libexec/tcpd/tcpdchk/scaffold.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scaffold.c,v 1.5 2002/05/07 23:01:07 deraadt Exp $ */ +/* $OpenBSD: scaffold.c,v 1.6 2002/06/07 03:32:04 itojun Exp $ */ /* * Routines for testing only. Not really industrial strength. @@ -10,7 +10,7 @@ #if 0 static char sccs_id[] = "@(#) scaffold.c 1.5 95/01/03 09:13:48"; #else -static char rcsid[] = "$OpenBSD: scaffold.c,v 1.5 2002/05/07 23:01:07 deraadt Exp $"; +static char rcsid[] = "$OpenBSD: scaffold.c,v 1.6 2002/06/07 03:32:04 itojun Exp $"; #endif #endif @@ -43,119 +43,31 @@ static char rcsid[] = "$OpenBSD: scaffold.c,v 1.5 2002/05/07 23:01:07 deraadt Ex */ int allow_severity = SEVERITY; int deny_severity = LOG_WARNING; -int rfc931_timeout = RFC931_TIMEOUT; - -/* dup_hostent - create hostent in one memory block */ - -static struct hostent *dup_hostent(hp) -struct hostent *hp; -{ - struct hostent_block { - struct hostent host; - char *addr_list[1]; - }; - struct hostent_block *hb; - int count; - char *data; - char *addr; - - for (count = 0; hp->h_addr_list[count] != 0; count++) - /* void */ ; - - if ((hb = (struct hostent_block *) malloc(sizeof(struct hostent_block) - + (hp->h_length + sizeof(char *)) * count)) == 0) { - fprintf(stderr, "Sorry, out of memory\n"); - exit(1); - } - memset((char *) &hb->host, 0, sizeof(hb->host)); - hb->host.h_addrtype = hp->h_addrtype; - hb->host.h_length = hp->h_length; - hb->host.h_addr_list = hb->addr_list; - hb->host.h_addr_list[count] = 0; - data = (char *) (hb->host.h_addr_list + count + 1); - - for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { - hb->host.h_addr_list[count] = data + hp->h_length * count; - memcpy(hb->host.h_addr_list[count], addr, hp->h_length); - } - return (&hb->host); -} +int rfc931_timeout = RFC931_TIMEOUT; /* find_inet_addr - find all addresses for this host, result to free() */ -struct hostent *find_inet_addr(host) +struct addrinfo *find_inet_addr(host, flags) char *host; +int flags; { - struct in_addr addr; - struct hostent *hp; - static struct hostent h; - static char *addr_list[2]; -#ifdef INET6 - static struct in6_addr in6; -#endif - - /* - * Host address: translate it to internal form. - */ - if (dot_quad_addr_new(host, &addr.s_addr)) { - h.h_addr_list = addr_list; - h.h_addr_list[0] = (char *) &addr; - h.h_length = sizeof(addr); - h.h_addrtype = AF_INET; - return (dup_hostent(&h)); - } -#ifdef INET6 - if (inet_pton(AF_INET6, host, &in6) == 1) { - h.h_addr_list = addr_list; - h.h_addr_list[0] = (char *) &in6; - h.h_length = sizeof(in6); - h.h_addrtype = AF_INET6; - return (dup_hostent(&h)); - } -#endif - - /* - * Map host name to a series of addresses. Watch out for non-internet - * forms or aliases. The NOT_INADDR() is here in case gethostbyname() has - * been "enhanced" to accept numeric addresses. Make a copy of the - * address list so that later gethostbyXXX() calls will not clobber it. - */ -#ifdef INET6 - if (NOT_INADDR(host) == 0 && inet_pton(AF_INET6, host, &in6) == 1) -#else - if (NOT_INADDR(host) == 0) -#endif - { - tcpd_warn("%s: not an internet address", host); - return (0); - } -#ifdef INET6 - /* - * XXX this behavior may, or may not be desirable. - * - we may better use getipnodebyname() to addresses of get both AFs, - * however, getipnodebyname() is not widely implemented. - * - it may be better to have a way to specify the AF to use. - */ - if ((hp = gethostbyname2(host, AF_INET)) == 0 - && (hp = gethostbyname2(host, AF_INET6)) == 0) { - tcpd_warn("%s: host not found", host); - return (0); - } -#else - if ((hp = gethostbyname(host)) == 0) { - tcpd_warn("%s: host not found", host); + struct addrinfo hints, *res; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_CANONNAME | flags; + error = getaddrinfo(host, "0", &hints, &res); + if (error) { + tcpd_warn("%s: %s", host, gai_strerror(error)); return (0); } - if (hp->h_addrtype != AF_INET) { - tcpd_warn("%d: not an internet host", hp->h_addrtype); - return (0); - } -#endif - if (STR_NE(host, hp->h_name)) { + + if (res->ai_canonname && STR_NE(host, res->ai_canonname)) { tcpd_warn("%s: hostname alias", host); - tcpd_warn("(official name: %s)", hp->h_name); + tcpd_warn("(official name: %.*s)", STRING_LENGTH, res->ai_canonname); } - return (dup_hostent(hp)); + return (res); } /* check_dns - give each address thorough workout, return address count */ @@ -164,36 +76,22 @@ int check_dns(host) char *host; { struct request_info request; - struct sockaddr_storage sin; - struct hostent *hp; + struct sockaddr_storage ss; + struct addrinfo *res0, *res; int count; - char *addr; - char *ap; - int alen; - if ((hp = find_inet_addr(host)) == 0) + if ((res0 = find_inet_addr(host, 0)) == NULL) return (0); - request_init(&request, RQ_CLIENT_SIN, &sin, 0); + memset(&ss, 0, sizeof(ss)); + request_init(&request, RQ_CLIENT_SIN, &ss, 0); sock_methods(&request); - memset((char *) &sin, 0, sizeof(sin)); - sin.ss_family = hp->h_addrtype; - switch (hp->h_addrtype) { - case AF_INET: - ap = (char *)&((struct sockaddr_in *)&sin)->sin_addr; - alen = sizeof(struct in_addr); - break; -#ifdef INET6 - case AF_INET6: - ap = (char *)&((struct sockaddr_in6 *)&sin)->sin6_addr; - alen = sizeof(struct in6_addr); - break; -#endif - default: - return (0); - } - for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { - memcpy(ap, addr, alen); + count = 0; + for (res = res0; res; res = res->ai_next) { + count++; + if (res->ai_addrlen > sizeof(ss)) + continue; + memcpy(&ss, res->ai_addr, res->ai_addrlen); /* * Force host name and address conversions. Use the request structure @@ -205,8 +103,9 @@ char *host; if (STR_EQ(eval_hostname(request.client), unknown)) tcpd_warn("host address %s->name lookup failed", eval_hostaddr(request.client)); + tcpd_warn("%s %s", eval_hostname(request.client), unknown); } - free((char *) hp); + freeaddrinfo(res0); return (count); } diff --git a/libexec/tcpd/tcpdchk/scaffold.h b/libexec/tcpd/tcpdchk/scaffold.h index 2450d24ca10..7bb69bc18a2 100644 --- a/libexec/tcpd/tcpdchk/scaffold.h +++ b/libexec/tcpd/tcpdchk/scaffold.h @@ -1,4 +1,4 @@ -/* $OpenBSD: scaffold.h,v 1.2 2002/02/16 21:27:31 millert Exp $ */ +/* $OpenBSD: scaffold.h,v 1.3 2002/06/07 03:32:04 itojun Exp $ */ /* * @(#) scaffold.h 1.3 94/12/31 18:19:19 @@ -9,7 +9,7 @@ #include <sys/cdefs.h> __BEGIN_DECLS -extern struct hostent *find_inet_addr(char *); +extern struct addrinfo *find_inet_addr(char *, int); extern int check_dns(char *); extern int check_path(char *, struct stat *); __END_DECLS diff --git a/libexec/tcpd/tcpdchk/tcpdchk.c b/libexec/tcpd/tcpdchk/tcpdchk.c index ec605da57da..ebe74dafcc7 100644 --- a/libexec/tcpd/tcpdchk/tcpdchk.c +++ b/libexec/tcpd/tcpdchk/tcpdchk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcpdchk.c,v 1.5 2001/07/08 21:18:13 deraadt Exp $ */ +/* $OpenBSD: tcpdchk.c,v 1.6 2002/06/07 03:32:04 itojun Exp $ */ /* * tcpdchk - examine all tcpd access control rules and inetd.conf entries @@ -20,7 +20,7 @@ #if 0 static char sccsid[] = "@(#) tcpdchk.c 1.8 97/02/12 02:13:25"; #else -static char rcsid[] = "$OpenBSD: tcpdchk.c,v 1.5 2001/07/08 21:18:13 deraadt Exp $"; +static char rcsid[] = "$OpenBSD: tcpdchk.c,v 1.6 2002/06/07 03:32:04 itojun Exp $"; #endif #endif @@ -28,9 +28,6 @@ static char rcsid[] = "$OpenBSD: tcpdchk.c,v 1.5 2001/07/08 21:18:13 deraadt Exp #include <sys/types.h> #include <sys/stat.h> -#ifdef INET6 -#include <sys/socket.h> -#endif #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> @@ -76,15 +73,18 @@ extern jmp_buf tcpd_buf; /* * Local stuff. */ -static void usage(); -static void parse_table(); -static void print_list(); -static void check_daemon_list(); -static void check_client_list(); -static void check_daemon(); -static void check_user(); -static int check_host(); -static int reserved_name(); +static void usage(void); +static void parse_table(char *, struct request_info *); +static void print_list(char *, char *); +static void check_daemon_list(char *); +static void check_client_list(char *); +static void check_daemon(char *); +static void check_user(char *); +#ifdef INET6 +static int check_inet_addr(char *); +#endif +static int check_host(char *); +static int reserved_name(char *); #define PERMIT 1 #define DENY 0 @@ -419,8 +419,22 @@ char *pat; } } -/* check_host - criticize host pattern */ +#ifdef INET6 +static int check_inet_addr(pat) +char *pat; +{ + struct addrinfo *res; + + res = find_inet_addr(pat, AI_NUMERICHOST); + if (res) { + freeaddrinfo(res); + return 1; + } else + return 0; +} +#endif +/* check_host - criticize host pattern */ static int check_host(pat) char *pat; { @@ -446,18 +460,15 @@ char *pat; #endif } else if ((mask = split_at(pat, '/')) != NULL) { /* network/netmask */ #ifdef INET6 - struct in6_addr in6; + char *ep; #endif - if (dot_quad_addr_new(pat, NULL) - && dot_quad_addr_new(mask, NULL)) + if (dot_quad_addr_new(pat, NULL) && dot_quad_addr_new(mask, NULL)) ; /*okay*/ #ifdef INET6 - else if (inet_pton(AF_INET6, pat, &in6) == 1 - && inet_pton(AF_INET6, mask, &in6) == 1) + else if (check_inet_addr(pat) && check_inet_addr(mask)) ; /*okay*/ - else if (inet_pton(AF_INET6, pat, &in6) == 1 - && strchr(mask, ':') == NULL - && 0 <= atoi(mask) && atoi(mask) <= 128) + else if (check_inet_addr(pat) && + (ep = NULL, strtoul(mask, &ep, 10), ep && !*ep)) ; /*okay*/ #endif else diff --git a/libexec/tcpd/tcpdmatch/tcpdmatch.c b/libexec/tcpd/tcpdmatch/tcpdmatch.c index f9de6575da6..de15e410663 100644 --- a/libexec/tcpd/tcpdmatch/tcpdmatch.c +++ b/libexec/tcpd/tcpdmatch/tcpdmatch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcpdmatch.c,v 1.5 2000/10/14 00:56:15 itojun Exp $ */ +/* $OpenBSD: tcpdmatch.c,v 1.6 2002/06/07 03:32:04 itojun Exp $ */ /* * tcpdmatch - explain what tcpd would do in a specific case @@ -19,7 +19,7 @@ #if 0 static char sccsid[] = "@(#) tcpdmatch.c 1.5 96/02/11 17:01:36"; #else -static char rcsid[] = "$OpenBSD: tcpdmatch.c,v 1.5 2000/10/14 00:56:15 itojun Exp $"; +static char rcsid[] = "$OpenBSD: tcpdmatch.c,v 1.6 2002/06/07 03:32:04 itojun Exp $"; #endif #endif @@ -53,8 +53,9 @@ static char rcsid[] = "$OpenBSD: tcpdmatch.c,v 1.5 2000/10/14 00:56:15 itojun Ex #include "inetcf.h" #include "scaffold.h" -static void usage(); -static void tcpdmatch(); +static void usage(char *); +static void expand(char *, char *, struct request_info *); +static void tcpdmatch(struct request_info *); /* The main program */ @@ -62,25 +63,19 @@ int main(argc, argv) int argc; char **argv; { - struct hostent *hp; + struct addrinfo *res, *res0; char *myname = argv[0]; char *client; char *server; - char *addr; char *user; char *daemon; struct request_info request; int ch; char *inetcf = 0; int count; - struct sockaddr_storage server_sin; - struct sockaddr_storage client_sin; + struct sockaddr_storage server_ss; + struct sockaddr_storage client_ss; struct stat st; - char *ap; - int alen; -#ifdef INET6 - struct sockaddr_in6 in6; -#endif /* * Show what rule actually matched. @@ -180,28 +175,17 @@ char **argv; * address and name conversion results. */ if (NOT_INADDR(server) == 0 || HOSTNAME_KNOWN(server)) { - if ((hp = find_inet_addr(server)) == 0) - exit(1); - memset((char *) &server_sin, 0, sizeof(server_sin)); - server_sin.ss_family = hp->h_addrtype; - switch (hp->h_addrtype) { - case AF_INET: - ap = (char *)&((struct sockaddr_in *)&server_sin)->sin_addr; - alen = sizeof(struct in_addr); - break; -#ifdef INET6 - case AF_INET6: - ap = (char *)&((struct sockaddr_in6 *)&server_sin)->sin6_addr; - alen = sizeof(struct in6_addr); - break; -#endif - default: + if ((res0 = find_inet_addr(server, 0)) == NULL) exit(1); - } - request_set(&request, RQ_SERVER_SIN, &server_sin, 0); + memset((char *) &server_ss, 0, sizeof(server_ss)); + request_set(&request, RQ_SERVER_SIN, &server_ss, 0); - for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { - memcpy(ap, addr, alen); + count = 0; + for (res = res0; res; res = res->ai_next) { + count++; + if (res->ai_addrlen > sizeof(server_ss)) + continue; + memcpy(&server_ss, res->ai_addr, res->ai_addrlen); /* * Force evaluation of server host name and address. Host name @@ -217,7 +201,7 @@ char **argv; fprintf(stderr, "Please specify an address instead\n"); exit(1); } - free((char *) hp); + freeaddrinfo(res0); } else { request_set(&request, RQ_SERVER_NAME, server, 0); } @@ -226,18 +210,15 @@ char **argv; * If a client address is specified, we simulate the effect of client * hostname lookup failure. */ - if (dot_quad_addr_new(client, NULL)) { - request_set(&request, RQ_CLIENT_ADDR, client, 0); - tcpdmatch(&request); - exit(0); - } -#ifdef INET6 - if (inet_pton(AF_INET6, client, &in6) == 1) { - request_set(&request, RQ_CLIENT_ADDR, client, 0); + res0 = find_inet_addr(client, AI_NUMERICHOST); + if (res0 && !res0->ai_next) { + request_set(&request, RQ_CLIENT_SIN, res0->ai_addr); tcpdmatch(&request); + freeaddrinfo(res0); exit(0); } -#endif + if (res0) + freeaddrinfo(res0); /* * Perhaps they are testing special client hostname patterns that aren't @@ -257,28 +238,17 @@ char **argv; * using the request.client structure as a cache for host name and * address conversion results. */ - if ((hp = find_inet_addr(client)) == 0) - exit(1); - memset((char *) &client_sin, 0, sizeof(client_sin)); - client_sin.ss_family = hp->h_addrtype; - switch (hp->h_addrtype) { - case AF_INET: - ap = (char *)&((struct sockaddr_in *)&client_sin)->sin_addr; - alen = sizeof(struct in_addr); - break; -#ifdef INET6 - case AF_INET6: - ap = (char *)&((struct sockaddr_in6 *)&client_sin)->sin6_addr; - alen = sizeof(struct in6_addr); - break; -#endif - default: + if ((res0 = find_inet_addr(client, 0)) == NULL) exit(1); - } - request_set(&request, RQ_CLIENT_SIN, &client_sin, 0); + memset((char *) &client_ss, 0, sizeof(client_ss)); + request_set(&request, RQ_CLIENT_SIN, &client_ss, 0); - for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { - memcpy(ap, addr, alen); + count = 0; + for (res = res0; res; res = res->ai_next) { + count++; + if (res->ai_addrlen > sizeof(client_ss)) + continue; + memcpy(&client_ss, res->ai_addr, res->ai_addrlen); /* * Force evaluation of client host name and address. Host name @@ -289,10 +259,10 @@ char **argv; tcpd_warn("host address %s->name lookup failed", eval_hostaddr(request.client)); tcpdmatch(&request); - if (hp->h_addr_list[count + 1]) + if (res->ai_next) printf("\n"); } - free((char *) hp); + freeaddrinfo(res0); exit(0); } |