libxt_string.c revision 1829ed482efbc8b390cc760d012b3a4450494e1a
13071913784b69423fd25c3db2344e585872920ccEmmanuel Roger/* Shared library add-on to iptables to add string matching support.
23071913784b69423fd25c3db2344e585872920ccEmmanuel Roger *
33071913784b69423fd25c3db2344e585872920ccEmmanuel Roger * Copyright (C) 2000 Emmanuel Roger  <winfield@freegates.be>
4764316a133db8e5e2d1f2a9d941ffae993d7c9d9András Kis-Szabó *
5c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira * 2005-08-05 Pablo Neira Ayuso <pablo@eurodev.net>
6c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira * 	- reimplemented to use new string matching iptables match
7c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira * 	- add functionality to match packets by using window offsets
8c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira * 	- add functionality to select the string matching algorithm
9c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira *
10764316a133db8e5e2d1f2a9d941ffae993d7c9d9András Kis-Szabó * ChangeLog
11b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash *     29.12.2003: Michael Rash <mbr@cipherdyne.org>
12b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash *             Fixed iptables save/restore for ascii strings
13b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash *             that contain space chars, and hex strings that
14b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash *             contain embedded NULL chars.  Updated to print
15b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash *             strings in hex mode if any non-printable char
16b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash *             is contained within the string.
17b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash *
18764316a133db8e5e2d1f2a9d941ffae993d7c9d9András Kis-Szabó *     27.01.2001: Gianni Tedesco <gianni@ecsc.co.uk>
19764316a133db8e5e2d1f2a9d941ffae993d7c9d9András Kis-Szabó *             Changed --tos to --string in save(). Also
20764316a133db8e5e2d1f2a9d941ffae993d7c9d9András Kis-Szabó *             updated to work with slightly modified
21764316a133db8e5e2d1f2a9d941ffae993d7c9d9András Kis-Szabó *             ipt_string_info.
223071913784b69423fd25c3db2344e585872920ccEmmanuel Roger */
2337b4bde745698bf140d74e59a2561f34deeb8726Jan Engelhardt#define _GNU_SOURCE 1
243071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <stdio.h>
253071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <netdb.h>
263071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <string.h>
273071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <stdlib.h>
283071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <getopt.h>
29f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash#include <ctype.h>
306ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI#include <xtables.h>
31c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira#include <stddef.h>
326ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI#include <linux/netfilter/xt_string.h>
333071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
34181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void string_help(void)
353071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
363071913784b69423fd25c3db2344e585872920ccEmmanuel Roger	printf(
378b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"string match options:\n"
38c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira"--from                       Offset to start searching from\n"
39c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira"--to                         Offset to stop searching\n"
4078d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park"--algo                       Algorithm\n"
4178d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park"--icase                      Ignore case (default: 0)\n"
429b488b992872d4d2b7ebf7897d74d52f4fb59e1cJan Engelhardt"[!] --string string          Match a string in a packet\n"
439b488b992872d4d2b7ebf7897d74d52f4fb59e1cJan Engelhardt"[!] --hex-string string      Match a hex string in a packet\n");
443071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
453071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
46181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic const struct option string_opts[] = {
47500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy	{ "from", 1, NULL, '1' },
48500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy	{ "to", 1, NULL, '2' },
49500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy	{ "algo", 1, NULL, '3' },
50500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy	{ "string", 1, NULL, '4' },
51500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy	{ "hex-string", 1, NULL, '5' },
5278d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	{ "icase", 0, NULL, '6' },
539ee386a1b6d7704b259460152c959ab0e79e02aaMax Kellermann	{ .name = NULL }
543071913784b69423fd25c3db2344e585872920ccEmmanuel Roger};
553071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
56181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void string_init(struct xt_entry_match *m)
57c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira{
586ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	struct xt_string_info *i = (struct xt_string_info *) m->data;
59c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira
60c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (i->to_offset == 0)
61a80975497968e69b23f56bf15d346c65bec381f2Jan Engelhardt		i->to_offset = UINT16_MAX;
62c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira}
63c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira
64c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neirastatic void
656ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAIparse_string(const char *s, struct xt_string_info *info)
663071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
676ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	if (strlen(s) <= XT_STRING_MAX_PATTERN_SIZE) {
686ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI		strncpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE);
69c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		info->patlen = strlen(s);
70c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		return;
71c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	}
721829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt	xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s);
7396d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash}
7496d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash
75c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neirastatic void
766ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAIparse_algo(const char *s, struct xt_string_info *info)
77c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira{
786ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	if (strlen(s) <= XT_STRING_MAX_ALGO_NAME_SIZE) {
796ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI		strncpy(info->algo, s, XT_STRING_MAX_ALGO_NAME_SIZE);
80c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		return;
81c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	}
821829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt	xtables_error(PARAMETER_PROBLEM, "ALGO too long \"%s\"", s);
83c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira}
84451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
8596d8593fffe816b3ee1bcd27df33beff5c404058Michael Rashstatic void
866ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAIparse_hex_string(const char *s, struct xt_string_info *info)
8796d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash{
88f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	int i=0, slen, sindex=0, schar;
89f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	short hex_f = 0, literal_f = 0;
90f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	char hextmp[3];
91f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash
92f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	slen = strlen(s);
93f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash
94f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	if (slen == 0) {
951829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
96f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			"STRING must contain at least one char");
97f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	}
98f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash
99f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	while (i < slen) {
100f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		if (s[i] == '\\' && !hex_f) {
101f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			literal_f = 1;
102f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		} else if (s[i] == '\\') {
1031829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
104f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				"Cannot include literals in hex data");
105f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		} else if (s[i] == '|') {
106f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (hex_f)
107f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				hex_f = 0;
108b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			else {
109f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				hex_f = 1;
110b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash				/* get past any initial whitespace just after the '|' */
111b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash				while (s[i+1] == ' ')
112b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash					i++;
113b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			}
114f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (i+1 >= slen)
115f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				break;
116f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			else
117f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				i++;  /* advance to the next character */
118f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		}
119f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash
120f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		if (literal_f) {
121f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (i+1 >= slen) {
1221829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM,
123f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash					"Bad literal placement at end of string");
124f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			}
125c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			info->pattern[sindex] = s[i+1];
126f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			i += 2;  /* skip over literal char */
127f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			literal_f = 0;
128f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		} else if (hex_f) {
129f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (i+1 >= slen) {
1301829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM,
131f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash					"Odd number of hex digits");
132f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			}
133f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (i+2 >= slen) {
134f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				/* must end with a "|" */
1351829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM, "Invalid hex block");
136f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			}
13796d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash			if (! isxdigit(s[i])) /* check for valid hex char */
1381829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM, "Invalid hex char '%c'", s[i]);
13996d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash			if (! isxdigit(s[i+1])) /* check for valid hex char */
1401829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM, "Invalid hex char '%c'", s[i+1]);
141f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			hextmp[0] = s[i];
142f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			hextmp[1] = s[i+1];
143f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			hextmp[2] = '\0';
144f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (! sscanf(hextmp, "%x", &schar))
1451829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM,
146f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash					"Invalid hex char `%c'", s[i]);
147c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			info->pattern[sindex] = (char) schar;
148f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (s[i+2] == ' ')
149f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				i += 3;  /* spaces included in the hex block */
150f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			else
151f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				i += 2;
152f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		} else {  /* the char is not part of hex data, so just copy */
153c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			info->pattern[sindex] = s[i];
154f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			i++;
155f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		}
1566ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI		if (sindex > XT_STRING_MAX_PATTERN_SIZE)
1571829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s);
158f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		sindex++;
159f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	}
160c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	info->patlen = sindex;
1613071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
1623071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
163c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira#define STRING 0x1
164c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira#define ALGO   0x2
165c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira#define FROM   0x4
166c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira#define TO     0x8
16778d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park#define ICASE  0x10
168451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
1693071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerstatic int
170181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstring_parse(int c, char **argv, int invert, unsigned int *flags,
171181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt             const void *entry, struct xt_entry_match **match)
1723071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
17378d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	struct xt_string_info *stringinfo =
17478d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	    (struct xt_string_info *)(*match)->data;
17578d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	const int revision = (*match)->u.user.revision;
1763071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
1773071913784b69423fd25c3db2344e585872920ccEmmanuel Roger	switch (c) {
1783071913784b69423fd25c3db2344e585872920ccEmmanuel Roger	case '1':
179c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		if (*flags & FROM)
1801829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
181c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira				   "Can't specify multiple --from");
182c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		stringinfo->from_offset = atoi(optarg);
183c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		*flags |= FROM;
184c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		break;
185c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	case '2':
186c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		if (*flags & TO)
1871829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
188c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira				   "Can't specify multiple --to");
189c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		stringinfo->to_offset = atoi(optarg);
190c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		*flags |= TO;
191c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		break;
192c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	case '3':
193c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		if (*flags & ALGO)
1941829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
195c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira				   "Can't specify multiple --algo");
196c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		parse_algo(optarg, stringinfo);
197c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		*flags |= ALGO;
198c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		break;
199c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	case '4':
200c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		if (*flags & STRING)
2011829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
202c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira				   "Can't specify multiple --string");
2030f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		xtables_check_inverse(optarg, &invert, &optind, 0);
2043071913784b69423fd25c3db2344e585872920ccEmmanuel Roger		parse_string(argv[optind-1], stringinfo);
20578d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		if (invert) {
20678d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park			if (revision == 0)
20778d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				stringinfo->u.v0.invert = 1;
20878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park			else
20978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				stringinfo->u.v1.flags |= XT_STRING_FLAG_INVERT;
21078d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		}
21137b4bde745698bf140d74e59a2561f34deeb8726Jan Engelhardt		stringinfo->patlen = strnlen((char *)&stringinfo->pattern,
21237b4bde745698bf140d74e59a2561f34deeb8726Jan Engelhardt			sizeof(stringinfo->patlen));
213c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		*flags |= STRING;
21496d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash		break;
21596d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash
216c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	case '5':
217c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		if (*flags & STRING)
2181829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
219c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira				   "Can't specify multiple --hex-string");
220451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
2210f16c725aadaac7e670d632ecbaea3661ff00827Jan Engelhardt		xtables_check_inverse(optarg, &invert, &optind, 0);
22296d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash		parse_hex_string(argv[optind-1], stringinfo);  /* sets length */
22378d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		if (invert) {
22478d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park			if (revision == 0)
22578d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				stringinfo->u.v0.invert = 1;
22678d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park			else
22778d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				stringinfo->u.v1.flags |= XT_STRING_FLAG_INVERT;
22878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		}
229c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		*flags |= STRING;
2303071913784b69423fd25c3db2344e585872920ccEmmanuel Roger		break;
2313071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
23278d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	case '6':
23378d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		if (revision == 0)
2341829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(VERSION_PROBLEM,
23578d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				   "Kernel doesn't support --icase");
23678d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park
23778d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		stringinfo->u.v1.flags |= XT_STRING_FLAG_IGNORECASE;
23878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		*flags |= ICASE;
23978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		break;
24078d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park
2413071913784b69423fd25c3db2344e585872920ccEmmanuel Roger	default:
2423071913784b69423fd25c3db2344e585872920ccEmmanuel Roger		return 0;
2433071913784b69423fd25c3db2344e585872920ccEmmanuel Roger	}
2443071913784b69423fd25c3db2344e585872920ccEmmanuel Roger	return 1;
2453071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
2463071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
247181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void string_check(unsigned int flags)
2483071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
249c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (!(flags & STRING))
2501829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
251c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			   "STRING match: You must specify `--string' or "
252c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			   "`--hex-string'");
253c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (!(flags & ALGO))
2541829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
255c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			   "STRING match: You must specify `--algo'");
2563071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
2573071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
258b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash/* Test to see if the string contains non-printable chars or quotes */
259b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashstatic unsigned short int
260b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashis_hex_string(const char *str, const unsigned short int len)
261b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash{
262b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	unsigned int i;
263b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	for (i=0; i < len; i++)
264b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		if (! isprint(str[i]))
265b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			return 1;  /* string contains at least one non-printable char */
266b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	/* use hex output if the last char is a "\" */
267b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	if ((unsigned char) str[len-1] == 0x5c)
268b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		return 1;
269b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	return 0;
270b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash}
271b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash
272b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash/* Print string with "|" chars included as one would pass to --hex-string */
273b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashstatic void
274b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashprint_hex_string(const char *str, const unsigned short int len)
275b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash{
276b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	unsigned int i;
277b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	/* start hex block */
278b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	printf("\"|");
279b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	for (i=0; i < len; i++) {
280b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		/* see if we need to prepend a zero */
281b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		if ((unsigned char) str[i] <= 0x0F)
282b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			printf("0%x", (unsigned char) str[i]);
283b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		else
284b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			printf("%x", (unsigned char) str[i]);
285b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	}
286b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	/* close hex block */
287b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	printf("|\" ");
288b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash}
289b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash
290b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashstatic void
291b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashprint_string(const char *str, const unsigned short int len)
292b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash{
293b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	unsigned int i;
294b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	printf("\"");
295b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	for (i=0; i < len; i++) {
296b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		if ((unsigned char) str[i] == 0x22)  /* escape any embedded quotes */
297b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			printf("%c", 0x5c);
298b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		printf("%c", (unsigned char) str[i]);
299b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	}
300b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	printf("\" ");  /* closing space and quote */
301b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash}
302451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
3033071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerstatic void
304181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstring_print(const void *ip, const struct xt_entry_match *match, int numeric)
3053071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
3066ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	const struct xt_string_info *info =
3076ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	    (const struct xt_string_info*) match->data;
30878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	const int revision = match->u.user.revision;
30978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	int invert = (revision == 0 ? info->u.v0.invert :
31078d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				    info->u.v1.flags & XT_STRING_FLAG_INVERT);
311451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
312c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (is_hex_string(info->pattern, info->patlen)) {
31378d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		printf("STRING match %s", invert ? "!" : "");
314c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		print_hex_string(info->pattern, info->patlen);
315b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	} else {
31678d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		printf("STRING match %s", invert ? "!" : "");
317c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		print_string(info->pattern, info->patlen);
318b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	}
319c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	printf("ALGO name %s ", info->algo);
320c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (info->from_offset != 0)
321c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		printf("FROM %u ", info->from_offset);
322c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (info->to_offset != 0)
3238a0b6ead35931422fbe02c63d9262ad9e40daaccPatrick McHardy		printf("TO %u ", info->to_offset);
32478d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
32578d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		printf("ICASE ");
3263071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
3273071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
328181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void string_save(const void *ip, const struct xt_entry_match *match)
3293071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
3306ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	const struct xt_string_info *info =
3316ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	    (const struct xt_string_info*) match->data;
33278d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	const int revision = match->u.user.revision;
33378d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	int invert = (revision == 0 ? info->u.v0.invert :
33478d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				    info->u.v1.flags & XT_STRING_FLAG_INVERT);
335451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
336c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (is_hex_string(info->pattern, info->patlen)) {
337cea9f71f5618250a38acb21c31fbbf93a752f7d4Jan Engelhardt		printf("%s--hex-string ", (invert) ? "! ": "");
338c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		print_hex_string(info->pattern, info->patlen);
339b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	} else {
340cea9f71f5618250a38acb21c31fbbf93a752f7d4Jan Engelhardt		printf("%s--string ", (invert) ? "! ": "");
341c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		print_string(info->pattern, info->patlen);
342b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	}
343c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	printf("--algo %s ", info->algo);
344c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (info->from_offset != 0)
3450829a2b72caa06c07e6eb710a81a04295c9f2621Michael Rash		printf("--from %u ", info->from_offset);
346c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (info->to_offset != 0)
3470829a2b72caa06c07e6eb710a81a04295c9f2621Michael Rash		printf("--to %u ", info->to_offset);
34878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
34978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		printf("--icase ");
3503071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
3513071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
352451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
353181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic struct xtables_match string_match = {
354c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira    .name		= "string",
35578d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .revision		= 0,
35678d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .family		= AF_UNSPEC,
35778d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .version		= XTABLES_VERSION,
35878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .size		= XT_ALIGN(sizeof(struct xt_string_info)),
35978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .userspacesize	= offsetof(struct xt_string_info, config),
36078d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .help		= string_help,
36178d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .init		= string_init,
36278d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .parse		= string_parse,
36378d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .final_check	= string_check,
36478d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .print		= string_print,
36578d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .save		= string_save,
36678d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .extra_opts		= string_opts,
36778d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park};
36878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park
36978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Parkstatic struct xtables_match string_match_v1 = {
37078d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .name		= "string",
37178d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park    .revision		= 1,
37223545c2a7a31c68c1e49c7c901b632c2f1c59968Jan Engelhardt    .family		= AF_UNSPEC,
3738b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt    .version		= XTABLES_VERSION,
3744ccb6f547b6c2c355a188a267afe6358b013a438Yasuyuki KOZAKAI    .size		= XT_ALIGN(sizeof(struct xt_string_info)),
3754ccb6f547b6c2c355a188a267afe6358b013a438Yasuyuki KOZAKAI    .userspacesize	= offsetof(struct xt_string_info, config),
376181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt    .help		= string_help,
377181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt    .init		= string_init,
378181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt    .parse		= string_parse,
379181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt    .final_check	= string_check,
380181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt    .print		= string_print,
381181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt    .save		= string_save,
382181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt    .extra_opts		= string_opts,
3834ccb6f547b6c2c355a188a267afe6358b013a438Yasuyuki KOZAKAI};
3844ccb6f547b6c2c355a188a267afe6358b013a438Yasuyuki KOZAKAI
3853071913784b69423fd25c3db2344e585872920ccEmmanuel Rogervoid _init(void)
3863071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
387181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt	xtables_register_match(&string_match);
38878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	xtables_register_match(&string_match_v1);
3893071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
390