libip6t_hbh.c revision cea9f71f5618250a38acb21c31fbbf93a752f7d4
1/* Shared library add-on to ip6tables to add Hop-by-Hop 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/in6.h>*/ 10#include <linux/netfilter_ipv6/ip6t_opts.h> 11#include <sys/types.h> 12#include <sys/socket.h> 13#include <arpa/inet.h> 14 15#define DEBUG 0 16 17static void hbh_help(void) 18{ 19 printf( 20"hbh match options:\n" 21"[!] --hbh-len length total length of this header\n" 22" --hbh-opts TYPE[:LEN][,TYPE[:LEN]...] \n" 23" Options and its length (list, max: %d)\n", 24IP6T_OPTS_OPTSNR); 25} 26 27static const struct option hbh_opts[] = { 28 { "hbh-len", 1, NULL, '1' }, 29 { "hbh-opts", 1, NULL, '2' }, 30 { "hbh-not-strict", 1, NULL, '3' }, 31 { .name = NULL } 32}; 33 34static u_int32_t 35parse_opts_num(const char *idstr, const char *typestr) 36{ 37 unsigned long int id; 38 char* ep; 39 40 id = strtoul(idstr,&ep,0) ; 41 42 if ( idstr == ep ) { 43 exit_error(PARAMETER_PROBLEM, 44 "hbh: no valid digits in %s `%s'", typestr, idstr); 45 } 46 if ( id == ULONG_MAX && errno == ERANGE ) { 47 exit_error(PARAMETER_PROBLEM, 48 "%s `%s' specified too big: would overflow", 49 typestr, idstr); 50 } 51 if ( *idstr != '\0' && *ep != '\0' ) { 52 exit_error(PARAMETER_PROBLEM, 53 "hbh: error parsing %s `%s'", typestr, idstr); 54 } 55 return (u_int32_t) id; 56} 57 58static int 59parse_options(const char *optsstr, u_int16_t *opts) 60{ 61 char *buffer, *cp, *next, *range; 62 unsigned int i; 63 64 buffer = strdup(optsstr); 65 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed"); 66 67 for (cp=buffer, i=0; cp && i<IP6T_OPTS_OPTSNR; cp=next,i++) 68 { 69 next=strchr(cp, ','); 70 if (next) *next++='\0'; 71 range = strchr(cp, ':'); 72 if (range) { 73 if (i == IP6T_OPTS_OPTSNR-1) 74 exit_error(PARAMETER_PROBLEM, 75 "too many ports specified"); 76 *range++ = '\0'; 77 } 78 opts[i] = (u_int16_t)((parse_opts_num(cp,"opt") & 0x000000FF)<<8); 79 if (range) { 80 if (opts[i] == 0) 81 exit_error(PARAMETER_PROBLEM, "PAD0 hasn't got length"); 82 opts[i] |= (u_int16_t)(parse_opts_num(range,"length") & 83 0x000000FF); 84 } else { 85 opts[i] |= (0x00FF); 86 } 87 88#if DEBUG 89 printf("opts str: %s %s\n", cp, range); 90 printf("opts opt: %04X\n", opts[i]); 91#endif 92 } 93 if (cp) exit_error(PARAMETER_PROBLEM, "too many addresses specified"); 94 95 free(buffer); 96 97#if DEBUG 98 printf("addr nr: %d\n", i); 99#endif 100 101 return i; 102} 103 104static void hbh_init(struct xt_entry_match *m) 105{ 106 struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data; 107 108 optinfo->hdrlen = 0; 109 optinfo->flags = 0; 110 optinfo->invflags = 0; 111 optinfo->optsnr = 0; 112} 113 114static int hbh_parse(int c, char **argv, int invert, unsigned int *flags, 115 const void *entry, struct xt_entry_match **match) 116{ 117 struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data; 118 119 switch (c) { 120 case '1': 121 if (*flags & IP6T_OPTS_LEN) 122 exit_error(PARAMETER_PROBLEM, 123 "Only one `--hbh-len' allowed"); 124 check_inverse(optarg, &invert, &optind, 0); 125 optinfo->hdrlen = parse_opts_num(argv[optind-1], "length"); 126 if (invert) 127 optinfo->invflags |= IP6T_OPTS_INV_LEN; 128 optinfo->flags |= IP6T_OPTS_LEN; 129 *flags |= IP6T_OPTS_LEN; 130 break; 131 case '2': 132 if (*flags & IP6T_OPTS_OPTS) 133 exit_error(PARAMETER_PROBLEM, 134 "Only one `--hbh-opts' allowed"); 135 check_inverse(optarg, &invert, &optind, 0); 136 if (invert) 137 exit_error(PARAMETER_PROBLEM, 138 " '!' not allowed with `--hbh-opts'"); 139 optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts); 140 optinfo->flags |= IP6T_OPTS_OPTS; 141 *flags |= IP6T_OPTS_OPTS; 142 break; 143 case '3': 144 if (*flags & IP6T_OPTS_NSTRICT) 145 exit_error(PARAMETER_PROBLEM, 146 "Only one `--hbh-not-strict' allowed"); 147 if ( !(*flags & IP6T_OPTS_OPTS) ) 148 exit_error(PARAMETER_PROBLEM, 149 "`--hbh-opts ...' required before `--hbh-not-strict'"); 150 optinfo->flags |= IP6T_OPTS_NSTRICT; 151 *flags |= IP6T_OPTS_NSTRICT; 152 break; 153 default: 154 return 0; 155 } 156 157 return 1; 158} 159 160static void 161print_options(unsigned int optsnr, u_int16_t *optsp) 162{ 163 unsigned int i; 164 165 for(i=0; i<optsnr; i++){ 166 printf("%d", (optsp[i] & 0xFF00)>>8); 167 if ((optsp[i] & 0x00FF) != 0x00FF){ 168 printf(":%d", (optsp[i] & 0x00FF)); 169 } 170 printf("%c", (i!=optsnr-1)?',':' '); 171 } 172} 173 174static void hbh_print(const void *ip, const struct xt_entry_match *match, 175 int numeric) 176{ 177 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; 178 179 printf("hbh "); 180 if (optinfo->flags & IP6T_OPTS_LEN) { 181 printf("length"); 182 printf(":%s", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : ""); 183 printf("%u", optinfo->hdrlen); 184 printf(" "); 185 } 186 if (optinfo->flags & IP6T_OPTS_OPTS) printf("opts "); 187 print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); 188 if (optinfo->flags & IP6T_OPTS_NSTRICT) printf("not-strict "); 189 if (optinfo->invflags & ~IP6T_OPTS_INV_MASK) 190 printf("Unknown invflags: 0x%X ", 191 optinfo->invflags & ~IP6T_OPTS_INV_MASK); 192} 193 194static void hbh_save(const void *ip, const struct xt_entry_match *match) 195{ 196 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; 197 198 if (optinfo->flags & IP6T_OPTS_LEN) { 199 printf("%s--hbh-len %u ", 200 (optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "", 201 optinfo->hdrlen); 202 } 203 204 if (optinfo->flags & IP6T_OPTS_OPTS) 205 printf("--hbh-opts "); 206 print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); 207 if (optinfo->flags & IP6T_OPTS_NSTRICT) 208 printf("--hbh-not-strict "); 209} 210 211static struct xtables_match hbh_mt6_reg = { 212 .name = "hbh", 213 .version = XTABLES_VERSION, 214 .family = NFPROTO_IPV6, 215 .size = XT_ALIGN(sizeof(struct ip6t_opts)), 216 .userspacesize = XT_ALIGN(sizeof(struct ip6t_opts)), 217 .help = hbh_help, 218 .init = hbh_init, 219 .parse = hbh_parse, 220 .print = hbh_print, 221 .save = hbh_save, 222 .extra_opts = hbh_opts, 223}; 224 225void 226_init(void) 227{ 228 xtables_register_match(&hbh_mt6_reg); 229} 230