1 /* Shared library add-on to iptables to add string matching support.
3 * Copyright (C) 2000 Emmanuel Roger <winfield@freegates.be>
6 * 29.12.2003: Michael Rash <mbr@cipherdyne.org>
7 * Fixed iptables save/restore for ascii strings
8 * that contain space chars, and hex strings that
9 * contain embedded NULL chars. Updated to print
10 * strings in hex mode if any non-printable char
11 * is contained within the string.
13 * 27.01.2001: Gianni Tedesco <gianni@ecsc.co.uk>
14 * Changed --tos to --string in save(). Also
15 * updated to work with slightly modified
26 #include <linux/netfilter_ipv4/ipt_string.h>
29 /* Function which prints out usage message. */
34 "STRING match v%s options:\n"
35 "--string [!] string Match a string in a packet\n"
36 "--hex-string [!] string Match a hex string in a packet\n",
41 static struct option opts[] = {
42 { .name = "string", .has_arg = 1, .flag = 0, .val = '1' },
43 { .name = "hex-string", .has_arg = 1, .flag = 0, .val = '2' },
48 parse_string(const unsigned char *s, struct ipt_string_info *info)
50 if (strlen(s) <= BM_MAX_NLEN) strcpy(info->string, s);
51 else exit_error(PARAMETER_PROBLEM, "STRING too long `%s'", s);
56 parse_hex_string(const unsigned char *s, struct ipt_string_info *info)
58 int i=0, slen, sindex=0, schar;
59 short hex_f = 0, literal_f = 0;
65 exit_error(PARAMETER_PROBLEM,
66 "STRING must contain at least one char");
70 if (s[i] == '\\' && !hex_f) {
72 } else if (s[i] == '\\') {
73 exit_error(PARAMETER_PROBLEM,
74 "Cannot include literals in hex data");
75 } else if (s[i] == '|') {
80 /* get past any initial whitespace just after the '|' */
87 i++; /* advance to the next character */
92 exit_error(PARAMETER_PROBLEM,
93 "Bad literal placement at end of string");
95 info->string[sindex] = s[i+1];
96 i += 2; /* skip over literal char */
100 exit_error(PARAMETER_PROBLEM,
101 "Odd number of hex digits");
104 /* must end with a "|" */
105 exit_error(PARAMETER_PROBLEM, "Invalid hex block");
107 if (! isxdigit(s[i])) /* check for valid hex char */
108 exit_error(PARAMETER_PROBLEM, "Invalid hex char `%c'", s[i]);
109 if (! isxdigit(s[i+1])) /* check for valid hex char */
110 exit_error(PARAMETER_PROBLEM, "Invalid hex char `%c'", s[i+1]);
114 if (! sscanf(hextmp, "%x", &schar))
115 exit_error(PARAMETER_PROBLEM,
116 "Invalid hex char `%c'", s[i]);
117 info->string[sindex] = (char) schar;
119 i += 3; /* spaces included in the hex block */
122 } else { /* the char is not part of hex data, so just copy */
123 info->string[sindex] = s[i];
126 if (sindex > BM_MAX_NLEN)
127 exit_error(PARAMETER_PROBLEM, "STRING too long `%s'", s);
134 /* Function which parses command options; returns true if it
137 parse(int c, char **argv, int invert, unsigned int *flags,
138 const struct ipt_entry *entry,
139 unsigned int *nfcache,
140 struct ipt_entry_match **match)
142 struct ipt_string_info *stringinfo = (struct ipt_string_info *)(*match)->data;
147 exit_error(PARAMETER_PROBLEM,
148 "Can't specify multiple strings");
150 check_inverse(optarg, &invert, &optind, 0);
151 parse_string(argv[optind-1], stringinfo);
153 stringinfo->invert = 1;
154 stringinfo->len=strlen((char *)&stringinfo->string);
160 exit_error(PARAMETER_PROBLEM,
161 "Can't specify multiple strings");
163 check_inverse(optarg, &invert, &optind, 0);
164 parse_hex_string(argv[optind-1], stringinfo); /* sets length */
166 stringinfo->invert = 1;
177 /* Final check; must have specified --string. */
179 final_check(unsigned int flags)
182 exit_error(PARAMETER_PROBLEM,
183 "STRING match: You must specify `--string' or `--hex-string'");
186 /* Test to see if the string contains non-printable chars or quotes */
187 static unsigned short int
188 is_hex_string(const char *str, const unsigned short int len)
191 for (i=0; i < len; i++)
192 if (! isprint(str[i]))
193 return 1; /* string contains at least one non-printable char */
194 /* use hex output if the last char is a "\" */
195 if ((unsigned char) str[len-1] == 0x5c)
200 /* Print string with "|" chars included as one would pass to --hex-string */
202 print_hex_string(const char *str, const unsigned short int len)
205 /* start hex block */
207 for (i=0; i < len; i++) {
208 /* see if we need to prepend a zero */
209 if ((unsigned char) str[i] <= 0x0F)
210 printf("0%x", (unsigned char) str[i]);
212 printf("%x", (unsigned char) str[i]);
214 /* close hex block */
219 print_string(const char *str, const unsigned short int len)
223 for (i=0; i < len; i++) {
224 if ((unsigned char) str[i] == 0x22) /* escape any embedded quotes */
226 printf("%c", (unsigned char) str[i]);
228 printf("\" "); /* closing space and quote */
231 /* Prints out the matchinfo. */
233 print(const struct ipt_ip *ip,
234 const struct ipt_entry_match *match,
237 const struct ipt_string_info *info =
238 (const struct ipt_string_info*) match->data;
240 if (is_hex_string(info->string, info->len)) {
241 printf("STRING match %s", (info->invert) ? "!" : "");
242 print_hex_string(info->string, info->len);
244 printf("STRING match %s", (info->invert) ? "!" : "");
245 print_string(info->string, info->len);
250 /* Saves the union ipt_matchinfo in parseable form to stdout. */
252 save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
254 const struct ipt_string_info *info =
255 (const struct ipt_string_info*) match->data;
257 if (is_hex_string(info->string, info->len)) {
258 printf("--hex-string %s", (info->invert) ? "! ": "");
259 print_hex_string(info->string, info->len);
261 printf("--string %s", (info->invert) ? "! ": "");
262 print_string(info->string, info->len);
267 static struct iptables_match string = {
269 .version = IPTABLES_VERSION,
270 .size = IPT_ALIGN(sizeof(struct ipt_string_info)),
271 .userspacesize = IPT_ALIGN(sizeof(struct ipt_string_info)),
274 .final_check = &final_check,
283 register_match(&string);