/*-
* Copyright (c) 2001 Charles Mott <cm@linktel.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
__FBSDID("$FreeBSD: src/sys/netinet/libalias/alias_irc.c,v 1.23.2.2.4.1 2009/04/15 03:14:26 kensmith Exp $");
/* Alias_irc.c intercepts packages contain IRC CTCP commands, and
changes DCC commands to export a port on the aliasing host instead
of an aliased host.
For this routine to work, the DCC command must fit entirely into a
single TCP packet. This will usually happen, but is not
guaranteed.
The interception is likely to change the length of the packet.
The handling of this is copied more-or-less verbatim from
Initial version: Eivind Eklund <perhaps@yes.no> (ee) 97-01-29
Version 2.1: May, 1997 (cjm)
Very minor changes to conform with
withing the packet alising module.
*/
/* Includes */
#ifdef _KERNEL
#else
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#endif
#include <netinet/in_systm.h>
#ifdef _KERNEL
#else
#include "alias_local.h"
#include "alias_mod.h"
#endif
char *newpacket;
/* Local defines */
#define DBprintf(a)
static void
int maxpacketsize);
static int
{
ah->maxpktsize == 0)
return (-1);
return (0);
return (-1);
}
static int
{
if (newpacket) {
}
return (0);
}
{
.pri = 90,
.fingerprint = &fingerprint,
},
{ EOH }
};
static int
{
int error;
switch (type) {
case MOD_LOAD:
error = 0;
break;
case MOD_UNLOAD:
error = 0;
break;
default:
}
return (error);
}
#ifdef _KERNEL
static
#endif
};
/* Kernel module definition. */
#ifdef _KERNEL
#endif
static void
int maxsize /* Maximum size of IP packet including
* headers */
)
{
char *sptr;
int i; /* Iterator through the source */
/* Calculate data length of TCP packet */
/*
* Return if data length is too short - assume an entire PRIVMSG in
* each packet.
*/
return;
/* Place string pointer at beginning of data */
* data, not packet */
/* Search for a CTCP command [Note 1] */
for (i = 0; i < dlen; i++) {
if (sptr[i] == '\001')
goto lFOUND_CTCP;
}
return; /* No CTCP commands in */
/* Handle CTCP commands - the buffer may have to be copied */
{
unsigned int copyat = i;
* copy-back string? */
* address */
goto lPACKET_DONE;
* character */
/* Start of a CTCP */
goto lBAD_CTCP;
if (sptr[i + 0] != 'D')
goto lBAD_CTCP;
goto lBAD_CTCP;
goto lBAD_CTCP;
goto lBAD_CTCP;
/* We have a DCC command - handle it! */
i += 4; /* Skip "DCC " */
goto lPACKET_DONE;
DBprintf(("Found DCC\n"));
/*
* Skip any extra spaces (should not occur according to
* protocol, but DCC breaks CTCP protocol anyway
*/
while (sptr[i] == ' ') {
if (++i >= dlen) {
DBprintf(("DCC packet terminated in just spaces\n"));
goto lPACKET_DONE;
}
}
DBprintf(("Transferring command...\n"));
while (sptr[i] != ' ') {
DBprintf(("DCC packet terminated during command\n"));
goto lPACKET_DONE;
}
}
/* Copy _one_ space */
DBprintf(("Done command - removing spaces\n"));
/*
* Skip any extra spaces (should not occur according to
* protocol, but DCC breaks CTCP protocol anyway
*/
while (sptr[i] == ' ') {
if (++i >= dlen) {
DBprintf(("DCC packet terminated in just spaces (post-command)\n"));
goto lPACKET_DONE;
}
}
DBprintf(("Transferring filename...\n"));
while (sptr[i] != ' ') {
DBprintf(("DCC packet terminated during filename\n"));
goto lPACKET_DONE;
}
}
/* Copy _one_ space */
DBprintf(("Done filename - removing spaces\n"));
/*
* Skip any extra spaces (should not occur according to
* protocol, but DCC breaks CTCP protocol anyway
*/
while (sptr[i] == ' ') {
if (++i >= dlen) {
DBprintf(("DCC packet terminated in just spaces (post-filename)\n"));
goto lPACKET_DONE;
}
}
DBprintf(("Fetching IP address\n"));
/* Fetch IP address */
org_addr = 0;
goto lBAD_CTCP;
}
org_addr *= 10;
}
DBprintf(("Skipping space\n"));
DBprintf(("Overflow (%d >= %d) or bad character (%02x) terminating IP address\n", i + 1, dlen, sptr[i]));
goto lBAD_CTCP;
}
/*
* Skip any extra spaces (should not occur according to
* protocol, but DCC breaks CTCP protocol anyway, so we
* might as well play it safe
*/
while (sptr[i] == ' ') {
if (++i >= dlen) {
DBprintf(("Packet failure - space overflow.\n"));
goto lPACKET_DONE;
}
}
DBprintf(("Fetching port number\n"));
/* Fetch source port */
org_port = 0;
* (65536/10 rounded up */
DBprintf(("DCC: port number overflow\n"));
goto lBAD_CTCP;
}
org_port *= 10;
}
/* Skip illegal addresses (or early termination) */
DBprintf(("Bad port termination\n"));
goto lBAD_CTCP;
}
/* We've got the address and port - now alias it */
{
goto lBAD_CTCP;
/*
* Steal the FTP_DATA_PORT - it doesn't really
* matter, and this would probably allow it through
* at least _some_ firewalls.
*/
true_port, 0,
IPPROTO_TCP, 1);
DBprintf(("Got a DCC link\n"));
if (dcc_lnk) {
* aliasing */
int n;
#ifndef NO_FW_PUNCH
/* Generate firewall hole as appropriate */
#endif
if (n < 0) {
DBprintf(("DCC packet construct failure.\n"));
goto lBAD_CTCP;
}
* - bad news */
DBprintf(("DCC constructed packet overflow.\n"));
goto lBAD_CTCP;
}
if (n < 0) {
DBprintf(("DCC packet construct failure.\n"));
goto lBAD_CTCP;
}
iCopy += n;
/*
* Done - truncated cases will be taken
* care of by lBAD_CTCP
*/
}
}
/*
* An uninteresting CTCP - state entered right after '\001'
* has been pushed. Also used to copy the rest of a DCC,
* after IP address and port has been handled
*/
if (sptr[i] == '\001') {
goto lNORMAL_TEXT;
}
}
goto lPACKET_DONE;
/* Normal text */
if (sptr[i] == '\001') {
goto lCTCP_START;
}
}
/* Handle the end of a packet */
/* Save information regarding modified seq and ack numbers */
{
int delta;
}
/* Revise IP header */
{
&new_len,
1);
}
/* Compute TCP checksum for revised packet */
#ifdef _KERNEL
#else
#endif
return;
}
}
/* Notes:
[Note 1]
The initial search will most often fail; it could be replaced with a 32-bit specific search.
Such a search would be done for 32-bit unsigned value V:
V ^= 0x01010101; (Search is for null bytes)
if( ((V-0x01010101)^V) & 0x80808080 ) {
(found a null bytes which was a 01 byte)
}
To assert that the processor is 32-bits, do
extern int ircdccar[32]; (32 bits)
extern int ircdccar[CHAR_BIT*sizeof(unsigned int)];
which will generate a type-error on all but 32-bit machines.
[Note 2] This routine really ought to be replaced with one that
creates a transparent proxy on the aliasing host, to allow arbitary
changes in the TCP stream. This should not be too difficult given
this base; I (ee) will try to do this some time later.
*/