blob: c17cd23a92ac137ef6bed10efdd9995fa9ec608a [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* Shared library add-on to iptables to add string matching support.
2 *
3 * Copyright (C) 2000 Emmanuel Roger <winfield@freegates.be>
4 *
5 * ChangeLog
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.
12 *
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
16 * ipt_string_info.
17 */
18#include <stdio.h>
19#include <netdb.h>
20#include <string.h>
21#include <stdlib.h>
22#include <getopt.h>
23#include <ctype.h>
24
25#include <xtables.h>
26#include <linux/netfilter_ipv4/ipt_string.h>
27
28
29static void
30help(void)
31{
32 printf(
33"STRING match options:\n"
34"--string [!] string Match a string in a packet\n"
35"--hex-string [!] string Match a hex string in a packet\n");
36}
37
38
39static struct option opts[] = {
40 { .name = "string", .has_arg = 1, .flag = 0, .val = '1' },
41 { .name = "hex-string", .has_arg = 1, .flag = 0, .val = '2' },
42 { .name = NULL }
43};
44
45
46static void
47init(struct xt_entry_match *m)
48{
49}
50
51
52static void
53parse_string(const char *s, struct ipt_string_info *info)
54{
55 if (strlen(s) <= BM_MAX_NLEN) strcpy(info->string, s);
56 else xtables_error(PARAMETER_PROBLEM, "STRING too long `%s'", s);
57}
58
59
60static void
61parse_hex_string(const char *s, struct ipt_string_info *info)
62{
63 int i=0, slen, sindex=0, schar;
64 short hex_f = 0, literal_f = 0;
65 char hextmp[3];
66
67 slen = strlen(s);
68
69 if (slen == 0) {
70 xtables_error(PARAMETER_PROBLEM,
71 "STRING must contain at least one char");
72 }
73
74 while (i < slen) {
75 if (s[i] == '\\' && !hex_f) {
76 literal_f = 1;
77 } else if (s[i] == '\\') {
78 xtables_error(PARAMETER_PROBLEM,
79 "Cannot include literals in hex data");
80 } else if (s[i] == '|') {
81 if (hex_f)
82 hex_f = 0;
83 else {
84 hex_f = 1;
85 /* get past any initial whitespace just after the '|' */
86 while (s[i+1] == ' ')
87 i++;
88 }
89 if (i+1 >= slen)
90 break;
91 else
92 i++; /* advance to the next character */
93 }
94
95 if (literal_f) {
96 if (i+1 >= slen) {
97 xtables_error(PARAMETER_PROBLEM,
98 "Bad literal placement at end of string");
99 }
100 info->string[sindex] = s[i+1];
101 i += 2; /* skip over literal char */
102 literal_f = 0;
103 } else if (hex_f) {
104 if (i+1 >= slen) {
105 xtables_error(PARAMETER_PROBLEM,
106 "Odd number of hex digits");
107 }
108 if (i+2 >= slen) {
109 /* must end with a "|" */
110 xtables_error(PARAMETER_PROBLEM, "Invalid hex block");
111 }
112 if (! isxdigit(s[i])) /* check for valid hex char */
113 xtables_error(PARAMETER_PROBLEM, "Invalid hex char `%c'", s[i]);
114 if (! isxdigit(s[i+1])) /* check for valid hex char */
115 xtables_error(PARAMETER_PROBLEM, "Invalid hex char `%c'", s[i+1]);
116 hextmp[0] = s[i];
117 hextmp[1] = s[i+1];
118 hextmp[2] = '\0';
119 if (! sscanf(hextmp, "%x", &schar))
120 xtables_error(PARAMETER_PROBLEM,
121 "Invalid hex char `%c'", s[i]);
122 info->string[sindex] = (char) schar;
123 if (s[i+2] == ' ')
124 i += 3; /* spaces included in the hex block */
125 else
126 i += 2;
127 } else { /* the char is not part of hex data, so just copy */
128 info->string[sindex] = s[i];
129 i++;
130 }
131 if (sindex > BM_MAX_NLEN)
132 xtables_error(PARAMETER_PROBLEM, "STRING too long `%s'", s);
133 sindex++;
134 }
135 info->len = sindex;
136}
137
138
139/* Function which parses command options; returns true if it
140 ate an option */
141static int
142parse(int c, char **argv, int invert, unsigned int *flags,
143 const void *entry, struct xt_entry_match **match)
144{
145 struct ipt_string_info *stringinfo = (struct ipt_string_info *)(*match)->data;
146
147 switch (c) {
148 case '1':
149 if (*flags)
150 xtables_error(PARAMETER_PROBLEM,
151 "Can't specify multiple strings");
152
153 xtables_check_inverse(optarg, &invert, &optind, 0);
154 parse_string(argv[optind-1], stringinfo);
155 if (invert)
156 stringinfo->invert = 1;
157 stringinfo->len=strlen((char *)&stringinfo->string);
158 *flags = 1;
159 break;
160
161 case '2':
162 if (*flags)
163 xtables_error(PARAMETER_PROBLEM,
164 "Can't specify multiple strings");
165
166 xtables_check_inverse(optarg, &invert, &optind, 0);
167 parse_hex_string(argv[optind-1], stringinfo); /* sets length */
168 if (invert)
169 stringinfo->invert = 1;
170 *flags = 1;
171 break;
172
173 default:
174 return 0;
175 }
176 return 1;
177}
178
179
180/* Final check; must have specified --string. */
181static void
182final_check(unsigned int flags)
183{
184 if (!flags)
185 xtables_error(PARAMETER_PROBLEM,
186 "STRING match: You must specify `--string' or `--hex-string'");
187}
188
189/* Test to see if the string contains non-printable chars or quotes */
190static unsigned short int
191is_hex_string(const char *str, const unsigned short int len)
192{
193 unsigned int i;
194 for (i=0; i < len; i++)
195 if (! isprint(str[i]))
196 return 1; /* string contains at least one non-printable char */
197 /* use hex output if the last char is a "\" */
198 if ((unsigned char) str[len-1] == 0x5c)
199 return 1;
200 return 0;
201}
202
203/* Print string with "|" chars included as one would pass to --hex-string */
204static void
205print_hex_string(const char *str, const unsigned short int len)
206{
207 unsigned int i;
208 /* start hex block */
209 printf("\"|");
210 for (i=0; i < len; i++) {
211 /* see if we need to prepend a zero */
212 if ((unsigned char) str[i] <= 0x0F)
213 printf("0%x", (unsigned char) str[i]);
214 else
215 printf("%x", (unsigned char) str[i]);
216 }
217 /* close hex block */
218 printf("|\" ");
219}
220
221static void
222print_string(const char *str, const unsigned short int len)
223{
224 unsigned int i;
225 printf("\"");
226 for (i=0; i < len; i++) {
227 if ((unsigned char) str[i] == 0x22) /* escape any embedded quotes */
228 printf("%c", 0x5c);
229 printf("%c", (unsigned char) str[i]);
230 }
231 printf("\" "); /* closing space and quote */
232}
233
234/* Prints out the matchinfo. */
235static void
236print(const void *ip,
237 const struct xt_entry_match *match,
238 int numeric)
239{
240 const struct ipt_string_info *info =
241 (const struct ipt_string_info*) match->data;
242
243 if (is_hex_string(info->string, info->len)) {
244 printf("STRING match %s", (info->invert) ? "!" : "");
245 print_hex_string(info->string, info->len);
246 } else {
247 printf("STRING match %s", (info->invert) ? "!" : "");
248 print_string(info->string, info->len);
249 }
250}
251
252
253/* Saves the union ipt_matchinfo in parseable form to stdout. */
254static void
255save(const void *ip, const struct xt_entry_match *match)
256{
257 const struct ipt_string_info *info =
258 (const struct ipt_string_info*) match->data;
259
260 if (is_hex_string(info->string, info->len)) {
261 printf("--hex-string %s", (info->invert) ? "! ": "");
262 print_hex_string(info->string, info->len);
263 } else {
264 printf("--string %s", (info->invert) ? "! ": "");
265 print_string(info->string, info->len);
266 }
267}
268
269
270static struct xtables_match string = {
271 .name = "string",
272 .version = XTABLES_VERSION,
273 .family = NFPROTO_IPV4,
274 .size = XT_ALIGN(sizeof(struct ipt_string_info)),
275 .userspacesize = XT_ALIGN(sizeof(struct ipt_string_info)),
276 .help = &help,
277 .init = &init,
278 .parse = &parse,
279 .final_check = &final_check,
280 .print = &print,
281 .save = &save,
282 .extra_opts = opts
283};
284
285
286void _init(void)
287{
288 xtables_register_match(&string);
289}