1/* Shared library add-on to ip6tables to add packet length matching support. */ 2 3#include <stdio.h> 4#include <netdb.h> 5#include <string.h> 6#include <stdlib.h> 7#include <getopt.h> 8 9#include <ip6tables.h> 10#include <linux/netfilter_ipv6/ip6t_length.h> 11 12/* Function which prints out usage message. */ 13static void 14help(void) 15{ 16 printf( 17"length v%s options:\n" 18"[!] --length length[:length] Match packet length against value or range\n" 19" of values (inclusive)\n", 20IPTABLES_VERSION); 21 22} 23 24static struct option opts[] = { 25 { "length", 1, 0, '1' }, 26 {0} 27}; 28 29/* Initialize the match. */ 30static void 31init(struct ip6t_entry_match *m, unsigned int *nfcache) 32{ 33 *nfcache |= NFC_UNKNOWN; 34} 35 36static u_int16_t 37parse_length(const char *s) 38{ 39 40 int len; 41 42 if (string_to_number(s, 0, 0xFFFF, &len) == -1) 43 exit_error(PARAMETER_PROBLEM, "length invalid: `%s'\n", s); 44 else 45 return (u_int16_t )len; 46} 47 48/* If a single value is provided, min and max are both set to the value */ 49static void 50parse_lengths(const char *s, struct ip6t_length_info *info) 51{ 52 char *buffer; 53 char *cp; 54 55 buffer = strdup(s); 56 if ((cp = strchr(buffer, ':')) == NULL) 57 info->min = info->max = parse_length(buffer); 58 else { 59 *cp = '\0'; 60 cp++; 61 62 info->min = buffer[0] ? parse_length(buffer) : 0; 63 info->max = cp[0] ? parse_length(cp) : 0xFFFF; 64 } 65 free(buffer); 66 67 if (info->min > info->max) 68 exit_error(PARAMETER_PROBLEM, 69 "length min. range value `%u' greater than max. " 70 "range value `%u'", info->min, info->max); 71 72} 73 74/* Function which parses command options; returns true if it 75 ate an option */ 76static int 77parse(int c, char **argv, int invert, unsigned int *flags, 78 const struct ip6t_entry *entry, 79 unsigned int *nfcache, 80 struct ip6t_entry_match **match) 81{ 82 struct ip6t_length_info *info = (struct ip6t_length_info *)(*match)->data; 83 84 switch (c) { 85 case '1': 86 if (*flags) 87 exit_error(PARAMETER_PROBLEM, 88 "length: `--length' may only be " 89 "specified once"); 90 check_inverse(optarg, &invert, &optind, 0); 91 parse_lengths(argv[optind-1], info); 92 if (invert) 93 info->invert = 1; 94 *flags = 1; 95 break; 96 97 default: 98 return 0; 99 } 100 return 1; 101} 102 103/* Final check; must have specified --length. */ 104static void 105final_check(unsigned int flags) 106{ 107 if (!flags) 108 exit_error(PARAMETER_PROBLEM, 109 "length: You must specify `--length'"); 110} 111 112/* Common match printing code. */ 113static void 114print_length(struct ip6t_length_info *info) 115{ 116 if (info->invert) 117 fputc('!', stdout); 118 119 if (info->max == info->min) 120 printf("%u ", info->min); 121 else 122 printf("%u:%u ", info->min, info->max); 123} 124 125/* Prints out the matchinfo. */ 126static void 127print(const struct ip6t_ip6 *ip, 128 const struct ip6t_entry_match *match, 129 int numeric) 130{ 131 printf("length "); 132 print_length((struct ip6t_length_info *)match->data); 133} 134 135/* Saves the union ip6t_matchinfo in parsable form to stdout. */ 136static void 137save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) 138{ 139 printf("--length "); 140 print_length((struct ip6t_length_info *)match->data); 141} 142 143struct ip6tables_match length 144= { NULL, 145 "length", 146 IPTABLES_VERSION, 147 IP6T_ALIGN(sizeof(struct ip6t_length_info)), 148 IP6T_ALIGN(sizeof(struct ip6t_length_info)), 149 &help, 150 &init, 151 &parse, 152 &final_check, 153 &print, 154 &save, 155 opts 156}; 157 158void _init(void) 159{ 160 register_match6(&length); 161} 162