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