source: rtems-libbsd/freebsd/sys/netinet/libalias/alias_irc.c @ 3d1e767

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 3d1e767 was 3d1e767, checked in by Sebastian Huber <sebastian.huber@…>, on 04/27/16 at 08:25:22

Directly use <sys/types.h> provided by Newlib

  • Property mode set to 100644
File size: 13.1 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*-
4 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32/* Alias_irc.c intercepts packages contain IRC CTCP commands, and
33        changes DCC commands to export a port on the aliasing host instead
34        of an aliased host.
35
36    For this routine to work, the DCC command must fit entirely into a
37    single TCP packet.  This will usually happen, but is not
38    guaranteed.
39
40         The interception is likely to change the length of the packet.
41         The handling of this is copied more-or-less verbatim from
42         ftp_alias.c
43
44         Initial version: Eivind Eklund <perhaps@yes.no> (ee) 97-01-29
45
46         Version 2.1:  May, 1997 (cjm)
47             Very minor changes to conform with
48             local/global/function naming conventions
49             withing the packet alising module.
50*/
51
52/* Includes */
53#ifdef _KERNEL
54#include <rtems/bsd/sys/param.h>
55#include <sys/ctype.h>
56#include <sys/limits.h>
57#include <sys/systm.h>
58#include <sys/kernel.h>
59#include <sys/module.h>
60#else
61#include <ctype.h>
62#include <errno.h>
63#include <sys/types.h>
64#include <stdio.h>
65#include <stdlib.h>
66#include <string.h>
67#include <limits.h>
68#endif
69
70#include <netinet/in_systm.h>
71#include <netinet/in.h>
72#include <netinet/ip.h>
73#include <netinet/tcp.h>
74
75#ifdef _KERNEL
76#include <netinet/libalias/alias.h>
77#include <netinet/libalias/alias_local.h>
78#include <netinet/libalias/alias_mod.h>
79#else
80#include "alias_local.h"
81#include "alias_mod.h"
82#endif
83
84#define IRC_CONTROL_PORT_NUMBER_1 6667
85#define IRC_CONTROL_PORT_NUMBER_2 6668
86
87#define PKTSIZE (IP_MAXPACKET + 1)
88char *newpacket;
89
90/* Local defines */
91#define DBprintf(a)
92
93static void
94AliasHandleIrcOut(struct libalias *, struct ip *, struct alias_link *, 
95                  int maxpacketsize);
96
97static int
98fingerprint(struct libalias *la, struct alias_data *ah)
99{
100
101        if (ah->dport == NULL || ah->dport == NULL || ah->lnk == NULL ||
102            ah->maxpktsize == 0)
103                return (-1);
104        if (ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_1
105            || ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_2)
106                return (0);
107        return (-1);
108}
109
110static int
111protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
112{
113
114        newpacket = malloc(PKTSIZE);
115        if (newpacket) {
116                AliasHandleIrcOut(la, pip, ah->lnk, ah->maxpktsize);
117                free(newpacket);
118        }
119        return (0);
120}
121
122struct proto_handler handlers[] = {
123        {
124          .pri = 90,
125          .dir = OUT,
126          .proto = TCP,
127          .fingerprint = &fingerprint,
128          .protohandler = &protohandler
129        },
130        { EOH }
131};
132
133static int
134mod_handler(module_t mod, int type, void *data)
135{
136        int error;
137
138        switch (type) {
139        case MOD_LOAD:
140                error = 0;
141                LibAliasAttachHandlers(handlers);
142                break;
143        case MOD_UNLOAD:
144                error = 0;
145                LibAliasDetachHandlers(handlers);
146                break;
147        default:
148                error = EINVAL;
149        }
150        return (error);
151}
152
153#ifdef _KERNEL
154static
155#endif
156moduledata_t alias_mod = {
157       "alias_irc", mod_handler, NULL
158};
159
160/* Kernel module definition. */
161#ifdef  _KERNEL
162DECLARE_MODULE(alias_irc, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
163MODULE_VERSION(alias_irc, 1);
164MODULE_DEPEND(alias_irc, libalias, 1, 1, 1);
165#endif
166
167static void
168AliasHandleIrcOut(struct libalias *la,
169    struct ip *pip,             /* IP packet to examine */
170    struct alias_link *lnk,     /* Which link are we on? */
171    int maxsize                 /* Maximum size of IP packet including
172                                 * headers */
173)
174{
175        int hlen, tlen, dlen;
176        struct in_addr true_addr;
177        u_short true_port;
178        char *sptr;
179        struct tcphdr *tc;
180        int i;                  /* Iterator through the source */
181
182/* Calculate data length of TCP packet */
183        tc = (struct tcphdr *)ip_next(pip);
184        hlen = (pip->ip_hl + tc->th_off) << 2;
185        tlen = ntohs(pip->ip_len);
186        dlen = tlen - hlen;
187
188        /*
189         * Return if data length is too short - assume an entire PRIVMSG in
190         * each packet.
191         */
192        if (dlen < (int)sizeof(":A!a@n.n PRIVMSG A :aDCC 1 1a") - 1)
193                return;
194
195/* Place string pointer at beginning of data */
196        sptr = (char *)pip;
197        sptr += hlen;
198        maxsize -= hlen;        /* We're interested in maximum size of
199                                 * data, not packet */
200
201        /* Search for a CTCP command [Note 1] */
202        for (i = 0; i < dlen; i++) {
203                if (sptr[i] == '\001')
204                        goto lFOUND_CTCP;
205        }
206        return;                 /* No CTCP commands in  */
207        /* Handle CTCP commands - the buffer may have to be copied */
208lFOUND_CTCP:
209        {
210                unsigned int copyat = i;
211                unsigned int iCopy = 0; /* How much data have we written to
212                                         * copy-back string? */
213                unsigned long org_addr; /* Original IP address */
214                unsigned short org_port;        /* Original source port
215                                                 * address */
216
217lCTCP_START:
218                if (i >= dlen || iCopy >= PKTSIZE)
219                        goto lPACKET_DONE;
220                newpacket[iCopy++] = sptr[i++]; /* Copy the CTCP start
221                                                 * character */
222                /* Start of a CTCP */
223                if (i + 4 >= dlen)      /* Too short for DCC */
224                        goto lBAD_CTCP;
225                if (sptr[i + 0] != 'D')
226                        goto lBAD_CTCP;
227                if (sptr[i + 1] != 'C')
228                        goto lBAD_CTCP;
229                if (sptr[i + 2] != 'C')
230                        goto lBAD_CTCP;
231                if (sptr[i + 3] != ' ')
232                        goto lBAD_CTCP;
233                /* We have a DCC command - handle it! */
234                i += 4;         /* Skip "DCC " */
235                if (iCopy + 4 > PKTSIZE)
236                        goto lPACKET_DONE;
237                newpacket[iCopy++] = 'D';
238                newpacket[iCopy++] = 'C';
239                newpacket[iCopy++] = 'C';
240                newpacket[iCopy++] = ' ';
241
242                DBprintf(("Found DCC\n"));
243                /*
244                 * Skip any extra spaces (should not occur according to
245                 * protocol, but DCC breaks CTCP protocol anyway
246                 */
247                while (sptr[i] == ' ') {
248                        if (++i >= dlen) {
249                                DBprintf(("DCC packet terminated in just spaces\n"));
250                                goto lPACKET_DONE;
251                        }
252                }
253
254                DBprintf(("Transferring command...\n"));
255                while (sptr[i] != ' ') {
256                        newpacket[iCopy++] = sptr[i];
257                        if (++i >= dlen || iCopy >= PKTSIZE) {
258                                DBprintf(("DCC packet terminated during command\n"));
259                                goto lPACKET_DONE;
260                        }
261                }
262                /* Copy _one_ space */
263                if (i + 1 < dlen && iCopy < PKTSIZE)
264                        newpacket[iCopy++] = sptr[i++];
265
266                DBprintf(("Done command - removing spaces\n"));
267                /*
268                 * Skip any extra spaces (should not occur according to
269                 * protocol, but DCC breaks CTCP protocol anyway
270                 */
271                while (sptr[i] == ' ') {
272                        if (++i >= dlen) {
273                                DBprintf(("DCC packet terminated in just spaces (post-command)\n"));
274                                goto lPACKET_DONE;
275                        }
276                }
277
278                DBprintf(("Transferring filename...\n"));
279                while (sptr[i] != ' ') {
280                        newpacket[iCopy++] = sptr[i];
281                        if (++i >= dlen || iCopy >= PKTSIZE) {
282                                DBprintf(("DCC packet terminated during filename\n"));
283                                goto lPACKET_DONE;
284                        }
285                }
286                /* Copy _one_ space */
287                if (i + 1 < dlen && iCopy < PKTSIZE)
288                        newpacket[iCopy++] = sptr[i++];
289
290                DBprintf(("Done filename - removing spaces\n"));
291                /*
292                 * Skip any extra spaces (should not occur according to
293                 * protocol, but DCC breaks CTCP protocol anyway
294                 */
295                while (sptr[i] == ' ') {
296                        if (++i >= dlen) {
297                                DBprintf(("DCC packet terminated in just spaces (post-filename)\n"));
298                                goto lPACKET_DONE;
299                        }
300                }
301
302                DBprintf(("Fetching IP address\n"));
303                /* Fetch IP address */
304                org_addr = 0;
305                while (i < dlen && isdigit(sptr[i])) {
306                        if (org_addr > ULONG_MAX / 10UL) {      /* Terminate on overflow */
307                                DBprintf(("DCC Address overflow (org_addr == 0x%08lx, next char %c\n", org_addr, sptr[i]));
308                                goto lBAD_CTCP;
309                        }
310                        org_addr *= 10;
311                        org_addr += sptr[i++] - '0';
312                }
313                DBprintf(("Skipping space\n"));
314                if (i + 1 >= dlen || sptr[i] != ' ') {
315                        DBprintf(("Overflow (%d >= %d) or bad character (%02x) terminating IP address\n", i + 1, dlen, sptr[i]));
316                        goto lBAD_CTCP;
317                }
318                /*
319                 * Skip any extra spaces (should not occur according to
320                 * protocol, but DCC breaks CTCP protocol anyway, so we
321                 * might as well play it safe
322                 */
323                while (sptr[i] == ' ') {
324                        if (++i >= dlen) {
325                                DBprintf(("Packet failure - space overflow.\n"));
326                                goto lPACKET_DONE;
327                        }
328                }
329                DBprintf(("Fetching port number\n"));
330                /* Fetch source port */
331                org_port = 0;
332                while (i < dlen && isdigit(sptr[i])) {
333                        if (org_port > 6554) {  /* Terminate on overflow
334                                                 * (65536/10 rounded up */
335                                DBprintf(("DCC: port number overflow\n"));
336                                goto lBAD_CTCP;
337                        }
338                        org_port *= 10;
339                        org_port += sptr[i++] - '0';
340                }
341                /* Skip illegal addresses (or early termination) */
342                if (i >= dlen || (sptr[i] != '\001' && sptr[i] != ' ')) {
343                        DBprintf(("Bad port termination\n"));
344                        goto lBAD_CTCP;
345                }
346                DBprintf(("Got IP %lu and port %u\n", org_addr, (unsigned)org_port));
347
348                /* We've got the address and port - now alias it */
349                {
350                        struct alias_link *dcc_lnk;
351                        struct in_addr destaddr;
352
353
354                        true_port = htons(org_port);
355                        true_addr.s_addr = htonl(org_addr);
356                        destaddr.s_addr = 0;
357
358                        /* Sanity/Security checking */
359                        if (!org_addr || !org_port ||
360                            pip->ip_src.s_addr != true_addr.s_addr ||
361                            org_port < IPPORT_RESERVED)
362                                goto lBAD_CTCP;
363
364                        /*
365                         * Steal the FTP_DATA_PORT - it doesn't really
366                         * matter, and this would probably allow it through
367                         * at least _some_ firewalls.
368                         */
369                        dcc_lnk = FindUdpTcpOut(la, true_addr, destaddr,
370                            true_port, 0,
371                            IPPROTO_TCP, 1);
372                        DBprintf(("Got a DCC link\n"));
373                        if (dcc_lnk) {
374                                struct in_addr alias_address;   /* Address from aliasing */
375                                u_short alias_port;     /* Port given by
376                                                         * aliasing */
377                                int n;
378
379#ifndef NO_FW_PUNCH
380                                /* Generate firewall hole as appropriate */
381                                PunchFWHole(dcc_lnk);
382#endif
383
384                                alias_address = GetAliasAddress(lnk);
385                                n = snprintf(&newpacket[iCopy],
386                                    PKTSIZE - iCopy,
387                                    "%lu ", (u_long) htonl(alias_address.s_addr));
388                                if (n < 0) {
389                                        DBprintf(("DCC packet construct failure.\n"));
390                                        goto lBAD_CTCP;
391                                }
392                                if ((iCopy += n) >= PKTSIZE) {  /* Truncated/fit exactly
393                                                                                 * - bad news */
394                                        DBprintf(("DCC constructed packet overflow.\n"));
395                                        goto lBAD_CTCP;
396                                }
397                                alias_port = GetAliasPort(dcc_lnk);
398                                n = snprintf(&newpacket[iCopy],
399                                    PKTSIZE - iCopy,
400                                    "%u", htons(alias_port));
401                                if (n < 0) {
402                                        DBprintf(("DCC packet construct failure.\n"));
403                                        goto lBAD_CTCP;
404                                }
405                                iCopy += n;
406                                /*
407                                 * Done - truncated cases will be taken
408                                 * care of by lBAD_CTCP
409                                 */
410                                DBprintf(("Aliased IP %lu and port %u\n", alias_address.s_addr, (unsigned)alias_port));
411                        }
412                }
413                /*
414                 * An uninteresting CTCP - state entered right after '\001'
415                 * has been pushed.  Also used to copy the rest of a DCC,
416                 * after IP address and port has been handled
417                 */
418lBAD_CTCP:
419                for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
420                        newpacket[iCopy] = sptr[i];     /* Copy CTCP unchanged */
421                        if (sptr[i] == '\001') {
422                                goto lNORMAL_TEXT;
423                        }
424                }
425                goto lPACKET_DONE;
426                /* Normal text */
427lNORMAL_TEXT:
428                for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
429                        newpacket[iCopy] = sptr[i];     /* Copy CTCP unchanged */
430                        if (sptr[i] == '\001') {
431                                goto lCTCP_START;
432                        }
433                }
434                /* Handle the end of a packet */
435lPACKET_DONE:
436                iCopy = iCopy > maxsize - copyat ? maxsize - copyat : iCopy;
437                memcpy(sptr + copyat, newpacket, iCopy);
438
439/* Save information regarding modified seq and ack numbers */
440                {
441                        int delta;
442
443                        SetAckModified(lnk);
444                        tc = (struct tcphdr *)ip_next(pip);                             
445                        delta = GetDeltaSeqOut(tc->th_seq, lnk);
446                        AddSeq(lnk, delta + copyat + iCopy - dlen, pip->ip_hl,
447                            pip->ip_len, tc->th_seq, tc->th_off);
448                }
449
450                /* Revise IP header */
451                {
452                        u_short new_len;
453
454                        new_len = htons(hlen + iCopy + copyat);
455                        DifferentialChecksum(&pip->ip_sum,
456                            &new_len,
457                            &pip->ip_len,
458                            1);
459                        pip->ip_len = new_len;
460                }
461
462                /* Compute TCP checksum for revised packet */
463                tc->th_sum = 0;
464#ifdef _KERNEL
465                tc->th_x2 = 1;
466#else
467                tc->th_sum = TcpChecksum(pip);
468#endif
469                return;
470        }
471}
472
473/* Notes:
474        [Note 1]
475        The initial search will most often fail; it could be replaced with a 32-bit specific search.
476        Such a search would be done for 32-bit unsigned value V:
477        V ^= 0x01010101;                                  (Search is for null bytes)
478        if( ((V-0x01010101)^V) & 0x80808080 ) {
479     (found a null bytes which was a 01 byte)
480        }
481   To assert that the processor is 32-bits, do
482   extern int ircdccar[32];        (32 bits)
483   extern int ircdccar[CHAR_BIT*sizeof(unsigned int)];
484   which will generate a type-error on all but 32-bit machines.
485
486        [Note 2] This routine really ought to be replaced with one that
487        creates a transparent proxy on the aliasing host, to allow arbitary
488        changes in the TCP stream.  This should not be too difficult given
489        this base;  I (ee) will try to do this some time later.
490        */
Note: See TracBrowser for help on using the repository browser.