alias_irc.c revision 162674
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 162674 2006-09-26 23:26:53Z piso $");
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
59162674Spiso#include <errno.h>
60145921Sglebius#include <sys/types.h>
6199207Sbrian#include <stdio.h>
62145921Sglebius#include <limits.h>
63145921Sglebius#endif
64145921Sglebius
6526026Sbrian#include <netinet/in_systm.h>
6626026Sbrian#include <netinet/in.h>
6726026Sbrian#include <netinet/ip.h>
6826026Sbrian#include <netinet/tcp.h>
6926026Sbrian
70145921Sglebius#ifdef _KERNEL
71145932Sglebius#include <netinet/libalias/alias.h>
72145921Sglebius#include <netinet/libalias/alias_local.h>
73162674Spiso#include <netinet/libalias/alias_mod.h>
74145921Sglebius#else
7526026Sbrian#include "alias_local.h"
76162674Spiso#include "alias_mod.h"
77145921Sglebius#endif
7826026Sbrian
79162674Spiso#define IRC_CONTROL_PORT_NUMBER_1 6667
80162674Spiso#define IRC_CONTROL_PORT_NUMBER_2 6668
81162674Spiso
8226026Sbrian/* Local defines */
8326026Sbrian#define DBprintf(a)
8426026Sbrian
85162674Spisostatic void
86162674SpisoAliasHandleIrcOut(struct libalias *, struct ip *, struct alias_link *,
87162674Spiso		  int maxpacketsize);
8826026Sbrian
89162674Spisostatic int
90162674Spisofingerprint(struct libalias *la, struct ip *pip, struct alias_data *ah)
91162674Spiso{
92162674Spiso
93162674Spiso	if (ah->dport == NULL || ah->dport == NULL || ah->lnk == NULL ||
94162674Spiso	    ah->maxpktsize == 0)
95162674Spiso		return (-1);
96162674Spiso	if (ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_1
97162674Spiso	    || ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_2)
98162674Spiso		return (0);
99162674Spiso	return (-1);
100162674Spiso}
101162674Spiso
102162674Spisostatic int
103162674Spisoprotohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
104162674Spiso{
105162674Spiso
106162674Spiso	AliasHandleIrcOut(la, pip, ah->lnk, ah->maxpktsize);
107162674Spiso	return (0);
108162674Spiso}
109162674Spiso
110162674Spisostruct proto_handler handlers[] = {
111162674Spiso	{
112162674Spiso	  .pri = 90,
113162674Spiso	  .dir = OUT,
114162674Spiso	  .proto = TCP,
115162674Spiso	  .fingerprint = &fingerprint,
116162674Spiso	  .protohandler = &protohandler
117162674Spiso	},
118162674Spiso	{ EOH }
119162674Spiso};
120162674Spiso
121162674Spisostatic int
122162674Spisomod_handler(module_t mod, int type, void *data)
123162674Spiso{
124162674Spiso	int error;
125162674Spiso
126162674Spiso	switch (type) {
127162674Spiso	case MOD_LOAD:
128162674Spiso		error = 0;
129162674Spiso		LibAliasAttachHandlers(handlers);
130162674Spiso		break;
131162674Spiso	case MOD_UNLOAD:
132162674Spiso		error = 0;
133162674Spiso		LibAliasDetachHandlers(handlers);
134162674Spiso		break;
135162674Spiso	default:
136162674Spiso		error = EINVAL;
137162674Spiso	}
138162674Spiso	return (error);
139162674Spiso}
140162674Spiso
141162674Spiso#ifdef _KERNEL
142162674Spisostatic
143162674Spiso#endif
144162674Spisomoduledata_t alias_mod = {
145162674Spiso       "alias_irc", mod_handler, NULL
146162674Spiso};
147162674Spiso
148162674Spiso/* Kernel module definition. */
149162674Spiso#ifdef	_KERNEL
150162674SpisoDECLARE_MODULE(alias_irc, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
151162674SpisoMODULE_VERSION(alias_irc, 1);
152162674SpisoMODULE_DEPEND(alias_irc, libalias, 1, 1, 1);
153162674Spiso#endif
154162674Spiso
155162674Spisostatic void
156127094SdesAliasHandleIrcOut(struct libalias *la,
157127094Sdes    struct ip *pip,		/* IP packet to examine */
158131614Sdes    struct alias_link *lnk,	/* Which link are we on? */
159127094Sdes    int maxsize			/* Maximum size of IP packet including
160127094Sdes				 * headers */
161127094Sdes)
16299207Sbrian{
163127094Sdes	int hlen, tlen, dlen;
164127094Sdes	struct in_addr true_addr;
165127094Sdes	u_short true_port;
166127094Sdes	char *sptr;
167127094Sdes	struct tcphdr *tc;
168127094Sdes	int i;			/* Iterator through the source */
16999207Sbrian
17026026Sbrian/* Calculate data length of TCP packet */
171131699Sdes	tc = (struct tcphdr *)ip_next(pip);
172127094Sdes	hlen = (pip->ip_hl + tc->th_off) << 2;
173127094Sdes	tlen = ntohs(pip->ip_len);
174127094Sdes	dlen = tlen - hlen;
17526026Sbrian
176127094Sdes	/*
177127094Sdes	 * Return if data length is too short - assume an entire PRIVMSG in
178127094Sdes	 * each packet.
179127094Sdes	 */
180131614Sdes	if (dlen < (int)sizeof(":A!a@n.n PRIVMSG A :aDCC 1 1a") - 1)
181127094Sdes		return;
18226026Sbrian
18326026Sbrian/* Place string pointer at beginning of data */
184127094Sdes	sptr = (char *)pip;
185127094Sdes	sptr += hlen;
186127094Sdes	maxsize -= hlen;	/* We're interested in maximum size of
187127094Sdes				 * data, not packet */
18826026Sbrian
189127094Sdes	/* Search for a CTCP command [Note 1] */
190127094Sdes	for (i = 0; i < dlen; i++) {
191127094Sdes		if (sptr[i] == '\001')
192127094Sdes			goto lFOUND_CTCP;
193127094Sdes	}
194127094Sdes	return;			/* No CTCP commands in  */
195127094Sdes	/* Handle CTCP commands - the buffer may have to be copied */
19626026SbrianlFOUND_CTCP:
197127094Sdes	{
198127094Sdes		char newpacket[65536];	/* Estimate of maximum packet size
199127094Sdes					 * :) */
200131614Sdes		unsigned int copyat = i;	/* Same */
201131614Sdes		unsigned int iCopy = 0;	/* How much data have we written to
202131614Sdes					 * copy-back string? */
203127094Sdes		unsigned long org_addr;	/* Original IP address */
204127094Sdes		unsigned short org_port;	/* Original source port
205127094Sdes						 * address */
20626026Sbrian
207127094SdeslCTCP_START:
208127094Sdes		if (i >= dlen || iCopy >= sizeof(newpacket))
209127094Sdes			goto lPACKET_DONE;
210127094Sdes		newpacket[iCopy++] = sptr[i++];	/* Copy the CTCP start
211127094Sdes						 * character */
212127094Sdes		/* Start of a CTCP */
213127094Sdes		if (i + 4 >= dlen)	/* Too short for DCC */
214127094Sdes			goto lBAD_CTCP;
215127094Sdes		if (sptr[i + 0] != 'D')
216127094Sdes			goto lBAD_CTCP;
217127094Sdes		if (sptr[i + 1] != 'C')
218127094Sdes			goto lBAD_CTCP;
219127094Sdes		if (sptr[i + 2] != 'C')
220127094Sdes			goto lBAD_CTCP;
221127094Sdes		if (sptr[i + 3] != ' ')
222127094Sdes			goto lBAD_CTCP;
223127094Sdes		/* We have a DCC command - handle it! */
224127094Sdes		i += 4;		/* Skip "DCC " */
225127094Sdes		if (iCopy + 4 > sizeof(newpacket))
226127094Sdes			goto lPACKET_DONE;
227127094Sdes		newpacket[iCopy++] = 'D';
228127094Sdes		newpacket[iCopy++] = 'C';
229127094Sdes		newpacket[iCopy++] = 'C';
230127094Sdes		newpacket[iCopy++] = ' ';
23126026Sbrian
232127094Sdes		DBprintf(("Found DCC\n"));
233127094Sdes		/*
234127094Sdes		 * Skip any extra spaces (should not occur according to
235127094Sdes		 * protocol, but DCC breaks CTCP protocol anyway
236127094Sdes		 */
237127094Sdes		while (sptr[i] == ' ') {
238127094Sdes			if (++i >= dlen) {
239127094Sdes				DBprintf(("DCC packet terminated in just spaces\n"));
240127094Sdes				goto lPACKET_DONE;
241127094Sdes			}
242127094Sdes		}
24326026Sbrian
244127094Sdes		DBprintf(("Transferring command...\n"));
245127094Sdes		while (sptr[i] != ' ') {
246127094Sdes			newpacket[iCopy++] = sptr[i];
247127094Sdes			if (++i >= dlen || iCopy >= sizeof(newpacket)) {
248127094Sdes				DBprintf(("DCC packet terminated during command\n"));
249127094Sdes				goto lPACKET_DONE;
250127094Sdes			}
251127094Sdes		}
252127094Sdes		/* Copy _one_ space */
253127094Sdes		if (i + 1 < dlen && iCopy < sizeof(newpacket))
254127094Sdes			newpacket[iCopy++] = sptr[i++];
25526026Sbrian
256127094Sdes		DBprintf(("Done command - removing spaces\n"));
257127094Sdes		/*
258127094Sdes		 * Skip any extra spaces (should not occur according to
259127094Sdes		 * protocol, but DCC breaks CTCP protocol anyway
260127094Sdes		 */
261127094Sdes		while (sptr[i] == ' ') {
262127094Sdes			if (++i >= dlen) {
263127094Sdes				DBprintf(("DCC packet terminated in just spaces (post-command)\n"));
264127094Sdes				goto lPACKET_DONE;
265127094Sdes			}
266127094Sdes		}
26726026Sbrian
268127094Sdes		DBprintf(("Transferring filename...\n"));
269127094Sdes		while (sptr[i] != ' ') {
270127094Sdes			newpacket[iCopy++] = sptr[i];
271127094Sdes			if (++i >= dlen || iCopy >= sizeof(newpacket)) {
272127094Sdes				DBprintf(("DCC packet terminated during filename\n"));
273127094Sdes				goto lPACKET_DONE;
274127094Sdes			}
275127094Sdes		}
276127094Sdes		/* Copy _one_ space */
277127094Sdes		if (i + 1 < dlen && iCopy < sizeof(newpacket))
278127094Sdes			newpacket[iCopy++] = sptr[i++];
27926026Sbrian
280127094Sdes		DBprintf(("Done filename - removing spaces\n"));
281127094Sdes		/*
282127094Sdes		 * Skip any extra spaces (should not occur according to
283127094Sdes		 * protocol, but DCC breaks CTCP protocol anyway
284127094Sdes		 */
285127094Sdes		while (sptr[i] == ' ') {
286127094Sdes			if (++i >= dlen) {
287127094Sdes				DBprintf(("DCC packet terminated in just spaces (post-filename)\n"));
288127094Sdes				goto lPACKET_DONE;
289127094Sdes			}
290127094Sdes		}
29126026Sbrian
292127094Sdes		DBprintf(("Fetching IP address\n"));
293127094Sdes		/* Fetch IP address */
294127094Sdes		org_addr = 0;
295127094Sdes		while (i < dlen && isdigit(sptr[i])) {
296127094Sdes			if (org_addr > ULONG_MAX / 10UL) {	/* Terminate on overflow */
297127094Sdes				DBprintf(("DCC Address overflow (org_addr == 0x%08lx, next char %c\n", org_addr, sptr[i]));
298127094Sdes				goto lBAD_CTCP;
299127094Sdes			}
300127094Sdes			org_addr *= 10;
301127094Sdes			org_addr += sptr[i++] - '0';
302127094Sdes		}
303127094Sdes		DBprintf(("Skipping space\n"));
304127094Sdes		if (i + 1 >= dlen || sptr[i] != ' ') {
305127094Sdes			DBprintf(("Overflow (%d >= %d) or bad character (%02x) terminating IP address\n", i + 1, dlen, sptr[i]));
306127094Sdes			goto lBAD_CTCP;
307127094Sdes		}
308127094Sdes		/*
309127094Sdes		 * Skip any extra spaces (should not occur according to
310127094Sdes		 * protocol, but DCC breaks CTCP protocol anyway, so we
311127094Sdes		 * might as well play it safe
312127094Sdes		 */
313127094Sdes		while (sptr[i] == ' ') {
314127094Sdes			if (++i >= dlen) {
315127094Sdes				DBprintf(("Packet failure - space overflow.\n"));
316127094Sdes				goto lPACKET_DONE;
317127094Sdes			}
318127094Sdes		}
319127094Sdes		DBprintf(("Fetching port number\n"));
320127094Sdes		/* Fetch source port */
321127094Sdes		org_port = 0;
322127094Sdes		while (i < dlen && isdigit(sptr[i])) {
323127094Sdes			if (org_port > 6554) {	/* Terminate on overflow
324127094Sdes						 * (65536/10 rounded up */
325127094Sdes				DBprintf(("DCC: port number overflow\n"));
326127094Sdes				goto lBAD_CTCP;
327127094Sdes			}
328127094Sdes			org_port *= 10;
329127094Sdes			org_port += sptr[i++] - '0';
330127094Sdes		}
331127094Sdes		/* Skip illegal addresses (or early termination) */
332127094Sdes		if (i >= dlen || (sptr[i] != '\001' && sptr[i] != ' ')) {
333127094Sdes			DBprintf(("Bad port termination\n"));
334127094Sdes			goto lBAD_CTCP;
335127094Sdes		}
336127094Sdes		DBprintf(("Got IP %lu and port %u\n", org_addr, (unsigned)org_port));
33726026Sbrian
338127094Sdes		/* We've got the address and port - now alias it */
339127094Sdes		{
340131614Sdes			struct alias_link *dcc_lnk;
341127094Sdes			struct in_addr destaddr;
34299207Sbrian
34326026Sbrian
344127094Sdes			true_port = htons(org_port);
345127094Sdes			true_addr.s_addr = htonl(org_addr);
346127094Sdes			destaddr.s_addr = 0;
34782050Sru
348127094Sdes			/* Sanity/Security checking */
349127094Sdes			if (!org_addr || !org_port ||
350127094Sdes			    pip->ip_src.s_addr != true_addr.s_addr ||
351127094Sdes			    org_port < IPPORT_RESERVED)
352127094Sdes				goto lBAD_CTCP;
35326026Sbrian
354127094Sdes			/*
355127094Sdes			 * Steal the FTP_DATA_PORT - it doesn't really
356127094Sdes			 * matter, and this would probably allow it through
357127094Sdes			 * at least _some_ firewalls.
358127094Sdes			 */
359131614Sdes			dcc_lnk = FindUdpTcpOut(la, true_addr, destaddr,
360127094Sdes			    true_port, 0,
361127094Sdes			    IPPROTO_TCP, 1);
362127094Sdes			DBprintf(("Got a DCC link\n"));
363131614Sdes			if (dcc_lnk) {
364127094Sdes				struct in_addr alias_address;	/* Address from aliasing */
365127094Sdes				u_short alias_port;	/* Port given by
366127094Sdes							 * aliasing */
367127094Sdes				int n;
368127094Sdes
36936711Sbrian#ifndef NO_FW_PUNCH
370127094Sdes				/* Generate firewall hole as appropriate */
371131614Sdes				PunchFWHole(dcc_lnk);
37236711Sbrian#endif
37332377Seivind
374131614Sdes				alias_address = GetAliasAddress(lnk);
375127094Sdes				n = snprintf(&newpacket[iCopy],
376127094Sdes				    sizeof(newpacket) - iCopy,
377127094Sdes				    "%lu ", (u_long) htonl(alias_address.s_addr));
378127094Sdes				if (n < 0) {
379127094Sdes					DBprintf(("DCC packet construct failure.\n"));
380127094Sdes					goto lBAD_CTCP;
381127094Sdes				}
382127094Sdes				if ((iCopy += n) >= sizeof(newpacket)) {	/* Truncated/fit exactly
383127094Sdes										 * - bad news */
384127094Sdes					DBprintf(("DCC constructed packet overflow.\n"));
385127094Sdes					goto lBAD_CTCP;
386127094Sdes				}
387131614Sdes				alias_port = GetAliasPort(dcc_lnk);
388127094Sdes				n = snprintf(&newpacket[iCopy],
389127094Sdes				    sizeof(newpacket) - iCopy,
390127094Sdes				    "%u", htons(alias_port));
391127094Sdes				if (n < 0) {
392127094Sdes					DBprintf(("DCC packet construct failure.\n"));
393127094Sdes					goto lBAD_CTCP;
394127094Sdes				}
395127094Sdes				iCopy += n;
396127094Sdes				/*
397127094Sdes				 * Done - truncated cases will be taken
398127094Sdes				 * care of by lBAD_CTCP
399127094Sdes				 */
400127094Sdes				DBprintf(("Aliased IP %lu and port %u\n", alias_address.s_addr, (unsigned)alias_port));
401127094Sdes			}
402127094Sdes		}
403127094Sdes		/*
404127094Sdes		 * An uninteresting CTCP - state entered right after '\001'
405127094Sdes		 * has been pushed.  Also used to copy the rest of a DCC,
406127094Sdes		 * after IP address and port has been handled
407127094Sdes		 */
408127094SdeslBAD_CTCP:
409127094Sdes		for (; i < dlen && iCopy < sizeof(newpacket); i++, iCopy++) {
410127094Sdes			newpacket[iCopy] = sptr[i];	/* Copy CTCP unchanged */
411127094Sdes			if (sptr[i] == '\001') {
412127094Sdes				goto lNORMAL_TEXT;
413127094Sdes			}
414127094Sdes		}
415127094Sdes		goto lPACKET_DONE;
416127094Sdes		/* Normal text */
417127094SdeslNORMAL_TEXT:
418127094Sdes		for (; i < dlen && iCopy < sizeof(newpacket); i++, iCopy++) {
419127094Sdes			newpacket[iCopy] = sptr[i];	/* Copy CTCP unchanged */
420127094Sdes			if (sptr[i] == '\001') {
421127094Sdes				goto lCTCP_START;
422127094Sdes			}
423127094Sdes		}
424127094Sdes		/* Handle the end of a packet */
425127094SdeslPACKET_DONE:
426127094Sdes		iCopy = iCopy > maxsize - copyat ? maxsize - copyat : iCopy;
427127094Sdes		memcpy(sptr + copyat, newpacket, iCopy);
42826026Sbrian
42926026Sbrian/* Save information regarding modified seq and ack numbers */
430127094Sdes		{
431127094Sdes			int delta;
43226026Sbrian
433131614Sdes			SetAckModified(lnk);
434131614Sdes			delta = GetDeltaSeqOut(pip, lnk);
435131614Sdes			AddSeq(pip, lnk, delta + copyat + iCopy - dlen);
436127094Sdes		}
43726026Sbrian
438127094Sdes		/* Revise IP header */
439127094Sdes		{
440127094Sdes			u_short new_len;
44199207Sbrian
442127094Sdes			new_len = htons(hlen + iCopy + copyat);
443127094Sdes			DifferentialChecksum(&pip->ip_sum,
444127094Sdes			    &new_len,
445127094Sdes			    &pip->ip_len,
446127094Sdes			    1);
447127094Sdes			pip->ip_len = new_len;
448127094Sdes		}
44926026Sbrian
450127094Sdes		/* Compute TCP checksum for revised packet */
451127094Sdes		tc->th_sum = 0;
452147623Sglebius#ifdef _KERNEL
453147623Sglebius		tc->th_x2 = 1;
454147623Sglebius#else
455127094Sdes		tc->th_sum = TcpChecksum(pip);
456147623Sglebius#endif
457127094Sdes		return;
458127094Sdes	}
45926026Sbrian}
46026026Sbrian
46126026Sbrian/* Notes:
46226026Sbrian	[Note 1]
46326026Sbrian	The initial search will most often fail; it could be replaced with a 32-bit specific search.
46426026Sbrian	Such a search would be done for 32-bit unsigned value V:
46526026Sbrian	V ^= 0x01010101;				  (Search is for null bytes)
46626026Sbrian	if( ((V-0x01010101)^V) & 0x80808080 ) {
46726026Sbrian     (found a null bytes which was a 01 byte)
46826026Sbrian	}
46926026Sbrian   To assert that the processor is 32-bits, do
47026026Sbrian   extern int ircdccar[32];        (32 bits)
47126026Sbrian   extern int ircdccar[CHAR_BIT*sizeof(unsigned int)];
47226026Sbrian   which will generate a type-error on all but 32-bit machines.
47326026Sbrian
47426026Sbrian	[Note 2] This routine really ought to be replaced with one that
47526026Sbrian	creates a transparent proxy on the aliasing host, to allow arbitary
47626026Sbrian	changes in the TCP stream.  This should not be too difficult given
47726026Sbrian	this base;  I (ee) will try to do this some time later.
47826026Sbrian	*/
479