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