1/* Shared library add-on to ip6tables to add ESP 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_esp.h> 10 11/* Function which prints out usage message. */ 12static void 13help(void) 14{ 15 printf( 16"ESP v%s options:\n" 17" --espspi [!] spi[:spi] match spi (range)\n", 18IPTABLES_VERSION); 19} 20 21static struct option opts[] = { 22 { .name = "espspi", .has_arg = 1, .flag = 0, .val = '1' }, 23 { .name = 0 } 24}; 25 26static u_int32_t 27parse_esp_spi(const char *spistr) 28{ 29 unsigned long int spi; 30 char* ep; 31 32 spi = strtoul(spistr, &ep, 0); 33 34 if ( spistr == ep ) { 35 exit_error(PARAMETER_PROBLEM, 36 "ESP no valid digits in spi `%s'", spistr); 37 } 38 if ( spi == ULONG_MAX && errno == ERANGE ) { 39 exit_error(PARAMETER_PROBLEM, 40 "spi `%s' specified too big: would overflow", spistr); 41 } 42 if ( *spistr != '\0' && *ep != '\0' ) { 43 exit_error(PARAMETER_PROBLEM, 44 "ESP error parsing spi `%s'", spistr); 45 } 46 return (u_int32_t) spi; 47} 48 49static void 50parse_esp_spis(const char *spistring, u_int32_t *spis) 51{ 52 char *buffer; 53 char *cp; 54 55 buffer = strdup(spistring); 56 if ((cp = strchr(buffer, ':')) == NULL) 57 spis[0] = spis[1] = parse_esp_spi(buffer); 58 else { 59 *cp = '\0'; 60 cp++; 61 62 spis[0] = buffer[0] ? parse_esp_spi(buffer) : 0; 63 spis[1] = cp[0] ? parse_esp_spi(cp) : 0xFFFFFFFF; 64 if (spis[0] > spis[1]) 65 exit_error(PARAMETER_PROBLEM, 66 "Invalid ESP spi range: %s", spistring); 67 } 68 free(buffer); 69} 70 71/* Initialize the match. */ 72static void 73init(struct ip6t_entry_match *m, unsigned int *nfcache) 74{ 75 struct ip6t_esp *espinfo = (struct ip6t_esp *)m->data; 76 77 espinfo->spis[1] = 0xFFFFFFFF; 78} 79 80#define ESP_SPI 0x01 81 82/* Function which parses command options; returns true if it 83 ate an option */ 84static int 85parse(int c, char **argv, int invert, unsigned int *flags, 86 const struct ip6t_entry *entry, 87 unsigned int *nfcache, 88 struct ip6t_entry_match **match) 89{ 90 struct ip6t_esp *espinfo = (struct ip6t_esp *)(*match)->data; 91 92 switch (c) { 93 case '1': 94 if (*flags & ESP_SPI) 95 exit_error(PARAMETER_PROBLEM, 96 "Only one `--espspi' allowed"); 97 check_inverse(optarg, &invert, &optind, 0); 98 parse_esp_spis(argv[optind-1], espinfo->spis); 99 if (invert) 100 espinfo->invflags |= IP6T_ESP_INV_SPI; 101 *flags |= ESP_SPI; 102 break; 103 default: 104 return 0; 105 } 106 107 return 1; 108} 109 110/* Final check; we don't care. */ 111static void 112final_check(unsigned int flags) 113{ 114} 115 116static void 117print_spis(const char *name, u_int32_t min, u_int32_t max, 118 int invert) 119{ 120 const char *inv = invert ? "!" : ""; 121 122 if (min != 0 || max != 0xFFFFFFFF || invert) { 123 if (min == max) 124 printf("%s:%s%u ", name, inv, min); 125 else 126 printf("%ss:%s%u:%u ", name, inv, min, max); 127 } 128} 129 130/* Prints out the union ip6t_matchinfo. */ 131static void 132print(const struct ip6t_ip6 *ip, 133 const struct ip6t_entry_match *match, int numeric) 134{ 135 const struct ip6t_esp *esp = (struct ip6t_esp *)match->data; 136 137 printf("esp "); 138 print_spis("spi", esp->spis[0], esp->spis[1], 139 esp->invflags & IP6T_ESP_INV_SPI); 140 if (esp->invflags & ~IP6T_ESP_INV_MASK) 141 printf("Unknown invflags: 0x%X ", 142 esp->invflags & ~IP6T_ESP_INV_MASK); 143} 144 145/* Saves the union ip6t_matchinfo in parsable form to stdout. */ 146static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) 147{ 148 const struct ip6t_esp *espinfo = (struct ip6t_esp *)match->data; 149 150 if (!(espinfo->spis[0] == 0 151 && espinfo->spis[1] == 0xFFFFFFFF)) { 152 printf("--espspi %s", 153 (espinfo->invflags & IP6T_ESP_INV_SPI) ? "! " : ""); 154 if (espinfo->spis[0] 155 != espinfo->spis[1]) 156 printf("%u:%u ", 157 espinfo->spis[0], 158 espinfo->spis[1]); 159 else 160 printf("%u ", 161 espinfo->spis[0]); 162 } 163 164} 165 166static 167struct ip6tables_match esp = { 168 .name = "esp", 169 .version = IPTABLES_VERSION, 170 .size = IP6T_ALIGN(sizeof(struct ip6t_esp)), 171 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_esp)), 172 .help = &help, 173 .init = &init, 174 .parse = &parse, 175 .final_check = &final_check, 176 .print = &print, 177 .save = &save, 178 .extra_opts = opts 179}; 180 181void 182_init(void) 183{ 184 register_match6(&esp); 185} 186