1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
3*0Sstevel@tonic-gate * Use is subject to license terms.
4*0Sstevel@tonic-gate */
5*0Sstevel@tonic-gate
6*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
7*0Sstevel@tonic-gate
8*0Sstevel@tonic-gate /****************************************************************************
9*0Sstevel@tonic-gate Copyright (c) 1999,2000 WU-FTPD Development Group.
10*0Sstevel@tonic-gate All rights reserved.
11*0Sstevel@tonic-gate
12*0Sstevel@tonic-gate Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
13*0Sstevel@tonic-gate The Regents of the University of California.
14*0Sstevel@tonic-gate Portions Copyright (c) 1993, 1994 Washington University in Saint Louis.
15*0Sstevel@tonic-gate Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc.
16*0Sstevel@tonic-gate Portions Copyright (c) 1989 Massachusetts Institute of Technology.
17*0Sstevel@tonic-gate Portions Copyright (c) 1998 Sendmail, Inc.
18*0Sstevel@tonic-gate Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P. Allman.
19*0Sstevel@tonic-gate Portions Copyright (c) 1997 by Stan Barber.
20*0Sstevel@tonic-gate Portions Copyright (c) 1997 by Kent Landfield.
21*0Sstevel@tonic-gate Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
22*0Sstevel@tonic-gate Free Software Foundation, Inc.
23*0Sstevel@tonic-gate
24*0Sstevel@tonic-gate Use and distribution of this software and its source code are governed
25*0Sstevel@tonic-gate by the terms and conditions of the WU-FTPD Software License ("LICENSE").
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate If you did not receive a copy of the license, it may be obtained online
28*0Sstevel@tonic-gate at http://www.wu-ftpd.org/license.html.
29*0Sstevel@tonic-gate
30*0Sstevel@tonic-gate $Id: routevector.c,v 1.13 2000/07/01 18:17:39 wuftpd Exp $
31*0Sstevel@tonic-gate
32*0Sstevel@tonic-gate ****************************************************************************/
33*0Sstevel@tonic-gate /*
34*0Sstevel@tonic-gate * Parse the entire ftpaccess file looking for:
35*0Sstevel@tonic-gate *
36*0Sstevel@tonic-gate * passive address <externalip> <address/CIDR>
37*0Sstevel@tonic-gate * passive ports <address/CIDR> <min> <max>
38*0Sstevel@tonic-gate *
39*0Sstevel@tonic-gate * vect_addr, passive_port_min and passive_port_max store the external IP
40*0Sstevel@tonic-gate * address, min and max ports found whose associated address is the most
41*0Sstevel@tonic-gate * specific match of the address the client connected from.
42*0Sstevel@tonic-gate *
43*0Sstevel@tonic-gate * The optional CIDR denotes the number of significant bits in the address,
44*0Sstevel@tonic-gate * the higher the CIDR the more specific the address. If no CIDR is specified,
45*0Sstevel@tonic-gate * the whole address is significant.
46*0Sstevel@tonic-gate *
47*0Sstevel@tonic-gate * When a passive data connection is requested the server listens on a port
48*0Sstevel@tonic-gate * randomly selected between passive_port_min and passive_port_max
49*0Sstevel@tonic-gate * (inclusive), if vect_addr is set its address is reported (if not the
50*0Sstevel@tonic-gate * local address of the control connection is reported). Note this does not
51*0Sstevel@tonic-gate * change the address the server actually listens on, only the address
52*0Sstevel@tonic-gate * reported to the client.
53*0Sstevel@tonic-gate *
54*0Sstevel@tonic-gate * For example if the ftpaccess file includes:
55*0Sstevel@tonic-gate * passive address 194.80.17.14 0.0.0.0/0
56*0Sstevel@tonic-gate * passive address 10.0.1.15 10.0.0.0/8
57*0Sstevel@tonic-gate *
58*0Sstevel@tonic-gate * Clients connecting from the class-A network 10 will be told the passive
59*0Sstevel@tonic-gate * connection is listening on IP address 10.0.1.15, while clients connecting
60*0Sstevel@tonic-gate * from all other addresses will be told the connection is listening on
61*0Sstevel@tonic-gate * 194.80.17.14 (a CIDR of /0 matches all addresses of the same address
62*0Sstevel@tonic-gate * family, if IPv6 support is enabled then IPv4 and IPv6 addresses are
63*0Sstevel@tonic-gate * supported).
64*0Sstevel@tonic-gate */
65*0Sstevel@tonic-gate
66*0Sstevel@tonic-gate #include "config.h"
67*0Sstevel@tonic-gate #include <sys/socket.h>
68*0Sstevel@tonic-gate #include <netinet/in.h>
69*0Sstevel@tonic-gate #include <arpa/inet.h>
70*0Sstevel@tonic-gate #include <string.h>
71*0Sstevel@tonic-gate #ifdef HAVE_SYS_SYSLOG_H
72*0Sstevel@tonic-gate #include <sys/syslog.h>
73*0Sstevel@tonic-gate #endif
74*0Sstevel@tonic-gate #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H))
75*0Sstevel@tonic-gate #include <syslog.h>
76*0Sstevel@tonic-gate #endif
77*0Sstevel@tonic-gate #include "extensions.h"
78*0Sstevel@tonic-gate #include "proto.h"
79*0Sstevel@tonic-gate
80*0Sstevel@tonic-gate extern struct SOCKSTORAGE his_addr;
81*0Sstevel@tonic-gate extern struct SOCKSTORAGE vect_addr; /* best matching external IP address */
82*0Sstevel@tonic-gate extern int passive_port_min;
83*0Sstevel@tonic-gate extern int passive_port_max;
84*0Sstevel@tonic-gate
85*0Sstevel@tonic-gate /* significance of the external IP address and port entries */
86*0Sstevel@tonic-gate static int vect_sig = -1;
87*0Sstevel@tonic-gate static int port_sig = -1;
88*0Sstevel@tonic-gate
89*0Sstevel@tonic-gate #ifdef INET6
90*0Sstevel@tonic-gate static int his_addr_family = AF_INET;
91*0Sstevel@tonic-gate static int his_v4mapped = 0;
92*0Sstevel@tonic-gate #endif
93*0Sstevel@tonic-gate
94*0Sstevel@tonic-gate /*
95*0Sstevel@tonic-gate * Compares the address the client connected from (in his_addr) with the
96*0Sstevel@tonic-gate * supplied address, with the specified number of bits being significant
97*0Sstevel@tonic-gate * in the comparison. Returns 0 if the addresses match, non-zero otherwise.
98*0Sstevel@tonic-gate */
addr_cmp(void * addr,int sig)99*0Sstevel@tonic-gate static int addr_cmp(void *addr, int sig)
100*0Sstevel@tonic-gate {
101*0Sstevel@tonic-gate uint32_t addr32[4], rem32[4];
102*0Sstevel@tonic-gate int bitstozero, i, start = 0, len = sizeof(uint32_t);
103*0Sstevel@tonic-gate char *ptr;
104*0Sstevel@tonic-gate
105*0Sstevel@tonic-gate #ifdef INET6
106*0Sstevel@tonic-gate if (his_addr_family == AF_INET) {
107*0Sstevel@tonic-gate if (his_v4mapped) {
108*0Sstevel@tonic-gate ptr = (char *)&((struct sockaddr_in6 *)&his_addr)->sin6_addr;
109*0Sstevel@tonic-gate /* move to the IPv4 part of an IPv4-mapped IPv6 address */
110*0Sstevel@tonic-gate ptr += 12;
111*0Sstevel@tonic-gate }
112*0Sstevel@tonic-gate else
113*0Sstevel@tonic-gate #endif
114*0Sstevel@tonic-gate ptr = (char *)&((struct sockaddr_in *)&his_addr)->sin_addr;
115*0Sstevel@tonic-gate
116*0Sstevel@tonic-gate /* IPv4 addresses are 32-bits long */
117*0Sstevel@tonic-gate bitstozero = 32 - sig;
118*0Sstevel@tonic-gate memcpy(addr32, addr, sizeof(uint32_t));
119*0Sstevel@tonic-gate memcpy(rem32, ptr, sizeof(uint32_t));
120*0Sstevel@tonic-gate #ifdef INET6
121*0Sstevel@tonic-gate }
122*0Sstevel@tonic-gate else {
123*0Sstevel@tonic-gate /* IPv6 addresses are 128-bits long */
124*0Sstevel@tonic-gate bitstozero = 128 - sig;
125*0Sstevel@tonic-gate start = 3;
126*0Sstevel@tonic-gate len = sizeof(addr32);
127*0Sstevel@tonic-gate memcpy(addr32, addr, sizeof(addr32));
128*0Sstevel@tonic-gate memcpy(rem32, &((struct sockaddr_in6 *)&his_addr)->sin6_addr, sizeof(rem32));
129*0Sstevel@tonic-gate }
130*0Sstevel@tonic-gate #endif
131*0Sstevel@tonic-gate
132*0Sstevel@tonic-gate /* zero bits starting with the least significant */
133*0Sstevel@tonic-gate for (i = start; (bitstozero > 0) && (i >= 0); i--, bitstozero -= 32) {
134*0Sstevel@tonic-gate if (bitstozero >= 32)
135*0Sstevel@tonic-gate addr32[i] = rem32[i] = 0;
136*0Sstevel@tonic-gate else {
137*0Sstevel@tonic-gate addr32[i] = (ntohl(addr32[i]) >> bitstozero) << bitstozero;
138*0Sstevel@tonic-gate rem32[i] = (ntohl(rem32[i]) >> bitstozero) << bitstozero;
139*0Sstevel@tonic-gate }
140*0Sstevel@tonic-gate }
141*0Sstevel@tonic-gate
142*0Sstevel@tonic-gate /* compare the IP addresses */
143*0Sstevel@tonic-gate return memcmp(addr32, rem32, len);
144*0Sstevel@tonic-gate }
145*0Sstevel@tonic-gate
146*0Sstevel@tonic-gate /*
147*0Sstevel@tonic-gate * Matches a supplied IP address string against the address the client
148*0Sstevel@tonic-gate * connected from (in his_addr). Returns 1 and updates sig if the addresses
149*0Sstevel@tonic-gate * match and there hasn't already been a more specific match, zero otherwise.
150*0Sstevel@tonic-gate */
better_match(char * addrstr,int * sig)151*0Sstevel@tonic-gate static int better_match(char *addrstr, int *sig)
152*0Sstevel@tonic-gate {
153*0Sstevel@tonic-gate int addr_sig, max_sig = 32;
154*0Sstevel@tonic-gate char *ptr;
155*0Sstevel@tonic-gate void *addr;
156*0Sstevel@tonic-gate #ifdef INET6
157*0Sstevel@tonic-gate int rval;
158*0Sstevel@tonic-gate struct in6_addr in6;
159*0Sstevel@tonic-gate #else
160*0Sstevel@tonic-gate struct in_addr in;
161*0Sstevel@tonic-gate #endif
162*0Sstevel@tonic-gate
163*0Sstevel@tonic-gate /* look for the optional significance (/CIDR) */
164*0Sstevel@tonic-gate if ((ptr = strstr(addrstr, "/")))
165*0Sstevel@tonic-gate *ptr = '\0';
166*0Sstevel@tonic-gate
167*0Sstevel@tonic-gate #ifdef INET6
168*0Sstevel@tonic-gate if (his_addr_family == AF_INET6)
169*0Sstevel@tonic-gate max_sig = 128;
170*0Sstevel@tonic-gate #endif
171*0Sstevel@tonic-gate
172*0Sstevel@tonic-gate if (ptr) {
173*0Sstevel@tonic-gate addr_sig = atoi(++ptr);
174*0Sstevel@tonic-gate if (addr_sig < 0)
175*0Sstevel@tonic-gate addr_sig = 0;
176*0Sstevel@tonic-gate else if (addr_sig > max_sig)
177*0Sstevel@tonic-gate addr_sig = max_sig;
178*0Sstevel@tonic-gate }
179*0Sstevel@tonic-gate else
180*0Sstevel@tonic-gate addr_sig = max_sig;
181*0Sstevel@tonic-gate
182*0Sstevel@tonic-gate /* return if we already have a more specific match */
183*0Sstevel@tonic-gate if (addr_sig < *sig) {
184*0Sstevel@tonic-gate if (ptr)
185*0Sstevel@tonic-gate *--ptr = '/';
186*0Sstevel@tonic-gate return 0;
187*0Sstevel@tonic-gate }
188*0Sstevel@tonic-gate
189*0Sstevel@tonic-gate #ifdef INET6
190*0Sstevel@tonic-gate rval = inet_pton6(addrstr, &in6);
191*0Sstevel@tonic-gate if (ptr)
192*0Sstevel@tonic-gate *--ptr = '/';
193*0Sstevel@tonic-gate if (rval != 1)
194*0Sstevel@tonic-gate return 0;
195*0Sstevel@tonic-gate
196*0Sstevel@tonic-gate if (his_addr_family == AF_INET) {
197*0Sstevel@tonic-gate /* convert IPv4-mapped IPv6 addresses to IPv4 addresses */
198*0Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&in6))
199*0Sstevel@tonic-gate addr = &in6.s6_addr[12];
200*0Sstevel@tonic-gate else
201*0Sstevel@tonic-gate return 0;
202*0Sstevel@tonic-gate }
203*0Sstevel@tonic-gate else
204*0Sstevel@tonic-gate addr = &in6.s6_addr;
205*0Sstevel@tonic-gate #else
206*0Sstevel@tonic-gate in.s_addr = inet_addr(addrstr);
207*0Sstevel@tonic-gate if (ptr)
208*0Sstevel@tonic-gate *--ptr = '/';
209*0Sstevel@tonic-gate if ((int)in.s_addr == -1)
210*0Sstevel@tonic-gate return 0;
211*0Sstevel@tonic-gate addr = &in.s_addr;
212*0Sstevel@tonic-gate #endif
213*0Sstevel@tonic-gate
214*0Sstevel@tonic-gate if (addr_cmp(addr, addr_sig) == 0) {
215*0Sstevel@tonic-gate *sig = addr_sig;
216*0Sstevel@tonic-gate return 1;
217*0Sstevel@tonic-gate }
218*0Sstevel@tonic-gate return 0;
219*0Sstevel@tonic-gate }
220*0Sstevel@tonic-gate
update_address(char * externalip,char * addrstr)221*0Sstevel@tonic-gate static void update_address(char *externalip, char *addrstr)
222*0Sstevel@tonic-gate {
223*0Sstevel@tonic-gate struct SOCKSTORAGE ext_addr;
224*0Sstevel@tonic-gate #ifndef INET6
225*0Sstevel@tonic-gate struct in_addr in;
226*0Sstevel@tonic-gate #endif
227*0Sstevel@tonic-gate
228*0Sstevel@tonic-gate /* validate the external IP address string */
229*0Sstevel@tonic-gate #ifdef INET6
230*0Sstevel@tonic-gate SET_SOCK_FAMILY(ext_addr, AF_INET6);
231*0Sstevel@tonic-gate if (inet_pton6(externalip, SOCK_ADDR(ext_addr)) != 1)
232*0Sstevel@tonic-gate return;
233*0Sstevel@tonic-gate if ((his_addr_family == AF_INET) &&
234*0Sstevel@tonic-gate !IN6_IS_ADDR_V4MAPPED((struct in6_addr *)SOCK_ADDR(ext_addr)))
235*0Sstevel@tonic-gate return;
236*0Sstevel@tonic-gate #else
237*0Sstevel@tonic-gate if ((int)(in.s_addr = inet_addr(externalip)) == -1)
238*0Sstevel@tonic-gate return;
239*0Sstevel@tonic-gate SET_SOCK_FAMILY(ext_addr, AF_INET);
240*0Sstevel@tonic-gate SET_SOCK_ADDR4(ext_addr, in);
241*0Sstevel@tonic-gate #endif
242*0Sstevel@tonic-gate
243*0Sstevel@tonic-gate if (better_match(addrstr, &vect_sig))
244*0Sstevel@tonic-gate vect_addr = ext_addr;
245*0Sstevel@tonic-gate }
246*0Sstevel@tonic-gate
update_ports(char * addrstr,char * minport,char * maxport)247*0Sstevel@tonic-gate static void update_ports(char *addrstr, char *minport, char *maxport)
248*0Sstevel@tonic-gate {
249*0Sstevel@tonic-gate int min, max;
250*0Sstevel@tonic-gate
251*0Sstevel@tonic-gate min = atoi(minport);
252*0Sstevel@tonic-gate max = atoi(maxport);
253*0Sstevel@tonic-gate
254*0Sstevel@tonic-gate /* validate the ports supplied */
255*0Sstevel@tonic-gate if ((min > max) || (min < 0) || (max > 65535) || (min == 0 && max != 0)) {
256*0Sstevel@tonic-gate syslog(LOG_WARNING, "ftpaccess passive ports entry invalid: %s %s %s", addrstr, minport, maxport);
257*0Sstevel@tonic-gate return;
258*0Sstevel@tonic-gate }
259*0Sstevel@tonic-gate
260*0Sstevel@tonic-gate if (better_match(addrstr, &port_sig)) {
261*0Sstevel@tonic-gate passive_port_min = min;
262*0Sstevel@tonic-gate passive_port_max = max;
263*0Sstevel@tonic-gate }
264*0Sstevel@tonic-gate }
265*0Sstevel@tonic-gate
routevector(void)266*0Sstevel@tonic-gate int routevector(void)
267*0Sstevel@tonic-gate {
268*0Sstevel@tonic-gate struct aclmember *entry = NULL;
269*0Sstevel@tonic-gate
270*0Sstevel@tonic-gate #ifdef INET6
271*0Sstevel@tonic-gate if (SOCK_FAMILY(his_addr) == AF_INET6) {
272*0Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&(his_addr))->sin6_addr))
273*0Sstevel@tonic-gate his_v4mapped = 1;
274*0Sstevel@tonic-gate else
275*0Sstevel@tonic-gate his_addr_family = AF_INET6;
276*0Sstevel@tonic-gate }
277*0Sstevel@tonic-gate #endif
278*0Sstevel@tonic-gate
279*0Sstevel@tonic-gate while (getaclentry("passive", &entry)) {
280*0Sstevel@tonic-gate if (!strcasecmp(ARG0, "address")) {
281*0Sstevel@tonic-gate if (!ARG1 || !ARG2)
282*0Sstevel@tonic-gate continue;
283*0Sstevel@tonic-gate update_address(ARG1, ARG2);
284*0Sstevel@tonic-gate }
285*0Sstevel@tonic-gate if (!strcasecmp(ARG0, "ports")) {
286*0Sstevel@tonic-gate if (!ARG1 || !ARG2 || !ARG3)
287*0Sstevel@tonic-gate continue;
288*0Sstevel@tonic-gate update_ports(ARG1, ARG2, ARG3);
289*0Sstevel@tonic-gate }
290*0Sstevel@tonic-gate }
291*0Sstevel@tonic-gate return vect_sig != -1;
292*0Sstevel@tonic-gate }
293