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