xref: /aosp_15_r20/external/iptables/extensions/libxt_string.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
1*a71a9546SAutomerger Merge Worker /* Shared library add-on to iptables to add string matching support.
2*a71a9546SAutomerger Merge Worker  *
3*a71a9546SAutomerger Merge Worker  * Copyright (C) 2000 Emmanuel Roger  <[email protected]>
4*a71a9546SAutomerger Merge Worker  *
5*a71a9546SAutomerger Merge Worker  * 2005-08-05 Pablo Neira Ayuso <[email protected]>
6*a71a9546SAutomerger Merge Worker  * 	- reimplemented to use new string matching iptables match
7*a71a9546SAutomerger Merge Worker  * 	- add functionality to match packets by using window offsets
8*a71a9546SAutomerger Merge Worker  * 	- add functionality to select the string matching algorithm
9*a71a9546SAutomerger Merge Worker  *
10*a71a9546SAutomerger Merge Worker  * ChangeLog
11*a71a9546SAutomerger Merge Worker  *     29.12.2003: Michael Rash <[email protected]>
12*a71a9546SAutomerger Merge Worker  *             Fixed iptables save/restore for ascii strings
13*a71a9546SAutomerger Merge Worker  *             that contain space chars, and hex strings that
14*a71a9546SAutomerger Merge Worker  *             contain embedded NULL chars.  Updated to print
15*a71a9546SAutomerger Merge Worker  *             strings in hex mode if any non-printable char
16*a71a9546SAutomerger Merge Worker  *             is contained within the string.
17*a71a9546SAutomerger Merge Worker  *
18*a71a9546SAutomerger Merge Worker  *     27.01.2001: Gianni Tedesco <[email protected]>
19*a71a9546SAutomerger Merge Worker  *             Changed --tos to --string in save(). Also
20*a71a9546SAutomerger Merge Worker  *             updated to work with slightly modified
21*a71a9546SAutomerger Merge Worker  *             ipt_string_info.
22*a71a9546SAutomerger Merge Worker  */
23*a71a9546SAutomerger Merge Worker #define _GNU_SOURCE 1 /* strnlen for older glibcs */
24*a71a9546SAutomerger Merge Worker #include <stdio.h>
25*a71a9546SAutomerger Merge Worker #include <string.h>
26*a71a9546SAutomerger Merge Worker #include <stdlib.h>
27*a71a9546SAutomerger Merge Worker #include <ctype.h>
28*a71a9546SAutomerger Merge Worker #include <xtables.h>
29*a71a9546SAutomerger Merge Worker #include <linux/netfilter/xt_string.h>
30*a71a9546SAutomerger Merge Worker 
31*a71a9546SAutomerger Merge Worker enum {
32*a71a9546SAutomerger Merge Worker 	O_FROM = 0,
33*a71a9546SAutomerger Merge Worker 	O_TO,
34*a71a9546SAutomerger Merge Worker 	O_ALGO,
35*a71a9546SAutomerger Merge Worker 	O_ICASE,
36*a71a9546SAutomerger Merge Worker 	O_STRING,
37*a71a9546SAutomerger Merge Worker 	O_HEX_STRING,
38*a71a9546SAutomerger Merge Worker 	F_STRING     = 1 << O_STRING,
39*a71a9546SAutomerger Merge Worker 	F_HEX_STRING = 1 << O_HEX_STRING,
40*a71a9546SAutomerger Merge Worker 	F_OP_ANY     = F_STRING | F_HEX_STRING,
41*a71a9546SAutomerger Merge Worker };
42*a71a9546SAutomerger Merge Worker 
string_help(void)43*a71a9546SAutomerger Merge Worker static void string_help(void)
44*a71a9546SAutomerger Merge Worker {
45*a71a9546SAutomerger Merge Worker 	printf(
46*a71a9546SAutomerger Merge Worker "string match options:\n"
47*a71a9546SAutomerger Merge Worker "--from                       Offset to start searching from\n"
48*a71a9546SAutomerger Merge Worker "--to                         Offset to stop searching\n"
49*a71a9546SAutomerger Merge Worker "--algo                       Algorithm\n"
50*a71a9546SAutomerger Merge Worker "--icase                      Ignore case (default: 0)\n"
51*a71a9546SAutomerger Merge Worker "[!] --string string          Match a string in a packet\n"
52*a71a9546SAutomerger Merge Worker "[!] --hex-string string      Match a hex string in a packet\n");
53*a71a9546SAutomerger Merge Worker }
54*a71a9546SAutomerger Merge Worker 
55*a71a9546SAutomerger Merge Worker #define s struct xt_string_info
56*a71a9546SAutomerger Merge Worker static const struct xt_option_entry string_opts[] = {
57*a71a9546SAutomerger Merge Worker 	{.name = "from", .id = O_FROM, .type = XTTYPE_UINT16,
58*a71a9546SAutomerger Merge Worker 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, from_offset)},
59*a71a9546SAutomerger Merge Worker 	{.name = "to", .id = O_TO, .type = XTTYPE_UINT16,
60*a71a9546SAutomerger Merge Worker 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, to_offset)},
61*a71a9546SAutomerger Merge Worker 	{.name = "algo", .id = O_ALGO, .type = XTTYPE_STRING,
62*a71a9546SAutomerger Merge Worker 	 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, algo)},
63*a71a9546SAutomerger Merge Worker 	{.name = "string", .id = O_STRING, .type = XTTYPE_STRING,
64*a71a9546SAutomerger Merge Worker 	 .flags = XTOPT_INVERT, .excl = F_HEX_STRING},
65*a71a9546SAutomerger Merge Worker 	{.name = "hex-string", .id = O_HEX_STRING, .type = XTTYPE_STRING,
66*a71a9546SAutomerger Merge Worker 	 .flags = XTOPT_INVERT, .excl = F_STRING},
67*a71a9546SAutomerger Merge Worker 	{.name = "icase", .id = O_ICASE, .type = XTTYPE_NONE},
68*a71a9546SAutomerger Merge Worker 	XTOPT_TABLEEND,
69*a71a9546SAutomerger Merge Worker };
70*a71a9546SAutomerger Merge Worker #undef s
71*a71a9546SAutomerger Merge Worker 
string_init(struct xt_entry_match * m)72*a71a9546SAutomerger Merge Worker static void string_init(struct xt_entry_match *m)
73*a71a9546SAutomerger Merge Worker {
74*a71a9546SAutomerger Merge Worker 	struct xt_string_info *i = (struct xt_string_info *) m->data;
75*a71a9546SAutomerger Merge Worker 
76*a71a9546SAutomerger Merge Worker 	i->to_offset = UINT16_MAX;
77*a71a9546SAutomerger Merge Worker }
78*a71a9546SAutomerger Merge Worker 
79*a71a9546SAutomerger Merge Worker static void
parse_string(const char * s,struct xt_string_info * info)80*a71a9546SAutomerger Merge Worker parse_string(const char *s, struct xt_string_info *info)
81*a71a9546SAutomerger Merge Worker {
82*a71a9546SAutomerger Merge Worker 	/* xt_string does not need \0 at the end of the pattern */
83*a71a9546SAutomerger Merge Worker 	if (strlen(s) > sizeof(info->pattern))
84*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s);
85*a71a9546SAutomerger Merge Worker 
86*a71a9546SAutomerger Merge Worker 	info->patlen = strnlen(s, sizeof(info->pattern));
87*a71a9546SAutomerger Merge Worker 	memcpy(info->pattern, s, info->patlen);
88*a71a9546SAutomerger Merge Worker }
89*a71a9546SAutomerger Merge Worker 
90*a71a9546SAutomerger Merge Worker static void
parse_hex_string(const char * s,struct xt_string_info * info)91*a71a9546SAutomerger Merge Worker parse_hex_string(const char *s, struct xt_string_info *info)
92*a71a9546SAutomerger Merge Worker {
93*a71a9546SAutomerger Merge Worker 	int i=0, slen, sindex=0, schar;
94*a71a9546SAutomerger Merge Worker 	short hex_f = 0, literal_f = 0;
95*a71a9546SAutomerger Merge Worker 	char hextmp[3];
96*a71a9546SAutomerger Merge Worker 
97*a71a9546SAutomerger Merge Worker 	slen = strlen(s);
98*a71a9546SAutomerger Merge Worker 
99*a71a9546SAutomerger Merge Worker 	if (slen == 0) {
100*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM,
101*a71a9546SAutomerger Merge Worker 			"STRING must contain at least one char");
102*a71a9546SAutomerger Merge Worker 	}
103*a71a9546SAutomerger Merge Worker 
104*a71a9546SAutomerger Merge Worker 	while (i < slen) {
105*a71a9546SAutomerger Merge Worker 		if (sindex >= XT_STRING_MAX_PATTERN_SIZE)
106*a71a9546SAutomerger Merge Worker 			xtables_error(PARAMETER_PROBLEM,
107*a71a9546SAutomerger Merge Worker 				      "STRING too long \"%s\"", s);
108*a71a9546SAutomerger Merge Worker 		if (s[i] == '\\' && !hex_f) {
109*a71a9546SAutomerger Merge Worker 			literal_f = 1;
110*a71a9546SAutomerger Merge Worker 		} else if (s[i] == '\\') {
111*a71a9546SAutomerger Merge Worker 			xtables_error(PARAMETER_PROBLEM,
112*a71a9546SAutomerger Merge Worker 				"Cannot include literals in hex data");
113*a71a9546SAutomerger Merge Worker 		} else if (s[i] == '|') {
114*a71a9546SAutomerger Merge Worker 			if (hex_f)
115*a71a9546SAutomerger Merge Worker 				hex_f = 0;
116*a71a9546SAutomerger Merge Worker 			else {
117*a71a9546SAutomerger Merge Worker 				hex_f = 1;
118*a71a9546SAutomerger Merge Worker 				/* get past any initial whitespace just after the '|' */
119*a71a9546SAutomerger Merge Worker 				while (s[i+1] == ' ')
120*a71a9546SAutomerger Merge Worker 					i++;
121*a71a9546SAutomerger Merge Worker 			}
122*a71a9546SAutomerger Merge Worker 			if (i+1 >= slen)
123*a71a9546SAutomerger Merge Worker 				break;
124*a71a9546SAutomerger Merge Worker 			else
125*a71a9546SAutomerger Merge Worker 				i++;  /* advance to the next character */
126*a71a9546SAutomerger Merge Worker 		}
127*a71a9546SAutomerger Merge Worker 
128*a71a9546SAutomerger Merge Worker 		if (literal_f) {
129*a71a9546SAutomerger Merge Worker 			if (i+1 >= slen) {
130*a71a9546SAutomerger Merge Worker 				xtables_error(PARAMETER_PROBLEM,
131*a71a9546SAutomerger Merge Worker 					"Bad literal placement at end of string");
132*a71a9546SAutomerger Merge Worker 			}
133*a71a9546SAutomerger Merge Worker 			info->pattern[sindex] = s[i+1];
134*a71a9546SAutomerger Merge Worker 			i += 2;  /* skip over literal char */
135*a71a9546SAutomerger Merge Worker 			literal_f = 0;
136*a71a9546SAutomerger Merge Worker 		} else if (hex_f) {
137*a71a9546SAutomerger Merge Worker 			if (i+1 >= slen) {
138*a71a9546SAutomerger Merge Worker 				xtables_error(PARAMETER_PROBLEM,
139*a71a9546SAutomerger Merge Worker 					"Odd number of hex digits");
140*a71a9546SAutomerger Merge Worker 			}
141*a71a9546SAutomerger Merge Worker 			if (i+2 >= slen) {
142*a71a9546SAutomerger Merge Worker 				/* must end with a "|" */
143*a71a9546SAutomerger Merge Worker 				xtables_error(PARAMETER_PROBLEM, "Invalid hex block");
144*a71a9546SAutomerger Merge Worker 			}
145*a71a9546SAutomerger Merge Worker 			if (! isxdigit(s[i])) /* check for valid hex char */
146*a71a9546SAutomerger Merge Worker 				xtables_error(PARAMETER_PROBLEM, "Invalid hex char '%c'", s[i]);
147*a71a9546SAutomerger Merge Worker 			if (! isxdigit(s[i+1])) /* check for valid hex char */
148*a71a9546SAutomerger Merge Worker 				xtables_error(PARAMETER_PROBLEM, "Invalid hex char '%c'", s[i+1]);
149*a71a9546SAutomerger Merge Worker 			hextmp[0] = s[i];
150*a71a9546SAutomerger Merge Worker 			hextmp[1] = s[i+1];
151*a71a9546SAutomerger Merge Worker 			hextmp[2] = '\0';
152*a71a9546SAutomerger Merge Worker 			if (! sscanf(hextmp, "%x", &schar))
153*a71a9546SAutomerger Merge Worker 				xtables_error(PARAMETER_PROBLEM,
154*a71a9546SAutomerger Merge Worker 					"Invalid hex char `%c'", s[i]);
155*a71a9546SAutomerger Merge Worker 			info->pattern[sindex] = (char) schar;
156*a71a9546SAutomerger Merge Worker 			if (s[i+2] == ' ')
157*a71a9546SAutomerger Merge Worker 				i += 3;  /* spaces included in the hex block */
158*a71a9546SAutomerger Merge Worker 			else
159*a71a9546SAutomerger Merge Worker 				i += 2;
160*a71a9546SAutomerger Merge Worker 		} else {  /* the char is not part of hex data, so just copy */
161*a71a9546SAutomerger Merge Worker 			info->pattern[sindex] = s[i];
162*a71a9546SAutomerger Merge Worker 			i++;
163*a71a9546SAutomerger Merge Worker 		}
164*a71a9546SAutomerger Merge Worker 		sindex++;
165*a71a9546SAutomerger Merge Worker 	}
166*a71a9546SAutomerger Merge Worker 	info->patlen = sindex;
167*a71a9546SAutomerger Merge Worker }
168*a71a9546SAutomerger Merge Worker 
string_parse(struct xt_option_call * cb)169*a71a9546SAutomerger Merge Worker static void string_parse(struct xt_option_call *cb)
170*a71a9546SAutomerger Merge Worker {
171*a71a9546SAutomerger Merge Worker 	struct xt_string_info *stringinfo = cb->data;
172*a71a9546SAutomerger Merge Worker 	const unsigned int revision = (*cb->match)->u.user.revision;
173*a71a9546SAutomerger Merge Worker 
174*a71a9546SAutomerger Merge Worker 	xtables_option_parse(cb);
175*a71a9546SAutomerger Merge Worker 	switch (cb->entry->id) {
176*a71a9546SAutomerger Merge Worker 	case O_STRING:
177*a71a9546SAutomerger Merge Worker 		parse_string(cb->arg, stringinfo);
178*a71a9546SAutomerger Merge Worker 		if (cb->invert) {
179*a71a9546SAutomerger Merge Worker 			if (revision == 0)
180*a71a9546SAutomerger Merge Worker 				stringinfo->u.v0.invert = 1;
181*a71a9546SAutomerger Merge Worker 			else
182*a71a9546SAutomerger Merge Worker 				stringinfo->u.v1.flags |= XT_STRING_FLAG_INVERT;
183*a71a9546SAutomerger Merge Worker 		}
184*a71a9546SAutomerger Merge Worker 		break;
185*a71a9546SAutomerger Merge Worker 	case O_HEX_STRING:
186*a71a9546SAutomerger Merge Worker 		parse_hex_string(cb->arg, stringinfo);  /* sets length */
187*a71a9546SAutomerger Merge Worker 		if (cb->invert) {
188*a71a9546SAutomerger Merge Worker 			if (revision == 0)
189*a71a9546SAutomerger Merge Worker 				stringinfo->u.v0.invert = 1;
190*a71a9546SAutomerger Merge Worker 			else
191*a71a9546SAutomerger Merge Worker 				stringinfo->u.v1.flags |= XT_STRING_FLAG_INVERT;
192*a71a9546SAutomerger Merge Worker 		}
193*a71a9546SAutomerger Merge Worker 		break;
194*a71a9546SAutomerger Merge Worker 	case O_ICASE:
195*a71a9546SAutomerger Merge Worker 		if (revision == 0)
196*a71a9546SAutomerger Merge Worker 			xtables_error(VERSION_PROBLEM,
197*a71a9546SAutomerger Merge Worker 				   "Kernel doesn't support --icase");
198*a71a9546SAutomerger Merge Worker 
199*a71a9546SAutomerger Merge Worker 		stringinfo->u.v1.flags |= XT_STRING_FLAG_IGNORECASE;
200*a71a9546SAutomerger Merge Worker 		break;
201*a71a9546SAutomerger Merge Worker 	}
202*a71a9546SAutomerger Merge Worker }
203*a71a9546SAutomerger Merge Worker 
string_check(struct xt_fcheck_call * cb)204*a71a9546SAutomerger Merge Worker static void string_check(struct xt_fcheck_call *cb)
205*a71a9546SAutomerger Merge Worker {
206*a71a9546SAutomerger Merge Worker 	if (!(cb->xflags & F_OP_ANY))
207*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM,
208*a71a9546SAutomerger Merge Worker 			   "STRING match: You must specify `--string' or "
209*a71a9546SAutomerger Merge Worker 			   "`--hex-string'");
210*a71a9546SAutomerger Merge Worker }
211*a71a9546SAutomerger Merge Worker 
212*a71a9546SAutomerger Merge Worker /* Test to see if the string contains non-printable chars or quotes */
213*a71a9546SAutomerger Merge Worker static unsigned short int
is_hex_string(const char * str,const unsigned short int len)214*a71a9546SAutomerger Merge Worker is_hex_string(const char *str, const unsigned short int len)
215*a71a9546SAutomerger Merge Worker {
216*a71a9546SAutomerger Merge Worker 	unsigned int i;
217*a71a9546SAutomerger Merge Worker 	for (i=0; i < len; i++)
218*a71a9546SAutomerger Merge Worker 		if (! isprint(str[i]))
219*a71a9546SAutomerger Merge Worker 			return 1;  /* string contains at least one non-printable char */
220*a71a9546SAutomerger Merge Worker 	/* use hex output if the last char is a "\" */
221*a71a9546SAutomerger Merge Worker 	if (str[len-1] == '\\')
222*a71a9546SAutomerger Merge Worker 		return 1;
223*a71a9546SAutomerger Merge Worker 	return 0;
224*a71a9546SAutomerger Merge Worker }
225*a71a9546SAutomerger Merge Worker 
226*a71a9546SAutomerger Merge Worker /* Print string with "|" chars included as one would pass to --hex-string */
227*a71a9546SAutomerger Merge Worker static void
print_hex_string(const char * str,const unsigned short int len)228*a71a9546SAutomerger Merge Worker print_hex_string(const char *str, const unsigned short int len)
229*a71a9546SAutomerger Merge Worker {
230*a71a9546SAutomerger Merge Worker 	unsigned int i;
231*a71a9546SAutomerger Merge Worker 	/* start hex block */
232*a71a9546SAutomerger Merge Worker 	printf(" \"|");
233*a71a9546SAutomerger Merge Worker 	for (i=0; i < len; i++)
234*a71a9546SAutomerger Merge Worker 		printf("%02x", (unsigned char)str[i]);
235*a71a9546SAutomerger Merge Worker 	/* close hex block */
236*a71a9546SAutomerger Merge Worker 	printf("|\"");
237*a71a9546SAutomerger Merge Worker }
238*a71a9546SAutomerger Merge Worker 
239*a71a9546SAutomerger Merge Worker static void
print_string(const char * str,const unsigned short int len)240*a71a9546SAutomerger Merge Worker print_string(const char *str, const unsigned short int len)
241*a71a9546SAutomerger Merge Worker {
242*a71a9546SAutomerger Merge Worker 	unsigned int i;
243*a71a9546SAutomerger Merge Worker 	printf(" \"");
244*a71a9546SAutomerger Merge Worker 	for (i=0; i < len; i++) {
245*a71a9546SAutomerger Merge Worker 		if (str[i] == '\"' || str[i] == '\\')
246*a71a9546SAutomerger Merge Worker 			putchar('\\');
247*a71a9546SAutomerger Merge Worker 		printf("%c", (unsigned char) str[i]);
248*a71a9546SAutomerger Merge Worker 	}
249*a71a9546SAutomerger Merge Worker 	printf("\"");  /* closing quote */
250*a71a9546SAutomerger Merge Worker }
251*a71a9546SAutomerger Merge Worker 
252*a71a9546SAutomerger Merge Worker static void
string_print(const void * ip,const struct xt_entry_match * match,int numeric)253*a71a9546SAutomerger Merge Worker string_print(const void *ip, const struct xt_entry_match *match, int numeric)
254*a71a9546SAutomerger Merge Worker {
255*a71a9546SAutomerger Merge Worker 	const struct xt_string_info *info =
256*a71a9546SAutomerger Merge Worker 	    (const struct xt_string_info*) match->data;
257*a71a9546SAutomerger Merge Worker 	const int revision = match->u.user.revision;
258*a71a9546SAutomerger Merge Worker 	int invert = (revision == 0 ? info->u.v0.invert :
259*a71a9546SAutomerger Merge Worker 				    info->u.v1.flags & XT_STRING_FLAG_INVERT);
260*a71a9546SAutomerger Merge Worker 
261*a71a9546SAutomerger Merge Worker 	if (is_hex_string(info->pattern, info->patlen)) {
262*a71a9546SAutomerger Merge Worker 		printf(" STRING match %s", invert ? "!" : "");
263*a71a9546SAutomerger Merge Worker 		print_hex_string(info->pattern, info->patlen);
264*a71a9546SAutomerger Merge Worker 	} else {
265*a71a9546SAutomerger Merge Worker 		printf(" STRING match %s", invert ? "!" : "");
266*a71a9546SAutomerger Merge Worker 		print_string(info->pattern, info->patlen);
267*a71a9546SAutomerger Merge Worker 	}
268*a71a9546SAutomerger Merge Worker 	printf(" ALGO name %s", info->algo);
269*a71a9546SAutomerger Merge Worker 	if (info->from_offset != 0)
270*a71a9546SAutomerger Merge Worker 		printf(" FROM %u", info->from_offset);
271*a71a9546SAutomerger Merge Worker 	if (info->to_offset != UINT16_MAX)
272*a71a9546SAutomerger Merge Worker 		printf(" TO %u", info->to_offset);
273*a71a9546SAutomerger Merge Worker 	if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
274*a71a9546SAutomerger Merge Worker 		printf(" ICASE");
275*a71a9546SAutomerger Merge Worker }
276*a71a9546SAutomerger Merge Worker 
string_save(const void * ip,const struct xt_entry_match * match)277*a71a9546SAutomerger Merge Worker static void string_save(const void *ip, const struct xt_entry_match *match)
278*a71a9546SAutomerger Merge Worker {
279*a71a9546SAutomerger Merge Worker 	const struct xt_string_info *info =
280*a71a9546SAutomerger Merge Worker 	    (const struct xt_string_info*) match->data;
281*a71a9546SAutomerger Merge Worker 	const int revision = match->u.user.revision;
282*a71a9546SAutomerger Merge Worker 	int invert = (revision == 0 ? info->u.v0.invert :
283*a71a9546SAutomerger Merge Worker 				    info->u.v1.flags & XT_STRING_FLAG_INVERT);
284*a71a9546SAutomerger Merge Worker 
285*a71a9546SAutomerger Merge Worker 	if (is_hex_string(info->pattern, info->patlen)) {
286*a71a9546SAutomerger Merge Worker 		printf("%s --hex-string", (invert) ? " !" : "");
287*a71a9546SAutomerger Merge Worker 		print_hex_string(info->pattern, info->patlen);
288*a71a9546SAutomerger Merge Worker 	} else {
289*a71a9546SAutomerger Merge Worker 		printf("%s --string", (invert) ? " !": "");
290*a71a9546SAutomerger Merge Worker 		print_string(info->pattern, info->patlen);
291*a71a9546SAutomerger Merge Worker 	}
292*a71a9546SAutomerger Merge Worker 	printf(" --algo %s", info->algo);
293*a71a9546SAutomerger Merge Worker 	if (info->from_offset != 0)
294*a71a9546SAutomerger Merge Worker 		printf(" --from %u", info->from_offset);
295*a71a9546SAutomerger Merge Worker 	if (info->to_offset != UINT16_MAX)
296*a71a9546SAutomerger Merge Worker 		printf(" --to %u", info->to_offset);
297*a71a9546SAutomerger Merge Worker 	if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
298*a71a9546SAutomerger Merge Worker 		printf(" --icase");
299*a71a9546SAutomerger Merge Worker }
300*a71a9546SAutomerger Merge Worker 
301*a71a9546SAutomerger Merge Worker 
302*a71a9546SAutomerger Merge Worker static struct xtables_match string_mt_reg[] = {
303*a71a9546SAutomerger Merge Worker 	{
304*a71a9546SAutomerger Merge Worker 		.name          = "string",
305*a71a9546SAutomerger Merge Worker 		.revision      = 0,
306*a71a9546SAutomerger Merge Worker 		.family        = NFPROTO_UNSPEC,
307*a71a9546SAutomerger Merge Worker 		.version       = XTABLES_VERSION,
308*a71a9546SAutomerger Merge Worker 		.size          = XT_ALIGN(sizeof(struct xt_string_info)),
309*a71a9546SAutomerger Merge Worker 		.userspacesize = offsetof(struct xt_string_info, config),
310*a71a9546SAutomerger Merge Worker 		.help          = string_help,
311*a71a9546SAutomerger Merge Worker 		.init          = string_init,
312*a71a9546SAutomerger Merge Worker 		.print         = string_print,
313*a71a9546SAutomerger Merge Worker 		.save          = string_save,
314*a71a9546SAutomerger Merge Worker 		.x6_parse      = string_parse,
315*a71a9546SAutomerger Merge Worker 		.x6_fcheck     = string_check,
316*a71a9546SAutomerger Merge Worker 		.x6_options    = string_opts,
317*a71a9546SAutomerger Merge Worker 	},
318*a71a9546SAutomerger Merge Worker 	{
319*a71a9546SAutomerger Merge Worker 		.name          = "string",
320*a71a9546SAutomerger Merge Worker 		.revision      = 1,
321*a71a9546SAutomerger Merge Worker 		.family        = NFPROTO_UNSPEC,
322*a71a9546SAutomerger Merge Worker 		.version       = XTABLES_VERSION,
323*a71a9546SAutomerger Merge Worker 		.size          = XT_ALIGN(sizeof(struct xt_string_info)),
324*a71a9546SAutomerger Merge Worker 		.userspacesize = offsetof(struct xt_string_info, config),
325*a71a9546SAutomerger Merge Worker 		.help          = string_help,
326*a71a9546SAutomerger Merge Worker 		.init          = string_init,
327*a71a9546SAutomerger Merge Worker 		.print         = string_print,
328*a71a9546SAutomerger Merge Worker 		.save          = string_save,
329*a71a9546SAutomerger Merge Worker 		.x6_parse      = string_parse,
330*a71a9546SAutomerger Merge Worker 		.x6_fcheck     = string_check,
331*a71a9546SAutomerger Merge Worker 		.x6_options    = string_opts,
332*a71a9546SAutomerger Merge Worker 	},
333*a71a9546SAutomerger Merge Worker };
334*a71a9546SAutomerger Merge Worker 
_init(void)335*a71a9546SAutomerger Merge Worker void _init(void)
336*a71a9546SAutomerger Merge Worker {
337*a71a9546SAutomerger Merge Worker 	xtables_register_matches(string_mt_reg, ARRAY_SIZE(string_mt_reg));
338*a71a9546SAutomerger Merge Worker }
339