libxt_string.c revision 6ac58e399ccb3c2fbadc373266f454ce301547da
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 <netdb.h> 253071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <string.h> 263071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <stdlib.h> 273071913784b69423fd25c3db2344e585872920ccEmmanuel Roger#include <getopt.h> 28f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash#include <ctype.h> 296ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI#include <xtables.h> 30c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira#include <stddef.h> 316ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI#include <linux/netfilter/xt_string.h> 323071913784b69423fd25c3db2344e585872920ccEmmanuel Roger 333071913784b69423fd25c3db2344e585872920ccEmmanuel Roger/* Function which prints out usage message. */ 343071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerstatic void 353071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerhelp(void) 363071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{ 373071913784b69423fd25c3db2344e585872920ccEmmanuel Roger printf( 383071913784b69423fd25c3db2344e585872920ccEmmanuel Roger"STRING match v%s options:\n" 39c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira"--from Offset to start searching from\n" 40c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira"--to Offset to stop searching\n" 41c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira"--algo Algorithm\n" 4296d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash"--string [!] string Match a string in a packet\n" 4396d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash"--hex-string [!] string Match a hex string in a packet\n", 4480fe35d6339b53a12ddaec41885613e4e37ed031Harald WelteIPTABLES_VERSION); 453071913784b69423fd25c3db2344e585872920ccEmmanuel Roger} 463071913784b69423fd25c3db2344e585872920ccEmmanuel Roger 473071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerstatic struct option opts[] = { 48c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira { "from", 1, 0, '1' }, 49c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira { "to", 1, 0, '2' }, 50c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira { "algo", 1, 0, '3' }, 51c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira { "string", 1, 0, '4' }, 52c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira { "hex-string", 1, 0, '5' }, 53c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira {0} 543071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}; 553071913784b69423fd25c3db2344e585872920ccEmmanuel Roger 563071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerstatic void 57193df8ee3507f0c02762c88a16916c4ea950bd99Yasuyuki KOZAKAIinit(struct xt_entry_match *m, unsigned int *nfcache) 58c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira{ 596ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI struct xt_string_info *i = (struct xt_string_info *) m->data; 60c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira 61c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (i->to_offset == 0) 62c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira i->to_offset = (u_int16_t) ~0UL; 63c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira} 64c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira 65c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neirastatic void 666ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAIparse_string(const char *s, struct xt_string_info *info) 673071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{ 686ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI if (strlen(s) <= XT_STRING_MAX_PATTERN_SIZE) { 696ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI strncpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE); 70c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira info->patlen = strlen(s); 71c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira return; 72c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira } 73c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira exit_error(PARAMETER_PROBLEM, "STRING too long `%s'", s); 7496d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash} 7596d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash 76c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neirastatic void 776ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAIparse_algo(const char *s, struct xt_string_info *info) 78c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira{ 796ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI if (strlen(s) <= XT_STRING_MAX_ALGO_NAME_SIZE) { 806ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI strncpy(info->algo, s, XT_STRING_MAX_ALGO_NAME_SIZE); 81c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira return; 82c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira } 83c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira exit_error(PARAMETER_PROBLEM, "ALGO too long `%s'", s); 84c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira} 85451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette 8696d8593fffe816b3ee1bcd27df33beff5c404058Michael Rashstatic void 876ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAIparse_hex_string(const char *s, struct xt_string_info *info) 8896d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash{ 89f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash int i=0, slen, sindex=0, schar; 90f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash short hex_f = 0, literal_f = 0; 91f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash char hextmp[3]; 92f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash 93f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash slen = strlen(s); 94f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash 95f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash if (slen == 0) { 96f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash exit_error(PARAMETER_PROBLEM, 97f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash "STRING must contain at least one char"); 98f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash } 99f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash 100f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash while (i < slen) { 101f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash if (s[i] == '\\' && !hex_f) { 102f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash literal_f = 1; 103f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash } else if (s[i] == '\\') { 104f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash exit_error(PARAMETER_PROBLEM, 105f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash "Cannot include literals in hex data"); 106f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash } else if (s[i] == '|') { 107f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash if (hex_f) 108f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash hex_f = 0; 109b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash else { 110f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash hex_f = 1; 111b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash /* get past any initial whitespace just after the '|' */ 112b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash while (s[i+1] == ' ') 113b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash i++; 114b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash } 115f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash if (i+1 >= slen) 116f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash break; 117f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash else 118f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash i++; /* advance to the next character */ 119f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash } 120f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash 121f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash if (literal_f) { 122f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash if (i+1 >= slen) { 123f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash exit_error(PARAMETER_PROBLEM, 124f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash "Bad literal placement at end of string"); 125f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash } 126c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira info->pattern[sindex] = s[i+1]; 127f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash i += 2; /* skip over literal char */ 128f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash literal_f = 0; 129f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash } else if (hex_f) { 130f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash if (i+1 >= slen) { 131f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash exit_error(PARAMETER_PROBLEM, 132f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash "Odd number of hex digits"); 133f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash } 134f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash if (i+2 >= slen) { 135f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash /* must end with a "|" */ 136f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash exit_error(PARAMETER_PROBLEM, "Invalid hex block"); 137f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash } 13896d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash if (! isxdigit(s[i])) /* check for valid hex char */ 13996d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash exit_error(PARAMETER_PROBLEM, "Invalid hex char `%c'", s[i]); 14096d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash if (! isxdigit(s[i+1])) /* check for valid hex char */ 14196d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash exit_error(PARAMETER_PROBLEM, "Invalid hex char `%c'", s[i+1]); 142f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash hextmp[0] = s[i]; 143f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash hextmp[1] = s[i+1]; 144f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash hextmp[2] = '\0'; 145f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash if (! sscanf(hextmp, "%x", &schar)) 146f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash exit_error(PARAMETER_PROBLEM, 147f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash "Invalid hex char `%c'", s[i]); 148c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira info->pattern[sindex] = (char) schar; 149f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash if (s[i+2] == ' ') 150f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash i += 3; /* spaces included in the hex block */ 151f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash else 152f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash i += 2; 153f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash } else { /* the char is not part of hex data, so just copy */ 154c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira info->pattern[sindex] = s[i]; 155f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash i++; 156f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash } 1576ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI if (sindex > XT_STRING_MAX_PATTERN_SIZE) 158f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash exit_error(PARAMETER_PROBLEM, "STRING too long `%s'", s); 159f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash sindex++; 160f8ac329cc9a8822273aefc6686d58cae07e8a8f9Michael Rash } 161c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira info->patlen = sindex; 1623071913784b69423fd25c3db2344e585872920ccEmmanuel Roger} 1633071913784b69423fd25c3db2344e585872920ccEmmanuel Roger 164c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira#define STRING 0x1 165c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira#define ALGO 0x2 166c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira#define FROM 0x4 167c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira#define TO 0x8 168451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette 1693071913784b69423fd25c3db2344e585872920ccEmmanuel Roger/* Function which parses command options; returns true if it 1703071913784b69423fd25c3db2344e585872920ccEmmanuel Roger ate an option */ 1713071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerstatic int 1723071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerparse(int c, char **argv, int invert, unsigned int *flags, 173c0a9ab93f49a3d2508c95d0ca1a01c1089983731Yasuyuki KOZAKAI const void *entry, 1743071913784b69423fd25c3db2344e585872920ccEmmanuel Roger unsigned int *nfcache, 175193df8ee3507f0c02762c88a16916c4ea950bd99Yasuyuki KOZAKAI struct xt_entry_match **match) 1763071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{ 1776ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI struct xt_string_info *stringinfo = (struct xt_string_info *)(*match)->data; 1783071913784b69423fd25c3db2344e585872920ccEmmanuel Roger 1793071913784b69423fd25c3db2344e585872920ccEmmanuel Roger switch (c) { 1803071913784b69423fd25c3db2344e585872920ccEmmanuel Roger case '1': 181c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (*flags & FROM) 182451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette exit_error(PARAMETER_PROBLEM, 183c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira "Can't specify multiple --from"); 184c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira stringinfo->from_offset = atoi(optarg); 185c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira *flags |= FROM; 186c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira break; 187c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira case '2': 188c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (*flags & TO) 189c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira exit_error(PARAMETER_PROBLEM, 190c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira "Can't specify multiple --to"); 191c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira stringinfo->to_offset = atoi(optarg); 192c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira *flags |= TO; 193c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira break; 194c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira case '3': 195c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (*flags & ALGO) 196c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira exit_error(PARAMETER_PROBLEM, 197c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira "Can't specify multiple --algo"); 198c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira parse_algo(optarg, stringinfo); 199c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira *flags |= ALGO; 200c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira break; 201c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira case '4': 202c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (*flags & STRING) 203c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira exit_error(PARAMETER_PROBLEM, 204c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira "Can't specify multiple --string"); 205b77f1dafb9f35752bb9685323bcacb32a0e6ddc5Harald Welte check_inverse(optarg, &invert, &optind, 0); 2063071913784b69423fd25c3db2344e585872920ccEmmanuel Roger parse_string(argv[optind-1], stringinfo); 2073071913784b69423fd25c3db2344e585872920ccEmmanuel Roger if (invert) 2083071913784b69423fd25c3db2344e585872920ccEmmanuel Roger stringinfo->invert = 1; 209c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira stringinfo->patlen=strlen((char *)&stringinfo->pattern); 210c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira *flags |= STRING; 21196d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash break; 21296d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash 213c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira case '5': 214c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (*flags & STRING) 215451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette exit_error(PARAMETER_PROBLEM, 216c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira "Can't specify multiple --hex-string"); 217451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette 21896d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash check_inverse(optarg, &invert, &optind, 0); 21996d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash parse_hex_string(argv[optind-1], stringinfo); /* sets length */ 22096d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash if (invert) 22196d8593fffe816b3ee1bcd27df33beff5c404058Michael Rash stringinfo->invert = 1; 222c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira *flags |= STRING; 2233071913784b69423fd25c3db2344e585872920ccEmmanuel Roger break; 2243071913784b69423fd25c3db2344e585872920ccEmmanuel Roger 2253071913784b69423fd25c3db2344e585872920ccEmmanuel Roger default: 2263071913784b69423fd25c3db2344e585872920ccEmmanuel Roger return 0; 2273071913784b69423fd25c3db2344e585872920ccEmmanuel Roger } 2283071913784b69423fd25c3db2344e585872920ccEmmanuel Roger return 1; 2293071913784b69423fd25c3db2344e585872920ccEmmanuel Roger} 2303071913784b69423fd25c3db2344e585872920ccEmmanuel Roger 2313071913784b69423fd25c3db2344e585872920ccEmmanuel Roger 2323071913784b69423fd25c3db2344e585872920ccEmmanuel Roger/* Final check; must have specified --string. */ 2333071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerstatic void 2343071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerfinal_check(unsigned int flags) 2353071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{ 236c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (!(flags & STRING)) 237c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira exit_error(PARAMETER_PROBLEM, 238c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira "STRING match: You must specify `--string' or " 239c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira "`--hex-string'"); 240c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (!(flags & ALGO)) 2413071913784b69423fd25c3db2344e585872920ccEmmanuel Roger exit_error(PARAMETER_PROBLEM, 242c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira "STRING match: You must specify `--algo'"); 2433071913784b69423fd25c3db2344e585872920ccEmmanuel Roger} 2443071913784b69423fd25c3db2344e585872920ccEmmanuel Roger 245b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash/* Test to see if the string contains non-printable chars or quotes */ 246b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashstatic unsigned short int 247b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashis_hex_string(const char *str, const unsigned short int len) 248b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash{ 249b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash unsigned int i; 250b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash for (i=0; i < len; i++) 251b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash if (! isprint(str[i])) 252b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash return 1; /* string contains at least one non-printable char */ 253b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash /* use hex output if the last char is a "\" */ 254b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash if ((unsigned char) str[len-1] == 0x5c) 255b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash return 1; 256b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash return 0; 257b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash} 258b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash 259b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash/* Print string with "|" chars included as one would pass to --hex-string */ 260b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashstatic void 261b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashprint_hex_string(const char *str, const unsigned short int len) 262b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash{ 263b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash unsigned int i; 264b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash /* start hex block */ 265b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash printf("\"|"); 266b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash for (i=0; i < len; i++) { 267b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash /* see if we need to prepend a zero */ 268b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash if ((unsigned char) str[i] <= 0x0F) 269b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash printf("0%x", (unsigned char) str[i]); 270b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash else 271b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash printf("%x", (unsigned char) str[i]); 272b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash } 273b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash /* close hex block */ 274b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash printf("|\" "); 275b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash} 276b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash 277b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashstatic void 278b807fb348369d852d031056f1c911f5b2b4c2114Michael Rashprint_string(const char *str, const unsigned short int len) 279b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash{ 280b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash unsigned int i; 281b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash printf("\""); 282b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash for (i=0; i < len; i++) { 283b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash if ((unsigned char) str[i] == 0x22) /* escape any embedded quotes */ 284b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash printf("%c", 0x5c); 285b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash printf("%c", (unsigned char) str[i]); 286b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash } 287b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash printf("\" "); /* closing space and quote */ 288b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash} 289451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette 2903071913784b69423fd25c3db2344e585872920ccEmmanuel Roger/* Prints out the matchinfo. */ 2913071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerstatic void 292c0a9ab93f49a3d2508c95d0ca1a01c1089983731Yasuyuki KOZAKAIprint(const void *ip, 293193df8ee3507f0c02762c88a16916c4ea950bd99Yasuyuki KOZAKAI const struct xt_entry_match *match, 2943071913784b69423fd25c3db2344e585872920ccEmmanuel Roger int numeric) 2953071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{ 2966ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI const struct xt_string_info *info = 2976ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI (const struct xt_string_info*) match->data; 298451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette 299c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (is_hex_string(info->pattern, info->patlen)) { 300b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash printf("STRING match %s", (info->invert) ? "!" : ""); 301c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira print_hex_string(info->pattern, info->patlen); 302b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash } else { 303b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash printf("STRING match %s", (info->invert) ? "!" : ""); 304c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira print_string(info->pattern, info->patlen); 305b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash } 306c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira printf("ALGO name %s ", info->algo); 307c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (info->from_offset != 0) 308c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira printf("FROM %u ", info->from_offset); 309c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (info->to_offset != 0) 3108a0b6ead35931422fbe02c63d9262ad9e40daaccPatrick McHardy printf("TO %u ", info->to_offset); 3113071913784b69423fd25c3db2344e585872920ccEmmanuel Roger} 3123071913784b69423fd25c3db2344e585872920ccEmmanuel Roger 313451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette 314451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette/* Saves the union ipt_matchinfo in parseable form to stdout. */ 3153071913784b69423fd25c3db2344e585872920ccEmmanuel Rogerstatic void 316c0a9ab93f49a3d2508c95d0ca1a01c1089983731Yasuyuki KOZAKAIsave(const void *ip, const struct xt_entry_match *match) 3173071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{ 3186ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI const struct xt_string_info *info = 3196ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI (const struct xt_string_info*) match->data; 320451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette 321c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (is_hex_string(info->pattern, info->patlen)) { 322b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash printf("--hex-string %s", (info->invert) ? "! ": ""); 323c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira print_hex_string(info->pattern, info->patlen); 324b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash } else { 325b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash printf("--string %s", (info->invert) ? "! ": ""); 326c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira print_string(info->pattern, info->patlen); 327b807fb348369d852d031056f1c911f5b2b4c2114Michael Rash } 328c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira printf("--algo %s ", info->algo); 329c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (info->from_offset != 0) 3300829a2b72caa06c07e6eb710a81a04295c9f2621Michael Rash printf("--from %u ", info->from_offset); 331c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira if (info->to_offset != 0) 3320829a2b72caa06c07e6eb710a81a04295c9f2621Michael Rash printf("--to %u ", info->to_offset); 3333071913784b69423fd25c3db2344e585872920ccEmmanuel Roger} 3343071913784b69423fd25c3db2344e585872920ccEmmanuel Roger 335451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette 3366ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAIstatic struct xtables_match string = { 337c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira .name = "string", 3386ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI .family = AF_INET, 339c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira .version = IPTABLES_VERSION, 3406ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI .size = XT_ALIGN(sizeof(struct xt_string_info)), 3416ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI .userspacesize = offsetof(struct xt_string_info, config), 342c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira .help = help, 343c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira .init = init, 344c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira .parse = parse, 345c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira .final_check = final_check, 346c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira .print = print, 347c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira .save = save, 348c6fbf41cdd15705559269d992da9938cbb1a1f4ePablo Neira .extra_opts = opts 3493071913784b69423fd25c3db2344e585872920ccEmmanuel Roger}; 3503071913784b69423fd25c3db2344e585872920ccEmmanuel Roger 351451f3eaad6712ba790aeba1a5af41ef9ee007d68Stephane Ouellette 3523071913784b69423fd25c3db2344e585872920ccEmmanuel Rogervoid _init(void) 3533071913784b69423fd25c3db2344e585872920ccEmmanuel Roger{ 3546ac58e399ccb3c2fbadc373266f454ce301547daYasuyuki KOZAKAI xtables_register_match(&string); 3553071913784b69423fd25c3db2344e585872920ccEmmanuel Roger} 356