002-layer7_2.22.patch 9.6 KB

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