linux-old/net/ipv4/ip_masq_irc.c
<<
>>
Prefs
   1/*
   2 *              IP_MASQ_IRC irc masquerading module
   3 *
   4 *
   5 * Version:     @(#)ip_masq_irc.c 0.03   97/11/30
   6 *
   7 * Author:      Juan Jose Ciarlante
   8 *              
   9 * Additions:
  10 *  - recognize a few non-irc-II DCC requests (Oliver Wagner)
  11 *     DCC MOVE (AmIRC/DCC.MOVE; SEND with resuming)
  12 *     DCC SCHAT (AmIRC IDEA encrypted CHAT)
  13 *     DCC TSEND (AmIRC/PIRCH SEND without ACKs)
  14 * Fixes:
  15 *      Juan Jose Ciarlante     :  set NO_DADDR flag in ip_masq_new()
  16 *      Nigel Metheringham      :  Added multiple port support 
  17 *      Juan Jose Ciarlante     :  litl bits for 2.1
  18 *      Oliver Wagner           :  more IRC cmds processing
  19 *        <winmute@lucifer.gv.kotnet.org>
  20 *      Juan Jose Ciarlante     :  put new ms entry to listen()
  21 *
  22 * FIXME:
  23 *      - detect also previous "PRIVMSG" string ?.
  24 *
  25 *      This program is free software; you can redistribute it and/or
  26 *      modify it under the terms of the GNU General Public License
  27 *      as published by the Free Software Foundation; either version
  28 *      2 of the License, or (at your option) any later version.
  29 *      
  30 * Multiple Port Support
  31 *      The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
  32 *      with the port numbers being defined at module load time.  The module
  33 *      uses the symbol "ports" to define a list of monitored ports, which can
  34 *      be specified on the insmod command line as
  35 *              ports=x1,x2,x3...
  36 *      where x[n] are integer port numbers.  This option can be put into
  37 *      /etc/conf.modules (or /etc/modules.conf depending on your config)
  38 *      where modload will pick it up should you use modload to load your
  39 *      modules.
  40 *      
  41 */
  42
  43#include <linux/config.h>
  44#include <linux/module.h>
  45
  46#include <linux/types.h>
  47#include <linux/kernel.h>
  48#include <asm/system.h>
  49#include <linux/skbuff.h>
  50#include <linux/in.h>
  51#include <linux/ip.h>
  52#include <linux/init.h>
  53#include <net/protocol.h>
  54#include <net/tcp.h>
  55#include <net/ip_masq.h>
  56
  57
  58/* 
  59 * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
  60 * First port is set to the default port.
  61 */
  62int ports[MAX_MASQ_APP_PORTS] = {6667}; /* I rely on the trailing items being set to zero */
  63struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
  64/*
  65 *      Debug level
  66 */
  67#ifdef CONFIG_IP_MASQ_DEBUG
  68static int debug=0;
  69MODULE_PARM(debug, "i");
  70#endif
  71
  72MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
  73
  74
  75/*
  76 * List of supported DCC protocols
  77 */
  78
  79#define NUM_DCCPROTO 5
  80
  81struct dccproto 
  82{
  83  char *match;
  84  int matchlen;
  85  int xtra_args;
  86};
  87
  88struct dccproto dccprotos[NUM_DCCPROTO] = {
  89 { "SEND ", 5, 1 },
  90 { "CHAT ", 5, 0, },
  91 { "MOVE ", 5, 1 },
  92 { "TSEND ", 6, 1, },
  93 { "SCHAT ", 6, 0, }
  94};
  95#define MAXMATCHLEN 6
  96
  97static int
  98masq_irc_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
  99{
 100        MOD_INC_USE_COUNT;
 101        return 0;
 102}
 103
 104static int
 105masq_irc_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
 106{
 107        MOD_DEC_USE_COUNT;
 108        return 0;
 109}
 110
 111int
 112masq_irc_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
 113{
 114        struct sk_buff *skb;
 115        struct iphdr *iph;
 116        struct tcphdr *th;
 117        char *data, *data_limit;
 118        __u32 s_addr;
 119        __u16 s_port;
 120        struct ip_masq *n_ms;
 121        char buf[20];           /* "m_addr m_port" (dec base)*/
 122        unsigned buf_len;
 123        int diff;
 124        int xtra_args = 0;      /* extra int args wanted after addr */
 125        char *dcc_p, *addr_beg_p, *addr_end_p;
 126
 127        skb = *skb_p;
 128        iph = skb->nh.iph;
 129        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
 130        data = (char *)&th[1];
 131
 132        /*
 133         *      Hunt irc DCC string, the _shortest_:
 134         *
 135         *      strlen("DCC CHAT chat AAAAAAAA P\x01\n")=26
 136         *      strlen("DCC SCHAT chat AAAAAAAA P\x01\n")=27
 137         *      strlen("DCC SEND F AAAAAAAA P S\x01\n")=25
 138         *      strlen("DCC MOVE F AAAAAAAA P S\x01\n")=25
 139         *      strlen("DCC TSEND F AAAAAAAA P S\x01\n")=26
 140         *      strlen("DCC MOVE F AAAAAAAA P S\x01\n")=25
 141         *              AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits)
 142         *              P:         bound port (min 1 d )
 143         *              F:         filename   (min 1 d )
 144         *              S:         size       (min 1 d ) 
 145         *              0x01, \n:  terminators
 146         */
 147
 148        data_limit = skb->h.raw + skb->len;
 149        
 150        while (data < (data_limit - ( 21 + MAXMATCHLEN ) ) )
 151        {
 152                int i;
 153                if (memcmp(data,"DCC ",4))  {
 154                        data ++;
 155                        continue;
 156                }
 157
 158                dcc_p = data;
 159                data += 4;     /* point to DCC cmd */
 160
 161                for(i=0; i<NUM_DCCPROTO; i++)
 162                {
 163                        /*
 164                         * go through the table and hunt a match string
 165                         */
 166
 167                        if( memcmp(data, dccprotos[i].match, dccprotos[i].matchlen ) == 0 )
 168                        {
 169                                xtra_args = dccprotos[i].xtra_args;
 170                                data += dccprotos[i].matchlen;
 171
 172                                /*
 173                                 *      skip next string.
 174                                 */
 175
 176                                while( *data++ != ' ')
 177
 178                                        /*
 179                                         *      must still parse, at least, "AAAAAAAA P\x01\n",
 180                                         *      12 bytes left.
 181                                         */
 182                                        if (data > (data_limit-12)) return 0;
 183
 184
 185                                addr_beg_p = data;
 186
 187                                /*
 188                                 *      client bound address in dec base
 189                                 */
 190
 191                                s_addr = simple_strtoul(data,&data,10);
 192                                if (*data++ !=' ')
 193                                        continue;
 194
 195                                /*
 196                                 *      client bound port in dec base
 197                                 */
 198
 199                                s_port = simple_strtoul(data,&data,10);
 200                                addr_end_p = data;
 201
 202                                /*
 203                                 *      should check args consistency?
 204                                 */
 205
 206                                while(xtra_args) {
 207                                        if (*data != ' ')
 208                                                break;
 209                                        data++;
 210                                        simple_strtoul(data,&data,10);
 211                                        xtra_args--;
 212                                }
 213
 214                                if (xtra_args != 0) continue;
 215
 216                                /*
 217                                 *      terminators.
 218                                 */
 219
 220                                if (data[0] != 0x01)
 221                                        continue;
 222                                if (data[1]!='\r' && data[1]!='\n')
 223                                        continue;
 224
 225                                /*
 226                                 *      Now create an masquerade entry for it
 227                                 *      must set NO_DPORT and NO_DADDR because
 228                                 *      connection is requested by another client.
 229                                 */
 230
 231                                n_ms = ip_masq_new(IPPROTO_TCP,
 232                                                maddr, 0,
 233                                                htonl(s_addr),htons(s_port),
 234                                                0, 0,
 235                                                IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR);
 236                                if (n_ms==NULL)
 237                                        return 0;
 238
 239                                /*
 240                                 * Replace the old "address port" with the new one
 241                                 */
 242
 243                                buf_len = sprintf(buf,"%lu %u",
 244                                                ntohl(n_ms->maddr),ntohs(n_ms->mport));
 245
 246                                /*
 247                                 * Calculate required delta-offset to keep TCP happy
 248                                 */
 249
 250                                diff = buf_len - (addr_end_p-addr_beg_p);
 251
 252                                *addr_beg_p = '\0';
 253                                IP_MASQ_DEBUG(1-debug, "masq_irc_out(): '%s' %X:%X detected (diff=%d)\n", dcc_p, s_addr,s_port, diff);
 254
 255                                /*
 256                                 *      No shift.
 257                                 */
 258
 259                                if (diff==0) {
 260                                        /*
 261                                         * simple case, just copy.
 262                                         */
 263                                        memcpy(addr_beg_p,buf,buf_len);
 264                                } else {
 265
 266                                        *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
 267                                                        addr_beg_p, addr_end_p-addr_beg_p,
 268                                                        buf, buf_len);
 269                                }
 270                                ip_masq_listen(n_ms);
 271                                ip_masq_put(n_ms);
 272                                return diff;
 273                        }
 274                }
 275        }
 276        return 0;
 277
 278}
 279
 280/*
 281 *      Main irc object
 282 *      You need 1 object per port in case you need
 283 *      to offer also other used irc ports (6665,6666,etc),
 284 *      they will share methods but they need own space for
 285 *      data. 
 286 */
 287
 288struct ip_masq_app ip_masq_irc = {
 289        NULL,                   /* next */
 290        "irc",                  /* name */
 291        0,                      /* type */
 292        0,                      /* n_attach */
 293        masq_irc_init_1,        /* init_1 */
 294        masq_irc_done_1,        /* done_1 */
 295        masq_irc_out,           /* pkt_out */
 296        NULL                    /* pkt_in */
 297};
 298
 299/*
 300 *      ip_masq_irc initialization
 301 */
 302
 303__initfunc(int ip_masq_irc_init(void))
 304{
 305        int i, j;
 306
 307        for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
 308                if (ports[i]) {
 309                        if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
 310                                                            GFP_KERNEL)) == NULL)
 311                                return -ENOMEM;
 312                        memcpy(masq_incarnations[i], &ip_masq_irc, sizeof(struct ip_masq_app));
 313                        if ((j = register_ip_masq_app(masq_incarnations[i], 
 314                                                      IPPROTO_TCP, 
 315                                                      ports[i]))) {
 316                                return j;
 317                        }
 318                        IP_MASQ_DEBUG(1-debug,
 319                                        "Irc: loaded support on port[%d] = %d\n",
 320                               i, ports[i]);
 321                } else {
 322                        /* To be safe, force the incarnation table entry to NULL */
 323                        masq_incarnations[i] = NULL;
 324                }
 325        }
 326        return 0;
 327}
 328
 329/*
 330 *      ip_masq_irc fin.
 331 */
 332
 333int ip_masq_irc_done(void)
 334{
 335        int i, j, k;
 336
 337        k=0;
 338        for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
 339                if (masq_incarnations[i]) {
 340                        if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
 341                                k = j;
 342                        } else {
 343                                kfree(masq_incarnations[i]);
 344                                masq_incarnations[i] = NULL;
 345                                IP_MASQ_DEBUG(1-debug, "Irc: unloaded support on port[%d] = %d\n",
 346                                       i, ports[i]);
 347                        }
 348                }
 349        }
 350        return k;
 351}
 352
 353
 354#ifdef MODULE
 355EXPORT_NO_SYMBOLS;
 356
 357int init_module(void)
 358{
 359        if (ip_masq_irc_init() != 0)
 360                return -EIO;
 361        return 0;
 362}
 363
 364void cleanup_module(void)
 365{
 366        if (ip_masq_irc_done() != 0)
 367                printk(KERN_INFO "ip_masq_irc: can't remove module");
 368}
 369
 370#endif /* MODULE */
 371
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.