├── CHANGELOG ├── README ├── for_older_iptables ├── iptables-1.3-for-kernel-2.6.20forward-layer7-2.21.patch ├── iptables-1.3-for-kernel-pre2.6.20-layer7-2.21.patch ├── iptables-1.4-for-kernel-2.6.20forward-layer7-2.21.patch └── iptables-1.4.1.1-for-kernel-2.6.20forward │ ├── libxt_layer7.c │ └── libxt_layer7.man ├── for_older_kernels ├── kernel-2.6.0-2.6.8.1-layer7-0.9.2.patch ├── kernel-2.6.11-2.6.12-layer7-1.4.patch ├── kernel-2.6.13-2.6.16-layer7-2.2.patch ├── kernel-2.6.17-layer7-2.5.patch ├── kernel-2.6.18-2.6.19-layer7-2.9.patch ├── kernel-2.6.20-2.6.21-layer7-2.16.1.patch ├── kernel-2.6.22-2.6.24-layer7-2.18.patch └── kernel-2.6.9-2.6.10-layer7-1.2.patch ├── iptables-1.4.3forward-for-kernel-2.6.20forward ├── libxt_layer7.c └── libxt_layer7.man ├── kernel-2.4-layer7-2.22.patch ├── kernel-2.6.25-2.6.28-layer7-2.22.patch └── kernel-2.6.35-layer7-2.23.patch /CHANGELOG: -------------------------------------------------------------------------------- 1 | v2.23 - Updated for Linux 2.6.35 and up. New API changes were 2 | introduced in the Kernel release 2.6.35 and some (specifically 3 | to xt_match struct found in linux/netfilter/x_tables.h), affected 4 | l7-filter. Patch by Huascar Tejeda. 5 | 6 | 7 | v2.22 - Updated for iptables 1.4.3 and 1.4.4. Organized files for older 8 | iptables releases using a similar system as the kernel patches. 9 | 10 | 11 | v2.21 - Updated for Linux 2.6.27 and 2.6.28. Removed #if 12 | LINUX_VERSION_CODE statements that can't ever be true because of how 13 | these patches are organized. 14 | 15 | 16 | v2.20 - Cleaned iptables files. For iptables 1.4.1.1 forward, removed 17 | .layer7-test, fixed help text, conformed to current negation convention 18 | ('!' flag goes before options rather than between option and argument), 19 | and so forth. Now distributing xt_layer7.{c,man} as individual files 20 | rather than a patch. No change to kernel patches. 21 | 22 | 23 | v2.19 - Update iptables patch for iptables 1.4.1.1. Note that iptables 24 | now uses a different compile procedure. Corrected MODULE_VERSION 25 | numbers on all kernel patches. 26 | 27 | 28 | v2.18 - Updated 2.6 patch for 2.6.25. Removed a stray "asdf" from 29 | 2.6.22-2.6.24 patch. 30 | 31 | 32 | v2.17 - Updated 2.6 patch for 2.6.24. 33 | 34 | 35 | v2.16.1 - Fixed and expanded documentation here and in README. 36 | 37 | 38 | v2.16 - iptables patch: Added a patch that works with iptables 1.4.0rc1. 39 | 40 | 41 | v2.15 - 2.6 patches: Added /proc/net/ip_conntrack code in the new place that 42 | it has to be for Linux 2.6.20 and up. Tested with 2.6.20.8, 2.6.21.1, 43 | 2.6.22-rc7 and 2.6.23.1. 44 | 45 | 46 | v2.14 - 2.6 patches: Added missing dependency (NF_CT_ACCT) and fixed 47 | Makefile in 2.6.20-21 and 2.6.22. 48 | 49 | 50 | v2.13 - 2.6 patch: Fixed compiler error on 64 bit platforms. 51 | 52 | 53 | v2.12.1 - Fixed documentation on iptables patch to reflect correct kernel 54 | version boundary. 55 | 56 | 57 | v2.12 - Updated iptables patch. Now there are two iptables patches, one 58 | for kernels before 2.6.20 and one for 2.6.20 forward. 59 | 60 | 61 | v2.11 - Added missing nf_ct_l3proto_module_put() call to 2.6.20/2.6.21 62 | patch. Added patch for 2.6.22. Some stylistic changes to 2.6 kernel 63 | code. 64 | 65 | 66 | v2.10 - Added a missing check to the pattern parsing code in iptables. 67 | Updated kernel patch for 2.6.20+, using paranoid locking. Some stylistic 68 | changes to 2.6 kernel code. No changes to 2.4. 69 | 70 | 71 | v2.9 - Changes to 2.6 version: Implemented "unset" which matches 72 | connections which are still being tested with no match. No changes to 73 | 2.4 version or iptables. 74 | 75 | 76 | v2.8 - Changes to 2.6 version: Removed checkmatch() from ipt_layer7.c 77 | (fixes iptables' "Invalid argument" problem) and surpressed compiler 78 | warning about non-const skb in match(). Removed stray_code, since the 79 | new port is to userspace, where this is not necessary either. 80 | 81 | 82 | v2.7 - In 2.6 version, ipt_layer7 now automatically loads ip_conntrack. 83 | No changes to 2.4 version or iptables. Updated documentation slightly. 84 | 85 | 86 | v2.6 - No functional changes, just changed one line to conform to 2.6.18. 87 | 88 | 89 | v2.5 - Changes to iptables only 90 | 91 | - iptables now allows spaces or tabs after the protocol name in the 92 | protocol files. This allows, for instance, "http " or "http I am the 93 | coolest!!!" instead of just "http" in http.pat. Pattern writers should 94 | stay conservative in what they send, however. 95 | 96 | 97 | v2.4.1 98 | 99 | - I had accidentally overwritten the 2.4 patch with a newer version of the 100 | 2.6 patch. Oops! It is now restored. 101 | 102 | 103 | v2.4 - Changes to 2.6 version only 104 | 105 | - Changed to using Deti Fliegl's match_globals in the regexp code 106 | for SMP safeness. (The code as a whole is still probably not SMP safe.) 107 | 108 | - Added Deti Fliegl's "if(!master_conntrack->layer7.app_data) return 0;" 109 | to add_data. 110 | 111 | - Removed whitespace at ends of lines to make quilt happy. 112 | 113 | 114 | v2.3 - No functional changes 115 | 116 | - Updated patch for 2.6.17. 117 | 118 | 119 | v2.2 120 | 121 | - Fixed type mismatch in debugging printk. 122 | 123 | - Updated for minor formatting changes in 2.6.16 that broke the old patch. 124 | 125 | 126 | v2.1 - iptables now issues warnings when regular expressions contain hex 127 | codes that are regexp control characters or null. No change to kernel 128 | patches. (Noted that kernel patch is now tested with 2.6.15.) 129 | 130 | 131 | v2.0 - No big changes. 132 | 133 | - iptables used to ask for --pattern if it didn't get --l7proto. Fixed. 134 | 135 | - Kernel patch is now aganst 2.6.14. This is just cosmetic, it still works 136 | with 2.6.13. 137 | 138 | - Cleaned up some #ifdef stuff in ipt_layer7.c 139 | 140 | - Added version information to kernel module. 141 | 142 | 143 | v2.0-beta - The maximum number of bytes examined can now be specified at 144 | module load time (rather than compile time). Increased the default 145 | numpackets to 10. 146 | 147 | 148 | v1.5 - No functional changes. 149 | 150 | - Updated 2.6 kernel patch for new lock syntax. 151 | 152 | - Removed init() from iptables (not necessary). 153 | 154 | - Made debugging messages less enthusiastic. 155 | 156 | v1.4 - Changed NSUBEXP back to 10 since it looks like our regexp library 157 | can't actually handle higher numbers properly. No change to iptables. 158 | 159 | 160 | v1.3 161 | 162 | - Brought the 2.4 patch up-to-date with the 2.6 patch. It now contains 163 | all the features that 2.6 does. (The 2.4 version still does not use 164 | CONFIG_IP_NF_CT_ACCT, so it is not necessary to apply that patch to make 165 | l7 work.) 166 | 167 | - Increased NSUBEXP from 10 to 16 in regexp.h to allow for longer 168 | regular expressions. 169 | 170 | - Removed extraneous .orig file from the iptables patch. 171 | 172 | - Module unloading in 2.4 now works. 173 | 174 | 175 | v1.2 - Bug fix release: 176 | 177 | - Fixed another (smaller, but significant) memory leak in 2.6 kernel. 178 | The fix is a bit of a hack and I'd like to fix it in a more satisfying 179 | way later. 180 | 181 | - Fixed compilation of 2.4 kernel on RH9 and other systems by adding 182 | another #include to ipt_layer7.c 183 | 184 | No change to iptables. 185 | 186 | 187 | v1.1 - Added patch for Linux 2.6.11.X. No real changes. 188 | 189 | 190 | v1.0.1 - Bug fix release: 191 | 192 | - Fixed memory leak in kernel. 193 | 194 | - Fixed iptables crash on AMD64. 195 | 196 | - Fixed kernel compilation problem on AMD64. 197 | 198 | This release does not yet work with Linux 2.6.11.X. Wait for v1.1 if 199 | you need that. (Should be soon.) 200 | 201 | 202 | v1.0 - No changes to 2.4 version or iptables. Shuffled around a bit of code 203 | in the 2.6 version so that it could patch cleanly to both 2.6.9 and 204 | 2.6.10. Included the previous version of 2.6 patch so that people using 205 | 2.6.0-2.6.8 don't have to get an older package. 206 | 207 | 208 | v1.0-rc1 - No changes to the 2.4 version or iptables. For 2.6: 209 | 210 | - Connections that have no match and are no longer being tested are now 211 | marked "unknown". 212 | 213 | - Now uses (and depends on) "Connection tracking flow accounting" 214 | (CONFIG_IP_NF_CT_ACCT). 215 | 216 | - Skbuffs are now linearized and error messages are net_ratelimited. 217 | 218 | 219 | v0.9.2 (retroactive) - Added a #include to 2.4 kernel patch so it would 220 | compile for more people. 221 | 222 | 223 | v0.9.1 - Changes to ipt_helper.c that aren't part of l7-filter had crept 224 | into the 2.6 patch of v0.9.0. They are now removed. No other changes. 225 | 226 | 227 | v0.9.0 - 2.4 version now should compile correctly if l7-filter is 228 | built-in. Fixed a significant bug which caused some patterns not to work 229 | (tolower was munging 'upper ascii' characters). No change to iptables. 230 | 231 | 232 | v0.8.2 - Iptables now uses modular man pages (as of v1.2.10). The iptables 233 | patch now conforms to this new format. No change to kernel. 234 | 235 | 236 | v0.8.1 - Made code slightly more paranoid about running out of memory. No 237 | change to iptables. 238 | 239 | 240 | v0.8 - Small improvements to locking code. All kmallocs should be 241 | checked now. Converted the regexp code into this century's C syntax. 242 | Added a patch for Linux 2.4. No change to iptables. 243 | 244 | 245 | v0.7 - Improvements to locking code. No change to iptables. 246 | 247 | 248 | v0.6.1 - Fixed places where iptables used --l7-proto instead of --l7proto. 249 | No change to kernel. 250 | 251 | 252 | v0.6 - Significant kernel code cleanup. Attempted to make code SMP safe with 253 | spin_lock() and GFP_ATOMIC. No change to iptables code. 254 | 255 | 256 | v0.5 - Initial release in this format. 257 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Please read this file and also: 2 | 3 | http://l7-filter.sf.net/README http://l7-filter.sf.net/HOWTO-kernel 4 | http://l7-filter.sf.net/protocols 5 | 6 | Mailing list: 7 | Or if you're shy: Matthew Strait 8 | 9 | In this directory you will find: 10 | 11 | ***** kernel patches ***** 12 | 13 | - kernel-2.6.35-2.23.patch 14 | 15 | This patch is against 2.6.35. 16 | 17 | - kernel-2.6.25-2.6.28-layer7-2.22.patch 18 | 19 | This patch is against 2.6.28. It will not work with 2.6.24.x or earlier. 20 | Hopefully, it works with future kernel versions (obviously we don't know yet). 21 | This package will NOT be updated just because a new kernel is released. 22 | Check http://l7-filter.sourceforge.net/kernelcompat for up-to-date 23 | compatibility information. 24 | 25 | - kernel-2.4-layer7-2.22.patch 26 | 27 | This patch is against 2.4.31. It is extremely likely that it will work with 28 | all future 2.4 versions. If you have some bizzare reason to use an older 29 | 2.4 kernel, check http://l7-filter.sourceforge.net/kernelcompat 30 | 31 | - for_older_kernels/ 32 | 33 | Here are files named 34 | "kernel-[kernel version range]-layer7-[l7-filter-version].patch". 35 | 36 | Use the one that matches your kernel version. If the l7-filter version 37 | is not the latest, then it may be missing some newer features. See CHANGELOG. 38 | 39 | ***** iptables patches/files ***** 40 | 41 | - iptables-1.4.3forward-for-kernel-2.6.20forward/libxt_layer7.{c,man} 42 | 43 | Use these files if you are compiling iptables 1.4.3 or later against Linux 44 | 2.6.20 or later. 45 | 46 | - for_older_iptables/ 47 | 48 | Use these files if you are using an older version of iptables or Linux. 49 | Note that not all combinations are supported. This includes, but is not 50 | limited to: 51 | 52 | -- Compiling iptables 1.4.x against Linux 2.6.19.x or earlier. 53 | 54 | -- iptables 1.4.1, period. 55 | 56 | 57 | General notes: 58 | 59 | - You do NOT need to recompile iptables if you change your running kernel 60 | version across the 2.6.20 boundary and you already have a working iptables. 61 | 62 | - You DO need to recompile iptables if you switch from a kernel patched 63 | with l7-filter <= v2.10 to one patched with l7-filter >= v2.11. 64 | -------------------------------------------------------------------------------- /for_older_iptables/iptables-1.3-for-kernel-2.6.20forward-layer7-2.21.patch: -------------------------------------------------------------------------------- 1 | diff -Nurp iptables-1.3.8/extensions/.layer7-test iptables-1.3.8-layer7/extensions/.layer7-test 2 | --- iptables-1.3.8/extensions/.layer7-test 1969-12-31 18:00:00.000000000 -0600 3 | +++ iptables-1.3.8-layer7/extensions/.layer7-test 2007-07-04 19:08:07.000000000 -0500 4 | @@ -0,0 +1,2 @@ 5 | +#! /bin/sh 6 | +[ -f $KERNEL_DIR/include/linux/netfilter/xt_layer7.h ] && echo layer7 7 | diff -Nurp iptables-1.3.8/extensions/libipt_layer7.c iptables-1.3.8-layer7/extensions/libipt_layer7.c 8 | --- iptables-1.3.8/extensions/libipt_layer7.c 1969-12-31 18:00:00.000000000 -0600 9 | +++ iptables-1.3.8-layer7/extensions/libipt_layer7.c 2007-07-04 19:23:04.000000000 -0500 10 | @@ -0,0 +1,394 @@ 11 | +/* 12 | + Shared library add-on to iptables to add layer 7 matching support. 13 | + 14 | + By Matthew Strait , 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 25 | +*/ 26 | + 27 | +#define _GNU_SOURCE 28 | +#include 29 | +#include 30 | +#include 31 | +#include 32 | +#include 33 | +#include 34 | +#include 35 | + 36 | +#include 37 | +#include 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 : Look for patterns here instead of /etc/l7-protocols/\n" 49 | + " (--l7dir must be specified before --l7proto if used!)\n" 50 | + "--l7proto [!] : 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 | +/* reads filename, puts protocol info into layer7_protocol_info, number of protocols to numprotos */ 62 | +int parse_protocol_file(char * filename, const char * protoname, struct xt_layer7_info *info) 63 | +{ 64 | + FILE * f; 65 | + char * line = NULL; 66 | + size_t len = 0; 67 | + 68 | + enum { protocol, pattern, done } datatype = protocol; 69 | + 70 | + f = fopen(filename, "r"); 71 | + 72 | + if(!f) 73 | + return 0; 74 | + 75 | + while(getline(&line, &len, f) != -1) 76 | + { 77 | + if(strlen(line) < 2 || line[0] == '#') 78 | + continue; 79 | + 80 | + /* strip the pesky newline... */ 81 | + if(line[strlen(line) - 1] == '\n') 82 | + line[strlen(line) - 1] = '\0'; 83 | + 84 | + if(datatype == protocol) 85 | + { 86 | + /* Ignore everything on the line beginning with the 87 | + first space or tab . For instance, this allows the 88 | + protocol line in http.pat to be "http " (or 89 | + "http I am so cool") instead of just "http". */ 90 | + if(strchr(line, ' ')){ 91 | + char * space = strchr(line, ' '); 92 | + space[0] = '\0'; 93 | + } 94 | + if(strchr(line, '\t')){ 95 | + char * space = strchr(line, '\t'); 96 | + space[0] = '\0'; 97 | + } 98 | + 99 | + /* sanity check. First non-comment non-blank 100 | + line must be the same as the file name. */ 101 | + if(strcmp(line, protoname)) 102 | + exit_error(OTHER_PROBLEM, 103 | + "Protocol name (%s) doesn't match file name (%s). Bailing out\n", 104 | + line, filename); 105 | + 106 | + if(strlen(line) >= MAX_PROTOCOL_LEN) 107 | + exit_error(PARAMETER_PROBLEM, 108 | + "Protocol name in %s too long!", filename); 109 | + strncpy(info->protocol, line, MAX_PROTOCOL_LEN); 110 | + 111 | + datatype = pattern; 112 | + } 113 | + else if(datatype == pattern) 114 | + { 115 | + if(strlen(line) >= MAX_PATTERN_LEN) 116 | + exit_error(PARAMETER_PROBLEM, "Pattern in %s too long!", filename); 117 | + strncpy(info->pattern, line, MAX_PATTERN_LEN); 118 | + 119 | + datatype = done; 120 | + break; 121 | + } 122 | + else 123 | + exit_error(OTHER_PROBLEM, "Internal error"); 124 | + } 125 | + 126 | + if(datatype != done) 127 | + exit_error(OTHER_PROBLEM, "Failed to get all needed data from %s", filename); 128 | + 129 | + if(line) free(line); 130 | + fclose(f); 131 | + 132 | + return 1; 133 | + 134 | +/* 135 | + fprintf(stderr, "protocol: %s\npattern: %s\n\n", 136 | + info->protocol, 137 | + info->pattern); 138 | +*/ 139 | +} 140 | + 141 | +static int hex2dec(char c) 142 | +{ 143 | + switch (c) 144 | + { 145 | + case '0' ... '9': 146 | + return c - '0'; 147 | + case 'a' ... 'f': 148 | + return c - 'a' + 10; 149 | + case 'A' ... 'F': 150 | + return c - 'A' + 10; 151 | + default: 152 | + exit_error(OTHER_PROBLEM, "hex2dec: bad value!\n"); 153 | + return 0; 154 | + } 155 | +} 156 | + 157 | +/* takes a string with \xHH escapes and returns one with the characters 158 | +they stand for */ 159 | +static char * pre_process(char * s) 160 | +{ 161 | + char * result = malloc(strlen(s) + 1); 162 | + int sindex = 0, rindex = 0; 163 | + while( sindex < strlen(s) ) 164 | + { 165 | + if( sindex + 3 < strlen(s) && 166 | + s[sindex] == '\\' && s[sindex+1] == 'x' && 167 | + isxdigit(s[sindex + 2]) && isxdigit(s[sindex + 3]) ) 168 | + { 169 | + /* carefully remember to call tolower here... */ 170 | + result[rindex] = tolower( hex2dec(s[sindex + 2])*16 + 171 | + hex2dec(s[sindex + 3] ) ); 172 | + 173 | + switch ( result[rindex] ) 174 | + { 175 | + case 0x24: 176 | + case 0x28: 177 | + case 0x29: 178 | + case 0x2a: 179 | + case 0x2b: 180 | + case 0x2e: 181 | + case 0x3f: 182 | + case 0x5b: 183 | + case 0x5c: 184 | + case 0x5d: 185 | + case 0x5e: 186 | + case 0x7c: 187 | + fprintf(stderr, 188 | + "Warning: layer7 regexp contains a control character, %c, in hex (\\x%c%c).\n" 189 | + "I recommend that you write this as %c or \\%c, depending on what you meant.\n", 190 | + result[rindex], s[sindex + 2], s[sindex + 3], result[rindex], result[rindex]); 191 | + break; 192 | + case 0x00: 193 | + fprintf(stderr, 194 | + "Warning: null (\\x00) in layer7 regexp. A null terminates the regexp string!\n"); 195 | + break; 196 | + default: 197 | + break; 198 | + } 199 | + 200 | + 201 | + sindex += 3; /* 4 total */ 202 | + } 203 | + else 204 | + result[rindex] = tolower(s[sindex]); 205 | + 206 | + sindex++; 207 | + rindex++; 208 | + } 209 | + result[rindex] = '\0'; 210 | + 211 | + return result; 212 | +} 213 | + 214 | +#define MAX_SUBDIRS 128 215 | +char ** readl7dir(char * dirname) 216 | +{ 217 | + DIR * scratchdir; 218 | + struct dirent ** namelist; 219 | + char ** subdirs = malloc(MAX_SUBDIRS * sizeof(char *)); 220 | + 221 | + int n, d = 1; 222 | + subdirs[0] = ""; 223 | + 224 | + n = scandir(dirname, &namelist, 0, alphasort); 225 | + 226 | + if (n < 0) 227 | + { 228 | + perror("scandir"); 229 | + exit_error(OTHER_PROBLEM, "Couldn't open %s\n", dirname); 230 | + } 231 | + else 232 | + { 233 | + while(n--) 234 | + { 235 | + char fulldirname[MAX_FN_LEN]; 236 | + 237 | + snprintf(fulldirname, MAX_FN_LEN, "%s/%s", dirname, namelist[n]->d_name); 238 | + 239 | + if((scratchdir = opendir(fulldirname)) != NULL) 240 | + { 241 | + closedir(scratchdir); 242 | + 243 | + if(!strcmp(namelist[n]->d_name, ".") || 244 | + !strcmp(namelist[n]->d_name, "..")) 245 | + /* do nothing */ ; 246 | + else 247 | + { 248 | + subdirs[d] = malloc(strlen(namelist[n]->d_name) + 1); 249 | + strcpy(subdirs[d], namelist[n]->d_name); 250 | + d++; 251 | + if(d >= MAX_SUBDIRS - 1) 252 | + { 253 | + fprintf(stderr, 254 | + "Too many subdirectories, skipping the rest!\n"); 255 | + break; 256 | + } 257 | + } 258 | + } 259 | + free(namelist[n]); 260 | + } 261 | + free(namelist); 262 | + } 263 | + 264 | + subdirs[d] = NULL; 265 | + 266 | + return subdirs; 267 | +} 268 | + 269 | +static void 270 | +parse_layer7_protocol(const char *s, struct xt_layer7_info *info) 271 | +{ 272 | + char filename[MAX_FN_LEN]; 273 | + char * dir = NULL; 274 | + char ** subdirs; 275 | + int n = 0, done = 0; 276 | + 277 | + if(strlen(l7dir) > 0) 278 | + dir = l7dir; 279 | + else 280 | + dir = "/etc/l7-protocols"; 281 | + 282 | + subdirs = readl7dir(dir); 283 | + 284 | + while(subdirs[n] != NULL) 285 | + { 286 | + int c = snprintf(filename, MAX_FN_LEN, "%s/%s/%s.pat", dir, subdirs[n], s); 287 | + 288 | + //fprintf(stderr, "Trying to find pattern in %s ... ", filename); 289 | + 290 | + if(c > MAX_FN_LEN) 291 | + { 292 | + exit_error(OTHER_PROBLEM, 293 | + "Filename beginning with %s is too long!\n", filename); 294 | + } 295 | + 296 | + /* read in the pattern from the file */ 297 | + if(parse_protocol_file(filename, s, info)) 298 | + { 299 | + //fprintf(stderr, "found\n"); 300 | + done = 1; 301 | + break; 302 | + } 303 | + 304 | + //fprintf(stderr, "not found\n"); 305 | + 306 | + n++; 307 | + } 308 | + 309 | + if(!done) 310 | + exit_error(OTHER_PROBLEM, 311 | + "Couldn't find a pattern definition file for %s.\n", s); 312 | + 313 | + /* process \xHH escapes and tolower everything. (our regex lib has no 314 | + case insensitivity option.) */ 315 | + strncpy(info->pattern, pre_process(info->pattern), MAX_PATTERN_LEN); 316 | +} 317 | + 318 | +/* Function which parses command options; returns true if it ate an option */ 319 | +static int parse(int c, char **argv, int invert, unsigned int *flags, 320 | + const struct ipt_entry *entry, unsigned int *nfcache, 321 | + struct ipt_entry_match **match) 322 | +{ 323 | + struct xt_layer7_info *layer7info = 324 | + (struct xt_layer7_info *)(*match)->data; 325 | + 326 | + switch (c) { 327 | + case '1': 328 | + check_inverse(optarg, &invert, &optind, 0); 329 | + parse_layer7_protocol(argv[optind-1], layer7info); 330 | + if (invert) 331 | + layer7info->invert = 1; 332 | + *flags = 1; 333 | + break; 334 | + 335 | + case '2': 336 | + /* not going to use this, but maybe we need to strip a ! anyway (?) */ 337 | + check_inverse(optarg, &invert, &optind, 0); 338 | + 339 | + if(strlen(argv[optind-1]) >= MAX_FN_LEN) 340 | + exit_error(PARAMETER_PROBLEM, "directory name too long\n"); 341 | + 342 | + strncpy(l7dir, argv[optind-1], MAX_FN_LEN); 343 | + 344 | + *flags = 1; 345 | + break; 346 | + 347 | + default: 348 | + return 0; 349 | + } 350 | + 351 | + return 1; 352 | +} 353 | + 354 | +/* Final check; must have specified --l7proto */ 355 | +static void final_check(unsigned int flags) 356 | +{ 357 | + if (!flags) 358 | + exit_error(PARAMETER_PROBLEM, 359 | + "LAYER7 match: You must specify `--l7proto'"); 360 | +} 361 | + 362 | +static void print_protocol(char s[], int invert, int numeric) 363 | +{ 364 | + fputs("l7proto ", stdout); 365 | + if (invert) fputc('!', stdout); 366 | + printf("%s ", s); 367 | +} 368 | + 369 | +/* Prints out the matchinfo. */ 370 | +static void print(const struct ipt_ip *ip, 371 | + const struct ipt_entry_match *match, 372 | + int numeric) 373 | +{ 374 | + printf("LAYER7 "); 375 | + 376 | + print_protocol(((struct xt_layer7_info *)match->data)->protocol, 377 | + ((struct xt_layer7_info *)match->data)->invert, numeric); 378 | +} 379 | +/* Saves the union ipt_matchinfo in parsable form to stdout. */ 380 | +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) 381 | +{ 382 | + const struct xt_layer7_info *info = 383 | + (const struct xt_layer7_info*) match->data; 384 | + 385 | + printf("--l7proto %s%s ", (info->invert) ? "! ": "", info->protocol); 386 | +} 387 | + 388 | +static struct iptables_match layer7 = { 389 | + .name = "layer7", 390 | + .version = IPTABLES_VERSION, 391 | + .size = IPT_ALIGN(sizeof(struct xt_layer7_info)), 392 | + .userspacesize = IPT_ALIGN(sizeof(struct xt_layer7_info)), 393 | + .help = &help, 394 | + .parse = &parse, 395 | + .final_check = &final_check, 396 | + .print = &print, 397 | + .save = &save, 398 | + .extra_opts = opts 399 | +}; 400 | + 401 | +void _init(void) 402 | +{ 403 | + register_match(&layer7); 404 | +} 405 | diff -Nurp iptables-1.3.8/extensions/libipt_layer7.man iptables-1.3.8-layer7/extensions/libipt_layer7.man 406 | --- iptables-1.3.8/extensions/libipt_layer7.man 1969-12-31 18:00:00.000000000 -0600 407 | +++ iptables-1.3.8-layer7/extensions/libipt_layer7.man 2007-07-04 19:06:03.000000000 -0500 408 | @@ -0,0 +1,14 @@ 409 | +This module matches packets based on the application layer data of 410 | +their connections. It uses regular expression matching to compare 411 | +the application layer data to regular expressions found it the layer7 412 | +configuration files. This is an experimental module which can be found at 413 | +http://l7-filter.sf.net. It takes two options. 414 | +.TP 415 | +.BI "--l7proto " "\fIprotocol\fP" 416 | +Match the specified protocol. The protocol name must match a file 417 | +name in /etc/l7-protocols/ or one of its first-level child directories. 418 | +.TP 419 | +.BI "--l7dir " "\fIdirectory\fP" 420 | +Use \fIdirectory\fP instead of /etc/l7-protocols/. This option must be 421 | +specified before --l7proto. 422 | + 423 | -------------------------------------------------------------------------------- /for_older_iptables/iptables-1.3-for-kernel-pre2.6.20-layer7-2.21.patch: -------------------------------------------------------------------------------- 1 | diff -Nurp iptables-1.3.7/extensions/.layer7-test iptables-1.3.7-layer7/extensions/.layer7-test 2 | --- iptables-1.3.7/extensions/.layer7-test 1969-12-31 18:00:00.000000000 -0600 3 | +++ iptables-1.3.7-layer7/extensions/.layer7-test 2006-12-14 22:08:11.000000000 -0600 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.3.7/extensions/libipt_layer7.c iptables-1.3.7-layer7/extensions/libipt_layer7.c 8 | --- iptables-1.3.7/extensions/libipt_layer7.c 1969-12-31 18:00:00.000000000 -0600 9 | +++ iptables-1.3.7-layer7/extensions/libipt_layer7.c 2007-01-15 23:03:55.000000000 -0600 10 | @@ -0,0 +1,394 @@ 11 | +/* 12 | + Shared library add-on to iptables to add layer 7 matching support. 13 | + 14 | + By Matthew Strait , 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 25 | +*/ 26 | + 27 | +#define _GNU_SOURCE 28 | +#include 29 | +#include 30 | +#include 31 | +#include 32 | +#include 33 | +#include 34 | +#include 35 | + 36 | +#include 37 | +#include 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 : Look for patterns here instead of /etc/l7-protocols/\n" 49 | + " (--l7dir must be specified before --l7proto if used!)\n" 50 | + "--l7proto [!] : 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 | +/* reads filename, puts protocol info into layer7_protocol_info, number of protocols to numprotos */ 62 | +int parse_protocol_file(char * filename, const unsigned char * protoname, struct ipt_layer7_info *info) 63 | +{ 64 | + FILE * f; 65 | + char * line = NULL; 66 | + size_t len = 0; 67 | + 68 | + enum { protocol, pattern, done } datatype = protocol; 69 | + 70 | + f = fopen(filename, "r"); 71 | + 72 | + if(!f) 73 | + return 0; 74 | + 75 | + while(getline(&line, &len, f) != -1) 76 | + { 77 | + if(strlen(line) < 2 || line[0] == '#') 78 | + continue; 79 | + 80 | + /* strip the pesky newline... */ 81 | + if(line[strlen(line) - 1] == '\n') 82 | + line[strlen(line) - 1] = '\0'; 83 | + 84 | + if(datatype == protocol) 85 | + { 86 | + /* Ignore everything on the line beginning with the 87 | + first space or tab . For instance, this allows the 88 | + protocol line in http.pat to be "http " (or 89 | + "http I am so cool") instead of just "http". */ 90 | + if(strchr(line, ' ')){ 91 | + char * space = strchr(line, ' '); 92 | + space[0] = '\0'; 93 | + } 94 | + if(strchr(line, '\t')){ 95 | + char * space = strchr(line, '\t'); 96 | + space[0] = '\0'; 97 | + } 98 | + 99 | + /* sanity check. First non-comment non-blank 100 | + line must be the same as the file name. */ 101 | + if(strcmp(line, protoname)) 102 | + exit_error(OTHER_PROBLEM, 103 | + "Protocol name (%s) doesn't match file name (%s). Bailing out\n", 104 | + line, filename); 105 | + 106 | + if(strlen(line) >= MAX_PROTOCOL_LEN) 107 | + exit_error(PARAMETER_PROBLEM, 108 | + "Protocol name in %s too long!", filename); 109 | + strncpy(info->protocol, line, MAX_PROTOCOL_LEN); 110 | + 111 | + datatype = pattern; 112 | + } 113 | + else if(datatype == pattern) 114 | + { 115 | + if(strlen(line) >= MAX_PATTERN_LEN) 116 | + exit_error(PARAMETER_PROBLEM, "Pattern in %s too long!", filename); 117 | + strncpy(info->pattern, line, MAX_PATTERN_LEN); 118 | + 119 | + datatype = done; 120 | + break; 121 | + } 122 | + else 123 | + exit_error(OTHER_PROBLEM, "Internal error"); 124 | + } 125 | + 126 | + if(datatype != done) 127 | + exit_error(OTHER_PROBLEM, "Failed to get all needed data from %s", filename); 128 | + 129 | + if(line) free(line); 130 | + fclose(f); 131 | + 132 | + return 1; 133 | + 134 | +/* 135 | + fprintf(stderr, "protocol: %s\npattern: %s\n\n", 136 | + info->protocol, 137 | + info->pattern); 138 | +*/ 139 | +} 140 | + 141 | +static int hex2dec(char c) 142 | +{ 143 | + switch (c) 144 | + { 145 | + case '0' ... '9': 146 | + return c - '0'; 147 | + case 'a' ... 'f': 148 | + return c - 'a' + 10; 149 | + case 'A' ... 'F': 150 | + return c - 'A' + 10; 151 | + default: 152 | + exit_error(OTHER_PROBLEM, "hex2dec: bad value!\n"); 153 | + return 0; 154 | + } 155 | +} 156 | + 157 | +/* takes a string with \xHH escapes and returns one with the characters 158 | +they stand for */ 159 | +static char * pre_process(char * s) 160 | +{ 161 | + char * result = malloc(strlen(s) + 1); 162 | + int sindex = 0, rindex = 0; 163 | + while( sindex < strlen(s) ) 164 | + { 165 | + if( sindex + 3 < strlen(s) && 166 | + s[sindex] == '\\' && s[sindex+1] == 'x' && 167 | + isxdigit(s[sindex + 2]) && isxdigit(s[sindex + 3]) ) 168 | + { 169 | + /* carefully remember to call tolower here... */ 170 | + result[rindex] = tolower( hex2dec(s[sindex + 2])*16 + 171 | + hex2dec(s[sindex + 3] ) ); 172 | + 173 | + switch ( result[rindex] ) 174 | + { 175 | + case 0x24: 176 | + case 0x28: 177 | + case 0x29: 178 | + case 0x2a: 179 | + case 0x2b: 180 | + case 0x2e: 181 | + case 0x3f: 182 | + case 0x5b: 183 | + case 0x5c: 184 | + case 0x5d: 185 | + case 0x5e: 186 | + case 0x7c: 187 | + fprintf(stderr, 188 | + "Warning: layer7 regexp contains a control character, %c, in hex (\\x%c%c).\n" 189 | + "I recommend that you write this as %c or \\%c, depending on what you meant.\n", 190 | + result[rindex], s[sindex + 2], s[sindex + 3], result[rindex], result[rindex]); 191 | + break; 192 | + case 0x00: 193 | + fprintf(stderr, 194 | + "Warning: null (\\x00) in layer7 regexp. A null terminates the regexp string!\n"); 195 | + break; 196 | + default: 197 | + break; 198 | + } 199 | + 200 | + 201 | + sindex += 3; /* 4 total */ 202 | + } 203 | + else 204 | + result[rindex] = tolower(s[sindex]); 205 | + 206 | + sindex++; 207 | + rindex++; 208 | + } 209 | + result[rindex] = '\0'; 210 | + 211 | + return result; 212 | +} 213 | + 214 | +#define MAX_SUBDIRS 128 215 | +char ** readl7dir(char * dirname) 216 | +{ 217 | + DIR * scratchdir; 218 | + struct dirent ** namelist; 219 | + char ** subdirs = malloc(MAX_SUBDIRS * sizeof(char *)); 220 | + 221 | + int n, d = 1; 222 | + subdirs[0] = ""; 223 | + 224 | + n = scandir(dirname, &namelist, 0, alphasort); 225 | + 226 | + if (n < 0) 227 | + { 228 | + perror("scandir"); 229 | + exit_error(OTHER_PROBLEM, "Couldn't open %s\n", dirname); 230 | + } 231 | + else 232 | + { 233 | + while(n--) 234 | + { 235 | + char fulldirname[MAX_FN_LEN]; 236 | + 237 | + snprintf(fulldirname, MAX_FN_LEN, "%s/%s", dirname, namelist[n]->d_name); 238 | + 239 | + if((scratchdir = opendir(fulldirname)) != NULL) 240 | + { 241 | + closedir(scratchdir); 242 | + 243 | + if(!strcmp(namelist[n]->d_name, ".") || 244 | + !strcmp(namelist[n]->d_name, "..")) 245 | + /* do nothing */ ; 246 | + else 247 | + { 248 | + subdirs[d] = malloc(strlen(namelist[n]->d_name) + 1); 249 | + strcpy(subdirs[d], namelist[n]->d_name); 250 | + d++; 251 | + if(d >= MAX_SUBDIRS - 1) 252 | + { 253 | + fprintf(stderr, 254 | + "Too many subdirectories, skipping the rest!\n"); 255 | + break; 256 | + } 257 | + } 258 | + } 259 | + free(namelist[n]); 260 | + } 261 | + free(namelist); 262 | + } 263 | + 264 | + subdirs[d] = NULL; 265 | + 266 | + return subdirs; 267 | +} 268 | + 269 | +static void 270 | +parse_layer7_protocol(const unsigned char *s, struct ipt_layer7_info *info) 271 | +{ 272 | + char filename[MAX_FN_LEN]; 273 | + char * dir = NULL; 274 | + char ** subdirs; 275 | + int n = 0, done = 0; 276 | + 277 | + if(strlen(l7dir) > 0) 278 | + dir = l7dir; 279 | + else 280 | + dir = "/etc/l7-protocols"; 281 | + 282 | + subdirs = readl7dir(dir); 283 | + 284 | + while(subdirs[n] != NULL) 285 | + { 286 | + int c = snprintf(filename, MAX_FN_LEN, "%s/%s/%s.pat", dir, subdirs[n], s); 287 | + 288 | + //fprintf(stderr, "Trying to find pattern in %s ... ", filename); 289 | + 290 | + if(c > MAX_FN_LEN) 291 | + { 292 | + exit_error(OTHER_PROBLEM, 293 | + "Filename beginning with %s is too long!\n", filename); 294 | + } 295 | + 296 | + /* read in the pattern from the file */ 297 | + if(parse_protocol_file(filename, s, info)) 298 | + { 299 | + //fprintf(stderr, "found\n"); 300 | + done = 1; 301 | + break; 302 | + } 303 | + 304 | + //fprintf(stderr, "not found\n"); 305 | + 306 | + n++; 307 | + } 308 | + 309 | + if(!done) 310 | + exit_error(OTHER_PROBLEM, 311 | + "Couldn't find a pattern definition file for %s.\n", s); 312 | + 313 | + /* process \xHH escapes and tolower everything. (our regex lib has no 314 | + case insensitivity option.) */ 315 | + strncpy(info->pattern, pre_process(info->pattern), MAX_PATTERN_LEN); 316 | +} 317 | + 318 | +/* Function which parses command options; returns true if it ate an option */ 319 | +static int parse(int c, char **argv, int invert, unsigned int *flags, 320 | + const struct ipt_entry *entry, unsigned int *nfcache, 321 | + struct ipt_entry_match **match) 322 | +{ 323 | + struct ipt_layer7_info *layer7info = 324 | + (struct ipt_layer7_info *)(*match)->data; 325 | + 326 | + switch (c) { 327 | + case '1': 328 | + check_inverse(optarg, &invert, &optind, 0); 329 | + parse_layer7_protocol(argv[optind-1], layer7info); 330 | + if (invert) 331 | + layer7info->invert = 1; 332 | + *flags = 1; 333 | + break; 334 | + 335 | + case '2': 336 | + /* not going to use this, but maybe we need to strip a ! anyway (?) */ 337 | + check_inverse(optarg, &invert, &optind, 0); 338 | + 339 | + if(strlen(argv[optind-1]) >= MAX_FN_LEN) 340 | + exit_error(PARAMETER_PROBLEM, "directory name too long\n"); 341 | + 342 | + strncpy(l7dir, argv[optind-1], MAX_FN_LEN); 343 | + 344 | + *flags = 1; 345 | + break; 346 | + 347 | + default: 348 | + return 0; 349 | + } 350 | + 351 | + return 1; 352 | +} 353 | + 354 | +/* Final check; must have specified --l7proto */ 355 | +static void final_check(unsigned int flags) 356 | +{ 357 | + if (!flags) 358 | + exit_error(PARAMETER_PROBLEM, 359 | + "LAYER7 match: You must specify `--l7proto'"); 360 | +} 361 | + 362 | +static void print_protocol(char s[], int invert, int numeric) 363 | +{ 364 | + fputs("l7proto ", stdout); 365 | + if (invert) fputc('!', stdout); 366 | + printf("%s ", s); 367 | +} 368 | + 369 | +/* Prints out the matchinfo. */ 370 | +static void print(const struct ipt_ip *ip, 371 | + const struct ipt_entry_match *match, 372 | + int numeric) 373 | +{ 374 | + printf("LAYER7 "); 375 | + 376 | + print_protocol(((struct ipt_layer7_info *)match->data)->protocol, 377 | + ((struct ipt_layer7_info *)match->data)->invert, numeric); 378 | +} 379 | +/* Saves the union ipt_matchinfo in parsable form to stdout. */ 380 | +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) 381 | +{ 382 | + const struct ipt_layer7_info *info = 383 | + (const struct ipt_layer7_info*) match->data; 384 | + 385 | + printf("--l7proto %s%s ", (info->invert) ? "! ": "", info->protocol); 386 | +} 387 | + 388 | +static struct iptables_match layer7 = { 389 | + .name = "layer7", 390 | + .version = IPTABLES_VERSION, 391 | + .size = IPT_ALIGN(sizeof(struct ipt_layer7_info)), 392 | + .userspacesize = IPT_ALIGN(sizeof(struct ipt_layer7_info)), 393 | + .help = &help, 394 | + .parse = &parse, 395 | + .final_check = &final_check, 396 | + .print = &print, 397 | + .save = &save, 398 | + .extra_opts = opts 399 | +}; 400 | + 401 | +void _init(void) 402 | +{ 403 | + register_match(&layer7); 404 | +} 405 | diff -Nurp iptables-1.3.7/extensions/libipt_layer7.man iptables-1.3.7-layer7/extensions/libipt_layer7.man 406 | --- iptables-1.3.7/extensions/libipt_layer7.man 1969-12-31 18:00:00.000000000 -0600 407 | +++ iptables-1.3.7-layer7/extensions/libipt_layer7.man 2006-12-14 22:08:11.000000000 -0600 408 | @@ -0,0 +1,14 @@ 409 | +This module matches packets based on the application layer data of 410 | +their connections. It uses regular expression matching to compare 411 | +the application layer data to regular expressions found it the layer7 412 | +configuration files. This is an experimental module which can be found at 413 | +http://l7-filter.sf.net. It takes two options. 414 | +.TP 415 | +.BI "--l7proto " "\fIprotocol\fP" 416 | +Match the specified protocol. The protocol name must match a file 417 | +name in /etc/l7-protocols/ or one of its first-level child directories. 418 | +.TP 419 | +.BI "--l7dir " "\fIdirectory\fP" 420 | +Use \fIdirectory\fP instead of /etc/l7-protocols/. This option must be 421 | +specified before --l7proto. 422 | + 423 | -------------------------------------------------------------------------------- /for_older_iptables/iptables-1.4-for-kernel-2.6.20forward-layer7-2.21.patch: -------------------------------------------------------------------------------- 1 | --- iptables-1.4.0rc1/extensions/libipt_layer7.c 1969-12-31 18:00:00.000000000 -0600 2 | +++ iptables-1.4.0rc1-layer7/extensions/libipt_layer7.c 2007-11-19 06:06:56.000000000 -0600 3 | @@ -0,0 +1,393 @@ 4 | +/* 5 | + Shared library add-on to iptables to add layer 7 matching support. 6 | + 7 | + By Matthew Strait , Oct 2003. 8 | + 9 | + http://l7-filter.sf.net 10 | + 11 | + This program is free software; you can redistribute it and/or 12 | + modify it under the terms of the GNU General Public License 13 | + as published by the Free Software Foundation; either version 14 | + 2 of the License, or (at your option) any later version. 15 | + http://www.gnu.org/licenses/gpl.txt 16 | + 17 | + Based on libipt_string.c (C) 2000 Emmanuel Roger 18 | +*/ 19 | + 20 | +#define _GNU_SOURCE 21 | +#include 22 | +#include 23 | +#include 24 | +#include 25 | +#include 26 | +#include 27 | +#include 28 | + 29 | +#include 30 | +#include 31 | + 32 | +#define MAX_FN_LEN 256 33 | + 34 | +static char l7dir[MAX_FN_LEN] = "\0"; 35 | + 36 | +/* Function which prints out usage message. */ 37 | +static void help(void) 38 | +{ 39 | + printf( 40 | + "LAYER7 match v%s options:\n" 41 | + "--l7dir : Look for patterns here instead of /etc/l7-protocols/\n" 42 | + " (--l7dir must be specified before --l7proto if used!)\n" 43 | + "--l7proto [!] : Match the protocol defined in /etc/l7-protocols/name.pat\n", 44 | + IPTABLES_VERSION); 45 | + fputc('\n', stdout); 46 | +} 47 | + 48 | +static struct option opts[] = { 49 | + { .name = "l7proto", .has_arg = 1, .flag = 0, .val = '1' }, 50 | + { .name = "l7dir", .has_arg = 1, .flag = 0, .val = '2' }, 51 | + { .name = 0 } 52 | +}; 53 | + 54 | +/* reads filename, puts protocol info into layer7_protocol_info, number of protocols to numprotos */ 55 | +int parse_protocol_file(char * filename, const char * protoname, struct xt_layer7_info *info) 56 | +{ 57 | + FILE * f; 58 | + char * line = NULL; 59 | + size_t len = 0; 60 | + 61 | + enum { protocol, pattern, done } datatype = protocol; 62 | + 63 | + f = fopen(filename, "r"); 64 | + 65 | + if(!f) 66 | + return 0; 67 | + 68 | + while(getline(&line, &len, f) != -1) 69 | + { 70 | + if(strlen(line) < 2 || line[0] == '#') 71 | + continue; 72 | + 73 | + /* strip the pesky newline... */ 74 | + if(line[strlen(line) - 1] == '\n') 75 | + line[strlen(line) - 1] = '\0'; 76 | + 77 | + if(datatype == protocol) 78 | + { 79 | + /* Ignore everything on the line beginning with the 80 | + first space or tab . For instance, this allows the 81 | + protocol line in http.pat to be "http " (or 82 | + "http I am so cool") instead of just "http". */ 83 | + if(strchr(line, ' ')){ 84 | + char * space = strchr(line, ' '); 85 | + space[0] = '\0'; 86 | + } 87 | + if(strchr(line, '\t')){ 88 | + char * space = strchr(line, '\t'); 89 | + space[0] = '\0'; 90 | + } 91 | + 92 | + /* sanity check. First non-comment non-blank 93 | + line must be the same as the file name. */ 94 | + if(strcmp(line, protoname)) 95 | + exit_error(OTHER_PROBLEM, 96 | + "Protocol name (%s) doesn't match file name (%s). Bailing out\n", 97 | + line, filename); 98 | + 99 | + if(strlen(line) >= MAX_PROTOCOL_LEN) 100 | + exit_error(PARAMETER_PROBLEM, 101 | + "Protocol name in %s too long!", filename); 102 | + strncpy(info->protocol, line, MAX_PROTOCOL_LEN); 103 | + 104 | + datatype = pattern; 105 | + } 106 | + else if(datatype == pattern) 107 | + { 108 | + if(strlen(line) >= MAX_PATTERN_LEN) 109 | + exit_error(PARAMETER_PROBLEM, "Pattern in %s too long!", filename); 110 | + strncpy(info->pattern, line, MAX_PATTERN_LEN); 111 | + 112 | + datatype = done; 113 | + break; 114 | + } 115 | + else 116 | + exit_error(OTHER_PROBLEM, "Internal error"); 117 | + } 118 | + 119 | + if(datatype != done) 120 | + exit_error(OTHER_PROBLEM, "Failed to get all needed data from %s", filename); 121 | + 122 | + if(line) free(line); 123 | + fclose(f); 124 | + 125 | + return 1; 126 | + 127 | +/* 128 | + fprintf(stderr, "protocol: %s\npattern: %s\n\n", 129 | + info->protocol, 130 | + info->pattern); 131 | +*/ 132 | +} 133 | + 134 | +static int hex2dec(char c) 135 | +{ 136 | + switch (c) 137 | + { 138 | + case '0' ... '9': 139 | + return c - '0'; 140 | + case 'a' ... 'f': 141 | + return c - 'a' + 10; 142 | + case 'A' ... 'F': 143 | + return c - 'A' + 10; 144 | + default: 145 | + exit_error(OTHER_PROBLEM, "hex2dec: bad value!\n"); 146 | + return 0; 147 | + } 148 | +} 149 | + 150 | +/* takes a string with \xHH escapes and returns one with the characters 151 | +they stand for */ 152 | +static char * pre_process(char * s) 153 | +{ 154 | + char * result = malloc(strlen(s) + 1); 155 | + int sindex = 0, rindex = 0; 156 | + while( sindex < strlen(s) ) 157 | + { 158 | + if( sindex + 3 < strlen(s) && 159 | + s[sindex] == '\\' && s[sindex+1] == 'x' && 160 | + isxdigit(s[sindex + 2]) && isxdigit(s[sindex + 3]) ) 161 | + { 162 | + /* carefully remember to call tolower here... */ 163 | + result[rindex] = tolower( hex2dec(s[sindex + 2])*16 + 164 | + hex2dec(s[sindex + 3] ) ); 165 | + 166 | + switch ( result[rindex] ) 167 | + { 168 | + case 0x24: 169 | + case 0x28: 170 | + case 0x29: 171 | + case 0x2a: 172 | + case 0x2b: 173 | + case 0x2e: 174 | + case 0x3f: 175 | + case 0x5b: 176 | + case 0x5c: 177 | + case 0x5d: 178 | + case 0x5e: 179 | + case 0x7c: 180 | + fprintf(stderr, 181 | + "Warning: layer7 regexp contains a control character, %c, in hex (\\x%c%c).\n" 182 | + "I recommend that you write this as %c or \\%c, depending on what you meant.\n", 183 | + result[rindex], s[sindex + 2], s[sindex + 3], result[rindex], result[rindex]); 184 | + break; 185 | + case 0x00: 186 | + fprintf(stderr, 187 | + "Warning: null (\\x00) in layer7 regexp. A null terminates the regexp string!\n"); 188 | + break; 189 | + default: 190 | + break; 191 | + } 192 | + 193 | + 194 | + sindex += 3; /* 4 total */ 195 | + } 196 | + else 197 | + result[rindex] = tolower(s[sindex]); 198 | + 199 | + sindex++; 200 | + rindex++; 201 | + } 202 | + result[rindex] = '\0'; 203 | + 204 | + return result; 205 | +} 206 | + 207 | +#define MAX_SUBDIRS 128 208 | +char ** readl7dir(char * dirname) 209 | +{ 210 | + DIR * scratchdir; 211 | + struct dirent ** namelist; 212 | + char ** subdirs = malloc(MAX_SUBDIRS * sizeof(char *)); 213 | + 214 | + int n, d = 1; 215 | + subdirs[0] = ""; 216 | + 217 | + n = scandir(dirname, &namelist, 0, alphasort); 218 | + 219 | + if (n < 0) 220 | + { 221 | + perror("scandir"); 222 | + exit_error(OTHER_PROBLEM, "Couldn't open %s\n", dirname); 223 | + } 224 | + else 225 | + { 226 | + while(n--) 227 | + { 228 | + char fulldirname[MAX_FN_LEN]; 229 | + 230 | + snprintf(fulldirname, MAX_FN_LEN, "%s/%s", dirname, namelist[n]->d_name); 231 | + 232 | + if((scratchdir = opendir(fulldirname)) != NULL) 233 | + { 234 | + closedir(scratchdir); 235 | + 236 | + if(!strcmp(namelist[n]->d_name, ".") || 237 | + !strcmp(namelist[n]->d_name, "..")) 238 | + /* do nothing */ ; 239 | + else 240 | + { 241 | + subdirs[d] = malloc(strlen(namelist[n]->d_name) + 1); 242 | + strcpy(subdirs[d], namelist[n]->d_name); 243 | + d++; 244 | + if(d >= MAX_SUBDIRS - 1) 245 | + { 246 | + fprintf(stderr, 247 | + "Too many subdirectories, skipping the rest!\n"); 248 | + break; 249 | + } 250 | + } 251 | + } 252 | + free(namelist[n]); 253 | + } 254 | + free(namelist); 255 | + } 256 | + 257 | + subdirs[d] = NULL; 258 | + 259 | + return subdirs; 260 | +} 261 | + 262 | +static void 263 | +parse_layer7_protocol(const char *s, struct xt_layer7_info *info) 264 | +{ 265 | + char filename[MAX_FN_LEN]; 266 | + char * dir = NULL; 267 | + char ** subdirs; 268 | + int n = 0, done = 0; 269 | + 270 | + if(strlen(l7dir) > 0) 271 | + dir = l7dir; 272 | + else 273 | + dir = "/etc/l7-protocols"; 274 | + 275 | + subdirs = readl7dir(dir); 276 | + 277 | + while(subdirs[n] != NULL) 278 | + { 279 | + int c = snprintf(filename, MAX_FN_LEN, "%s/%s/%s.pat", dir, subdirs[n], s); 280 | + 281 | + //fprintf(stderr, "Trying to find pattern in %s ... ", filename); 282 | + 283 | + if(c > MAX_FN_LEN) 284 | + { 285 | + exit_error(OTHER_PROBLEM, 286 | + "Filename beginning with %s is too long!\n", filename); 287 | + } 288 | + 289 | + /* read in the pattern from the file */ 290 | + if(parse_protocol_file(filename, s, info)) 291 | + { 292 | + //fprintf(stderr, "found\n"); 293 | + done = 1; 294 | + break; 295 | + } 296 | + 297 | + //fprintf(stderr, "not found\n"); 298 | + 299 | + n++; 300 | + } 301 | + 302 | + if(!done) 303 | + exit_error(OTHER_PROBLEM, 304 | + "Couldn't find a pattern definition file for %s.\n", s); 305 | + 306 | + /* process \xHH escapes and tolower everything. (our regex lib has no 307 | + case insensitivity option.) */ 308 | + strncpy(info->pattern, pre_process(info->pattern), MAX_PATTERN_LEN); 309 | +} 310 | + 311 | +/* Function which parses command options; returns true if it ate an option */ 312 | +static int parse(int c, char **argv, int invert, unsigned int *flags, 313 | + const void *entry, struct xt_entry_match **match) 314 | +{ 315 | + struct xt_layer7_info *layer7info = 316 | + (struct xt_layer7_info *)(*match)->data; 317 | + 318 | + switch (c) { 319 | + case '1': 320 | + check_inverse(optarg, &invert, &optind, 0); 321 | + parse_layer7_protocol(argv[optind-1], layer7info); 322 | + if (invert) 323 | + layer7info->invert = 1; 324 | + *flags = 1; 325 | + break; 326 | + 327 | + case '2': 328 | + /* not going to use this, but maybe we need to strip a ! anyway (?) */ 329 | + check_inverse(optarg, &invert, &optind, 0); 330 | + 331 | + if(strlen(argv[optind-1]) >= MAX_FN_LEN) 332 | + exit_error(PARAMETER_PROBLEM, "directory name too long\n"); 333 | + 334 | + strncpy(l7dir, argv[optind-1], MAX_FN_LEN); 335 | + 336 | + *flags = 1; 337 | + break; 338 | + 339 | + default: 340 | + return 0; 341 | + } 342 | + 343 | + return 1; 344 | +} 345 | + 346 | +/* Final check; must have specified --l7proto */ 347 | +static void final_check(unsigned int flags) 348 | +{ 349 | + if (!flags) 350 | + exit_error(PARAMETER_PROBLEM, 351 | + "LAYER7 match: You must specify `--l7proto'"); 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 void *ip, 363 | + const struct xt_entry_match *match, 364 | + int numeric) 365 | +{ 366 | + printf("LAYER7 "); 367 | + 368 | + print_protocol(((struct xt_layer7_info *)match->data)->protocol, 369 | + ((struct xt_layer7_info *)match->data)->invert, numeric); 370 | +} 371 | +/* Saves the union ipt_matchinfo in parsable form to stdout. */ 372 | +static void save(const void *ip, const struct xt_entry_match *match) 373 | +{ 374 | + const struct xt_layer7_info *info = 375 | + (const struct xt_layer7_info*) match->data; 376 | + 377 | + printf("--l7proto %s%s ", (info->invert) ? "! ": "", info->protocol); 378 | +} 379 | + 380 | +static struct iptables_match layer7 = { 381 | + .name = "layer7", 382 | + .version = IPTABLES_VERSION, 383 | + .size = IPT_ALIGN(sizeof(struct xt_layer7_info)), 384 | + .userspacesize = IPT_ALIGN(sizeof(struct xt_layer7_info)), 385 | + .help = &help, 386 | + .parse = &parse, 387 | + .final_check = &final_check, 388 | + .print = &print, 389 | + .save = &save, 390 | + .extra_opts = opts 391 | +}; 392 | + 393 | +void _init(void) 394 | +{ 395 | + register_match(&layer7); 396 | +} 397 | --- iptables-1.4.0rc1/extensions/libipt_layer7.man 1969-12-31 18:00:00.000000000 -0600 398 | +++ iptables-1.4.0rc1-layer7/extensions/libipt_layer7.man 2007-11-19 05:49:46.000000000 -0600 399 | @@ -0,0 +1,14 @@ 400 | +This module matches packets based on the application layer data of 401 | +their connections. It uses regular expression matching to compare 402 | +the application layer data to regular expressions found it the layer7 403 | +configuration files. This is an experimental module which can be found at 404 | +http://l7-filter.sf.net. It takes two options. 405 | +.TP 406 | +.BI "--l7proto " "\fIprotocol\fP" 407 | +Match the specified protocol. The protocol name must match a file 408 | +name in /etc/l7-protocols/ or one of its first-level child directories. 409 | +.TP 410 | +.BI "--l7dir " "\fIdirectory\fP" 411 | +Use \fIdirectory\fP instead of /etc/l7-protocols/. This option must be 412 | +specified before --l7proto. 413 | + 414 | --- iptables-1.4.0rc1/extensions/.layer7-test 1969-12-31 18:00:00.000000000 -0600 415 | +++ iptables-1.4.0rc1-layer7/extensions/.layer7-test 2007-11-19 06:18:58.000000000 -0600 416 | @@ -0,0 +1,2 @@ 417 | +#! /bin/sh 418 | +[ -f $KERNEL_DIR/include/linux/netfilter/xt_layer7.h ] && echo layer7 419 | -------------------------------------------------------------------------------- /for_older_iptables/iptables-1.4.1.1-for-kernel-2.6.20forward/libxt_layer7.c: -------------------------------------------------------------------------------- 1 | /* 2 | Shared library add-on to iptables for layer 7 matching support. 3 | 4 | By Matthew Strait , Oct 2003-Aug 2008. 5 | 6 | http://l7-filter.sf.net 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 11 | 2 of the License, or (at your option) any later version. 12 | http://www.gnu.org/licenses/gpl.txt 13 | */ 14 | 15 | #define _GNU_SOURCE 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #define MAX_FN_LEN 256 28 | 29 | static char l7dir[MAX_FN_LEN] = "\0"; 30 | 31 | /* Function which prints out usage message. */ 32 | static void help(void) 33 | { 34 | printf( 35 | "layer7 match options:\n" 36 | " --l7dir : Look for patterns here instead of /etc/l7-protocols/\n" 37 | " (--l7dir must be specified before --l7proto if used)\n" 38 | "[!] --l7proto : Match named protocol using /etc/l7-protocols/.../name.pat\n"); 39 | } 40 | 41 | static const struct option opts[] = { 42 | { .name = "l7proto", .has_arg = 1, .val = 'p' }, 43 | { .name = "l7dir", .has_arg = 1, .val = 'd' }, 44 | { .name = NULL } 45 | }; 46 | 47 | /* reads filename, puts protocol info into layer7_protocol_info, number of protocols to numprotos */ 48 | static int parse_protocol_file(char * filename, const char * protoname, struct xt_layer7_info *info) 49 | { 50 | FILE * f; 51 | char * line = NULL; 52 | size_t len = 0; 53 | 54 | enum { protocol, pattern, done } datatype = protocol; 55 | 56 | f = fopen(filename, "r"); 57 | 58 | if(!f) 59 | return 0; 60 | 61 | while(getline(&line, &len, f) != -1) 62 | { 63 | if(strlen(line) < 2 || line[0] == '#') 64 | continue; 65 | 66 | /* strip the pesky newline... */ 67 | if(line[strlen(line) - 1] == '\n') 68 | line[strlen(line) - 1] = '\0'; 69 | 70 | if(datatype == protocol) 71 | { 72 | /* Ignore everything on the line beginning with the 73 | first space or tab . For instance, this allows the 74 | protocol line in http.pat to be "http " (or 75 | "http I am so cool") instead of just "http". */ 76 | if(strchr(line, ' ')){ 77 | char * space = strchr(line, ' '); 78 | space[0] = '\0'; 79 | } 80 | if(strchr(line, '\t')){ 81 | char * space = strchr(line, '\t'); 82 | space[0] = '\0'; 83 | } 84 | 85 | /* sanity check. First non-comment non-blank 86 | line must be the same as the file name. */ 87 | if(strcmp(line, protoname)) 88 | exit_error(OTHER_PROBLEM, 89 | "Protocol name (%s) doesn't match file name (%s). Bailing out\n", 90 | line, filename); 91 | 92 | if(strlen(line) >= MAX_PROTOCOL_LEN) 93 | exit_error(PARAMETER_PROBLEM, 94 | "Protocol name in %s too long!", filename); 95 | strncpy(info->protocol, line, MAX_PROTOCOL_LEN); 96 | 97 | datatype = pattern; 98 | } 99 | else if(datatype == pattern) 100 | { 101 | if(strlen(line) >= MAX_PATTERN_LEN) 102 | exit_error(PARAMETER_PROBLEM, "Pattern in %s too long!", filename); 103 | strncpy(info->pattern, line, MAX_PATTERN_LEN); 104 | 105 | datatype = done; 106 | break; 107 | } 108 | else 109 | exit_error(OTHER_PROBLEM, "Internal error"); 110 | } 111 | 112 | if(datatype != done) 113 | exit_error(OTHER_PROBLEM, "Failed to get all needed data from %s", filename); 114 | 115 | if(line) free(line); 116 | fclose(f); 117 | 118 | return 1; 119 | } 120 | 121 | static int hex2dec(char c) 122 | { 123 | switch (c) 124 | { 125 | case '0' ... '9': 126 | return c - '0'; 127 | case 'a' ... 'f': 128 | return c - 'a' + 10; 129 | case 'A' ... 'F': 130 | return c - 'A' + 10; 131 | default: 132 | exit_error(OTHER_PROBLEM, "hex2dec: bad value!\n"); 133 | return 0; 134 | } 135 | } 136 | 137 | /* takes a string with \xHH escapes and returns one with the characters 138 | they stand for */ 139 | static char * pre_process(char * s) 140 | { 141 | char * result = malloc(strlen(s) + 1); 142 | int sindex = 0, rrindex = 0; 143 | while( sindex < strlen(s) ) 144 | { 145 | if( sindex + 3 < strlen(s) && 146 | s[sindex] == '\\' && s[sindex+1] == 'x' && 147 | isxdigit(s[sindex + 2]) && isxdigit(s[sindex + 3]) ) 148 | { 149 | /* carefully remember to call tolower here... */ 150 | result[rrindex] = tolower( hex2dec(s[sindex + 2])*16 + 151 | hex2dec(s[sindex + 3] ) ); 152 | 153 | switch ( result[rrindex] ) 154 | { 155 | case 0x24: 156 | case 0x28: 157 | case 0x29: 158 | case 0x2a: 159 | case 0x2b: 160 | case 0x2e: 161 | case 0x3f: 162 | case 0x5b: 163 | case 0x5c: 164 | case 0x5d: 165 | case 0x5e: 166 | case 0x7c: 167 | fprintf(stderr, 168 | "Warning: layer7 regexp contains a control character, %c, in hex (\\x%c%c).\n" 169 | "I recommend that you write this as %c or \\%c, depending on what you meant.\n", 170 | result[rrindex], s[sindex + 2], s[sindex + 3], result[rrindex], result[rrindex]); 171 | break; 172 | case 0x00: 173 | fprintf(stderr, 174 | "Warning: null (\\x00) in layer7 regexp. A null terminates the regexp string!\n"); 175 | break; 176 | default: 177 | break; 178 | } 179 | 180 | 181 | sindex += 3; /* 4 total */ 182 | } 183 | else 184 | result[rrindex] = tolower(s[sindex]); 185 | 186 | sindex++; 187 | rrindex++; 188 | } 189 | result[rrindex] = '\0'; 190 | 191 | return result; 192 | } 193 | 194 | #define MAX_SUBDIRS 128 195 | static char ** readl7dir(char * dirname) 196 | { 197 | DIR * scratchdir; 198 | struct dirent ** namelist; 199 | char ** subdirs = malloc(MAX_SUBDIRS * sizeof(char *)); 200 | 201 | int n, d = 1; 202 | subdirs[0] = ""; 203 | 204 | n = scandir(dirname, &namelist, 0, alphasort); 205 | 206 | if (n < 0) 207 | { 208 | perror("scandir"); 209 | exit_error(OTHER_PROBLEM, "Couldn't open %s\n", dirname); 210 | } 211 | else 212 | { 213 | while(n--) 214 | { 215 | char fulldirname[MAX_FN_LEN]; 216 | 217 | snprintf(fulldirname, MAX_FN_LEN, "%s/%s", dirname, namelist[n]->d_name); 218 | 219 | if((scratchdir = opendir(fulldirname)) != NULL) 220 | { 221 | closedir(scratchdir); 222 | 223 | if(!strcmp(namelist[n]->d_name, ".") || 224 | !strcmp(namelist[n]->d_name, "..")) 225 | /* do nothing */ ; 226 | else 227 | { 228 | subdirs[d] = malloc(strlen(namelist[n]->d_name) + 1); 229 | strcpy(subdirs[d], namelist[n]->d_name); 230 | d++; 231 | if(d >= MAX_SUBDIRS - 1) 232 | { 233 | fprintf(stderr, 234 | "Too many subdirectories, skipping the rest!\n"); 235 | break; 236 | } 237 | } 238 | } 239 | free(namelist[n]); 240 | } 241 | free(namelist); 242 | } 243 | 244 | subdirs[d] = NULL; 245 | 246 | return subdirs; 247 | } 248 | 249 | static void parse_layer7_protocol(const char *s, struct xt_layer7_info *info) 250 | { 251 | char filename[MAX_FN_LEN]; 252 | char * dir = NULL; 253 | char ** subdirs; 254 | int n = 0, done = 0; 255 | 256 | if(strlen(l7dir) > 0) dir = l7dir; 257 | else dir = "/etc/l7-protocols"; 258 | 259 | subdirs = readl7dir(dir); 260 | 261 | while(subdirs[n] != NULL) 262 | { 263 | int c = snprintf(filename, MAX_FN_LEN, "%s/%s/%s.pat", dir, subdirs[n], s); 264 | 265 | if(c > MAX_FN_LEN) 266 | exit_error(OTHER_PROBLEM, 267 | "Filename beginning with %s is too long!\n", filename); 268 | 269 | /* read in the pattern from the file */ 270 | if(parse_protocol_file(filename, s, info)){ 271 | done = 1; 272 | break; 273 | } 274 | 275 | n++; 276 | } 277 | 278 | if(!done) 279 | exit_error(OTHER_PROBLEM, 280 | "Couldn't find a pattern definition file for %s.\n", s); 281 | 282 | /* process \xHH escapes and tolower everything. (our regex lib has no 283 | case insensitivity option.) */ 284 | strncpy(info->pattern, pre_process(info->pattern), MAX_PATTERN_LEN); 285 | } 286 | 287 | /* Function which parses command options; returns true if it ate an option */ 288 | static int parse(int c, char **argv, int invert, unsigned int *flags, 289 | const void *entry, struct xt_entry_match **match) 290 | { 291 | struct xt_layer7_info *layer7info = 292 | (struct xt_layer7_info *)(*match)->data; 293 | 294 | switch (c) { 295 | case 'p': 296 | parse_layer7_protocol(argv[optind-1], layer7info); 297 | if (invert) 298 | layer7info->invert = true; 299 | *flags = 1; 300 | break; 301 | 302 | case 'd': 303 | if(strlen(argv[optind-1]) >= MAX_FN_LEN) 304 | exit_error(PARAMETER_PROBLEM, "directory name too long\n"); 305 | 306 | strncpy(l7dir, argv[optind-1], MAX_FN_LEN); 307 | 308 | *flags = 1; 309 | break; 310 | 311 | default: 312 | return 0; 313 | } 314 | 315 | return 1; 316 | } 317 | 318 | /* Final check; must have specified --l7proto */ 319 | static void final_check(unsigned int flags) 320 | { 321 | if (!flags) 322 | exit_error(PARAMETER_PROBLEM, 323 | "LAYER7 match: You must specify `--l7proto'"); 324 | } 325 | 326 | static void print_protocol(char s[], int invert, int numeric) 327 | { 328 | fputs("l7proto ", stdout); 329 | if (invert) fputc('!', stdout); 330 | printf("%s ", s); 331 | } 332 | 333 | /* Prints out the matchinfo. */ 334 | static void print(const void *ip, 335 | const struct xt_entry_match *match, 336 | int numeric) 337 | { 338 | printf("LAYER7 "); 339 | print_protocol(((struct xt_layer7_info *)match->data)->protocol, 340 | ((struct xt_layer7_info *)match->data)->invert, numeric); 341 | } 342 | /* Saves the union ipt_matchinfo in parsable form to stdout. */ 343 | static void save(const void *ip, const struct xt_entry_match *match) 344 | { 345 | const struct xt_layer7_info *info = 346 | (const struct xt_layer7_info*) match->data; 347 | 348 | printf("--l7proto %s%s ", (info->invert)? "! ":"", info->protocol); 349 | } 350 | 351 | static struct xtables_match layer7 = { 352 | .family = AF_INET, 353 | .name = "layer7", 354 | .version = XTABLES_VERSION, 355 | .size = XT_ALIGN(sizeof(struct xt_layer7_info)), 356 | .userspacesize = XT_ALIGN(sizeof(struct xt_layer7_info)), 357 | .help = &help, 358 | .parse = &parse, 359 | .final_check = &final_check, 360 | .print = &print, 361 | .save = &save, 362 | .extra_opts = opts 363 | }; 364 | 365 | void _init(void) 366 | { 367 | xtables_register_match(&layer7); 368 | } 369 | -------------------------------------------------------------------------------- /for_older_iptables/iptables-1.4.1.1-for-kernel-2.6.20forward/libxt_layer7.man: -------------------------------------------------------------------------------- 1 | This module matches packets based on the application layer data of 2 | their connections. It uses regular expression matching to compare 3 | the application layer data to regular expressions found it the layer7 4 | configuration files. This is an experimental module which can be found at 5 | http://l7-filter.sf.net. It takes two options. 6 | .TP 7 | .BI "--l7proto " "\fIprotocol\fP" 8 | Match the specified protocol. The protocol name must match a file 9 | name in /etc/l7-protocols/ or one of its first-level child directories. 10 | .TP 11 | .BI "--l7dir " "\fIdirectory\fP" 12 | Use \fIdirectory\fP instead of /etc/l7-protocols/. This option must be 13 | specified before --l7proto. 14 | 15 | -------------------------------------------------------------------------------- /for_older_kernels/kernel-2.6.11-2.6.12-layer7-1.4.patch: -------------------------------------------------------------------------------- 1 | --- linux-2.6.11.3-stock/include/linux/netfilter_ipv4/ip_conntrack.h 2005-03-13 00:44:41.000000000 -0600 2 | +++ linux-2.6.11.3-layer7/include/linux/netfilter_ipv4/ip_conntrack.h 2005-03-13 20:30:01.000000000 -0600 3 | @@ -177,6 +177,15 @@ struct ip_conntrack 4 | /* Traversed often, so hopefully in different cacheline to top */ 5 | /* These are my tuples; original and reply */ 6 | struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; 7 | + 8 | +#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) 9 | + struct { 10 | + char * app_proto; /* e.g. "http". NULL before decision. "unknown" after decision if no match */ 11 | + char * app_data; /* application layer data so far. NULL after match decision */ 12 | + unsigned int app_data_len; 13 | + } layer7; 14 | +#endif 15 | + 16 | }; 17 | 18 | struct ip_conntrack_expect 19 | --- linux-2.6.11.3-stock/include/linux/netfilter_ipv4/ipt_layer7.h 1969-12-31 18:00:00.000000000 -0600 20 | +++ linux-2.6.11.3-layer7/include/linux/netfilter_ipv4/ipt_layer7.h 2005-03-13 20:30:01.000000000 -0600 21 | @@ -0,0 +1,26 @@ 22 | +/* 23 | + By Matthew Strait , Dec 2003. 24 | + http://l7-filter.sf.net 25 | + 26 | + This program is free software; you can redistribute it and/or 27 | + modify it under the terms of the GNU General Public License 28 | + as published by the Free Software Foundation; either version 29 | + 2 of the License, or (at your option) any later version. 30 | + http://www.gnu.org/licenses/gpl.txt 31 | +*/ 32 | + 33 | +#ifndef _IPT_LAYER7_H 34 | +#define _IPT_LAYER7_H 35 | + 36 | +#define MAX_PATTERN_LEN 8192 37 | +#define MAX_PROTOCOL_LEN 256 38 | + 39 | +typedef char *(*proc_ipt_search) (char *, char, char *); 40 | + 41 | +struct ipt_layer7_info { 42 | + char protocol[MAX_PROTOCOL_LEN]; 43 | + char invert:1; 44 | + char pattern[MAX_PATTERN_LEN]; 45 | +}; 46 | + 47 | +#endif /* _IPT_LAYER7_H */ 48 | --- linux-2.6.11.3-stock/net/ipv4/netfilter/Kconfig 2005-03-13 00:44:38.000000000 -0600 49 | +++ linux-2.6.11.3-layer7/net/ipv4/netfilter/Kconfig 2005-03-13 20:30:01.000000000 -0600 50 | @@ -146,6 +146,33 @@ config IP_NF_MATCH_MAC 51 | 52 | To compile it as a module, choose M here. If unsure, say N. 53 | 54 | +config IP_NF_MATCH_LAYER7 55 | + tristate "Layer 7 match support (EXPERIMENTAL)" 56 | + depends on IP_NF_IPTABLES && IP_NF_CT_ACCT && IP_NF_CONNTRACK && EXPERIMENTAL 57 | + help 58 | + Say Y if you want to be able to classify connections (and their 59 | + packets) based on regular expression matching of their application 60 | + layer data. This is one way to classify applications such as 61 | + peer-to-peer filesharing systems that do not always use the same 62 | + port. 63 | + 64 | + To compile it as a module, choose M here. If unsure, say N. 65 | + 66 | +config IP_NF_MATCH_LAYER7_DEBUG 67 | + bool "Layer 7 debugging output" 68 | + depends on IP_NF_MATCH_LAYER7 69 | + help 70 | + Say Y to get lots of debugging output. 71 | + 72 | +config IP_NF_MATCH_LAYER7_MAXDATALEN 73 | + int "Buffer size for application layer data" if IP_NF_MATCH_LAYER7 74 | + range 256 65536 75 | + default 2048 76 | + help 77 | + Size of the buffer that the application layer data is stored in. 78 | + Unless you know what you're doing, leave it at the default of 2kB. 79 | + 80 | + 81 | config IP_NF_MATCH_PKTTYPE 82 | tristate "Packet type match support" 83 | depends on IP_NF_IPTABLES 84 | --- linux-2.6.11.3-stock/net/ipv4/netfilter/Makefile 2005-03-13 00:44:14.000000000 -0600 85 | +++ linux-2.6.11.3-layer7/net/ipv4/netfilter/Makefile 2005-03-13 20:30:01.000000000 -0600 86 | @@ -60,6 +60,8 @@ obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ip 87 | obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o 88 | obj-$(CONFIG_IP_NF_MATCH_COMMENT) += ipt_comment.o 89 | 90 | +obj-$(CONFIG_IP_NF_MATCH_LAYER7) += ipt_layer7.o 91 | + 92 | # targets 93 | obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o 94 | obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o 95 | --- linux-2.6.11.3-stock/net/ipv4/netfilter/ip_conntrack_core.c 2005-03-13 00:43:57.000000000 -0600 96 | +++ linux-2.6.11.3-layer7/net/ipv4/netfilter/ip_conntrack_core.c 2005-03-13 22:09:32.000000000 -0600 97 | @@ -247,6 +247,13 @@ destroy_conntrack(struct nf_conntrack *n 98 | * too. */ 99 | remove_expectations(ct); 100 | 101 | + #if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) 102 | + if(ct->layer7.app_proto) 103 | + kfree(ct->layer7.app_proto); 104 | + if(ct->layer7.app_data) 105 | + kfree(ct->layer7.app_data); 106 | + #endif 107 | + 108 | /* We overload first tuple to link into unconfirmed list. */ 109 | if (!is_confirmed(ct)) { 110 | BUG_ON(list_empty(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list)); 111 | --- linux-2.6.11.3-stock/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-03-13 00:44:25.000000000 -0600 112 | +++ linux-2.6.11.3-layer7/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-03-13 20:30:01.000000000 -0600 113 | @@ -152,6 +152,12 @@ static int ct_seq_real_show(const struct 114 | return 1; 115 | #endif 116 | 117 | +#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) 118 | + if(conntrack->layer7.app_proto) 119 | + if (seq_printf(s, "l7proto=%s ",conntrack->layer7.app_proto)) 120 | + return 1; 121 | +#endif 122 | + 123 | if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use))) 124 | return 1; 125 | 126 | --- linux-2.6.11.3-stock/net/ipv4/netfilter/ipt_layer7.c 1969-12-31 18:00:00.000000000 -0600 127 | +++ linux-2.6.11.3-layer7/net/ipv4/netfilter/ipt_layer7.c 2005-03-13 20:30:01.000000000 -0600 128 | @@ -0,0 +1,552 @@ 129 | +/* 130 | + Kernel module to match application layer (OSI layer 7) 131 | + data in connections. 132 | + 133 | + http://l7-filter.sf.net 134 | + 135 | + By Matthew Strait and Ethan Sommer, 2003-2005. 136 | + 137 | + This program is free software; you can redistribute it and/or 138 | + modify it under the terms of the GNU General Public License 139 | + as published by the Free Software Foundation; either version 140 | + 2 of the License, or (at your option) any later version. 141 | + http://www.gnu.org/licenses/gpl.txt 142 | + 143 | + Based on ipt_string.c (C) 2000 Emmanuel Roger 144 | + and cls_layer7.c (C) 2003 Matthew Strait, Ethan Sommer, Justin Levandoski 145 | +*/ 146 | + 147 | +#include 148 | +#include 149 | +#include 150 | +#include 151 | +#include 152 | +#include 153 | +#include 154 | +#include 155 | + 156 | +#include "regexp/regexp.c" 157 | + 158 | +#include 159 | +#include 160 | + 161 | +MODULE_AUTHOR("Matthew Strait , Ethan Sommer "); 162 | +MODULE_LICENSE("GPL"); 163 | +MODULE_DESCRIPTION("iptables application layer match module"); 164 | + 165 | +#if defined(CONFIG_IP_NF_MATCH_LAYER7_DEBUG) 166 | + #define DPRINTK(format,args...) printk(format,##args) 167 | +#else 168 | + #define DPRINTK(format,args...) 169 | +#endif 170 | + 171 | +#define TOTAL_PACKETS master_conntrack->counters[IP_CT_DIR_ORIGINAL].packets + \ 172 | + master_conntrack->counters[IP_CT_DIR_REPLY].packets 173 | + 174 | +/* Number of packets whose data we look at. 175 | +This can be modified through /proc/net/layer7_numpackets */ 176 | +static int num_packets = 8; 177 | + 178 | +static struct pattern_cache { 179 | + char * regex_string; 180 | + regexp * pattern; 181 | + struct pattern_cache * next; 182 | +} * first_pattern_cache = NULL; 183 | + 184 | +/* I'm new to locking. Here are my assumptions: 185 | + 186 | +- No one will write to /proc/net/layer7_numpackets over and over very fast; 187 | + if they did, nothing awful would happen. 188 | + 189 | +- This code will never be processing the same packet twice at the same time, 190 | + because iptables rules are traversed in order. 191 | + 192 | +- It doesn't matter if two packets from different connections are in here at 193 | + the same time, because they don't share any data. 194 | + 195 | +- It _does_ matter if two packets from the same connection are here at the same 196 | + time. In this case, we have to protect the conntracks and the list of 197 | + compiled patterns. 198 | +*/ 199 | +DECLARE_RWLOCK(ct_lock); 200 | +DECLARE_LOCK(list_lock); 201 | + 202 | +#if CONFIG_IP_NF_MATCH_LAYER7_DEBUG 203 | +/* Converts an unfriendly string into a friendly one by 204 | +replacing unprintables with periods and all whitespace with " ". */ 205 | +static char * friendly_print(unsigned char * s) 206 | +{ 207 | + char * f = kmalloc(strlen(s) + 1, GFP_ATOMIC); 208 | + int i; 209 | + 210 | + if(!f) { 211 | + if (net_ratelimit()) 212 | + printk(KERN_ERR "layer7: out of memory in friendly_print, bailing.\n"); 213 | + return NULL; 214 | + } 215 | + 216 | + for(i = 0; i < strlen(s); i++){ 217 | + if(isprint(s[i]) && s[i] < 128) f[i] = s[i]; 218 | + else if(isspace(s[i])) f[i] = ' '; 219 | + else f[i] = '.'; 220 | + } 221 | + f[i] = '\0'; 222 | + return f; 223 | +} 224 | + 225 | +static char dec2hex(int i) 226 | +{ 227 | + switch (i) { 228 | + case 0 ... 9: 229 | + return (char)(i + '0'); 230 | + break; 231 | + case 10 ... 15: 232 | + return (char)(i - 10 + 'a'); 233 | + break; 234 | + default: 235 | + if (net_ratelimit()) 236 | + printk("Problem in dec2hex\n"); 237 | + return '\0'; 238 | + } 239 | +} 240 | + 241 | +static char * hex_print(unsigned char * s) 242 | +{ 243 | + char * g = kmalloc(strlen(s)*3 + 1, GFP_ATOMIC); 244 | + int i; 245 | + 246 | + if(!g) { 247 | + if (net_ratelimit()) 248 | + printk(KERN_ERR "layer7: out of memory in hex_print, bailing.\n"); 249 | + return NULL; 250 | + } 251 | + 252 | + for(i = 0; i < strlen(s); i++) { 253 | + g[i*3 ] = dec2hex(s[i]/16); 254 | + g[i*3 + 1] = dec2hex(s[i]%16); 255 | + g[i*3 + 2] = ' '; 256 | + } 257 | + g[i*3] = '\0'; 258 | + 259 | + return g; 260 | +} 261 | +#endif // DEBUG 262 | + 263 | +/* Use instead of regcomp. As we expect to be seeing the same regexps over and 264 | +over again, it make sense to cache the results. */ 265 | +static regexp * compile_and_cache(char * regex_string, char * protocol) 266 | +{ 267 | + struct pattern_cache * node = first_pattern_cache; 268 | + struct pattern_cache * last_pattern_cache = first_pattern_cache; 269 | + struct pattern_cache * tmp; 270 | + unsigned int len; 271 | + 272 | + while (node != NULL) { 273 | + if (!strcmp(node->regex_string, regex_string)) 274 | + return node->pattern; 275 | + 276 | + last_pattern_cache = node;/* points at the last non-NULL node */ 277 | + node = node->next; 278 | + } 279 | + 280 | + /* If we reach the end of the list, then we have not yet cached 281 | + the pattern for this regex. Let's do that now. 282 | + Be paranoid about running out of memory to avoid list corruption. */ 283 | + tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC); 284 | + 285 | + if(!tmp) { 286 | + if (net_ratelimit()) 287 | + printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n"); 288 | + return NULL; 289 | + } 290 | + 291 | + tmp->regex_string = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC); 292 | + tmp->pattern = kmalloc(sizeof(struct regexp), GFP_ATOMIC); 293 | + tmp->next = NULL; 294 | + 295 | + if(!tmp->regex_string || !tmp->pattern) { 296 | + if (net_ratelimit()) 297 | + printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n"); 298 | + kfree(tmp->regex_string); 299 | + kfree(tmp->pattern); 300 | + kfree(tmp); 301 | + return NULL; 302 | + } 303 | + 304 | + /* Ok. The new node is all ready now. */ 305 | + node = tmp; 306 | + 307 | + if(first_pattern_cache == NULL) /* list is empty */ 308 | + first_pattern_cache = node; /* make node the beginning */ 309 | + else 310 | + last_pattern_cache->next = node; /* attach node to the end */ 311 | + 312 | + /* copy the string and compile the regex */ 313 | + len = strlen(regex_string); 314 | + DPRINTK("About to compile this: \"%s\"\n", regex_string); 315 | + node->pattern = regcomp(regex_string, &len); 316 | + if ( !node->pattern ) { 317 | + if (net_ratelimit()) 318 | + printk(KERN_ERR "layer7: Error compiling regexp \"%s\" (%s)\n", regex_string, protocol); 319 | + /* pattern is now cached as NULL, so we won't try again. */ 320 | + } 321 | + 322 | + strcpy(node->regex_string, regex_string); 323 | + return node->pattern; 324 | +} 325 | + 326 | +static int can_handle(const struct sk_buff *skb) 327 | +{ 328 | + if(!skb->nh.iph) /* not IP */ 329 | + return 0; 330 | + if(skb->nh.iph->protocol != IPPROTO_TCP && 331 | + skb->nh.iph->protocol != IPPROTO_UDP && 332 | + skb->nh.iph->protocol != IPPROTO_ICMP) 333 | + return 0; 334 | + return 1; 335 | +} 336 | + 337 | +/* Returns offset the into the skb->data that the application data starts */ 338 | +static int app_data_offset(const struct sk_buff *skb) 339 | +{ 340 | + /* In case we are ported somewhere (ebtables?) where skb->nh.iph 341 | + isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */ 342 | + int ip_hl = 4*skb->nh.iph->ihl; 343 | + 344 | + if( skb->nh.iph->protocol == IPPROTO_TCP ) { 345 | + /* 12 == offset into TCP header for the header length field. 346 | + Can't get this with skb->h.th->doff because the tcphdr 347 | + struct doesn't get set when routing (this is confirmed to be 348 | + true in Netfilter as well as QoS.) */ 349 | + int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4); 350 | + 351 | + return ip_hl + tcp_hl; 352 | + } else if( skb->nh.iph->protocol == IPPROTO_UDP ) { 353 | + return ip_hl + 8; /* UDP header is always 8 bytes */ 354 | + } else if( skb->nh.iph->protocol == IPPROTO_ICMP ) { 355 | + return ip_hl + 8; /* ICMP header is 8 bytes */ 356 | + } else { 357 | + if (net_ratelimit()) 358 | + printk(KERN_ERR "layer7: tried to handle unknown protocol!\n"); 359 | + return ip_hl + 8; /* something reasonable */ 360 | + } 361 | +} 362 | + 363 | +/* handles whether there's a match when we aren't appending data anymore */ 364 | +static int match_no_append(struct ip_conntrack * conntrack, struct ip_conntrack * master_conntrack, 365 | + enum ip_conntrack_info ctinfo, enum ip_conntrack_info master_ctinfo, 366 | + struct ipt_layer7_info * info) 367 | +{ 368 | + /* If we're in here, throw the app data away */ 369 | + WRITE_LOCK(&ct_lock); 370 | + if(master_conntrack->layer7.app_data != NULL) { 371 | + 372 | + #ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG 373 | + if(!master_conntrack->layer7.app_proto) { 374 | + char * f = friendly_print(master_conntrack->layer7.app_data); 375 | + char * g = hex_print(master_conntrack->layer7.app_data); 376 | + DPRINTK("\nl7-filter gave up after %d bytes (%llu packets):\n%s\n", 377 | + strlen(f), 378 | + TOTAL_PACKETS, f); 379 | + kfree(f); 380 | + DPRINTK("In hex: %s\n", g); 381 | + kfree(g); 382 | + } 383 | + #endif 384 | + 385 | + kfree(master_conntrack->layer7.app_data); 386 | + master_conntrack->layer7.app_data = NULL; /* don't free again */ 387 | + } 388 | + WRITE_UNLOCK(&ct_lock); 389 | + 390 | + if(master_conntrack->layer7.app_proto){ 391 | + /* Here child connections set their .app_proto (for /proc/net/ip_conntrack) */ 392 | + WRITE_LOCK(&ct_lock); 393 | + if(!conntrack->layer7.app_proto) { 394 | + conntrack->layer7.app_proto = kmalloc(strlen(master_conntrack->layer7.app_proto)+1, GFP_ATOMIC); 395 | + if(!conntrack->layer7.app_proto){ 396 | + if (net_ratelimit()) 397 | + printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n"); 398 | + WRITE_UNLOCK(&ct_lock); 399 | + return 1; 400 | + } 401 | + strcpy(conntrack->layer7.app_proto, master_conntrack->layer7.app_proto); 402 | + } 403 | + WRITE_UNLOCK(&ct_lock); 404 | + 405 | + return (!strcmp(master_conntrack->layer7.app_proto, info->protocol)); 406 | + } 407 | + else { 408 | + /* If not classified, set to "unknown" to distinguish from 409 | + connections that are still being tested. */ 410 | + WRITE_LOCK(&ct_lock); 411 | + master_conntrack->layer7.app_proto = kmalloc(strlen("unknown")+1, GFP_ATOMIC); 412 | + if(!master_conntrack->layer7.app_proto){ 413 | + if (net_ratelimit()) 414 | + printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n"); 415 | + WRITE_UNLOCK(&ct_lock); 416 | + return 1; 417 | + } 418 | + strcpy(master_conntrack->layer7.app_proto, "unknown"); 419 | + WRITE_UNLOCK(&ct_lock); 420 | + return 0; 421 | + } 422 | +} 423 | + 424 | +/* add the new app data to the conntrack. Return number of bytes added. */ 425 | +static int add_data(struct ip_conntrack * master_conntrack, 426 | + char * app_data, int appdatalen) 427 | +{ 428 | + int length = 0, i; 429 | + int oldlength = master_conntrack->layer7.app_data_len; 430 | + 431 | + /* Strip nulls. Make everything lower case (our regex lib doesn't 432 | + do case insensitivity). Add it to the end of the current data. */ 433 | + for(i = 0; i < CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN-oldlength-1 && 434 | + i < appdatalen; i++) { 435 | + if(app_data[i] != '\0') { 436 | + master_conntrack->layer7.app_data[length+oldlength] = 437 | + /* the kernel version of tolower mungs 'upper ascii' */ 438 | + isascii(app_data[i])? tolower(app_data[i]) : app_data[i]; 439 | + length++; 440 | + } 441 | + } 442 | + 443 | + master_conntrack->layer7.app_data[length+oldlength] = '\0'; 444 | + master_conntrack->layer7.app_data_len = length + oldlength; 445 | + 446 | + return length; 447 | +} 448 | + 449 | +/* Returns true on match and false otherwise. */ 450 | +static int match(/* const */struct sk_buff *skb, const struct net_device *in, 451 | + const struct net_device *out, const void *matchinfo, 452 | + int offset, int *hotdrop) 453 | +{ 454 | + struct ipt_layer7_info * info = (struct ipt_layer7_info *)matchinfo; 455 | + enum ip_conntrack_info master_ctinfo, ctinfo; 456 | + struct ip_conntrack *master_conntrack, *conntrack; 457 | + unsigned char * app_data; 458 | + unsigned int pattern_result, appdatalen; 459 | + regexp * comppattern; 460 | + 461 | + if(!can_handle(skb)){ 462 | + DPRINTK("layer7: This is some protocol I can't handle.\n"); 463 | + return info->invert; 464 | + } 465 | + 466 | + /* Treat the parent and all its children together as one connection, 467 | + except for the purpose of setting conntrack->layer7.app_proto in the 468 | + actual connection. This makes /proc/net/ip_conntrack somewhat more 469 | + satisfying. */ 470 | + if(!(conntrack = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) || 471 | + !(master_conntrack = ip_conntrack_get((struct sk_buff *)skb, &master_ctinfo))) { 472 | + DPRINTK("layer7: packet is not from a known connection, giving up.\n"); 473 | + return info->invert; 474 | + } 475 | + 476 | + /* Try to get a master conntrack (and its master etc) for FTP, etc. */ 477 | + while (master_ct(master_conntrack) != NULL) 478 | + master_conntrack = master_ct(master_conntrack); 479 | + 480 | + /* if we've classified it or seen too many packets */ 481 | + if(TOTAL_PACKETS > num_packets || 482 | + master_conntrack->layer7.app_proto) { 483 | + 484 | + pattern_result = match_no_append(conntrack, master_conntrack, ctinfo, master_ctinfo, info); 485 | + 486 | + /* skb->cb[0] == seen. Avoid doing things twice if there are two l7 487 | + rules. I'm not sure that using cb for this purpose is correct, although 488 | + it says "put your private variables there". But it doesn't look like it 489 | + is being used for anything else in the skbs that make it here. How can 490 | + I write to cb without making the compiler angry? */ 491 | + skb->cb[0] = 1; /* marking it seen here is probably irrelevant, but consistant */ 492 | + 493 | + return (pattern_result ^ info->invert); 494 | + } 495 | + 496 | + if(skb_is_nonlinear(skb)){ 497 | + if(skb_linearize(skb, GFP_ATOMIC) != 0){ 498 | + if (net_ratelimit()) 499 | + printk(KERN_ERR "layer7: failed to linearize packet, bailing.\n"); 500 | + return info->invert; 501 | + } 502 | + } 503 | + 504 | + /* now that the skb is linearized, it's safe to set these. */ 505 | + app_data = skb->data + app_data_offset(skb); 506 | + appdatalen = skb->tail - app_data; 507 | + 508 | + LOCK_BH(&list_lock); 509 | + /* the return value gets checked later, when we're ready to use it */ 510 | + comppattern = compile_and_cache(info->pattern, info->protocol); 511 | + UNLOCK_BH(&list_lock); 512 | + 513 | + /* On the first packet of a connection, allocate space for app data */ 514 | + WRITE_LOCK(&ct_lock); 515 | + if(TOTAL_PACKETS == 1 && !skb->cb[0] && !master_conntrack->layer7.app_data) { 516 | + master_conntrack->layer7.app_data = kmalloc(CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN, GFP_ATOMIC); 517 | + if(!master_conntrack->layer7.app_data){ 518 | + if (net_ratelimit()) 519 | + printk(KERN_ERR "layer7: out of memory in match, bailing.\n"); 520 | + WRITE_UNLOCK(&ct_lock); 521 | + return info->invert; 522 | + } 523 | + 524 | + master_conntrack->layer7.app_data[0] = '\0'; 525 | + } 526 | + WRITE_UNLOCK(&ct_lock); 527 | + 528 | + /* Can be here, but unallocated, if numpackets is increased near 529 | + the beginning of a connection */ 530 | + if(master_conntrack->layer7.app_data == NULL) 531 | + return (info->invert); /* unmatched */ 532 | + 533 | + if(!skb->cb[0]){ 534 | + int newbytes; 535 | + WRITE_LOCK(&ct_lock); 536 | + newbytes = add_data(master_conntrack, app_data, appdatalen); 537 | + WRITE_UNLOCK(&ct_lock); 538 | + 539 | + if(newbytes == 0) { /* didn't add any data */ 540 | + skb->cb[0] = 1; 541 | + /* Didn't match before, not going to match now */ 542 | + return info->invert; 543 | + } 544 | + } 545 | + 546 | + /* If looking for "unknown", then never match. "Unknown" means that 547 | + we've given up; we're still trying with these packets. */ 548 | + if(!strcmp(info->protocol, "unknown")) { 549 | + pattern_result = 0; 550 | + /* If the regexp failed to compile, don't bother running it */ 551 | + } else if(comppattern && regexec(comppattern, master_conntrack->layer7.app_data)) { 552 | + DPRINTK("layer7: regexec positive: %s!\n", info->protocol); 553 | + pattern_result = 1; 554 | + } else pattern_result = 0; 555 | + 556 | + if(pattern_result) { 557 | + WRITE_LOCK(&ct_lock); 558 | + master_conntrack->layer7.app_proto = kmalloc(strlen(info->protocol)+1, GFP_ATOMIC); 559 | + if(!master_conntrack->layer7.app_proto){ 560 | + if (net_ratelimit()) 561 | + printk(KERN_ERR "layer7: out of memory in match, bailing.\n"); 562 | + WRITE_UNLOCK(&ct_lock); 563 | + return (pattern_result ^ info->invert); 564 | + } 565 | + strcpy(master_conntrack->layer7.app_proto, info->protocol); 566 | + WRITE_UNLOCK(&ct_lock); 567 | + } 568 | + 569 | + /* mark the packet seen */ 570 | + skb->cb[0] = 1; 571 | + 572 | + return (pattern_result ^ info->invert); 573 | +} 574 | + 575 | +static int checkentry(const char *tablename, const struct ipt_ip *ip, 576 | + void *matchinfo, unsigned int matchsize, unsigned int hook_mask) 577 | +{ 578 | + if (matchsize != IPT_ALIGN(sizeof(struct ipt_layer7_info))) 579 | + return 0; 580 | + return 1; 581 | +} 582 | + 583 | +static struct ipt_match layer7_match = { 584 | + .name = "layer7", 585 | + .match = &match, 586 | + .checkentry = &checkentry, 587 | + .me = THIS_MODULE 588 | +}; 589 | + 590 | +/* taken from drivers/video/modedb.c */ 591 | +static int my_atoi(const char *s) 592 | +{ 593 | + int val = 0; 594 | + 595 | + for (;; s++) { 596 | + switch (*s) { 597 | + case '0'...'9': 598 | + val = 10*val+(*s-'0'); 599 | + break; 600 | + default: 601 | + return val; 602 | + } 603 | + } 604 | +} 605 | + 606 | +/* write out num_packets to userland. */ 607 | +static int layer7_read_proc(char* page, char ** start, off_t off, int count, 608 | + int* eof, void * data) 609 | +{ 610 | + if(num_packets > 99 && net_ratelimit()) 611 | + printk(KERN_ERR "layer7: NOT REACHED. num_packets too big\n"); 612 | + 613 | + page[0] = num_packets/10 + '0'; 614 | + page[1] = num_packets%10 + '0'; 615 | + page[2] = '\n'; 616 | + page[3] = '\0'; 617 | + 618 | + *eof=1; 619 | + 620 | + return 3; 621 | +} 622 | + 623 | +/* Read in num_packets from userland */ 624 | +static int layer7_write_proc(struct file* file, const char* buffer, 625 | + unsigned long count, void *data) 626 | +{ 627 | + char * foo = kmalloc(count, GFP_ATOMIC); 628 | + 629 | + if(!foo){ 630 | + if (net_ratelimit()) 631 | + printk(KERN_ERR "layer7: out of memory, bailing. num_packets unchanged.\n"); 632 | + return count; 633 | + } 634 | + 635 | + copy_from_user(foo, buffer, count); 636 | + 637 | + num_packets = my_atoi(foo); 638 | + kfree (foo); 639 | + 640 | + /* This has an arbitrary limit to make the math easier. I'm lazy. 641 | + But anyway, 99 is a LOT! If you want more, you're doing it wrong! */ 642 | + if(num_packets > 99) { 643 | + printk(KERN_WARNING "layer7: num_packets can't be > 99.\n"); 644 | + num_packets = 99; 645 | + } else if(num_packets < 1) { 646 | + printk(KERN_WARNING "layer7: num_packets can't be < 1.\n"); 647 | + num_packets = 1; 648 | + } 649 | + 650 | + return count; 651 | +} 652 | + 653 | +/* register the proc file */ 654 | +static void layer7_init_proc(void) 655 | +{ 656 | + struct proc_dir_entry* entry; 657 | + entry = create_proc_entry("layer7_numpackets", 0644, proc_net); 658 | + entry->read_proc = layer7_read_proc; 659 | + entry->write_proc = layer7_write_proc; 660 | +} 661 | + 662 | +static void layer7_cleanup_proc(void) 663 | +{ 664 | + remove_proc_entry("layer7_numpackets", proc_net); 665 | +} 666 | + 667 | +static int __init init(void) 668 | +{ 669 | + layer7_init_proc(); 670 | + return ipt_register_match(&layer7_match); 671 | +} 672 | + 673 | +static void __exit fini(void) 674 | +{ 675 | + layer7_cleanup_proc(); 676 | + ipt_unregister_match(&layer7_match); 677 | +} 678 | + 679 | +module_init(init); 680 | +module_exit(fini); 681 | --- linux-2.6.11.3-stock/net/ipv4/netfilter/regexp/regexp.c 1969-12-31 18:00:00.000000000 -0600 682 | +++ linux-2.6.11.3-layer7/net/ipv4/netfilter/regexp/regexp.c 2005-03-13 20:30:01.000000000 -0600 683 | @@ -0,0 +1,1195 @@ 684 | +/* 685 | + * regcomp and regexec -- regsub and regerror are elsewhere 686 | + * @(#)regexp.c 1.3 of 18 April 87 687 | + * 688 | + * Copyright (c) 1986 by University of Toronto. 689 | + * Written by Henry Spencer. Not derived from licensed software. 690 | + * 691 | + * Permission is granted to anyone to use this software for any 692 | + * purpose on any computer system, and to redistribute it freely, 693 | + * subject to the following restrictions: 694 | + * 695 | + * 1. The author is not responsible for the consequences of use of 696 | + * this software, no matter how awful, even if they arise 697 | + * from defects in it. 698 | + * 699 | + * 2. The origin of this software must not be misrepresented, either 700 | + * by explicit claim or by omission. 701 | + * 702 | + * 3. Altered versions must be plainly marked as such, and must not 703 | + * be misrepresented as being the original software. 704 | + * 705 | + * Beware that some of this code is subtly aware of the way operator 706 | + * precedence is structured in regular expressions. Serious changes in 707 | + * regular-expression syntax might require a total rethink. 708 | + * 709 | + * This code was modified by Ethan Sommer to work within the kernel 710 | + * (it now uses kmalloc etc..) 711 | + * 712 | + * Modified slightly by Matthew Strait to use more modern C. 713 | + */ 714 | + 715 | +#include "regexp.h" 716 | +#include "regmagic.h" 717 | + 718 | +/* added by ethan and matt. Lets it work in both kernel and user space. 719 | +(So iptables can use it, for instance.) Yea, it goes both ways... */ 720 | +#if __KERNEL__ 721 | + #define malloc(foo) kmalloc(foo,GFP_ATOMIC) 722 | +#else 723 | + #define printk(format,args...) printf(format,##args) 724 | +#endif 725 | + 726 | +void regerror(char * s) 727 | +{ 728 | + printk("<3>Regexp: %s\n", s); 729 | + /* NOTREACHED */ 730 | +} 731 | + 732 | +/* 733 | + * The "internal use only" fields in regexp.h are present to pass info from 734 | + * compile to execute that permits the execute phase to run lots faster on 735 | + * simple cases. They are: 736 | + * 737 | + * regstart char that must begin a match; '\0' if none obvious 738 | + * reganch is the match anchored (at beginning-of-line only)? 739 | + * regmust string (pointer into program) that match must include, or NULL 740 | + * regmlen length of regmust string 741 | + * 742 | + * Regstart and reganch permit very fast decisions on suitable starting points 743 | + * for a match, cutting down the work a lot. Regmust permits fast rejection 744 | + * of lines that cannot possibly match. The regmust tests are costly enough 745 | + * that regcomp() supplies a regmust only if the r.e. contains something 746 | + * potentially expensive (at present, the only such thing detected is * or + 747 | + * at the start of the r.e., which can involve a lot of backup). Regmlen is 748 | + * supplied because the test in regexec() needs it and regcomp() is computing 749 | + * it anyway. 750 | + */ 751 | + 752 | +/* 753 | + * Structure for regexp "program". This is essentially a linear encoding 754 | + * of a nondeterministic finite-state machine (aka syntax charts or 755 | + * "railroad normal form" in parsing technology). Each node is an opcode 756 | + * plus a "next" pointer, possibly plus an operand. "Next" pointers of 757 | + * all nodes except BRANCH implement concatenation; a "next" pointer with 758 | + * a BRANCH on both ends of it is connecting two alternatives. (Here we 759 | + * have one of the subtle syntax dependencies: an individual BRANCH (as 760 | + * opposed to a collection of them) is never concatenated with anything 761 | + * because of operator precedence.) The operand of some types of node is 762 | + * a literal string; for others, it is a node leading into a sub-FSM. In 763 | + * particular, the operand of a BRANCH node is the first node of the branch. 764 | + * (NB this is *not* a tree structure: the tail of the branch connects 765 | + * to the thing following the set of BRANCHes.) The opcodes are: 766 | + */ 767 | + 768 | +/* definition number opnd? meaning */ 769 | +#define END 0 /* no End of program. */ 770 | +#define BOL 1 /* no Match "" at beginning of line. */ 771 | +#define EOL 2 /* no Match "" at end of line. */ 772 | +#define ANY 3 /* no Match any one character. */ 773 | +#define ANYOF 4 /* str Match any character in this string. */ 774 | +#define ANYBUT 5 /* str Match any character not in this string. */ 775 | +#define BRANCH 6 /* node Match this alternative, or the next... */ 776 | +#define BACK 7 /* no Match "", "next" ptr points backward. */ 777 | +#define EXACTLY 8 /* str Match this string. */ 778 | +#define NOTHING 9 /* no Match empty string. */ 779 | +#define STAR 10 /* node Match this (simple) thing 0 or more times. */ 780 | +#define PLUS 11 /* node Match this (simple) thing 1 or more times. */ 781 | +#define OPEN 20 /* no Mark this point in input as start of #n. */ 782 | + /* OPEN+1 is number 1, etc. */ 783 | +#define CLOSE 30 /* no Analogous to OPEN. */ 784 | + 785 | +/* 786 | + * Opcode notes: 787 | + * 788 | + * BRANCH The set of branches constituting a single choice are hooked 789 | + * together with their "next" pointers, since precedence prevents 790 | + * anything being concatenated to any individual branch. The 791 | + * "next" pointer of the last BRANCH in a choice points to the 792 | + * thing following the whole choice. This is also where the 793 | + * final "next" pointer of each individual branch points; each 794 | + * branch starts with the operand node of a BRANCH node. 795 | + * 796 | + * BACK Normal "next" pointers all implicitly point forward; BACK 797 | + * exists to make loop structures possible. 798 | + * 799 | + * STAR,PLUS '?', and complex '*' and '+', are implemented as circular 800 | + * BRANCH structures using BACK. Simple cases (one character 801 | + * per match) are implemented with STAR and PLUS for speed 802 | + * and to minimize recursive plunges. 803 | + * 804 | + * OPEN,CLOSE ...are numbered at compile time. 805 | + */ 806 | + 807 | +/* 808 | + * A node is one char of opcode followed by two chars of "next" pointer. 809 | + * "Next" pointers are stored as two 8-bit pieces, high order first. The 810 | + * value is a positive offset from the opcode of the node containing it. 811 | + * An operand, if any, simply follows the node. (Note that much of the 812 | + * code generation knows about this implicit relationship.) 813 | + * 814 | + * Using two bytes for the "next" pointer is vast overkill for most things, 815 | + * but allows patterns to get big without disasters. 816 | + */ 817 | +#define OP(p) (*(p)) 818 | +#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) 819 | +#define OPERAND(p) ((p) + 3) 820 | + 821 | +/* 822 | + * See regmagic.h for one further detail of program structure. 823 | + */ 824 | + 825 | + 826 | +/* 827 | + * Utility definitions. 828 | + */ 829 | +#ifndef CHARBITS 830 | +#define UCHARAT(p) ((int)*(unsigned char *)(p)) 831 | +#else 832 | +#define UCHARAT(p) ((int)*(p)&CHARBITS) 833 | +#endif 834 | + 835 | +#define FAIL(m) { regerror(m); return(NULL); } 836 | +#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') 837 | +#define META "^$.[()|?+*\\" 838 | + 839 | +/* 840 | + * Flags to be passed up and down. 841 | + */ 842 | +#define HASWIDTH 01 /* Known never to match null string. */ 843 | +#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ 844 | +#define SPSTART 04 /* Starts with * or +. */ 845 | +#define WORST 0 /* Worst case. */ 846 | + 847 | +/* 848 | + * Global work variables for regcomp(). 849 | + */ 850 | +static char *regparse; /* Input-scan pointer. */ 851 | +static int regnpar; /* () count. */ 852 | +static char regdummy; 853 | +static char *regcode; /* Code-emit pointer; ®dummy = don't. */ 854 | +static long regsize; /* Code size. */ 855 | + 856 | +/* 857 | + * Forward declarations for regcomp()'s friends. 858 | + */ 859 | +#ifndef STATIC 860 | +#define STATIC static 861 | +#endif 862 | +STATIC char *reg(int paren,int *flagp); 863 | +STATIC char *regbranch(int *flagp); 864 | +STATIC char *regpiece(int *flagp); 865 | +STATIC char *regatom(int *flagp); 866 | +STATIC char *regnode(char op); 867 | +STATIC char *regnext(char *p); 868 | +STATIC void regc(char b); 869 | +STATIC void reginsert(char op, char *opnd); 870 | +STATIC void regtail(char *p, char *val); 871 | +STATIC void regoptail(char *p, char *val); 872 | + 873 | + 874 | +__kernel_size_t my_strcspn(const char *s1,const char *s2) 875 | +{ 876 | + char *scan1; 877 | + char *scan2; 878 | + int count; 879 | + 880 | + count = 0; 881 | + for (scan1 = (char *)s1; *scan1 != '\0'; scan1++) { 882 | + for (scan2 = (char *)s2; *scan2 != '\0';) /* ++ moved down. */ 883 | + if (*scan1 == *scan2++) 884 | + return(count); 885 | + count++; 886 | + } 887 | + return(count); 888 | +} 889 | + 890 | +/* 891 | + - regcomp - compile a regular expression into internal code 892 | + * 893 | + * We can't allocate space until we know how big the compiled form will be, 894 | + * but we can't compile it (and thus know how big it is) until we've got a 895 | + * place to put the code. So we cheat: we compile it twice, once with code 896 | + * generation turned off and size counting turned on, and once "for real". 897 | + * This also means that we don't allocate space until we are sure that the 898 | + * thing really will compile successfully, and we never have to move the 899 | + * code and thus invalidate pointers into it. (Note that it has to be in 900 | + * one piece because free() must be able to free it all.) 901 | + * 902 | + * Beware that the optimization-preparation code in here knows about some 903 | + * of the structure of the compiled regexp. 904 | + */ 905 | +regexp * 906 | +regcomp(char *exp,int *patternsize) 907 | +{ 908 | + register regexp *r; 909 | + register char *scan; 910 | + register char *longest; 911 | + register int len; 912 | + int flags; 913 | + /* commented out by ethan 914 | + extern char *malloc(); 915 | + */ 916 | + 917 | + if (exp == NULL) 918 | + FAIL("NULL argument"); 919 | + 920 | + /* First pass: determine size, legality. */ 921 | + regparse = exp; 922 | + regnpar = 1; 923 | + regsize = 0L; 924 | + regcode = ®dummy; 925 | + regc(MAGIC); 926 | + if (reg(0, &flags) == NULL) 927 | + return(NULL); 928 | + 929 | + /* Small enough for pointer-storage convention? */ 930 | + if (regsize >= 32767L) /* Probably could be 65535L. */ 931 | + FAIL("regexp too big"); 932 | + 933 | + /* Allocate space. */ 934 | + *patternsize=sizeof(regexp) + (unsigned)regsize; 935 | + r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); 936 | + if (r == NULL) 937 | + FAIL("out of space"); 938 | + 939 | + /* Second pass: emit code. */ 940 | + regparse = exp; 941 | + regnpar = 1; 942 | + regcode = r->program; 943 | + regc(MAGIC); 944 | + if (reg(0, &flags) == NULL) 945 | + return(NULL); 946 | + 947 | + /* Dig out information for optimizations. */ 948 | + r->regstart = '\0'; /* Worst-case defaults. */ 949 | + r->reganch = 0; 950 | + r->regmust = NULL; 951 | + r->regmlen = 0; 952 | + scan = r->program+1; /* First BRANCH. */ 953 | + if (OP(regnext(scan)) == END) { /* Only one top-level choice. */ 954 | + scan = OPERAND(scan); 955 | + 956 | + /* Starting-point info. */ 957 | + if (OP(scan) == EXACTLY) 958 | + r->regstart = *OPERAND(scan); 959 | + else if (OP(scan) == BOL) 960 | + r->reganch++; 961 | + 962 | + /* 963 | + * If there's something expensive in the r.e., find the 964 | + * longest literal string that must appear and make it the 965 | + * regmust. Resolve ties in favor of later strings, since 966 | + * the regstart check works with the beginning of the r.e. 967 | + * and avoiding duplication strengthens checking. Not a 968 | + * strong reason, but sufficient in the absence of others. 969 | + */ 970 | + if (flags&SPSTART) { 971 | + longest = NULL; 972 | + len = 0; 973 | + for (; scan != NULL; scan = regnext(scan)) 974 | + if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { 975 | + longest = OPERAND(scan); 976 | + len = strlen(OPERAND(scan)); 977 | + } 978 | + r->regmust = longest; 979 | + r->regmlen = len; 980 | + } 981 | + } 982 | + 983 | + return(r); 984 | +} 985 | + 986 | +/* 987 | + - reg - regular expression, i.e. main body or parenthesized thing 988 | + * 989 | + * Caller must absorb opening parenthesis. 990 | + * 991 | + * Combining parenthesis handling with the base level of regular expression 992 | + * is a trifle forced, but the need to tie the tails of the branches to what 993 | + * follows makes it hard to avoid. 994 | + */ 995 | +static char * 996 | +reg(int paren, int *flagp /* Parenthesized? */ ) 997 | +{ 998 | + register char *ret; 999 | + register char *br; 1000 | + register char *ender; 1001 | + register int parno = 0; /* 0 makes gcc happy */ 1002 | + int flags; 1003 | + 1004 | + *flagp = HASWIDTH; /* Tentatively. */ 1005 | + 1006 | + /* Make an OPEN node, if parenthesized. */ 1007 | + if (paren) { 1008 | + if (regnpar >= NSUBEXP) 1009 | + FAIL("too many ()"); 1010 | + parno = regnpar; 1011 | + regnpar++; 1012 | + ret = regnode(OPEN+parno); 1013 | + } else 1014 | + ret = NULL; 1015 | + 1016 | + /* Pick up the branches, linking them together. */ 1017 | + br = regbranch(&flags); 1018 | + if (br == NULL) 1019 | + return(NULL); 1020 | + if (ret != NULL) 1021 | + regtail(ret, br); /* OPEN -> first. */ 1022 | + else 1023 | + ret = br; 1024 | + if (!(flags&HASWIDTH)) 1025 | + *flagp &= ~HASWIDTH; 1026 | + *flagp |= flags&SPSTART; 1027 | + while (*regparse == '|') { 1028 | + regparse++; 1029 | + br = regbranch(&flags); 1030 | + if (br == NULL) 1031 | + return(NULL); 1032 | + regtail(ret, br); /* BRANCH -> BRANCH. */ 1033 | + if (!(flags&HASWIDTH)) 1034 | + *flagp &= ~HASWIDTH; 1035 | + *flagp |= flags&SPSTART; 1036 | + } 1037 | + 1038 | + /* Make a closing node, and hook it on the end. */ 1039 | + ender = regnode((paren) ? CLOSE+parno : END); 1040 | + regtail(ret, ender); 1041 | + 1042 | + /* Hook the tails of the branches to the closing node. */ 1043 | + for (br = ret; br != NULL; br = regnext(br)) 1044 | + regoptail(br, ender); 1045 | + 1046 | + /* Check for proper termination. */ 1047 | + if (paren && *regparse++ != ')') { 1048 | + FAIL("unmatched ()"); 1049 | + } else if (!paren && *regparse != '\0') { 1050 | + if (*regparse == ')') { 1051 | + FAIL("unmatched ()"); 1052 | + } else 1053 | + FAIL("junk on end"); /* "Can't happen". */ 1054 | + /* NOTREACHED */ 1055 | + } 1056 | + 1057 | + return(ret); 1058 | +} 1059 | + 1060 | +/* 1061 | + - regbranch - one alternative of an | operator 1062 | + * 1063 | + * Implements the concatenation operator. 1064 | + */ 1065 | +static char * 1066 | +regbranch(int *flagp) 1067 | +{ 1068 | + register char *ret; 1069 | + register char *chain; 1070 | + register char *latest; 1071 | + int flags; 1072 | + 1073 | + *flagp = WORST; /* Tentatively. */ 1074 | + 1075 | + ret = regnode(BRANCH); 1076 | + chain = NULL; 1077 | + while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { 1078 | + latest = regpiece(&flags); 1079 | + if (latest == NULL) 1080 | + return(NULL); 1081 | + *flagp |= flags&HASWIDTH; 1082 | + if (chain == NULL) /* First piece. */ 1083 | + *flagp |= flags&SPSTART; 1084 | + else 1085 | + regtail(chain, latest); 1086 | + chain = latest; 1087 | + } 1088 | + if (chain == NULL) /* Loop ran zero times. */ 1089 | + (void) regnode(NOTHING); 1090 | + 1091 | + return(ret); 1092 | +} 1093 | + 1094 | +/* 1095 | + - regpiece - something followed by possible [*+?] 1096 | + * 1097 | + * Note that the branching code sequences used for ? and the general cases 1098 | + * of * and + are somewhat optimized: they use the same NOTHING node as 1099 | + * both the endmarker for their branch list and the body of the last branch. 1100 | + * It might seem that this node could be dispensed with entirely, but the 1101 | + * endmarker role is not redundant. 1102 | + */ 1103 | +static char * 1104 | +regpiece(int *flagp) 1105 | +{ 1106 | + register char *ret; 1107 | + register char op; 1108 | + register char *next; 1109 | + int flags; 1110 | + 1111 | + ret = regatom(&flags); 1112 | + if (ret == NULL) 1113 | + return(NULL); 1114 | + 1115 | + op = *regparse; 1116 | + if (!ISMULT(op)) { 1117 | + *flagp = flags; 1118 | + return(ret); 1119 | + } 1120 | + 1121 | + if (!(flags&HASWIDTH) && op != '?') 1122 | + FAIL("*+ operand could be empty"); 1123 | + *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); 1124 | + 1125 | + if (op == '*' && (flags&SIMPLE)) 1126 | + reginsert(STAR, ret); 1127 | + else if (op == '*') { 1128 | + /* Emit x* as (x&|), where & means "self". */ 1129 | + reginsert(BRANCH, ret); /* Either x */ 1130 | + regoptail(ret, regnode(BACK)); /* and loop */ 1131 | + regoptail(ret, ret); /* back */ 1132 | + regtail(ret, regnode(BRANCH)); /* or */ 1133 | + regtail(ret, regnode(NOTHING)); /* null. */ 1134 | + } else if (op == '+' && (flags&SIMPLE)) 1135 | + reginsert(PLUS, ret); 1136 | + else if (op == '+') { 1137 | + /* Emit x+ as x(&|), where & means "self". */ 1138 | + next = regnode(BRANCH); /* Either */ 1139 | + regtail(ret, next); 1140 | + regtail(regnode(BACK), ret); /* loop back */ 1141 | + regtail(next, regnode(BRANCH)); /* or */ 1142 | + regtail(ret, regnode(NOTHING)); /* null. */ 1143 | + } else if (op == '?') { 1144 | + /* Emit x? as (x|) */ 1145 | + reginsert(BRANCH, ret); /* Either x */ 1146 | + regtail(ret, regnode(BRANCH)); /* or */ 1147 | + next = regnode(NOTHING); /* null. */ 1148 | + regtail(ret, next); 1149 | + regoptail(ret, next); 1150 | + } 1151 | + regparse++; 1152 | + if (ISMULT(*regparse)) 1153 | + FAIL("nested *?+"); 1154 | + 1155 | + return(ret); 1156 | +} 1157 | + 1158 | +/* 1159 | + - regatom - the lowest level 1160 | + * 1161 | + * Optimization: gobbles an entire sequence of ordinary characters so that 1162 | + * it can turn them into a single node, which is smaller to store and 1163 | + * faster to run. Backslashed characters are exceptions, each becoming a 1164 | + * separate node; the code is simpler that way and it's not worth fixing. 1165 | + */ 1166 | +static char * 1167 | +regatom(int *flagp) 1168 | +{ 1169 | + register char *ret; 1170 | + int flags; 1171 | + 1172 | + *flagp = WORST; /* Tentatively. */ 1173 | + 1174 | + switch (*regparse++) { 1175 | + case '^': 1176 | + ret = regnode(BOL); 1177 | + break; 1178 | + case '$': 1179 | + ret = regnode(EOL); 1180 | + break; 1181 | + case '.': 1182 | + ret = regnode(ANY); 1183 | + *flagp |= HASWIDTH|SIMPLE; 1184 | + break; 1185 | + case '[': { 1186 | + register int class; 1187 | + register int classend; 1188 | + 1189 | + if (*regparse == '^') { /* Complement of range. */ 1190 | + ret = regnode(ANYBUT); 1191 | + regparse++; 1192 | + } else 1193 | + ret = regnode(ANYOF); 1194 | + if (*regparse == ']' || *regparse == '-') 1195 | + regc(*regparse++); 1196 | + while (*regparse != '\0' && *regparse != ']') { 1197 | + if (*regparse == '-') { 1198 | + regparse++; 1199 | + if (*regparse == ']' || *regparse == '\0') 1200 | + regc('-'); 1201 | + else { 1202 | + class = UCHARAT(regparse-2)+1; 1203 | + classend = UCHARAT(regparse); 1204 | + if (class > classend+1) 1205 | + FAIL("invalid [] range"); 1206 | + for (; class <= classend; class++) 1207 | + regc(class); 1208 | + regparse++; 1209 | + } 1210 | + } else 1211 | + regc(*regparse++); 1212 | + } 1213 | + regc('\0'); 1214 | + if (*regparse != ']') 1215 | + FAIL("unmatched []"); 1216 | + regparse++; 1217 | + *flagp |= HASWIDTH|SIMPLE; 1218 | + } 1219 | + break; 1220 | + case '(': 1221 | + ret = reg(1, &flags); 1222 | + if (ret == NULL) 1223 | + return(NULL); 1224 | + *flagp |= flags&(HASWIDTH|SPSTART); 1225 | + break; 1226 | + case '\0': 1227 | + case '|': 1228 | + case ')': 1229 | + FAIL("internal urp"); /* Supposed to be caught earlier. */ 1230 | + break; 1231 | + case '?': 1232 | + case '+': 1233 | + case '*': 1234 | + FAIL("?+* follows nothing"); 1235 | + break; 1236 | + case '\\': 1237 | + if (*regparse == '\0') 1238 | + FAIL("trailing \\"); 1239 | + ret = regnode(EXACTLY); 1240 | + regc(*regparse++); 1241 | + regc('\0'); 1242 | + *flagp |= HASWIDTH|SIMPLE; 1243 | + break; 1244 | + default: { 1245 | + register int len; 1246 | + register char ender; 1247 | + 1248 | + regparse--; 1249 | + len = my_strcspn((const char *)regparse, (const char *)META); 1250 | + if (len <= 0) 1251 | + FAIL("internal disaster"); 1252 | + ender = *(regparse+len); 1253 | + if (len > 1 && ISMULT(ender)) 1254 | + len--; /* Back off clear of ?+* operand. */ 1255 | + *flagp |= HASWIDTH; 1256 | + if (len == 1) 1257 | + *flagp |= SIMPLE; 1258 | + ret = regnode(EXACTLY); 1259 | + while (len > 0) { 1260 | + regc(*regparse++); 1261 | + len--; 1262 | + } 1263 | + regc('\0'); 1264 | + } 1265 | + break; 1266 | + } 1267 | + 1268 | + return(ret); 1269 | +} 1270 | + 1271 | +/* 1272 | + - regnode - emit a node 1273 | + */ 1274 | +static char * /* Location. */ 1275 | +regnode(char op) 1276 | +{ 1277 | + register char *ret; 1278 | + register char *ptr; 1279 | + 1280 | + ret = regcode; 1281 | + if (ret == ®dummy) { 1282 | + regsize += 3; 1283 | + return(ret); 1284 | + } 1285 | + 1286 | + ptr = ret; 1287 | + *ptr++ = op; 1288 | + *ptr++ = '\0'; /* Null "next" pointer. */ 1289 | + *ptr++ = '\0'; 1290 | + regcode = ptr; 1291 | + 1292 | + return(ret); 1293 | +} 1294 | + 1295 | +/* 1296 | + - regc - emit (if appropriate) a byte of code 1297 | + */ 1298 | +static void 1299 | +regc(char b) 1300 | +{ 1301 | + if (regcode != ®dummy) 1302 | + *regcode++ = b; 1303 | + else 1304 | + regsize++; 1305 | +} 1306 | + 1307 | +/* 1308 | + - reginsert - insert an operator in front of already-emitted operand 1309 | + * 1310 | + * Means relocating the operand. 1311 | + */ 1312 | +static void 1313 | +reginsert(char op, char* opnd) 1314 | +{ 1315 | + register char *src; 1316 | + register char *dst; 1317 | + register char *place; 1318 | + 1319 | + if (regcode == ®dummy) { 1320 | + regsize += 3; 1321 | + return; 1322 | + } 1323 | + 1324 | + src = regcode; 1325 | + regcode += 3; 1326 | + dst = regcode; 1327 | + while (src > opnd) 1328 | + *--dst = *--src; 1329 | + 1330 | + place = opnd; /* Op node, where operand used to be. */ 1331 | + *place++ = op; 1332 | + *place++ = '\0'; 1333 | + *place++ = '\0'; 1334 | +} 1335 | + 1336 | +/* 1337 | + - regtail - set the next-pointer at the end of a node chain 1338 | + */ 1339 | +static void 1340 | +regtail(char *p, char *val) 1341 | +{ 1342 | + register char *scan; 1343 | + register char *temp; 1344 | + register int offset; 1345 | + 1346 | + if (p == ®dummy) 1347 | + return; 1348 | + 1349 | + /* Find last node. */ 1350 | + scan = p; 1351 | + for (;;) { 1352 | + temp = regnext(scan); 1353 | + if (temp == NULL) 1354 | + break; 1355 | + scan = temp; 1356 | + } 1357 | + 1358 | + if (OP(scan) == BACK) 1359 | + offset = scan - val; 1360 | + else 1361 | + offset = val - scan; 1362 | + *(scan+1) = (offset>>8)&0377; 1363 | + *(scan+2) = offset&0377; 1364 | +} 1365 | + 1366 | +/* 1367 | + - regoptail - regtail on operand of first argument; nop if operandless 1368 | + */ 1369 | +static void 1370 | +regoptail(char *p, char *val) 1371 | +{ 1372 | + /* "Operandless" and "op != BRANCH" are synonymous in practice. */ 1373 | + if (p == NULL || p == ®dummy || OP(p) != BRANCH) 1374 | + return; 1375 | + regtail(OPERAND(p), val); 1376 | +} 1377 | + 1378 | +/* 1379 | + * regexec and friends 1380 | + */ 1381 | + 1382 | +/* 1383 | + * Global work variables for regexec(). 1384 | + */ 1385 | +static char *reginput; /* String-input pointer. */ 1386 | +static char *regbol; /* Beginning of input, for ^ check. */ 1387 | +static char **regstartp; /* Pointer to startp array. */ 1388 | +static char **regendp; /* Ditto for endp. */ 1389 | + 1390 | +/* 1391 | + * Forwards. 1392 | + */ 1393 | +STATIC int regtry(regexp *prog, char *string); 1394 | +STATIC int regmatch(char *prog); 1395 | +STATIC int regrepeat(char *p); 1396 | + 1397 | +#ifdef DEBUG 1398 | +int regnarrate = 0; 1399 | +void regdump(); 1400 | +STATIC char *regprop(char *op); 1401 | +#endif 1402 | + 1403 | +/* 1404 | + - regexec - match a regexp against a string 1405 | + */ 1406 | +int 1407 | +regexec(regexp *prog, char *string) 1408 | +{ 1409 | + register char *s; 1410 | + 1411 | + /* Be paranoid... */ 1412 | + if (prog == NULL || string == NULL) { 1413 | + printk("<3>Regexp: NULL parameter\n"); 1414 | + return(0); 1415 | + } 1416 | + 1417 | + /* Check validity of program. */ 1418 | + if (UCHARAT(prog->program) != MAGIC) { 1419 | + printk("<3>Regexp: corrupted program\n"); 1420 | + return(0); 1421 | + } 1422 | + 1423 | + /* If there is a "must appear" string, look for it. */ 1424 | + if (prog->regmust != NULL) { 1425 | + s = string; 1426 | + while ((s = strchr(s, prog->regmust[0])) != NULL) { 1427 | + if (strncmp(s, prog->regmust, prog->regmlen) == 0) 1428 | + break; /* Found it. */ 1429 | + s++; 1430 | + } 1431 | + if (s == NULL) /* Not present. */ 1432 | + return(0); 1433 | + } 1434 | + 1435 | + /* Mark beginning of line for ^ . */ 1436 | + regbol = string; 1437 | + 1438 | + /* Simplest case: anchored match need be tried only once. */ 1439 | + if (prog->reganch) 1440 | + return(regtry(prog, string)); 1441 | + 1442 | + /* Messy cases: unanchored match. */ 1443 | + s = string; 1444 | + if (prog->regstart != '\0') 1445 | + /* We know what char it must start with. */ 1446 | + while ((s = strchr(s, prog->regstart)) != NULL) { 1447 | + if (regtry(prog, s)) 1448 | + return(1); 1449 | + s++; 1450 | + } 1451 | + else 1452 | + /* We don't -- general case. */ 1453 | + do { 1454 | + if (regtry(prog, s)) 1455 | + return(1); 1456 | + } while (*s++ != '\0'); 1457 | + 1458 | + /* Failure. */ 1459 | + return(0); 1460 | +} 1461 | + 1462 | +/* 1463 | + - regtry - try match at specific point 1464 | + */ 1465 | +static int /* 0 failure, 1 success */ 1466 | +regtry(regexp *prog, char *string) 1467 | +{ 1468 | + register int i; 1469 | + register char **sp; 1470 | + register char **ep; 1471 | + 1472 | + reginput = string; 1473 | + regstartp = prog->startp; 1474 | + regendp = prog->endp; 1475 | + 1476 | + sp = prog->startp; 1477 | + ep = prog->endp; 1478 | + for (i = NSUBEXP; i > 0; i--) { 1479 | + *sp++ = NULL; 1480 | + *ep++ = NULL; 1481 | + } 1482 | + if (regmatch(prog->program + 1)) { 1483 | + prog->startp[0] = string; 1484 | + prog->endp[0] = reginput; 1485 | + return(1); 1486 | + } else 1487 | + return(0); 1488 | +} 1489 | + 1490 | +/* 1491 | + - regmatch - main matching routine 1492 | + * 1493 | + * Conceptually the strategy is simple: check to see whether the current 1494 | + * node matches, call self recursively to see whether the rest matches, 1495 | + * and then act accordingly. In practice we make some effort to avoid 1496 | + * recursion, in particular by going through "ordinary" nodes (that don't 1497 | + * need to know whether the rest of the match failed) by a loop instead of 1498 | + * by recursion. 1499 | + */ 1500 | +static int /* 0 failure, 1 success */ 1501 | +regmatch(char *prog) 1502 | +{ 1503 | + register char *scan = prog; /* Current node. */ 1504 | + char *next; /* Next node. */ 1505 | + 1506 | +#ifdef DEBUG 1507 | + if (scan != NULL && regnarrate) 1508 | + fprintf(stderr, "%s(\n", regprop(scan)); 1509 | +#endif 1510 | + while (scan != NULL) { 1511 | +#ifdef DEBUG 1512 | + if (regnarrate) 1513 | + fprintf(stderr, "%s...\n", regprop(scan)); 1514 | +#endif 1515 | + next = regnext(scan); 1516 | + 1517 | + switch (OP(scan)) { 1518 | + case BOL: 1519 | + if (reginput != regbol) 1520 | + return(0); 1521 | + break; 1522 | + case EOL: 1523 | + if (*reginput != '\0') 1524 | + return(0); 1525 | + break; 1526 | + case ANY: 1527 | + if (*reginput == '\0') 1528 | + return(0); 1529 | + reginput++; 1530 | + break; 1531 | + case EXACTLY: { 1532 | + register int len; 1533 | + register char *opnd; 1534 | + 1535 | + opnd = OPERAND(scan); 1536 | + /* Inline the first character, for speed. */ 1537 | + if (*opnd != *reginput) 1538 | + return(0); 1539 | + len = strlen(opnd); 1540 | + if (len > 1 && strncmp(opnd, reginput, len) != 0) 1541 | + return(0); 1542 | + reginput += len; 1543 | + } 1544 | + break; 1545 | + case ANYOF: 1546 | + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL) 1547 | + return(0); 1548 | + reginput++; 1549 | + break; 1550 | + case ANYBUT: 1551 | + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL) 1552 | + return(0); 1553 | + reginput++; 1554 | + break; 1555 | + case NOTHING: 1556 | + case BACK: 1557 | + break; 1558 | + case OPEN+1: 1559 | + case OPEN+2: 1560 | + case OPEN+3: 1561 | + case OPEN+4: 1562 | + case OPEN+5: 1563 | + case OPEN+6: 1564 | + case OPEN+7: 1565 | + case OPEN+8: 1566 | + case OPEN+9: { 1567 | + register int no; 1568 | + register char *save; 1569 | + 1570 | + no = OP(scan) - OPEN; 1571 | + save = reginput; 1572 | + 1573 | + if (regmatch(next)) { 1574 | + /* 1575 | + * Don't set startp if some later 1576 | + * invocation of the same parentheses 1577 | + * already has. 1578 | + */ 1579 | + if (regstartp[no] == NULL) 1580 | + regstartp[no] = save; 1581 | + return(1); 1582 | + } else 1583 | + return(0); 1584 | + } 1585 | + break; 1586 | + case CLOSE+1: 1587 | + case CLOSE+2: 1588 | + case CLOSE+3: 1589 | + case CLOSE+4: 1590 | + case CLOSE+5: 1591 | + case CLOSE+6: 1592 | + case CLOSE+7: 1593 | + case CLOSE+8: 1594 | + case CLOSE+9: 1595 | + { 1596 | + register int no; 1597 | + register char *save; 1598 | + 1599 | + no = OP(scan) - CLOSE; 1600 | + save = reginput; 1601 | + 1602 | + if (regmatch(next)) { 1603 | + /* 1604 | + * Don't set endp if some later 1605 | + * invocation of the same parentheses 1606 | + * already has. 1607 | + */ 1608 | + if (regendp[no] == NULL) 1609 | + regendp[no] = save; 1610 | + return(1); 1611 | + } else 1612 | + return(0); 1613 | + } 1614 | + break; 1615 | + case BRANCH: { 1616 | + register char *save; 1617 | + 1618 | + if (OP(next) != BRANCH) /* No choice. */ 1619 | + next = OPERAND(scan); /* Avoid recursion. */ 1620 | + else { 1621 | + do { 1622 | + save = reginput; 1623 | + if (regmatch(OPERAND(scan))) 1624 | + return(1); 1625 | + reginput = save; 1626 | + scan = regnext(scan); 1627 | + } while (scan != NULL && OP(scan) == BRANCH); 1628 | + return(0); 1629 | + /* NOTREACHED */ 1630 | + } 1631 | + } 1632 | + break; 1633 | + case STAR: 1634 | + case PLUS: { 1635 | + register char nextch; 1636 | + register int no; 1637 | + register char *save; 1638 | + register int min; 1639 | + 1640 | + /* 1641 | + * Lookahead to avoid useless match attempts 1642 | + * when we know what character comes next. 1643 | + */ 1644 | + nextch = '\0'; 1645 | + if (OP(next) == EXACTLY) 1646 | + nextch = *OPERAND(next); 1647 | + min = (OP(scan) == STAR) ? 0 : 1; 1648 | + save = reginput; 1649 | + no = regrepeat(OPERAND(scan)); 1650 | + while (no >= min) { 1651 | + /* If it could work, try it. */ 1652 | + if (nextch == '\0' || *reginput == nextch) 1653 | + if (regmatch(next)) 1654 | + return(1); 1655 | + /* Couldn't or didn't -- back up. */ 1656 | + no--; 1657 | + reginput = save + no; 1658 | + } 1659 | + return(0); 1660 | + } 1661 | + break; 1662 | + case END: 1663 | + return(1); /* Success! */ 1664 | + break; 1665 | + default: 1666 | + printk("<3>Regexp: memory corruption\n"); 1667 | + return(0); 1668 | + break; 1669 | + } 1670 | + 1671 | + scan = next; 1672 | + } 1673 | + 1674 | + /* 1675 | + * We get here only if there's trouble -- normally "case END" is 1676 | + * the terminating point. 1677 | + */ 1678 | + printk("<3>Regexp: corrupted pointers\n"); 1679 | + return(0); 1680 | +} 1681 | + 1682 | +/* 1683 | + - regrepeat - repeatedly match something simple, report how many 1684 | + */ 1685 | +static int 1686 | +regrepeat(char *p) 1687 | +{ 1688 | + register int count = 0; 1689 | + register char *scan; 1690 | + register char *opnd; 1691 | + 1692 | + scan = reginput; 1693 | + opnd = OPERAND(p); 1694 | + switch (OP(p)) { 1695 | + case ANY: 1696 | + count = strlen(scan); 1697 | + scan += count; 1698 | + break; 1699 | + case EXACTLY: 1700 | + while (*opnd == *scan) { 1701 | + count++; 1702 | + scan++; 1703 | + } 1704 | + break; 1705 | + case ANYOF: 1706 | + while (*scan != '\0' && strchr(opnd, *scan) != NULL) { 1707 | + count++; 1708 | + scan++; 1709 | + } 1710 | + break; 1711 | + case ANYBUT: 1712 | + while (*scan != '\0' && strchr(opnd, *scan) == NULL) { 1713 | + count++; 1714 | + scan++; 1715 | + } 1716 | + break; 1717 | + default: /* Oh dear. Called inappropriately. */ 1718 | + printk("<3>Regexp: internal foulup\n"); 1719 | + count = 0; /* Best compromise. */ 1720 | + break; 1721 | + } 1722 | + reginput = scan; 1723 | + 1724 | + return(count); 1725 | +} 1726 | + 1727 | +/* 1728 | + - regnext - dig the "next" pointer out of a node 1729 | + */ 1730 | +static char* 1731 | +regnext(char *p) 1732 | +{ 1733 | + register int offset; 1734 | + 1735 | + if (p == ®dummy) 1736 | + return(NULL); 1737 | + 1738 | + offset = NEXT(p); 1739 | + if (offset == 0) 1740 | + return(NULL); 1741 | + 1742 | + if (OP(p) == BACK) 1743 | + return(p-offset); 1744 | + else 1745 | + return(p+offset); 1746 | +} 1747 | + 1748 | +#ifdef DEBUG 1749 | + 1750 | +STATIC char *regprop(); 1751 | + 1752 | +/* 1753 | + - regdump - dump a regexp onto stdout in vaguely comprehensible form 1754 | + */ 1755 | +void 1756 | +regdump(regexp *r) 1757 | +{ 1758 | + register char *s; 1759 | + register char op = EXACTLY; /* Arbitrary non-END op. */ 1760 | + register char *next; 1761 | + /* extern char *strchr(); */ 1762 | + 1763 | + 1764 | + s = r->program + 1; 1765 | + while (op != END) { /* While that wasn't END last time... */ 1766 | + op = OP(s); 1767 | + printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */ 1768 | + next = regnext(s); 1769 | + if (next == NULL) /* Next ptr. */ 1770 | + printf("(0)"); 1771 | + else 1772 | + printf("(%d)", (s-r->program)+(next-s)); 1773 | + s += 3; 1774 | + if (op == ANYOF || op == ANYBUT || op == EXACTLY) { 1775 | + /* Literal string, where present. */ 1776 | + while (*s != '\0') { 1777 | + putchar(*s); 1778 | + s++; 1779 | + } 1780 | + s++; 1781 | + } 1782 | + putchar('\n'); 1783 | + } 1784 | + 1785 | + /* Header fields of interest. */ 1786 | + if (r->regstart != '\0') 1787 | + printf("start `%c' ", r->regstart); 1788 | + if (r->reganch) 1789 | + printf("anchored "); 1790 | + if (r->regmust != NULL) 1791 | + printf("must have \"%s\"", r->regmust); 1792 | + printf("\n"); 1793 | +} 1794 | + 1795 | +/* 1796 | + - regprop - printable representation of opcode 1797 | + */ 1798 | +static char * 1799 | +regprop(char *op) 1800 | +{ 1801 | +#define BUFLEN 50 1802 | + register char *p; 1803 | + static char buf[BUFLEN]; 1804 | + 1805 | + strcpy(buf, ":"); 1806 | + 1807 | + switch (OP(op)) { 1808 | + case BOL: 1809 | + p = "BOL"; 1810 | + break; 1811 | + case EOL: 1812 | + p = "EOL"; 1813 | + break; 1814 | + case ANY: 1815 | + p = "ANY"; 1816 | + break; 1817 | + case ANYOF: 1818 | + p = "ANYOF"; 1819 | + break; 1820 | + case ANYBUT: 1821 | + p = "ANYBUT"; 1822 | + break; 1823 | + case BRANCH: 1824 | + p = "BRANCH"; 1825 | + break; 1826 | + case EXACTLY: 1827 | + p = "EXACTLY"; 1828 | + break; 1829 | + case NOTHING: 1830 | + p = "NOTHING"; 1831 | + break; 1832 | + case BACK: 1833 | + p = "BACK"; 1834 | + break; 1835 | + case END: 1836 | + p = "END"; 1837 | + break; 1838 | + case OPEN+1: 1839 | + case OPEN+2: 1840 | + case OPEN+3: 1841 | + case OPEN+4: 1842 | + case OPEN+5: 1843 | + case OPEN+6: 1844 | + case OPEN+7: 1845 | + case OPEN+8: 1846 | + case OPEN+9: 1847 | + snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "OPEN%d", OP(op)-OPEN); 1848 | + p = NULL; 1849 | + break; 1850 | + case CLOSE+1: 1851 | + case CLOSE+2: 1852 | + case CLOSE+3: 1853 | + case CLOSE+4: 1854 | + case CLOSE+5: 1855 | + case CLOSE+6: 1856 | + case CLOSE+7: 1857 | + case CLOSE+8: 1858 | + case CLOSE+9: 1859 | + snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "CLOSE%d", OP(op)-CLOSE); 1860 | + p = NULL; 1861 | + break; 1862 | + case STAR: 1863 | + p = "STAR"; 1864 | + break; 1865 | + case PLUS: 1866 | + p = "PLUS"; 1867 | + break; 1868 | + default: 1869 | + printk("<3>Regexp: corrupted opcode\n"); 1870 | + break; 1871 | + } 1872 | + if (p != NULL) 1873 | + strncat(buf, p, BUFLEN-strlen(buf)); 1874 | + return(buf); 1875 | +} 1876 | +#endif 1877 | + 1878 | + 1879 | --- linux-2.6.11.3-stock/net/ipv4/netfilter/regexp/regexp.h 1969-12-31 18:00:00.000000000 -0600 1880 | +++ linux-2.6.11.3-layer7/net/ipv4/netfilter/regexp/regexp.h 2005-03-13 20:30:01.000000000 -0600 1881 | @@ -0,0 +1,41 @@ 1882 | +/* 1883 | + * Definitions etc. for regexp(3) routines. 1884 | + * 1885 | + * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], 1886 | + * not the System V one. 1887 | + */ 1888 | + 1889 | +#ifndef REGEXP_H 1890 | +#define REGEXP_H 1891 | + 1892 | + 1893 | +/* 1894 | +http://www.opensource.apple.com/darwinsource/10.3/expect-1/expect/expect.h , 1895 | +which contains a version of this library, says: 1896 | + 1897 | + * 1898 | + * NSUBEXP must be at least 10, and no greater than 117 or the parser 1899 | + * will not work properly. 1900 | + * 1901 | + 1902 | +However, it looks rather like this library is limited to 10. If you think 1903 | +otherwise, let us know. 1904 | +*/ 1905 | + 1906 | +#define NSUBEXP 10 1907 | +typedef struct regexp { 1908 | + char *startp[NSUBEXP]; 1909 | + char *endp[NSUBEXP]; 1910 | + char regstart; /* Internal use only. */ 1911 | + char reganch; /* Internal use only. */ 1912 | + char *regmust; /* Internal use only. */ 1913 | + int regmlen; /* Internal use only. */ 1914 | + char program[1]; /* Unwarranted chumminess with compiler. */ 1915 | +} regexp; 1916 | + 1917 | +regexp * regcomp(char *exp, int *patternsize); 1918 | +int regexec(regexp *prog, char *string); 1919 | +void regsub(regexp *prog, char *source, char *dest); 1920 | +void regerror(char *s); 1921 | + 1922 | +#endif 1923 | --- linux-2.6.11.3-stock/net/ipv4/netfilter/regexp/regmagic.h 1969-12-31 18:00:00.000000000 -0600 1924 | +++ linux-2.6.11.3-layer7/net/ipv4/netfilter/regexp/regmagic.h 2005-03-13 20:30:01.000000000 -0600 1925 | @@ -0,0 +1,5 @@ 1926 | +/* 1927 | + * The first byte of the regexp internal "program" is actually this magic 1928 | + * number; the start node begins in the second byte. 1929 | + */ 1930 | +#define MAGIC 0234 1931 | --- linux-2.6.11.3-stock/net/ipv4/netfilter/regexp/regsub.c 1969-12-31 18:00:00.000000000 -0600 1932 | +++ linux-2.6.11.3-layer7/net/ipv4/netfilter/regexp/regsub.c 2005-03-13 20:30:01.000000000 -0600 1933 | @@ -0,0 +1,95 @@ 1934 | +/* 1935 | + * regsub 1936 | + * @(#)regsub.c 1.3 of 2 April 86 1937 | + * 1938 | + * Copyright (c) 1986 by University of Toronto. 1939 | + * Written by Henry Spencer. Not derived from licensed software. 1940 | + * 1941 | + * Permission is granted to anyone to use this software for any 1942 | + * purpose on any computer system, and to redistribute it freely, 1943 | + * subject to the following restrictions: 1944 | + * 1945 | + * 1. The author is not responsible for the consequences of use of 1946 | + * this software, no matter how awful, even if they arise 1947 | + * from defects in it. 1948 | + * 1949 | + * 2. The origin of this software must not be misrepresented, either 1950 | + * by explicit claim or by omission. 1951 | + * 1952 | + * 3. Altered versions must be plainly marked as such, and must not 1953 | + * be misrepresented as being the original software. 1954 | + * 1955 | + * 1956 | + * This code was modified by Ethan Sommer to work within the kernel 1957 | + * (it now uses kmalloc etc..) 1958 | + * 1959 | + */ 1960 | +#include "regexp.h" 1961 | +#include "regmagic.h" 1962 | +#include 1963 | + 1964 | + 1965 | +#ifndef CHARBITS 1966 | +#define UCHARAT(p) ((int)*(unsigned char *)(p)) 1967 | +#else 1968 | +#define UCHARAT(p) ((int)*(p)&CHARBITS) 1969 | +#endif 1970 | + 1971 | +#if 0 1972 | +//void regerror(char * s) 1973 | +//{ 1974 | +// printk("regexp(3): %s", s); 1975 | +// /* NOTREACHED */ 1976 | +//} 1977 | +#endif 1978 | + 1979 | +/* 1980 | + - regsub - perform substitutions after a regexp match 1981 | + */ 1982 | +void 1983 | +regsub(regexp * prog, char * source, char * dest) 1984 | +{ 1985 | + register char *src; 1986 | + register char *dst; 1987 | + register char c; 1988 | + register int no; 1989 | + register int len; 1990 | + 1991 | + /* Not necessary and gcc doesn't like it -MLS */ 1992 | + /*extern char *strncpy();*/ 1993 | + 1994 | + if (prog == NULL || source == NULL || dest == NULL) { 1995 | + regerror("NULL parm to regsub"); 1996 | + return; 1997 | + } 1998 | + if (UCHARAT(prog->program) != MAGIC) { 1999 | + regerror("damaged regexp fed to regsub"); 2000 | + return; 2001 | + } 2002 | + 2003 | + src = source; 2004 | + dst = dest; 2005 | + while ((c = *src++) != '\0') { 2006 | + if (c == '&') 2007 | + no = 0; 2008 | + else if (c == '\\' && '0' <= *src && *src <= '9') 2009 | + no = *src++ - '0'; 2010 | + else 2011 | + no = -1; 2012 | + 2013 | + if (no < 0) { /* Ordinary character. */ 2014 | + if (c == '\\' && (*src == '\\' || *src == '&')) 2015 | + c = *src++; 2016 | + *dst++ = c; 2017 | + } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) { 2018 | + len = prog->endp[no] - prog->startp[no]; 2019 | + (void) strncpy(dst, prog->startp[no], len); 2020 | + dst += len; 2021 | + if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */ 2022 | + regerror("damaged match string"); 2023 | + return; 2024 | + } 2025 | + } 2026 | + } 2027 | + *dst++ = '\0'; 2028 | +} 2029 | -------------------------------------------------------------------------------- /for_older_kernels/kernel-2.6.9-2.6.10-layer7-1.2.patch: -------------------------------------------------------------------------------- 1 | --- linux-2.6.10-stock/include/linux/netfilter_ipv4/ip_conntrack.h 2004-12-24 15:35:28.000000000 -0600 2 | +++ linux-2.6.10-layer7/include/linux/netfilter_ipv4/ip_conntrack.h 2005-01-07 13:24:01.000000000 -0600 3 | @@ -219,6 +219,15 @@ struct ip_conntrack 4 | /* Traversed often, so hopefully in different cacheline to top */ 5 | /* These are my tuples; original and reply */ 6 | struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; 7 | + 8 | +#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) 9 | + struct { 10 | + char * app_proto; /* e.g. "http". NULL before decision. "unknown" after decision if no match */ 11 | + char * app_data; /* application layer data so far. NULL after match decision */ 12 | + unsigned int app_data_len; 13 | + } layer7; 14 | +#endif 15 | + 16 | }; 17 | 18 | /* get master conntrack via master expectation */ 19 | --- linux-2.6.10-stock/include/linux/netfilter_ipv4/ipt_layer7.h 1969-12-31 18:00:00.000000000 -0600 20 | +++ linux-2.6.10-layer7/include/linux/netfilter_ipv4/ipt_layer7.h 2005-01-07 13:24:01.000000000 -0600 21 | @@ -0,0 +1,26 @@ 22 | +/* 23 | + By Matthew Strait , Dec 2003. 24 | + http://l7-filter.sf.net 25 | + 26 | + This program is free software; you can redistribute it and/or 27 | + modify it under the terms of the GNU General Public License 28 | + as published by the Free Software Foundation; either version 29 | + 2 of the License, or (at your option) any later version. 30 | + http://www.gnu.org/licenses/gpl.txt 31 | +*/ 32 | + 33 | +#ifndef _IPT_LAYER7_H 34 | +#define _IPT_LAYER7_H 35 | + 36 | +#define MAX_PATTERN_LEN 8192 37 | +#define MAX_PROTOCOL_LEN 256 38 | + 39 | +typedef char *(*proc_ipt_search) (char *, char, char *); 40 | + 41 | +struct ipt_layer7_info { 42 | + char protocol[MAX_PROTOCOL_LEN]; 43 | + char invert:1; 44 | + char pattern[MAX_PATTERN_LEN]; 45 | +}; 46 | + 47 | +#endif /* _IPT_LAYER7_H */ 48 | --- linux-2.6.10-stock/net/ipv4/netfilter/Kconfig 2004-12-24 15:35:24.000000000 -0600 49 | +++ linux-2.6.10-layer7/net/ipv4/netfilter/Kconfig 2005-01-07 13:24:01.000000000 -0600 50 | @@ -146,6 +146,33 @@ config IP_NF_MATCH_MAC 51 | 52 | To compile it as a module, choose M here. If unsure, say N. 53 | 54 | +config IP_NF_MATCH_LAYER7 55 | + tristate "Layer 7 match support (EXPERIMENTAL)" 56 | + depends on IP_NF_IPTABLES && IP_NF_CT_ACCT && IP_NF_CONNTRACK && EXPERIMENTAL 57 | + help 58 | + Say Y if you want to be able to classify connections (and their 59 | + packets) based on regular expression matching of their application 60 | + layer data. This is one way to classify applications such as 61 | + peer-to-peer filesharing systems that do not always use the same 62 | + port. 63 | + 64 | + To compile it as a module, choose M here. If unsure, say N. 65 | + 66 | +config IP_NF_MATCH_LAYER7_DEBUG 67 | + bool "Layer 7 debugging output" 68 | + depends on IP_NF_MATCH_LAYER7 69 | + help 70 | + Say Y to get lots of debugging output. 71 | + 72 | +config IP_NF_MATCH_LAYER7_MAXDATALEN 73 | + int "Buffer size for application layer data" if IP_NF_MATCH_LAYER7 74 | + range 256 65536 75 | + default 2048 76 | + help 77 | + Size of the buffer that the application layer data is stored in. 78 | + Unless you know what you're doing, leave it at the default of 2kB. 79 | + 80 | + 81 | config IP_NF_MATCH_PKTTYPE 82 | tristate "Packet type match support" 83 | depends on IP_NF_IPTABLES 84 | --- linux-2.6.10-stock/net/ipv4/netfilter/Makefile 2004-12-24 15:34:26.000000000 -0600 85 | +++ linux-2.6.10-layer7/net/ipv4/netfilter/Makefile 2005-01-07 13:24:01.000000000 -0600 86 | @@ -70,6 +70,8 @@ obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ip 87 | obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o 88 | obj-$(CONFIG_IP_NF_MATCH_COMMENT) += ipt_comment.o 89 | 90 | +obj-$(CONFIG_IP_NF_MATCH_LAYER7) += ipt_layer7.o 91 | + 92 | # targets 93 | obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o 94 | obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o 95 | --- linux-2.6.10-stock/net/ipv4/netfilter/ip_conntrack_core.c 2004-12-24 15:33:47.000000000 -0600 96 | +++ linux-2.6.10-layer7/net/ipv4/netfilter/ip_conntrack_core.c 2005-03-11 00:44:23.000000000 -0600 97 | @@ -302,6 +302,13 @@ destroy_conntrack(struct nf_conntrack *n 98 | if (ct->expecting) 99 | remove_expectations(ct, 1); 100 | 101 | + #if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) 102 | + if(ct->layer7.app_proto) 103 | + kfree(ct->layer7.app_proto); 104 | + if(ct->layer7.app_data) 105 | + kfree(ct->layer7.app_data); 106 | + #endif 107 | + 108 | /* Delete our master expectation */ 109 | if (ct->master) { 110 | if (ct->master->expectant) { 111 | --- linux-2.6.10-stock/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-12-24 15:34:33.000000000 -0600 112 | +++ linux-2.6.10-layer7/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-01-07 13:24:01.000000000 -0600 113 | @@ -151,6 +151,12 @@ static int ct_seq_real_show(const struct 114 | return 1; 115 | #endif 116 | 117 | +#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) 118 | + if(conntrack->layer7.app_proto) 119 | + if (seq_printf(s, "l7proto=%s ",conntrack->layer7.app_proto)) 120 | + return 1; 121 | +#endif 122 | + 123 | if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use))) 124 | return 1; 125 | 126 | --- linux-2.6.10-stock/net/ipv4/netfilter/ipt_layer7.c 1969-12-31 18:00:00.000000000 -0600 127 | +++ linux-2.6.10-layer7/net/ipv4/netfilter/ipt_layer7.c 2005-03-13 16:26:43.397224912 -0600 128 | @@ -0,0 +1,552 @@ 129 | +/* 130 | + Kernel module to match application layer (OSI layer 7) 131 | + data in connections. 132 | + 133 | + http://l7-filter.sf.net 134 | + 135 | + By Matthew Strait and Ethan Sommer, 2003-2005. 136 | + 137 | + This program is free software; you can redistribute it and/or 138 | + modify it under the terms of the GNU General Public License 139 | + as published by the Free Software Foundation; either version 140 | + 2 of the License, or (at your option) any later version. 141 | + http://www.gnu.org/licenses/gpl.txt 142 | + 143 | + Based on ipt_string.c (C) 2000 Emmanuel Roger 144 | + and cls_layer7.c (C) 2003 Matthew Strait, Ethan Sommer, Justin Levandoski 145 | +*/ 146 | + 147 | +#include 148 | +#include 149 | +#include 150 | +#include 151 | +#include 152 | +#include 153 | +#include 154 | +#include 155 | + 156 | +#include "regexp/regexp.c" 157 | + 158 | +#include 159 | +#include 160 | + 161 | +MODULE_AUTHOR("Matthew Strait , Ethan Sommer "); 162 | +MODULE_LICENSE("GPL"); 163 | +MODULE_DESCRIPTION("iptables application layer match module"); 164 | + 165 | +#if defined(CONFIG_IP_NF_MATCH_LAYER7_DEBUG) 166 | + #define DPRINTK(format,args...) printk(format,##args) 167 | +#else 168 | + #define DPRINTK(format,args...) 169 | +#endif 170 | + 171 | +#define TOTAL_PACKETS master_conntrack->counters[IP_CT_DIR_ORIGINAL].packets + \ 172 | + master_conntrack->counters[IP_CT_DIR_REPLY].packets 173 | + 174 | +/* Number of packets whose data we look at. 175 | +This can be modified through /proc/net/layer7_numpackets */ 176 | +static int num_packets = 8; 177 | + 178 | +static struct pattern_cache { 179 | + char * regex_string; 180 | + regexp * pattern; 181 | + struct pattern_cache * next; 182 | +} * first_pattern_cache = NULL; 183 | + 184 | +/* I'm new to locking. Here are my assumptions: 185 | + 186 | +- No one will write to /proc/net/layer7_numpackets over and over very fast; 187 | + if they did, nothing awful would happen. 188 | + 189 | +- This code will never be processing the same packet twice at the same time, 190 | + because iptables rules are traversed in order. 191 | + 192 | +- It doesn't matter if two packets from different connections are in here at 193 | + the same time, because they don't share any data. 194 | + 195 | +- It _does_ matter if two packets from the same connection are here at the same 196 | + time. In this case, we have to protect the conntracks and the list of 197 | + compiled patterns. 198 | +*/ 199 | +DECLARE_RWLOCK(ct_lock); 200 | +DECLARE_LOCK(list_lock); 201 | + 202 | +#if CONFIG_IP_NF_MATCH_LAYER7_DEBUG 203 | +/* Converts an unfriendly string into a friendly one by 204 | +replacing unprintables with periods and all whitespace with " ". */ 205 | +static char * friendly_print(unsigned char * s) 206 | +{ 207 | + char * f = kmalloc(strlen(s) + 1, GFP_ATOMIC); 208 | + int i; 209 | + 210 | + if(!f) { 211 | + if (net_ratelimit()) 212 | + printk(KERN_ERR "layer7: out of memory in friendly_print, bailing.\n"); 213 | + return NULL; 214 | + } 215 | + 216 | + for(i = 0; i < strlen(s); i++){ 217 | + if(isprint(s[i]) && s[i] < 128) f[i] = s[i]; 218 | + else if(isspace(s[i])) f[i] = ' '; 219 | + else f[i] = '.'; 220 | + } 221 | + f[i] = '\0'; 222 | + return f; 223 | +} 224 | + 225 | +static char dec2hex(int i) 226 | +{ 227 | + switch (i) { 228 | + case 0 ... 9: 229 | + return (char)(i + '0'); 230 | + break; 231 | + case 10 ... 15: 232 | + return (char)(i - 10 + 'a'); 233 | + break; 234 | + default: 235 | + if (net_ratelimit()) 236 | + printk("Problem in dec2hex\n"); 237 | + return '\0'; 238 | + } 239 | +} 240 | + 241 | +static char * hex_print(unsigned char * s) 242 | +{ 243 | + char * g = kmalloc(strlen(s)*3 + 1, GFP_ATOMIC); 244 | + int i; 245 | + 246 | + if(!g) { 247 | + if (net_ratelimit()) 248 | + printk(KERN_ERR "layer7: out of memory in hex_print, bailing.\n"); 249 | + return NULL; 250 | + } 251 | + 252 | + for(i = 0; i < strlen(s); i++) { 253 | + g[i*3 ] = dec2hex(s[i]/16); 254 | + g[i*3 + 1] = dec2hex(s[i]%16); 255 | + g[i*3 + 2] = ' '; 256 | + } 257 | + g[i*3] = '\0'; 258 | + 259 | + return g; 260 | +} 261 | +#endif // DEBUG 262 | + 263 | +/* Use instead of regcomp. As we expect to be seeing the same regexps over and 264 | +over again, it make sense to cache the results. */ 265 | +static regexp * compile_and_cache(char * regex_string, char * protocol) 266 | +{ 267 | + struct pattern_cache * node = first_pattern_cache; 268 | + struct pattern_cache * last_pattern_cache = first_pattern_cache; 269 | + struct pattern_cache * tmp; 270 | + unsigned int len; 271 | + 272 | + while (node != NULL) { 273 | + if (!strcmp(node->regex_string, regex_string)) 274 | + return node->pattern; 275 | + 276 | + last_pattern_cache = node;/* points at the last non-NULL node */ 277 | + node = node->next; 278 | + } 279 | + 280 | + /* If we reach the end of the list, then we have not yet cached 281 | + the pattern for this regex. Let's do that now. 282 | + Be paranoid about running out of memory to avoid list corruption. */ 283 | + tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC); 284 | + 285 | + if(!tmp) { 286 | + if (net_ratelimit()) 287 | + printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n"); 288 | + return NULL; 289 | + } 290 | + 291 | + tmp->regex_string = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC); 292 | + tmp->pattern = kmalloc(sizeof(struct regexp), GFP_ATOMIC); 293 | + tmp->next = NULL; 294 | + 295 | + if(!tmp->regex_string || !tmp->pattern) { 296 | + if (net_ratelimit()) 297 | + printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n"); 298 | + kfree(tmp->regex_string); 299 | + kfree(tmp->pattern); 300 | + kfree(tmp); 301 | + return NULL; 302 | + } 303 | + 304 | + /* Ok. The new node is all ready now. */ 305 | + node = tmp; 306 | + 307 | + if(first_pattern_cache == NULL) /* list is empty */ 308 | + first_pattern_cache = node; /* make node the beginning */ 309 | + else 310 | + last_pattern_cache->next = node; /* attach node to the end */ 311 | + 312 | + /* copy the string and compile the regex */ 313 | + len = strlen(regex_string); 314 | + DPRINTK("About to compile this: \"%s\"\n", regex_string); 315 | + node->pattern = regcomp(regex_string, &len); 316 | + if ( !node->pattern ) { 317 | + if (net_ratelimit()) 318 | + printk(KERN_ERR "layer7: Error compiling regexp \"%s\" (%s)\n", regex_string, protocol); 319 | + /* pattern is now cached as NULL, so we won't try again. */ 320 | + } 321 | + 322 | + strcpy(node->regex_string, regex_string); 323 | + return node->pattern; 324 | +} 325 | + 326 | +static int can_handle(const struct sk_buff *skb) 327 | +{ 328 | + if(!skb->nh.iph) /* not IP */ 329 | + return 0; 330 | + if(skb->nh.iph->protocol != IPPROTO_TCP && 331 | + skb->nh.iph->protocol != IPPROTO_UDP && 332 | + skb->nh.iph->protocol != IPPROTO_ICMP) 333 | + return 0; 334 | + return 1; 335 | +} 336 | + 337 | +/* Returns offset the into the skb->data that the application data starts */ 338 | +static int app_data_offset(const struct sk_buff *skb) 339 | +{ 340 | + /* In case we are ported somewhere (ebtables?) where skb->nh.iph 341 | + isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */ 342 | + int ip_hl = 4*skb->nh.iph->ihl; 343 | + 344 | + if( skb->nh.iph->protocol == IPPROTO_TCP ) { 345 | + /* 12 == offset into TCP header for the header length field. 346 | + Can't get this with skb->h.th->doff because the tcphdr 347 | + struct doesn't get set when routing (this is confirmed to be 348 | + true in Netfilter as well as QoS.) */ 349 | + int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4); 350 | + 351 | + return ip_hl + tcp_hl; 352 | + } else if( skb->nh.iph->protocol == IPPROTO_UDP ) { 353 | + return ip_hl + 8; /* UDP header is always 8 bytes */ 354 | + } else if( skb->nh.iph->protocol == IPPROTO_ICMP ) { 355 | + return ip_hl + 8; /* ICMP header is 8 bytes */ 356 | + } else { 357 | + if (net_ratelimit()) 358 | + printk(KERN_ERR "layer7: tried to handle unknown protocol!\n"); 359 | + return ip_hl + 8; /* something reasonable */ 360 | + } 361 | +} 362 | + 363 | +/* handles whether there's a match when we aren't appending data anymore */ 364 | +static int match_no_append(struct ip_conntrack * conntrack, struct ip_conntrack * master_conntrack, 365 | + enum ip_conntrack_info ctinfo, enum ip_conntrack_info master_ctinfo, 366 | + struct ipt_layer7_info * info) 367 | +{ 368 | + /* If we're in here, throw the app data away */ 369 | + WRITE_LOCK(&ct_lock); 370 | + if(master_conntrack->layer7.app_data != NULL) { 371 | + 372 | + #ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG 373 | + if(!master_conntrack->layer7.app_proto) { 374 | + char * f = friendly_print(master_conntrack->layer7.app_data); 375 | + char * g = hex_print(master_conntrack->layer7.app_data); 376 | + DPRINTK("\nl7-filter gave up after %d bytes (%llu packets):\n%s\n", 377 | + strlen(f), 378 | + TOTAL_PACKETS, f); 379 | + kfree(f); 380 | + DPRINTK("In hex: %s\n", g); 381 | + kfree(g); 382 | + } 383 | + #endif 384 | + 385 | + kfree(master_conntrack->layer7.app_data); 386 | + master_conntrack->layer7.app_data = NULL; /* don't free again */ 387 | + } 388 | + WRITE_UNLOCK(&ct_lock); 389 | + 390 | + if(master_conntrack->layer7.app_proto){ 391 | + /* Here child connections set their .app_proto (for /proc/net/ip_conntrack) */ 392 | + WRITE_LOCK(&ct_lock); 393 | + if(!conntrack->layer7.app_proto) { 394 | + conntrack->layer7.app_proto = kmalloc(strlen(master_conntrack->layer7.app_proto)+1, GFP_ATOMIC); 395 | + if(!conntrack->layer7.app_proto){ 396 | + if (net_ratelimit()) 397 | + printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n"); 398 | + WRITE_UNLOCK(&ct_lock); 399 | + return 1; 400 | + } 401 | + strcpy(conntrack->layer7.app_proto, master_conntrack->layer7.app_proto); 402 | + } 403 | + WRITE_UNLOCK(&ct_lock); 404 | + 405 | + return (!strcmp(master_conntrack->layer7.app_proto, info->protocol)); 406 | + } 407 | + else { 408 | + /* If not classified, set to "unknown" to distinguish from 409 | + connections that are still being tested. */ 410 | + WRITE_LOCK(&ct_lock); 411 | + master_conntrack->layer7.app_proto = kmalloc(strlen("unknown")+1, GFP_ATOMIC); 412 | + if(!master_conntrack->layer7.app_proto){ 413 | + if (net_ratelimit()) 414 | + printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n"); 415 | + WRITE_UNLOCK(&ct_lock); 416 | + return 1; 417 | + } 418 | + strcpy(master_conntrack->layer7.app_proto, "unknown"); 419 | + WRITE_UNLOCK(&ct_lock); 420 | + return 0; 421 | + } 422 | +} 423 | + 424 | +/* add the new app data to the conntrack. Return number of bytes added. */ 425 | +static int add_data(struct ip_conntrack * master_conntrack, 426 | + char * app_data, int appdatalen) 427 | +{ 428 | + int length = 0, i; 429 | + int oldlength = master_conntrack->layer7.app_data_len; 430 | + 431 | + /* Strip nulls. Make everything lower case (our regex lib doesn't 432 | + do case insensitivity). Add it to the end of the current data. */ 433 | + for(i = 0; i < CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN-oldlength-1 && 434 | + i < appdatalen; i++) { 435 | + if(app_data[i] != '\0') { 436 | + master_conntrack->layer7.app_data[length+oldlength] = 437 | + /* the kernel version of tolower mungs 'upper ascii' */ 438 | + isascii(app_data[i])? tolower(app_data[i]) : app_data[i]; 439 | + length++; 440 | + } 441 | + } 442 | + 443 | + master_conntrack->layer7.app_data[length+oldlength] = '\0'; 444 | + master_conntrack->layer7.app_data_len = length + oldlength; 445 | + 446 | + return length; 447 | +} 448 | + 449 | +/* Returns true on match and false otherwise. */ 450 | +static int match(/* const */struct sk_buff *skb, const struct net_device *in, 451 | + const struct net_device *out, const void *matchinfo, 452 | + int offset, int *hotdrop) 453 | +{ 454 | + struct ipt_layer7_info * info = (struct ipt_layer7_info *)matchinfo; 455 | + enum ip_conntrack_info master_ctinfo, ctinfo; 456 | + struct ip_conntrack *master_conntrack, *conntrack; 457 | + unsigned char * app_data; 458 | + unsigned int pattern_result, appdatalen; 459 | + regexp * comppattern; 460 | + 461 | + if(!can_handle(skb)){ 462 | + DPRINTK("layer7: This is some protocol I can't handle.\n"); 463 | + return info->invert; 464 | + } 465 | + 466 | + /* Treat the parent and all its children together as one connection, 467 | + except for the purpose of setting conntrack->layer7.app_proto in the 468 | + actual connection. This makes /proc/net/ip_conntrack somewhat more 469 | + satisfying. */ 470 | + if(!(conntrack = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) || 471 | + !(master_conntrack = ip_conntrack_get((struct sk_buff *)skb, &master_ctinfo))) { 472 | + DPRINTK("layer7: packet is not from a known connection, giving up.\n"); 473 | + return info->invert; 474 | + } 475 | + 476 | + /* Try to get a master conntrack (and its master etc) for FTP, etc. */ 477 | + while (master_ct(master_conntrack) != NULL) 478 | + master_conntrack = master_ct(master_conntrack); 479 | + 480 | + /* if we've classified it or seen too many packets */ 481 | + if(TOTAL_PACKETS > num_packets || 482 | + master_conntrack->layer7.app_proto) { 483 | + 484 | + pattern_result = match_no_append(conntrack, master_conntrack, ctinfo, master_ctinfo, info); 485 | + 486 | + /* skb->cb[0] == seen. Avoid doing things twice if there are two l7 487 | + rules. I'm not sure that using cb for this purpose is correct, although 488 | + it says "put your private variables there". But it doesn't look like it 489 | + is being used for anything else in the skbs that make it here. How can 490 | + I write to cb without making the compiler angry? */ 491 | + skb->cb[0] = 1; /* marking it seen here is probably irrelevant, but consistant */ 492 | + 493 | + return (pattern_result ^ info->invert); 494 | + } 495 | + 496 | + if(skb_is_nonlinear(skb)){ 497 | + if(skb_linearize(skb, GFP_ATOMIC) != 0){ 498 | + if (net_ratelimit()) 499 | + printk(KERN_ERR "layer7: failed to linearize packet, bailing.\n"); 500 | + return info->invert; 501 | + } 502 | + } 503 | + 504 | + /* now that the skb is linearized, it's safe to set these. */ 505 | + app_data = skb->data + app_data_offset(skb); 506 | + appdatalen = skb->tail - app_data; 507 | + 508 | + LOCK_BH(&list_lock); 509 | + /* the return value gets checked later, when we're ready to use it */ 510 | + comppattern = compile_and_cache(info->pattern, info->protocol); 511 | + UNLOCK_BH(&list_lock); 512 | + 513 | + /* On the first packet of a connection, allocate space for app data */ 514 | + WRITE_LOCK(&ct_lock); 515 | + if(TOTAL_PACKETS == 1 && !skb->cb[0] && !master_conntrack->layer7.app_data) { 516 | + master_conntrack->layer7.app_data = kmalloc(CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN, GFP_ATOMIC); 517 | + if(!master_conntrack->layer7.app_data){ 518 | + if (net_ratelimit()) 519 | + printk(KERN_ERR "layer7: out of memory in match, bailing.\n"); 520 | + WRITE_UNLOCK(&ct_lock); 521 | + return info->invert; 522 | + } 523 | + 524 | + master_conntrack->layer7.app_data[0] = '\0'; 525 | + } 526 | + WRITE_UNLOCK(&ct_lock); 527 | + 528 | + /* Can be here, but unallocated, if numpackets is increased near 529 | + the beginning of a connection */ 530 | + if(master_conntrack->layer7.app_data == NULL) 531 | + return (info->invert); /* unmatched */ 532 | + 533 | + if(!skb->cb[0]){ 534 | + int newbytes; 535 | + WRITE_LOCK(&ct_lock); 536 | + newbytes = add_data(master_conntrack, app_data, appdatalen); 537 | + WRITE_UNLOCK(&ct_lock); 538 | + 539 | + if(newbytes == 0) { /* didn't add any data */ 540 | + skb->cb[0] = 1; 541 | + /* Didn't match before, not going to match now */ 542 | + return info->invert; 543 | + } 544 | + } 545 | + 546 | + /* If looking for "unknown", then never match. "Unknown" means that 547 | + we've given up; we're still trying with these packets. */ 548 | + if(!strcmp(info->protocol, "unknown")) { 549 | + pattern_result = 0; 550 | + /* If the regexp failed to compile, don't bother running it */ 551 | + } else if(comppattern && regexec(comppattern, master_conntrack->layer7.app_data)) { 552 | + DPRINTK("layer7: regexec positive: %s!\n", info->protocol); 553 | + pattern_result = 1; 554 | + } else pattern_result = 0; 555 | + 556 | + if(pattern_result) { 557 | + WRITE_LOCK(&ct_lock); 558 | + master_conntrack->layer7.app_proto = kmalloc(strlen(info->protocol)+1, GFP_ATOMIC); 559 | + if(!master_conntrack->layer7.app_proto){ 560 | + if (net_ratelimit()) 561 | + printk(KERN_ERR "layer7: out of memory in match, bailing.\n"); 562 | + WRITE_UNLOCK(&ct_lock); 563 | + return (pattern_result ^ info->invert); 564 | + } 565 | + strcpy(master_conntrack->layer7.app_proto, info->protocol); 566 | + WRITE_UNLOCK(&ct_lock); 567 | + } 568 | + 569 | + /* mark the packet seen */ 570 | + skb->cb[0] = 1; 571 | + 572 | + return (pattern_result ^ info->invert); 573 | +} 574 | + 575 | +static int checkentry(const char *tablename, const struct ipt_ip *ip, 576 | + void *matchinfo, unsigned int matchsize, unsigned int hook_mask) 577 | +{ 578 | + if (matchsize != IPT_ALIGN(sizeof(struct ipt_layer7_info))) 579 | + return 0; 580 | + return 1; 581 | +} 582 | + 583 | +static struct ipt_match layer7_match = { 584 | + .name = "layer7", 585 | + .match = &match, 586 | + .checkentry = &checkentry, 587 | + .me = THIS_MODULE 588 | +}; 589 | + 590 | +/* taken from drivers/video/modedb.c */ 591 | +static int my_atoi(const char *s) 592 | +{ 593 | + int val = 0; 594 | + 595 | + for (;; s++) { 596 | + switch (*s) { 597 | + case '0'...'9': 598 | + val = 10*val+(*s-'0'); 599 | + break; 600 | + default: 601 | + return val; 602 | + } 603 | + } 604 | +} 605 | + 606 | +/* write out num_packets to userland. */ 607 | +static int layer7_read_proc(char* page, char ** start, off_t off, int count, 608 | + int* eof, void * data) 609 | +{ 610 | + if(num_packets > 99 && net_ratelimit()) 611 | + printk(KERN_ERR "layer7: NOT REACHED. num_packets too big\n"); 612 | + 613 | + page[0] = num_packets/10 + '0'; 614 | + page[1] = num_packets%10 + '0'; 615 | + page[2] = '\n'; 616 | + page[3] = '\0'; 617 | + 618 | + *eof=1; 619 | + 620 | + return 3; 621 | +} 622 | + 623 | +/* Read in num_packets from userland */ 624 | +static int layer7_write_proc(struct file* file, const char* buffer, 625 | + unsigned long count, void *data) 626 | +{ 627 | + char * foo = kmalloc(count, GFP_ATOMIC); 628 | + 629 | + if(!foo){ 630 | + if (net_ratelimit()) 631 | + printk(KERN_ERR "layer7: out of memory, bailing. num_packets unchanged.\n"); 632 | + return count; 633 | + } 634 | + 635 | + copy_from_user(foo, buffer, count); 636 | + 637 | + num_packets = my_atoi(foo); 638 | + kfree (foo); 639 | + 640 | + /* This has an arbitrary limit to make the math easier. I'm lazy. 641 | + But anyway, 99 is a LOT! If you want more, you're doing it wrong! */ 642 | + if(num_packets > 99) { 643 | + printk(KERN_WARNING "layer7: num_packets can't be > 99.\n"); 644 | + num_packets = 99; 645 | + } else if(num_packets < 1) { 646 | + printk(KERN_WARNING "layer7: num_packets can't be < 1.\n"); 647 | + num_packets = 1; 648 | + } 649 | + 650 | + return count; 651 | +} 652 | + 653 | +/* register the proc file */ 654 | +static void layer7_init_proc(void) 655 | +{ 656 | + struct proc_dir_entry* entry; 657 | + entry = create_proc_entry("layer7_numpackets", 0644, proc_net); 658 | + entry->read_proc = layer7_read_proc; 659 | + entry->write_proc = layer7_write_proc; 660 | +} 661 | + 662 | +static void layer7_cleanup_proc(void) 663 | +{ 664 | + remove_proc_entry("layer7_numpackets", proc_net); 665 | +} 666 | + 667 | +static int __init init(void) 668 | +{ 669 | + layer7_init_proc(); 670 | + return ipt_register_match(&layer7_match); 671 | +} 672 | + 673 | +static void __exit fini(void) 674 | +{ 675 | + layer7_cleanup_proc(); 676 | + ipt_unregister_match(&layer7_match); 677 | +} 678 | + 679 | +module_init(init); 680 | +module_exit(fini); 681 | --- linux-2.6.10-stock/net/ipv4/netfilter/regexp/regexp.c 1969-12-31 18:00:00.000000000 -0600 682 | +++ linux-2.6.10-layer7/net/ipv4/netfilter/regexp/regexp.c 2005-01-07 13:24:01.000000000 -0600 683 | @@ -0,0 +1,1195 @@ 684 | +/* 685 | + * regcomp and regexec -- regsub and regerror are elsewhere 686 | + * @(#)regexp.c 1.3 of 18 April 87 687 | + * 688 | + * Copyright (c) 1986 by University of Toronto. 689 | + * Written by Henry Spencer. Not derived from licensed software. 690 | + * 691 | + * Permission is granted to anyone to use this software for any 692 | + * purpose on any computer system, and to redistribute it freely, 693 | + * subject to the following restrictions: 694 | + * 695 | + * 1. The author is not responsible for the consequences of use of 696 | + * this software, no matter how awful, even if they arise 697 | + * from defects in it. 698 | + * 699 | + * 2. The origin of this software must not be misrepresented, either 700 | + * by explicit claim or by omission. 701 | + * 702 | + * 3. Altered versions must be plainly marked as such, and must not 703 | + * be misrepresented as being the original software. 704 | + * 705 | + * Beware that some of this code is subtly aware of the way operator 706 | + * precedence is structured in regular expressions. Serious changes in 707 | + * regular-expression syntax might require a total rethink. 708 | + * 709 | + * This code was modified by Ethan Sommer to work within the kernel 710 | + * (it now uses kmalloc etc..) 711 | + * 712 | + * Modified slightly by Matthew Strait to use more modern C. 713 | + */ 714 | + 715 | +#include "regexp.h" 716 | +#include "regmagic.h" 717 | + 718 | +/* added by ethan and matt. Lets it work in both kernel and user space. 719 | +(So iptables can use it, for instance.) Yea, it goes both ways... */ 720 | +#if __KERNEL__ 721 | + #define malloc(foo) kmalloc(foo,GFP_ATOMIC) 722 | +#else 723 | + #define printk(format,args...) printf(format,##args) 724 | +#endif 725 | + 726 | +void regerror(char * s) 727 | +{ 728 | + printk("<3>Regexp: %s\n", s); 729 | + /* NOTREACHED */ 730 | +} 731 | + 732 | +/* 733 | + * The "internal use only" fields in regexp.h are present to pass info from 734 | + * compile to execute that permits the execute phase to run lots faster on 735 | + * simple cases. They are: 736 | + * 737 | + * regstart char that must begin a match; '\0' if none obvious 738 | + * reganch is the match anchored (at beginning-of-line only)? 739 | + * regmust string (pointer into program) that match must include, or NULL 740 | + * regmlen length of regmust string 741 | + * 742 | + * Regstart and reganch permit very fast decisions on suitable starting points 743 | + * for a match, cutting down the work a lot. Regmust permits fast rejection 744 | + * of lines that cannot possibly match. The regmust tests are costly enough 745 | + * that regcomp() supplies a regmust only if the r.e. contains something 746 | + * potentially expensive (at present, the only such thing detected is * or + 747 | + * at the start of the r.e., which can involve a lot of backup). Regmlen is 748 | + * supplied because the test in regexec() needs it and regcomp() is computing 749 | + * it anyway. 750 | + */ 751 | + 752 | +/* 753 | + * Structure for regexp "program". This is essentially a linear encoding 754 | + * of a nondeterministic finite-state machine (aka syntax charts or 755 | + * "railroad normal form" in parsing technology). Each node is an opcode 756 | + * plus a "next" pointer, possibly plus an operand. "Next" pointers of 757 | + * all nodes except BRANCH implement concatenation; a "next" pointer with 758 | + * a BRANCH on both ends of it is connecting two alternatives. (Here we 759 | + * have one of the subtle syntax dependencies: an individual BRANCH (as 760 | + * opposed to a collection of them) is never concatenated with anything 761 | + * because of operator precedence.) The operand of some types of node is 762 | + * a literal string; for others, it is a node leading into a sub-FSM. In 763 | + * particular, the operand of a BRANCH node is the first node of the branch. 764 | + * (NB this is *not* a tree structure: the tail of the branch connects 765 | + * to the thing following the set of BRANCHes.) The opcodes are: 766 | + */ 767 | + 768 | +/* definition number opnd? meaning */ 769 | +#define END 0 /* no End of program. */ 770 | +#define BOL 1 /* no Match "" at beginning of line. */ 771 | +#define EOL 2 /* no Match "" at end of line. */ 772 | +#define ANY 3 /* no Match any one character. */ 773 | +#define ANYOF 4 /* str Match any character in this string. */ 774 | +#define ANYBUT 5 /* str Match any character not in this string. */ 775 | +#define BRANCH 6 /* node Match this alternative, or the next... */ 776 | +#define BACK 7 /* no Match "", "next" ptr points backward. */ 777 | +#define EXACTLY 8 /* str Match this string. */ 778 | +#define NOTHING 9 /* no Match empty string. */ 779 | +#define STAR 10 /* node Match this (simple) thing 0 or more times. */ 780 | +#define PLUS 11 /* node Match this (simple) thing 1 or more times. */ 781 | +#define OPEN 20 /* no Mark this point in input as start of #n. */ 782 | + /* OPEN+1 is number 1, etc. */ 783 | +#define CLOSE 30 /* no Analogous to OPEN. */ 784 | + 785 | +/* 786 | + * Opcode notes: 787 | + * 788 | + * BRANCH The set of branches constituting a single choice are hooked 789 | + * together with their "next" pointers, since precedence prevents 790 | + * anything being concatenated to any individual branch. The 791 | + * "next" pointer of the last BRANCH in a choice points to the 792 | + * thing following the whole choice. This is also where the 793 | + * final "next" pointer of each individual branch points; each 794 | + * branch starts with the operand node of a BRANCH node. 795 | + * 796 | + * BACK Normal "next" pointers all implicitly point forward; BACK 797 | + * exists to make loop structures possible. 798 | + * 799 | + * STAR,PLUS '?', and complex '*' and '+', are implemented as circular 800 | + * BRANCH structures using BACK. Simple cases (one character 801 | + * per match) are implemented with STAR and PLUS for speed 802 | + * and to minimize recursive plunges. 803 | + * 804 | + * OPEN,CLOSE ...are numbered at compile time. 805 | + */ 806 | + 807 | +/* 808 | + * A node is one char of opcode followed by two chars of "next" pointer. 809 | + * "Next" pointers are stored as two 8-bit pieces, high order first. The 810 | + * value is a positive offset from the opcode of the node containing it. 811 | + * An operand, if any, simply follows the node. (Note that much of the 812 | + * code generation knows about this implicit relationship.) 813 | + * 814 | + * Using two bytes for the "next" pointer is vast overkill for most things, 815 | + * but allows patterns to get big without disasters. 816 | + */ 817 | +#define OP(p) (*(p)) 818 | +#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) 819 | +#define OPERAND(p) ((p) + 3) 820 | + 821 | +/* 822 | + * See regmagic.h for one further detail of program structure. 823 | + */ 824 | + 825 | + 826 | +/* 827 | + * Utility definitions. 828 | + */ 829 | +#ifndef CHARBITS 830 | +#define UCHARAT(p) ((int)*(unsigned char *)(p)) 831 | +#else 832 | +#define UCHARAT(p) ((int)*(p)&CHARBITS) 833 | +#endif 834 | + 835 | +#define FAIL(m) { regerror(m); return(NULL); } 836 | +#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') 837 | +#define META "^$.[()|?+*\\" 838 | + 839 | +/* 840 | + * Flags to be passed up and down. 841 | + */ 842 | +#define HASWIDTH 01 /* Known never to match null string. */ 843 | +#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ 844 | +#define SPSTART 04 /* Starts with * or +. */ 845 | +#define WORST 0 /* Worst case. */ 846 | + 847 | +/* 848 | + * Global work variables for regcomp(). 849 | + */ 850 | +static char *regparse; /* Input-scan pointer. */ 851 | +static int regnpar; /* () count. */ 852 | +static char regdummy; 853 | +static char *regcode; /* Code-emit pointer; ®dummy = don't. */ 854 | +static long regsize; /* Code size. */ 855 | + 856 | +/* 857 | + * Forward declarations for regcomp()'s friends. 858 | + */ 859 | +#ifndef STATIC 860 | +#define STATIC static 861 | +#endif 862 | +STATIC char *reg(int paren,int *flagp); 863 | +STATIC char *regbranch(int *flagp); 864 | +STATIC char *regpiece(int *flagp); 865 | +STATIC char *regatom(int *flagp); 866 | +STATIC char *regnode(char op); 867 | +STATIC char *regnext(char *p); 868 | +STATIC void regc(char b); 869 | +STATIC void reginsert(char op, char *opnd); 870 | +STATIC void regtail(char *p, char *val); 871 | +STATIC void regoptail(char *p, char *val); 872 | + 873 | + 874 | +__kernel_size_t my_strcspn(const char *s1,const char *s2) 875 | +{ 876 | + char *scan1; 877 | + char *scan2; 878 | + int count; 879 | + 880 | + count = 0; 881 | + for (scan1 = (char *)s1; *scan1 != '\0'; scan1++) { 882 | + for (scan2 = (char *)s2; *scan2 != '\0';) /* ++ moved down. */ 883 | + if (*scan1 == *scan2++) 884 | + return(count); 885 | + count++; 886 | + } 887 | + return(count); 888 | +} 889 | + 890 | +/* 891 | + - regcomp - compile a regular expression into internal code 892 | + * 893 | + * We can't allocate space until we know how big the compiled form will be, 894 | + * but we can't compile it (and thus know how big it is) until we've got a 895 | + * place to put the code. So we cheat: we compile it twice, once with code 896 | + * generation turned off and size counting turned on, and once "for real". 897 | + * This also means that we don't allocate space until we are sure that the 898 | + * thing really will compile successfully, and we never have to move the 899 | + * code and thus invalidate pointers into it. (Note that it has to be in 900 | + * one piece because free() must be able to free it all.) 901 | + * 902 | + * Beware that the optimization-preparation code in here knows about some 903 | + * of the structure of the compiled regexp. 904 | + */ 905 | +regexp * 906 | +regcomp(char *exp,int *patternsize) 907 | +{ 908 | + register regexp *r; 909 | + register char *scan; 910 | + register char *longest; 911 | + register int len; 912 | + int flags; 913 | + /* commented out by ethan 914 | + extern char *malloc(); 915 | + */ 916 | + 917 | + if (exp == NULL) 918 | + FAIL("NULL argument"); 919 | + 920 | + /* First pass: determine size, legality. */ 921 | + regparse = exp; 922 | + regnpar = 1; 923 | + regsize = 0L; 924 | + regcode = ®dummy; 925 | + regc(MAGIC); 926 | + if (reg(0, &flags) == NULL) 927 | + return(NULL); 928 | + 929 | + /* Small enough for pointer-storage convention? */ 930 | + if (regsize >= 32767L) /* Probably could be 65535L. */ 931 | + FAIL("regexp too big"); 932 | + 933 | + /* Allocate space. */ 934 | + *patternsize=sizeof(regexp) + (unsigned)regsize; 935 | + r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); 936 | + if (r == NULL) 937 | + FAIL("out of space"); 938 | + 939 | + /* Second pass: emit code. */ 940 | + regparse = exp; 941 | + regnpar = 1; 942 | + regcode = r->program; 943 | + regc(MAGIC); 944 | + if (reg(0, &flags) == NULL) 945 | + return(NULL); 946 | + 947 | + /* Dig out information for optimizations. */ 948 | + r->regstart = '\0'; /* Worst-case defaults. */ 949 | + r->reganch = 0; 950 | + r->regmust = NULL; 951 | + r->regmlen = 0; 952 | + scan = r->program+1; /* First BRANCH. */ 953 | + if (OP(regnext(scan)) == END) { /* Only one top-level choice. */ 954 | + scan = OPERAND(scan); 955 | + 956 | + /* Starting-point info. */ 957 | + if (OP(scan) == EXACTLY) 958 | + r->regstart = *OPERAND(scan); 959 | + else if (OP(scan) == BOL) 960 | + r->reganch++; 961 | + 962 | + /* 963 | + * If there's something expensive in the r.e., find the 964 | + * longest literal string that must appear and make it the 965 | + * regmust. Resolve ties in favor of later strings, since 966 | + * the regstart check works with the beginning of the r.e. 967 | + * and avoiding duplication strengthens checking. Not a 968 | + * strong reason, but sufficient in the absence of others. 969 | + */ 970 | + if (flags&SPSTART) { 971 | + longest = NULL; 972 | + len = 0; 973 | + for (; scan != NULL; scan = regnext(scan)) 974 | + if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { 975 | + longest = OPERAND(scan); 976 | + len = strlen(OPERAND(scan)); 977 | + } 978 | + r->regmust = longest; 979 | + r->regmlen = len; 980 | + } 981 | + } 982 | + 983 | + return(r); 984 | +} 985 | + 986 | +/* 987 | + - reg - regular expression, i.e. main body or parenthesized thing 988 | + * 989 | + * Caller must absorb opening parenthesis. 990 | + * 991 | + * Combining parenthesis handling with the base level of regular expression 992 | + * is a trifle forced, but the need to tie the tails of the branches to what 993 | + * follows makes it hard to avoid. 994 | + */ 995 | +static char * 996 | +reg(int paren, int *flagp /* Parenthesized? */ ) 997 | +{ 998 | + register char *ret; 999 | + register char *br; 1000 | + register char *ender; 1001 | + register int parno = 0; /* 0 makes gcc happy */ 1002 | + int flags; 1003 | + 1004 | + *flagp = HASWIDTH; /* Tentatively. */ 1005 | + 1006 | + /* Make an OPEN node, if parenthesized. */ 1007 | + if (paren) { 1008 | + if (regnpar >= NSUBEXP) 1009 | + FAIL("too many ()"); 1010 | + parno = regnpar; 1011 | + regnpar++; 1012 | + ret = regnode(OPEN+parno); 1013 | + } else 1014 | + ret = NULL; 1015 | + 1016 | + /* Pick up the branches, linking them together. */ 1017 | + br = regbranch(&flags); 1018 | + if (br == NULL) 1019 | + return(NULL); 1020 | + if (ret != NULL) 1021 | + regtail(ret, br); /* OPEN -> first. */ 1022 | + else 1023 | + ret = br; 1024 | + if (!(flags&HASWIDTH)) 1025 | + *flagp &= ~HASWIDTH; 1026 | + *flagp |= flags&SPSTART; 1027 | + while (*regparse == '|') { 1028 | + regparse++; 1029 | + br = regbranch(&flags); 1030 | + if (br == NULL) 1031 | + return(NULL); 1032 | + regtail(ret, br); /* BRANCH -> BRANCH. */ 1033 | + if (!(flags&HASWIDTH)) 1034 | + *flagp &= ~HASWIDTH; 1035 | + *flagp |= flags&SPSTART; 1036 | + } 1037 | + 1038 | + /* Make a closing node, and hook it on the end. */ 1039 | + ender = regnode((paren) ? CLOSE+parno : END); 1040 | + regtail(ret, ender); 1041 | + 1042 | + /* Hook the tails of the branches to the closing node. */ 1043 | + for (br = ret; br != NULL; br = regnext(br)) 1044 | + regoptail(br, ender); 1045 | + 1046 | + /* Check for proper termination. */ 1047 | + if (paren && *regparse++ != ')') { 1048 | + FAIL("unmatched ()"); 1049 | + } else if (!paren && *regparse != '\0') { 1050 | + if (*regparse == ')') { 1051 | + FAIL("unmatched ()"); 1052 | + } else 1053 | + FAIL("junk on end"); /* "Can't happen". */ 1054 | + /* NOTREACHED */ 1055 | + } 1056 | + 1057 | + return(ret); 1058 | +} 1059 | + 1060 | +/* 1061 | + - regbranch - one alternative of an | operator 1062 | + * 1063 | + * Implements the concatenation operator. 1064 | + */ 1065 | +static char * 1066 | +regbranch(int *flagp) 1067 | +{ 1068 | + register char *ret; 1069 | + register char *chain; 1070 | + register char *latest; 1071 | + int flags; 1072 | + 1073 | + *flagp = WORST; /* Tentatively. */ 1074 | + 1075 | + ret = regnode(BRANCH); 1076 | + chain = NULL; 1077 | + while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { 1078 | + latest = regpiece(&flags); 1079 | + if (latest == NULL) 1080 | + return(NULL); 1081 | + *flagp |= flags&HASWIDTH; 1082 | + if (chain == NULL) /* First piece. */ 1083 | + *flagp |= flags&SPSTART; 1084 | + else 1085 | + regtail(chain, latest); 1086 | + chain = latest; 1087 | + } 1088 | + if (chain == NULL) /* Loop ran zero times. */ 1089 | + (void) regnode(NOTHING); 1090 | + 1091 | + return(ret); 1092 | +} 1093 | + 1094 | +/* 1095 | + - regpiece - something followed by possible [*+?] 1096 | + * 1097 | + * Note that the branching code sequences used for ? and the general cases 1098 | + * of * and + are somewhat optimized: they use the same NOTHING node as 1099 | + * both the endmarker for their branch list and the body of the last branch. 1100 | + * It might seem that this node could be dispensed with entirely, but the 1101 | + * endmarker role is not redundant. 1102 | + */ 1103 | +static char * 1104 | +regpiece(int *flagp) 1105 | +{ 1106 | + register char *ret; 1107 | + register char op; 1108 | + register char *next; 1109 | + int flags; 1110 | + 1111 | + ret = regatom(&flags); 1112 | + if (ret == NULL) 1113 | + return(NULL); 1114 | + 1115 | + op = *regparse; 1116 | + if (!ISMULT(op)) { 1117 | + *flagp = flags; 1118 | + return(ret); 1119 | + } 1120 | + 1121 | + if (!(flags&HASWIDTH) && op != '?') 1122 | + FAIL("*+ operand could be empty"); 1123 | + *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); 1124 | + 1125 | + if (op == '*' && (flags&SIMPLE)) 1126 | + reginsert(STAR, ret); 1127 | + else if (op == '*') { 1128 | + /* Emit x* as (x&|), where & means "self". */ 1129 | + reginsert(BRANCH, ret); /* Either x */ 1130 | + regoptail(ret, regnode(BACK)); /* and loop */ 1131 | + regoptail(ret, ret); /* back */ 1132 | + regtail(ret, regnode(BRANCH)); /* or */ 1133 | + regtail(ret, regnode(NOTHING)); /* null. */ 1134 | + } else if (op == '+' && (flags&SIMPLE)) 1135 | + reginsert(PLUS, ret); 1136 | + else if (op == '+') { 1137 | + /* Emit x+ as x(&|), where & means "self". */ 1138 | + next = regnode(BRANCH); /* Either */ 1139 | + regtail(ret, next); 1140 | + regtail(regnode(BACK), ret); /* loop back */ 1141 | + regtail(next, regnode(BRANCH)); /* or */ 1142 | + regtail(ret, regnode(NOTHING)); /* null. */ 1143 | + } else if (op == '?') { 1144 | + /* Emit x? as (x|) */ 1145 | + reginsert(BRANCH, ret); /* Either x */ 1146 | + regtail(ret, regnode(BRANCH)); /* or */ 1147 | + next = regnode(NOTHING); /* null. */ 1148 | + regtail(ret, next); 1149 | + regoptail(ret, next); 1150 | + } 1151 | + regparse++; 1152 | + if (ISMULT(*regparse)) 1153 | + FAIL("nested *?+"); 1154 | + 1155 | + return(ret); 1156 | +} 1157 | + 1158 | +/* 1159 | + - regatom - the lowest level 1160 | + * 1161 | + * Optimization: gobbles an entire sequence of ordinary characters so that 1162 | + * it can turn them into a single node, which is smaller to store and 1163 | + * faster to run. Backslashed characters are exceptions, each becoming a 1164 | + * separate node; the code is simpler that way and it's not worth fixing. 1165 | + */ 1166 | +static char * 1167 | +regatom(int *flagp) 1168 | +{ 1169 | + register char *ret; 1170 | + int flags; 1171 | + 1172 | + *flagp = WORST; /* Tentatively. */ 1173 | + 1174 | + switch (*regparse++) { 1175 | + case '^': 1176 | + ret = regnode(BOL); 1177 | + break; 1178 | + case '$': 1179 | + ret = regnode(EOL); 1180 | + break; 1181 | + case '.': 1182 | + ret = regnode(ANY); 1183 | + *flagp |= HASWIDTH|SIMPLE; 1184 | + break; 1185 | + case '[': { 1186 | + register int class; 1187 | + register int classend; 1188 | + 1189 | + if (*regparse == '^') { /* Complement of range. */ 1190 | + ret = regnode(ANYBUT); 1191 | + regparse++; 1192 | + } else 1193 | + ret = regnode(ANYOF); 1194 | + if (*regparse == ']' || *regparse == '-') 1195 | + regc(*regparse++); 1196 | + while (*regparse != '\0' && *regparse != ']') { 1197 | + if (*regparse == '-') { 1198 | + regparse++; 1199 | + if (*regparse == ']' || *regparse == '\0') 1200 | + regc('-'); 1201 | + else { 1202 | + class = UCHARAT(regparse-2)+1; 1203 | + classend = UCHARAT(regparse); 1204 | + if (class > classend+1) 1205 | + FAIL("invalid [] range"); 1206 | + for (; class <= classend; class++) 1207 | + regc(class); 1208 | + regparse++; 1209 | + } 1210 | + } else 1211 | + regc(*regparse++); 1212 | + } 1213 | + regc('\0'); 1214 | + if (*regparse != ']') 1215 | + FAIL("unmatched []"); 1216 | + regparse++; 1217 | + *flagp |= HASWIDTH|SIMPLE; 1218 | + } 1219 | + break; 1220 | + case '(': 1221 | + ret = reg(1, &flags); 1222 | + if (ret == NULL) 1223 | + return(NULL); 1224 | + *flagp |= flags&(HASWIDTH|SPSTART); 1225 | + break; 1226 | + case '\0': 1227 | + case '|': 1228 | + case ')': 1229 | + FAIL("internal urp"); /* Supposed to be caught earlier. */ 1230 | + break; 1231 | + case '?': 1232 | + case '+': 1233 | + case '*': 1234 | + FAIL("?+* follows nothing"); 1235 | + break; 1236 | + case '\\': 1237 | + if (*regparse == '\0') 1238 | + FAIL("trailing \\"); 1239 | + ret = regnode(EXACTLY); 1240 | + regc(*regparse++); 1241 | + regc('\0'); 1242 | + *flagp |= HASWIDTH|SIMPLE; 1243 | + break; 1244 | + default: { 1245 | + register int len; 1246 | + register char ender; 1247 | + 1248 | + regparse--; 1249 | + len = my_strcspn((const char *)regparse, (const char *)META); 1250 | + if (len <= 0) 1251 | + FAIL("internal disaster"); 1252 | + ender = *(regparse+len); 1253 | + if (len > 1 && ISMULT(ender)) 1254 | + len--; /* Back off clear of ?+* operand. */ 1255 | + *flagp |= HASWIDTH; 1256 | + if (len == 1) 1257 | + *flagp |= SIMPLE; 1258 | + ret = regnode(EXACTLY); 1259 | + while (len > 0) { 1260 | + regc(*regparse++); 1261 | + len--; 1262 | + } 1263 | + regc('\0'); 1264 | + } 1265 | + break; 1266 | + } 1267 | + 1268 | + return(ret); 1269 | +} 1270 | + 1271 | +/* 1272 | + - regnode - emit a node 1273 | + */ 1274 | +static char * /* Location. */ 1275 | +regnode(char op) 1276 | +{ 1277 | + register char *ret; 1278 | + register char *ptr; 1279 | + 1280 | + ret = regcode; 1281 | + if (ret == ®dummy) { 1282 | + regsize += 3; 1283 | + return(ret); 1284 | + } 1285 | + 1286 | + ptr = ret; 1287 | + *ptr++ = op; 1288 | + *ptr++ = '\0'; /* Null "next" pointer. */ 1289 | + *ptr++ = '\0'; 1290 | + regcode = ptr; 1291 | + 1292 | + return(ret); 1293 | +} 1294 | + 1295 | +/* 1296 | + - regc - emit (if appropriate) a byte of code 1297 | + */ 1298 | +static void 1299 | +regc(char b) 1300 | +{ 1301 | + if (regcode != ®dummy) 1302 | + *regcode++ = b; 1303 | + else 1304 | + regsize++; 1305 | +} 1306 | + 1307 | +/* 1308 | + - reginsert - insert an operator in front of already-emitted operand 1309 | + * 1310 | + * Means relocating the operand. 1311 | + */ 1312 | +static void 1313 | +reginsert(char op, char* opnd) 1314 | +{ 1315 | + register char *src; 1316 | + register char *dst; 1317 | + register char *place; 1318 | + 1319 | + if (regcode == ®dummy) { 1320 | + regsize += 3; 1321 | + return; 1322 | + } 1323 | + 1324 | + src = regcode; 1325 | + regcode += 3; 1326 | + dst = regcode; 1327 | + while (src > opnd) 1328 | + *--dst = *--src; 1329 | + 1330 | + place = opnd; /* Op node, where operand used to be. */ 1331 | + *place++ = op; 1332 | + *place++ = '\0'; 1333 | + *place++ = '\0'; 1334 | +} 1335 | + 1336 | +/* 1337 | + - regtail - set the next-pointer at the end of a node chain 1338 | + */ 1339 | +static void 1340 | +regtail(char *p, char *val) 1341 | +{ 1342 | + register char *scan; 1343 | + register char *temp; 1344 | + register int offset; 1345 | + 1346 | + if (p == ®dummy) 1347 | + return; 1348 | + 1349 | + /* Find last node. */ 1350 | + scan = p; 1351 | + for (;;) { 1352 | + temp = regnext(scan); 1353 | + if (temp == NULL) 1354 | + break; 1355 | + scan = temp; 1356 | + } 1357 | + 1358 | + if (OP(scan) == BACK) 1359 | + offset = scan - val; 1360 | + else 1361 | + offset = val - scan; 1362 | + *(scan+1) = (offset>>8)&0377; 1363 | + *(scan+2) = offset&0377; 1364 | +} 1365 | + 1366 | +/* 1367 | + - regoptail - regtail on operand of first argument; nop if operandless 1368 | + */ 1369 | +static void 1370 | +regoptail(char *p, char *val) 1371 | +{ 1372 | + /* "Operandless" and "op != BRANCH" are synonymous in practice. */ 1373 | + if (p == NULL || p == ®dummy || OP(p) != BRANCH) 1374 | + return; 1375 | + regtail(OPERAND(p), val); 1376 | +} 1377 | + 1378 | +/* 1379 | + * regexec and friends 1380 | + */ 1381 | + 1382 | +/* 1383 | + * Global work variables for regexec(). 1384 | + */ 1385 | +static char *reginput; /* String-input pointer. */ 1386 | +static char *regbol; /* Beginning of input, for ^ check. */ 1387 | +static char **regstartp; /* Pointer to startp array. */ 1388 | +static char **regendp; /* Ditto for endp. */ 1389 | + 1390 | +/* 1391 | + * Forwards. 1392 | + */ 1393 | +STATIC int regtry(regexp *prog, char *string); 1394 | +STATIC int regmatch(char *prog); 1395 | +STATIC int regrepeat(char *p); 1396 | + 1397 | +#ifdef DEBUG 1398 | +int regnarrate = 0; 1399 | +void regdump(); 1400 | +STATIC char *regprop(char *op); 1401 | +#endif 1402 | + 1403 | +/* 1404 | + - regexec - match a regexp against a string 1405 | + */ 1406 | +int 1407 | +regexec(regexp *prog, char *string) 1408 | +{ 1409 | + register char *s; 1410 | + 1411 | + /* Be paranoid... */ 1412 | + if (prog == NULL || string == NULL) { 1413 | + printk("<3>Regexp: NULL parameter\n"); 1414 | + return(0); 1415 | + } 1416 | + 1417 | + /* Check validity of program. */ 1418 | + if (UCHARAT(prog->program) != MAGIC) { 1419 | + printk("<3>Regexp: corrupted program\n"); 1420 | + return(0); 1421 | + } 1422 | + 1423 | + /* If there is a "must appear" string, look for it. */ 1424 | + if (prog->regmust != NULL) { 1425 | + s = string; 1426 | + while ((s = strchr(s, prog->regmust[0])) != NULL) { 1427 | + if (strncmp(s, prog->regmust, prog->regmlen) == 0) 1428 | + break; /* Found it. */ 1429 | + s++; 1430 | + } 1431 | + if (s == NULL) /* Not present. */ 1432 | + return(0); 1433 | + } 1434 | + 1435 | + /* Mark beginning of line for ^ . */ 1436 | + regbol = string; 1437 | + 1438 | + /* Simplest case: anchored match need be tried only once. */ 1439 | + if (prog->reganch) 1440 | + return(regtry(prog, string)); 1441 | + 1442 | + /* Messy cases: unanchored match. */ 1443 | + s = string; 1444 | + if (prog->regstart != '\0') 1445 | + /* We know what char it must start with. */ 1446 | + while ((s = strchr(s, prog->regstart)) != NULL) { 1447 | + if (regtry(prog, s)) 1448 | + return(1); 1449 | + s++; 1450 | + } 1451 | + else 1452 | + /* We don't -- general case. */ 1453 | + do { 1454 | + if (regtry(prog, s)) 1455 | + return(1); 1456 | + } while (*s++ != '\0'); 1457 | + 1458 | + /* Failure. */ 1459 | + return(0); 1460 | +} 1461 | + 1462 | +/* 1463 | + - regtry - try match at specific point 1464 | + */ 1465 | +static int /* 0 failure, 1 success */ 1466 | +regtry(regexp *prog, char *string) 1467 | +{ 1468 | + register int i; 1469 | + register char **sp; 1470 | + register char **ep; 1471 | + 1472 | + reginput = string; 1473 | + regstartp = prog->startp; 1474 | + regendp = prog->endp; 1475 | + 1476 | + sp = prog->startp; 1477 | + ep = prog->endp; 1478 | + for (i = NSUBEXP; i > 0; i--) { 1479 | + *sp++ = NULL; 1480 | + *ep++ = NULL; 1481 | + } 1482 | + if (regmatch(prog->program + 1)) { 1483 | + prog->startp[0] = string; 1484 | + prog->endp[0] = reginput; 1485 | + return(1); 1486 | + } else 1487 | + return(0); 1488 | +} 1489 | + 1490 | +/* 1491 | + - regmatch - main matching routine 1492 | + * 1493 | + * Conceptually the strategy is simple: check to see whether the current 1494 | + * node matches, call self recursively to see whether the rest matches, 1495 | + * and then act accordingly. In practice we make some effort to avoid 1496 | + * recursion, in particular by going through "ordinary" nodes (that don't 1497 | + * need to know whether the rest of the match failed) by a loop instead of 1498 | + * by recursion. 1499 | + */ 1500 | +static int /* 0 failure, 1 success */ 1501 | +regmatch(char *prog) 1502 | +{ 1503 | + register char *scan = prog; /* Current node. */ 1504 | + char *next; /* Next node. */ 1505 | + 1506 | +#ifdef DEBUG 1507 | + if (scan != NULL && regnarrate) 1508 | + fprintf(stderr, "%s(\n", regprop(scan)); 1509 | +#endif 1510 | + while (scan != NULL) { 1511 | +#ifdef DEBUG 1512 | + if (regnarrate) 1513 | + fprintf(stderr, "%s...\n", regprop(scan)); 1514 | +#endif 1515 | + next = regnext(scan); 1516 | + 1517 | + switch (OP(scan)) { 1518 | + case BOL: 1519 | + if (reginput != regbol) 1520 | + return(0); 1521 | + break; 1522 | + case EOL: 1523 | + if (*reginput != '\0') 1524 | + return(0); 1525 | + break; 1526 | + case ANY: 1527 | + if (*reginput == '\0') 1528 | + return(0); 1529 | + reginput++; 1530 | + break; 1531 | + case EXACTLY: { 1532 | + register int len; 1533 | + register char *opnd; 1534 | + 1535 | + opnd = OPERAND(scan); 1536 | + /* Inline the first character, for speed. */ 1537 | + if (*opnd != *reginput) 1538 | + return(0); 1539 | + len = strlen(opnd); 1540 | + if (len > 1 && strncmp(opnd, reginput, len) != 0) 1541 | + return(0); 1542 | + reginput += len; 1543 | + } 1544 | + break; 1545 | + case ANYOF: 1546 | + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL) 1547 | + return(0); 1548 | + reginput++; 1549 | + break; 1550 | + case ANYBUT: 1551 | + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL) 1552 | + return(0); 1553 | + reginput++; 1554 | + break; 1555 | + case NOTHING: 1556 | + case BACK: 1557 | + break; 1558 | + case OPEN+1: 1559 | + case OPEN+2: 1560 | + case OPEN+3: 1561 | + case OPEN+4: 1562 | + case OPEN+5: 1563 | + case OPEN+6: 1564 | + case OPEN+7: 1565 | + case OPEN+8: 1566 | + case OPEN+9: { 1567 | + register int no; 1568 | + register char *save; 1569 | + 1570 | + no = OP(scan) - OPEN; 1571 | + save = reginput; 1572 | + 1573 | + if (regmatch(next)) { 1574 | + /* 1575 | + * Don't set startp if some later 1576 | + * invocation of the same parentheses 1577 | + * already has. 1578 | + */ 1579 | + if (regstartp[no] == NULL) 1580 | + regstartp[no] = save; 1581 | + return(1); 1582 | + } else 1583 | + return(0); 1584 | + } 1585 | + break; 1586 | + case CLOSE+1: 1587 | + case CLOSE+2: 1588 | + case CLOSE+3: 1589 | + case CLOSE+4: 1590 | + case CLOSE+5: 1591 | + case CLOSE+6: 1592 | + case CLOSE+7: 1593 | + case CLOSE+8: 1594 | + case CLOSE+9: 1595 | + { 1596 | + register int no; 1597 | + register char *save; 1598 | + 1599 | + no = OP(scan) - CLOSE; 1600 | + save = reginput; 1601 | + 1602 | + if (regmatch(next)) { 1603 | + /* 1604 | + * Don't set endp if some later 1605 | + * invocation of the same parentheses 1606 | + * already has. 1607 | + */ 1608 | + if (regendp[no] == NULL) 1609 | + regendp[no] = save; 1610 | + return(1); 1611 | + } else 1612 | + return(0); 1613 | + } 1614 | + break; 1615 | + case BRANCH: { 1616 | + register char *save; 1617 | + 1618 | + if (OP(next) != BRANCH) /* No choice. */ 1619 | + next = OPERAND(scan); /* Avoid recursion. */ 1620 | + else { 1621 | + do { 1622 | + save = reginput; 1623 | + if (regmatch(OPERAND(scan))) 1624 | + return(1); 1625 | + reginput = save; 1626 | + scan = regnext(scan); 1627 | + } while (scan != NULL && OP(scan) == BRANCH); 1628 | + return(0); 1629 | + /* NOTREACHED */ 1630 | + } 1631 | + } 1632 | + break; 1633 | + case STAR: 1634 | + case PLUS: { 1635 | + register char nextch; 1636 | + register int no; 1637 | + register char *save; 1638 | + register int min; 1639 | + 1640 | + /* 1641 | + * Lookahead to avoid useless match attempts 1642 | + * when we know what character comes next. 1643 | + */ 1644 | + nextch = '\0'; 1645 | + if (OP(next) == EXACTLY) 1646 | + nextch = *OPERAND(next); 1647 | + min = (OP(scan) == STAR) ? 0 : 1; 1648 | + save = reginput; 1649 | + no = regrepeat(OPERAND(scan)); 1650 | + while (no >= min) { 1651 | + /* If it could work, try it. */ 1652 | + if (nextch == '\0' || *reginput == nextch) 1653 | + if (regmatch(next)) 1654 | + return(1); 1655 | + /* Couldn't or didn't -- back up. */ 1656 | + no--; 1657 | + reginput = save + no; 1658 | + } 1659 | + return(0); 1660 | + } 1661 | + break; 1662 | + case END: 1663 | + return(1); /* Success! */ 1664 | + break; 1665 | + default: 1666 | + printk("<3>Regexp: memory corruption\n"); 1667 | + return(0); 1668 | + break; 1669 | + } 1670 | + 1671 | + scan = next; 1672 | + } 1673 | + 1674 | + /* 1675 | + * We get here only if there's trouble -- normally "case END" is 1676 | + * the terminating point. 1677 | + */ 1678 | + printk("<3>Regexp: corrupted pointers\n"); 1679 | + return(0); 1680 | +} 1681 | + 1682 | +/* 1683 | + - regrepeat - repeatedly match something simple, report how many 1684 | + */ 1685 | +static int 1686 | +regrepeat(char *p) 1687 | +{ 1688 | + register int count = 0; 1689 | + register char *scan; 1690 | + register char *opnd; 1691 | + 1692 | + scan = reginput; 1693 | + opnd = OPERAND(p); 1694 | + switch (OP(p)) { 1695 | + case ANY: 1696 | + count = strlen(scan); 1697 | + scan += count; 1698 | + break; 1699 | + case EXACTLY: 1700 | + while (*opnd == *scan) { 1701 | + count++; 1702 | + scan++; 1703 | + } 1704 | + break; 1705 | + case ANYOF: 1706 | + while (*scan != '\0' && strchr(opnd, *scan) != NULL) { 1707 | + count++; 1708 | + scan++; 1709 | + } 1710 | + break; 1711 | + case ANYBUT: 1712 | + while (*scan != '\0' && strchr(opnd, *scan) == NULL) { 1713 | + count++; 1714 | + scan++; 1715 | + } 1716 | + break; 1717 | + default: /* Oh dear. Called inappropriately. */ 1718 | + printk("<3>Regexp: internal foulup\n"); 1719 | + count = 0; /* Best compromise. */ 1720 | + break; 1721 | + } 1722 | + reginput = scan; 1723 | + 1724 | + return(count); 1725 | +} 1726 | + 1727 | +/* 1728 | + - regnext - dig the "next" pointer out of a node 1729 | + */ 1730 | +static char* 1731 | +regnext(char *p) 1732 | +{ 1733 | + register int offset; 1734 | + 1735 | + if (p == ®dummy) 1736 | + return(NULL); 1737 | + 1738 | + offset = NEXT(p); 1739 | + if (offset == 0) 1740 | + return(NULL); 1741 | + 1742 | + if (OP(p) == BACK) 1743 | + return(p-offset); 1744 | + else 1745 | + return(p+offset); 1746 | +} 1747 | + 1748 | +#ifdef DEBUG 1749 | + 1750 | +STATIC char *regprop(); 1751 | + 1752 | +/* 1753 | + - regdump - dump a regexp onto stdout in vaguely comprehensible form 1754 | + */ 1755 | +void 1756 | +regdump(regexp *r) 1757 | +{ 1758 | + register char *s; 1759 | + register char op = EXACTLY; /* Arbitrary non-END op. */ 1760 | + register char *next; 1761 | + /* extern char *strchr(); */ 1762 | + 1763 | + 1764 | + s = r->program + 1; 1765 | + while (op != END) { /* While that wasn't END last time... */ 1766 | + op = OP(s); 1767 | + printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */ 1768 | + next = regnext(s); 1769 | + if (next == NULL) /* Next ptr. */ 1770 | + printf("(0)"); 1771 | + else 1772 | + printf("(%d)", (s-r->program)+(next-s)); 1773 | + s += 3; 1774 | + if (op == ANYOF || op == ANYBUT || op == EXACTLY) { 1775 | + /* Literal string, where present. */ 1776 | + while (*s != '\0') { 1777 | + putchar(*s); 1778 | + s++; 1779 | + } 1780 | + s++; 1781 | + } 1782 | + putchar('\n'); 1783 | + } 1784 | + 1785 | + /* Header fields of interest. */ 1786 | + if (r->regstart != '\0') 1787 | + printf("start `%c' ", r->regstart); 1788 | + if (r->reganch) 1789 | + printf("anchored "); 1790 | + if (r->regmust != NULL) 1791 | + printf("must have \"%s\"", r->regmust); 1792 | + printf("\n"); 1793 | +} 1794 | + 1795 | +/* 1796 | + - regprop - printable representation of opcode 1797 | + */ 1798 | +static char * 1799 | +regprop(char *op) 1800 | +{ 1801 | +#define BUFLEN 50 1802 | + register char *p; 1803 | + static char buf[BUFLEN]; 1804 | + 1805 | + strcpy(buf, ":"); 1806 | + 1807 | + switch (OP(op)) { 1808 | + case BOL: 1809 | + p = "BOL"; 1810 | + break; 1811 | + case EOL: 1812 | + p = "EOL"; 1813 | + break; 1814 | + case ANY: 1815 | + p = "ANY"; 1816 | + break; 1817 | + case ANYOF: 1818 | + p = "ANYOF"; 1819 | + break; 1820 | + case ANYBUT: 1821 | + p = "ANYBUT"; 1822 | + break; 1823 | + case BRANCH: 1824 | + p = "BRANCH"; 1825 | + break; 1826 | + case EXACTLY: 1827 | + p = "EXACTLY"; 1828 | + break; 1829 | + case NOTHING: 1830 | + p = "NOTHING"; 1831 | + break; 1832 | + case BACK: 1833 | + p = "BACK"; 1834 | + break; 1835 | + case END: 1836 | + p = "END"; 1837 | + break; 1838 | + case OPEN+1: 1839 | + case OPEN+2: 1840 | + case OPEN+3: 1841 | + case OPEN+4: 1842 | + case OPEN+5: 1843 | + case OPEN+6: 1844 | + case OPEN+7: 1845 | + case OPEN+8: 1846 | + case OPEN+9: 1847 | + snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "OPEN%d", OP(op)-OPEN); 1848 | + p = NULL; 1849 | + break; 1850 | + case CLOSE+1: 1851 | + case CLOSE+2: 1852 | + case CLOSE+3: 1853 | + case CLOSE+4: 1854 | + case CLOSE+5: 1855 | + case CLOSE+6: 1856 | + case CLOSE+7: 1857 | + case CLOSE+8: 1858 | + case CLOSE+9: 1859 | + snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "CLOSE%d", OP(op)-CLOSE); 1860 | + p = NULL; 1861 | + break; 1862 | + case STAR: 1863 | + p = "STAR"; 1864 | + break; 1865 | + case PLUS: 1866 | + p = "PLUS"; 1867 | + break; 1868 | + default: 1869 | + printk("<3>Regexp: corrupted opcode\n"); 1870 | + break; 1871 | + } 1872 | + if (p != NULL) 1873 | + strncat(buf, p, BUFLEN-strlen(buf)); 1874 | + return(buf); 1875 | +} 1876 | +#endif 1877 | + 1878 | + 1879 | --- linux-2.6.10-stock/net/ipv4/netfilter/regexp/regexp.h 1969-12-31 18:00:00.000000000 -0600 1880 | +++ linux-2.6.10-layer7/net/ipv4/netfilter/regexp/regexp.h 2005-01-07 13:24:01.000000000 -0600 1881 | @@ -0,0 +1,27 @@ 1882 | +/* 1883 | + * Definitions etc. for regexp(3) routines. 1884 | + * 1885 | + * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], 1886 | + * not the System V one. 1887 | + */ 1888 | + 1889 | +#ifndef REGEXP_H 1890 | +#define REGEXP_H 1891 | + 1892 | +#define NSUBEXP 10 1893 | +typedef struct regexp { 1894 | + char *startp[NSUBEXP]; 1895 | + char *endp[NSUBEXP]; 1896 | + char regstart; /* Internal use only. */ 1897 | + char reganch; /* Internal use only. */ 1898 | + char *regmust; /* Internal use only. */ 1899 | + int regmlen; /* Internal use only. */ 1900 | + char program[1]; /* Unwarranted chumminess with compiler. */ 1901 | +} regexp; 1902 | + 1903 | +regexp * regcomp(char *exp, int *patternsize); 1904 | +int regexec(regexp *prog, char *string); 1905 | +void regsub(regexp *prog, char *source, char *dest); 1906 | +void regerror(char *s); 1907 | + 1908 | +#endif 1909 | --- linux-2.6.10-stock/net/ipv4/netfilter/regexp/regmagic.h 1969-12-31 18:00:00.000000000 -0600 1910 | +++ linux-2.6.10-layer7/net/ipv4/netfilter/regexp/regmagic.h 2005-01-07 13:24:01.000000000 -0600 1911 | @@ -0,0 +1,5 @@ 1912 | +/* 1913 | + * The first byte of the regexp internal "program" is actually this magic 1914 | + * number; the start node begins in the second byte. 1915 | + */ 1916 | +#define MAGIC 0234 1917 | --- linux-2.6.10-stock/net/ipv4/netfilter/regexp/regsub.c 1969-12-31 18:00:00.000000000 -0600 1918 | +++ linux-2.6.10-layer7/net/ipv4/netfilter/regexp/regsub.c 2005-01-07 13:24:01.000000000 -0600 1919 | @@ -0,0 +1,95 @@ 1920 | +/* 1921 | + * regsub 1922 | + * @(#)regsub.c 1.3 of 2 April 86 1923 | + * 1924 | + * Copyright (c) 1986 by University of Toronto. 1925 | + * Written by Henry Spencer. Not derived from licensed software. 1926 | + * 1927 | + * Permission is granted to anyone to use this software for any 1928 | + * purpose on any computer system, and to redistribute it freely, 1929 | + * subject to the following restrictions: 1930 | + * 1931 | + * 1. The author is not responsible for the consequences of use of 1932 | + * this software, no matter how awful, even if they arise 1933 | + * from defects in it. 1934 | + * 1935 | + * 2. The origin of this software must not be misrepresented, either 1936 | + * by explicit claim or by omission. 1937 | + * 1938 | + * 3. Altered versions must be plainly marked as such, and must not 1939 | + * be misrepresented as being the original software. 1940 | + * 1941 | + * 1942 | + * This code was modified by Ethan Sommer to work within the kernel 1943 | + * (it now uses kmalloc etc..) 1944 | + * 1945 | + */ 1946 | +#include "regexp.h" 1947 | +#include "regmagic.h" 1948 | +#include 1949 | + 1950 | + 1951 | +#ifndef CHARBITS 1952 | +#define UCHARAT(p) ((int)*(unsigned char *)(p)) 1953 | +#else 1954 | +#define UCHARAT(p) ((int)*(p)&CHARBITS) 1955 | +#endif 1956 | + 1957 | +#if 0 1958 | +//void regerror(char * s) 1959 | +//{ 1960 | +// printk("regexp(3): %s", s); 1961 | +// /* NOTREACHED */ 1962 | +//} 1963 | +#endif 1964 | + 1965 | +/* 1966 | + - regsub - perform substitutions after a regexp match 1967 | + */ 1968 | +void 1969 | +regsub(regexp * prog, char * source, char * dest) 1970 | +{ 1971 | + register char *src; 1972 | + register char *dst; 1973 | + register char c; 1974 | + register int no; 1975 | + register int len; 1976 | + 1977 | + /* Not necessary and gcc doesn't like it -MLS */ 1978 | + /*extern char *strncpy();*/ 1979 | + 1980 | + if (prog == NULL || source == NULL || dest == NULL) { 1981 | + regerror("NULL parm to regsub"); 1982 | + return; 1983 | + } 1984 | + if (UCHARAT(prog->program) != MAGIC) { 1985 | + regerror("damaged regexp fed to regsub"); 1986 | + return; 1987 | + } 1988 | + 1989 | + src = source; 1990 | + dst = dest; 1991 | + while ((c = *src++) != '\0') { 1992 | + if (c == '&') 1993 | + no = 0; 1994 | + else if (c == '\\' && '0' <= *src && *src <= '9') 1995 | + no = *src++ - '0'; 1996 | + else 1997 | + no = -1; 1998 | + 1999 | + if (no < 0) { /* Ordinary character. */ 2000 | + if (c == '\\' && (*src == '\\' || *src == '&')) 2001 | + c = *src++; 2002 | + *dst++ = c; 2003 | + } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) { 2004 | + len = prog->endp[no] - prog->startp[no]; 2005 | + (void) strncpy(dst, prog->startp[no], len); 2006 | + dst += len; 2007 | + if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */ 2008 | + regerror("damaged match string"); 2009 | + return; 2010 | + } 2011 | + } 2012 | + } 2013 | + *dst++ = '\0'; 2014 | +} 2015 | -------------------------------------------------------------------------------- /iptables-1.4.3forward-for-kernel-2.6.20forward/libxt_layer7.c: -------------------------------------------------------------------------------- 1 | /* 2 | Shared library add-on to iptables for layer 7 matching support. 3 | 4 | By Matthew Strait , Oct 2003-Aug 2008. 5 | 6 | http://l7-filter.sf.net 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 11 | 2 of the License, or (at your option) any later version. 12 | http://www.gnu.org/licenses/gpl.txt 13 | */ 14 | 15 | #define _GNU_SOURCE 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #define MAX_FN_LEN 256 28 | 29 | static char l7dir[MAX_FN_LEN] = "\0"; 30 | 31 | /* Function which prints out usage message. */ 32 | static void help(void) 33 | { 34 | printf( 35 | "layer7 match options:\n" 36 | " --l7dir : Look for patterns here instead of /etc/l7-protocols/\n" 37 | " (--l7dir must be specified before --l7proto if used)\n" 38 | "[!] --l7proto : Match named protocol using /etc/l7-protocols/.../name.pat\n"); 39 | } 40 | 41 | static const struct option opts[] = { 42 | { .name = "l7proto", .has_arg = 1, .val = 'p' }, 43 | { .name = "l7dir", .has_arg = 1, .val = 'd' }, 44 | { .name = NULL } 45 | }; 46 | 47 | /* reads filename, puts protocol info into layer7_protocol_info, number of protocols to numprotos */ 48 | static int parse_protocol_file(char * filename, const char * protoname, struct xt_layer7_info *info) 49 | { 50 | FILE * f; 51 | char * line = NULL; 52 | size_t len = 0; 53 | 54 | enum { protocol, pattern, done } datatype = protocol; 55 | 56 | f = fopen(filename, "r"); 57 | 58 | if(!f) 59 | return 0; 60 | 61 | while(getline(&line, &len, f) != -1) 62 | { 63 | if(strlen(line) < 2 || line[0] == '#') 64 | continue; 65 | 66 | /* strip the pesky newline... */ 67 | if(line[strlen(line) - 1] == '\n') 68 | line[strlen(line) - 1] = '\0'; 69 | 70 | if(datatype == protocol) 71 | { 72 | /* Ignore everything on the line beginning with the 73 | first space or tab . For instance, this allows the 74 | protocol line in http.pat to be "http " (or 75 | "http I am so cool") instead of just "http". */ 76 | if(strchr(line, ' ')){ 77 | char * space = strchr(line, ' '); 78 | space[0] = '\0'; 79 | } 80 | if(strchr(line, '\t')){ 81 | char * space = strchr(line, '\t'); 82 | space[0] = '\0'; 83 | } 84 | 85 | /* sanity check. First non-comment non-blank 86 | line must be the same as the file name. */ 87 | if(strcmp(line, protoname)) 88 | xtables_error(OTHER_PROBLEM, 89 | "Protocol name (%s) doesn't match file name (%s). Bailing out\n", 90 | line, filename); 91 | 92 | if(strlen(line) >= MAX_PROTOCOL_LEN) 93 | xtables_error(PARAMETER_PROBLEM, 94 | "Protocol name in %s too long!", filename); 95 | strncpy(info->protocol, line, MAX_PROTOCOL_LEN); 96 | 97 | datatype = pattern; 98 | } 99 | else if(datatype == pattern) 100 | { 101 | if(strlen(line) >= MAX_PATTERN_LEN) 102 | xtables_error(PARAMETER_PROBLEM, "Pattern in %s too long!", filename); 103 | strncpy(info->pattern, line, MAX_PATTERN_LEN); 104 | 105 | datatype = done; 106 | break; 107 | } 108 | else 109 | xtables_error(OTHER_PROBLEM, "Internal error"); 110 | } 111 | 112 | if(datatype != done) 113 | xtables_error(OTHER_PROBLEM, "Failed to get all needed data from %s", filename); 114 | 115 | if(line) free(line); 116 | fclose(f); 117 | 118 | return 1; 119 | } 120 | 121 | static int hex2dec(char c) 122 | { 123 | switch (c) 124 | { 125 | case '0' ... '9': 126 | return c - '0'; 127 | case 'a' ... 'f': 128 | return c - 'a' + 10; 129 | case 'A' ... 'F': 130 | return c - 'A' + 10; 131 | default: 132 | xtables_error(OTHER_PROBLEM, "hex2dec: bad value!\n"); 133 | return 0; 134 | } 135 | } 136 | 137 | /* takes a string with \xHH escapes and returns one with the characters 138 | they stand for */ 139 | static char * pre_process(char * s) 140 | { 141 | char * result = malloc(strlen(s) + 1); 142 | int sindex = 0, rrindex = 0; 143 | while( sindex < strlen(s) ) 144 | { 145 | if( sindex + 3 < strlen(s) && 146 | s[sindex] == '\\' && s[sindex+1] == 'x' && 147 | isxdigit(s[sindex + 2]) && isxdigit(s[sindex + 3]) ) 148 | { 149 | /* carefully remember to call tolower here... */ 150 | result[rrindex] = tolower( hex2dec(s[sindex + 2])*16 + 151 | hex2dec(s[sindex + 3] ) ); 152 | 153 | switch ( result[rrindex] ) 154 | { 155 | case 0x24: 156 | case 0x28: 157 | case 0x29: 158 | case 0x2a: 159 | case 0x2b: 160 | case 0x2e: 161 | case 0x3f: 162 | case 0x5b: 163 | case 0x5c: 164 | case 0x5d: 165 | case 0x5e: 166 | case 0x7c: 167 | fprintf(stderr, 168 | "Warning: layer7 regexp contains a control character, %c, in hex (\\x%c%c).\n" 169 | "I recommend that you write this as %c or \\%c, depending on what you meant.\n", 170 | result[rrindex], s[sindex + 2], s[sindex + 3], result[rrindex], result[rrindex]); 171 | break; 172 | case 0x00: 173 | fprintf(stderr, 174 | "Warning: null (\\x00) in layer7 regexp. A null terminates the regexp string!\n"); 175 | break; 176 | default: 177 | break; 178 | } 179 | 180 | 181 | sindex += 3; /* 4 total */ 182 | } 183 | else 184 | result[rrindex] = tolower(s[sindex]); 185 | 186 | sindex++; 187 | rrindex++; 188 | } 189 | result[rrindex] = '\0'; 190 | 191 | return result; 192 | } 193 | 194 | #define MAX_SUBDIRS 128 195 | static char ** readl7dir(char * dirname) 196 | { 197 | DIR * scratchdir; 198 | struct dirent ** namelist; 199 | char ** subdirs = malloc(MAX_SUBDIRS * sizeof(char *)); 200 | 201 | int n, d = 1; 202 | subdirs[0] = ""; 203 | 204 | n = scandir(dirname, &namelist, 0, alphasort); 205 | 206 | if (n < 0) 207 | { 208 | perror("scandir"); 209 | xtables_error(OTHER_PROBLEM, "Couldn't open %s\n", dirname); 210 | } 211 | else 212 | { 213 | while(n--) 214 | { 215 | char fulldirname[MAX_FN_LEN]; 216 | 217 | snprintf(fulldirname, MAX_FN_LEN, "%s/%s", dirname, namelist[n]->d_name); 218 | 219 | if((scratchdir = opendir(fulldirname)) != NULL) 220 | { 221 | closedir(scratchdir); 222 | 223 | if(!strcmp(namelist[n]->d_name, ".") || 224 | !strcmp(namelist[n]->d_name, "..")) 225 | /* do nothing */ ; 226 | else 227 | { 228 | subdirs[d] = malloc(strlen(namelist[n]->d_name) + 1); 229 | strcpy(subdirs[d], namelist[n]->d_name); 230 | d++; 231 | if(d >= MAX_SUBDIRS - 1) 232 | { 233 | fprintf(stderr, 234 | "Too many subdirectories, skipping the rest!\n"); 235 | break; 236 | } 237 | } 238 | } 239 | free(namelist[n]); 240 | } 241 | free(namelist); 242 | } 243 | 244 | subdirs[d] = NULL; 245 | 246 | return subdirs; 247 | } 248 | 249 | static void parse_layer7_protocol(const char *s, struct xt_layer7_info *info) 250 | { 251 | char filename[MAX_FN_LEN]; 252 | char * dir = NULL; 253 | char ** subdirs; 254 | int n = 0, done = 0; 255 | 256 | if(strlen(l7dir) > 0) dir = l7dir; 257 | else dir = "/etc/l7-protocols"; 258 | 259 | subdirs = readl7dir(dir); 260 | 261 | while(subdirs[n] != NULL) 262 | { 263 | int c = snprintf(filename, MAX_FN_LEN, "%s/%s/%s.pat", dir, subdirs[n], s); 264 | 265 | if(c > MAX_FN_LEN) 266 | xtables_error(OTHER_PROBLEM, 267 | "Filename beginning with %s is too long!\n", filename); 268 | 269 | /* read in the pattern from the file */ 270 | if(parse_protocol_file(filename, s, info)){ 271 | done = 1; 272 | break; 273 | } 274 | 275 | n++; 276 | } 277 | 278 | if(!done) 279 | xtables_error(OTHER_PROBLEM, 280 | "Couldn't find a pattern definition file for %s.\n", s); 281 | 282 | /* process \xHH escapes and tolower everything. (our regex lib has no 283 | case insensitivity option.) */ 284 | strncpy(info->pattern, pre_process(info->pattern), MAX_PATTERN_LEN); 285 | } 286 | 287 | /* Function which parses command options; returns true if it ate an option */ 288 | static int parse(int c, char **argv, int invert, unsigned int *flags, 289 | const void *entry, struct xt_entry_match **match) 290 | { 291 | struct xt_layer7_info *layer7info = 292 | (struct xt_layer7_info *)(*match)->data; 293 | 294 | switch (c) { 295 | case 'p': 296 | parse_layer7_protocol(argv[optind-1], layer7info); 297 | if (invert) 298 | layer7info->invert = true; 299 | *flags = 1; 300 | break; 301 | 302 | case 'd': 303 | if(strlen(argv[optind-1]) >= MAX_FN_LEN) 304 | xtables_error(PARAMETER_PROBLEM, "directory name too long\n"); 305 | 306 | strncpy(l7dir, argv[optind-1], MAX_FN_LEN); 307 | 308 | *flags = 1; 309 | break; 310 | 311 | default: 312 | return 0; 313 | } 314 | 315 | return 1; 316 | } 317 | 318 | /* Final check; must have specified --l7proto */ 319 | static void final_check(unsigned int flags) 320 | { 321 | if (!flags) 322 | xtables_error(PARAMETER_PROBLEM, 323 | "LAYER7 match: You must specify `--l7proto'"); 324 | } 325 | 326 | static void print_protocol(char s[], int invert, int numeric) 327 | { 328 | fputs("l7proto ", stdout); 329 | if (invert) fputc('!', stdout); 330 | printf("%s ", s); 331 | } 332 | 333 | /* Prints out the matchinfo. */ 334 | static void print(const void *ip, 335 | const struct xt_entry_match *match, 336 | int numeric) 337 | { 338 | printf("LAYER7 "); 339 | print_protocol(((struct xt_layer7_info *)match->data)->protocol, 340 | ((struct xt_layer7_info *)match->data)->invert, numeric); 341 | } 342 | /* Saves the union ipt_matchinfo in parsable form to stdout. */ 343 | static void save(const void *ip, const struct xt_entry_match *match) 344 | { 345 | const struct xt_layer7_info *info = 346 | (const struct xt_layer7_info*) match->data; 347 | 348 | printf("--l7proto %s%s ", (info->invert)? "! ":"", info->protocol); 349 | } 350 | 351 | static struct xtables_match layer7 = { 352 | .family = AF_INET, 353 | .name = "layer7", 354 | .version = XTABLES_VERSION, 355 | .size = XT_ALIGN(sizeof(struct xt_layer7_info)), 356 | .userspacesize = XT_ALIGN(sizeof(struct xt_layer7_info)), 357 | .help = &help, 358 | .parse = &parse, 359 | .final_check = &final_check, 360 | .print = &print, 361 | .save = &save, 362 | .extra_opts = opts 363 | }; 364 | 365 | void _init(void) 366 | { 367 | xtables_register_match(&layer7); 368 | } 369 | -------------------------------------------------------------------------------- /iptables-1.4.3forward-for-kernel-2.6.20forward/libxt_layer7.man: -------------------------------------------------------------------------------- 1 | This module matches packets based on the application layer data of 2 | their connections. It uses regular expression matching to compare 3 | the application layer data to regular expressions found it the layer7 4 | configuration files. This is an experimental module which can be found at 5 | http://l7-filter.sf.net. It takes two options. 6 | .TP 7 | .BI "--l7proto " "\fIprotocol\fP" 8 | Match the specified protocol. The protocol name must match a file 9 | name in /etc/l7-protocols/ or one of its first-level child directories. 10 | .TP 11 | .BI "--l7dir " "\fIdirectory\fP" 12 | Use \fIdirectory\fP instead of /etc/l7-protocols/. This option must be 13 | specified before --l7proto. 14 | 15 | --------------------------------------------------------------------------------