177701Sbrian/*-
285964Sbrian * Copyright (c) 2001 Charles Mott <cm@linktel.net>
377701Sbrian * All rights reserved.
477701Sbrian *
577701Sbrian * Redistribution and use in source and binary forms, with or without
677701Sbrian * modification, are permitted provided that the following conditions
777701Sbrian * are met:
877701Sbrian * 1. Redistributions of source code must retain the above copyright
977701Sbrian *    notice, this list of conditions and the following disclaimer.
1077701Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1177701Sbrian *    notice, this list of conditions and the following disclaimer in the
1277701Sbrian *    documentation and/or other materials provided with the distribution.
1377701Sbrian *
1477701Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1577701Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1677701Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1777701Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1877701Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1977701Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2077701Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2177701Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2277701Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2377701Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2477701Sbrian * SUCH DAMAGE.
2577701Sbrian */
2677701Sbrian
2784195Sdillon#include <sys/cdefs.h>
2884195Sdillon__FBSDID("$FreeBSD: stable/11/sys/netinet/libalias/alias_irc.c 336279 2018-07-14 15:32:36Z markj $");
2984195Sdillon
3026026Sbrian/* Alias_irc.c intercepts packages contain IRC CTCP commands, and
3126026Sbrian	changes DCC commands to export a port on the aliasing host instead
3226026Sbrian	of an aliased host.
3326026Sbrian
3426026Sbrian    For this routine to work, the DCC command must fit entirely into a
3526026Sbrian    single TCP packet.  This will usually happen, but is not
3626026Sbrian    guaranteed.
3726026Sbrian
3826026Sbrian	 The interception is likely to change the length of the packet.
3926026Sbrian	 The handling of this is copied more-or-less verbatim from
4026026Sbrian	 ftp_alias.c
4126026Sbrian
4226026Sbrian	 Initial version: Eivind Eklund <perhaps@yes.no> (ee) 97-01-29
4326026Sbrian
44131612Sdes	 Version 2.1:  May, 1997 (cjm)
45131612Sdes	     Very minor changes to conform with
46131612Sdes	     local/global/function naming conventions
47298995Spfg	     within the packet alising module.
4826026Sbrian*/
4926026Sbrian
5026026Sbrian/* Includes */
51145921Sglebius#ifdef _KERNEL
52145921Sglebius#include <sys/param.h>
53145921Sglebius#include <sys/ctype.h>
54145921Sglebius#include <sys/limits.h>
55162674Spiso#include <sys/systm.h>
56162674Spiso#include <sys/kernel.h>
57162674Spiso#include <sys/module.h>
58145921Sglebius#else
59187304Spiso#include <ctype.h>
60162674Spiso#include <errno.h>
61145921Sglebius#include <sys/types.h>
6299207Sbrian#include <stdio.h>
63177323Spiso#include <stdlib.h>
64168346Skan#include <string.h>
65145921Sglebius#include <limits.h>
66145921Sglebius#endif
67145921Sglebius
6826026Sbrian#include <netinet/in_systm.h>
6926026Sbrian#include <netinet/in.h>
7026026Sbrian#include <netinet/ip.h>
7126026Sbrian#include <netinet/tcp.h>
7226026Sbrian
73145921Sglebius#ifdef _KERNEL
74145932Sglebius#include <netinet/libalias/alias.h>
75145921Sglebius#include <netinet/libalias/alias_local.h>
76162674Spiso#include <netinet/libalias/alias_mod.h>
77145921Sglebius#else
7826026Sbrian#include "alias_local.h"
79162674Spiso#include "alias_mod.h"
80145921Sglebius#endif
8126026Sbrian
82162674Spiso#define IRC_CONTROL_PORT_NUMBER_1 6667
83162674Spiso#define IRC_CONTROL_PORT_NUMBER_2 6668
84162674Spiso
85177382Spiso#define PKTSIZE (IP_MAXPACKET + 1)
86177323Spisochar *newpacket;
87177323Spiso
8826026Sbrian/* Local defines */
8926026Sbrian#define DBprintf(a)
9026026Sbrian
91162674Spisostatic void
92162674SpisoAliasHandleIrcOut(struct libalias *, struct ip *, struct alias_link *,
93162674Spiso		  int maxpacketsize);
9426026Sbrian
95259858Sglebiusstatic int
96190841Spisofingerprint(struct libalias *la, struct alias_data *ah)
97162674Spiso{
98162674Spiso
99336279Smarkj	if (ah->dport == NULL || ah->lnk == NULL || ah->maxpktsize == 0)
100162674Spiso		return (-1);
101162674Spiso	if (ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_1
102162674Spiso	    || ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_2)
103162674Spiso		return (0);
104162674Spiso	return (-1);
105162674Spiso}
106162674Spiso
107259858Sglebiusstatic int
108162674Spisoprotohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
109162674Spiso{
110177323Spiso
111177382Spiso	newpacket = malloc(PKTSIZE);
112177323Spiso	if (newpacket) {
113177323Spiso		AliasHandleIrcOut(la, pip, ah->lnk, ah->maxpktsize);
114177323Spiso		free(newpacket);
115177323Spiso	}
116162674Spiso	return (0);
117162674Spiso}
118162674Spiso
119162674Spisostruct proto_handler handlers[] = {
120259858Sglebius	{
121259858Sglebius	  .pri = 90,
122259858Sglebius	  .dir = OUT,
123259858Sglebius	  .proto = TCP,
124259858Sglebius	  .fingerprint = &fingerprint,
125162674Spiso	  .protohandler = &protohandler
126259858Sglebius	},
127162674Spiso	{ EOH }
128162674Spiso};
129162674Spiso
130162674Spisostatic int
131162674Spisomod_handler(module_t mod, int type, void *data)
132162674Spiso{
133162674Spiso	int error;
134162674Spiso
135162674Spiso	switch (type) {
136162674Spiso	case MOD_LOAD:
137162674Spiso		error = 0;
138162674Spiso		LibAliasAttachHandlers(handlers);
139162674Spiso		break;
140162674Spiso	case MOD_UNLOAD:
141162674Spiso		error = 0;
142162674Spiso		LibAliasDetachHandlers(handlers);
143162674Spiso		break;
144162674Spiso	default:
145162674Spiso		error = EINVAL;
146162674Spiso	}
147162674Spiso	return (error);
148162674Spiso}
149162674Spiso
150162674Spiso#ifdef _KERNEL
151259858Sglebiusstatic
152162674Spiso#endif
153162674Spisomoduledata_t alias_mod = {
154162674Spiso       "alias_irc", mod_handler, NULL
155162674Spiso};
156162674Spiso
157162674Spiso/* Kernel module definition. */
158162674Spiso#ifdef	_KERNEL
159162674SpisoDECLARE_MODULE(alias_irc, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
160162674SpisoMODULE_VERSION(alias_irc, 1);
161162674SpisoMODULE_DEPEND(alias_irc, libalias, 1, 1, 1);
162162674Spiso#endif
163162674Spiso
164162674Spisostatic void
165127094SdesAliasHandleIrcOut(struct libalias *la,
166127094Sdes    struct ip *pip,		/* IP packet to examine */
167131614Sdes    struct alias_link *lnk,	/* Which link are we on? */
168127094Sdes    int maxsize			/* Maximum size of IP packet including
169127094Sdes				 * headers */
170127094Sdes)
17199207Sbrian{
172127094Sdes	int hlen, tlen, dlen;
173127094Sdes	struct in_addr true_addr;
174127094Sdes	u_short true_port;
175127094Sdes	char *sptr;
176127094Sdes	struct tcphdr *tc;
177127094Sdes	int i;			/* Iterator through the source */
17899207Sbrian
17926026Sbrian/* Calculate data length of TCP packet */
180131699Sdes	tc = (struct tcphdr *)ip_next(pip);
181127094Sdes	hlen = (pip->ip_hl + tc->th_off) << 2;
182127094Sdes	tlen = ntohs(pip->ip_len);
183127094Sdes	dlen = tlen - hlen;
18426026Sbrian
185127094Sdes	/*
186127094Sdes	 * Return if data length is too short - assume an entire PRIVMSG in
187127094Sdes	 * each packet.
188127094Sdes	 */
189131614Sdes	if (dlen < (int)sizeof(":A!a@n.n PRIVMSG A :aDCC 1 1a") - 1)
190127094Sdes		return;
19126026Sbrian
19226026Sbrian/* Place string pointer at beginning of data */
193127094Sdes	sptr = (char *)pip;
194127094Sdes	sptr += hlen;
195127094Sdes	maxsize -= hlen;	/* We're interested in maximum size of
196127094Sdes				 * data, not packet */
19726026Sbrian
198127094Sdes	/* Search for a CTCP command [Note 1] */
199127094Sdes	for (i = 0; i < dlen; i++) {
200127094Sdes		if (sptr[i] == '\001')
201127094Sdes			goto lFOUND_CTCP;
202127094Sdes	}
203127094Sdes	return;			/* No CTCP commands in  */
204127094Sdes	/* Handle CTCP commands - the buffer may have to be copied */
20526026SbrianlFOUND_CTCP:
206127094Sdes	{
207177323Spiso		unsigned int copyat = i;
208131614Sdes		unsigned int iCopy = 0;	/* How much data have we written to
209131614Sdes					 * copy-back string? */
210127094Sdes		unsigned long org_addr;	/* Original IP address */
211127094Sdes		unsigned short org_port;	/* Original source port
212127094Sdes						 * address */
21326026Sbrian
214127094SdeslCTCP_START:
215177382Spiso		if (i >= dlen || iCopy >= PKTSIZE)
216127094Sdes			goto lPACKET_DONE;
217127094Sdes		newpacket[iCopy++] = sptr[i++];	/* Copy the CTCP start
218127094Sdes						 * character */
219127094Sdes		/* Start of a CTCP */
220127094Sdes		if (i + 4 >= dlen)	/* Too short for DCC */
221127094Sdes			goto lBAD_CTCP;
222127094Sdes		if (sptr[i + 0] != 'D')
223127094Sdes			goto lBAD_CTCP;
224127094Sdes		if (sptr[i + 1] != 'C')
225127094Sdes			goto lBAD_CTCP;
226127094Sdes		if (sptr[i + 2] != 'C')
227127094Sdes			goto lBAD_CTCP;
228127094Sdes		if (sptr[i + 3] != ' ')
229127094Sdes			goto lBAD_CTCP;
230127094Sdes		/* We have a DCC command - handle it! */
231127094Sdes		i += 4;		/* Skip "DCC " */
232177382Spiso		if (iCopy + 4 > PKTSIZE)
233127094Sdes			goto lPACKET_DONE;
234127094Sdes		newpacket[iCopy++] = 'D';
235127094Sdes		newpacket[iCopy++] = 'C';
236127094Sdes		newpacket[iCopy++] = 'C';
237127094Sdes		newpacket[iCopy++] = ' ';
23826026Sbrian
239127094Sdes		DBprintf(("Found DCC\n"));
240127094Sdes		/*
241127094Sdes		 * Skip any extra spaces (should not occur according to
242127094Sdes		 * protocol, but DCC breaks CTCP protocol anyway
243127094Sdes		 */
244127094Sdes		while (sptr[i] == ' ') {
245127094Sdes			if (++i >= dlen) {
246127094Sdes				DBprintf(("DCC packet terminated in just spaces\n"));
247127094Sdes				goto lPACKET_DONE;
248127094Sdes			}
249127094Sdes		}
25026026Sbrian
251127094Sdes		DBprintf(("Transferring command...\n"));
252127094Sdes		while (sptr[i] != ' ') {
253127094Sdes			newpacket[iCopy++] = sptr[i];
254177382Spiso			if (++i >= dlen || iCopy >= PKTSIZE) {
255127094Sdes				DBprintf(("DCC packet terminated during command\n"));
256127094Sdes				goto lPACKET_DONE;
257127094Sdes			}
258127094Sdes		}
259127094Sdes		/* Copy _one_ space */
260177382Spiso		if (i + 1 < dlen && iCopy < PKTSIZE)
261127094Sdes			newpacket[iCopy++] = sptr[i++];
26226026Sbrian
263127094Sdes		DBprintf(("Done command - removing spaces\n"));
264127094Sdes		/*
265127094Sdes		 * Skip any extra spaces (should not occur according to
266127094Sdes		 * protocol, but DCC breaks CTCP protocol anyway
267127094Sdes		 */
268127094Sdes		while (sptr[i] == ' ') {
269127094Sdes			if (++i >= dlen) {
270127094Sdes				DBprintf(("DCC packet terminated in just spaces (post-command)\n"));
271127094Sdes				goto lPACKET_DONE;
272127094Sdes			}
273127094Sdes		}
27426026Sbrian
275127094Sdes		DBprintf(("Transferring filename...\n"));
276127094Sdes		while (sptr[i] != ' ') {
277127094Sdes			newpacket[iCopy++] = sptr[i];
278177382Spiso			if (++i >= dlen || iCopy >= PKTSIZE) {
279127094Sdes				DBprintf(("DCC packet terminated during filename\n"));
280127094Sdes				goto lPACKET_DONE;
281127094Sdes			}
282127094Sdes		}
283127094Sdes		/* Copy _one_ space */
284177382Spiso		if (i + 1 < dlen && iCopy < PKTSIZE)
285127094Sdes			newpacket[iCopy++] = sptr[i++];
28626026Sbrian
287127094Sdes		DBprintf(("Done filename - removing spaces\n"));
288127094Sdes		/*
289127094Sdes		 * Skip any extra spaces (should not occur according to
290127094Sdes		 * protocol, but DCC breaks CTCP protocol anyway
291127094Sdes		 */
292127094Sdes		while (sptr[i] == ' ') {
293127094Sdes			if (++i >= dlen) {
294127094Sdes				DBprintf(("DCC packet terminated in just spaces (post-filename)\n"));
295127094Sdes				goto lPACKET_DONE;
296127094Sdes			}
297127094Sdes		}
29826026Sbrian
299127094Sdes		DBprintf(("Fetching IP address\n"));
300127094Sdes		/* Fetch IP address */
301127094Sdes		org_addr = 0;
302127094Sdes		while (i < dlen && isdigit(sptr[i])) {
303127094Sdes			if (org_addr > ULONG_MAX / 10UL) {	/* Terminate on overflow */
304127094Sdes				DBprintf(("DCC Address overflow (org_addr == 0x%08lx, next char %c\n", org_addr, sptr[i]));
305127094Sdes				goto lBAD_CTCP;
306127094Sdes			}
307127094Sdes			org_addr *= 10;
308127094Sdes			org_addr += sptr[i++] - '0';
309127094Sdes		}
310127094Sdes		DBprintf(("Skipping space\n"));
311127094Sdes		if (i + 1 >= dlen || sptr[i] != ' ') {
312127094Sdes			DBprintf(("Overflow (%d >= %d) or bad character (%02x) terminating IP address\n", i + 1, dlen, sptr[i]));
313127094Sdes			goto lBAD_CTCP;
314127094Sdes		}
315127094Sdes		/*
316127094Sdes		 * Skip any extra spaces (should not occur according to
317127094Sdes		 * protocol, but DCC breaks CTCP protocol anyway, so we
318127094Sdes		 * might as well play it safe
319127094Sdes		 */
320127094Sdes		while (sptr[i] == ' ') {
321127094Sdes			if (++i >= dlen) {
322127094Sdes				DBprintf(("Packet failure - space overflow.\n"));
323127094Sdes				goto lPACKET_DONE;
324127094Sdes			}
325127094Sdes		}
326127094Sdes		DBprintf(("Fetching port number\n"));
327127094Sdes		/* Fetch source port */
328127094Sdes		org_port = 0;
329127094Sdes		while (i < dlen && isdigit(sptr[i])) {
330127094Sdes			if (org_port > 6554) {	/* Terminate on overflow
331127094Sdes						 * (65536/10 rounded up */
332127094Sdes				DBprintf(("DCC: port number overflow\n"));
333127094Sdes				goto lBAD_CTCP;
334127094Sdes			}
335127094Sdes			org_port *= 10;
336127094Sdes			org_port += sptr[i++] - '0';
337127094Sdes		}
338127094Sdes		/* Skip illegal addresses (or early termination) */
339127094Sdes		if (i >= dlen || (sptr[i] != '\001' && sptr[i] != ' ')) {
340127094Sdes			DBprintf(("Bad port termination\n"));
341127094Sdes			goto lBAD_CTCP;
342127094Sdes		}
343127094Sdes		DBprintf(("Got IP %lu and port %u\n", org_addr, (unsigned)org_port));
34426026Sbrian
345127094Sdes		/* We've got the address and port - now alias it */
346127094Sdes		{
347131614Sdes			struct alias_link *dcc_lnk;
348127094Sdes			struct in_addr destaddr;
34999207Sbrian
35026026Sbrian
351127094Sdes			true_port = htons(org_port);
352127094Sdes			true_addr.s_addr = htonl(org_addr);
353127094Sdes			destaddr.s_addr = 0;
35482050Sru
355127094Sdes			/* Sanity/Security checking */
356127094Sdes			if (!org_addr || !org_port ||
357127094Sdes			    pip->ip_src.s_addr != true_addr.s_addr ||
358127094Sdes			    org_port < IPPORT_RESERVED)
359127094Sdes				goto lBAD_CTCP;
36026026Sbrian
361127094Sdes			/*
362127094Sdes			 * Steal the FTP_DATA_PORT - it doesn't really
363127094Sdes			 * matter, and this would probably allow it through
364127094Sdes			 * at least _some_ firewalls.
365127094Sdes			 */
366131614Sdes			dcc_lnk = FindUdpTcpOut(la, true_addr, destaddr,
367127094Sdes			    true_port, 0,
368127094Sdes			    IPPROTO_TCP, 1);
369127094Sdes			DBprintf(("Got a DCC link\n"));
370131614Sdes			if (dcc_lnk) {
371127094Sdes				struct in_addr alias_address;	/* Address from aliasing */
372127094Sdes				u_short alias_port;	/* Port given by
373127094Sdes							 * aliasing */
374127094Sdes				int n;
375127094Sdes
37636711Sbrian#ifndef NO_FW_PUNCH
377127094Sdes				/* Generate firewall hole as appropriate */
378131614Sdes				PunchFWHole(dcc_lnk);
37936711Sbrian#endif
38032377Seivind
381131614Sdes				alias_address = GetAliasAddress(lnk);
382127094Sdes				n = snprintf(&newpacket[iCopy],
383177382Spiso				    PKTSIZE - iCopy,
384127094Sdes				    "%lu ", (u_long) htonl(alias_address.s_addr));
385127094Sdes				if (n < 0) {
386127094Sdes					DBprintf(("DCC packet construct failure.\n"));
387127094Sdes					goto lBAD_CTCP;
388127094Sdes				}
389177382Spiso				if ((iCopy += n) >= PKTSIZE) {	/* Truncated/fit exactly
390127094Sdes										 * - bad news */
391127094Sdes					DBprintf(("DCC constructed packet overflow.\n"));
392127094Sdes					goto lBAD_CTCP;
393127094Sdes				}
394131614Sdes				alias_port = GetAliasPort(dcc_lnk);
395127094Sdes				n = snprintf(&newpacket[iCopy],
396177382Spiso				    PKTSIZE - iCopy,
397127094Sdes				    "%u", htons(alias_port));
398127094Sdes				if (n < 0) {
399127094Sdes					DBprintf(("DCC packet construct failure.\n"));
400127094Sdes					goto lBAD_CTCP;
401127094Sdes				}
402127094Sdes				iCopy += n;
403127094Sdes				/*
404127094Sdes				 * Done - truncated cases will be taken
405127094Sdes				 * care of by lBAD_CTCP
406127094Sdes				 */
407127094Sdes				DBprintf(("Aliased IP %lu and port %u\n", alias_address.s_addr, (unsigned)alias_port));
408127094Sdes			}
409127094Sdes		}
410127094Sdes		/*
411127094Sdes		 * An uninteresting CTCP - state entered right after '\001'
412127094Sdes		 * has been pushed.  Also used to copy the rest of a DCC,
413127094Sdes		 * after IP address and port has been handled
414127094Sdes		 */
415127094SdeslBAD_CTCP:
416177382Spiso		for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
417127094Sdes			newpacket[iCopy] = sptr[i];	/* Copy CTCP unchanged */
418127094Sdes			if (sptr[i] == '\001') {
419127094Sdes				goto lNORMAL_TEXT;
420127094Sdes			}
421127094Sdes		}
422127094Sdes		goto lPACKET_DONE;
423127094Sdes		/* Normal text */
424127094SdeslNORMAL_TEXT:
425177382Spiso		for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
426127094Sdes			newpacket[iCopy] = sptr[i];	/* Copy CTCP unchanged */
427127094Sdes			if (sptr[i] == '\001') {
428127094Sdes				goto lCTCP_START;
429127094Sdes			}
430127094Sdes		}
431127094Sdes		/* Handle the end of a packet */
432127094SdeslPACKET_DONE:
433127094Sdes		iCopy = iCopy > maxsize - copyat ? maxsize - copyat : iCopy;
434127094Sdes		memcpy(sptr + copyat, newpacket, iCopy);
43526026Sbrian
43626026Sbrian/* Save information regarding modified seq and ack numbers */
437127094Sdes		{
438127094Sdes			int delta;
43926026Sbrian
440131614Sdes			SetAckModified(lnk);
441176884Spiso			tc = (struct tcphdr *)ip_next(pip);
442176884Spiso			delta = GetDeltaSeqOut(tc->th_seq, lnk);
443176884Spiso			AddSeq(lnk, delta + copyat + iCopy - dlen, pip->ip_hl,
444176884Spiso			    pip->ip_len, tc->th_seq, tc->th_off);
445127094Sdes		}
44626026Sbrian
447127094Sdes		/* Revise IP header */
448127094Sdes		{
449127094Sdes			u_short new_len;
45099207Sbrian
451127094Sdes			new_len = htons(hlen + iCopy + copyat);
452127094Sdes			DifferentialChecksum(&pip->ip_sum,
453127094Sdes			    &new_len,
454127094Sdes			    &pip->ip_len,
455127094Sdes			    1);
456127094Sdes			pip->ip_len = new_len;
457127094Sdes		}
45826026Sbrian
459127094Sdes		/* Compute TCP checksum for revised packet */
460127094Sdes		tc->th_sum = 0;
461147623Sglebius#ifdef _KERNEL
462147623Sglebius		tc->th_x2 = 1;
463147623Sglebius#else
464127094Sdes		tc->th_sum = TcpChecksum(pip);
465147623Sglebius#endif
466127094Sdes		return;
467127094Sdes	}
46826026Sbrian}
46926026Sbrian
47026026Sbrian/* Notes:
47126026Sbrian	[Note 1]
47226026Sbrian	The initial search will most often fail; it could be replaced with a 32-bit specific search.
47326026Sbrian	Such a search would be done for 32-bit unsigned value V:
47426026Sbrian	V ^= 0x01010101;				  (Search is for null bytes)
47526026Sbrian	if( ((V-0x01010101)^V) & 0x80808080 ) {
47626026Sbrian     (found a null bytes which was a 01 byte)
47726026Sbrian	}
47826026Sbrian   To assert that the processor is 32-bits, do
47926026Sbrian   extern int ircdccar[32];        (32 bits)
48026026Sbrian   extern int ircdccar[CHAR_BIT*sizeof(unsigned int)];
48126026Sbrian   which will generate a type-error on all but 32-bit machines.
48226026Sbrian
48326026Sbrian	[Note 2] This routine really ought to be replaced with one that
484298995Spfg	creates a transparent proxy on the aliasing host, to allow arbitrary
48526026Sbrian	changes in the TCP stream.  This should not be too difficult given
48626026Sbrian	this base;  I (ee) will try to do this some time later.
48726026Sbrian	*/
488