17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (C) 2000-2003 Darren Reed
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * See the IPFILTER.LICENCE file for details on licencing.
57c478bd9Sstevel@tonic-gate  *
6ab25eeb5Syz  * $Id: ip_irc_pxy.c,v 2.39.2.4 2005/02/04 10:22:55 darrenr Exp $
77c478bd9Sstevel@tonic-gate  *
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 
127c478bd9Sstevel@tonic-gate #define	IPF_IRC_PROXY
137c478bd9Sstevel@tonic-gate 
147c478bd9Sstevel@tonic-gate #define	IPF_IRCBUFSZ	96	/* This *MUST* be >= 64! */
157c478bd9Sstevel@tonic-gate 
16f4b3ec61Sdh typedef struct ifs_ircpxy {
17f4b3ec61Sdh 	frentry_t	ircnatfr;
18f4b3ec61Sdh 	int		irc_proxy_init;
19f4b3ec61Sdh } ifs_ircpxy_t;
207c478bd9Sstevel@tonic-gate 
21f4b3ec61Sdh 
22f4b3ec61Sdh int ippr_irc_init __P((void **, ipf_stack_t *));
23f4b3ec61Sdh void ippr_irc_fini __P((void **, ipf_stack_t *));
24f4b3ec61Sdh int ippr_irc_new __P((fr_info_t *, ap_session_t *, nat_t *, void *));
25f4b3ec61Sdh int ippr_irc_out __P((fr_info_t *, ap_session_t *, nat_t *, void *));
26f4b3ec61Sdh int ippr_irc_send __P((fr_info_t *, nat_t *, ifs_ircpxy_t *));
277c478bd9Sstevel@tonic-gate int ippr_irc_complete __P((ircinfo_t *, char *, size_t));
287c478bd9Sstevel@tonic-gate u_short ipf_irc_atoi __P((char **));
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * Initialize local structures.
327c478bd9Sstevel@tonic-gate  */
33f4b3ec61Sdh /*ARGSUSED*/
ippr_irc_init(private,ifs)34f4b3ec61Sdh int ippr_irc_init(private, ifs)
35f4b3ec61Sdh void **private;
36f4b3ec61Sdh ipf_stack_t *ifs;
377c478bd9Sstevel@tonic-gate {
38f4b3ec61Sdh 	ifs_ircpxy_t *ifsirc;
39f4b3ec61Sdh 
40f4b3ec61Sdh 	KMALLOC(ifsirc, ifs_ircpxy_t *);
41f4b3ec61Sdh 	if (ifsirc == NULL)
42f4b3ec61Sdh 		return -1;
43f4b3ec61Sdh 
44f4b3ec61Sdh 	bzero((char *)&ifsirc->ircnatfr, sizeof(ifsirc->ircnatfr));
45f4b3ec61Sdh 	ifsirc->ircnatfr.fr_ref = 1;
46f4b3ec61Sdh 	ifsirc->ircnatfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
47f4b3ec61Sdh 	MUTEX_INIT(&ifsirc->ircnatfr.fr_lock, "IRC proxy rule lock");
48f4b3ec61Sdh 	ifsirc->irc_proxy_init = 1;
49f4b3ec61Sdh 
50f4b3ec61Sdh 	*private = (void *)ifsirc;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 	return 0;
537c478bd9Sstevel@tonic-gate }
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate 
56f4b3ec61Sdh /*ARGSUSED*/
ippr_irc_fini(private,ifs)57f4b3ec61Sdh void ippr_irc_fini(private, ifs)
58f4b3ec61Sdh void **private;
59f4b3ec61Sdh ipf_stack_t *ifs;
607c478bd9Sstevel@tonic-gate {
61f4b3ec61Sdh 	ifs_ircpxy_t *ifsirc = *((ifs_ircpxy_t **)private);
62f4b3ec61Sdh 
63f4b3ec61Sdh 	if (ifsirc->irc_proxy_init == 1) {
64f4b3ec61Sdh 		MUTEX_DESTROY(&ifsirc->ircnatfr.fr_lock);
65f4b3ec61Sdh 		ifsirc->irc_proxy_init = 0;
667c478bd9Sstevel@tonic-gate 	}
67f4b3ec61Sdh 
68f4b3ec61Sdh 	KFREE(ifsirc);
69f4b3ec61Sdh 	*private = NULL;
707c478bd9Sstevel@tonic-gate }
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 
73f4b3ec61Sdh static char *ippr_irc_dcctypes[] = {
747c478bd9Sstevel@tonic-gate 	"CHAT ",	/* CHAT chat ipnumber portnumber */
757c478bd9Sstevel@tonic-gate 	"SEND ",	/* SEND filename ipnumber portnumber */
767c478bd9Sstevel@tonic-gate 	"MOVE ",
777c478bd9Sstevel@tonic-gate 	"TSEND ",
787c478bd9Sstevel@tonic-gate 	"SCHAT ",
797c478bd9Sstevel@tonic-gate 	NULL,
807c478bd9Sstevel@tonic-gate };
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * :A PRIVMSG B :^ADCC CHAT chat 0 0^A\r\n
857c478bd9Sstevel@tonic-gate  * PRIVMSG B ^ADCC CHAT chat 0 0^A\r\n
867c478bd9Sstevel@tonic-gate  */
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 
ippr_irc_complete(ircp,buf,len)897c478bd9Sstevel@tonic-gate int ippr_irc_complete(ircp, buf, len)
907c478bd9Sstevel@tonic-gate ircinfo_t *ircp;
917c478bd9Sstevel@tonic-gate char *buf;
927c478bd9Sstevel@tonic-gate size_t len;
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	register char *s, c;
957c478bd9Sstevel@tonic-gate 	register size_t i;
967c478bd9Sstevel@tonic-gate 	u_32_t l;
977c478bd9Sstevel@tonic-gate 	int j, k;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	ircp->irc_ipnum = 0;
1007c478bd9Sstevel@tonic-gate 	ircp->irc_port = 0;
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	if (len < 31)
1037c478bd9Sstevel@tonic-gate 		return 0;
1047c478bd9Sstevel@tonic-gate 	s = buf;
1057c478bd9Sstevel@tonic-gate 	c = *s++;
1067c478bd9Sstevel@tonic-gate 	i = len - 1;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	if ((c != ':') && (c != 'P'))
1097c478bd9Sstevel@tonic-gate 		return 0;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	if (c == ':') {
1127c478bd9Sstevel@tonic-gate 		/*
1137c478bd9Sstevel@tonic-gate 		 * Loosely check that the source is a nickname of some sort
1147c478bd9Sstevel@tonic-gate 		 */
1157c478bd9Sstevel@tonic-gate 		s++;
1167c478bd9Sstevel@tonic-gate 		c = *s;
1177c478bd9Sstevel@tonic-gate 		ircp->irc_snick = s;
118ab25eeb5Syz 		if (!ISALPHA(c))
1197c478bd9Sstevel@tonic-gate 			return 0;
1207c478bd9Sstevel@tonic-gate 		i--;
121ab25eeb5Syz 		for (c = *s; !ISSPACE(c) && (i > 0); i--)
1227c478bd9Sstevel@tonic-gate 			c = *s++;
1237c478bd9Sstevel@tonic-gate 		if (i < 31)
1247c478bd9Sstevel@tonic-gate 			return 0;
1257c478bd9Sstevel@tonic-gate 		if (c != 'P')
1267c478bd9Sstevel@tonic-gate 			return 0;
1277c478bd9Sstevel@tonic-gate 	} else
1287c478bd9Sstevel@tonic-gate 		ircp->irc_snick = NULL;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	/*
1317c478bd9Sstevel@tonic-gate 	 * Check command string
1327c478bd9Sstevel@tonic-gate 	 */
1337c478bd9Sstevel@tonic-gate 	if (strncmp(s, "PRIVMSG ", 8))
1347c478bd9Sstevel@tonic-gate 		return 0;
1357c478bd9Sstevel@tonic-gate 	i -= 8;
1367c478bd9Sstevel@tonic-gate 	s += 8;
1377c478bd9Sstevel@tonic-gate 	c = *s;
1387c478bd9Sstevel@tonic-gate 	ircp->irc_dnick = s;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	/*
1417c478bd9Sstevel@tonic-gate 	 * Loosely check that the destination is a nickname of some sort
1427c478bd9Sstevel@tonic-gate 	 */
143ab25eeb5Syz 	if (!ISALPHA(c))
1447c478bd9Sstevel@tonic-gate 		return 0;
145ab25eeb5Syz 	for (; !ISSPACE(c) && (i > 0); i--)
1467c478bd9Sstevel@tonic-gate 		c = *s++;
1477c478bd9Sstevel@tonic-gate 	if (i < 20)
1487c478bd9Sstevel@tonic-gate 		return 0;
1497c478bd9Sstevel@tonic-gate 	s++,
1507c478bd9Sstevel@tonic-gate 	i--;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	/*
1537c478bd9Sstevel@tonic-gate 	 * Look for a ^A to start the DCC
1547c478bd9Sstevel@tonic-gate 	 */
1557c478bd9Sstevel@tonic-gate 	c = *s;
1567c478bd9Sstevel@tonic-gate 	if (c == ':') {
1577c478bd9Sstevel@tonic-gate 		s++;
1587c478bd9Sstevel@tonic-gate 		c = *s;
1597c478bd9Sstevel@tonic-gate 	}
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	if (strncmp(s, "\001DCC ", 4))
1627c478bd9Sstevel@tonic-gate 		return 0;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	i -= 4;
1657c478bd9Sstevel@tonic-gate 	s += 4;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	/*
1687c478bd9Sstevel@tonic-gate 	 * Check for a recognised DCC command
1697c478bd9Sstevel@tonic-gate 	 */
1707c478bd9Sstevel@tonic-gate 	for (j = 0, k = 0; ippr_irc_dcctypes[j]; j++) {
1717c478bd9Sstevel@tonic-gate 		k = MIN(strlen(ippr_irc_dcctypes[j]), i);
1727c478bd9Sstevel@tonic-gate 		if (!strncmp(ippr_irc_dcctypes[j], s, k))
1737c478bd9Sstevel@tonic-gate 			break;
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 	if (!ippr_irc_dcctypes[j])
1767c478bd9Sstevel@tonic-gate 		return 0;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	ircp->irc_type = s;
1797c478bd9Sstevel@tonic-gate 	i -= k;
1807c478bd9Sstevel@tonic-gate 	s += k;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	if (i < 11)
1837c478bd9Sstevel@tonic-gate 		return 0;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	/*
1867c478bd9Sstevel@tonic-gate 	 * Check for the arg
1877c478bd9Sstevel@tonic-gate 	 */
1887c478bd9Sstevel@tonic-gate 	c = *s;
189ab25eeb5Syz 	if (ISSPACE(c))
1907c478bd9Sstevel@tonic-gate 		return 0;
1917c478bd9Sstevel@tonic-gate 	ircp->irc_arg = s;
1927c478bd9Sstevel@tonic-gate 	for (; (c != ' ') && (c != '\001') && (i > 0); i--)
1937c478bd9Sstevel@tonic-gate 		c = *s++;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	if (c == '\001')	/* In reality a ^A can quote another ^A...*/
1967c478bd9Sstevel@tonic-gate 		return 0;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	if (i < 5)
1997c478bd9Sstevel@tonic-gate 		return 0;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	s++;
2027c478bd9Sstevel@tonic-gate 	i--;
2037c478bd9Sstevel@tonic-gate 	c = *s;
204ab25eeb5Syz 	if (!ISDIGIT(c))
2057c478bd9Sstevel@tonic-gate 		return 0;
2067c478bd9Sstevel@tonic-gate 	ircp->irc_addr = s;
2077c478bd9Sstevel@tonic-gate 	/*
2087c478bd9Sstevel@tonic-gate 	 * Get the IP#
2097c478bd9Sstevel@tonic-gate 	 */
210ab25eeb5Syz 	for (l = 0; ISDIGIT(c) && (i > 0); i--) {
2117c478bd9Sstevel@tonic-gate 		l *= 10;
2127c478bd9Sstevel@tonic-gate 		l += c - '0';
2137c478bd9Sstevel@tonic-gate 		c = *s++;
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	if (i < 4)
2177c478bd9Sstevel@tonic-gate 		return 0;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (c != ' ')
2207c478bd9Sstevel@tonic-gate 		return 0;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	ircp->irc_ipnum = l;
2237c478bd9Sstevel@tonic-gate 	s++;
2247c478bd9Sstevel@tonic-gate 	i--;
2257c478bd9Sstevel@tonic-gate 	c = *s;
226ab25eeb5Syz 	if (!ISDIGIT(c))
2277c478bd9Sstevel@tonic-gate 		return 0;
2287c478bd9Sstevel@tonic-gate 	/*
2297c478bd9Sstevel@tonic-gate 	 * Get the port#
2307c478bd9Sstevel@tonic-gate 	 */
231ab25eeb5Syz 	for (l = 0; ISDIGIT(c) && (i > 0); i--) {
2327c478bd9Sstevel@tonic-gate 		l *= 10;
2337c478bd9Sstevel@tonic-gate 		l += c - '0';
2347c478bd9Sstevel@tonic-gate 		c = *s++;
2357c478bd9Sstevel@tonic-gate 	}
2367c478bd9Sstevel@tonic-gate 	if (i < 3)
2377c478bd9Sstevel@tonic-gate 		return 0;
2387c478bd9Sstevel@tonic-gate 	if (strncmp(s, "\001\r\n", 3))
2397c478bd9Sstevel@tonic-gate 		return 0;
2407c478bd9Sstevel@tonic-gate 	s += 3;
2417c478bd9Sstevel@tonic-gate 	ircp->irc_len = s - buf;
2427c478bd9Sstevel@tonic-gate 	ircp->irc_port = l;
2437c478bd9Sstevel@tonic-gate 	return 1;
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 
247f4b3ec61Sdh /*ARGSUSED*/
ippr_irc_new(fin,aps,nat,private)248f4b3ec61Sdh int ippr_irc_new(fin, aps, nat, private)
2497c478bd9Sstevel@tonic-gate fr_info_t *fin;
2507c478bd9Sstevel@tonic-gate ap_session_t *aps;
2517c478bd9Sstevel@tonic-gate nat_t *nat;
252f4b3ec61Sdh void *private;
2537c478bd9Sstevel@tonic-gate {
2547c478bd9Sstevel@tonic-gate 	ircinfo_t *irc;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	KMALLOC(irc, ircinfo_t *);
2577c478bd9Sstevel@tonic-gate 	if (irc == NULL)
2587c478bd9Sstevel@tonic-gate 		return -1;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	fin = fin;	/* LINT */
2617c478bd9Sstevel@tonic-gate 	nat = nat;	/* LINT */
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	aps->aps_data = irc;
2647c478bd9Sstevel@tonic-gate 	aps->aps_psiz = sizeof(ircinfo_t);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	bzero((char *)irc, sizeof(*irc));
2677c478bd9Sstevel@tonic-gate 	return 0;
2687c478bd9Sstevel@tonic-gate }
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 
ippr_irc_send(fin,nat,ifsirc)271f4b3ec61Sdh int ippr_irc_send(fin, nat, ifsirc)
2727c478bd9Sstevel@tonic-gate fr_info_t *fin;
2737c478bd9Sstevel@tonic-gate nat_t *nat;
274f4b3ec61Sdh ifs_ircpxy_t *ifsirc;
2757c478bd9Sstevel@tonic-gate {
2767c478bd9Sstevel@tonic-gate 	char ctcpbuf[IPF_IRCBUFSZ], newbuf[IPF_IRCBUFSZ];
2777c478bd9Sstevel@tonic-gate 	tcphdr_t *tcp, tcph, *tcp2 = &tcph;
2787c478bd9Sstevel@tonic-gate 	int off, inc = 0, i, dlen;
2797c478bd9Sstevel@tonic-gate 	size_t nlen = 0, olen;
2807c478bd9Sstevel@tonic-gate 	struct in_addr swip;
2817c478bd9Sstevel@tonic-gate 	u_short a5, sp;
2827c478bd9Sstevel@tonic-gate 	ircinfo_t *irc;
2837c478bd9Sstevel@tonic-gate 	fr_info_t fi;
2847c478bd9Sstevel@tonic-gate 	nat_t *nat2;
2857c478bd9Sstevel@tonic-gate 	u_int a1;
2867c478bd9Sstevel@tonic-gate 	ip_t *ip;
2877c478bd9Sstevel@tonic-gate 	mb_t *m;
2887c478bd9Sstevel@tonic-gate #ifdef	MENTAT
2897c478bd9Sstevel@tonic-gate 	mb_t *m1;
2907c478bd9Sstevel@tonic-gate #endif
2917c478bd9Sstevel@tonic-gate 
292ab25eeb5Syz 	m = fin->fin_m;
2937c478bd9Sstevel@tonic-gate 	ip = fin->fin_ip;
2947c478bd9Sstevel@tonic-gate 	tcp = (tcphdr_t *)fin->fin_dp;
2957c478bd9Sstevel@tonic-gate 	bzero(ctcpbuf, sizeof(ctcpbuf));
296ab25eeb5Syz 	off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
2977c478bd9Sstevel@tonic-gate 
298ab25eeb5Syz #ifdef __sgi
299ab25eeb5Syz 	dlen = fin->fin_plen - off;
300ab25eeb5Syz #else
3017c478bd9Sstevel@tonic-gate 	dlen = MSGDSIZE(m) - off;
302ab25eeb5Syz #endif
3037c478bd9Sstevel@tonic-gate 	if (dlen <= 0)
3047c478bd9Sstevel@tonic-gate 		return 0;
3057c478bd9Sstevel@tonic-gate 	COPYDATA(m, off, MIN(sizeof(ctcpbuf), dlen), ctcpbuf);
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	if (dlen <= 0)
3087c478bd9Sstevel@tonic-gate 		return 0;
3097c478bd9Sstevel@tonic-gate 	ctcpbuf[sizeof(ctcpbuf) - 1] = '\0';
3107c478bd9Sstevel@tonic-gate 	*newbuf = '\0';
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	irc = nat->nat_aps->aps_data;
3137c478bd9Sstevel@tonic-gate 	if (ippr_irc_complete(irc, ctcpbuf, dlen) == 0)
3147c478bd9Sstevel@tonic-gate 		return 0;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	/*
3177c478bd9Sstevel@tonic-gate 	 * check that IP address in the PORT/PASV reply is the same as the
3187c478bd9Sstevel@tonic-gate 	 * sender of the command - prevents using PORT for port scanning.
3197c478bd9Sstevel@tonic-gate 	 */
3207c478bd9Sstevel@tonic-gate 	if (irc->irc_ipnum != ntohl(nat->nat_inip.s_addr))
3217c478bd9Sstevel@tonic-gate 		return 0;
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	a5 = irc->irc_port;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	/*
3267c478bd9Sstevel@tonic-gate 	 * Calculate new address parts for the DCC command
3277c478bd9Sstevel@tonic-gate 	 */
3287c478bd9Sstevel@tonic-gate 	a1 = ntohl(ip->ip_src.s_addr);
3297c478bd9Sstevel@tonic-gate 	olen = irc->irc_len;
3307c478bd9Sstevel@tonic-gate 	i = irc->irc_addr - ctcpbuf;
3317c478bd9Sstevel@tonic-gate 	i++;
3327c478bd9Sstevel@tonic-gate 	(void) strncpy(newbuf, ctcpbuf, i);
3337c478bd9Sstevel@tonic-gate 	/* DO NOT change these! */
334ab25eeb5Syz #if defined(SNPRINTF) && defined(KERNEL)
335ab25eeb5Syz 	(void) SNPRINTF(newbuf, sizeof(newbuf) - i, "%u %u\001\r\n", a1, a5);
3367c478bd9Sstevel@tonic-gate #else
3377c478bd9Sstevel@tonic-gate 	(void) sprintf(newbuf, "%u %u\001\r\n", a1, a5);
3387c478bd9Sstevel@tonic-gate #endif
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	nlen = strlen(newbuf);
3417c478bd9Sstevel@tonic-gate 	inc = nlen - olen;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	if ((inc + ip->ip_len) > 65535)
3447c478bd9Sstevel@tonic-gate 		return 0;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate #ifdef	MENTAT
3477c478bd9Sstevel@tonic-gate 	for (m1 = m; m1->b_cont; m1 = m1->b_cont)
3487c478bd9Sstevel@tonic-gate 		;
3497c478bd9Sstevel@tonic-gate 	if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) {
3507c478bd9Sstevel@tonic-gate 		mblk_t *nm;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 		/* alloc enough to keep same trailer space for lower driver */
3537c478bd9Sstevel@tonic-gate 		nm = allocb(nlen, BPRI_MED);
3547c478bd9Sstevel@tonic-gate 		PANIC((!nm),("ippr_irc_out: allocb failed"));
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 		nm->b_band = m1->b_band;
3577c478bd9Sstevel@tonic-gate 		nm->b_wptr += nlen;
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 		m1->b_wptr -= olen;
3607c478bd9Sstevel@tonic-gate 		PANIC((m1->b_wptr < m1->b_rptr),
3617c478bd9Sstevel@tonic-gate 		      ("ippr_irc_out: cannot handle fragmented data block"));
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 		linkb(m1, nm);
3647c478bd9Sstevel@tonic-gate 	} else {
3657c478bd9Sstevel@tonic-gate # if SOLARIS && defined(ICK_VALID)
3667c478bd9Sstevel@tonic-gate 		if (m1->b_datap->db_struiolim == m1->b_wptr)
3677c478bd9Sstevel@tonic-gate 			m1->b_datap->db_struiolim += inc;
3687c478bd9Sstevel@tonic-gate 		m1->b_datap->db_struioflag &= ~STRUIO_IP;
3697c478bd9Sstevel@tonic-gate # endif
3707c478bd9Sstevel@tonic-gate 		m1->b_wptr += inc;
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate #else
3737c478bd9Sstevel@tonic-gate 	if (inc < 0)
3747c478bd9Sstevel@tonic-gate 		m_adj(m, inc);
3757c478bd9Sstevel@tonic-gate 	/* the mbuf chain will be extended if necessary by m_copyback() */
3767c478bd9Sstevel@tonic-gate #endif
3777c478bd9Sstevel@tonic-gate 	COPYBACK(m, off, nlen, newbuf);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	if (inc != 0) {
3807c478bd9Sstevel@tonic-gate #if defined(MENTAT) || defined(__sgi)
3817c478bd9Sstevel@tonic-gate 		register u_32_t	sum1, sum2;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 		sum1 = ip->ip_len;
3847c478bd9Sstevel@tonic-gate 		sum2 = ip->ip_len + inc;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 		/* Because ~1 == -2, We really need ~1 == -1 */
3877c478bd9Sstevel@tonic-gate 		if (sum1 > sum2)
3887c478bd9Sstevel@tonic-gate 			sum2--;
3897c478bd9Sstevel@tonic-gate 		sum2 -= sum1;
3907c478bd9Sstevel@tonic-gate 		sum2 = (sum2 & 0xffff) + (sum2 >> 16);
3917c478bd9Sstevel@tonic-gate 
392381a2a9aSdr 		fix_outcksum(&ip->ip_sum, sum2);
3937c478bd9Sstevel@tonic-gate #endif
3947c478bd9Sstevel@tonic-gate 		ip->ip_len += inc;
3957c478bd9Sstevel@tonic-gate 	}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	/*
3987c478bd9Sstevel@tonic-gate 	 * Add skeleton NAT entry for connection which will come back the
3997c478bd9Sstevel@tonic-gate 	 * other way.
4007c478bd9Sstevel@tonic-gate 	 */
4017c478bd9Sstevel@tonic-gate 	sp = htons(a5);
4027c478bd9Sstevel@tonic-gate 	/*
4037c478bd9Sstevel@tonic-gate 	 * Don't allow the PORT command to specify a port < 1024 due to
4047c478bd9Sstevel@tonic-gate 	 * security crap.
4057c478bd9Sstevel@tonic-gate 	 */
4067c478bd9Sstevel@tonic-gate 	if (ntohs(sp) < 1024)
4077c478bd9Sstevel@tonic-gate 		return 0;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	/*
4107c478bd9Sstevel@tonic-gate 	 * The server may not make the connection back from port 20, but
4117c478bd9Sstevel@tonic-gate 	 * it is the most likely so use it here to check for a conflicting
4127c478bd9Sstevel@tonic-gate 	 * mapping.
4137c478bd9Sstevel@tonic-gate 	 */
4147c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi));
4157c478bd9Sstevel@tonic-gate 	fi.fin_data[0] = sp;
4167c478bd9Sstevel@tonic-gate 	fi.fin_data[1] = fin->fin_data[1];
4177c478bd9Sstevel@tonic-gate 	nat2 = nat_outlookup(fin, IPN_TCP, nat->nat_p, nat->nat_inip,
4187c478bd9Sstevel@tonic-gate 			     ip->ip_dst);
4197c478bd9Sstevel@tonic-gate 	if (nat2 == NULL) {
4207c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi));
4217c478bd9Sstevel@tonic-gate 		bzero((char *)tcp2, sizeof(*tcp2));
4227c478bd9Sstevel@tonic-gate 		tcp2->th_win = htons(8192);
4237c478bd9Sstevel@tonic-gate 		tcp2->th_sport = sp;
4247c478bd9Sstevel@tonic-gate 		tcp2->th_dport = 0; /* XXX - don't specify remote port */
4257c478bd9Sstevel@tonic-gate 		fi.fin_data[0] = ntohs(sp);
4267c478bd9Sstevel@tonic-gate 		fi.fin_data[1] = 0;
4277c478bd9Sstevel@tonic-gate 		fi.fin_dp = (char *)tcp2;
428f4b3ec61Sdh 		fi.fin_fr = &ifsirc->ircnatfr;
4297c478bd9Sstevel@tonic-gate 		fi.fin_dlen = sizeof(*tcp2);
4307c478bd9Sstevel@tonic-gate 		fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
4317c478bd9Sstevel@tonic-gate 		swip = ip->ip_src;
4327c478bd9Sstevel@tonic-gate 		ip->ip_src = nat->nat_inip;
4337c478bd9Sstevel@tonic-gate 		nat2 = nat_new(&fi, nat->nat_ptr, NULL,
4347c478bd9Sstevel@tonic-gate 			       NAT_SLAVE|IPN_TCP|SI_W_DPORT, NAT_OUTBOUND);
4357c478bd9Sstevel@tonic-gate 		if (nat2 != NULL) {
4367c478bd9Sstevel@tonic-gate 			(void) nat_proto(&fi, nat2, 0);
4377c478bd9Sstevel@tonic-gate 			nat_update(&fi, nat2, nat2->nat_ptr);
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 			(void) fr_addstate(&fi, NULL, SI_W_DPORT);
4407c478bd9Sstevel@tonic-gate 		}
4417c478bd9Sstevel@tonic-gate 		ip->ip_src = swip;
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 	return inc;
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 
ippr_irc_out(fin,aps,nat,private)447f4b3ec61Sdh int ippr_irc_out(fin, aps, nat, private)
4487c478bd9Sstevel@tonic-gate fr_info_t *fin;
4497c478bd9Sstevel@tonic-gate ap_session_t *aps;
4507c478bd9Sstevel@tonic-gate nat_t *nat;
451f4b3ec61Sdh void *private;
4527c478bd9Sstevel@tonic-gate {
4537c478bd9Sstevel@tonic-gate 	aps = aps;	/* LINT */
454f4b3ec61Sdh 	return ippr_irc_send(fin, nat, (ifs_ircpxy_t *)private);
4557c478bd9Sstevel@tonic-gate }
456