1 /* 2 * Copyright 2001 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 #pragma ident "%Z%%M% %I% %E% SMI" 6 7 /* 8 * Misc routines that are used by tcpd and by tcpdchk. 9 * 10 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 11 */ 12 13 #ifndef lint 14 static char sccsic[] = "@(#) misc.c 1.2 96/02/11 17:01:29"; 15 #endif 16 17 #include <sys/types.h> 18 #include <sys/param.h> 19 #include <netinet/in.h> 20 #include <arpa/inet.h> 21 #include <stdio.h> 22 #include <string.h> 23 #include <ctype.h> 24 #include <netdb.h> 25 26 #include "tcpd.h" 27 28 extern char *fgets(); 29 30 #ifndef INADDR_NONE 31 #define INADDR_NONE (-1) /* XXX should be 0xffffffff */ 32 #endif 33 34 /* xgets - fgets() with backslash-newline stripping */ 35 36 char *xgets(ptr, len, fp) 37 char *ptr; 38 int len; 39 FILE *fp; 40 { 41 int got; 42 char *start = ptr; 43 44 while (fgets(ptr, len, fp)) { 45 got = strlen(ptr); 46 if (got >= 1 && ptr[got - 1] == '\n') { 47 tcpd_context.line++; 48 if (got >= 2 && ptr[got - 2] == '\\') { 49 got -= 2; 50 } else { 51 return (start); 52 } 53 } 54 ptr += got; 55 len -= got; 56 ptr[0] = 0; 57 } 58 return (ptr > start ? start : 0); 59 } 60 61 /* split_at - break string at delimiter or return NULL */ 62 63 char *split_at(string, delimiter) 64 char *string; 65 int delimiter; 66 { 67 char *cp; 68 69 if ((cp = strchr(string, delimiter)) != 0) 70 *cp++ = 0; 71 return (cp); 72 } 73 74 /* dot_quad_addr - convert dotted quad to internal form */ 75 76 unsigned long dot_quad_addr(str) 77 char *str; 78 { 79 int in_run = 0; 80 int runs = 0; 81 char *cp = str; 82 83 /* Count the number of runs of non-dot characters. */ 84 85 while (*cp) { 86 if (*cp == '.') { 87 in_run = 0; 88 } else if (in_run == 0) { 89 in_run = 1; 90 runs++; 91 } 92 cp++; 93 } 94 return (runs == 4 ? inet_addr(str) : INADDR_NONE); 95 } 96 97 /* numeric_addr - convert textual IP address to binary form */ 98 99 int numeric_addr(str, addr, af, len) 100 char *str; 101 union gen_addr *addr; 102 int *af; 103 int *len; 104 { 105 union gen_addr t; 106 107 if (addr == NULL) 108 addr = &t; 109 #ifdef HAVE_IPV6 110 if (strchr(str,':')) { 111 if (af) *af = AF_INET6; 112 if (len) *len = sizeof(struct in6_addr); 113 if (inet_pton(AF_INET6, str, (void*) addr) == 1) 114 return 0; 115 return -1; 116 } 117 #endif 118 if (af) *af = AF_INET; 119 if (len) *len = sizeof(struct in_addr); 120 addr->ga_in.s_addr = dot_quad_addr(str); 121 return addr->ga_in.s_addr == INADDR_NONE ? -1 : 0; 122 } 123 124 /* For none RFC 2553 compliant systems */ 125 #ifdef USE_GETHOSTBYNAME2 126 #define getipnodebyname(h,af,flags,err) gethostbyname2(h,af) 127 #define freehostent(x) x = 0 128 #endif 129 130 /* tcpd_gethostbyname - an IP family neutral gethostbyname */ 131 132 struct hostent *tcpd_gethostbyname(host, af) 133 char *host; 134 int af; 135 { 136 #ifdef HAVE_IPV6 137 struct hostent *hp; 138 static struct hostent *hs; /* freehostent() on next call */ 139 int err; 140 141 if (af == AF_INET6) { /* must be AF_INET6 */ 142 if (hs) 143 freehostent(hs); 144 return (hs = getipnodebyname(host, AF_INET6, 0, &err)); 145 } 146 hp = gethostbyname(host); 147 if (hp != NULL || af == AF_INET) { /* found or must be AF_INET */ 148 return hp; 149 } else { /* Try INET6 */ 150 if (hs) 151 freehostent(hs); 152 return (hs = getipnodebyname(host, AF_INET6, 0, &err)); 153 } 154 #else 155 return gethostbyname(host); 156 #endif 157 } 158 159 #ifdef HAVE_IPV6 160 /* 161 * When using IPv6 addresses, we'll be seeing lots of ":"s; 162 * we require the addresses to be specified as [address]. 163 * An IPv6 address can be specified in 3 ways: 164 * 165 * x:x:x:x:x:x:x:x (fully specified) 166 * x::x:x:x:x (zeroes squashed) 167 * ::FFFF:1.2.3.4 (IPv4 mapped) 168 * 169 * These need to be skipped to get at the ":" delimeters. 170 * 171 * We also allow a '/prefix' specifier. 172 */ 173 char *skip_ipv6_addrs(str) 174 char *str; 175 { 176 char *obr, *cbr, *colon; 177 char *p = str; 178 char *q; 179 180 while (1) { 181 if ((colon = strchr(p, ':')) == NULL) 182 return p; 183 if ((obr = strchr(p, '[')) == NULL || obr > colon) 184 return p; 185 if ((cbr = strchr(obr, ']')) == NULL) 186 return p; 187 188 for (q = obr + 1; q < cbr; q++) { 189 /* 190 * Quick and dirty parse, cheaper than inet_pton 191 * Could count colons and dots (must be 0 or 3 dots, no 192 * colons after dots seens, only one double :, etc, etc) 193 */ 194 if (*q != ':' && *q != '.' && *q != '/' && !isxdigit(*q & 0xff)) 195 return p; 196 } 197 p = cbr + 1; 198 } 199 } 200 #endif /* HAVE_IPV6 */ 201