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 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 ip6t_entry_match *m, unsigned int *nfcache) 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 struct ip6t_entry *entry, 136 unsigned int *nfcache, 137 struct ip6t_entry_match **match) 138{ 139 struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data; 140 141 switch (c) { 142 case '1': 143 if (*flags & IP6T_OPTS_LEN) 144 exit_error(PARAMETER_PROBLEM, 145 "Only one `--" LNAME "-len' allowed"); 146 check_inverse(optarg, &invert, &optind, 0); 147 optinfo->hdrlen = parse_opts_num(argv[optind-1], "length"); 148 if (invert) 149 optinfo->invflags |= IP6T_OPTS_INV_LEN; 150 optinfo->flags |= IP6T_OPTS_LEN; 151 *flags |= IP6T_OPTS_LEN; 152 break; 153 case '2': 154 if (*flags & IP6T_OPTS_OPTS) 155 exit_error(PARAMETER_PROBLEM, 156 "Only one `--" LNAME "-opts' allowed"); 157 check_inverse(optarg, &invert, &optind, 0); 158 if (invert) 159 exit_error(PARAMETER_PROBLEM, 160 " '!' not allowed with `--" LNAME "-opts'"); 161 optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts); 162 optinfo->flags |= IP6T_OPTS_OPTS; 163 *flags |= IP6T_OPTS_OPTS; 164 break; 165 case '3': 166 if (*flags & IP6T_OPTS_NSTRICT) 167 exit_error(PARAMETER_PROBLEM, 168 "Only one `--" LNAME "-not-strict' allowed"); 169 if ( !(*flags & IP6T_OPTS_OPTS) ) 170 exit_error(PARAMETER_PROBLEM, 171 "`--" LNAME "-opts ...' required before `--" 172 LNAME "-not-strict'"); 173 optinfo->flags |= IP6T_OPTS_NSTRICT; 174 *flags |= IP6T_OPTS_NSTRICT; 175 break; 176 default: 177 return 0; 178 } 179 180 return 1; 181} 182 183/* Final check; we don't care. */ 184static void 185final_check(unsigned int flags) 186{ 187} 188 189static void 190print_options(int optsnr, u_int16_t *optsp) 191{ 192 unsigned int i; 193 194 for(i = 0; i < optsnr; i++) { 195 printf("%d", (optsp[i] & 0xFF00) >> 8); 196 197 if ((optsp[i] & 0x00FF) != 0x00FF) 198 printf(":%d", (optsp[i] & 0x00FF)); 199 200 printf("%c", (i != optsnr - 1) ? ',' : ' '); 201 } 202} 203 204/* Prints out the union ip6t_matchinfo. */ 205static void 206print(const struct ip6t_ip6 *ip, 207 const struct ip6t_entry_match *match, int numeric) 208{ 209 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; 210 211 printf(LNAME " "); 212 if (optinfo->flags & IP6T_OPTS_LEN) 213 printf("length:%s%u ", 214 optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "", 215 optinfo->hdrlen); 216 217 if (optinfo->flags & IP6T_OPTS_OPTS) 218 printf("opts "); 219 220 print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); 221 222 if (optinfo->flags & IP6T_OPTS_NSTRICT) 223 printf("not-strict "); 224 225 if (optinfo->invflags & ~IP6T_OPTS_INV_MASK) 226 printf("Unknown invflags: 0x%X ", 227 optinfo->invflags & ~IP6T_OPTS_INV_MASK); 228} 229 230/* Saves the union ip6t_matchinfo in parsable form to stdout. */ 231static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) 232{ 233 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; 234 235 if (optinfo->flags & IP6T_OPTS_LEN) { 236 printf("--" LNAME "-len %s%u ", 237 (optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "", 238 optinfo->hdrlen); 239 } 240 241 if (optinfo->flags & IP6T_OPTS_OPTS) 242 printf("--" LNAME "-opts "); 243 244 print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); 245 246 if (optinfo->flags & IP6T_OPTS_NSTRICT) 247 printf("--" LNAME "-not-strict "); 248} 249 250static 251struct ip6tables_match optstruct = { 252 .name = LNAME, 253 .version = IPTABLES_VERSION, 254 .size = IP6T_ALIGN(sizeof(struct ip6t_opts)), 255 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_opts)), 256 .help = &help, 257 .init = &init, 258 .parse = &parse, 259 .final_check = &final_check, 260 .print = &print, 261 .save = &save, 262 .extra_opts = opts 263}; 264 265void 266_init(void) 267{ 268 register_match6(&optstruct); 269} 270