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