002-layer7_2.17.patch 11 KB

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