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