Home | History | Annotate | Download | only in extensions
      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