libip6t_ah.c revision b85256b07a2939d712a2547bc151653eae511909
1/* Shared library add-on to ip6tables to add AH 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_ah.h> 10 11/* Function which prints out usage message. */ 12static void 13help(void) 14{ 15 printf( 16"AH v%s options:\n" 17" --ahspi [!] spi[:spi] match spi (range)\n" 18" --ahlen [!] length total length of this header\n" 19" --ahres check the reserved filed, too\n", 20IPTABLES_VERSION); 21} 22 23static struct option opts[] = { 24 { .name = "ahspi", .has_arg = 1, .flag = 0, .val = '1' }, 25 { .name = "ahlen", .has_arg = 1, .flag = 0, .val = '2' }, 26 { .name = "ahres", .has_arg = 0, .flag = 0, .val = '3' }, 27 { .name = 0 } 28}; 29 30static u_int32_t 31parse_ah_spi(const char *spistr, const char *typestr) 32{ 33 unsigned long int spi; 34 char* ep; 35 36 spi = strtoul(spistr, &ep, 0); 37 38 if ( spistr == ep ) 39 exit_error(PARAMETER_PROBLEM, 40 "AH no valid digits in %s `%s'", typestr, spistr); 41 42 if ( spi == ULONG_MAX && errno == ERANGE ) 43 exit_error(PARAMETER_PROBLEM, 44 "%s `%s' specified too big: would overflow", 45 typestr, spistr); 46 47 if ( *spistr != '\0' && *ep != '\0' ) 48 exit_error(PARAMETER_PROBLEM, 49 "AH error parsing %s `%s'", typestr, spistr); 50 51 return (u_int32_t) spi; 52} 53 54static void 55parse_ah_spis(const char *spistring, u_int32_t *spis) 56{ 57 char *buffer; 58 char *cp; 59 60 buffer = strdup(spistring); 61 if ((cp = strchr(buffer, ':')) == NULL) 62 spis[0] = spis[1] = parse_ah_spi(buffer, "spi"); 63 else { 64 *cp = '\0'; 65 cp++; 66 67 spis[0] = buffer[0] ? parse_ah_spi(buffer, "spi") : 0; 68 spis[1] = cp[0] ? parse_ah_spi(cp, "spi") : 0xFFFFFFFF; 69 } 70 free(buffer); 71} 72 73/* Initialize the match. */ 74static void 75init(struct xt_entry_match *m, unsigned int *nfcache) 76{ 77 struct ip6t_ah *ahinfo = (struct ip6t_ah *)m->data; 78 79 ahinfo->spis[1] = 0xFFFFFFFF; 80 ahinfo->hdrlen = 0; 81 ahinfo->hdrres = 0; 82} 83 84/* Function which parses command options; returns true if it 85 ate an option */ 86static int 87parse(int c, char **argv, int invert, unsigned int *flags, 88 const struct ip6t_entry *entry, 89 unsigned int *nfcache, 90 struct xt_entry_match **match) 91{ 92 struct ip6t_ah *ahinfo = (struct ip6t_ah *)(*match)->data; 93 94 switch (c) { 95 case '1': 96 if (*flags & IP6T_AH_SPI) 97 exit_error(PARAMETER_PROBLEM, 98 "Only one `--ahspi' allowed"); 99 check_inverse(optarg, &invert, &optind, 0); 100 parse_ah_spis(argv[optind-1], ahinfo->spis); 101 if (invert) 102 ahinfo->invflags |= IP6T_AH_INV_SPI; 103 *flags |= IP6T_AH_SPI; 104 break; 105 case '2': 106 if (*flags & IP6T_AH_LEN) 107 exit_error(PARAMETER_PROBLEM, 108 "Only one `--ahlen' allowed"); 109 check_inverse(optarg, &invert, &optind, 0); 110 ahinfo->hdrlen = parse_ah_spi(argv[optind-1], "length"); 111 if (invert) 112 ahinfo->invflags |= IP6T_AH_INV_LEN; 113 *flags |= IP6T_AH_LEN; 114 break; 115 case '3': 116 if (*flags & IP6T_AH_RES) 117 exit_error(PARAMETER_PROBLEM, 118 "Only one `--ahres' allowed"); 119 ahinfo->hdrres = 1; 120 *flags |= IP6T_AH_RES; 121 break; 122 default: 123 return 0; 124 } 125 126 return 1; 127} 128 129/* Final check; we don't care. */ 130static void 131final_check(unsigned int flags) 132{ 133} 134 135static void 136print_spis(const char *name, u_int32_t min, u_int32_t max, 137 int invert) 138{ 139 const char *inv = invert ? "!" : ""; 140 141 if (min != 0 || max != 0xFFFFFFFF || invert) { 142 if (min == max) 143 printf("%s:%s%u ", name, inv, min); 144 else 145 printf("%ss:%s%u:%u ", name, inv, min, max); 146 } 147} 148 149static void 150print_len(const char *name, u_int32_t len, int invert) 151{ 152 const char *inv = invert ? "!" : ""; 153 154 if (len != 0 || invert) 155 printf("%s:%s%u ", name, inv, len); 156} 157 158/* Prints out the union ip6t_matchinfo. */ 159static void 160print(const struct ip6t_ip6 *ip, 161 const struct xt_entry_match *match, int numeric) 162{ 163 const struct ip6t_ah *ah = (struct ip6t_ah *)match->data; 164 165 printf("ah "); 166 print_spis("spi", ah->spis[0], ah->spis[1], 167 ah->invflags & IP6T_AH_INV_SPI); 168 print_len("length", ah->hdrlen, 169 ah->invflags & IP6T_AH_INV_LEN); 170 171 if (ah->hdrres) 172 printf("reserved "); 173 174 if (ah->invflags & ~IP6T_AH_INV_MASK) 175 printf("Unknown invflags: 0x%X ", 176 ah->invflags & ~IP6T_AH_INV_MASK); 177} 178 179/* Saves the union ip6t_matchinfo in parsable form to stdout. */ 180static void save(const struct ip6t_ip6 *ip, const struct xt_entry_match *match) 181{ 182 const struct ip6t_ah *ahinfo = (struct ip6t_ah *)match->data; 183 184 if (!(ahinfo->spis[0] == 0 185 && ahinfo->spis[1] == 0xFFFFFFFF)) { 186 printf("--ahspi %s", 187 (ahinfo->invflags & IP6T_AH_INV_SPI) ? "! " : ""); 188 if (ahinfo->spis[0] 189 != ahinfo->spis[1]) 190 printf("%u:%u ", 191 ahinfo->spis[0], 192 ahinfo->spis[1]); 193 else 194 printf("%u ", 195 ahinfo->spis[0]); 196 } 197 198 if (ahinfo->hdrlen != 0 || (ahinfo->invflags & IP6T_AH_INV_LEN) ) { 199 printf("--ahlen %s%u ", 200 (ahinfo->invflags & IP6T_AH_INV_LEN) ? "! " : "", 201 ahinfo->hdrlen); 202 } 203 204 if (ahinfo->hdrres != 0 ) 205 printf("--ahres "); 206} 207 208static 209struct ip6tables_match ah = { 210 .name = "ah", 211 .version = IPTABLES_VERSION, 212 .size = IP6T_ALIGN(sizeof(struct ip6t_ah)), 213 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_ah)), 214 .help = &help, 215 .init = &init, 216 .parse = &parse, 217 .final_check = &final_check, 218 .print = &print, 219 .save = &save, 220 .extra_opts = opts 221}; 222 223void 224_init(void) 225{ 226 register_match6(&ah); 227} 228