alias_irc.c revision 259858
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: head/sys/netinet/libalias/alias_irc.c 259858 2013-12-25 02:06:57Z glebius $");
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
47131612Sdes	     withing 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
99259858Sglebius	if (ah->dport == NULL || ah->dport == NULL || ah->lnk == NULL ||
100162674Spiso	    ah->maxpktsize == 0)
101162674Spiso		return (-1);
102162674Spiso	if (ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_1
103162674Spiso	    || ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_2)
104162674Spiso		return (0);
105162674Spiso	return (-1);
106162674Spiso}
107162674Spiso
108259858Sglebiusstatic int
109162674Spisoprotohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
110162674Spiso{
111177323Spiso
112177382Spiso	newpacket = malloc(PKTSIZE);
113177323Spiso	if (newpacket) {
114177323Spiso		AliasHandleIrcOut(la, pip, ah->lnk, ah->maxpktsize);
115177323Spiso		free(newpacket);
116177323Spiso	}
117162674Spiso	return (0);
118162674Spiso}
119162674Spiso
120162674Spisostruct proto_handler handlers[] = {
121259858Sglebius	{
122259858Sglebius	  .pri = 90,
123259858Sglebius	  .dir = OUT,
124259858Sglebius	  .proto = TCP,
125259858Sglebius	  .fingerprint = &fingerprint,
126162674Spiso	  .protohandler = &protohandler
127259858Sglebius	},
128162674Spiso	{ EOH }
129162674Spiso};
130162674Spiso
131162674Spisostatic int
132162674Spisomod_handler(module_t mod, int type, void *data)
133162674Spiso{
134162674Spiso	int error;
135162674Spiso
136162674Spiso	switch (type) {
137162674Spiso	case MOD_LOAD:
138162674Spiso		error = 0;
139162674Spiso		LibAliasAttachHandlers(handlers);
140162674Spiso		break;
141162674Spiso	case MOD_UNLOAD:
142162674Spiso		error = 0;
143162674Spiso		LibAliasDetachHandlers(handlers);
144162674Spiso		break;
145162674Spiso	default:
146162674Spiso		error = EINVAL;
147162674Spiso	}
148162674Spiso	return (error);
149162674Spiso}
150162674Spiso
151162674Spiso#ifdef _KERNEL
152259858Sglebiusstatic
153162674Spiso#endif
154162674Spisomoduledata_t alias_mod = {
155162674Spiso       "alias_irc", mod_handler, NULL
156162674Spiso};
157162674Spiso
158162674Spiso/* Kernel module definition. */
159162674Spiso#ifdef	_KERNEL
160162674SpisoDECLARE_MODULE(alias_irc, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
161162674SpisoMODULE_VERSION(alias_irc, 1);
162162674SpisoMODULE_DEPEND(alias_irc, libalias, 1, 1, 1);
163162674Spiso#endif
164162674Spiso
165162674Spisostatic void
166127094SdesAliasHandleIrcOut(struct libalias *la,
167127094Sdes    struct ip *pip,		/* IP packet to examine */
168131614Sdes    struct alias_link *lnk,	/* Which link are we on? */
169127094Sdes    int maxsize			/* Maximum size of IP packet including
170127094Sdes				 * headers */
171127094Sdes)
17299207Sbrian{
173127094Sdes	int hlen, tlen, dlen;
174127094Sdes	struct in_addr true_addr;
175127094Sdes	u_short true_port;
176127094Sdes	char *sptr;
177127094Sdes	struct tcphdr *tc;
178127094Sdes	int i;			/* Iterator through the source */
17999207Sbrian
18026026Sbrian/* Calculate data length of TCP packet */
181131699Sdes	tc = (struct tcphdr *)ip_next(pip);
182127094Sdes	hlen = (pip->ip_hl + tc->th_off) << 2;
183127094Sdes	tlen = ntohs(pip->ip_len);
184127094Sdes	dlen = tlen - hlen;
18526026Sbrian
186127094Sdes	/*
187127094Sdes	 * Return if data length is too short - assume an entire PRIVMSG in
188127094Sdes	 * each packet.
189127094Sdes	 */
190131614Sdes	if (dlen < (int)sizeof(":A!a@n.n PRIVMSG A :aDCC 1 1a") - 1)
191127094Sdes		return;
19226026Sbrian
19326026Sbrian/* Place string pointer at beginning of data */
194127094Sdes	sptr = (char *)pip;
195127094Sdes	sptr += hlen;
196127094Sdes	maxsize -= hlen;	/* We're interested in maximum size of
197127094Sdes				 * data, not packet */
19826026Sbrian
199127094Sdes	/* Search for a CTCP command [Note 1] */
200127094Sdes	for (i = 0; i < dlen; i++) {
201127094Sdes		if (sptr[i] == '\001')
202127094Sdes			goto lFOUND_CTCP;
203127094Sdes	}
204127094Sdes	return;			/* No CTCP commands in  */
205127094Sdes	/* Handle CTCP commands - the buffer may have to be copied */
20626026SbrianlFOUND_CTCP:
207127094Sdes	{
208177323Spiso		unsigned int copyat = i;
209131614Sdes		unsigned int iCopy = 0;	/* How much data have we written to
210131614Sdes					 * copy-back string? */
211127094Sdes		unsigned long org_addr;	/* Original IP address */
212127094Sdes		unsigned short org_port;	/* Original source port
213127094Sdes						 * address */
21426026Sbrian
215127094SdeslCTCP_START:
216177382Spiso		if (i >= dlen || iCopy >= PKTSIZE)
217127094Sdes			goto lPACKET_DONE;
218127094Sdes		newpacket[iCopy++] = sptr[i++];	/* Copy the CTCP start
219127094Sdes						 * character */
220127094Sdes		/* Start of a CTCP */
221127094Sdes		if (i + 4 >= dlen)	/* Too short for DCC */
222127094Sdes			goto lBAD_CTCP;
223127094Sdes		if (sptr[i + 0] != 'D')
224127094Sdes			goto lBAD_CTCP;
225127094Sdes		if (sptr[i + 1] != 'C')
226127094Sdes			goto lBAD_CTCP;
227127094Sdes		if (sptr[i + 2] != 'C')
228127094Sdes			goto lBAD_CTCP;
229127094Sdes		if (sptr[i + 3] != ' ')
230127094Sdes			goto lBAD_CTCP;
231127094Sdes		/* We have a DCC command - handle it! */
232127094Sdes		i += 4;		/* Skip "DCC " */
233177382Spiso		if (iCopy + 4 > PKTSIZE)
234127094Sdes			goto lPACKET_DONE;
235127094Sdes		newpacket[iCopy++] = 'D';
236127094Sdes		newpacket[iCopy++] = 'C';
237127094Sdes		newpacket[iCopy++] = 'C';
238127094Sdes		newpacket[iCopy++] = ' ';
23926026Sbrian
240127094Sdes		DBprintf(("Found DCC\n"));
241127094Sdes		/*
242127094Sdes		 * Skip any extra spaces (should not occur according to
243127094Sdes		 * protocol, but DCC breaks CTCP protocol anyway
244127094Sdes		 */
245127094Sdes		while (sptr[i] == ' ') {
246127094Sdes			if (++i >= dlen) {
247127094Sdes				DBprintf(("DCC packet terminated in just spaces\n"));
248127094Sdes				goto lPACKET_DONE;
249127094Sdes			}
250127094Sdes		}
25126026Sbrian
252127094Sdes		DBprintf(("Transferring command...\n"));
253127094Sdes		while (sptr[i] != ' ') {
254127094Sdes			newpacket[iCopy++] = sptr[i];
255177382Spiso			if (++i >= dlen || iCopy >= PKTSIZE) {
256127094Sdes				DBprintf(("DCC packet terminated during command\n"));
257127094Sdes				goto lPACKET_DONE;
258127094Sdes			}
259127094Sdes		}
260127094Sdes		/* Copy _one_ space */
261177382Spiso		if (i + 1 < dlen && iCopy < PKTSIZE)
262127094Sdes			newpacket[iCopy++] = sptr[i++];
26326026Sbrian
264127094Sdes		DBprintf(("Done command - removing spaces\n"));
265127094Sdes		/*
266127094Sdes		 * Skip any extra spaces (should not occur according to
267127094Sdes		 * protocol, but DCC breaks CTCP protocol anyway
268127094Sdes		 */
269127094Sdes		while (sptr[i] == ' ') {
270127094Sdes			if (++i >= dlen) {
271127094Sdes				DBprintf(("DCC packet terminated in just spaces (post-command)\n"));
272127094Sdes				goto lPACKET_DONE;
273127094Sdes			}
274127094Sdes		}
27526026Sbrian
276127094Sdes		DBprintf(("Transferring filename...\n"));
277127094Sdes		while (sptr[i] != ' ') {
278127094Sdes			newpacket[iCopy++] = sptr[i];
279177382Spiso			if (++i >= dlen || iCopy >= PKTSIZE) {
280127094Sdes				DBprintf(("DCC packet terminated during filename\n"));
281127094Sdes				goto lPACKET_DONE;
282127094Sdes			}
283127094Sdes		}
284127094Sdes		/* Copy _one_ space */
285177382Spiso		if (i + 1 < dlen && iCopy < PKTSIZE)
286127094Sdes			newpacket[iCopy++] = sptr[i++];
28726026Sbrian
288127094Sdes		DBprintf(("Done filename - removing spaces\n"));
289127094Sdes		/*
290127094Sdes		 * Skip any extra spaces (should not occur according to
291127094Sdes		 * protocol, but DCC breaks CTCP protocol anyway
292127094Sdes		 */
293127094Sdes		while (sptr[i] == ' ') {
294127094Sdes			if (++i >= dlen) {
295127094Sdes				DBprintf(("DCC packet terminated in just spaces (post-filename)\n"));
296127094Sdes				goto lPACKET_DONE;
297127094Sdes			}
298127094Sdes		}
29926026Sbrian
300127094Sdes		DBprintf(("Fetching IP address\n"));
301127094Sdes		/* Fetch IP address */
302127094Sdes		org_addr = 0;
303127094Sdes		while (i < dlen && isdigit(sptr[i])) {
304127094Sdes			if (org_addr > ULONG_MAX / 10UL) {	/* Terminate on overflow */
305127094Sdes				DBprintf(("DCC Address overflow (org_addr == 0x%08lx, next char %c\n", org_addr, sptr[i]));
306127094Sdes				goto lBAD_CTCP;
307127094Sdes			}
308127094Sdes			org_addr *= 10;
309127094Sdes			org_addr += sptr[i++] - '0';
310127094Sdes		}
311127094Sdes		DBprintf(("Skipping space\n"));
312127094Sdes		if (i + 1 >= dlen || sptr[i] != ' ') {
313127094Sdes			DBprintf(("Overflow (%d >= %d) or bad character (%02x) terminating IP address\n", i + 1, dlen, sptr[i]));
314127094Sdes			goto lBAD_CTCP;
315127094Sdes		}
316127094Sdes		/*
317127094Sdes		 * Skip any extra spaces (should not occur according to
318127094Sdes		 * protocol, but DCC breaks CTCP protocol anyway, so we
319127094Sdes		 * might as well play it safe
320127094Sdes		 */
321127094Sdes		while (sptr[i] == ' ') {
322127094Sdes			if (++i >= dlen) {
323127094Sdes				DBprintf(("Packet failure - space overflow.\n"));
324127094Sdes				goto lPACKET_DONE;
325127094Sdes			}
326127094Sdes		}
327127094Sdes		DBprintf(("Fetching port number\n"));
328127094Sdes		/* Fetch source port */
329127094Sdes		org_port = 0;
330127094Sdes		while (i < dlen && isdigit(sptr[i])) {
331127094Sdes			if (org_port > 6554) {	/* Terminate on overflow
332127094Sdes						 * (65536/10 rounded up */
333127094Sdes				DBprintf(("DCC: port number overflow\n"));
334127094Sdes				goto lBAD_CTCP;
335127094Sdes			}
336127094Sdes			org_port *= 10;
337127094Sdes			org_port += sptr[i++] - '0';
338127094Sdes		}
339127094Sdes		/* Skip illegal addresses (or early termination) */
340127094Sdes		if (i >= dlen || (sptr[i] != '\001' && sptr[i] != ' ')) {
341127094Sdes			DBprintf(("Bad port termination\n"));
342127094Sdes			goto lBAD_CTCP;
343127094Sdes		}
344127094Sdes		DBprintf(("Got IP %lu and port %u\n", org_addr, (unsigned)org_port));
34526026Sbrian
346127094Sdes		/* We've got the address and port - now alias it */
347127094Sdes		{
348131614Sdes			struct alias_link *dcc_lnk;
349127094Sdes			struct in_addr destaddr;
35099207Sbrian
35126026Sbrian
352127094Sdes			true_port = htons(org_port);
353127094Sdes			true_addr.s_addr = htonl(org_addr);
354127094Sdes			destaddr.s_addr = 0;
35582050Sru
356127094Sdes			/* Sanity/Security checking */
357127094Sdes			if (!org_addr || !org_port ||
358127094Sdes			    pip->ip_src.s_addr != true_addr.s_addr ||
359127094Sdes			    org_port < IPPORT_RESERVED)
360127094Sdes				goto lBAD_CTCP;
36126026Sbrian
362127094Sdes			/*
363127094Sdes			 * Steal the FTP_DATA_PORT - it doesn't really
364127094Sdes			 * matter, and this would probably allow it through
365127094Sdes			 * at least _some_ firewalls.
366127094Sdes			 */
367131614Sdes			dcc_lnk = FindUdpTcpOut(la, true_addr, destaddr,
368127094Sdes			    true_port, 0,
369127094Sdes			    IPPROTO_TCP, 1);
370127094Sdes			DBprintf(("Got a DCC link\n"));
371131614Sdes			if (dcc_lnk) {
372127094Sdes				struct in_addr alias_address;	/* Address from aliasing */
373127094Sdes				u_short alias_port;	/* Port given by
374127094Sdes							 * aliasing */
375127094Sdes				int n;
376127094Sdes
37736711Sbrian#ifndef NO_FW_PUNCH
378127094Sdes				/* Generate firewall hole as appropriate */
379131614Sdes				PunchFWHole(dcc_lnk);
38036711Sbrian#endif
38132377Seivind
382131614Sdes				alias_address = GetAliasAddress(lnk);
383127094Sdes				n = snprintf(&newpacket[iCopy],
384177382Spiso				    PKTSIZE - iCopy,
385127094Sdes				    "%lu ", (u_long) htonl(alias_address.s_addr));
386127094Sdes				if (n < 0) {
387127094Sdes					DBprintf(("DCC packet construct failure.\n"));
388127094Sdes					goto lBAD_CTCP;
389127094Sdes				}
390177382Spiso				if ((iCopy += n) >= PKTSIZE) {	/* Truncated/fit exactly
391127094Sdes										 * - bad news */
392127094Sdes					DBprintf(("DCC constructed packet overflow.\n"));
393127094Sdes					goto lBAD_CTCP;
394127094Sdes				}
395131614Sdes				alias_port = GetAliasPort(dcc_lnk);
396127094Sdes				n = snprintf(&newpacket[iCopy],
397177382Spiso				    PKTSIZE - iCopy,
398127094Sdes				    "%u", htons(alias_port));
399127094Sdes				if (n < 0) {
400127094Sdes					DBprintf(("DCC packet construct failure.\n"));
401127094Sdes					goto lBAD_CTCP;
402127094Sdes				}
403127094Sdes				iCopy += n;
404127094Sdes				/*
405127094Sdes				 * Done - truncated cases will be taken
406127094Sdes				 * care of by lBAD_CTCP
407127094Sdes				 */
408127094Sdes				DBprintf(("Aliased IP %lu and port %u\n", alias_address.s_addr, (unsigned)alias_port));
409127094Sdes			}
410127094Sdes		}
411127094Sdes		/*
412127094Sdes		 * An uninteresting CTCP - state entered right after '\001'
413127094Sdes		 * has been pushed.  Also used to copy the rest of a DCC,
414127094Sdes		 * after IP address and port has been handled
415127094Sdes		 */
416127094SdeslBAD_CTCP:
417177382Spiso		for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
418127094Sdes			newpacket[iCopy] = sptr[i];	/* Copy CTCP unchanged */
419127094Sdes			if (sptr[i] == '\001') {
420127094Sdes				goto lNORMAL_TEXT;
421127094Sdes			}
422127094Sdes		}
423127094Sdes		goto lPACKET_DONE;
424127094Sdes		/* Normal text */
425127094SdeslNORMAL_TEXT:
426177382Spiso		for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
427127094Sdes			newpacket[iCopy] = sptr[i];	/* Copy CTCP unchanged */
428127094Sdes			if (sptr[i] == '\001') {
429127094Sdes				goto lCTCP_START;
430127094Sdes			}
431127094Sdes		}
432127094Sdes		/* Handle the end of a packet */
433127094SdeslPACKET_DONE:
434127094Sdes		iCopy = iCopy > maxsize - copyat ? maxsize - copyat : iCopy;
435127094Sdes		memcpy(sptr + copyat, newpacket, iCopy);
43626026Sbrian
43726026Sbrian/* Save information regarding modified seq and ack numbers */
438127094Sdes		{
439127094Sdes			int delta;
44026026Sbrian
441131614Sdes			SetAckModified(lnk);
442176884Spiso			tc = (struct tcphdr *)ip_next(pip);
443176884Spiso			delta = GetDeltaSeqOut(tc->th_seq, lnk);
444176884Spiso			AddSeq(lnk, delta + copyat + iCopy - dlen, pip->ip_hl,
445176884Spiso			    pip->ip_len, tc->th_seq, tc->th_off);
446127094Sdes		}
44726026Sbrian
448127094Sdes		/* Revise IP header */
449127094Sdes		{
450127094Sdes			u_short new_len;
45199207Sbrian
452127094Sdes			new_len = htons(hlen + iCopy + copyat);
453127094Sdes			DifferentialChecksum(&pip->ip_sum,
454127094Sdes			    &new_len,
455127094Sdes			    &pip->ip_len,
456127094Sdes			    1);
457127094Sdes			pip->ip_len = new_len;
458127094Sdes		}
45926026Sbrian
460127094Sdes		/* Compute TCP checksum for revised packet */
461127094Sdes		tc->th_sum = 0;
462147623Sglebius#ifdef _KERNEL
463147623Sglebius		tc->th_x2 = 1;
464147623Sglebius#else
465127094Sdes		tc->th_sum = TcpChecksum(pip);
466147623Sglebius#endif
467127094Sdes		return;
468127094Sdes	}
46926026Sbrian}
47026026Sbrian
47126026Sbrian/* Notes:
47226026Sbrian	[Note 1]
47326026Sbrian	The initial search will most often fail; it could be replaced with a 32-bit specific search.
47426026Sbrian	Such a search would be done for 32-bit unsigned value V:
47526026Sbrian	V ^= 0x01010101;				  (Search is for null bytes)
47626026Sbrian	if( ((V-0x01010101)^V) & 0x80808080 ) {
47726026Sbrian     (found a null bytes which was a 01 byte)
47826026Sbrian	}
47926026Sbrian   To assert that the processor is 32-bits, do
48026026Sbrian   extern int ircdccar[32];        (32 bits)
48126026Sbrian   extern int ircdccar[CHAR_BIT*sizeof(unsigned int)];
48226026Sbrian   which will generate a type-error on all but 32-bit machines.
48326026Sbrian
48426026Sbrian	[Note 2] This routine really ought to be replaced with one that
48526026Sbrian	creates a transparent proxy on the aliasing host, to allow arbitary
48626026Sbrian	changes in the TCP stream.  This should not be too difficult given
48726026Sbrian	this base;  I (ee) will try to do this some time later.
48826026Sbrian	*/
489