xref: /freebsd/sys/netinet/libalias/alias_irc.c (revision fb2ea26f3c3681f5ef639af9c798a631d800864b)
1f987e1bdSBrian Somers /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni  *
4e83aaae3SBrian Somers  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5f987e1bdSBrian Somers  * All rights reserved.
6f987e1bdSBrian Somers  *
7f987e1bdSBrian Somers  * Redistribution and use in source and binary forms, with or without
8f987e1bdSBrian Somers  * modification, are permitted provided that the following conditions
9f987e1bdSBrian Somers  * are met:
10f987e1bdSBrian Somers  * 1. Redistributions of source code must retain the above copyright
11f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer.
12f987e1bdSBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
13f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer in the
14f987e1bdSBrian Somers  *    documentation and/or other materials provided with the distribution.
15f987e1bdSBrian Somers  *
16f987e1bdSBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f987e1bdSBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f987e1bdSBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f987e1bdSBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f987e1bdSBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f987e1bdSBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f987e1bdSBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f987e1bdSBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f987e1bdSBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f987e1bdSBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f987e1bdSBrian Somers  * SUCH DAMAGE.
27f987e1bdSBrian Somers  */
28f987e1bdSBrian Somers 
29e2505aa6SMatthew Dillon #include <sys/cdefs.h>
303b160b8bSBrian Somers /* Alias_irc.c intercepts packages contain IRC CTCP commands, and
313b160b8bSBrian Somers 	changes DCC commands to export a port on the aliasing host instead
323b160b8bSBrian Somers 	of an aliased host.
333b160b8bSBrian Somers 
343b160b8bSBrian Somers     For this routine to work, the DCC command must fit entirely into a
353b160b8bSBrian Somers     single TCP packet.  This will usually happen, but is not
363b160b8bSBrian Somers     guaranteed.
373b160b8bSBrian Somers 
383b160b8bSBrian Somers 	 The interception is likely to change the length of the packet.
393b160b8bSBrian Somers 	 The handling of this is copied more-or-less verbatim from
403b160b8bSBrian Somers 	 ftp_alias.c
413b160b8bSBrian Somers 
423b160b8bSBrian Somers 	 Initial version: Eivind Eklund <perhaps@yes.no> (ee) 97-01-29
433b160b8bSBrian Somers 
443b160b8bSBrian Somers 	 Version 2.1:  May, 1997 (cjm)
453b160b8bSBrian Somers 	     Very minor changes to conform with
463b160b8bSBrian Somers 	     local/global/function naming conventions
47a4641f4eSPedro F. Giffuni 	     within the packet alising module.
483b160b8bSBrian Somers */
493b160b8bSBrian Somers 
503b160b8bSBrian Somers /* Includes */
51c649a2e0SGleb Smirnoff #ifdef _KERNEL
52c649a2e0SGleb Smirnoff #include <sys/param.h>
53c649a2e0SGleb Smirnoff #include <sys/ctype.h>
54c649a2e0SGleb Smirnoff #include <sys/limits.h>
55be4f3cd0SPaolo Pisati #include <sys/systm.h>
56be4f3cd0SPaolo Pisati #include <sys/kernel.h>
57be4f3cd0SPaolo Pisati #include <sys/module.h>
58c649a2e0SGleb Smirnoff #else
59dd14bc5dSPaolo Pisati #include <ctype.h>
60be4f3cd0SPaolo Pisati #include <errno.h>
61c649a2e0SGleb Smirnoff #include <sys/types.h>
623b160b8bSBrian Somers #include <stdio.h>
63f6efbc88SPaolo Pisati #include <stdlib.h>
64edb2e5dcSAlexander Kabaev #include <string.h>
65c649a2e0SGleb Smirnoff #include <limits.h>
66c649a2e0SGleb Smirnoff #endif
67c649a2e0SGleb Smirnoff 
683b160b8bSBrian Somers #include <netinet/in_systm.h>
693b160b8bSBrian Somers #include <netinet/in.h>
703b160b8bSBrian Somers #include <netinet/ip.h>
713b160b8bSBrian Somers #include <netinet/tcp.h>
723b160b8bSBrian Somers 
73c649a2e0SGleb Smirnoff #ifdef _KERNEL
74c649a2e0SGleb Smirnoff #include <netinet/libalias/alias.h>
7575bc2620SGleb Smirnoff #include <netinet/libalias/alias_local.h>
76be4f3cd0SPaolo Pisati #include <netinet/libalias/alias_mod.h>
77c649a2e0SGleb Smirnoff #else
783b160b8bSBrian Somers #include "alias_local.h"
79be4f3cd0SPaolo Pisati #include "alias_mod.h"
80c649a2e0SGleb Smirnoff #endif
813b160b8bSBrian Somers 
82be4f3cd0SPaolo Pisati #define IRC_CONTROL_PORT_NUMBER_1 6667
83be4f3cd0SPaolo Pisati #define IRC_CONTROL_PORT_NUMBER_2 6668
84be4f3cd0SPaolo Pisati 
8563bea446SPaolo Pisati #define PKTSIZE (IP_MAXPACKET + 1)
86f6efbc88SPaolo Pisati char *newpacket;
87f6efbc88SPaolo Pisati 
883b160b8bSBrian Somers /* Local defines */
893b160b8bSBrian Somers #define DBprintf(a)
903b160b8bSBrian Somers 
91be4f3cd0SPaolo Pisati static void
92be4f3cd0SPaolo Pisati AliasHandleIrcOut(struct libalias *, struct ip *, struct alias_link *,
93be4f3cd0SPaolo Pisati     int maxpacketsize);
943b160b8bSBrian Somers 
95be4f3cd0SPaolo Pisati static int
fingerprint(struct libalias * la,struct alias_data * ah)9643197d29SPaolo Pisati fingerprint(struct libalias *la, struct alias_data *ah)
97be4f3cd0SPaolo Pisati {
98aaf268f9SMark Johnston 	if (ah->dport == NULL || ah->lnk == NULL || ah->maxpktsize == 0)
99be4f3cd0SPaolo Pisati 		return (-1);
100be4f3cd0SPaolo Pisati 	if (ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_1
101be4f3cd0SPaolo Pisati 	    || ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_2)
102be4f3cd0SPaolo Pisati 		return (0);
103be4f3cd0SPaolo Pisati 	return (-1);
104be4f3cd0SPaolo Pisati }
105be4f3cd0SPaolo Pisati 
106be4f3cd0SPaolo Pisati static int
protohandler(struct libalias * la,struct ip * pip,struct alias_data * ah)107be4f3cd0SPaolo Pisati protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
108be4f3cd0SPaolo Pisati {
10963bea446SPaolo Pisati 	newpacket = malloc(PKTSIZE);
110f6efbc88SPaolo Pisati 	if (newpacket) {
111be4f3cd0SPaolo Pisati 		AliasHandleIrcOut(la, pip, ah->lnk, ah->maxpktsize);
112f6efbc88SPaolo Pisati 		free(newpacket);
113f6efbc88SPaolo Pisati 	}
114be4f3cd0SPaolo Pisati 	return (0);
115be4f3cd0SPaolo Pisati }
116be4f3cd0SPaolo Pisati 
117be4f3cd0SPaolo Pisati struct proto_handler handlers[] = {
118be4f3cd0SPaolo Pisati 	{
119be4f3cd0SPaolo Pisati 	  .pri = 90,
120be4f3cd0SPaolo Pisati 	  .dir = OUT,
121be4f3cd0SPaolo Pisati 	  .proto = TCP,
122be4f3cd0SPaolo Pisati 	  .fingerprint = &fingerprint,
123be4f3cd0SPaolo Pisati 	  .protohandler = &protohandler
124be4f3cd0SPaolo Pisati 	},
125be4f3cd0SPaolo Pisati 	{ EOH }
126be4f3cd0SPaolo Pisati };
127be4f3cd0SPaolo Pisati 
128be4f3cd0SPaolo Pisati static int
mod_handler(module_t mod,int type,void * data)129be4f3cd0SPaolo Pisati mod_handler(module_t mod, int type, void *data)
130be4f3cd0SPaolo Pisati {
131be4f3cd0SPaolo Pisati 	int error;
132be4f3cd0SPaolo Pisati 
133be4f3cd0SPaolo Pisati 	switch (type) {
134be4f3cd0SPaolo Pisati 	case MOD_LOAD:
135be4f3cd0SPaolo Pisati 		error = 0;
136be4f3cd0SPaolo Pisati 		LibAliasAttachHandlers(handlers);
137be4f3cd0SPaolo Pisati 		break;
138be4f3cd0SPaolo Pisati 	case MOD_UNLOAD:
139be4f3cd0SPaolo Pisati 		error = 0;
140be4f3cd0SPaolo Pisati 		LibAliasDetachHandlers(handlers);
141be4f3cd0SPaolo Pisati 		break;
142be4f3cd0SPaolo Pisati 	default:
143be4f3cd0SPaolo Pisati 		error = EINVAL;
144be4f3cd0SPaolo Pisati 	}
145be4f3cd0SPaolo Pisati 	return (error);
146be4f3cd0SPaolo Pisati }
147be4f3cd0SPaolo Pisati 
148be4f3cd0SPaolo Pisati #ifdef _KERNEL
149be4f3cd0SPaolo Pisati static
150be4f3cd0SPaolo Pisati #endif
151be4f3cd0SPaolo Pisati moduledata_t alias_mod = {
152be4f3cd0SPaolo Pisati        "alias_irc", mod_handler, NULL
153be4f3cd0SPaolo Pisati };
154be4f3cd0SPaolo Pisati 
155be4f3cd0SPaolo Pisati /* Kernel module definition. */
156be4f3cd0SPaolo Pisati #ifdef _KERNEL
157be4f3cd0SPaolo Pisati DECLARE_MODULE(alias_irc, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
158be4f3cd0SPaolo Pisati MODULE_VERSION(alias_irc, 1);
159be4f3cd0SPaolo Pisati MODULE_DEPEND(alias_irc, libalias, 1, 1, 1);
160be4f3cd0SPaolo Pisati #endif
161be4f3cd0SPaolo Pisati 
162be4f3cd0SPaolo Pisati static void
AliasHandleIrcOut(struct libalias * la,struct ip * pip,struct alias_link * lnk,int maxsize)1635e289f9eSPoul-Henning Kamp AliasHandleIrcOut(struct libalias *la,
1645e289f9eSPoul-Henning Kamp     struct ip *pip,		/* IP packet to examine */
165ed01a582SDag-Erling Smørgrav     struct alias_link *lnk,	/* Which link are we on? */
166f0f93429SDag-Erling Smørgrav     int maxsize			/* Maximum size of IP packet including
167f0f93429SDag-Erling Smørgrav 				 * headers */
1683b160b8bSBrian Somers )
1693b160b8bSBrian Somers {
1703b160b8bSBrian Somers 	int hlen, tlen, dlen;
1713b160b8bSBrian Somers 	struct in_addr true_addr;
1723b160b8bSBrian Somers 	u_short true_port;
1733b160b8bSBrian Somers 	char *sptr;
1743b160b8bSBrian Somers 	struct tcphdr *tc;
1753b160b8bSBrian Somers 	int i;			/* Iterator through the source */
1763b160b8bSBrian Somers 
1773b160b8bSBrian Somers 	/* Calculate data length of TCP packet */
1789fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
1793b160b8bSBrian Somers 	hlen = (pip->ip_hl + tc->th_off) << 2;
1803b160b8bSBrian Somers 	tlen = ntohs(pip->ip_len);
1813b160b8bSBrian Somers 	dlen = tlen - hlen;
1823b160b8bSBrian Somers 
183f0f93429SDag-Erling Smørgrav 	/*
184f0f93429SDag-Erling Smørgrav 	 * Return if data length is too short - assume an entire PRIVMSG in
185f0f93429SDag-Erling Smørgrav 	 * each packet.
186f0f93429SDag-Erling Smørgrav 	 */
187ed01a582SDag-Erling Smørgrav 	if (dlen < (int)sizeof(":A!a@n.n PRIVMSG A :aDCC 1 1a") - 1)
1883b160b8bSBrian Somers 		return;
1893b160b8bSBrian Somers 
1903b160b8bSBrian Somers 	/* Place string pointer at beginning of data */
1913b160b8bSBrian Somers 	sptr = (char *)pip;
1923b160b8bSBrian Somers 	sptr += hlen;
193f0f93429SDag-Erling Smørgrav 	maxsize -= hlen;	/* We're interested in maximum size of
194f0f93429SDag-Erling Smørgrav 				 * data, not packet */
1953b160b8bSBrian Somers 
1963b160b8bSBrian Somers 	/* Search for a CTCP command [Note 1] */
1973b160b8bSBrian Somers 	for (i = 0; i < dlen; i++) {
1983b160b8bSBrian Somers 		if (sptr[i] == '\001')
1993b160b8bSBrian Somers 			goto lFOUND_CTCP;
2003b160b8bSBrian Somers 	}
2013b160b8bSBrian Somers 	return;			/* No CTCP commands in  */
2023b160b8bSBrian Somers 	/* Handle CTCP commands - the buffer may have to be copied */
2033b160b8bSBrian Somers 	lFOUND_CTCP:
2043b160b8bSBrian Somers 	{
205f6efbc88SPaolo Pisati 		unsigned int copyat = i;
206ed01a582SDag-Erling Smørgrav 		unsigned int iCopy = 0;	/* How much data have we written to
207f0f93429SDag-Erling Smørgrav 					 * copy-back string? */
2083b160b8bSBrian Somers 		unsigned long org_addr;	/* Original IP address */
209f0f93429SDag-Erling Smørgrav 		unsigned short org_port;	/* Original source port
210f0f93429SDag-Erling Smørgrav 						 * address */
211f0f93429SDag-Erling Smørgrav 
2123b160b8bSBrian Somers 	lCTCP_START:
21363bea446SPaolo Pisati 		if (i >= dlen || iCopy >= PKTSIZE)
2143b160b8bSBrian Somers 			goto lPACKET_DONE;
215f0f93429SDag-Erling Smørgrav 		newpacket[iCopy++] = sptr[i++];	/* Copy the CTCP start
216f0f93429SDag-Erling Smørgrav 						 * character */
2173b160b8bSBrian Somers 		/* Start of a CTCP */
2183b160b8bSBrian Somers 		if (i + 4 >= dlen)	/* Too short for DCC */
2193b160b8bSBrian Somers 			goto lBAD_CTCP;
2203b160b8bSBrian Somers 		if (sptr[i + 0] != 'D')
2213b160b8bSBrian Somers 			goto lBAD_CTCP;
2223b160b8bSBrian Somers 		if (sptr[i + 1] != 'C')
2233b160b8bSBrian Somers 			goto lBAD_CTCP;
2243b160b8bSBrian Somers 		if (sptr[i + 2] != 'C')
2253b160b8bSBrian Somers 			goto lBAD_CTCP;
2263b160b8bSBrian Somers 		if (sptr[i + 3] != ' ')
2273b160b8bSBrian Somers 			goto lBAD_CTCP;
2283b160b8bSBrian Somers 		/* We have a DCC command - handle it! */
2293b160b8bSBrian Somers 		i += 4;		/* Skip "DCC " */
23063bea446SPaolo Pisati 		if (iCopy + 4 > PKTSIZE)
2313b160b8bSBrian Somers 			goto lPACKET_DONE;
2323b160b8bSBrian Somers 		newpacket[iCopy++] = 'D';
2333b160b8bSBrian Somers 		newpacket[iCopy++] = 'C';
2343b160b8bSBrian Somers 		newpacket[iCopy++] = 'C';
2353b160b8bSBrian Somers 		newpacket[iCopy++] = ' ';
2363b160b8bSBrian Somers 
2373b160b8bSBrian Somers 		DBprintf(("Found DCC\n"));
238f0f93429SDag-Erling Smørgrav 		/*
239f0f93429SDag-Erling Smørgrav 		 * Skip any extra spaces (should not occur according to
240f0f93429SDag-Erling Smørgrav 		 * protocol, but DCC breaks CTCP protocol anyway
241f0f93429SDag-Erling Smørgrav 		 */
2423b160b8bSBrian Somers 		while (sptr[i] == ' ') {
2433b160b8bSBrian Somers 			if (++i >= dlen) {
2443b160b8bSBrian Somers 				DBprintf(("DCC packet terminated in just spaces\n"));
2453b160b8bSBrian Somers 				goto lPACKET_DONE;
2463b160b8bSBrian Somers 			}
2473b160b8bSBrian Somers 		}
2483b160b8bSBrian Somers 
2493b160b8bSBrian Somers 		DBprintf(("Transferring command...\n"));
2503b160b8bSBrian Somers 		while (sptr[i] != ' ') {
2513b160b8bSBrian Somers 			newpacket[iCopy++] = sptr[i];
25263bea446SPaolo Pisati 			if (++i >= dlen || iCopy >= PKTSIZE) {
2533b160b8bSBrian Somers 				DBprintf(("DCC packet terminated during command\n"));
2543b160b8bSBrian Somers 				goto lPACKET_DONE;
2553b160b8bSBrian Somers 			}
2563b160b8bSBrian Somers 		}
2573b160b8bSBrian Somers 		/* Copy _one_ space */
25863bea446SPaolo Pisati 		if (i + 1 < dlen && iCopy < PKTSIZE)
2593b160b8bSBrian Somers 			newpacket[iCopy++] = sptr[i++];
2603b160b8bSBrian Somers 
2613b160b8bSBrian Somers 		DBprintf(("Done command - removing spaces\n"));
262f0f93429SDag-Erling Smørgrav 		/*
263f0f93429SDag-Erling Smørgrav 		 * Skip any extra spaces (should not occur according to
264f0f93429SDag-Erling Smørgrav 		 * protocol, but DCC breaks CTCP protocol anyway
265f0f93429SDag-Erling Smørgrav 		 */
2663b160b8bSBrian Somers 		while (sptr[i] == ' ') {
2673b160b8bSBrian Somers 			if (++i >= dlen) {
2683b160b8bSBrian Somers 				DBprintf(("DCC packet terminated in just spaces (post-command)\n"));
2693b160b8bSBrian Somers 				goto lPACKET_DONE;
2703b160b8bSBrian Somers 			}
2713b160b8bSBrian Somers 		}
2723b160b8bSBrian Somers 
2733b160b8bSBrian Somers 		DBprintf(("Transferring filename...\n"));
2743b160b8bSBrian Somers 		while (sptr[i] != ' ') {
2753b160b8bSBrian Somers 			newpacket[iCopy++] = sptr[i];
27663bea446SPaolo Pisati 			if (++i >= dlen || iCopy >= PKTSIZE) {
2773b160b8bSBrian Somers 				DBprintf(("DCC packet terminated during filename\n"));
2783b160b8bSBrian Somers 				goto lPACKET_DONE;
2793b160b8bSBrian Somers 			}
2803b160b8bSBrian Somers 		}
2813b160b8bSBrian Somers 		/* Copy _one_ space */
28263bea446SPaolo Pisati 		if (i + 1 < dlen && iCopy < PKTSIZE)
2833b160b8bSBrian Somers 			newpacket[iCopy++] = sptr[i++];
2843b160b8bSBrian Somers 
2853b160b8bSBrian Somers 		DBprintf(("Done filename - removing spaces\n"));
286f0f93429SDag-Erling Smørgrav 		/*
287f0f93429SDag-Erling Smørgrav 		 * Skip any extra spaces (should not occur according to
288f0f93429SDag-Erling Smørgrav 		 * protocol, but DCC breaks CTCP protocol anyway
289f0f93429SDag-Erling Smørgrav 		 */
2903b160b8bSBrian Somers 		while (sptr[i] == ' ') {
2913b160b8bSBrian Somers 			if (++i >= dlen) {
2923b160b8bSBrian Somers 				DBprintf(("DCC packet terminated in just spaces (post-filename)\n"));
2933b160b8bSBrian Somers 				goto lPACKET_DONE;
2943b160b8bSBrian Somers 			}
2953b160b8bSBrian Somers 		}
2963b160b8bSBrian Somers 
2973b160b8bSBrian Somers 		DBprintf(("Fetching IP address\n"));
2983b160b8bSBrian Somers 		/* Fetch IP address */
2993b160b8bSBrian Somers 		org_addr = 0;
3003b160b8bSBrian Somers 		while (i < dlen && isdigit(sptr[i])) {
3013b160b8bSBrian Somers 			if (org_addr > ULONG_MAX / 10UL) {	/* Terminate on overflow */
3023b160b8bSBrian Somers 				DBprintf(("DCC Address overflow (org_addr == 0x%08lx, next char %c\n", org_addr, sptr[i]));
3033b160b8bSBrian Somers 				goto lBAD_CTCP;
3043b160b8bSBrian Somers 			}
3053b160b8bSBrian Somers 			org_addr *= 10;
3063b160b8bSBrian Somers 			org_addr += sptr[i++] - '0';
3073b160b8bSBrian Somers 		}
3083b160b8bSBrian Somers 		DBprintf(("Skipping space\n"));
3093b160b8bSBrian Somers 		if (i + 1 >= dlen || sptr[i] != ' ') {
3103b160b8bSBrian Somers 			DBprintf(("Overflow (%d >= %d) or bad character (%02x) terminating IP address\n", i + 1, dlen, sptr[i]));
3113b160b8bSBrian Somers 			goto lBAD_CTCP;
3123b160b8bSBrian Somers 		}
313f0f93429SDag-Erling Smørgrav 		/*
314f0f93429SDag-Erling Smørgrav 		 * Skip any extra spaces (should not occur according to
315f0f93429SDag-Erling Smørgrav 		 * protocol, but DCC breaks CTCP protocol anyway, so we
316f0f93429SDag-Erling Smørgrav 		 * might as well play it safe
317f0f93429SDag-Erling Smørgrav 		 */
3183b160b8bSBrian Somers 		while (sptr[i] == ' ') {
3193b160b8bSBrian Somers 			if (++i >= dlen) {
3203b160b8bSBrian Somers 				DBprintf(("Packet failure - space overflow.\n"));
3213b160b8bSBrian Somers 				goto lPACKET_DONE;
3223b160b8bSBrian Somers 			}
3233b160b8bSBrian Somers 		}
3243b160b8bSBrian Somers 		DBprintf(("Fetching port number\n"));
3253b160b8bSBrian Somers 		/* Fetch source port */
3263b160b8bSBrian Somers 		org_port = 0;
3273b160b8bSBrian Somers 		while (i < dlen && isdigit(sptr[i])) {
328f0f93429SDag-Erling Smørgrav 			if (org_port > 6554) {	/* Terminate on overflow
329f0f93429SDag-Erling Smørgrav 						 * (65536/10 rounded up */
3303b160b8bSBrian Somers 				DBprintf(("DCC: port number overflow\n"));
3313b160b8bSBrian Somers 				goto lBAD_CTCP;
3323b160b8bSBrian Somers 			}
3333b160b8bSBrian Somers 			org_port *= 10;
3343b160b8bSBrian Somers 			org_port += sptr[i++] - '0';
3353b160b8bSBrian Somers 		}
3363b160b8bSBrian Somers 		/* Skip illegal addresses (or early termination) */
3373b160b8bSBrian Somers 		if (i >= dlen || (sptr[i] != '\001' && sptr[i] != ' ')) {
3383b160b8bSBrian Somers 			DBprintf(("Bad port termination\n"));
3393b160b8bSBrian Somers 			goto lBAD_CTCP;
3403b160b8bSBrian Somers 		}
3413b160b8bSBrian Somers 		DBprintf(("Got IP %lu and port %u\n", org_addr, (unsigned)org_port));
3423b160b8bSBrian Somers 
3433b160b8bSBrian Somers 		/* We've got the address and port - now alias it */
3443b160b8bSBrian Somers 		{
345ed01a582SDag-Erling Smørgrav 			struct alias_link *dcc_lnk;
3463b160b8bSBrian Somers 			struct in_addr destaddr;
3473b160b8bSBrian Somers 
3483b160b8bSBrian Somers 			true_port = htons(org_port);
3493b160b8bSBrian Somers 			true_addr.s_addr = htonl(org_addr);
3503b160b8bSBrian Somers 			destaddr.s_addr = 0;
3513b160b8bSBrian Somers 
35204c3e339SRuslan Ermilov 			/* Sanity/Security checking */
35304c3e339SRuslan Ermilov 			if (!org_addr || !org_port ||
35404c3e339SRuslan Ermilov 			    pip->ip_src.s_addr != true_addr.s_addr ||
35504c3e339SRuslan Ermilov 			    org_port < IPPORT_RESERVED)
35604c3e339SRuslan Ermilov 				goto lBAD_CTCP;
35704c3e339SRuslan Ermilov 
358f0f93429SDag-Erling Smørgrav 			/*
359f0f93429SDag-Erling Smørgrav 			 * Steal the FTP_DATA_PORT - it doesn't really
360f0f93429SDag-Erling Smørgrav 			 * matter, and this would probably allow it through
361f0f93429SDag-Erling Smørgrav 			 * at least _some_ firewalls.
362f0f93429SDag-Erling Smørgrav 			 */
363*fb2ea26fSMark Johnston 			(void)FindUdpTcpOut(la, true_addr, destaddr,
364642cd09fSRuslan Ermilov 			    true_port, 0,
365*fb2ea26fSMark Johnston 			    IPPROTO_TCP, 1, &dcc_lnk);
3663b160b8bSBrian Somers 			DBprintf(("Got a DCC link\n"));
367ed01a582SDag-Erling Smørgrav 			if (dcc_lnk) {
3683b160b8bSBrian Somers 				struct in_addr alias_address;	/* Address from aliasing */
369f0f93429SDag-Erling Smørgrav 				u_short alias_port;	/* Port given by
370f0f93429SDag-Erling Smørgrav 							 * aliasing */
3717806546cSBrian Somers 				int n;
3723b160b8bSBrian Somers 
373b5ce85feSBrian Somers #ifndef NO_FW_PUNCH
3748ddc51bcSEivind Eklund 				/* Generate firewall hole as appropriate */
375ed01a582SDag-Erling Smørgrav 				PunchFWHole(dcc_lnk);
376b5ce85feSBrian Somers #endif
3778ddc51bcSEivind Eklund 
378ed01a582SDag-Erling Smørgrav 				alias_address = GetAliasAddress(lnk);
3797806546cSBrian Somers 				n = snprintf(&newpacket[iCopy],
38063bea446SPaolo Pisati 				    PKTSIZE - iCopy,
3819feab75aSBrian Somers 				    "%lu ", (u_long) htonl(alias_address.s_addr));
3827806546cSBrian Somers 				if (n < 0) {
3837806546cSBrian Somers 					DBprintf(("DCC packet construct failure.\n"));
3847806546cSBrian Somers 					goto lBAD_CTCP;
3857806546cSBrian Somers 				}
38663bea446SPaolo Pisati 				if ((iCopy += n) >= PKTSIZE) {	/* Truncated/fit exactly
387f0f93429SDag-Erling Smørgrav 										 * - bad news */
3883b160b8bSBrian Somers 					DBprintf(("DCC constructed packet overflow.\n"));
3893b160b8bSBrian Somers 					goto lBAD_CTCP;
3903b160b8bSBrian Somers 				}
391ed01a582SDag-Erling Smørgrav 				alias_port = GetAliasPort(dcc_lnk);
3927806546cSBrian Somers 				n = snprintf(&newpacket[iCopy],
39363bea446SPaolo Pisati 				    PKTSIZE - iCopy,
3943b160b8bSBrian Somers 				    "%u", htons(alias_port));
3957806546cSBrian Somers 				if (n < 0) {
3967806546cSBrian Somers 					DBprintf(("DCC packet construct failure.\n"));
3977806546cSBrian Somers 					goto lBAD_CTCP;
3987806546cSBrian Somers 				}
3997806546cSBrian Somers 				iCopy += n;
400f0f93429SDag-Erling Smørgrav 				/*
401f0f93429SDag-Erling Smørgrav 				 * Done - truncated cases will be taken
402f0f93429SDag-Erling Smørgrav 				 * care of by lBAD_CTCP
403f0f93429SDag-Erling Smørgrav 				 */
4043b160b8bSBrian Somers 				DBprintf(("Aliased IP %lu and port %u\n", alias_address.s_addr, (unsigned)alias_port));
4053b160b8bSBrian Somers 			}
4063b160b8bSBrian Somers 		}
407f0f93429SDag-Erling Smørgrav 		/*
408f0f93429SDag-Erling Smørgrav 		 * An uninteresting CTCP - state entered right after '\001'
409f0f93429SDag-Erling Smørgrav 		 * has been pushed.  Also used to copy the rest of a DCC,
410f0f93429SDag-Erling Smørgrav 		 * after IP address and port has been handled
411f0f93429SDag-Erling Smørgrav 		 */
4123b160b8bSBrian Somers 		lBAD_CTCP:
41363bea446SPaolo Pisati 		for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
4143b160b8bSBrian Somers 			newpacket[iCopy] = sptr[i];	/* Copy CTCP unchanged */
4153b160b8bSBrian Somers 			if (sptr[i] == '\001') {
4163b160b8bSBrian Somers 				goto lNORMAL_TEXT;
4173b160b8bSBrian Somers 			}
4183b160b8bSBrian Somers 		}
4193b160b8bSBrian Somers 		goto lPACKET_DONE;
4203b160b8bSBrian Somers 		/* Normal text */
4213b160b8bSBrian Somers 		lNORMAL_TEXT:
42263bea446SPaolo Pisati 		for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
4233b160b8bSBrian Somers 			newpacket[iCopy] = sptr[i];	/* Copy CTCP unchanged */
4243b160b8bSBrian Somers 			if (sptr[i] == '\001') {
4253b160b8bSBrian Somers 				goto lCTCP_START;
4263b160b8bSBrian Somers 			}
4273b160b8bSBrian Somers 		}
4283b160b8bSBrian Somers 		/* Handle the end of a packet */
4293b160b8bSBrian Somers 		lPACKET_DONE:
4303b160b8bSBrian Somers 		iCopy = iCopy > maxsize - copyat ? maxsize - copyat : iCopy;
4313b160b8bSBrian Somers 		memcpy(sptr + copyat, newpacket, iCopy);
4323b160b8bSBrian Somers 
4333b160b8bSBrian Somers 		/* Save information regarding modified seq and ack numbers */
4343b160b8bSBrian Somers 		{
4353b160b8bSBrian Somers 			int delta;
4363b160b8bSBrian Somers 
437ed01a582SDag-Erling Smørgrav 			SetAckModified(lnk);
4384741f3a1SPaolo Pisati 			tc = (struct tcphdr *)ip_next(pip);
4394741f3a1SPaolo Pisati 			delta = GetDeltaSeqOut(tc->th_seq, lnk);
4404741f3a1SPaolo Pisati 			AddSeq(lnk, delta + copyat + iCopy - dlen, pip->ip_hl,
4414741f3a1SPaolo Pisati 			    pip->ip_len, tc->th_seq, tc->th_off);
4423b160b8bSBrian Somers 		}
4433b160b8bSBrian Somers 
4443b160b8bSBrian Somers 		/* Revise IP header */
4453b160b8bSBrian Somers 		{
4463b160b8bSBrian Somers 			u_short new_len;
4473b160b8bSBrian Somers 
4483b160b8bSBrian Somers 			new_len = htons(hlen + iCopy + copyat);
4493b160b8bSBrian Somers 			DifferentialChecksum(&pip->ip_sum,
4503b160b8bSBrian Somers 			    &new_len,
4513b160b8bSBrian Somers 			    &pip->ip_len,
4523b160b8bSBrian Somers 			    1);
4533b160b8bSBrian Somers 			pip->ip_len = new_len;
4543b160b8bSBrian Somers 		}
4553b160b8bSBrian Somers 
4563b160b8bSBrian Somers 		/* Compute TCP checksum for revised packet */
4573b160b8bSBrian Somers 		tc->th_sum = 0;
45859dde15eSGleb Smirnoff #ifdef _KERNEL
4590fc7bdc9SRichard Scheffenegger 		tcp_set_flags(tc, tcp_get_flags(tc) | TH_RES1);
46059dde15eSGleb Smirnoff #else
4613b160b8bSBrian Somers 		tc->th_sum = TcpChecksum(pip);
46259dde15eSGleb Smirnoff #endif
4633b160b8bSBrian Somers 		return;
4643b160b8bSBrian Somers 	}
4653b160b8bSBrian Somers }
4663b160b8bSBrian Somers 
4673b160b8bSBrian Somers /* Notes:
4683b160b8bSBrian Somers   [Note 1]
4693b160b8bSBrian Somers   The initial search will most often fail; it could be replaced with a 32-bit specific search.
4703b160b8bSBrian Somers   Such a search would be done for 32-bit unsigned value V:
4713b160b8bSBrian Somers    V ^= 0x01010101;          (Search is for null bytes)
4723b160b8bSBrian Somers    if( ((V-0x01010101)^V) & 0x80808080 ) {
4733b160b8bSBrian Somers      (found a null bytes which was a 01 byte)
4743b160b8bSBrian Somers    }
4753b160b8bSBrian Somers   To assert that the processor is 32-bits, do
4763b160b8bSBrian Somers    extern int ircdccar[32];        (32 bits)
4773b160b8bSBrian Somers    extern int ircdccar[CHAR_BIT*sizeof(unsigned int)];
4783b160b8bSBrian Somers   which will generate a type-error on all but 32-bit machines.
4793b160b8bSBrian Somers 
4803b160b8bSBrian Somers   [Note 2] This routine really ought to be replaced with one that
481a4641f4eSPedro F. Giffuni   creates a transparent proxy on the aliasing host, to allow arbitrary
4823b160b8bSBrian Somers   changes in the TCP stream.  This should not be too difficult given
4833b160b8bSBrian Somers   this base;  I (ee) will try to do this some time later.
4843b160b8bSBrian Somers */
485