libip6t_hbh.c revision 0f16c725aadaac7e670d632ecbaea3661ff00827
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 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] = (parse_opts_num(cp, "opt") & 0xFF) << 8; 79 if (range) { 80 if (opts[i] == 0) 81 exit_error(PARAMETER_PROBLEM, "PAD0 hasn't got length"); 82 opts[i] |= parse_opts_num(range, "length") & 0xFF; 83 } else { 84 opts[i] |= (0x00FF); 85 } 86 87#if DEBUG 88 printf("opts str: %s %s\n", cp, range); 89 printf("opts opt: %04X\n", opts[i]); 90#endif 91 } 92 if (cp) exit_error(PARAMETER_PROBLEM, "too many addresses specified"); 93 94 free(buffer); 95 96#if DEBUG 97 printf("addr nr: %d\n", i); 98#endif 99 100 return i; 101} 102 103static void hbh_init(struct xt_entry_match *m) 104{ 105 struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data; 106 107 optinfo->hdrlen = 0; 108 optinfo->flags = 0; 109 optinfo->invflags = 0; 110 optinfo->optsnr = 0; 111} 112 113static int hbh_parse(int c, char **argv, int invert, unsigned int *flags, 114 const void *entry, struct xt_entry_match **match) 115{ 116 struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data; 117 118 switch (c) { 119 case '1': 120 if (*flags & IP6T_OPTS_LEN) 121 exit_error(PARAMETER_PROBLEM, 122 "Only one `--hbh-len' allowed"); 123 xtables_check_inverse(optarg, &invert, &optind, 0); 124 optinfo->hdrlen = parse_opts_num(argv[optind-1], "length"); 125 if (invert) 126 optinfo->invflags |= IP6T_OPTS_INV_LEN; 127 optinfo->flags |= IP6T_OPTS_LEN; 128 *flags |= IP6T_OPTS_LEN; 129 break; 130 case '2': 131 if (*flags & IP6T_OPTS_OPTS) 132 exit_error(PARAMETER_PROBLEM, 133 "Only one `--hbh-opts' allowed"); 134 xtables_check_inverse(optarg, &invert, &optind, 0); 135 if (invert) 136 exit_error(PARAMETER_PROBLEM, 137 " '!' not allowed with `--hbh-opts'"); 138 optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts); 139 optinfo->flags |= IP6T_OPTS_OPTS; 140 *flags |= IP6T_OPTS_OPTS; 141 break; 142 case '3': 143 if (*flags & IP6T_OPTS_NSTRICT) 144 exit_error(PARAMETER_PROBLEM, 145 "Only one `--hbh-not-strict' allowed"); 146 if ( !(*flags & IP6T_OPTS_OPTS) ) 147 exit_error(PARAMETER_PROBLEM, 148 "`--hbh-opts ...' required before `--hbh-not-strict'"); 149 optinfo->flags |= IP6T_OPTS_NSTRICT; 150 *flags |= IP6T_OPTS_NSTRICT; 151 break; 152 default: 153 return 0; 154 } 155 156 return 1; 157} 158 159static void 160print_options(unsigned int optsnr, u_int16_t *optsp) 161{ 162 unsigned int i; 163 164 for(i=0; i<optsnr; i++){ 165 printf("%d", (optsp[i] & 0xFF00)>>8); 166 if ((optsp[i] & 0x00FF) != 0x00FF){ 167 printf(":%d", (optsp[i] & 0x00FF)); 168 } 169 printf("%c", (i!=optsnr-1)?',':' '); 170 } 171} 172 173static void hbh_print(const void *ip, const struct xt_entry_match *match, 174 int numeric) 175{ 176 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; 177 178 printf("hbh "); 179 if (optinfo->flags & IP6T_OPTS_LEN) { 180 printf("length"); 181 printf(":%s", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : ""); 182 printf("%u", optinfo->hdrlen); 183 printf(" "); 184 } 185 if (optinfo->flags & IP6T_OPTS_OPTS) printf("opts "); 186 print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); 187 if (optinfo->flags & IP6T_OPTS_NSTRICT) printf("not-strict "); 188 if (optinfo->invflags & ~IP6T_OPTS_INV_MASK) 189 printf("Unknown invflags: 0x%X ", 190 optinfo->invflags & ~IP6T_OPTS_INV_MASK); 191} 192 193static void hbh_save(const void *ip, const struct xt_entry_match *match) 194{ 195 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; 196 197 if (optinfo->flags & IP6T_OPTS_LEN) { 198 printf("%s--hbh-len %u ", 199 (optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "", 200 optinfo->hdrlen); 201 } 202 203 if (optinfo->flags & IP6T_OPTS_OPTS) 204 printf("--hbh-opts "); 205 print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); 206 if (optinfo->flags & IP6T_OPTS_NSTRICT) 207 printf("--hbh-not-strict "); 208} 209 210static struct xtables_match hbh_mt6_reg = { 211 .name = "hbh", 212 .version = XTABLES_VERSION, 213 .family = NFPROTO_IPV6, 214 .size = XT_ALIGN(sizeof(struct ip6t_opts)), 215 .userspacesize = XT_ALIGN(sizeof(struct ip6t_opts)), 216 .help = hbh_help, 217 .init = hbh_init, 218 .parse = hbh_parse, 219 .print = hbh_print, 220 .save = hbh_save, 221 .extra_opts = hbh_opts, 222}; 223 224void 225_init(void) 226{ 227 xtables_register_match(&hbh_mt6_reg); 228} 229