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