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 */
233071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <stdio.h>
243071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <string.h>
253071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <stdlib.h>
26f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash#include <ctype.h>
276ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI#include <xtables.h>
286ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI#include <linux/netfilter/xt_string.h>
293071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
30c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardtenum {
31c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	O_FROM = 0,
32c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	O_TO,
33c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	O_ALGO,
34c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	O_ICASE,
35c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	O_STRING,
36c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	O_HEX_STRING,
37c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	F_STRING     = 1 << O_STRING,
38c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	F_HEX_STRING = 1 << O_HEX_STRING,
39c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	F_OP_ANY     = F_STRING | F_HEX_STRING,
40c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt};
41c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt
42181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void string_help(void)
433071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
443071913784b69423fd25c3db2344e585872920ccEmmanuel Roger	printf(
458b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"string match options:\n"
46c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira"--from                       Offset to start searching from\n"
47c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira"--to                         Offset to stop searching\n"
4878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park"--algo                       Algorithm\n"
4978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park"--icase                      Ignore case (default: 0)\n"
509b488b992872d4d2b7ebf7897d74d52f4fb59e1cJan Engelhardt"[!] --string string          Match a string in a packet\n"
519b488b992872d4d2b7ebf7897d74d52f4fb59e1cJan Engelhardt"[!] --hex-string string      Match a hex string in a packet\n");
523071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
533071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
54c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt#define s struct xt_string_info
55c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardtstatic const struct xt_option_entry string_opts[] = {
56c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	{.name = "from", .id = O_FROM, .type = XTTYPE_UINT16,
57c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	 .flags = XTOPT_PUT, XTOPT_POINTER(s, from_offset)},
58c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	{.name = "to", .id = O_TO, .type = XTTYPE_UINT16,
59c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	 .flags = XTOPT_PUT, XTOPT_POINTER(s, to_offset)},
60c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	{.name = "algo", .id = O_ALGO, .type = XTTYPE_STRING,
61c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, algo)},
62c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	{.name = "string", .id = O_STRING, .type = XTTYPE_STRING,
63c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	 .flags = XTOPT_INVERT, .excl = F_HEX_STRING},
64c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	{.name = "hex-string", .id = O_HEX_STRING, .type = XTTYPE_STRING,
65c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	 .flags = XTOPT_INVERT, .excl = F_STRING},
66c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	{.name = "icase", .id = O_ICASE, .type = XTTYPE_NONE},
67c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	XTOPT_TABLEEND,
683071913784b69423fd25c3db2344e585872920ccEmmanuel Roger};
69c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt#undef s
703071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
71181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void string_init(struct xt_entry_match *m)
72c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira{
736ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	struct xt_string_info *i = (struct xt_string_info *) m->data;
74c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira
75e88a7c2c7175742b58b6aa03f2b5aba2d80330a1Jan Engelhardt	i->to_offset = UINT16_MAX;
76c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira}
77c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira
78c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neirastatic void
796ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAIparse_string(const char *s, struct xt_string_info *info)
803071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
81409f2a8e3b2706c8c6c5e345a4bc77fca8ad7105Pablo Neira Ayuso	/* xt_string does not need \0 at the end of the pattern */
826ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	if (strlen(s) <= XT_STRING_MAX_PATTERN_SIZE) {
836ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI		strncpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE);
84409f2a8e3b2706c8c6c5e345a4bc77fca8ad7105Pablo Neira Ayuso		info->patlen = strnlen(s, XT_STRING_MAX_PATTERN_SIZE);
85c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		return;
86c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	}
871829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt	xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s);
8896d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash}
8996d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash
90c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neirastatic void
916ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAIparse_hex_string(const char *s, struct xt_string_info *info)
9296d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash{
93f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	int i=0, slen, sindex=0, schar;
94f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	short hex_f = 0, literal_f = 0;
95f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	char hextmp[3];
96f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash
97f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	slen = strlen(s);
98f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash
99f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	if (slen == 0) {
1001829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
101f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			"STRING must contain at least one char");
102f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	}
103f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash
104f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	while (i < slen) {
105f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		if (s[i] == '\\' && !hex_f) {
106f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			literal_f = 1;
107f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		} else if (s[i] == '\\') {
1081829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
109f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				"Cannot include literals in hex data");
110f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		} else if (s[i] == '|') {
111f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (hex_f)
112f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				hex_f = 0;
113b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			else {
114f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				hex_f = 1;
115b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash				/* get past any initial whitespace just after the '|' */
116b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash				while (s[i+1] == ' ')
117b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash					i++;
118b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			}
119f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (i+1 >= slen)
120f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				break;
121f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			else
122f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				i++;  /* advance to the next character */
123f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		}
124f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash
125f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		if (literal_f) {
126f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (i+1 >= slen) {
1271829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM,
128f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash					"Bad literal placement at end of string");
129f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			}
130c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			info->pattern[sindex] = s[i+1];
131f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			i += 2;  /* skip over literal char */
132f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			literal_f = 0;
133f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		} else if (hex_f) {
134f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (i+1 >= slen) {
1351829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM,
136f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash					"Odd number of hex digits");
137f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			}
138f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (i+2 >= slen) {
139f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				/* must end with a "|" */
1401829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM, "Invalid hex block");
141f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			}
14296d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash			if (! isxdigit(s[i])) /* check for valid hex char */
1431829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM, "Invalid hex char '%c'", s[i]);
14496d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash			if (! isxdigit(s[i+1])) /* check for valid hex char */
1451829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM, "Invalid hex char '%c'", s[i+1]);
146f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			hextmp[0] = s[i];
147f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			hextmp[1] = s[i+1];
148f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			hextmp[2] = '\0';
149f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (! sscanf(hextmp, "%x", &schar))
1501829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM,
151f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash					"Invalid hex char `%c'", s[i]);
152c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			info->pattern[sindex] = (char) schar;
153f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			if (s[i+2] == ' ')
154f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				i += 3;  /* spaces included in the hex block */
155f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			else
156f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash				i += 2;
157f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		} else {  /* the char is not part of hex data, so just copy */
158c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			info->pattern[sindex] = s[i];
159f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash			i++;
160f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		}
1616ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI		if (sindex > XT_STRING_MAX_PATTERN_SIZE)
1621829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s);
163f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash		sindex++;
164f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash	}
165c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	info->patlen = sindex;
1663071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
1673071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
168c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardtstatic void string_parse(struct xt_option_call *cb)
1693071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
170c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	struct xt_string_info *stringinfo = cb->data;
171c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	const unsigned int revision = (*cb->match)->u.user.revision;
1723071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
173c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	xtables_option_parse(cb);
174c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	switch (cb->entry->id) {
175c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	case O_STRING:
176c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		parse_string(cb->arg, stringinfo);
177c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		if (cb->invert) {
17878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park			if (revision == 0)
17978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				stringinfo->u.v0.invert = 1;
18078d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park			else
18178d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				stringinfo->u.v1.flags |= XT_STRING_FLAG_INVERT;
18278d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		}
18396d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash		break;
184c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	case O_HEX_STRING:
185c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		parse_hex_string(cb->arg, stringinfo);  /* sets length */
186c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		if (cb->invert) {
18778d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park			if (revision == 0)
18878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				stringinfo->u.v0.invert = 1;
18978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park			else
19078d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				stringinfo->u.v1.flags |= XT_STRING_FLAG_INVERT;
19178d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		}
1923071913784b69423fd25c3db2344e585872920ccEmmanuel Roger		break;
193c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	case O_ICASE:
19478d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		if (revision == 0)
1951829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(VERSION_PROBLEM,
19678d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				   "Kernel doesn't support --icase");
19778d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park
19878d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		stringinfo->u.v1.flags |= XT_STRING_FLAG_IGNORECASE;
19978d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park		break;
2003071913784b69423fd25c3db2344e585872920ccEmmanuel Roger	}
2013071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
2023071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
203c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardtstatic void string_check(struct xt_fcheck_call *cb)
2043071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
205c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt	if (!(cb->xflags & F_OP_ANY))
2061829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
207c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			   "STRING match: You must specify `--string' or "
208c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira			   "`--hex-string'");
2093071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
2103071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
211b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash/* Test to see if the string contains non-printable chars or quotes */
212b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashstatic unsigned short int
213b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashis_hex_string(const char *str, const unsigned short int len)
214b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash{
215b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	unsigned int i;
216b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	for (i=0; i < len; i++)
217b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		if (! isprint(str[i]))
218b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			return 1;  /* string contains at least one non-printable char */
219b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	/* use hex output if the last char is a "\" */
220b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	if ((unsigned char) str[len-1] == 0x5c)
221b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		return 1;
222b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	return 0;
223b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash}
224b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash
225b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash/* Print string with "|" chars included as one would pass to --hex-string */
226b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashstatic void
227b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashprint_hex_string(const char *str, const unsigned short int len)
228b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash{
229b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	unsigned int i;
230b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	/* start hex block */
231b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	printf("\"|");
232b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	for (i=0; i < len; i++) {
233b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		/* see if we need to prepend a zero */
234b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		if ((unsigned char) str[i] <= 0x0F)
235b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			printf("0%x", (unsigned char) str[i]);
236b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		else
237b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			printf("%x", (unsigned char) str[i]);
238b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	}
239b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	/* close hex block */
240b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	printf("|\" ");
241b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash}
242b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash
243b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashstatic void
244b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashprint_string(const char *str, const unsigned short int len)
245b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash{
246b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	unsigned int i;
24773866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" \"");
248b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	for (i=0; i < len; i++) {
249b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		if ((unsigned char) str[i] == 0x22)  /* escape any embedded quotes */
250b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash			printf("%c", 0x5c);
251b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash		printf("%c", (unsigned char) str[i]);
252b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	}
25373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf("\"");  /* closing quote */
254b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash}
255451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
2563071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerstatic void
257181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstring_print(const void *ip, const struct xt_entry_match *match, int numeric)
2583071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
2596ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	const struct xt_string_info *info =
2606ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	    (const struct xt_string_info*) match->data;
26178d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	const int revision = match->u.user.revision;
26278d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	int invert = (revision == 0 ? info->u.v0.invert :
26378d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				    info->u.v1.flags & XT_STRING_FLAG_INVERT);
264451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
265c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (is_hex_string(info->pattern, info->patlen)) {
26673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" STRING match %s", invert ? "!" : "");
267c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		print_hex_string(info->pattern, info->patlen);
268b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	} else {
26973866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" STRING match %s", invert ? "!" : "");
270c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		print_string(info->pattern, info->patlen);
271b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	}
27273866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" ALGO name %s", info->algo);
273c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (info->from_offset != 0)
27473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" FROM %u", info->from_offset);
275c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (info->to_offset != 0)
27673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" TO %u", info->to_offset);
27778d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
27873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" ICASE");
2793071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
2803071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
281181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void string_save(const void *ip, const struct xt_entry_match *match)
2823071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
2836ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	const struct xt_string_info *info =
2846ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI	    (const struct xt_string_info*) match->data;
28578d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	const int revision = match->u.user.revision;
28678d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	int invert = (revision == 0 ? info->u.v0.invert :
28778d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park				    info->u.v1.flags & XT_STRING_FLAG_INVERT);
288451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
289c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (is_hex_string(info->pattern, info->patlen)) {
29073866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf("%s --hex-string", (invert) ? " !" : "");
291c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		print_hex_string(info->pattern, info->patlen);
292b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	} else {
29373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf("%s --string", (invert) ? " !": "");
294c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira		print_string(info->pattern, info->patlen);
295b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash	}
29673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" --algo %s", info->algo);
297c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (info->from_offset != 0)
29873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --from %u", info->from_offset);
299c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira	if (info->to_offset != 0)
30073866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --to %u", info->to_offset);
30178d2d14211466f1986882ba6bdf82e6429ce78dcJoonwoo Park	if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
30273866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --icase");
3033071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
3043071913784b69423fd25c3db2344e585872920ccEmmanuel Roger
305451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette
306f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardtstatic struct xtables_match string_mt_reg[] = {
307f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	{
308f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.name          = "string",
309f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.revision      = 0,
310f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.family        = NFPROTO_UNSPEC,
311f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.version       = XTABLES_VERSION,
312f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.size          = XT_ALIGN(sizeof(struct xt_string_info)),
313f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.userspacesize = offsetof(struct xt_string_info, config),
314f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.help          = string_help,
315f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.init          = string_init,
316f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.print         = string_print,
317f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.save          = string_save,
318c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		.x6_parse      = string_parse,
319c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		.x6_fcheck     = string_check,
320c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		.x6_options    = string_opts,
321f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	},
322f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	{
323f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.name          = "string",
324f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.revision      = 1,
325f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.family        = NFPROTO_UNSPEC,
326f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.version       = XTABLES_VERSION,
327f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.size          = XT_ALIGN(sizeof(struct xt_string_info)),
328f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.userspacesize = offsetof(struct xt_string_info, config),
329f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.help          = string_help,
330f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.init          = string_init,
331f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.print         = string_print,
332f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.save          = string_save,
333c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		.x6_parse      = string_parse,
334c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		.x6_fcheck     = string_check,
335c618a0b1d3696c30f7791a427da9ba60186dfe05Jan Engelhardt		.x6_options    = string_opts,
336f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	},
3374ccb6f547b6c2c355a188a267afe6358b013a438Yasuyuki KOZAKAI};
3384ccb6f547b6c2c355a188a267afe6358b013a438Yasuyuki KOZAKAI
3393071913784b69423fd25c3db2344e585872920ccEmmanuel Rogervoid _init(void)
3403071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{
341f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	xtables_register_matches(string_mt_reg, ARRAY_SIZE(string_mt_reg));
3423071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}
343