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