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 { "ahspi", 1, 0, '1' }, 25 { "ahlen", 1, 0, '2' }, 26 { "ahres", 0, 0, '3' }, 27 {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 ip6t_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 ip6t_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 printf("%s", name); 143 if (min == max) { 144 printf(":%s", inv); 145 printf("%u", min); 146 } else { 147 printf("s:%s", inv); 148 printf("%u",min); 149 printf(":"); 150 printf("%u",max); 151 } 152 printf(" "); 153 } 154} 155 156static void 157print_len(const char *name, u_int32_t len, int invert) 158{ 159 const char *inv = invert ? "!" : ""; 160 161 if (len != 0 || invert) { 162 printf("%s", name); 163 printf(":%s", inv); 164 printf("%u", len); 165 printf(" "); 166 } 167} 168 169/* Prints out the union ip6t_matchinfo. */ 170static void 171print(const struct ip6t_ip6 *ip, 172 const struct ip6t_entry_match *match, int numeric) 173{ 174 const struct ip6t_ah *ah = (struct ip6t_ah *)match->data; 175 176 printf("ah "); 177 print_spis("spi", ah->spis[0], ah->spis[1], 178 ah->invflags & IP6T_AH_INV_SPI); 179 print_len("length", ah->hdrlen, 180 ah->invflags & IP6T_AH_INV_LEN); 181 if (ah->hdrres) printf("reserved "); 182 if (ah->invflags & ~IP6T_AH_INV_MASK) 183 printf("Unknown invflags: 0x%X ", 184 ah->invflags & ~IP6T_AH_INV_MASK); 185} 186 187/* Saves the union ip6t_matchinfo in parsable form to stdout. */ 188static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) 189{ 190 const struct ip6t_ah *ahinfo = (struct ip6t_ah *)match->data; 191 192 if (!(ahinfo->spis[0] == 0 193 && ahinfo->spis[1] == 0xFFFFFFFF)) { 194 printf("--ahspi %s", 195 (ahinfo->invflags & IP6T_AH_INV_SPI) ? "! " : ""); 196 if (ahinfo->spis[0] 197 != ahinfo->spis[1]) 198 printf("%u:%u ", 199 ahinfo->spis[0], 200 ahinfo->spis[1]); 201 else 202 printf("%u ", 203 ahinfo->spis[0]); 204 } 205 206 if (ahinfo->hdrlen != 0 || (ahinfo->invflags & IP6T_AH_INV_LEN) ) { 207 printf("--ahlen %s%u ", 208 (ahinfo->invflags & IP6T_AH_INV_LEN) ? "! " : "", 209 ahinfo->hdrlen); 210 } 211 212 if (ahinfo->hdrres != 0 ) { 213 printf("--ahres "); 214 } 215 216} 217 218static 219struct ip6tables_match ah 220= { NULL, 221 "ah", 222 IPTABLES_VERSION, 223 IP6T_ALIGN(sizeof(struct ip6t_ah)), 224 IP6T_ALIGN(sizeof(struct ip6t_ah)), 225 &help, 226 &init, 227 &parse, 228 &final_check, 229 &print, 230 &save, 231 opts 232}; 233 234void 235_init(void) 236{ 237 register_match6(&ah); 238} 239