Index: iptables-1.3.8/extensions/.layer7-test =================================================================== --- /dev/null +++ iptables-1.3.8/extensions/.layer7-test @@ -0,0 +1,2 @@ +#! /bin/sh +[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_layer7.h ] && echo layer7 Index: iptables-1.3.8/extensions/libipt_layer7.c =================================================================== --- /dev/null +++ iptables-1.3.8/extensions/libipt_layer7.c @@ -0,0 +1,394 @@ +/* + Shared library add-on to iptables to add layer 7 matching support. + + By Matthew Strait , Oct 2003. + + http://l7-filter.sf.net + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version + 2 of the License, or (at your option) any later version. + http://www.gnu.org/licenses/gpl.txt + + Based on libipt_string.c (C) 2000 Emmanuel Roger +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_FN_LEN 256 + +static char l7dir[MAX_FN_LEN] = "\0"; + +/* Function which prints out usage message. */ +static void help(void) +{ + printf( + "LAYER7 match v%s options:\n" + "--l7dir : Look for patterns here instead of /etc/l7-protocols/\n" + " (--l7dir must be specified before --l7proto if used!)\n" + "--l7proto [!] : Match the protocol defined in /etc/l7-protocols/name.pat\n", + IPTABLES_VERSION); + fputc('\n', stdout); +} + +static struct option opts[] = { + { .name = "l7proto", .has_arg = 1, .flag = 0, .val = '1' }, + { .name = "l7dir", .has_arg = 1, .flag = 0, .val = '2' }, + { .name = 0 } +}; + +/* reads filename, puts protocol info into layer7_protocol_info, number of protocols to numprotos */ +int parse_protocol_file(char * filename, const unsigned char * protoname, struct ipt_layer7_info *info) +{ + FILE * f; + char * line = NULL; + size_t len = 0; + + enum { protocol, pattern, done } datatype = protocol; + + f = fopen(filename, "r"); + + if(!f) + return 0; + + while(getline(&line, &len, f) != -1) + { + if(strlen(line) < 2 || line[0] == '#') + continue; + + /* strip the pesky newline... */ + if(line[strlen(line) - 1] == '\n') + line[strlen(line) - 1] = '\0'; + + if(datatype == protocol) + { + /* Ignore everything on the line beginning with the + first space or tab . For instance, this allows the + protocol line in http.pat to be "http " (or + "http I am so cool") instead of just "http". */ + if(strchr(line, ' ')){ + char * space = strchr(line, ' '); + space[0] = '\0'; + } + if(strchr(line, '\t')){ + char * space = strchr(line, '\t'); + space[0] = '\0'; + } + + /* sanity check. First non-comment non-blank + line must be the same as the file name. */ + if(strcmp(line, protoname)) + exit_error(OTHER_PROBLEM, + "Protocol name (%s) doesn't match file name (%s). Bailing out\n", + line, filename); + + if(strlen(line) >= MAX_PROTOCOL_LEN) + exit_error(PARAMETER_PROBLEM, + "Protocol name in %s too long!", filename); + strncpy(info->protocol, line, MAX_PROTOCOL_LEN); + + datatype = pattern; + } + else if(datatype == pattern) + { + if(strlen(line) >= MAX_PATTERN_LEN) + exit_error(PARAMETER_PROBLEM, "Pattern in %s too long!", filename); + strncpy(info->pattern, line, MAX_PATTERN_LEN); + + datatype = done; + break; + } + else + exit_error(OTHER_PROBLEM, "Internal error"); + } + + if(datatype != done) + exit_error(OTHER_PROBLEM, "Failed to get all needed data from %s", filename); + + if(line) free(line); + fclose(f); + + return 1; + +/* + fprintf(stderr, "protocol: %s\npattern: %s\n\n", + info->protocol, + info->pattern); +*/ +} + +static int hex2dec(char c) +{ + switch (c) + { + case '0' ... '9': + return c - '0'; + case 'a' ... 'f': + return c - 'a' + 10; + case 'A' ... 'F': + return c - 'A' + 10; + default: + exit_error(OTHER_PROBLEM, "hex2dec: bad value!\n"); + return 0; + } +} + +/* takes a string with \xHH escapes and returns one with the characters +they stand for */ +static char * pre_process(char * s) +{ + char * result = malloc(strlen(s) + 1); + int sindex = 0, rindex = 0; + while( sindex < strlen(s) ) + { + if( sindex + 3 < strlen(s) && + s[sindex] == '\\' && s[sindex+1] == 'x' && + isxdigit(s[sindex + 2]) && isxdigit(s[sindex + 3]) ) + { + /* carefully remember to call tolower here... */ + result[rindex] = tolower( hex2dec(s[sindex + 2])*16 + + hex2dec(s[sindex + 3] ) ); + + switch ( result[rindex] ) + { + case 0x24: + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2e: + case 0x3f: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x5e: + case 0x7c: + fprintf(stderr, + "Warning: layer7 regexp contains a control character, %c, in hex (\\x%c%c).\n" + "I recommend that you write this as %c or \\%c, depending on what you meant.\n", + result[rindex], s[sindex + 2], s[sindex + 3], result[rindex], result[rindex]); + break; + case 0x00: + fprintf(stderr, + "Warning: null (\\x00) in layer7 regexp. A null terminates the regexp string!\n"); + break; + default: + break; + } + + + sindex += 3; /* 4 total */ + } + else + result[rindex] = tolower(s[sindex]); + + sindex++; + rindex++; + } + result[rindex] = '\0'; + + return result; +} + +#define MAX_SUBDIRS 128 +char ** readl7dir(char * dirname) +{ + DIR * scratchdir; + struct dirent ** namelist; + char ** subdirs = malloc(MAX_SUBDIRS * sizeof(char *)); + + int n, d = 1; + subdirs[0] = ""; + + n = scandir(dirname, &namelist, 0, alphasort); + + if (n < 0) + { + perror("scandir"); + exit_error(OTHER_PROBLEM, "Couldn't open %s\n", dirname); + } + else + { + while(n--) + { + char fulldirname[MAX_FN_LEN]; + + snprintf(fulldirname, MAX_FN_LEN, "%s/%s", dirname, namelist[n]->d_name); + + if((scratchdir = opendir(fulldirname)) != NULL) + { + closedir(scratchdir); + + if(!strcmp(namelist[n]->d_name, ".") || + !strcmp(namelist[n]->d_name, "..")) + /* do nothing */ ; + else + { + subdirs[d] = malloc(strlen(namelist[n]->d_name) + 1); + strcpy(subdirs[d], namelist[n]->d_name); + d++; + if(d >= MAX_SUBDIRS - 1) + { + fprintf(stderr, + "Too many subdirectories, skipping the rest!\n"); + break; + } + } + } + free(namelist[n]); + } + free(namelist); + } + + subdirs[d] = NULL; + + return subdirs; +} + +static void +parse_layer7_protocol(const unsigned char *s, struct ipt_layer7_info *info) +{ + char filename[MAX_FN_LEN]; + char * dir = NULL; + char ** subdirs; + int n = 0, done = 0; + + if(strlen(l7dir) > 0) + dir = l7dir; + else + dir = "/etc/l7-protocols"; + + subdirs = readl7dir(dir); + + while(subdirs[n] != NULL) + { + int c = snprintf(filename, MAX_FN_LEN, "%s/%s/%s.pat", dir, subdirs[n], s); + + //fprintf(stderr, "Trying to find pattern in %s ... ", filename); + + if(c > MAX_FN_LEN) + { + exit_error(OTHER_PROBLEM, + "Filename beginning with %s is too long!\n", filename); + } + + /* read in the pattern from the file */ + if(parse_protocol_file(filename, s, info)) + { + //fprintf(stderr, "found\n"); + done = 1; + break; + } + + //fprintf(stderr, "not found\n"); + + n++; + } + + if(!done) + exit_error(OTHER_PROBLEM, + "Couldn't find a pattern definition file for %s.\n", s); + + /* process \xHH escapes and tolower everything. (our regex lib has no + case insensitivity option.) */ + strncpy(info->pattern, pre_process(info->pattern), MAX_PATTERN_LEN); +} + +/* Function which parses command options; returns true if it ate an option */ +static int parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, unsigned int *nfcache, + struct ipt_entry_match **match) +{ + struct ipt_layer7_info *layer7info = + (struct ipt_layer7_info *)(*match)->data; + + switch (c) { + case '1': + check_inverse(optarg, &invert, &optind, 0); + parse_layer7_protocol(argv[optind-1], layer7info); + if (invert) + layer7info->invert = 1; + *flags = 1; + break; + + case '2': + /* not going to use this, but maybe we need to strip a ! anyway (?) */ + check_inverse(optarg, &invert, &optind, 0); + + if(strlen(argv[optind-1]) >= MAX_FN_LEN) + exit_error(PARAMETER_PROBLEM, "directory name too long\n"); + + strncpy(l7dir, argv[optind-1], MAX_FN_LEN); + + *flags = 1; + break; + + default: + return 0; + } + + return 1; +} + +/* Final check; must have specified --l7proto */ +static void final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, + "LAYER7 match: You must specify `--l7proto'"); +} + +static void print_protocol(char s[], int invert, int numeric) +{ + fputs("l7proto ", stdout); + if (invert) fputc('!', stdout); + printf("%s ", s); +} + +/* Prints out the matchinfo. */ +static void print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) +{ + printf("LAYER7 "); + + print_protocol(((struct ipt_layer7_info *)match->data)->protocol, + ((struct ipt_layer7_info *)match->data)->invert, numeric); +} +/* Saves the union ipt_matchinfo in parsable form to stdout. */ +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + const struct ipt_layer7_info *info = + (const struct ipt_layer7_info*) match->data; + + printf("--l7proto %s%s ", (info->invert) ? "! ": "", info->protocol); +} + +static struct iptables_match layer7 = { + .name = "layer7", + .version = IPTABLES_VERSION, + .size = IPT_ALIGN(sizeof(struct ipt_layer7_info)), + .userspacesize = IPT_ALIGN(sizeof(struct ipt_layer7_info)), + .help = &help, + .parse = &parse, + .final_check = &final_check, + .print = &print, + .save = &save, + .extra_opts = opts +}; + +void _init(void) +{ + register_match(&layer7); +} Index: iptables-1.3.8/extensions/libipt_layer7.man =================================================================== --- /dev/null +++ iptables-1.3.8/extensions/libipt_layer7.man @@ -0,0 +1,14 @@ +This module matches packets based on the application layer data of +their connections. It uses regular expression matching to compare +the application layer data to regular expressions found it the layer7 +configuration files. This is an experimental module which can be found at +http://l7-filter.sf.net. It takes two options. +.TP +.BI "--l7proto " "\fIprotocol\fP" +Match the specified protocol. The protocol name must match a file +name in /etc/l7-protocols/ or one of its first-level child directories. +.TP +.BI "--l7dir " "\fIdirectory\fP" +Use \fIdirectory\fP instead of /etc/l7-protocols/. This option must be +specified before --l7proto. + id='n276' href='#n276'>276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
### GNU GENERAL PUBLIC LICENSE

Version 2, June 1991

    Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA

    Everyone is permitted to copy and distribute verbatim copies
    of this license document, but changing it is not allowed.

### Preamble

The licenses for most software are designed to take away your freedom
to share and change it. By contrast, the GNU General Public License is
intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.

When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the software, or if you modify it.

For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.

We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on,
we want its recipients to know that what they have is not the
original, so that any problems introduced by others will not reflect
on the original authors' reputations.

Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at
all.

The precise terms and conditions for copying, distribution and
modification follow.

### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION