1f987e1bdSBrian Somers /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
4e83aaae3SBrian Somers * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5f987e1bdSBrian Somers * All rights reserved.
6f987e1bdSBrian Somers *
7f987e1bdSBrian Somers * Redistribution and use in source and binary forms, with or without
8f987e1bdSBrian Somers * modification, are permitted provided that the following conditions
9f987e1bdSBrian Somers * are met:
10f987e1bdSBrian Somers * 1. Redistributions of source code must retain the above copyright
11f987e1bdSBrian Somers * notice, this list of conditions and the following disclaimer.
12f987e1bdSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright
13f987e1bdSBrian Somers * notice, this list of conditions and the following disclaimer in the
14f987e1bdSBrian Somers * documentation and/or other materials provided with the distribution.
15f987e1bdSBrian Somers *
16f987e1bdSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f987e1bdSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f987e1bdSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f987e1bdSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f987e1bdSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f987e1bdSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f987e1bdSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f987e1bdSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f987e1bdSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f987e1bdSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f987e1bdSBrian Somers * SUCH DAMAGE.
27f987e1bdSBrian Somers */
28f987e1bdSBrian Somers
29e2505aa6SMatthew Dillon #include <sys/cdefs.h>
303b160b8bSBrian Somers /* Alias_irc.c intercepts packages contain IRC CTCP commands, and
313b160b8bSBrian Somers changes DCC commands to export a port on the aliasing host instead
323b160b8bSBrian Somers of an aliased host.
333b160b8bSBrian Somers
343b160b8bSBrian Somers For this routine to work, the DCC command must fit entirely into a
353b160b8bSBrian Somers single TCP packet. This will usually happen, but is not
363b160b8bSBrian Somers guaranteed.
373b160b8bSBrian Somers
383b160b8bSBrian Somers The interception is likely to change the length of the packet.
393b160b8bSBrian Somers The handling of this is copied more-or-less verbatim from
403b160b8bSBrian Somers ftp_alias.c
413b160b8bSBrian Somers
423b160b8bSBrian Somers Initial version: Eivind Eklund <perhaps@yes.no> (ee) 97-01-29
433b160b8bSBrian Somers
443b160b8bSBrian Somers Version 2.1: May, 1997 (cjm)
453b160b8bSBrian Somers Very minor changes to conform with
463b160b8bSBrian Somers local/global/function naming conventions
47a4641f4eSPedro F. Giffuni within the packet alising module.
483b160b8bSBrian Somers */
493b160b8bSBrian Somers
503b160b8bSBrian Somers /* Includes */
51c649a2e0SGleb Smirnoff #ifdef _KERNEL
52c649a2e0SGleb Smirnoff #include <sys/param.h>
53c649a2e0SGleb Smirnoff #include <sys/ctype.h>
54c649a2e0SGleb Smirnoff #include <sys/limits.h>
55be4f3cd0SPaolo Pisati #include <sys/systm.h>
56be4f3cd0SPaolo Pisati #include <sys/kernel.h>
57be4f3cd0SPaolo Pisati #include <sys/module.h>
58c649a2e0SGleb Smirnoff #else
59dd14bc5dSPaolo Pisati #include <ctype.h>
60be4f3cd0SPaolo Pisati #include <errno.h>
61c649a2e0SGleb Smirnoff #include <sys/types.h>
623b160b8bSBrian Somers #include <stdio.h>
63f6efbc88SPaolo Pisati #include <stdlib.h>
64edb2e5dcSAlexander Kabaev #include <string.h>
65c649a2e0SGleb Smirnoff #include <limits.h>
66c649a2e0SGleb Smirnoff #endif
67c649a2e0SGleb Smirnoff
683b160b8bSBrian Somers #include <netinet/in_systm.h>
693b160b8bSBrian Somers #include <netinet/in.h>
703b160b8bSBrian Somers #include <netinet/ip.h>
713b160b8bSBrian Somers #include <netinet/tcp.h>
723b160b8bSBrian Somers
73c649a2e0SGleb Smirnoff #ifdef _KERNEL
74c649a2e0SGleb Smirnoff #include <netinet/libalias/alias.h>
7575bc2620SGleb Smirnoff #include <netinet/libalias/alias_local.h>
76be4f3cd0SPaolo Pisati #include <netinet/libalias/alias_mod.h>
77c649a2e0SGleb Smirnoff #else
783b160b8bSBrian Somers #include "alias_local.h"
79be4f3cd0SPaolo Pisati #include "alias_mod.h"
80c649a2e0SGleb Smirnoff #endif
813b160b8bSBrian Somers
82be4f3cd0SPaolo Pisati #define IRC_CONTROL_PORT_NUMBER_1 6667
83be4f3cd0SPaolo Pisati #define IRC_CONTROL_PORT_NUMBER_2 6668
84be4f3cd0SPaolo Pisati
8563bea446SPaolo Pisati #define PKTSIZE (IP_MAXPACKET + 1)
86f6efbc88SPaolo Pisati char *newpacket;
87f6efbc88SPaolo Pisati
883b160b8bSBrian Somers /* Local defines */
893b160b8bSBrian Somers #define DBprintf(a)
903b160b8bSBrian Somers
91be4f3cd0SPaolo Pisati static void
92be4f3cd0SPaolo Pisati AliasHandleIrcOut(struct libalias *, struct ip *, struct alias_link *,
93be4f3cd0SPaolo Pisati int maxpacketsize);
943b160b8bSBrian Somers
95be4f3cd0SPaolo Pisati static int
fingerprint(struct libalias * la,struct alias_data * ah)9643197d29SPaolo Pisati fingerprint(struct libalias *la, struct alias_data *ah)
97be4f3cd0SPaolo Pisati {
98aaf268f9SMark Johnston if (ah->dport == NULL || ah->lnk == NULL || ah->maxpktsize == 0)
99be4f3cd0SPaolo Pisati return (-1);
100be4f3cd0SPaolo Pisati if (ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_1
101be4f3cd0SPaolo Pisati || ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_2)
102be4f3cd0SPaolo Pisati return (0);
103be4f3cd0SPaolo Pisati return (-1);
104be4f3cd0SPaolo Pisati }
105be4f3cd0SPaolo Pisati
106be4f3cd0SPaolo Pisati static int
protohandler(struct libalias * la,struct ip * pip,struct alias_data * ah)107be4f3cd0SPaolo Pisati protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
108be4f3cd0SPaolo Pisati {
10963bea446SPaolo Pisati newpacket = malloc(PKTSIZE);
110f6efbc88SPaolo Pisati if (newpacket) {
111be4f3cd0SPaolo Pisati AliasHandleIrcOut(la, pip, ah->lnk, ah->maxpktsize);
112f6efbc88SPaolo Pisati free(newpacket);
113f6efbc88SPaolo Pisati }
114be4f3cd0SPaolo Pisati return (0);
115be4f3cd0SPaolo Pisati }
116be4f3cd0SPaolo Pisati
117be4f3cd0SPaolo Pisati struct proto_handler handlers[] = {
118be4f3cd0SPaolo Pisati {
119be4f3cd0SPaolo Pisati .pri = 90,
120be4f3cd0SPaolo Pisati .dir = OUT,
121be4f3cd0SPaolo Pisati .proto = TCP,
122be4f3cd0SPaolo Pisati .fingerprint = &fingerprint,
123be4f3cd0SPaolo Pisati .protohandler = &protohandler
124be4f3cd0SPaolo Pisati },
125be4f3cd0SPaolo Pisati { EOH }
126be4f3cd0SPaolo Pisati };
127be4f3cd0SPaolo Pisati
128be4f3cd0SPaolo Pisati static int
mod_handler(module_t mod,int type,void * data)129be4f3cd0SPaolo Pisati mod_handler(module_t mod, int type, void *data)
130be4f3cd0SPaolo Pisati {
131be4f3cd0SPaolo Pisati int error;
132be4f3cd0SPaolo Pisati
133be4f3cd0SPaolo Pisati switch (type) {
134be4f3cd0SPaolo Pisati case MOD_LOAD:
135be4f3cd0SPaolo Pisati error = 0;
136be4f3cd0SPaolo Pisati LibAliasAttachHandlers(handlers);
137be4f3cd0SPaolo Pisati break;
138be4f3cd0SPaolo Pisati case MOD_UNLOAD:
139be4f3cd0SPaolo Pisati error = 0;
140be4f3cd0SPaolo Pisati LibAliasDetachHandlers(handlers);
141be4f3cd0SPaolo Pisati break;
142be4f3cd0SPaolo Pisati default:
143be4f3cd0SPaolo Pisati error = EINVAL;
144be4f3cd0SPaolo Pisati }
145be4f3cd0SPaolo Pisati return (error);
146be4f3cd0SPaolo Pisati }
147be4f3cd0SPaolo Pisati
148be4f3cd0SPaolo Pisati #ifdef _KERNEL
149be4f3cd0SPaolo Pisati static
150be4f3cd0SPaolo Pisati #endif
151be4f3cd0SPaolo Pisati moduledata_t alias_mod = {
152be4f3cd0SPaolo Pisati "alias_irc", mod_handler, NULL
153be4f3cd0SPaolo Pisati };
154be4f3cd0SPaolo Pisati
155be4f3cd0SPaolo Pisati /* Kernel module definition. */
156be4f3cd0SPaolo Pisati #ifdef _KERNEL
157be4f3cd0SPaolo Pisati DECLARE_MODULE(alias_irc, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
158be4f3cd0SPaolo Pisati MODULE_VERSION(alias_irc, 1);
159be4f3cd0SPaolo Pisati MODULE_DEPEND(alias_irc, libalias, 1, 1, 1);
160be4f3cd0SPaolo Pisati #endif
161be4f3cd0SPaolo Pisati
162be4f3cd0SPaolo Pisati static void
AliasHandleIrcOut(struct libalias * la,struct ip * pip,struct alias_link * lnk,int maxsize)1635e289f9eSPoul-Henning Kamp AliasHandleIrcOut(struct libalias *la,
1645e289f9eSPoul-Henning Kamp struct ip *pip, /* IP packet to examine */
165ed01a582SDag-Erling Smørgrav struct alias_link *lnk, /* Which link are we on? */
166f0f93429SDag-Erling Smørgrav int maxsize /* Maximum size of IP packet including
167f0f93429SDag-Erling Smørgrav * headers */
1683b160b8bSBrian Somers )
1693b160b8bSBrian Somers {
1703b160b8bSBrian Somers int hlen, tlen, dlen;
1713b160b8bSBrian Somers struct in_addr true_addr;
1723b160b8bSBrian Somers u_short true_port;
1733b160b8bSBrian Somers char *sptr;
1743b160b8bSBrian Somers struct tcphdr *tc;
1753b160b8bSBrian Somers int i; /* Iterator through the source */
1763b160b8bSBrian Somers
1773b160b8bSBrian Somers /* Calculate data length of TCP packet */
1789fa0fd26SDag-Erling Smørgrav tc = (struct tcphdr *)ip_next(pip);
1793b160b8bSBrian Somers hlen = (pip->ip_hl + tc->th_off) << 2;
1803b160b8bSBrian Somers tlen = ntohs(pip->ip_len);
1813b160b8bSBrian Somers dlen = tlen - hlen;
1823b160b8bSBrian Somers
183f0f93429SDag-Erling Smørgrav /*
184f0f93429SDag-Erling Smørgrav * Return if data length is too short - assume an entire PRIVMSG in
185f0f93429SDag-Erling Smørgrav * each packet.
186f0f93429SDag-Erling Smørgrav */
187ed01a582SDag-Erling Smørgrav if (dlen < (int)sizeof(":A!a@n.n PRIVMSG A :aDCC 1 1a") - 1)
1883b160b8bSBrian Somers return;
1893b160b8bSBrian Somers
1903b160b8bSBrian Somers /* Place string pointer at beginning of data */
1913b160b8bSBrian Somers sptr = (char *)pip;
1923b160b8bSBrian Somers sptr += hlen;
193f0f93429SDag-Erling Smørgrav maxsize -= hlen; /* We're interested in maximum size of
194f0f93429SDag-Erling Smørgrav * data, not packet */
1953b160b8bSBrian Somers
1963b160b8bSBrian Somers /* Search for a CTCP command [Note 1] */
1973b160b8bSBrian Somers for (i = 0; i < dlen; i++) {
1983b160b8bSBrian Somers if (sptr[i] == '\001')
1993b160b8bSBrian Somers goto lFOUND_CTCP;
2003b160b8bSBrian Somers }
2013b160b8bSBrian Somers return; /* No CTCP commands in */
2023b160b8bSBrian Somers /* Handle CTCP commands - the buffer may have to be copied */
2033b160b8bSBrian Somers lFOUND_CTCP:
2043b160b8bSBrian Somers {
205f6efbc88SPaolo Pisati unsigned int copyat = i;
206ed01a582SDag-Erling Smørgrav unsigned int iCopy = 0; /* How much data have we written to
207f0f93429SDag-Erling Smørgrav * copy-back string? */
2083b160b8bSBrian Somers unsigned long org_addr; /* Original IP address */
209f0f93429SDag-Erling Smørgrav unsigned short org_port; /* Original source port
210f0f93429SDag-Erling Smørgrav * address */
211f0f93429SDag-Erling Smørgrav
2123b160b8bSBrian Somers lCTCP_START:
21363bea446SPaolo Pisati if (i >= dlen || iCopy >= PKTSIZE)
2143b160b8bSBrian Somers goto lPACKET_DONE;
215f0f93429SDag-Erling Smørgrav newpacket[iCopy++] = sptr[i++]; /* Copy the CTCP start
216f0f93429SDag-Erling Smørgrav * character */
2173b160b8bSBrian Somers /* Start of a CTCP */
2183b160b8bSBrian Somers if (i + 4 >= dlen) /* Too short for DCC */
2193b160b8bSBrian Somers goto lBAD_CTCP;
2203b160b8bSBrian Somers if (sptr[i + 0] != 'D')
2213b160b8bSBrian Somers goto lBAD_CTCP;
2223b160b8bSBrian Somers if (sptr[i + 1] != 'C')
2233b160b8bSBrian Somers goto lBAD_CTCP;
2243b160b8bSBrian Somers if (sptr[i + 2] != 'C')
2253b160b8bSBrian Somers goto lBAD_CTCP;
2263b160b8bSBrian Somers if (sptr[i + 3] != ' ')
2273b160b8bSBrian Somers goto lBAD_CTCP;
2283b160b8bSBrian Somers /* We have a DCC command - handle it! */
2293b160b8bSBrian Somers i += 4; /* Skip "DCC " */
23063bea446SPaolo Pisati if (iCopy + 4 > PKTSIZE)
2313b160b8bSBrian Somers goto lPACKET_DONE;
2323b160b8bSBrian Somers newpacket[iCopy++] = 'D';
2333b160b8bSBrian Somers newpacket[iCopy++] = 'C';
2343b160b8bSBrian Somers newpacket[iCopy++] = 'C';
2353b160b8bSBrian Somers newpacket[iCopy++] = ' ';
2363b160b8bSBrian Somers
2373b160b8bSBrian Somers DBprintf(("Found DCC\n"));
238f0f93429SDag-Erling Smørgrav /*
239f0f93429SDag-Erling Smørgrav * Skip any extra spaces (should not occur according to
240f0f93429SDag-Erling Smørgrav * protocol, but DCC breaks CTCP protocol anyway
241f0f93429SDag-Erling Smørgrav */
2423b160b8bSBrian Somers while (sptr[i] == ' ') {
2433b160b8bSBrian Somers if (++i >= dlen) {
2443b160b8bSBrian Somers DBprintf(("DCC packet terminated in just spaces\n"));
2453b160b8bSBrian Somers goto lPACKET_DONE;
2463b160b8bSBrian Somers }
2473b160b8bSBrian Somers }
2483b160b8bSBrian Somers
2493b160b8bSBrian Somers DBprintf(("Transferring command...\n"));
2503b160b8bSBrian Somers while (sptr[i] != ' ') {
2513b160b8bSBrian Somers newpacket[iCopy++] = sptr[i];
25263bea446SPaolo Pisati if (++i >= dlen || iCopy >= PKTSIZE) {
2533b160b8bSBrian Somers DBprintf(("DCC packet terminated during command\n"));
2543b160b8bSBrian Somers goto lPACKET_DONE;
2553b160b8bSBrian Somers }
2563b160b8bSBrian Somers }
2573b160b8bSBrian Somers /* Copy _one_ space */
25863bea446SPaolo Pisati if (i + 1 < dlen && iCopy < PKTSIZE)
2593b160b8bSBrian Somers newpacket[iCopy++] = sptr[i++];
2603b160b8bSBrian Somers
2613b160b8bSBrian Somers DBprintf(("Done command - removing spaces\n"));
262f0f93429SDag-Erling Smørgrav /*
263f0f93429SDag-Erling Smørgrav * Skip any extra spaces (should not occur according to
264f0f93429SDag-Erling Smørgrav * protocol, but DCC breaks CTCP protocol anyway
265f0f93429SDag-Erling Smørgrav */
2663b160b8bSBrian Somers while (sptr[i] == ' ') {
2673b160b8bSBrian Somers if (++i >= dlen) {
2683b160b8bSBrian Somers DBprintf(("DCC packet terminated in just spaces (post-command)\n"));
2693b160b8bSBrian Somers goto lPACKET_DONE;
2703b160b8bSBrian Somers }
2713b160b8bSBrian Somers }
2723b160b8bSBrian Somers
2733b160b8bSBrian Somers DBprintf(("Transferring filename...\n"));
2743b160b8bSBrian Somers while (sptr[i] != ' ') {
2753b160b8bSBrian Somers newpacket[iCopy++] = sptr[i];
27663bea446SPaolo Pisati if (++i >= dlen || iCopy >= PKTSIZE) {
2773b160b8bSBrian Somers DBprintf(("DCC packet terminated during filename\n"));
2783b160b8bSBrian Somers goto lPACKET_DONE;
2793b160b8bSBrian Somers }
2803b160b8bSBrian Somers }
2813b160b8bSBrian Somers /* Copy _one_ space */
28263bea446SPaolo Pisati if (i + 1 < dlen && iCopy < PKTSIZE)
2833b160b8bSBrian Somers newpacket[iCopy++] = sptr[i++];
2843b160b8bSBrian Somers
2853b160b8bSBrian Somers DBprintf(("Done filename - removing spaces\n"));
286f0f93429SDag-Erling Smørgrav /*
287f0f93429SDag-Erling Smørgrav * Skip any extra spaces (should not occur according to
288f0f93429SDag-Erling Smørgrav * protocol, but DCC breaks CTCP protocol anyway
289f0f93429SDag-Erling Smørgrav */
2903b160b8bSBrian Somers while (sptr[i] == ' ') {
2913b160b8bSBrian Somers if (++i >= dlen) {
2923b160b8bSBrian Somers DBprintf(("DCC packet terminated in just spaces (post-filename)\n"));
2933b160b8bSBrian Somers goto lPACKET_DONE;
2943b160b8bSBrian Somers }
2953b160b8bSBrian Somers }
2963b160b8bSBrian Somers
2973b160b8bSBrian Somers DBprintf(("Fetching IP address\n"));
2983b160b8bSBrian Somers /* Fetch IP address */
2993b160b8bSBrian Somers org_addr = 0;
3003b160b8bSBrian Somers while (i < dlen && isdigit(sptr[i])) {
3013b160b8bSBrian Somers if (org_addr > ULONG_MAX / 10UL) { /* Terminate on overflow */
3023b160b8bSBrian Somers DBprintf(("DCC Address overflow (org_addr == 0x%08lx, next char %c\n", org_addr, sptr[i]));
3033b160b8bSBrian Somers goto lBAD_CTCP;
3043b160b8bSBrian Somers }
3053b160b8bSBrian Somers org_addr *= 10;
3063b160b8bSBrian Somers org_addr += sptr[i++] - '0';
3073b160b8bSBrian Somers }
3083b160b8bSBrian Somers DBprintf(("Skipping space\n"));
3093b160b8bSBrian Somers if (i + 1 >= dlen || sptr[i] != ' ') {
3103b160b8bSBrian Somers DBprintf(("Overflow (%d >= %d) or bad character (%02x) terminating IP address\n", i + 1, dlen, sptr[i]));
3113b160b8bSBrian Somers goto lBAD_CTCP;
3123b160b8bSBrian Somers }
313f0f93429SDag-Erling Smørgrav /*
314f0f93429SDag-Erling Smørgrav * Skip any extra spaces (should not occur according to
315f0f93429SDag-Erling Smørgrav * protocol, but DCC breaks CTCP protocol anyway, so we
316f0f93429SDag-Erling Smørgrav * might as well play it safe
317f0f93429SDag-Erling Smørgrav */
3183b160b8bSBrian Somers while (sptr[i] == ' ') {
3193b160b8bSBrian Somers if (++i >= dlen) {
3203b160b8bSBrian Somers DBprintf(("Packet failure - space overflow.\n"));
3213b160b8bSBrian Somers goto lPACKET_DONE;
3223b160b8bSBrian Somers }
3233b160b8bSBrian Somers }
3243b160b8bSBrian Somers DBprintf(("Fetching port number\n"));
3253b160b8bSBrian Somers /* Fetch source port */
3263b160b8bSBrian Somers org_port = 0;
3273b160b8bSBrian Somers while (i < dlen && isdigit(sptr[i])) {
328f0f93429SDag-Erling Smørgrav if (org_port > 6554) { /* Terminate on overflow
329f0f93429SDag-Erling Smørgrav * (65536/10 rounded up */
3303b160b8bSBrian Somers DBprintf(("DCC: port number overflow\n"));
3313b160b8bSBrian Somers goto lBAD_CTCP;
3323b160b8bSBrian Somers }
3333b160b8bSBrian Somers org_port *= 10;
3343b160b8bSBrian Somers org_port += sptr[i++] - '0';
3353b160b8bSBrian Somers }
3363b160b8bSBrian Somers /* Skip illegal addresses (or early termination) */
3373b160b8bSBrian Somers if (i >= dlen || (sptr[i] != '\001' && sptr[i] != ' ')) {
3383b160b8bSBrian Somers DBprintf(("Bad port termination\n"));
3393b160b8bSBrian Somers goto lBAD_CTCP;
3403b160b8bSBrian Somers }
3413b160b8bSBrian Somers DBprintf(("Got IP %lu and port %u\n", org_addr, (unsigned)org_port));
3423b160b8bSBrian Somers
3433b160b8bSBrian Somers /* We've got the address and port - now alias it */
3443b160b8bSBrian Somers {
345ed01a582SDag-Erling Smørgrav struct alias_link *dcc_lnk;
3463b160b8bSBrian Somers struct in_addr destaddr;
3473b160b8bSBrian Somers
3483b160b8bSBrian Somers true_port = htons(org_port);
3493b160b8bSBrian Somers true_addr.s_addr = htonl(org_addr);
3503b160b8bSBrian Somers destaddr.s_addr = 0;
3513b160b8bSBrian Somers
35204c3e339SRuslan Ermilov /* Sanity/Security checking */
35304c3e339SRuslan Ermilov if (!org_addr || !org_port ||
35404c3e339SRuslan Ermilov pip->ip_src.s_addr != true_addr.s_addr ||
35504c3e339SRuslan Ermilov org_port < IPPORT_RESERVED)
35604c3e339SRuslan Ermilov goto lBAD_CTCP;
35704c3e339SRuslan Ermilov
358f0f93429SDag-Erling Smørgrav /*
359f0f93429SDag-Erling Smørgrav * Steal the FTP_DATA_PORT - it doesn't really
360f0f93429SDag-Erling Smørgrav * matter, and this would probably allow it through
361f0f93429SDag-Erling Smørgrav * at least _some_ firewalls.
362f0f93429SDag-Erling Smørgrav */
363*fb2ea26fSMark Johnston (void)FindUdpTcpOut(la, true_addr, destaddr,
364642cd09fSRuslan Ermilov true_port, 0,
365*fb2ea26fSMark Johnston IPPROTO_TCP, 1, &dcc_lnk);
3663b160b8bSBrian Somers DBprintf(("Got a DCC link\n"));
367ed01a582SDag-Erling Smørgrav if (dcc_lnk) {
3683b160b8bSBrian Somers struct in_addr alias_address; /* Address from aliasing */
369f0f93429SDag-Erling Smørgrav u_short alias_port; /* Port given by
370f0f93429SDag-Erling Smørgrav * aliasing */
3717806546cSBrian Somers int n;
3723b160b8bSBrian Somers
373b5ce85feSBrian Somers #ifndef NO_FW_PUNCH
3748ddc51bcSEivind Eklund /* Generate firewall hole as appropriate */
375ed01a582SDag-Erling Smørgrav PunchFWHole(dcc_lnk);
376b5ce85feSBrian Somers #endif
3778ddc51bcSEivind Eklund
378ed01a582SDag-Erling Smørgrav alias_address = GetAliasAddress(lnk);
3797806546cSBrian Somers n = snprintf(&newpacket[iCopy],
38063bea446SPaolo Pisati PKTSIZE - iCopy,
3819feab75aSBrian Somers "%lu ", (u_long) htonl(alias_address.s_addr));
3827806546cSBrian Somers if (n < 0) {
3837806546cSBrian Somers DBprintf(("DCC packet construct failure.\n"));
3847806546cSBrian Somers goto lBAD_CTCP;
3857806546cSBrian Somers }
38663bea446SPaolo Pisati if ((iCopy += n) >= PKTSIZE) { /* Truncated/fit exactly
387f0f93429SDag-Erling Smørgrav * - bad news */
3883b160b8bSBrian Somers DBprintf(("DCC constructed packet overflow.\n"));
3893b160b8bSBrian Somers goto lBAD_CTCP;
3903b160b8bSBrian Somers }
391ed01a582SDag-Erling Smørgrav alias_port = GetAliasPort(dcc_lnk);
3927806546cSBrian Somers n = snprintf(&newpacket[iCopy],
39363bea446SPaolo Pisati PKTSIZE - iCopy,
3943b160b8bSBrian Somers "%u", htons(alias_port));
3957806546cSBrian Somers if (n < 0) {
3967806546cSBrian Somers DBprintf(("DCC packet construct failure.\n"));
3977806546cSBrian Somers goto lBAD_CTCP;
3987806546cSBrian Somers }
3997806546cSBrian Somers iCopy += n;
400f0f93429SDag-Erling Smørgrav /*
401f0f93429SDag-Erling Smørgrav * Done - truncated cases will be taken
402f0f93429SDag-Erling Smørgrav * care of by lBAD_CTCP
403f0f93429SDag-Erling Smørgrav */
4043b160b8bSBrian Somers DBprintf(("Aliased IP %lu and port %u\n", alias_address.s_addr, (unsigned)alias_port));
4053b160b8bSBrian Somers }
4063b160b8bSBrian Somers }
407f0f93429SDag-Erling Smørgrav /*
408f0f93429SDag-Erling Smørgrav * An uninteresting CTCP - state entered right after '\001'
409f0f93429SDag-Erling Smørgrav * has been pushed. Also used to copy the rest of a DCC,
410f0f93429SDag-Erling Smørgrav * after IP address and port has been handled
411f0f93429SDag-Erling Smørgrav */
4123b160b8bSBrian Somers lBAD_CTCP:
41363bea446SPaolo Pisati for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
4143b160b8bSBrian Somers newpacket[iCopy] = sptr[i]; /* Copy CTCP unchanged */
4153b160b8bSBrian Somers if (sptr[i] == '\001') {
4163b160b8bSBrian Somers goto lNORMAL_TEXT;
4173b160b8bSBrian Somers }
4183b160b8bSBrian Somers }
4193b160b8bSBrian Somers goto lPACKET_DONE;
4203b160b8bSBrian Somers /* Normal text */
4213b160b8bSBrian Somers lNORMAL_TEXT:
42263bea446SPaolo Pisati for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
4233b160b8bSBrian Somers newpacket[iCopy] = sptr[i]; /* Copy CTCP unchanged */
4243b160b8bSBrian Somers if (sptr[i] == '\001') {
4253b160b8bSBrian Somers goto lCTCP_START;
4263b160b8bSBrian Somers }
4273b160b8bSBrian Somers }
4283b160b8bSBrian Somers /* Handle the end of a packet */
4293b160b8bSBrian Somers lPACKET_DONE:
4303b160b8bSBrian Somers iCopy = iCopy > maxsize - copyat ? maxsize - copyat : iCopy;
4313b160b8bSBrian Somers memcpy(sptr + copyat, newpacket, iCopy);
4323b160b8bSBrian Somers
4333b160b8bSBrian Somers /* Save information regarding modified seq and ack numbers */
4343b160b8bSBrian Somers {
4353b160b8bSBrian Somers int delta;
4363b160b8bSBrian Somers
437ed01a582SDag-Erling Smørgrav SetAckModified(lnk);
4384741f3a1SPaolo Pisati tc = (struct tcphdr *)ip_next(pip);
4394741f3a1SPaolo Pisati delta = GetDeltaSeqOut(tc->th_seq, lnk);
4404741f3a1SPaolo Pisati AddSeq(lnk, delta + copyat + iCopy - dlen, pip->ip_hl,
4414741f3a1SPaolo Pisati pip->ip_len, tc->th_seq, tc->th_off);
4423b160b8bSBrian Somers }
4433b160b8bSBrian Somers
4443b160b8bSBrian Somers /* Revise IP header */
4453b160b8bSBrian Somers {
4463b160b8bSBrian Somers u_short new_len;
4473b160b8bSBrian Somers
4483b160b8bSBrian Somers new_len = htons(hlen + iCopy + copyat);
4493b160b8bSBrian Somers DifferentialChecksum(&pip->ip_sum,
4503b160b8bSBrian Somers &new_len,
4513b160b8bSBrian Somers &pip->ip_len,
4523b160b8bSBrian Somers 1);
4533b160b8bSBrian Somers pip->ip_len = new_len;
4543b160b8bSBrian Somers }
4553b160b8bSBrian Somers
4563b160b8bSBrian Somers /* Compute TCP checksum for revised packet */
4573b160b8bSBrian Somers tc->th_sum = 0;
45859dde15eSGleb Smirnoff #ifdef _KERNEL
4590fc7bdc9SRichard Scheffenegger tcp_set_flags(tc, tcp_get_flags(tc) | TH_RES1);
46059dde15eSGleb Smirnoff #else
4613b160b8bSBrian Somers tc->th_sum = TcpChecksum(pip);
46259dde15eSGleb Smirnoff #endif
4633b160b8bSBrian Somers return;
4643b160b8bSBrian Somers }
4653b160b8bSBrian Somers }
4663b160b8bSBrian Somers
4673b160b8bSBrian Somers /* Notes:
4683b160b8bSBrian Somers [Note 1]
4693b160b8bSBrian Somers The initial search will most often fail; it could be replaced with a 32-bit specific search.
4703b160b8bSBrian Somers Such a search would be done for 32-bit unsigned value V:
4713b160b8bSBrian Somers V ^= 0x01010101; (Search is for null bytes)
4723b160b8bSBrian Somers if( ((V-0x01010101)^V) & 0x80808080 ) {
4733b160b8bSBrian Somers (found a null bytes which was a 01 byte)
4743b160b8bSBrian Somers }
4753b160b8bSBrian Somers To assert that the processor is 32-bits, do
4763b160b8bSBrian Somers extern int ircdccar[32]; (32 bits)
4773b160b8bSBrian Somers extern int ircdccar[CHAR_BIT*sizeof(unsigned int)];
4783b160b8bSBrian Somers which will generate a type-error on all but 32-bit machines.
4793b160b8bSBrian Somers
4803b160b8bSBrian Somers [Note 2] This routine really ought to be replaced with one that
481a4641f4eSPedro F. Giffuni creates a transparent proxy on the aliasing host, to allow arbitrary
4823b160b8bSBrian Somers changes in the TCP stream. This should not be too difficult given
4833b160b8bSBrian Somers this base; I (ee) will try to do this some time later.
4843b160b8bSBrian Somers */
485