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