1 /* Shared library add-on to iptables to add string matching support.
3 * Copyright (C) 2000 Emmanuel Roger <winfield@freegates.be>
5 * 2005-08-05 Pablo Neira Ayuso <pablo@eurodev.net>
6 * - reimplemented to use new string matching iptables match
7 * - add functionality to match packets by using window offsets
8 * - add functionality to select the string matching algorithm
11 * 29.12.2003: Michael Rash <mbr@cipherdyne.org>
12 * Fixed iptables save/restore for ascii strings
13 * that contain space chars, and hex strings that
14 * contain embedded NULL chars. Updated to print
15 * strings in hex mode if any non-printable char
16 * is contained within the string.
18 * 27.01.2001: Gianni Tedesco <gianni@ecsc.co.uk>
19 * Changed --tos to --string in save(). Also
20 * updated to work with slightly modified
31 #include <linux/netfilter/xt_string.h>
33 /* Function which prints out usage message. */
34 static void string_help(void)
37 "string match options:\n"
38 "--from Offset to start searching from\n"
39 "--to Offset to stop searching\n"
41 "[!] --string string Match a string in a packet\n"
42 "[!] --hex-string string Match a hex string in a packet\n");
45 static const struct option string_opts[] = {
46 { "from", 1, NULL, '1' },
47 { "to", 1, NULL, '2' },
48 { "algo", 1, NULL, '3' },
49 { "string", 1, NULL, '4' },
50 { "hex-string", 1, NULL, '5' },
54 static void string_init(struct xt_entry_match *m)
56 struct xt_string_info *i = (struct xt_string_info *) m->data;
58 if (i->to_offset == 0)
59 i->to_offset = (u_int16_t) ~0UL;
63 parse_string(const char *s, struct xt_string_info *info)
65 if (strlen(s) <= XT_STRING_MAX_PATTERN_SIZE) {
66 strncpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE);
67 info->patlen = strlen(s);
70 exit_error(PARAMETER_PROBLEM, "STRING too long `%s'", s);
74 parse_algo(const char *s, struct xt_string_info *info)
76 if (strlen(s) <= XT_STRING_MAX_ALGO_NAME_SIZE) {
77 strncpy(info->algo, s, XT_STRING_MAX_ALGO_NAME_SIZE);
80 exit_error(PARAMETER_PROBLEM, "ALGO too long `%s'", s);
84 parse_hex_string(const char *s, struct xt_string_info *info)
86 int i=0, slen, sindex=0, schar;
87 short hex_f = 0, literal_f = 0;
93 exit_error(PARAMETER_PROBLEM,
94 "STRING must contain at least one char");
98 if (s[i] == '\\' && !hex_f) {
100 } else if (s[i] == '\\') {
101 exit_error(PARAMETER_PROBLEM,
102 "Cannot include literals in hex data");
103 } else if (s[i] == '|') {
108 /* get past any initial whitespace just after the '|' */
109 while (s[i+1] == ' ')
115 i++; /* advance to the next character */
120 exit_error(PARAMETER_PROBLEM,
121 "Bad literal placement at end of string");
123 info->pattern[sindex] = s[i+1];
124 i += 2; /* skip over literal char */
128 exit_error(PARAMETER_PROBLEM,
129 "Odd number of hex digits");
132 /* must end with a "|" */
133 exit_error(PARAMETER_PROBLEM, "Invalid hex block");
135 if (! isxdigit(s[i])) /* check for valid hex char */
136 exit_error(PARAMETER_PROBLEM, "Invalid hex char `%c'", s[i]);
137 if (! isxdigit(s[i+1])) /* check for valid hex char */
138 exit_error(PARAMETER_PROBLEM, "Invalid hex char `%c'", s[i+1]);
142 if (! sscanf(hextmp, "%x", &schar))
143 exit_error(PARAMETER_PROBLEM,
144 "Invalid hex char `%c'", s[i]);
145 info->pattern[sindex] = (char) schar;
147 i += 3; /* spaces included in the hex block */
150 } else { /* the char is not part of hex data, so just copy */
151 info->pattern[sindex] = s[i];
154 if (sindex > XT_STRING_MAX_PATTERN_SIZE)
155 exit_error(PARAMETER_PROBLEM, "STRING too long `%s'", s);
158 info->patlen = sindex;
166 /* Function which parses command options; returns true if it
169 string_parse(int c, char **argv, int invert, unsigned int *flags,
170 const void *entry, struct xt_entry_match **match)
172 struct xt_string_info *stringinfo = (struct xt_string_info *)(*match)->data;
177 exit_error(PARAMETER_PROBLEM,
178 "Can't specify multiple --from");
179 stringinfo->from_offset = atoi(optarg);
184 exit_error(PARAMETER_PROBLEM,
185 "Can't specify multiple --to");
186 stringinfo->to_offset = atoi(optarg);
191 exit_error(PARAMETER_PROBLEM,
192 "Can't specify multiple --algo");
193 parse_algo(optarg, stringinfo);
198 exit_error(PARAMETER_PROBLEM,
199 "Can't specify multiple --string");
200 check_inverse(optarg, &invert, &optind, 0);
201 parse_string(argv[optind-1], stringinfo);
203 stringinfo->invert = 1;
204 stringinfo->patlen=strlen((char *)&stringinfo->pattern);
210 exit_error(PARAMETER_PROBLEM,
211 "Can't specify multiple --hex-string");
213 check_inverse(optarg, &invert, &optind, 0);
214 parse_hex_string(argv[optind-1], stringinfo); /* sets length */
216 stringinfo->invert = 1;
227 /* Final check; must have specified --string. */
228 static void string_check(unsigned int flags)
230 if (!(flags & STRING))
231 exit_error(PARAMETER_PROBLEM,
232 "STRING match: You must specify `--string' or "
235 exit_error(PARAMETER_PROBLEM,
236 "STRING match: You must specify `--algo'");
239 /* Test to see if the string contains non-printable chars or quotes */
240 static unsigned short int
241 is_hex_string(const char *str, const unsigned short int len)
244 for (i=0; i < len; i++)
245 if (! isprint(str[i]))
246 return 1; /* string contains at least one non-printable char */
247 /* use hex output if the last char is a "\" */
248 if ((unsigned char) str[len-1] == 0x5c)
253 /* Print string with "|" chars included as one would pass to --hex-string */
255 print_hex_string(const char *str, const unsigned short int len)
258 /* start hex block */
260 for (i=0; i < len; i++) {
261 /* see if we need to prepend a zero */
262 if ((unsigned char) str[i] <= 0x0F)
263 printf("0%x", (unsigned char) str[i]);
265 printf("%x", (unsigned char) str[i]);
267 /* close hex block */
272 print_string(const char *str, const unsigned short int len)
276 for (i=0; i < len; i++) {
277 if ((unsigned char) str[i] == 0x22) /* escape any embedded quotes */
279 printf("%c", (unsigned char) str[i]);
281 printf("\" "); /* closing space and quote */
284 /* Prints out the matchinfo. */
286 string_print(const void *ip, const struct xt_entry_match *match, int numeric)
288 const struct xt_string_info *info =
289 (const struct xt_string_info*) match->data;
291 if (is_hex_string(info->pattern, info->patlen)) {
292 printf("STRING match %s", (info->invert) ? "!" : "");
293 print_hex_string(info->pattern, info->patlen);
295 printf("STRING match %s", (info->invert) ? "!" : "");
296 print_string(info->pattern, info->patlen);
298 printf("ALGO name %s ", info->algo);
299 if (info->from_offset != 0)
300 printf("FROM %u ", info->from_offset);
301 if (info->to_offset != 0)
302 printf("TO %u ", info->to_offset);
306 /* Saves the union ipt_matchinfo in parseable form to stdout. */
307 static void string_save(const void *ip, const struct xt_entry_match *match)
309 const struct xt_string_info *info =
310 (const struct xt_string_info*) match->data;
312 if (is_hex_string(info->pattern, info->patlen)) {
313 printf("--hex-string %s", (info->invert) ? "! ": "");
314 print_hex_string(info->pattern, info->patlen);
316 printf("--string %s", (info->invert) ? "! ": "");
317 print_string(info->pattern, info->patlen);
319 printf("--algo %s ", info->algo);
320 if (info->from_offset != 0)
321 printf("--from %u ", info->from_offset);
322 if (info->to_offset != 0)
323 printf("--to %u ", info->to_offset);
327 static struct xtables_match string_match = {
330 .version = XTABLES_VERSION,
331 .size = XT_ALIGN(sizeof(struct xt_string_info)),
332 .userspacesize = offsetof(struct xt_string_info, config),
335 .parse = string_parse,
336 .final_check = string_check,
337 .print = string_print,
339 .extra_opts = string_opts,
344 xtables_register_match(&string_match);