libip6t_dst.c revision ea146a982e26c42f9954f140276f8deeb2edbe98
1/* Shared library add-on to ip6tables to add Hop-by-Hop and Dst headers 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_opts.h> 10#include <sys/types.h> 11#include <sys/socket.h> 12#include <arpa/inet.h> 13 14#ifdef HOPBYHOP 15#define UNAME "HBH" 16#define LNAME "hbh" 17#else 18#define UNAME "DST" 19#define LNAME "dst" 20#endif 21 22/* Function which prints out usage message. */ 23static void 24help(void) 25{ 26 printf( 27UNAME " v%s options:\n" 28" --" LNAME "-len [!] length total length of this header\n" 29" --" LNAME "-opts TYPE[:LEN][,TYPE[:LEN]...] \n" 30" Options and its length (list, max: %d)\n", 31IPTABLES_VERSION, IP6T_OPTS_OPTSNR); 32} 33 34static const struct option opts[] = { 35 { .name = LNAME "-len", .has_arg = 1, .flag = 0, .val = '1' }, 36 { .name = LNAME "-opts", .has_arg = 1, .flag = 0, .val = '2' }, 37 { .name = LNAME "-not-strict", .has_arg = 1, .flag = 0, .val = '3' }, 38 { .name = 0 } 39}; 40 41static u_int32_t 42parse_opts_num(const char *idstr, const char *typestr) 43{ 44 unsigned long int id; 45 char* ep; 46 47 id = strtoul(idstr, &ep, 0); 48 49 if ( idstr == ep ) { 50 exit_error(PARAMETER_PROBLEM, 51 UNAME " no valid digits in %s `%s'", typestr, idstr); 52 } 53 if ( id == ULONG_MAX && errno == ERANGE ) { 54 exit_error(PARAMETER_PROBLEM, 55 "%s `%s' specified too big: would overflow", 56 typestr, idstr); 57 } 58 if ( *idstr != '\0' && *ep != '\0' ) { 59 exit_error(PARAMETER_PROBLEM, 60 UNAME " error parsing %s `%s'", typestr, idstr); 61 } 62 return (u_int32_t) id; 63} 64 65static int 66parse_options(const char *optsstr, u_int16_t *opts) 67{ 68 char *buffer, *cp, *next, *range; 69 unsigned int i; 70 71 buffer = strdup(optsstr); 72 if (!buffer) 73 exit_error(OTHER_PROBLEM, "strdup failed"); 74 75 for (cp = buffer, i = 0; cp && i < IP6T_OPTS_OPTSNR; cp = next, i++) 76 { 77 next = strchr(cp, ','); 78 79 if (next) 80 *next++='\0'; 81 82 range = strchr(cp, ':'); 83 84 if (range) { 85 if (i == IP6T_OPTS_OPTSNR-1) 86 exit_error(PARAMETER_PROBLEM, 87 "too many ports specified"); 88 *range++ = '\0'; 89 } 90 91 opts[i] = (u_int16_t)((parse_opts_num(cp,"opt") & 0x000000FF)<<8); 92 if (range) { 93 if (opts[i] == 0) 94 exit_error(PARAMETER_PROBLEM, 95 "PAD0 hasn't got length"); 96 opts[i] |= (u_int16_t)(parse_opts_num(range,"length") & 97 0x000000FF); 98 } else 99 opts[i] |= (0x00FF); 100 101#ifdef DEBUG 102 printf("opts str: %s %s\n", cp, range); 103 printf("opts opt: %04X\n", opts[i]); 104#endif 105 } 106 107 if (cp) 108 exit_error(PARAMETER_PROBLEM, "too many addresses specified"); 109 110 free(buffer); 111 112#ifdef DEBUG 113 printf("addr nr: %d\n", i); 114#endif 115 116 return i; 117} 118 119/* Initialize the match. */ 120static void 121init(struct xt_entry_match *m) 122{ 123 struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data; 124 125 optinfo->hdrlen = 0; 126 optinfo->flags = 0; 127 optinfo->invflags = 0; 128 optinfo->optsnr = 0; 129} 130 131/* Function which parses command options; returns true if it 132 ate an option */ 133static int 134parse(int c, char **argv, int invert, unsigned int *flags, 135 const void *entry, 136 struct xt_entry_match **match) 137{ 138 struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data; 139 140 switch (c) { 141 case '1': 142 if (*flags & IP6T_OPTS_LEN) 143 exit_error(PARAMETER_PROBLEM, 144 "Only one `--" LNAME "-len' allowed"); 145 check_inverse(optarg, &invert, &optind, 0); 146 optinfo->hdrlen = parse_opts_num(argv[optind-1], "length"); 147 if (invert) 148 optinfo->invflags |= IP6T_OPTS_INV_LEN; 149 optinfo->flags |= IP6T_OPTS_LEN; 150 *flags |= IP6T_OPTS_LEN; 151 break; 152 case '2': 153 if (*flags & IP6T_OPTS_OPTS) 154 exit_error(PARAMETER_PROBLEM, 155 "Only one `--" LNAME "-opts' allowed"); 156 check_inverse(optarg, &invert, &optind, 0); 157 if (invert) 158 exit_error(PARAMETER_PROBLEM, 159 " '!' not allowed with `--" LNAME "-opts'"); 160 optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts); 161 optinfo->flags |= IP6T_OPTS_OPTS; 162 *flags |= IP6T_OPTS_OPTS; 163 break; 164 case '3': 165 if (*flags & IP6T_OPTS_NSTRICT) 166 exit_error(PARAMETER_PROBLEM, 167 "Only one `--" LNAME "-not-strict' allowed"); 168 if ( !(*flags & IP6T_OPTS_OPTS) ) 169 exit_error(PARAMETER_PROBLEM, 170 "`--" LNAME "-opts ...' required before `--" 171 LNAME "-not-strict'"); 172 optinfo->flags |= IP6T_OPTS_NSTRICT; 173 *flags |= IP6T_OPTS_NSTRICT; 174 break; 175 default: 176 return 0; 177 } 178 179 return 1; 180} 181 182/* Final check; we don't care. */ 183static void 184final_check(unsigned int flags) 185{ 186} 187 188static void 189print_options(int optsnr, u_int16_t *optsp) 190{ 191 unsigned int i; 192 193 for(i = 0; i < optsnr; i++) { 194 printf("%d", (optsp[i] & 0xFF00) >> 8); 195 196 if ((optsp[i] & 0x00FF) != 0x00FF) 197 printf(":%d", (optsp[i] & 0x00FF)); 198 199 printf("%c", (i != optsnr - 1) ? ',' : ' '); 200 } 201} 202 203/* Prints out the union ip6t_matchinfo. */ 204static void 205print(const void *ip, 206 const struct xt_entry_match *match, int numeric) 207{ 208 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; 209 210 printf(LNAME " "); 211 if (optinfo->flags & IP6T_OPTS_LEN) 212 printf("length:%s%u ", 213 optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "", 214 optinfo->hdrlen); 215 216 if (optinfo->flags & IP6T_OPTS_OPTS) 217 printf("opts "); 218 219 print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); 220 221 if (optinfo->flags & IP6T_OPTS_NSTRICT) 222 printf("not-strict "); 223 224 if (optinfo->invflags & ~IP6T_OPTS_INV_MASK) 225 printf("Unknown invflags: 0x%X ", 226 optinfo->invflags & ~IP6T_OPTS_INV_MASK); 227} 228 229/* Saves the union ip6t_matchinfo in parsable form to stdout. */ 230static void save(const void *ip, const struct xt_entry_match *match) 231{ 232 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; 233 234 if (optinfo->flags & IP6T_OPTS_LEN) { 235 printf("--" LNAME "-len %s%u ", 236 (optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "", 237 optinfo->hdrlen); 238 } 239 240 if (optinfo->flags & IP6T_OPTS_OPTS) 241 printf("--" LNAME "-opts "); 242 243 print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); 244 245 if (optinfo->flags & IP6T_OPTS_NSTRICT) 246 printf("--" LNAME "-not-strict "); 247} 248 249static 250struct ip6tables_match optstruct = { 251 .name = LNAME, 252 .version = IPTABLES_VERSION, 253 .size = IP6T_ALIGN(sizeof(struct ip6t_opts)), 254 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_opts)), 255 .help = &help, 256 .init = &init, 257 .parse = &parse, 258 .final_check = &final_check, 259 .print = &print, 260 .save = &save, 261 .extra_opts = opts 262}; 263 264void 265_init(void) 266{ 267 register_match6(&optstruct); 268} 269