Home | History | Annotate | Download | only in extensions
      1 /* Shared library add-on to iptables to add simple non load-balancing SNAT support. */
      2 #include <stdio.h>
      3 #include <netdb.h>
      4 #include <string.h>
      5 #include <stdlib.h>
      6 #include <getopt.h>
      7 #include <iptables.h>
      8 #include <linux/netfilter_ipv4/ip_tables.h>
      9 #include <linux/netfilter_ipv4/ip_nat_rule.h>
     10 /* For 64bit kernel / 32bit userspace */
     11 #include "../include/linux/netfilter_ipv4/ipt_SAME.h"
     12 
     13 /* Function which prints out usage message. */
     14 static void
     15 help(void)
     16 {
     17 	printf(
     18 "SAME v%s options:\n"
     19 " --to <ipaddr>-<ipaddr>\n"
     20 "				Addresses to map source to.\n"
     21 "				 May be specified more than\n"
     22 "				  once for multiple ranges.\n"
     23 " --nodst\n"
     24 "				Don't use destination-ip in\n"
     25 "				           source selection\n",
     26 IPTABLES_VERSION);
     27 }
     28 
     29 static struct option opts[] = {
     30 	{ "to", 1, 0, '1' },
     31 	{ "nodst", 0, 0, '2'},
     32 	{ 0 }
     33 };
     34 
     35 /* Initialize the target. */
     36 static void
     37 init(struct ipt_entry_target *t, unsigned int *nfcache)
     38 {
     39 	struct ipt_same_info *mr = (struct ipt_same_info *)t->data;
     40 
     41 	/* Set default to 0 */
     42 	mr->rangesize = 0;
     43 	mr->info = 0;
     44 	mr->ipnum = 0;
     45 
     46 }
     47 
     48 /* Parses range of IPs */
     49 static void
     50 parse_to(char *arg, struct ip_nat_range *range)
     51 {
     52 	char *dash;
     53 	struct in_addr *ip;
     54 
     55 	range->flags |= IP_NAT_RANGE_MAP_IPS;
     56 	dash = strchr(arg, '-');
     57 
     58 	if (dash)
     59 		*dash = '\0';
     60 
     61 	ip = dotted_to_addr(arg);
     62 	if (!ip)
     63 		exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
     64 			   arg);
     65 	range->min_ip = ip->s_addr;
     66 
     67 	if (dash) {
     68 		ip = dotted_to_addr(dash+1);
     69 		if (!ip)
     70 			exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
     71 				   dash+1);
     72 	}
     73 	range->max_ip = ip->s_addr;
     74 	if (dash)
     75 		if (range->min_ip > range->max_ip)
     76 			exit_error(PARAMETER_PROBLEM, "Bad IP range `%s-%s'\n",
     77 				   arg, dash+1);
     78 }
     79 
     80 #define IPT_SAME_OPT_TO			0x01
     81 #define IPT_SAME_OPT_NODST		0x02
     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       struct ipt_entry_target **target)
     89 {
     90 	struct ipt_same_info *mr
     91 		= (struct ipt_same_info *)(*target)->data;
     92 
     93 	switch (c) {
     94 	case '1':
     95 		if (mr->rangesize == IPT_SAME_MAX_RANGE)
     96 			exit_error(PARAMETER_PROBLEM,
     97 				   "Too many ranges specified, maximum "
     98 				   "is %i ranges.\n",
     99 				   IPT_SAME_MAX_RANGE);
    100 		if (check_inverse(optarg, &invert, NULL, 0))
    101 			exit_error(PARAMETER_PROBLEM,
    102 				   "Unexpected `!' after --to");
    103 
    104 		parse_to(optarg, &mr->range[mr->rangesize]);
    105 		mr->rangesize++;
    106 		*flags |= IPT_SAME_OPT_TO;
    107 		break;
    108 
    109 	case '2':
    110 		if (*flags & IPT_SAME_OPT_NODST)
    111 			exit_error(PARAMETER_PROBLEM,
    112 				   "Can't specify --nodst twice");
    113 
    114 		mr->info |= IPT_SAME_NODST;
    115 		*flags |= IPT_SAME_OPT_NODST;
    116 		break;
    117 
    118 	default:
    119 		return 0;
    120 	}
    121 
    122 	return 1;
    123 }
    124 
    125 /* Final check; need --to. */
    126 static void final_check(unsigned int flags)
    127 {
    128 	if (!(flags & IPT_SAME_OPT_TO))
    129 		exit_error(PARAMETER_PROBLEM,
    130 			   "SAME needs --to");
    131 }
    132 
    133 /* Prints out the targinfo. */
    134 static void
    135 print(const struct ipt_ip *ip,
    136       const struct ipt_entry_target *target,
    137       int numeric)
    138 {
    139 	int count;
    140 	struct ipt_same_info *mr
    141 		= (struct ipt_same_info *)target->data;
    142 
    143 	printf("same:");
    144 
    145 	for (count = 0; count < mr->rangesize; count++) {
    146 		struct ip_nat_range *r = &mr->range[count];
    147 		struct in_addr a;
    148 
    149 		a.s_addr = r->min_ip;
    150 
    151 		printf("%s", addr_to_dotted(&a));
    152 		a.s_addr = r->max_ip;
    153 
    154 		if (r->min_ip == r->max_ip)
    155 			printf(" ");
    156 		else
    157 			printf("-%s ", addr_to_dotted(&a));
    158 	}
    159 
    160 	if (mr->info & IPT_SAME_NODST)
    161 		printf("nodst ");
    162 }
    163 
    164 /* Saves the union ipt_targinfo in parsable form to stdout. */
    165 static void
    166 save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
    167 {
    168 	int count;
    169 	struct ipt_same_info *mr
    170 		= (struct ipt_same_info *)target->data;
    171 
    172 	for (count = 0; count < mr->rangesize; count++) {
    173 		struct ip_nat_range *r = &mr->range[count];
    174 		struct in_addr a;
    175 
    176 		a.s_addr = r->min_ip;
    177 		printf("--to %s", addr_to_dotted(&a));
    178 		a.s_addr = r->max_ip;
    179 
    180 		if (r->min_ip == r->max_ip)
    181 			printf(" ");
    182 		else
    183 			printf("-%s ", addr_to_dotted(&a));
    184 	}
    185 
    186 	if (mr->info & IPT_SAME_NODST)
    187 		printf("--nodst ");
    188 }
    189 
    190 static struct iptables_target same = {
    191 	.next		= NULL,
    192 	.name		= "SAME",
    193 	.version	= IPTABLES_VERSION,
    194 	.size		= IPT_ALIGN(sizeof(struct ipt_same_info)),
    195 	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_same_info)),
    196 	.help		= &help,
    197 	.init		= &init,
    198 	.parse		= &parse,
    199 	.final_check	= &final_check,
    200 	.print		= &print,
    201 	.save		= &save,
    202 	.extra_opts	= opts
    203 };
    204 
    205 void ipt_SAME_init(void)
    206 {
    207 	register_target(&same);
    208 }
    209