1a9643ea8Slogwang /*-
2*22ce4affSfengbojiang  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*22ce4affSfengbojiang  *
4a9643ea8Slogwang  * Copyright (c) 2001 Charles Mott <[email protected]>
5a9643ea8Slogwang  * All rights reserved.
6a9643ea8Slogwang  *
7a9643ea8Slogwang  * Redistribution and use in source and binary forms, with or without
8a9643ea8Slogwang  * modification, are permitted provided that the following conditions
9a9643ea8Slogwang  * are met:
10a9643ea8Slogwang  * 1. Redistributions of source code must retain the above copyright
11a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer.
12a9643ea8Slogwang  * 2. Redistributions in binary form must reproduce the above copyright
13a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer in the
14a9643ea8Slogwang  *    documentation and/or other materials provided with the distribution.
15a9643ea8Slogwang  *
16a9643ea8Slogwang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17a9643ea8Slogwang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18a9643ea8Slogwang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19a9643ea8Slogwang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20a9643ea8Slogwang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21a9643ea8Slogwang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22a9643ea8Slogwang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23a9643ea8Slogwang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24a9643ea8Slogwang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25a9643ea8Slogwang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26a9643ea8Slogwang  * SUCH DAMAGE.
27a9643ea8Slogwang  */
28a9643ea8Slogwang 
29a9643ea8Slogwang #include <sys/cdefs.h>
30a9643ea8Slogwang __FBSDID("$FreeBSD$");
31a9643ea8Slogwang 
32a9643ea8Slogwang /* Alias_irc.c intercepts packages contain IRC CTCP commands, and
33a9643ea8Slogwang 	changes DCC commands to export a port on the aliasing host instead
34a9643ea8Slogwang 	of an aliased host.
35a9643ea8Slogwang 
36a9643ea8Slogwang     For this routine to work, the DCC command must fit entirely into a
37a9643ea8Slogwang     single TCP packet.  This will usually happen, but is not
38a9643ea8Slogwang     guaranteed.
39a9643ea8Slogwang 
40a9643ea8Slogwang 	 The interception is likely to change the length of the packet.
41a9643ea8Slogwang 	 The handling of this is copied more-or-less verbatim from
42a9643ea8Slogwang 	 ftp_alias.c
43a9643ea8Slogwang 
44a9643ea8Slogwang 	 Initial version: Eivind Eklund <[email protected]> (ee) 97-01-29
45a9643ea8Slogwang 
46a9643ea8Slogwang 	 Version 2.1:  May, 1997 (cjm)
47a9643ea8Slogwang 	     Very minor changes to conform with
48a9643ea8Slogwang 	     local/global/function naming conventions
49a9643ea8Slogwang 	     within the packet alising module.
50a9643ea8Slogwang */
51a9643ea8Slogwang 
52a9643ea8Slogwang /* Includes */
53a9643ea8Slogwang #ifdef _KERNEL
54a9643ea8Slogwang #include <sys/param.h>
55a9643ea8Slogwang #include <sys/ctype.h>
56a9643ea8Slogwang #include <sys/limits.h>
57a9643ea8Slogwang #include <sys/systm.h>
58a9643ea8Slogwang #include <sys/kernel.h>
59a9643ea8Slogwang #include <sys/module.h>
60a9643ea8Slogwang #else
61a9643ea8Slogwang #include <ctype.h>
62a9643ea8Slogwang #include <errno.h>
63a9643ea8Slogwang #include <sys/types.h>
64a9643ea8Slogwang #include <stdio.h>
65a9643ea8Slogwang #include <stdlib.h>
66a9643ea8Slogwang #include <string.h>
67a9643ea8Slogwang #include <limits.h>
68a9643ea8Slogwang #endif
69a9643ea8Slogwang 
70a9643ea8Slogwang #include <netinet/in_systm.h>
71a9643ea8Slogwang #include <netinet/in.h>
72a9643ea8Slogwang #include <netinet/ip.h>
73a9643ea8Slogwang #include <netinet/tcp.h>
74a9643ea8Slogwang 
75a9643ea8Slogwang #ifdef _KERNEL
76a9643ea8Slogwang #include <netinet/libalias/alias.h>
77a9643ea8Slogwang #include <netinet/libalias/alias_local.h>
78a9643ea8Slogwang #include <netinet/libalias/alias_mod.h>
79a9643ea8Slogwang #else
80a9643ea8Slogwang #include "alias_local.h"
81a9643ea8Slogwang #include "alias_mod.h"
82a9643ea8Slogwang #endif
83a9643ea8Slogwang 
84a9643ea8Slogwang #define IRC_CONTROL_PORT_NUMBER_1 6667
85a9643ea8Slogwang #define IRC_CONTROL_PORT_NUMBER_2 6668
86a9643ea8Slogwang 
87a9643ea8Slogwang #define PKTSIZE (IP_MAXPACKET + 1)
88a9643ea8Slogwang char *newpacket;
89a9643ea8Slogwang 
90a9643ea8Slogwang /* Local defines */
91a9643ea8Slogwang #define DBprintf(a)
92a9643ea8Slogwang 
93a9643ea8Slogwang static void
94a9643ea8Slogwang AliasHandleIrcOut(struct libalias *, struct ip *, struct alias_link *,
95a9643ea8Slogwang 		  int maxpacketsize);
96a9643ea8Slogwang 
97a9643ea8Slogwang static int
fingerprint(struct libalias * la,struct alias_data * ah)98a9643ea8Slogwang fingerprint(struct libalias *la, struct alias_data *ah)
99a9643ea8Slogwang {
100a9643ea8Slogwang 
101*22ce4affSfengbojiang 	if (ah->dport == NULL || ah->lnk == NULL || ah->maxpktsize == 0)
102a9643ea8Slogwang 		return (-1);
103a9643ea8Slogwang 	if (ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_1
104a9643ea8Slogwang 	    || ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_2)
105a9643ea8Slogwang 		return (0);
106a9643ea8Slogwang 	return (-1);
107a9643ea8Slogwang }
108a9643ea8Slogwang 
109a9643ea8Slogwang static int
protohandler(struct libalias * la,struct ip * pip,struct alias_data * ah)110a9643ea8Slogwang protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
111a9643ea8Slogwang {
112a9643ea8Slogwang 
113a9643ea8Slogwang 	newpacket = malloc(PKTSIZE);
114a9643ea8Slogwang 	if (newpacket) {
115a9643ea8Slogwang 		AliasHandleIrcOut(la, pip, ah->lnk, ah->maxpktsize);
116a9643ea8Slogwang 		free(newpacket);
117a9643ea8Slogwang 	}
118a9643ea8Slogwang 	return (0);
119a9643ea8Slogwang }
120a9643ea8Slogwang 
121a9643ea8Slogwang struct proto_handler handlers[] = {
122a9643ea8Slogwang 	{
123a9643ea8Slogwang 	  .pri = 90,
124a9643ea8Slogwang 	  .dir = OUT,
125a9643ea8Slogwang 	  .proto = TCP,
126a9643ea8Slogwang 	  .fingerprint = &fingerprint,
127a9643ea8Slogwang 	  .protohandler = &protohandler
128a9643ea8Slogwang 	},
129a9643ea8Slogwang 	{ EOH }
130a9643ea8Slogwang };
131a9643ea8Slogwang 
132a9643ea8Slogwang static int
mod_handler(module_t mod,int type,void * data)133a9643ea8Slogwang mod_handler(module_t mod, int type, void *data)
134a9643ea8Slogwang {
135a9643ea8Slogwang 	int error;
136a9643ea8Slogwang 
137a9643ea8Slogwang 	switch (type) {
138a9643ea8Slogwang 	case MOD_LOAD:
139a9643ea8Slogwang 		error = 0;
140a9643ea8Slogwang 		LibAliasAttachHandlers(handlers);
141a9643ea8Slogwang 		break;
142a9643ea8Slogwang 	case MOD_UNLOAD:
143a9643ea8Slogwang 		error = 0;
144a9643ea8Slogwang 		LibAliasDetachHandlers(handlers);
145a9643ea8Slogwang 		break;
146a9643ea8Slogwang 	default:
147a9643ea8Slogwang 		error = EINVAL;
148a9643ea8Slogwang 	}
149a9643ea8Slogwang 	return (error);
150a9643ea8Slogwang }
151a9643ea8Slogwang 
152a9643ea8Slogwang #ifdef _KERNEL
153a9643ea8Slogwang static
154a9643ea8Slogwang #endif
155a9643ea8Slogwang moduledata_t alias_mod = {
156a9643ea8Slogwang        "alias_irc", mod_handler, NULL
157a9643ea8Slogwang };
158a9643ea8Slogwang 
159a9643ea8Slogwang /* Kernel module definition. */
160a9643ea8Slogwang #ifdef	_KERNEL
161a9643ea8Slogwang DECLARE_MODULE(alias_irc, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
162a9643ea8Slogwang MODULE_VERSION(alias_irc, 1);
163a9643ea8Slogwang MODULE_DEPEND(alias_irc, libalias, 1, 1, 1);
164a9643ea8Slogwang #endif
165a9643ea8Slogwang 
166a9643ea8Slogwang static void
AliasHandleIrcOut(struct libalias * la,struct ip * pip,struct alias_link * lnk,int maxsize)167a9643ea8Slogwang AliasHandleIrcOut(struct libalias *la,
168a9643ea8Slogwang     struct ip *pip,		/* IP packet to examine */
169a9643ea8Slogwang     struct alias_link *lnk,	/* Which link are we on? */
170a9643ea8Slogwang     int maxsize			/* Maximum size of IP packet including
171a9643ea8Slogwang 				 * headers */
172a9643ea8Slogwang )
173a9643ea8Slogwang {
174a9643ea8Slogwang 	int hlen, tlen, dlen;
175a9643ea8Slogwang 	struct in_addr true_addr;
176a9643ea8Slogwang 	u_short true_port;
177a9643ea8Slogwang 	char *sptr;
178a9643ea8Slogwang 	struct tcphdr *tc;
179a9643ea8Slogwang 	int i;			/* Iterator through the source */
180a9643ea8Slogwang 
181a9643ea8Slogwang /* Calculate data length of TCP packet */
182a9643ea8Slogwang 	tc = (struct tcphdr *)ip_next(pip);
183a9643ea8Slogwang 	hlen = (pip->ip_hl + tc->th_off) << 2;
184a9643ea8Slogwang 	tlen = ntohs(pip->ip_len);
185a9643ea8Slogwang 	dlen = tlen - hlen;
186a9643ea8Slogwang 
187a9643ea8Slogwang 	/*
188a9643ea8Slogwang 	 * Return if data length is too short - assume an entire PRIVMSG in
189a9643ea8Slogwang 	 * each packet.
190a9643ea8Slogwang 	 */
191a9643ea8Slogwang 	if (dlen < (int)sizeof(":[email protected] PRIVMSG A :aDCC 1 1a") - 1)
192a9643ea8Slogwang 		return;
193a9643ea8Slogwang 
194a9643ea8Slogwang /* Place string pointer at beginning of data */
195a9643ea8Slogwang 	sptr = (char *)pip;
196a9643ea8Slogwang 	sptr += hlen;
197a9643ea8Slogwang 	maxsize -= hlen;	/* We're interested in maximum size of
198a9643ea8Slogwang 				 * data, not packet */
199a9643ea8Slogwang 
200a9643ea8Slogwang 	/* Search for a CTCP command [Note 1] */
201a9643ea8Slogwang 	for (i = 0; i < dlen; i++) {
202a9643ea8Slogwang 		if (sptr[i] == '\001')
203a9643ea8Slogwang 			goto lFOUND_CTCP;
204a9643ea8Slogwang 	}
205a9643ea8Slogwang 	return;			/* No CTCP commands in  */
206a9643ea8Slogwang 	/* Handle CTCP commands - the buffer may have to be copied */
207a9643ea8Slogwang lFOUND_CTCP:
208a9643ea8Slogwang 	{
209a9643ea8Slogwang 		unsigned int copyat = i;
210a9643ea8Slogwang 		unsigned int iCopy = 0;	/* How much data have we written to
211a9643ea8Slogwang 					 * copy-back string? */
212a9643ea8Slogwang 		unsigned long org_addr;	/* Original IP address */
213a9643ea8Slogwang 		unsigned short org_port;	/* Original source port
214a9643ea8Slogwang 						 * address */
215a9643ea8Slogwang 
216a9643ea8Slogwang lCTCP_START:
217a9643ea8Slogwang 		if (i >= dlen || iCopy >= PKTSIZE)
218a9643ea8Slogwang 			goto lPACKET_DONE;
219a9643ea8Slogwang 		newpacket[iCopy++] = sptr[i++];	/* Copy the CTCP start
220a9643ea8Slogwang 						 * character */
221a9643ea8Slogwang 		/* Start of a CTCP */
222a9643ea8Slogwang 		if (i + 4 >= dlen)	/* Too short for DCC */
223a9643ea8Slogwang 			goto lBAD_CTCP;
224a9643ea8Slogwang 		if (sptr[i + 0] != 'D')
225a9643ea8Slogwang 			goto lBAD_CTCP;
226a9643ea8Slogwang 		if (sptr[i + 1] != 'C')
227a9643ea8Slogwang 			goto lBAD_CTCP;
228a9643ea8Slogwang 		if (sptr[i + 2] != 'C')
229a9643ea8Slogwang 			goto lBAD_CTCP;
230a9643ea8Slogwang 		if (sptr[i + 3] != ' ')
231a9643ea8Slogwang 			goto lBAD_CTCP;
232a9643ea8Slogwang 		/* We have a DCC command - handle it! */
233a9643ea8Slogwang 		i += 4;		/* Skip "DCC " */
234a9643ea8Slogwang 		if (iCopy + 4 > PKTSIZE)
235a9643ea8Slogwang 			goto lPACKET_DONE;
236a9643ea8Slogwang 		newpacket[iCopy++] = 'D';
237a9643ea8Slogwang 		newpacket[iCopy++] = 'C';
238a9643ea8Slogwang 		newpacket[iCopy++] = 'C';
239a9643ea8Slogwang 		newpacket[iCopy++] = ' ';
240a9643ea8Slogwang 
241a9643ea8Slogwang 		DBprintf(("Found DCC\n"));
242a9643ea8Slogwang 		/*
243a9643ea8Slogwang 		 * Skip any extra spaces (should not occur according to
244a9643ea8Slogwang 		 * protocol, but DCC breaks CTCP protocol anyway
245a9643ea8Slogwang 		 */
246a9643ea8Slogwang 		while (sptr[i] == ' ') {
247a9643ea8Slogwang 			if (++i >= dlen) {
248a9643ea8Slogwang 				DBprintf(("DCC packet terminated in just spaces\n"));
249a9643ea8Slogwang 				goto lPACKET_DONE;
250a9643ea8Slogwang 			}
251a9643ea8Slogwang 		}
252a9643ea8Slogwang 
253a9643ea8Slogwang 		DBprintf(("Transferring command...\n"));
254a9643ea8Slogwang 		while (sptr[i] != ' ') {
255a9643ea8Slogwang 			newpacket[iCopy++] = sptr[i];
256a9643ea8Slogwang 			if (++i >= dlen || iCopy >= PKTSIZE) {
257a9643ea8Slogwang 				DBprintf(("DCC packet terminated during command\n"));
258a9643ea8Slogwang 				goto lPACKET_DONE;
259a9643ea8Slogwang 			}
260a9643ea8Slogwang 		}
261a9643ea8Slogwang 		/* Copy _one_ space */
262a9643ea8Slogwang 		if (i + 1 < dlen && iCopy < PKTSIZE)
263a9643ea8Slogwang 			newpacket[iCopy++] = sptr[i++];
264a9643ea8Slogwang 
265a9643ea8Slogwang 		DBprintf(("Done command - removing spaces\n"));
266a9643ea8Slogwang 		/*
267a9643ea8Slogwang 		 * Skip any extra spaces (should not occur according to
268a9643ea8Slogwang 		 * protocol, but DCC breaks CTCP protocol anyway
269a9643ea8Slogwang 		 */
270a9643ea8Slogwang 		while (sptr[i] == ' ') {
271a9643ea8Slogwang 			if (++i >= dlen) {
272a9643ea8Slogwang 				DBprintf(("DCC packet terminated in just spaces (post-command)\n"));
273a9643ea8Slogwang 				goto lPACKET_DONE;
274a9643ea8Slogwang 			}
275a9643ea8Slogwang 		}
276a9643ea8Slogwang 
277a9643ea8Slogwang 		DBprintf(("Transferring filename...\n"));
278a9643ea8Slogwang 		while (sptr[i] != ' ') {
279a9643ea8Slogwang 			newpacket[iCopy++] = sptr[i];
280a9643ea8Slogwang 			if (++i >= dlen || iCopy >= PKTSIZE) {
281a9643ea8Slogwang 				DBprintf(("DCC packet terminated during filename\n"));
282a9643ea8Slogwang 				goto lPACKET_DONE;
283a9643ea8Slogwang 			}
284a9643ea8Slogwang 		}
285a9643ea8Slogwang 		/* Copy _one_ space */
286a9643ea8Slogwang 		if (i + 1 < dlen && iCopy < PKTSIZE)
287a9643ea8Slogwang 			newpacket[iCopy++] = sptr[i++];
288a9643ea8Slogwang 
289a9643ea8Slogwang 		DBprintf(("Done filename - removing spaces\n"));
290a9643ea8Slogwang 		/*
291a9643ea8Slogwang 		 * Skip any extra spaces (should not occur according to
292a9643ea8Slogwang 		 * protocol, but DCC breaks CTCP protocol anyway
293a9643ea8Slogwang 		 */
294a9643ea8Slogwang 		while (sptr[i] == ' ') {
295a9643ea8Slogwang 			if (++i >= dlen) {
296a9643ea8Slogwang 				DBprintf(("DCC packet terminated in just spaces (post-filename)\n"));
297a9643ea8Slogwang 				goto lPACKET_DONE;
298a9643ea8Slogwang 			}
299a9643ea8Slogwang 		}
300a9643ea8Slogwang 
301a9643ea8Slogwang 		DBprintf(("Fetching IP address\n"));
302a9643ea8Slogwang 		/* Fetch IP address */
303a9643ea8Slogwang 		org_addr = 0;
304a9643ea8Slogwang 		while (i < dlen && isdigit(sptr[i])) {
305a9643ea8Slogwang 			if (org_addr > ULONG_MAX / 10UL) {	/* Terminate on overflow */
306a9643ea8Slogwang 				DBprintf(("DCC Address overflow (org_addr == 0x%08lx, next char %c\n", org_addr, sptr[i]));
307a9643ea8Slogwang 				goto lBAD_CTCP;
308a9643ea8Slogwang 			}
309a9643ea8Slogwang 			org_addr *= 10;
310a9643ea8Slogwang 			org_addr += sptr[i++] - '0';
311a9643ea8Slogwang 		}
312a9643ea8Slogwang 		DBprintf(("Skipping space\n"));
313a9643ea8Slogwang 		if (i + 1 >= dlen || sptr[i] != ' ') {
314a9643ea8Slogwang 			DBprintf(("Overflow (%d >= %d) or bad character (%02x) terminating IP address\n", i + 1, dlen, sptr[i]));
315a9643ea8Slogwang 			goto lBAD_CTCP;
316a9643ea8Slogwang 		}
317a9643ea8Slogwang 		/*
318a9643ea8Slogwang 		 * Skip any extra spaces (should not occur according to
319a9643ea8Slogwang 		 * protocol, but DCC breaks CTCP protocol anyway, so we
320a9643ea8Slogwang 		 * might as well play it safe
321a9643ea8Slogwang 		 */
322a9643ea8Slogwang 		while (sptr[i] == ' ') {
323a9643ea8Slogwang 			if (++i >= dlen) {
324a9643ea8Slogwang 				DBprintf(("Packet failure - space overflow.\n"));
325a9643ea8Slogwang 				goto lPACKET_DONE;
326a9643ea8Slogwang 			}
327a9643ea8Slogwang 		}
328a9643ea8Slogwang 		DBprintf(("Fetching port number\n"));
329a9643ea8Slogwang 		/* Fetch source port */
330a9643ea8Slogwang 		org_port = 0;
331a9643ea8Slogwang 		while (i < dlen && isdigit(sptr[i])) {
332a9643ea8Slogwang 			if (org_port > 6554) {	/* Terminate on overflow
333a9643ea8Slogwang 						 * (65536/10 rounded up */
334a9643ea8Slogwang 				DBprintf(("DCC: port number overflow\n"));
335a9643ea8Slogwang 				goto lBAD_CTCP;
336a9643ea8Slogwang 			}
337a9643ea8Slogwang 			org_port *= 10;
338a9643ea8Slogwang 			org_port += sptr[i++] - '0';
339a9643ea8Slogwang 		}
340a9643ea8Slogwang 		/* Skip illegal addresses (or early termination) */
341a9643ea8Slogwang 		if (i >= dlen || (sptr[i] != '\001' && sptr[i] != ' ')) {
342a9643ea8Slogwang 			DBprintf(("Bad port termination\n"));
343a9643ea8Slogwang 			goto lBAD_CTCP;
344a9643ea8Slogwang 		}
345a9643ea8Slogwang 		DBprintf(("Got IP %lu and port %u\n", org_addr, (unsigned)org_port));
346a9643ea8Slogwang 
347a9643ea8Slogwang 		/* We've got the address and port - now alias it */
348a9643ea8Slogwang 		{
349a9643ea8Slogwang 			struct alias_link *dcc_lnk;
350a9643ea8Slogwang 			struct in_addr destaddr;
351a9643ea8Slogwang 
352a9643ea8Slogwang 			true_port = htons(org_port);
353a9643ea8Slogwang 			true_addr.s_addr = htonl(org_addr);
354a9643ea8Slogwang 			destaddr.s_addr = 0;
355a9643ea8Slogwang 
356a9643ea8Slogwang 			/* Sanity/Security checking */
357a9643ea8Slogwang 			if (!org_addr || !org_port ||
358a9643ea8Slogwang 			    pip->ip_src.s_addr != true_addr.s_addr ||
359a9643ea8Slogwang 			    org_port < IPPORT_RESERVED)
360a9643ea8Slogwang 				goto lBAD_CTCP;
361a9643ea8Slogwang 
362a9643ea8Slogwang 			/*
363a9643ea8Slogwang 			 * Steal the FTP_DATA_PORT - it doesn't really
364a9643ea8Slogwang 			 * matter, and this would probably allow it through
365a9643ea8Slogwang 			 * at least _some_ firewalls.
366a9643ea8Slogwang 			 */
367a9643ea8Slogwang 			dcc_lnk = FindUdpTcpOut(la, true_addr, destaddr,
368a9643ea8Slogwang 			    true_port, 0,
369a9643ea8Slogwang 			    IPPROTO_TCP, 1);
370a9643ea8Slogwang 			DBprintf(("Got a DCC link\n"));
371a9643ea8Slogwang 			if (dcc_lnk) {
372a9643ea8Slogwang 				struct in_addr alias_address;	/* Address from aliasing */
373a9643ea8Slogwang 				u_short alias_port;	/* Port given by
374a9643ea8Slogwang 							 * aliasing */
375a9643ea8Slogwang 				int n;
376a9643ea8Slogwang 
377a9643ea8Slogwang #ifndef NO_FW_PUNCH
378a9643ea8Slogwang 				/* Generate firewall hole as appropriate */
379a9643ea8Slogwang 				PunchFWHole(dcc_lnk);
380a9643ea8Slogwang #endif
381a9643ea8Slogwang 
382a9643ea8Slogwang 				alias_address = GetAliasAddress(lnk);
383a9643ea8Slogwang 				n = snprintf(&newpacket[iCopy],
384a9643ea8Slogwang 				    PKTSIZE - iCopy,
385a9643ea8Slogwang 				    "%lu ", (u_long) htonl(alias_address.s_addr));
386a9643ea8Slogwang 				if (n < 0) {
387a9643ea8Slogwang 					DBprintf(("DCC packet construct failure.\n"));
388a9643ea8Slogwang 					goto lBAD_CTCP;
389a9643ea8Slogwang 				}
390a9643ea8Slogwang 				if ((iCopy += n) >= PKTSIZE) {	/* Truncated/fit exactly
391a9643ea8Slogwang 										 * - bad news */
392a9643ea8Slogwang 					DBprintf(("DCC constructed packet overflow.\n"));
393a9643ea8Slogwang 					goto lBAD_CTCP;
394a9643ea8Slogwang 				}
395a9643ea8Slogwang 				alias_port = GetAliasPort(dcc_lnk);
396a9643ea8Slogwang 				n = snprintf(&newpacket[iCopy],
397a9643ea8Slogwang 				    PKTSIZE - iCopy,
398a9643ea8Slogwang 				    "%u", htons(alias_port));
399a9643ea8Slogwang 				if (n < 0) {
400a9643ea8Slogwang 					DBprintf(("DCC packet construct failure.\n"));
401a9643ea8Slogwang 					goto lBAD_CTCP;
402a9643ea8Slogwang 				}
403a9643ea8Slogwang 				iCopy += n;
404a9643ea8Slogwang 				/*
405a9643ea8Slogwang 				 * Done - truncated cases will be taken
406a9643ea8Slogwang 				 * care of by lBAD_CTCP
407a9643ea8Slogwang 				 */
408a9643ea8Slogwang 				DBprintf(("Aliased IP %lu and port %u\n", alias_address.s_addr, (unsigned)alias_port));
409a9643ea8Slogwang 			}
410a9643ea8Slogwang 		}
411a9643ea8Slogwang 		/*
412a9643ea8Slogwang 		 * An uninteresting CTCP - state entered right after '\001'
413a9643ea8Slogwang 		 * has been pushed.  Also used to copy the rest of a DCC,
414a9643ea8Slogwang 		 * after IP address and port has been handled
415a9643ea8Slogwang 		 */
416a9643ea8Slogwang lBAD_CTCP:
417a9643ea8Slogwang 		for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
418a9643ea8Slogwang 			newpacket[iCopy] = sptr[i];	/* Copy CTCP unchanged */
419a9643ea8Slogwang 			if (sptr[i] == '\001') {
420a9643ea8Slogwang 				goto lNORMAL_TEXT;
421a9643ea8Slogwang 			}
422a9643ea8Slogwang 		}
423a9643ea8Slogwang 		goto lPACKET_DONE;
424a9643ea8Slogwang 		/* Normal text */
425a9643ea8Slogwang lNORMAL_TEXT:
426a9643ea8Slogwang 		for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
427a9643ea8Slogwang 			newpacket[iCopy] = sptr[i];	/* Copy CTCP unchanged */
428a9643ea8Slogwang 			if (sptr[i] == '\001') {
429a9643ea8Slogwang 				goto lCTCP_START;
430a9643ea8Slogwang 			}
431a9643ea8Slogwang 		}
432a9643ea8Slogwang 		/* Handle the end of a packet */
433a9643ea8Slogwang lPACKET_DONE:
434a9643ea8Slogwang 		iCopy = iCopy > maxsize - copyat ? maxsize - copyat : iCopy;
435a9643ea8Slogwang 		memcpy(sptr + copyat, newpacket, iCopy);
436a9643ea8Slogwang 
437a9643ea8Slogwang /* Save information regarding modified seq and ack numbers */
438a9643ea8Slogwang 		{
439a9643ea8Slogwang 			int delta;
440a9643ea8Slogwang 
441a9643ea8Slogwang 			SetAckModified(lnk);
442a9643ea8Slogwang 			tc = (struct tcphdr *)ip_next(pip);
443a9643ea8Slogwang 			delta = GetDeltaSeqOut(tc->th_seq, lnk);
444a9643ea8Slogwang 			AddSeq(lnk, delta + copyat + iCopy - dlen, pip->ip_hl,
445a9643ea8Slogwang 			    pip->ip_len, tc->th_seq, tc->th_off);
446a9643ea8Slogwang 		}
447a9643ea8Slogwang 
448a9643ea8Slogwang 		/* Revise IP header */
449a9643ea8Slogwang 		{
450a9643ea8Slogwang 			u_short new_len;
451a9643ea8Slogwang 
452a9643ea8Slogwang 			new_len = htons(hlen + iCopy + copyat);
453a9643ea8Slogwang 			DifferentialChecksum(&pip->ip_sum,
454a9643ea8Slogwang 			    &new_len,
455a9643ea8Slogwang 			    &pip->ip_len,
456a9643ea8Slogwang 			    1);
457a9643ea8Slogwang 			pip->ip_len = new_len;
458a9643ea8Slogwang 		}
459a9643ea8Slogwang 
460a9643ea8Slogwang 		/* Compute TCP checksum for revised packet */
461a9643ea8Slogwang 		tc->th_sum = 0;
462a9643ea8Slogwang #ifdef _KERNEL
463a9643ea8Slogwang 		tc->th_x2 = 1;
464a9643ea8Slogwang #else
465a9643ea8Slogwang 		tc->th_sum = TcpChecksum(pip);
466a9643ea8Slogwang #endif
467a9643ea8Slogwang 		return;
468a9643ea8Slogwang 	}
469a9643ea8Slogwang }
470a9643ea8Slogwang 
471a9643ea8Slogwang /* Notes:
472a9643ea8Slogwang 	[Note 1]
473a9643ea8Slogwang 	The initial search will most often fail; it could be replaced with a 32-bit specific search.
474a9643ea8Slogwang 	Such a search would be done for 32-bit unsigned value V:
475a9643ea8Slogwang 	V ^= 0x01010101;				  (Search is for null bytes)
476a9643ea8Slogwang 	if( ((V-0x01010101)^V) & 0x80808080 ) {
477a9643ea8Slogwang      (found a null bytes which was a 01 byte)
478a9643ea8Slogwang 	}
479a9643ea8Slogwang    To assert that the processor is 32-bits, do
480a9643ea8Slogwang    extern int ircdccar[32];        (32 bits)
481a9643ea8Slogwang    extern int ircdccar[CHAR_BIT*sizeof(unsigned int)];
482a9643ea8Slogwang    which will generate a type-error on all but 32-bit machines.
483a9643ea8Slogwang 
484a9643ea8Slogwang 	[Note 2] This routine really ought to be replaced with one that
485a9643ea8Slogwang 	creates a transparent proxy on the aliasing host, to allow arbitrary
486a9643ea8Slogwang 	changes in the TCP stream.  This should not be too difficult given
487a9643ea8Slogwang 	this base;  I (ee) will try to do this some time later.
488a9643ea8Slogwang 	*/
489