17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (C) 1997-2003 by Darren Reed
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * See the IPFILTER.LICENCE file for details on licencing.
57c478bd9Sstevel@tonic-gate  *
6ab25eeb5Syz  * $Id: ip_ftp_pxy.c,v 2.88.2.15 2005/03/19 19:38:10 darrenr Exp $
7ab25eeb5Syz  *
8*33f2fefdSDarren Reed  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
97c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  * Simple FTP transparent proxy for in-kernel use.  For use with the NAT
127c478bd9Sstevel@tonic-gate  * code.
13ab25eeb5Syz */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #define	IPF_FTP_PROXY
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #define	IPF_MINPORTLEN	18
187c478bd9Sstevel@tonic-gate #define	IPF_MAXPORTLEN	30
197c478bd9Sstevel@tonic-gate #define	IPF_MIN227LEN	39
207c478bd9Sstevel@tonic-gate #define	IPF_MAX227LEN	51
217c478bd9Sstevel@tonic-gate #define	IPF_MIN229LEN	47
227c478bd9Sstevel@tonic-gate #define	IPF_MAX229LEN	51
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate #define	FTPXY_GO	0
257c478bd9Sstevel@tonic-gate #define	FTPXY_INIT	1
267c478bd9Sstevel@tonic-gate #define	FTPXY_USER_1	2
277c478bd9Sstevel@tonic-gate #define	FTPXY_USOK_1	3
287c478bd9Sstevel@tonic-gate #define	FTPXY_PASS_1	4
297c478bd9Sstevel@tonic-gate #define	FTPXY_PAOK_1	5
307c478bd9Sstevel@tonic-gate #define	FTPXY_AUTH_1	6
317c478bd9Sstevel@tonic-gate #define	FTPXY_AUOK_1	7
327c478bd9Sstevel@tonic-gate #define	FTPXY_ADAT_1	8
337c478bd9Sstevel@tonic-gate #define	FTPXY_ADOK_1	9
347c478bd9Sstevel@tonic-gate #define	FTPXY_ACCT_1	10
357c478bd9Sstevel@tonic-gate #define	FTPXY_ACOK_1	11
367c478bd9Sstevel@tonic-gate #define	FTPXY_USER_2	12
377c478bd9Sstevel@tonic-gate #define	FTPXY_USOK_2	13
387c478bd9Sstevel@tonic-gate #define	FTPXY_PASS_2	14
397c478bd9Sstevel@tonic-gate #define	FTPXY_PAOK_2	15
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * Values for FTP commands.  Numerics cover 0-999
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate #define	FTPXY_C_PASV	1000
457c478bd9Sstevel@tonic-gate 
46f4b3ec61Sdh typedef struct ifs_ftppxy {
47f4b3ec61Sdh 	frentry_t		ftppxyfr;
48f4b3ec61Sdh 	int			ftp_proxy_init;
49f4b3ec61Sdh 	int			ippr_ftp_pasvonly;
50f4b3ec61Sdh 	int			ippr_ftp_insecure;
51f4b3ec61Sdh 				/* Do not require logins before transfers */
52f4b3ec61Sdh 	int			ippr_ftp_pasvrdr;
53f4b3ec61Sdh 	int			ippr_ftp_forcepasv;
54f4b3ec61Sdh 				/* PASV must be last command prior to 227 */
55f4b3ec61Sdh 	/*
56f4b3ec61Sdh 	 * 1 - security
57f4b3ec61Sdh 	 * 2 - errors
58f4b3ec61Sdh 	 * 3 - error debugging
59f4b3ec61Sdh 	 * 4 - parsing errors
60f4b3ec61Sdh 	 * 5 - parsing info
61f4b3ec61Sdh 	 * 6 - parsing debug
62f4b3ec61Sdh 	 */
63f4b3ec61Sdh 	int			ippr_ftp_debug;
64f4b3ec61Sdh 	ipftuneable_t		ftptune;
65f4b3ec61Sdh } ifs_ftppxy_t;
66f4b3ec61Sdh 
67f4b3ec61Sdh int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int,
68f4b3ec61Sdh     ifs_ftppxy_t *));
697c478bd9Sstevel@tonic-gate int ippr_ftp_complete __P((char *, size_t));
70f4b3ec61Sdh int ippr_ftp_in __P((fr_info_t *, ap_session_t *, nat_t *, void *));
71f4b3ec61Sdh int ippr_ftp_init __P((void **, ipf_stack_t *));
72f4b3ec61Sdh void ippr_ftp_fini __P((void **, ipf_stack_t *));
73f4b3ec61Sdh int ippr_ftp_new __P((fr_info_t *, ap_session_t *, nat_t *, void *));
74f4b3ec61Sdh int ippr_ftp_out __P((fr_info_t *, ap_session_t *, nat_t *, void *));
75f4b3ec61Sdh int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int,
76f4b3ec61Sdh     ifs_ftppxy_t *));
77f4b3ec61Sdh int ippr_ftp_epsv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int,
78f4b3ec61Sdh     ifs_ftppxy_t *));
79f4b3ec61Sdh int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int,
80f4b3ec61Sdh     ifs_ftppxy_t *));
81f4b3ec61Sdh int ippr_ftp_process __P((fr_info_t *, nat_t *, ftpinfo_t *, int,
82f4b3ec61Sdh     ifs_ftppxy_t *));
83f4b3ec61Sdh int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int,
84f4b3ec61Sdh     ifs_ftppxy_t *));
85f4b3ec61Sdh int ippr_ftp_valid __P((ftpinfo_t *, int, char *, size_t, ifs_ftppxy_t *));
86f4b3ec61Sdh int ippr_ftp_server_valid __P((ftpside_t *, char *, size_t, ifs_ftppxy_t *));
87f4b3ec61Sdh int ippr_ftp_client_valid __P((ftpside_t *, char *, size_t, ifs_ftppxy_t *));
887c478bd9Sstevel@tonic-gate u_short ippr_ftp_atoi __P((char **));
897c478bd9Sstevel@tonic-gate int ippr_ftp_pasvreply __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *,
90f4b3ec61Sdh 			    u_int, char *, char *, u_int, ifs_ftppxy_t *));
91f4b3ec61Sdh 
92f4b3ec61Sdh /*
93f4b3ec61Sdh  * Initialize local structures.
94f4b3ec61Sdh  */
ippr_ftp_init(private,ifs)95f4b3ec61Sdh int ippr_ftp_init(private, ifs)
96f4b3ec61Sdh void **private;
97f4b3ec61Sdh ipf_stack_t *ifs;
98f4b3ec61Sdh {
99f4b3ec61Sdh 	ifs_ftppxy_t *ifsftp;
1007c478bd9Sstevel@tonic-gate 
101f4b3ec61Sdh 	KMALLOC(ifsftp, ifs_ftppxy_t *);
102f4b3ec61Sdh 	if (ifsftp == NULL)
103f4b3ec61Sdh 		return -1;
1047c478bd9Sstevel@tonic-gate 
105f4b3ec61Sdh 	bzero((char *)&ifsftp->ftppxyfr, sizeof(ifsftp->ftppxyfr));
106f4b3ec61Sdh 	ifsftp->ftppxyfr.fr_ref = 1;
107f4b3ec61Sdh 	ifsftp->ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
108f4b3ec61Sdh 	MUTEX_INIT(&ifsftp->ftppxyfr.fr_lock, "FTP Proxy Mutex");
109f4b3ec61Sdh 	ifsftp->ftp_proxy_init = 1;
110f4b3ec61Sdh 	ifsftp->ippr_ftp_pasvonly = 0;
111f4b3ec61Sdh 	ifsftp->ippr_ftp_insecure = 0;
112f4b3ec61Sdh 	ifsftp->ippr_ftp_pasvrdr = 0;
113f4b3ec61Sdh 	ifsftp->ippr_ftp_forcepasv = 0;
114ab25eeb5Syz #if defined(_KERNEL)
115f4b3ec61Sdh 	ifsftp->ippr_ftp_debug = 0;
116ab25eeb5Syz #else
117f4b3ec61Sdh 	ifsftp->ippr_ftp_debug = 2;
118ab25eeb5Syz #endif
119f4b3ec61Sdh 	bzero((char *)&ifsftp->ftptune, sizeof(ifsftp->ftptune));
120f4b3ec61Sdh 	ifsftp->ftptune.ipft_pint = (uint_t *)&ifsftp->ippr_ftp_debug;
121f4b3ec61Sdh 	ifsftp->ftptune.ipft_name = "ippr_ftp_debug";
122f4b3ec61Sdh 	ifsftp->ftptune.ipft_max = 10;
123f4b3ec61Sdh 	ifsftp->ftptune.ipft_sz = sizeof(ifsftp->ippr_ftp_debug);
124f4b3ec61Sdh 	ifsftp->ftptune.ipft_next = NULL;
125ab25eeb5Syz 
126f4b3ec61Sdh 	(void) fr_addipftune(&ifsftp->ftptune, ifs);
1277c478bd9Sstevel@tonic-gate 
128f4b3ec61Sdh 	*private = (void *)ifsftp;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	return 0;
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 
ippr_ftp_fini(private,ifs)134f4b3ec61Sdh void ippr_ftp_fini(private, ifs)
135f4b3ec61Sdh void **private;
136f4b3ec61Sdh ipf_stack_t *ifs;
1377c478bd9Sstevel@tonic-gate {
138f4b3ec61Sdh 	ifs_ftppxy_t *ifsftp = *((ifs_ftppxy_t **)private);
139ab25eeb5Syz 
140f4b3ec61Sdh 	(void) fr_delipftune(&ifsftp->ftptune, ifs);
141f4b3ec61Sdh 
142f4b3ec61Sdh 	if (ifsftp->ftp_proxy_init == 1) {
143f4b3ec61Sdh 		MUTEX_DESTROY(&ifsftp->ftppxyfr.fr_lock);
144f4b3ec61Sdh 		ifsftp->ftp_proxy_init = 0;
1457c478bd9Sstevel@tonic-gate 	}
146f4b3ec61Sdh 
147f4b3ec61Sdh 	KFREE(ifsftp);
148f4b3ec61Sdh 	*private = NULL;
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 
152f4b3ec61Sdh /*ARGSUSED*/
ippr_ftp_new(fin,aps,nat,private)153f4b3ec61Sdh int ippr_ftp_new(fin, aps, nat, private)
1547c478bd9Sstevel@tonic-gate fr_info_t *fin;
1557c478bd9Sstevel@tonic-gate ap_session_t *aps;
1567c478bd9Sstevel@tonic-gate nat_t *nat;
157f4b3ec61Sdh void *private;
1587c478bd9Sstevel@tonic-gate {
1597c478bd9Sstevel@tonic-gate 	ftpinfo_t *ftp;
1607c478bd9Sstevel@tonic-gate 	ftpside_t *f;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	KMALLOC(ftp, ftpinfo_t *);
1637c478bd9Sstevel@tonic-gate 	if (ftp == NULL)
1647c478bd9Sstevel@tonic-gate 		return -1;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	fin = fin;	/* LINT */
1677c478bd9Sstevel@tonic-gate 	nat = nat;	/* LINT */
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	aps->aps_data = ftp;
1707c478bd9Sstevel@tonic-gate 	aps->aps_psiz = sizeof(ftpinfo_t);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	bzero((char *)ftp, sizeof(*ftp));
1737c478bd9Sstevel@tonic-gate 	f = &ftp->ftp_side[0];
1747c478bd9Sstevel@tonic-gate 	f->ftps_rptr = f->ftps_buf;
1757c478bd9Sstevel@tonic-gate 	f->ftps_wptr = f->ftps_buf;
1767c478bd9Sstevel@tonic-gate 	f = &ftp->ftp_side[1];
1777c478bd9Sstevel@tonic-gate 	f->ftps_rptr = f->ftps_buf;
1787c478bd9Sstevel@tonic-gate 	f->ftps_wptr = f->ftps_buf;
1797c478bd9Sstevel@tonic-gate 	ftp->ftp_passok = FTPXY_INIT;
1807c478bd9Sstevel@tonic-gate 	ftp->ftp_incok = 0;
1817c478bd9Sstevel@tonic-gate 	return 0;
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 
ippr_ftp_port(fin,ip,nat,f,dlen,ifsftp)185f4b3ec61Sdh int ippr_ftp_port(fin, ip, nat, f, dlen, ifsftp)
1867c478bd9Sstevel@tonic-gate fr_info_t *fin;
1877c478bd9Sstevel@tonic-gate ip_t *ip;
1887c478bd9Sstevel@tonic-gate nat_t *nat;
1897c478bd9Sstevel@tonic-gate ftpside_t *f;
1907c478bd9Sstevel@tonic-gate int dlen;
191f4b3ec61Sdh ifs_ftppxy_t *ifsftp;
1927c478bd9Sstevel@tonic-gate {
1937c478bd9Sstevel@tonic-gate 	tcphdr_t *tcp, tcph, *tcp2 = &tcph;
1947c478bd9Sstevel@tonic-gate 	char newbuf[IPF_FTPBUFSZ], *s;
1957c478bd9Sstevel@tonic-gate 	struct in_addr swip, swip2;
1967c478bd9Sstevel@tonic-gate 	u_int a1, a2, a3, a4;
197ab25eeb5Syz 	int inc, off, flags;
1987c478bd9Sstevel@tonic-gate 	u_short a5, a6, sp;
1997c478bd9Sstevel@tonic-gate 	size_t nlen, olen;
2007c478bd9Sstevel@tonic-gate 	fr_info_t fi;
2017c478bd9Sstevel@tonic-gate 	nat_t *nat2;
2027c478bd9Sstevel@tonic-gate 	mb_t *m;
203f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	m = fin->fin_m;
2067c478bd9Sstevel@tonic-gate 	tcp = (tcphdr_t *)fin->fin_dp;
207ab25eeb5Syz 	off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	/*
2107c478bd9Sstevel@tonic-gate 	 * Check for client sending out PORT message.
2117c478bd9Sstevel@tonic-gate 	 */
2127c478bd9Sstevel@tonic-gate 	if (dlen < IPF_MINPORTLEN) {
213f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
214ab25eeb5Syz 			printf("ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n",
215ab25eeb5Syz 			       dlen);
2167c478bd9Sstevel@tonic-gate 		return 0;
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 	/*
2197c478bd9Sstevel@tonic-gate 	 * Skip the PORT command + space
2207c478bd9Sstevel@tonic-gate 	 */
2217c478bd9Sstevel@tonic-gate 	s = f->ftps_rptr + 5;
2227c478bd9Sstevel@tonic-gate 	/*
2237c478bd9Sstevel@tonic-gate 	 * Pick out the address components, two at a time.
2247c478bd9Sstevel@tonic-gate 	 */
2257c478bd9Sstevel@tonic-gate 	a1 = ippr_ftp_atoi(&s);
2267c478bd9Sstevel@tonic-gate 	if (s == NULL) {
227f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
228ab25eeb5Syz 			printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 1);
2297c478bd9Sstevel@tonic-gate 		return 0;
2307c478bd9Sstevel@tonic-gate 	}
2317c478bd9Sstevel@tonic-gate 	a2 = ippr_ftp_atoi(&s);
2327c478bd9Sstevel@tonic-gate 	if (s == NULL) {
233f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
234ab25eeb5Syz 			printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 2);
2357c478bd9Sstevel@tonic-gate 		return 0;
2367c478bd9Sstevel@tonic-gate 	}
237ab25eeb5Syz 
2387c478bd9Sstevel@tonic-gate 	/*
2397c478bd9Sstevel@tonic-gate 	 * Check that IP address in the PORT/PASV reply is the same as the
2407c478bd9Sstevel@tonic-gate 	 * sender of the command - prevents using PORT for port scanning.
2417c478bd9Sstevel@tonic-gate 	 */
2427c478bd9Sstevel@tonic-gate 	a1 <<= 16;
2437c478bd9Sstevel@tonic-gate 	a1 |= a2;
2447c478bd9Sstevel@tonic-gate 	if (((nat->nat_dir == NAT_OUTBOUND) &&
2457c478bd9Sstevel@tonic-gate 	     (a1 != ntohl(nat->nat_inip.s_addr))) ||
2467c478bd9Sstevel@tonic-gate 	    ((nat->nat_dir == NAT_INBOUND) &&
2477c478bd9Sstevel@tonic-gate 	     (a1 != ntohl(nat->nat_oip.s_addr)))) {
248f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 0)
249ab25eeb5Syz 			printf("ippr_ftp_port:%s != nat->nat_inip\n", "a1");
2507c478bd9Sstevel@tonic-gate 		return APR_ERR(1);
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	a5 = ippr_ftp_atoi(&s);
2547c478bd9Sstevel@tonic-gate 	if (s == NULL) {
255f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
256ab25eeb5Syz 			printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 3);
2577c478bd9Sstevel@tonic-gate 		return 0;
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 	if (*s == ')')
2607c478bd9Sstevel@tonic-gate 		s++;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	/*
2637c478bd9Sstevel@tonic-gate 	 * check for CR-LF at the end.
2647c478bd9Sstevel@tonic-gate 	 */
2657c478bd9Sstevel@tonic-gate 	if (*s == '\n')
2667c478bd9Sstevel@tonic-gate 		s--;
2677c478bd9Sstevel@tonic-gate 	if ((*s == '\r') && (*(s + 1) == '\n')) {
2687c478bd9Sstevel@tonic-gate 		s += 2;
2697c478bd9Sstevel@tonic-gate 		a6 = a5 & 0xff;
2707c478bd9Sstevel@tonic-gate 	} else {
271f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 1)
272ab25eeb5Syz 			printf("ippr_ftp_port:missing %s\n", "cr-lf");
2737c478bd9Sstevel@tonic-gate 		return 0;
2747c478bd9Sstevel@tonic-gate 	}
275ab25eeb5Syz 
2767c478bd9Sstevel@tonic-gate 	a5 >>= 8;
2777c478bd9Sstevel@tonic-gate 	a5 &= 0xff;
278ab25eeb5Syz 	sp = a5 << 8 | a6;
279ab25eeb5Syz 	/*
280ab25eeb5Syz 	 * Don't allow the PORT command to specify a port < 1024 due to
281ab25eeb5Syz 	 * security crap.
282ab25eeb5Syz 	 */
283ab25eeb5Syz 	if (sp < 1024) {
284f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 0)
285ab25eeb5Syz 			printf("ippr_ftp_port:sp(%d) < 1024\n", sp);
286ab25eeb5Syz 		return 0;
287ab25eeb5Syz 	}
2887c478bd9Sstevel@tonic-gate 	/*
2897c478bd9Sstevel@tonic-gate 	 * Calculate new address parts for PORT command
2907c478bd9Sstevel@tonic-gate 	 */
2917c478bd9Sstevel@tonic-gate 	if (nat->nat_dir == NAT_INBOUND)
2927c478bd9Sstevel@tonic-gate 		a1 = ntohl(nat->nat_oip.s_addr);
2937c478bd9Sstevel@tonic-gate 	else
2947c478bd9Sstevel@tonic-gate 		a1 = ntohl(ip->ip_src.s_addr);
2957c478bd9Sstevel@tonic-gate 	a2 = (a1 >> 16) & 0xff;
2967c478bd9Sstevel@tonic-gate 	a3 = (a1 >> 8) & 0xff;
2977c478bd9Sstevel@tonic-gate 	a4 = a1 & 0xff;
2987c478bd9Sstevel@tonic-gate 	a1 >>= 24;
2997c478bd9Sstevel@tonic-gate 	olen = s - f->ftps_rptr;
3007c478bd9Sstevel@tonic-gate 	/* DO NOT change this to snprintf! */
301ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL)
302ab25eeb5Syz 	(void) SNPRINTF(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n",
303ab25eeb5Syz 		 "PORT", a1, a2, a3, a4, a5, a6);
3047c478bd9Sstevel@tonic-gate #else
3057c478bd9Sstevel@tonic-gate 	(void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n",
3067c478bd9Sstevel@tonic-gate 		       "PORT", a1, a2, a3, a4, a5, a6);
3077c478bd9Sstevel@tonic-gate #endif
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	nlen = strlen(newbuf);
3107c478bd9Sstevel@tonic-gate 	inc = nlen - olen;
3117c478bd9Sstevel@tonic-gate 	if ((inc + ip->ip_len) > 65535) {
312f4b3ec61Sdh 		if (ifsftp->ippr_ftp_debug > 0)
313ab25eeb5Syz 			printf("ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n",
314ab25eeb5Syz 			       inc);
3157c478bd9Sstevel@tonic-gate 		return 0;
3167c478bd9Sstevel@tonic-gate 	}
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate #if !defined(_KERNEL)
3197c478bd9Sstevel@tonic-gate 	bcopy(newbuf, MTOD(m, char *) + off, nlen);
3207c478bd9Sstevel@tonic-gate #else
3217c478bd9Sstevel@tonic-gate # if defined(MENTAT)
3227c478bd9Sstevel@tonic-gate 	if (inc < 0)
3237c478bd9Sstevel@tonic-gate 		(void)adjmsg(m, inc);
324ab25eeb5Syz # else /* defined(MENTAT) */
325ab25eeb5Syz 	/*
326ab25eeb5Syz 	 * m_adj takes care of pkthdr.len, if required and treats inc<0 to
327ab25eeb5Syz 	 * mean remove -len bytes from the end of the packet.
328ab25eeb5Syz 	 * The mbuf chain will be extended if necessary by m_copyback().
329ab25eeb5Syz 	 */
3307c478bd9Sstevel@tonic-gate 	if (inc < 0)
3317c478bd9Sstevel@tonic-gate 		m_adj(m, inc);
332ab25eeb5Syz # endif /* defined(MENTAT) */
333ab25eeb5Syz #endif /* !defined(_KERNEL) */
3347c478bd9Sstevel@tonic-gate 	COPYBACK(m, off, nlen, newbuf);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	if (inc != 0) {
3377c478bd9Sstevel@tonic-gate 		ip->ip_len += inc;
3387c478bd9Sstevel@tonic-gate 		fin->fin_dlen += inc;
3397c478bd9Sstevel@tonic-gate 		fin->fin_plen += inc;
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	/*
3437c478bd9Sstevel@tonic-gate 	 * The server may not make the connection back from port 20, but
3447c478bd9Sstevel@tonic-gate 	 * it is the most likely so use it here to check for a conflicting
3457c478bd9Sstevel@tonic-gate 	 * mapping.
3467c478bd9Sstevel@tonic-gate 	 */
3477c478bd9Sstevel@tonic-gate 	bcopy((char *)fin, (char *)&fi, sizeof(fi));
3487c478bd9Sstevel@tonic-gate 	fi.fin_flx |= FI_IGNORE;
3497c478bd9Sstevel@tonic-gate 	fi.fin_data[0] = sp;
3507c478bd9Sstevel@tonic-gate 	fi.fin_data[1] = fin->fin_data[1] - 1;
351ab25eeb5Syz 	/*
352ab25eeb5Syz 	 * Add skeleton NAT entry for connection which will come back the
353ab25eeb5Syz 	 * other way.
354ab25eeb5Syz 	 */
3557c478bd9Sstevel@tonic-gate 	if (nat->nat_dir == NAT_OUTBOUND)
3567c478bd9Sstevel@tonic-gate 		nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
3577c478bd9Sstevel@tonic-gate 				     nat->nat_inip, nat->nat_oip);
3587c478bd9Sstevel@tonic-gate 	else
3597c478bd9Sstevel@tonic-gate 		nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
3607c478bd9Sstevel@tonic-gate 				    nat->nat_inip, nat->nat_oip);
3617c478bd9Sstevel@tonic-gate 	if (nat2 == NULL) {
3627c478bd9Sstevel@tonic-gate 		int slen;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 		slen = ip->ip_len;
3657c478bd9Sstevel@tonic-gate 		ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
3667c478bd9Sstevel@tonic-gate 		bzero((char *)tcp2, sizeof(*tcp2));
3677c478bd9Sstevel@tonic-gate 		tcp2->th_win = htons(8192);
3687c478bd9Sstevel@tonic-gate 		tcp2->th_sport = htons(sp);
3697c478bd9Sstevel@tonic-gate 		TCP_OFF_A(tcp2, 5);
3707c478bd9Sstevel@tonic-gate 		tcp2->th_flags = TH_SYN;
3717c478bd9Sstevel@tonic-gate 		tcp2->th_dport = 0; /* XXX - don't specify remote port */
3727c478bd9Sstevel@tonic-gate 		fi.fin_data[1] = 0;
3737c478bd9Sstevel@tonic-gate 		fi.fin_dlen = sizeof(*tcp2);
3747c478bd9Sstevel@tonic-gate 		fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
3757c478bd9Sstevel@tonic-gate 		fi.fin_dp = (char *)tcp2;
376f4b3ec61Sdh 		fi.fin_fr = &ifsftp->ftppxyfr;
3777c478bd9Sstevel@tonic-gate 		fi.fin_out = nat->nat_dir;
3787c478bd9Sstevel@tonic-gate 		fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
3797c478bd9Sstevel@tonic-gate 		swip = ip->ip_src;
3807c478bd9Sstevel@tonic-gate 		swip2 = ip->ip_dst;
3817c478bd9Sstevel@tonic-gate 		if (nat->nat_dir == NAT_OUTBOUND) {
3827c478bd9Sstevel@tonic-gate 			fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
3837c478bd9Sstevel@tonic-gate 			ip->ip_src = nat->nat_inip;
3847c478bd9Sstevel@tonic-gate 		} else if (nat->nat_dir == NAT_INBOUND) {
3857c478bd9Sstevel@tonic-gate 			fi.fin_fi.fi_saddr = nat->nat_oip.s_addr;
3867c478bd9Sstevel@tonic-gate 			ip->ip_src = nat->nat_oip;
3877c478bd9Sstevel@tonic-gate 		}
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 		flags = NAT_SLAVE|IPN_TCP|SI_W_DPORT;
3907c478bd9Sstevel@tonic-gate 		if (nat->nat_dir == NAT_INBOUND)
3917c478bd9Sstevel@tonic-gate 			flags |= NAT_NOTRULEPORT;
3927c478bd9Sstevel@tonic-gate 		nat2 = nat_new(&fi, nat->nat_ptr, NULL, flags, nat->nat_dir);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 		if (nat2 != NULL) {
3957c478bd9Sstevel@tonic-gate 			(void) nat_proto(&fi, nat2, IPN_TCP);
3967c478bd9Sstevel@tonic-gate 			nat_update(&fi, nat2, nat->nat_ptr);
3977c478bd9Sstevel@tonic-gate 			fi.fin_ifp = NULL;
3987c478bd9Sstevel@tonic-gate 			if (nat->nat_dir == NAT_INBOUND) {
3997c478bd9Sstevel@tonic-gate 				fi.fin_fi.fi_daddr = nat->nat_inip.s_addr;
4007c478bd9Sstevel@tonic-gate 				ip->ip_dst = nat->nat_inip;
4017c478bd9Sstevel@tonic-gate 			}
4027c478bd9Sstevel@tonic-gate 			(void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT);
4037c478bd9Sstevel@tonic-gate 		}
4047c478bd9Sstevel@tonic-gate 		ip->ip_len = slen;
4057c478bd9Sstevel@tonic-gate 		ip->ip_src = swip;
4067c478bd9Sstevel@tonic-gate 		ip->ip_dst = swip2;
4077c478bd9Sstevel@tonic-gate 	} else {
4087c478bd9Sstevel@tonic-gate 		ipstate_t *is;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 		nat_update(&fi, nat2, nat->nat_ptr);
411f4b3ec61Sdh 		READ_ENTER(&ifs->ifs_ipf_state);
4127c478bd9Sstevel@tonic-gate 		is = nat2->nat_state;
4137c478bd9Sstevel@tonic-gate 		if (is != NULL) {
4147c478bd9Sstevel@tonic-gate 			MUTEX_ENTER(&is->is_lock);
415f4b3ec61Sdh 			(void)fr_tcp_age(&is->is_sti, &fi, ifs->ifs_ips_tqtqb,
416f4b3ec61Sdh 				         is->is_flags);
4177c478bd9Sstevel@tonic-gate 			MUTEX_EXIT(&is->is_lock);
4187c478bd9Sstevel@tonic-gate 		}
419f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_state);
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 	return APR_INC(inc);
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 
ippr_ftp_client(fin,ip,nat,ftp,dlen,ifsftp)425f4b3ec61Sdh int ippr_ftp_client(fin, ip, nat, ftp, dlen, ifsftp)
4267c478bd9Sstevel@tonic-gate fr_info_t *fin;
4277c478bd9Sstevel@tonic-gate nat_t *nat;
4287c478bd9Sstevel@tonic-gate ftpinfo_t *ftp;
4297c478bd9Sstevel@tonic-gate ip_t *ip;
4307c478bd9Sstevel@tonic-gate int dlen;
431