/* * Copyright 2001 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * Misc routines that are used by tcpd and by tcpdchk. * * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. */ #ifndef lint static char sccsic[] = "@(#) misc.c 1.2 96/02/11 17:01:29"; #endif #include #include #include #include #include #include #include #include #include "tcpd.h" extern char *fgets(); #ifndef INADDR_NONE #define INADDR_NONE (-1) /* XXX should be 0xffffffff */ #endif /* xgets - fgets() with backslash-newline stripping */ char *xgets(ptr, len, fp) char *ptr; int len; FILE *fp; { int got; char *start = ptr; while (fgets(ptr, len, fp)) { got = strlen(ptr); if (got >= 1 && ptr[got - 1] == '\n') { tcpd_context.line++; if (got >= 2 && ptr[got - 2] == '\\') { got -= 2; } else { return (start); } } ptr += got; len -= got; ptr[0] = 0; } return (ptr > start ? start : 0); } /* split_at - break string at delimiter or return NULL */ char *split_at(string, delimiter) char *string; int delimiter; { char *cp; if ((cp = strchr(string, delimiter)) != 0) *cp++ = 0; return (cp); } /* dot_quad_addr - convert dotted quad to internal form */ unsigned long dot_quad_addr(str) char *str; { int in_run = 0; int runs = 0; char *cp = str; /* Count the number of runs of non-dot characters. */ while (*cp) { if (*cp == '.') { in_run = 0; } else if (in_run == 0) { in_run = 1; runs++; } cp++; } return (runs == 4 ? inet_addr(str) : INADDR_NONE); } /* numeric_addr - convert textual IP address to binary form */ int numeric_addr(str, addr, af, len) char *str; union gen_addr *addr; int *af; int *len; { union gen_addr t; if (addr == NULL) addr = &t; #ifdef HAVE_IPV6 if (strchr(str,':')) { if (af) *af = AF_INET6; if (len) *len = sizeof(struct in6_addr); if (inet_pton(AF_INET6, str, (void*) addr) == 1) return 0; return -1; } #endif if (af) *af = AF_INET; if (len) *len = sizeof(struct in_addr); addr->ga_in.s_addr = dot_quad_addr(str); return addr->ga_in.s_addr == INADDR_NONE ? -1 : 0; } /* For none RFC 2553 compliant systems */ #ifdef USE_GETHOSTBYNAME2 #define getipnodebyname(h,af,flags,err) gethostbyname2(h,af) #define freehostent(x) x = 0 #endif /* tcpd_gethostbyname - an IP family neutral gethostbyname */ struct hostent *tcpd_gethostbyname(host, af) char *host; int af; { #ifdef HAVE_IPV6 struct hostent *hp; static struct hostent *hs; /* freehostent() on next call */ int err; if (af == AF_INET6) { /* must be AF_INET6 */ if (hs) freehostent(hs); return (hs = getipnodebyname(host, AF_INET6, 0, &err)); } hp = gethostbyname(host); if (hp != NULL || af == AF_INET) { /* found or must be AF_INET */ return hp; } else { /* Try INET6 */ if (hs) freehostent(hs); return (hs = getipnodebyname(host, AF_INET6, 0, &err)); } #else return gethostbyname(host); #endif } #ifdef HAVE_IPV6 /* * When using IPv6 addresses, we'll be seeing lots of ":"s; * we require the addresses to be specified as [address]. * An IPv6 address can be specified in 3 ways: * * x:x:x:x:x:x:x:x (fully specified) * x::x:x:x:x (zeroes squashed) * ::FFFF:1.2.3.4 (IPv4 mapped) * * These need to be skipped to get at the ":" delimeters. * * We also allow a '/prefix' specifier. */ char *skip_ipv6_addrs(str) char *str; { char *obr, *cbr, *colon; char *p = str; char *q; while (1) { if ((colon = strchr(p, ':')) == NULL) return p; if ((obr = strchr(p, '[')) == NULL || obr > colon) return p; if ((cbr = strchr(obr, ']')) == NULL) return p; for (q = obr + 1; q < cbr; q++) { /* * Quick and dirty parse, cheaper than inet_pton * Could count colons and dots (must be 0 or 3 dots, no * colons after dots seens, only one double :, etc, etc) */ if (*q != ':' && *q != '.' && *q != '/' && !isxdigit(*q & 0xff)) return p; } p = cbr + 1; } } #endif /* HAVE_IPV6 */