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 */
2367156c0b9a3d35f5e7836e5683d8ca0b46ac36caJan Engelhardt#define _GNU_SOURCE 1 /* strnlen for older glibcs */
243071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <stdio.h>
253071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <string.h>
263071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <stdlib.h>
27f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash#include <ctype.h>
286ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI#include <xtables.h>
296ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI#include <linux/netfilter/xt_string.h>
303071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
31c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardtenum {
32c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	O_FROM = 0,
33c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	O_TO,
34c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	O_ALGO,
35c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	O_ICASE,
36c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	O_STRING,
37c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	O_HEX_STRING,
38c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	F_STRING     = 1 << O_STRING,
39c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	F_HEX_STRING = 1 << O_HEX_STRING,
40c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	F_OP_ANY     = F_STRING | F_HEX_STRING,
41c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt};
42c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt
43181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void string_help(void)
443071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
453071913784b69423fd25c3db2344e585872920ccEmmanuel Roger	printf(
468b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"string match options:\n"
47c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira"--from                       Offset to start searching from\n"
48c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira"--to                         Offset to stop searching\n"
4978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park"--algo                       Algorithm\n"
5078d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park"--icase                      Ignore case (default: 0)\n"
519b488b992872d4d2b7ebf7897d74d52f4fb59e1cJan Engelhardt"[!] --string string          Match a string in a packet\n"
529b488b992872d4d2b7ebf7897d74d52f4fb59e1cJan Engelhardt"[!] --hex-string string      Match a hex string in a packet\n");
533071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
543071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
55c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt#define s struct xt_string_info
56c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardtstatic const struct xt_option_entry string_opts[] = {
57c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	{.name = "from", .id = O_FROM, .type = XTTYPE_UINT16,
58c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	 .flags = XTOPT_PUT, XTOPT_POINTER(s, from_offset)},
59c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	{.name = "to", .id = O_TO, .type = XTTYPE_UINT16,
60c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	 .flags = XTOPT_PUT, XTOPT_POINTER(s, to_offset)},
61c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	{.name = "algo", .id = O_ALGO, .type = XTTYPE_STRING,
62c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, algo)},
63c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	{.name = "string", .id = O_STRING, .type = XTTYPE_STRING,
64c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	 .flags = XTOPT_INVERT, .excl = F_HEX_STRING},
65c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	{.name = "hex-string", .id = O_HEX_STRING, .type = XTTYPE_STRING,
66c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	 .flags = XTOPT_INVERT, .excl = F_STRING},
67c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	{.name = "icase", .id = O_ICASE, .type = XTTYPE_NONE},
68c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	XTOPT_TABLEEND,
693071913784b69423fd25c3db2344e585872920ccEmmanuel Roger};
70c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt#undef s
713071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
72181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void string_init(struct xt_entry_match *m)
73c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira{
746ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	struct xt_string_info *i = (struct xt_string_info *) m->data;
75c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira
76e88a7c2c7175742b58b6aa03f2b5aba2d80330a1Jan Engelhardt	i->to_offset = UINT16_MAX;
77c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira}
78c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira
79c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neirastatic void
806ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAIparse_string(const char *s, struct xt_string_info *info)
813071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
82409f2a8e3b2706c8c6c5e345a4bc77fca8ad7105Pablo Neira Ayuso	/* xt_string does not need \0 at the end of the pattern */
836ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	if (strlen(s) <= XT_STRING_MAX_PATTERN_SIZE) {
846ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI		strncpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE);
85409f2a8e3b2706c8c6c5e345a4bc77fca8ad7105Pablo Neira Ayuso		info->patlen = strnlen(s, XT_STRING_MAX_PATTERN_SIZE);
86c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		return;
87c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	}
881829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt	xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s);
8996d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash}
9096d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash
91c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neirastatic void
926ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAIparse_hex_string(const char *s, struct xt_string_info *info)
9396d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash{
94f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	int i=0, slen, sindex=0, schar;
95f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	short hex_f = 0, literal_f = 0;
96f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	char hextmp[3];
97f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash
98f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	slen = strlen(s);
99f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash
100f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	if (slen == 0) {
1011829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
102f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			"STRING must contain at least one char");
103f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	}
104f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash
105f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	while (i < slen) {
106f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		if (s[i] == '\\' && !hex_f) {
107f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			literal_f = 1;
108f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		} else if (s[i] == '\\') {
1091829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
110f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				"Cannot include literals in hex data");
111f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		} else if (s[i] == '|') {
112f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (hex_f)
113f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				hex_f = 0;
114b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			else {
115f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				hex_f = 1;
116b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash				/* get past any initial whitespace just after the '|' */
117b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash				while (s[i+1] == ' ')
118b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash					i++;
119b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			}
120f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (i+1 >= slen)
121f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				break;
122f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			else
123f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				i++;  /* advance to the next character */
124f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		}
125f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash
126f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		if (literal_f) {
127f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (i+1 >= slen) {
1281829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM,
129f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash					"Bad literal placement at end of string");
130f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			}
131c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			info->pattern[sindex] = s[i+1];
132f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			i += 2;  /* skip over literal char */
133f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			literal_f = 0;
134f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		} else if (hex_f) {
135f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (i+1 >= slen) {
1361829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM,
137f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash					"Odd number of hex digits");
138f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			}
139f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (i+2 >= slen) {
140f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				/* must end with a "|" */
1411829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM, "Invalid hex block");
142f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			}
14396d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash			if (! isxdigit(s[i])) /* check for valid hex char */
1441829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM, "Invalid hex char '%c'", s[i]);
14596d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash			if (! isxdigit(s[i+1])) /* check for valid hex char */
1461829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM, "Invalid hex char '%c'", s[i+1]);
147f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			hextmp[0] = s[i];
148f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			hextmp[1] = s[i+1];
149f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			hextmp[2] = '\0';
150f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (! sscanf(hextmp, "%x", &schar))
1511829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM,
152f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash					"Invalid hex char `%c'", s[i]);
153c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			info->pattern[sindex] = (char) schar;
154f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (s[i+2] == ' ')
155f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				i += 3;  /* spaces included in the hex block */
156f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			else
157f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				i += 2;
158f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		} else {  /* the char is not part of hex data, so just copy */
159c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			info->pattern[sindex] = s[i];
160f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			i++;
161f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		}
1626ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI		if (sindex > XT_STRING_MAX_PATTERN_SIZE)
1631829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s);
164f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		sindex++;
165f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	}
166c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	info->patlen = sindex;
1673071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
1683071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
169c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardtstatic void string_parse(struct xt_option_call *cb)
1703071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
171c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	struct xt_string_info *stringinfo = cb->data;
172c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	const unsigned int revision = (*cb->match)->u.user.revision;
1733071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
174c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	xtables_option_parse(cb);
175c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	switch (cb->entry->id) {
176c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	case O_STRING:
177c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		parse_string(cb->arg, stringinfo);
178c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		if (cb->invert) {
17978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park			if (revision == 0)
18078d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				stringinfo->u.v0.invert = 1;
18178d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park			else
18278d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				stringinfo->u.v1.flags |= XT_STRING_FLAG_INVERT;
18378d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		}
18496d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash		break;
185c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	case O_HEX_STRING:
186c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		parse_hex_string(cb->arg, stringinfo);  /* sets length */
187c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		if (cb->invert) {
18878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park			if (revision == 0)
18978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				stringinfo->u.v0.invert = 1;
19078d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park			else
19178d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				stringinfo->u.v1.flags |= XT_STRING_FLAG_INVERT;
19278d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		}
1933071913784b69423fd25c3db2344e585872920ccEmmanuel Roger		break;
194c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	case O_ICASE:
19578d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		if (revision == 0)
1961829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(VERSION_PROBLEM,
19778d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				   "Kernel doesn't support --icase");
19878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park
19978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		stringinfo->u.v1.flags |= XT_STRING_FLAG_IGNORECASE;
20078d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		break;
2013071913784b69423fd25c3db2344e585872920ccEmmanuel Roger	}
2023071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
2033071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
204c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardtstatic void string_check(struct xt_fcheck_call *cb)
2053071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
206c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	if (!(cb->xflags & F_OP_ANY))
2071829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
208c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			   "STRING match: You must specify `--string' or "
209c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			   "`--hex-string'");
2103071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
2113071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
212b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash/* Test to see if the string contains non-printable chars or quotes */
213b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashstatic unsigned short int
214b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashis_hex_string(const char *str, const unsigned short int len)
215b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash{
216b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	unsigned int i;
217b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	for (i=0; i < len; i++)
218b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		if (! isprint(str[i]))
219b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			return 1;  /* string contains at least one non-printable char */
220b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	/* use hex output if the last char is a "\" */
221f4daf54e5c184680559de33eb08f2a0fb701dbe9Jan Engelhardt	if (str[len-1] == '\\')
222b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		return 1;
223b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	return 0;
224b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash}
225b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash
226b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash/* Print string with "|" chars included as one would pass to --hex-string */
227b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashstatic void
228b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashprint_hex_string(const char *str, const unsigned short int len)
229b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash{
230b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	unsigned int i;
231b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	/* start hex block */
2323716dfd7eac3afa7fb3098952550e510c8df0220Dwight Davis	printf(" \"|");
233131d4fb53b45be85b1315f72f958cadf7b24a63fJan Engelhardt	for (i=0; i < len; i++)
234131d4fb53b45be85b1315f72f958cadf7b24a63fJan Engelhardt		printf("%02x", (unsigned char)str[i]);
235b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	/* close hex block */
2363716dfd7eac3afa7fb3098952550e510c8df0220Dwight Davis	printf("|\"");
237b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash}
238b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash
239b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashstatic void
240b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashprint_string(const char *str, const unsigned short int len)
241b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash{
242b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	unsigned int i;
24373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" \"");
244b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	for (i=0; i < len; i++) {
245d51a97bc52ee81a962b761c7e58a5eb9f07a2c8aJan Engelhardt		if (str[i] == '\"' || str[i] == '\\')
246f4daf54e5c184680559de33eb08f2a0fb701dbe9Jan Engelhardt			putchar('\\');
247b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		printf("%c", (unsigned char) str[i]);
248b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	}
24973866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf("\"");  /* closing quote */
250b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash}
251451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
2523071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerstatic void
253181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstring_print(const void *ip, const struct xt_entry_match *match, int numeric)
2543071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
2556ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	const struct xt_string_info *info =
2566ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	    (const struct xt_string_info*) match->data;
25778d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	const int revision = match->u.user.revision;
25878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	int invert = (revision == 0 ? info->u.v0.invert :
25978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				    info->u.v1.flags & XT_STRING_FLAG_INVERT);
260451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
261c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (is_hex_string(info->pattern, info->patlen)) {
26273866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" STRING match %s", invert ? "!" : "");
263c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		print_hex_string(info->pattern, info->patlen);
264b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	} else {
26573866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" STRING match %s", invert ? "!" : "");
266c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		print_string(info->pattern, info->patlen);
267b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	}
26873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" ALGO name %s", info->algo);
269c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (info->from_offset != 0)
27073866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" FROM %u", info->from_offset);
271c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (info->to_offset != 0)
27273866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" TO %u", info->to_offset);
27378d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
27473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" ICASE");
2753071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
2763071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
277181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void string_save(const void *ip, const struct xt_entry_match *match)
2783071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
2796ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	const struct xt_string_info *info =
2806ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	    (const struct xt_string_info*) match->data;
28178d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	const int revision = match->u.user.revision;
28278d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	int invert = (revision == 0 ? info->u.v0.invert :
28378d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				    info->u.v1.flags & XT_STRING_FLAG_INVERT);
284451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
285c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (is_hex_string(info->pattern, info->patlen)) {
28673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf("%s --hex-string", (invert) ? " !" : "");
287c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		print_hex_string(info->pattern, info->patlen);
288b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	} else {
28973866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf("%s --string", (invert) ? " !": "");
290c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		print_string(info->pattern, info->patlen);
291b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	}
29273866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" --algo %s", info->algo);
293c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (info->from_offset != 0)
29473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --from %u", info->from_offset);
295c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (info->to_offset != 0)
29673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --to %u", info->to_offset);
29778d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
29873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --icase");
2993071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
3003071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
301451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
302f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardtstatic struct xtables_match string_mt_reg[] = {
303f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	{
304f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.name          = "string",
305f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.revision      = 0,
306f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.family        = NFPROTO_UNSPEC,
307f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.version       = XTABLES_VERSION,
308f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.size          = XT_ALIGN(sizeof(struct xt_string_info)),
309f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.userspacesize = offsetof(struct xt_string_info, config),
310f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.help          = string_help,
311f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.init          = string_init,
312f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.print         = string_print,
313f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.save          = string_save,
314c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		.x6_parse      = string_parse,
315c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		.x6_fcheck     = string_check,
316c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		.x6_options    = string_opts,
317f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	},
318f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	{
319f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.name          = "string",
320f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.revision      = 1,
321f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.family        = NFPROTO_UNSPEC,
322f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.version       = XTABLES_VERSION,
323f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.size          = XT_ALIGN(sizeof(struct xt_string_info)),
324f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.userspacesize = offsetof(struct xt_string_info, config),
325f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.help          = string_help,
326f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.init          = string_init,
327f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.print         = string_print,
328f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.save          = string_save,
329c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		.x6_parse      = string_parse,
330c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		.x6_fcheck     = string_check,
331c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		.x6_options    = string_opts,
332f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	},
3334ccb6f547b6c2c355a188a267afe6358b013a438Yasuyuki KOZAKAI};
3344ccb6f547b6c2c355a188a267afe6358b013a438Yasuyuki KOZAKAI
3353071913784b69423fd25c3db2344e585872920ccEmmanuel Rogervoid _init(void)
3363071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
337f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	xtables_register_matches(string_mt_reg, ARRAY_SIZE(string_mt_reg));
3383071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
339