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