/* Shared library add-on to iptables to add string matching support. * * Copyright (C) 2000 Emmanuel Roger * * ChangeLog * 27.01.2001: Gianni Tedesco * Changed --tos to --string in save(). Also * updated to work with slightly modified * ipt_string_info. */ #include #include #include #include #include #include #include #include /* Function which prints out usage message. */ static void help(void) { printf( "STRING match v%s options:\n" "--string [!] string Match a string in a packet\n", IPTABLES_VERSION); fputc('\n', stdout); } static struct option opts[] = { { "string", 1, 0, '1' }, {0} }; /* Initialize the match. */ static void init(struct ipt_entry_match *m, unsigned int *nfcache) { *nfcache |= NFC_UNKNOWN; } static void parse_string(const unsigned char *s, struct ipt_string_info *info) { int i=0, slen, sindex=0, schar; short hex_f = 0, literal_f = 0; char hextmp[3]; slen = strlen(s); if (slen == 0) { exit_error(PARAMETER_PROBLEM, "STRING must contain at least one char"); } while (i < slen) { if (s[i] == '\\' && !hex_f) { literal_f = 1; } else if (s[i] == '\\') { exit_error(PARAMETER_PROBLEM, "Cannot include literals in hex data"); } else if (s[i] == '|') { if (hex_f) hex_f = 0; else hex_f = 1; if (i+1 >= slen) break; else i++; /* advance to the next character */ } if (literal_f) { if (i+1 >= slen) { exit_error(PARAMETER_PROBLEM, "Bad literal placement at end of string"); } info->string[sindex] = s[i+1]; i += 2; /* skip over literal char */ literal_f = 0; } else if (hex_f) { if (i+1 >= slen) { exit_error(PARAMETER_PROBLEM, "Odd number of hex digits"); } if (i+2 >= slen) { /* must end with a "|" */ exit_error(PARAMETER_PROBLEM, "Invalid hex block"); } hextmp[0] = s[i]; hextmp[1] = s[i+1]; hextmp[2] = '\0'; if (! sscanf(hextmp, "%x", &schar)) exit_error(PARAMETER_PROBLEM, "Invalid hex char `%c'", s[i]); info->string[sindex] = (char) schar; if (s[i+2] == ' ') i += 3; /* spaces included in the hex block */ else i += 2; } else { /* the char is not part of hex data, so just copy */ info->string[sindex] = s[i]; i++; } if (sindex > BM_MAX_NLEN) exit_error(PARAMETER_PROBLEM, "STRING too long `%s'", s); sindex++; } } /* Function which parses command options; returns true if it ate an option */ static int parse(int c, char **argv, int invert, unsigned int *flags, const struct ipt_entry *entry, unsigned int *nfcache, struct ipt_entry_match **match) { struct ipt_string_info *stringinfo = (struct ipt_string_info *)(*match)->data; switch (c) { case '1': check_inverse(optarg, &invert, &optind, 0); parse_string(argv[optind-1], stringinfo); if (invert) stringinfo->invert = 1; stringinfo->len=strlen((char *)&stringinfo->string); *flags = 1; break; default: return 0; } return 1; } static void print_string(char string[], int invert, int numeric) { if (invert) fputc('!', stdout); printf("%s ",string); } /* Final check; must have specified --string. */ static void final_check(unsigned int flags) { if (!flags) exit_error(PARAMETER_PROBLEM, "STRING match: You must specify `--string'"); } /* Prints out the matchinfo. */ static void print(const struct ipt_ip *ip, const struct ipt_entry_match *match, int numeric) { printf("STRING match "); print_string(((struct ipt_string_info *)match->data)->string, ((struct ipt_string_info *)match->data)->invert, numeric); } /* Saves the union ipt_matchinfo in parsable form to stdout. */ static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) { printf("--string "); print_string(((struct ipt_string_info *)match->data)->string, ((struct ipt_string_info *)match->data)->invert, 0); } static struct iptables_match string = { NULL, "string", IPTABLES_VERSION, IPT_ALIGN(sizeof(struct ipt_string_info)), IPT_ALIGN(sizeof(struct ipt_string_info)), &help, &init, &parse, &final_check, &print, &save, opts }; void _init(void) { register_match(&string); }