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