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