95c62a860a2e0343978485d7d3e7408c8dd6d2fb
[openwrt.git] / package / iptables / patches / 02-layer7-1.5nbd.patch
1 diff -urN iptables.old/extensions/.layer7-test iptables.dev/extensions/.layer7-test
2 --- iptables.old/extensions/.layer7-test        1970-01-01 01:00:00.000000000 +0100
3 +++ iptables.dev/extensions/.layer7-test        2005-11-10 16:57:51.819381000 +0100
4 @@ -0,0 +1,2 @@
5 +#! /bin/sh
6 +[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_layer7.h ] && echo layer7
7 diff -urN iptables.old/extensions/ipt_layer7.h iptables.dev/extensions/ipt_layer7.h
8 --- iptables.old/extensions/ipt_layer7.h        1970-01-01 01:00:00.000000000 +0100
9 +++ iptables.dev/extensions/ipt_layer7.h        2005-11-10 17:46:32.933599750 +0100
10 @@ -0,0 +1,27 @@
11 +/* 
12 +  By Matthew Strait <quadong@users.sf.net>, Dec 2003.
13 +  http://l7-filter.sf.net
14 +
15 +  This program is free software; you can redistribute it and/or
16 +  modify it under the terms of the GNU General Public License
17 +  as published by the Free Software Foundation; either version
18 +  2 of the License, or (at your option) any later version.
19 +  http://www.gnu.org/licenses/gpl.txt
20 +*/
21 +
22 +#ifndef _IPT_LAYER7_H
23 +#define _IPT_LAYER7_H
24 +
25 +#define MAX_PATTERN_LEN 8192
26 +#define MAX_PROTOCOL_LEN 256
27 +
28 +typedef char *(*proc_ipt_search) (char *, char, char *);
29 +
30 +struct ipt_layer7_info {
31 +    char protocol[MAX_PROTOCOL_LEN];
32 +    char invert:1;
33 +    char pattern[MAX_PATTERN_LEN];
34 +       char pkt;
35 +};
36 +
37 +#endif /* _IPT_LAYER7_H */
38 diff -urN iptables.old/extensions/libipt_layer7.c iptables.dev/extensions/libipt_layer7.c
39 --- iptables.old/extensions/libipt_layer7.c     1970-01-01 01:00:00.000000000 +0100
40 +++ iptables.dev/extensions/libipt_layer7.c     2005-11-10 17:47:01.399378750 +0100
41 @@ -0,0 +1,358 @@
42 +/* 
43 +   Shared library add-on to iptables to add layer 7 matching support. 
44 +  
45 +   By Matthew Strait <quadong@users.sf.net>, Oct 2003.
46 +
47 +   http://l7-filter.sf.net 
48 +
49 +   This program is free software; you can redistribute it and/or
50 +   modify it under the terms of the GNU General Public License
51 +   as published by the Free Software Foundation; either version
52 +   2 of the License, or (at your option) any later version.
53 +   http://www.gnu.org/licenses/gpl.txt
54 +
55 +   Based on libipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be>
56 +*/
57 +
58 +#define _GNU_SOURCE
59 +#include <stdio.h>
60 +#include <netdb.h>
61 +#include <string.h>
62 +#include <stdlib.h>
63 +#include <getopt.h>
64 +#include <ctype.h>
65 +#include <dirent.h>
66 +
67 +#include <iptables.h>
68 +#include "ipt_layer7.h"
69 +
70 +#define MAX_FN_LEN 256
71 +
72 +static char l7dir[MAX_FN_LEN] = "\0";
73 +
74 +/* Function which prints out usage message. */
75 +static void help(void)
76 +{
77 +       printf(
78 +       "LAYER7 match v%s options:\n"
79 +       "--l7dir <directory>  : Look for patterns here instead of /etc/l7-protocols/\n"
80 +       "                       (--l7dir must be specified before --l7proto if used!)\n"
81 +       "--l7proto [!] <name> : Match the protocol defined in /etc/l7-protocols/name.pat\n"
82 +       "--l7pkt              : Skip connection tracking and match individual packets\n",
83 +       IPTABLES_VERSION);
84 +       fputc('\n', stdout);
85 +}
86 +
87 +static struct option opts[] = {
88 +       { .name = "l7proto", .has_arg = 1, .flag = 0, .val = '1' },
89 +       { .name = "l7dir",   .has_arg = 1, .flag = 0, .val = '2' },
90 +       { .name = "l7pkt",   .has_arg = 0, .flag = 0, .val = '3' },
91 +       { .name = 0 }
92 +};
93 +
94 +/* reads filename, puts protocol info into layer7_protocol_info, number of protocols to numprotos */
95 +int parse_protocol_file(char * filename, const unsigned char * protoname, struct ipt_layer7_info *info)
96 +{
97 +       FILE * f;
98 +       char * line = NULL;
99 +       size_t len = 0;
100 +
101 +       enum { protocol, pattern, done } datatype = protocol;
102 +
103 +       f = fopen(filename, "r");
104 +
105 +       if(!f)
106 +               return 0;
107 +
108 +       while(getline(&line, &len, f) != -1)
109 +       {
110 +               if(strlen(line) < 2 || line[0] == '#')
111 +                       continue;
112 +
113 +               /* strip the pesky newline... */
114 +               if(line[strlen(line) - 1] == '\n')
115 +                       line[strlen(line) - 1] = '\0';
116 +
117 +               if(datatype == protocol)
118 +               {
119 +                       if(strcmp(line, protoname))
120 +                               exit_error(OTHER_PROBLEM, 
121 +                                       "Protocol name (%s) doesn't match file name (%s).  Bailing out\n",
122 +                                       protoname, filename);
123 +
124 +                       if(strlen(line) >= MAX_PROTOCOL_LEN)
125 +                                exit_error(PARAMETER_PROBLEM, 
126 +                                       "Protocol name in %s too long!", filename);
127 +                       strncpy(info->protocol, line, MAX_PROTOCOL_LEN);
128 +
129 +                       datatype = pattern; 
130 +               }
131 +               else if(datatype == pattern)
132 +               {
133 +                       if(strlen(line) >= MAX_PATTERN_LEN)
134 +                                exit_error(PARAMETER_PROBLEM, "Pattern in %s too long!", filename);
135 +                       strncpy(info->pattern, line, MAX_PATTERN_LEN);
136 +                       
137 +                       datatype = done;                        
138 +                       break;
139 +               }
140 +               else
141 +                       exit_error(OTHER_PROBLEM, "Internal error");
142 +       }
143 +
144 +       if(datatype != done)
145 +               exit_error(OTHER_PROBLEM, "Failed to get all needed data from %s", filename);
146 +
147 +       if(line) free(line);
148 +       fclose(f);
149 +
150 +       return 1;
151 +
152 +/*
153 +       fprintf(stderr, "protocol: %s\npattern: %s\n\n", 
154 +                       info->protocol,
155 +                       info->pattern);
156 +*/
157 +}
158 +
159 +static int hex2dec(char c)
160 +{
161 +        switch (c)
162 +        {
163 +                case '0' ... '9':
164 +                        return c - '0';
165 +                case 'a' ... 'f':
166 +                        return c - 'a' + 10;
167 +                case 'A' ... 'F':
168 +                        return c - 'A' + 10;
169 +                default:
170 +                        exit_error(OTHER_PROBLEM, "hex2dec: bad value!\n");
171 +                        return 0;
172 +        }
173 +}
174 +
175 +/* takes a string with \xHH escapes and returns one with the characters 
176 +they stand for */
177 +static char * pre_process(char * s)
178 +{
179 +       char * result = malloc(strlen(s) + 1);
180 +       int sindex = 0, rindex = 0;
181 +        while( sindex < strlen(s) )
182 +        {
183 +            if( sindex + 3 < strlen(s) &&
184 +                s[sindex] == '\\' && s[sindex+1] == 'x' && 
185 +                isxdigit(s[sindex + 2]) && isxdigit(s[sindex + 3]) ) 
186 +                {
187 +                        /* carefully remember to call tolower here... */
188 +                        result[rindex] = tolower( hex2dec(s[sindex + 2])*16 +
189 +                                                  hex2dec(s[sindex + 3] ) );
190 +                        sindex += 3; /* 4 total */
191 +                }
192 +                else
193 +                        result[rindex] = tolower(s[sindex]);
194 +
195 +               sindex++; 
196 +               rindex++;
197 +        }
198 +       result[rindex] = '\0';
199 +
200 +       return result;
201 +}
202 +
203 +#define MAX_SUBDIRS 128
204 +char ** readl7dir(char * dirname)
205 +{
206 +        DIR             * scratchdir;
207 +        struct dirent   ** namelist;
208 +       char ** subdirs = malloc(MAX_SUBDIRS * sizeof(char *));
209 +
210 +        int n, d = 1;
211 +       subdirs[0] = "";
212 +
213 +        n = scandir(dirname, &namelist, 0, alphasort);
214 +
215 +       if (n < 0)
216 +       {
217 +            perror("scandir");
218 +           exit_error(OTHER_PROBLEM, "Couldn't open %s\n", dirname);
219 +       }
220 +        else 
221 +       {
222 +               while(n--) 
223 +               {
224 +                       char fulldirname[MAX_FN_LEN];
225 +
226 +                       snprintf(fulldirname, MAX_FN_LEN, "%s/%s", dirname, namelist[n]->d_name);
227 +
228 +                       if((scratchdir = opendir(fulldirname)) != NULL)
229 +                       {
230 +                               closedir(scratchdir);
231 +
232 +                               if(!strcmp(namelist[n]->d_name, ".") || 
233 +                                  !strcmp(namelist[n]->d_name, ".."))
234 +                                       /* do nothing */ ;
235 +                               else
236 +                               {
237 +                                       subdirs[d] = malloc(strlen(namelist[n]->d_name) + 1);
238 +                                       strcpy(subdirs[d], namelist[n]->d_name);
239 +                                       d++;
240 +                                       if(d >= MAX_SUBDIRS - 1)
241 +                                       {
242 +                                               fprintf(stderr, 
243 +                                                 "Too many subdirectories, skipping the rest!\n");
244 +                                               break;
245 +                                       }
246 +                               }
247 +                       }
248 +                       free(namelist[n]);
249 +               }
250 +               free(namelist);
251 +        }
252 +       
253 +       subdirs[d] = NULL;
254 +
255 +       return subdirs;
256 +}
257 +
258 +static void
259 +parse_layer7_protocol(const unsigned char *s, struct ipt_layer7_info *info)
260 +{
261 +       char filename[MAX_FN_LEN];
262 +       char * dir = NULL;
263 +       char ** subdirs;
264 +       int n = 0, done = 0;
265 +
266 +       if(strlen(l7dir) > 0)
267 +               dir = l7dir;
268 +       else
269 +               dir = "/etc/l7-protocols";
270 +
271 +       subdirs = readl7dir(dir);
272 +
273 +       while(subdirs[n] != NULL)
274 +       {
275 +               int c = snprintf(filename, MAX_FN_LEN, "%s/%s/%s.pat", dir, subdirs[n], s);
276 +
277 +               //fprintf(stderr, "Trying to find pattern in %s ... ", filename);
278 +
279 +               if(c > MAX_FN_LEN)
280 +               {
281 +                       exit_error(OTHER_PROBLEM, 
282 +                               "Filename beginning with %s is too long!\n", filename);
283 +               }
284 +
285 +               /* read in the pattern from the file */
286 +               if(parse_protocol_file(filename, s, info))
287 +               {
288 +                       //fprintf(stderr, "found\n");
289 +                       done = 1;
290 +                       break;
291 +               }
292 +               
293 +               //fprintf(stderr, "not found\n");
294 +
295 +               n++;
296 +       }
297 +
298 +       if(!done)
299 +               exit_error(OTHER_PROBLEM, 
300 +                       "Couldn't find a pattern definition file for %s.\n", s);
301 +
302 +       /* process \xHH escapes and tolower everything. (our regex lib has no
303 +       case insensitivity option.) */
304 +       strncpy(info->pattern, pre_process(info->pattern), MAX_PATTERN_LEN);
305 +}
306 +
307 +/* Function which parses command options; returns true if it ate an option */
308 +static int parse(int c, char **argv, int invert, unsigned int *flags,
309 +      const struct ipt_entry *entry, unsigned int *nfcache,
310 +      struct ipt_entry_match **match)
311 +{
312 +       struct ipt_layer7_info *layer7info = 
313 +               (struct ipt_layer7_info *)(*match)->data;
314 +
315 +       switch (c) {
316 +       case '1':
317 +               check_inverse(optarg, &invert, &optind, 0);
318 +               parse_layer7_protocol(argv[optind-1], layer7info);
319 +               if (invert)
320 +                       layer7info->invert = 1;
321 +               *flags = 1;
322 +               break;
323 +
324 +       case '2':
325 +               /* not going to use this, but maybe we need to strip a ! anyway (?) */
326 +               check_inverse(optarg, &invert, &optind, 0);
327 +
328 +               if(strlen(argv[optind-1]) >= MAX_FN_LEN)
329 +                       exit_error(PARAMETER_PROBLEM, "directory name too long\n");
330 +
331 +               strncpy(l7dir, argv[optind-1], MAX_FN_LEN);
332 +
333 +               *flags = 1;
334 +               break;
335 +       case '3':
336 +               layer7info->pkt = 1;
337 +               break;
338 +
339 +       default:
340 +               return 0;
341 +       }
342 +
343 +       return 1;
344 +}
345 +
346 +/* Final check; must have specified --pattern. */
347 +static void final_check(unsigned int flags)
348 +{
349 +       if (!flags)
350 +               exit_error(PARAMETER_PROBLEM,
351 +                          "LAYER7 match: You must specify `--pattern'");
352 +}
353 +
354 +static void print_protocol(char s[], int invert, int numeric)
355 +{
356 +       fputs("l7proto ", stdout);
357 +       if (invert) fputc('!', stdout);
358 +       printf("%s ", s);
359 +}
360 +
361 +/* Prints out the matchinfo. */
362 +static void print(const struct ipt_ip *ip,
363 +      const struct ipt_entry_match *match,
364 +      int numeric)
365 +{
366 +       printf("LAYER7 ");
367 +
368 +       print_protocol(((struct ipt_layer7_info *)match->data)->protocol,
369 +                 ((struct ipt_layer7_info *)match->data)->invert, numeric);
370 +
371 +       if (((struct ipt_layer7_info *)match->data)->pkt)
372 +               printf("l7pkt ");
373 +}
374 +/* Saves the union ipt_matchinfo in parsable form to stdout. */
375 +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
376 +{
377 +        const struct ipt_layer7_info *info =
378 +            (const struct ipt_layer7_info*) match->data;
379 +
380 +        printf("--l7proto %s%s ", (info->invert)   ? "! ": "", info->protocol);
381 +}
382 +
383 +static struct iptables_match layer7 = { 
384 +    .name          = "layer7",
385 +    .version       = IPTABLES_VERSION,
386 +    .size          = IPT_ALIGN(sizeof(struct ipt_layer7_info)),
387 +    .userspacesize = IPT_ALIGN(sizeof(struct ipt_layer7_info)),
388 +    .help          = &help,
389 +    .parse         = &parse,
390 +    .final_check   = &final_check,
391 +    .print         = &print,
392 +    .save          = &save,
393 +    .extra_opts    = opts
394 +};
395 +
396 +void _init(void)
397 +{
398 +       register_match(&layer7);
399 +}
400 diff -urN iptables.old/extensions/libipt_layer7.man iptables.dev/extensions/libipt_layer7.man
401 --- iptables.old/extensions/libipt_layer7.man   1970-01-01 01:00:00.000000000 +0100
402 +++ iptables.dev/extensions/libipt_layer7.man   2005-11-10 16:57:51.823381250 +0100
403 @@ -0,0 +1,13 @@
404 +This module matches packets based on the application layer data of 
405 +their connections.  It uses regular expression matching to compare 
406 +the application layer data to regular expressions found it the layer7 
407 +configuration files.  This is an experimental module which can be found at 
408 +http://l7-filter.sf.net.  It takes two options.
409 +.TP
410 +.BI "--l7proto " "\fIprotocol\fP"
411 +Match the specified protocol.  The protocol name must match a file 
412 +name in /etc/l7-protocols/
413 +.TP
414 +.BI "--l7dir " "\fIdirectory\fP"
415 +Use \fIdirectory\fP instead of /etc/l7-protocols/
416 +