libip6t_hbh.c revision e88a7c2c7175742b58b6aa03f2b5aba2d80330a1
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 {.name = "hbh-len", .has_arg = true, .val = '1'}, 29 {.name = "hbh-opts", .has_arg = true, .val = '2'}, 30 {.name = "hbh-not-strict", .has_arg = true, .val = '3'}, 31 XT_GETOPT_TABLEEND, 32}; 33 34static uint32_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 xtables_error(PARAMETER_PROBLEM, 44 "hbh: no valid digits in %s `%s'", typestr, idstr); 45 } 46 if ( id == ULONG_MAX && errno == ERANGE ) { 47 xtables_error(PARAMETER_PROBLEM, 48 "%s `%s' specified too big: would overflow", 49 typestr, idstr); 50 } 51 if ( *idstr != '\0' && *ep != '\0' ) { 52 xtables_error(PARAMETER_PROBLEM, 53 "hbh: error parsing %s `%s'", typestr, idstr); 54 } 55 return id; 56} 57 58static int 59parse_options(const char *optsstr, uint16_t *opts) 60{ 61 char *buffer, *cp, *next, *range; 62 unsigned int i; 63 64 buffer = strdup(optsstr); 65 if (!buffer) xtables_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 xtables_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 xtables_error(PARAMETER_PROBLEM, "PAD0 has not 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) xtables_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 int hbh_parse(int c, char **argv, int invert, unsigned int *flags, 104 const void *entry, struct xt_entry_match **match) 105{ 106 struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data; 107 108 switch (c) { 109 case '1': 110 if (*flags & IP6T_OPTS_LEN) 111 xtables_error(PARAMETER_PROBLEM, 112 "Only one `--hbh-len' allowed"); 113 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 114 optinfo->hdrlen = parse_opts_num(optarg, "length"); 115 if (invert) 116 optinfo->invflags |= IP6T_OPTS_INV_LEN; 117 optinfo->flags |= IP6T_OPTS_LEN; 118 *flags |= IP6T_OPTS_LEN; 119 break; 120 case '2': 121 if (*flags & IP6T_OPTS_OPTS) 122 xtables_error(PARAMETER_PROBLEM, 123 "Only one `--hbh-opts' allowed"); 124 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 125 if (invert) 126 xtables_error(PARAMETER_PROBLEM, 127 " '!' not allowed with `--hbh-opts'"); 128 optinfo->optsnr = parse_options(optarg, optinfo->opts); 129 optinfo->flags |= IP6T_OPTS_OPTS; 130 *flags |= IP6T_OPTS_OPTS; 131 break; 132 case '3': 133 if (*flags & IP6T_OPTS_NSTRICT) 134 xtables_error(PARAMETER_PROBLEM, 135 "Only one `--hbh-not-strict' allowed"); 136 if ( !(*flags & IP6T_OPTS_OPTS) ) 137 xtables_error(PARAMETER_PROBLEM, 138 "`--hbh-opts ...' required before `--hbh-not-strict'"); 139 optinfo->flags |= IP6T_OPTS_NSTRICT; 140 *flags |= IP6T_OPTS_NSTRICT; 141 break; 142 } 143 144 return 1; 145} 146 147static void 148print_options(unsigned int optsnr, uint16_t *optsp) 149{ 150 unsigned int i; 151 152 for(i=0; i<optsnr; i++){ 153 printf("%c", (i==0)?' ':','); 154 printf("%d", (optsp[i] & 0xFF00)>>8); 155 if ((optsp[i] & 0x00FF) != 0x00FF){ 156 printf(":%d", (optsp[i] & 0x00FF)); 157 } 158 } 159} 160 161static void hbh_print(const void *ip, const struct xt_entry_match *match, 162 int numeric) 163{ 164 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; 165 166 printf(" hbh"); 167 if (optinfo->flags & IP6T_OPTS_LEN) { 168 printf(" length"); 169 printf(":%s", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : ""); 170 printf("%u", optinfo->hdrlen); 171 } 172 if (optinfo->flags & IP6T_OPTS_OPTS) printf(" opts"); 173 print_options(optinfo->optsnr, (uint16_t *)optinfo->opts); 174 if (optinfo->flags & IP6T_OPTS_NSTRICT) printf(" not-strict"); 175 if (optinfo->invflags & ~IP6T_OPTS_INV_MASK) 176 printf(" Unknown invflags: 0x%X", 177 optinfo->invflags & ~IP6T_OPTS_INV_MASK); 178} 179 180static void hbh_save(const void *ip, const struct xt_entry_match *match) 181{ 182 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; 183 184 if (optinfo->flags & IP6T_OPTS_LEN) { 185 printf("%s --hbh-len %u", 186 (optinfo->invflags & IP6T_OPTS_INV_LEN) ? " !" : "", 187 optinfo->hdrlen); 188 } 189 190 if (optinfo->flags & IP6T_OPTS_OPTS) 191 printf(" --hbh-opts"); 192 print_options(optinfo->optsnr, (uint16_t *)optinfo->opts); 193 if (optinfo->flags & IP6T_OPTS_NSTRICT) 194 printf(" --hbh-not-strict"); 195} 196 197static struct xtables_match hbh_mt6_reg = { 198 .name = "hbh", 199 .version = XTABLES_VERSION, 200 .family = NFPROTO_IPV6, 201 .size = XT_ALIGN(sizeof(struct ip6t_opts)), 202 .userspacesize = XT_ALIGN(sizeof(struct ip6t_opts)), 203 .help = hbh_help, 204 .parse = hbh_parse, 205 .print = hbh_print, 206 .save = hbh_save, 207 .extra_opts = hbh_opts, 208}; 209 210void 211_init(void) 212{ 213 xtables_register_match(&hbh_mt6_reg); 214} 215