libip6t_frag.c revision 997045f536026c0d643bf884da5ff5de2605197f
1/* Shared library add-on to ip6tables to add Fragmentation header support. */ 2#include <stdio.h> 3#include <netdb.h> 4#include <string.h> 5#include <stdlib.h> 6#include <getopt.h> 7#include <errno.h> 8#include <ip6tables.h> 9#include <linux/netfilter_ipv6/ip6t_frag.h> 10 11/* Function which prints out usage message. */ 12static void frag_help(void) 13{ 14 printf( 15"FRAG v%s options:\n" 16" --fragid [!] id[:id] match the id (range)\n" 17" --fraglen [!] length total length of this header\n" 18" --fragres check the reserved filed, too\n" 19" --fragfirst matches on the first fragment\n" 20" [--fragmore|--fraglast] there are more fragments or this\n" 21" is the last one\n", 22IPTABLES_VERSION); 23} 24 25static const struct option frag_opts[] = { 26 { .name = "fragid", .has_arg = 1, .val = '1' }, 27 { .name = "fraglen", .has_arg = 1, .val = '2' }, 28 { .name = "fragres", .has_arg = 0, .val = '3' }, 29 { .name = "fragfirst", .has_arg = 0, .val = '4' }, 30 { .name = "fragmore", .has_arg = 0, .val = '5' }, 31 { .name = "fraglast", .has_arg = 0, .val = '6' }, 32 { } 33}; 34 35static u_int32_t 36parse_frag_id(const char *idstr, const char *typestr) 37{ 38 unsigned long int id; 39 char* ep; 40 41 id = strtoul(idstr, &ep, 0); 42 43 if ( idstr == ep ) { 44 exit_error(PARAMETER_PROBLEM, 45 "FRAG no valid digits in %s `%s'", typestr, idstr); 46 } 47 if ( id == ULONG_MAX && errno == ERANGE ) { 48 exit_error(PARAMETER_PROBLEM, 49 "%s `%s' specified too big: would overflow", 50 typestr, idstr); 51 } 52 if ( *idstr != '\0' && *ep != '\0' ) { 53 exit_error(PARAMETER_PROBLEM, 54 "FRAG error parsing %s `%s'", typestr, idstr); 55 } 56 return (u_int32_t) id; 57} 58 59static void 60parse_frag_ids(const char *idstring, u_int32_t *ids) 61{ 62 char *buffer; 63 char *cp; 64 65 buffer = strdup(idstring); 66 if ((cp = strchr(buffer, ':')) == NULL) 67 ids[0] = ids[1] = parse_frag_id(buffer,"id"); 68 else { 69 *cp = '\0'; 70 cp++; 71 72 ids[0] = buffer[0] ? parse_frag_id(buffer,"id") : 0; 73 ids[1] = cp[0] ? parse_frag_id(cp,"id") : 0xFFFFFFFF; 74 } 75 free(buffer); 76} 77 78/* Initialize the match. */ 79static void frag_init(struct xt_entry_match *m) 80{ 81 struct ip6t_frag *fraginfo = (struct ip6t_frag *)m->data; 82 83 fraginfo->ids[0] = 0x0L; 84 fraginfo->ids[1] = 0xFFFFFFFF; 85 fraginfo->hdrlen = 0; 86 fraginfo->flags = 0; 87 fraginfo->invflags = 0; 88} 89 90/* Function which parses command options; returns true if it 91 ate an option */ 92static int frag_parse(int c, char **argv, int invert, unsigned int *flags, 93 const void *entry, struct xt_entry_match **match) 94{ 95 struct ip6t_frag *fraginfo = (struct ip6t_frag *)(*match)->data; 96 97 switch (c) { 98 case '1': 99 if (*flags & IP6T_FRAG_IDS) 100 exit_error(PARAMETER_PROBLEM, 101 "Only one `--fragid' allowed"); 102 check_inverse(optarg, &invert, &optind, 0); 103 parse_frag_ids(argv[optind-1], fraginfo->ids); 104 if (invert) 105 fraginfo->invflags |= IP6T_FRAG_INV_IDS; 106 fraginfo->flags |= IP6T_FRAG_IDS; 107 *flags |= IP6T_FRAG_IDS; 108 break; 109 case '2': 110 if (*flags & IP6T_FRAG_LEN) 111 exit_error(PARAMETER_PROBLEM, 112 "Only one `--fraglen' allowed"); 113 check_inverse(optarg, &invert, &optind, 0); 114 fraginfo->hdrlen = parse_frag_id(argv[optind-1], "length"); 115 if (invert) 116 fraginfo->invflags |= IP6T_FRAG_INV_LEN; 117 fraginfo->flags |= IP6T_FRAG_LEN; 118 *flags |= IP6T_FRAG_LEN; 119 break; 120 case '3': 121 if (*flags & IP6T_FRAG_RES) 122 exit_error(PARAMETER_PROBLEM, 123 "Only one `--fragres' allowed"); 124 fraginfo->flags |= IP6T_FRAG_RES; 125 *flags |= IP6T_FRAG_RES; 126 break; 127 case '4': 128 if (*flags & IP6T_FRAG_FST) 129 exit_error(PARAMETER_PROBLEM, 130 "Only one `--fragfirst' allowed"); 131 fraginfo->flags |= IP6T_FRAG_FST; 132 *flags |= IP6T_FRAG_FST; 133 break; 134 case '5': 135 if (*flags & (IP6T_FRAG_MF|IP6T_FRAG_NMF)) 136 exit_error(PARAMETER_PROBLEM, 137 "Only one `--fragmore' or `--fraglast' allowed"); 138 fraginfo->flags |= IP6T_FRAG_MF; 139 *flags |= IP6T_FRAG_MF; 140 break; 141 case '6': 142 if (*flags & (IP6T_FRAG_MF|IP6T_FRAG_NMF)) 143 exit_error(PARAMETER_PROBLEM, 144 "Only one `--fragmore' or `--fraglast' allowed"); 145 fraginfo->flags |= IP6T_FRAG_NMF; 146 *flags |= IP6T_FRAG_NMF; 147 break; 148 default: 149 return 0; 150 } 151 152 return 1; 153} 154 155static void 156print_ids(const char *name, u_int32_t min, u_int32_t max, 157 int invert) 158{ 159 const char *inv = invert ? "!" : ""; 160 161 if (min != 0 || max != 0xFFFFFFFF || invert) { 162 printf("%s", name); 163 if (min == max) 164 printf(":%s%u ", inv, min); 165 else 166 printf("s:%s%u:%u ", inv, min, max); 167 } 168} 169 170/* Prints out the union ip6t_matchinfo. */ 171static void frag_print(const void *ip, const struct xt_entry_match *match, 172 int numeric) 173{ 174 const struct ip6t_frag *frag = (struct ip6t_frag *)match->data; 175 176 printf("frag "); 177 print_ids("id", frag->ids[0], frag->ids[1], 178 frag->invflags & IP6T_FRAG_INV_IDS); 179 180 if (frag->flags & IP6T_FRAG_LEN) { 181 printf("length:%s%u ", 182 frag->invflags & IP6T_FRAG_INV_LEN ? "!" : "", 183 frag->hdrlen); 184 } 185 186 if (frag->flags & IP6T_FRAG_RES) 187 printf("reserved "); 188 189 if (frag->flags & IP6T_FRAG_FST) 190 printf("first "); 191 192 if (frag->flags & IP6T_FRAG_MF) 193 printf("more "); 194 195 if (frag->flags & IP6T_FRAG_NMF) 196 printf("last "); 197 198 if (frag->invflags & ~IP6T_FRAG_INV_MASK) 199 printf("Unknown invflags: 0x%X ", 200 frag->invflags & ~IP6T_FRAG_INV_MASK); 201} 202 203/* Saves the union ip6t_matchinfo in parsable form to stdout. */ 204static void frag_save(const void *ip, const struct xt_entry_match *match) 205{ 206 const struct ip6t_frag *fraginfo = (struct ip6t_frag *)match->data; 207 208 if (!(fraginfo->ids[0] == 0 209 && fraginfo->ids[1] == 0xFFFFFFFF)) { 210 printf("--fragid %s", 211 (fraginfo->invflags & IP6T_FRAG_INV_IDS) ? "! " : ""); 212 if (fraginfo->ids[0] 213 != fraginfo->ids[1]) 214 printf("%u:%u ", 215 fraginfo->ids[0], 216 fraginfo->ids[1]); 217 else 218 printf("%u ", 219 fraginfo->ids[0]); 220 } 221 222 if (fraginfo->flags & IP6T_FRAG_LEN) { 223 printf("--fraglen %s%u ", 224 (fraginfo->invflags & IP6T_FRAG_INV_LEN) ? "! " : "", 225 fraginfo->hdrlen); 226 } 227 228 if (fraginfo->flags & IP6T_FRAG_RES) 229 printf("--fragres "); 230 231 if (fraginfo->flags & IP6T_FRAG_FST) 232 printf("--fragfirst "); 233 234 if (fraginfo->flags & IP6T_FRAG_MF) 235 printf("--fragmore "); 236 237 if (fraginfo->flags & IP6T_FRAG_NMF) 238 printf("--fraglast "); 239} 240 241static struct ip6tables_match frag_match6 = { 242 .name = "frag", 243 .version = IPTABLES_VERSION, 244 .size = IP6T_ALIGN(sizeof(struct ip6t_frag)), 245 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_frag)), 246 .help = frag_help, 247 .init = frag_init, 248 .parse = frag_parse, 249 .print = frag_print, 250 .save = frag_save, 251 .extra_opts = frag_opts, 252}; 253 254void 255_init(void) 256{ 257 register_match6(&frag_match6); 258} 259