libipt_SAME.c revision 40d54756cd8a2705e22b36f7aef03bb2c472a10b
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/nf_nat.h> 10/* For 64bit kernel / 32bit userspace */ 11#include "../include/linux/netfilter_ipv4/ipt_SAME.h" 12 13/* Function which prints out usage message. */ 14static void 15help(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 27#ifdef IP_NAT_RANGE_PROTO_RANDOM 28" --random\n" 29" Randomize source port\n" 30#endif 31, 32IPTABLES_VERSION); 33} 34 35static struct option opts[] = { 36 { "to", 1, 0, '1' }, 37 { "nodst", 0, 0, '2'}, 38#ifdef IP_NAT_RANGE_PROTO_RANDOM 39 { "random", 0, 0, '3' }, 40#endif 41 { 0 } 42}; 43 44/* Initialize the target. */ 45static void 46init(struct ipt_entry_target *t, unsigned int *nfcache) 47{ 48 struct ipt_same_info *mr = (struct ipt_same_info *)t->data; 49 50 /* Set default to 0 */ 51 mr->rangesize = 0; 52 mr->info = 0; 53 mr->ipnum = 0; 54 55} 56 57/* Parses range of IPs */ 58static void 59parse_to(char *arg, struct ip_nat_range *range) 60{ 61 char *dash; 62 struct in_addr *ip; 63 64 range->flags |= IP_NAT_RANGE_MAP_IPS; 65 dash = strchr(arg, '-'); 66 67 if (dash) 68 *dash = '\0'; 69 70 ip = dotted_to_addr(arg); 71 if (!ip) 72 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", 73 arg); 74 range->min_ip = ip->s_addr; 75 76 if (dash) { 77 ip = dotted_to_addr(dash+1); 78 if (!ip) 79 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", 80 dash+1); 81 } 82 range->max_ip = ip->s_addr; 83 if (dash) 84 if (range->min_ip > range->max_ip) 85 exit_error(PARAMETER_PROBLEM, "Bad IP range `%s-%s'\n", 86 arg, dash+1); 87} 88 89#define IPT_SAME_OPT_TO 0x01 90#define IPT_SAME_OPT_NODST 0x02 91#ifdef IP_NAT_RANGE_PROTO_RANDOM 92# define IPT_SAME_OPT_RANDOM 0x04 93#endif 94 95/* Function which parses command options; returns true if it 96 ate an option */ 97static int 98parse(int c, char **argv, int invert, unsigned int *flags, 99 const struct ipt_entry *entry, 100 struct ipt_entry_target **target) 101{ 102 struct ipt_same_info *mr 103 = (struct ipt_same_info *)(*target)->data; 104#ifdef IP_NAT_RANGE_PROTO_RANDOM 105 int count; 106#endif 107 108 switch (c) { 109 case '1': 110 if (mr->rangesize == IPT_SAME_MAX_RANGE) 111 exit_error(PARAMETER_PROBLEM, 112 "Too many ranges specified, maximum " 113 "is %i ranges.\n", 114 IPT_SAME_MAX_RANGE); 115 if (check_inverse(optarg, &invert, NULL, 0)) 116 exit_error(PARAMETER_PROBLEM, 117 "Unexpected `!' after --to"); 118 119 parse_to(optarg, &mr->range[mr->rangesize]); 120#ifdef IP_NAT_RANGE_PROTO_RANDOM 121 if (*flags & IPT_SAME_OPT_RANDOM) 122 mr->range[mr->rangesize].flags 123 |= IP_NAT_RANGE_PROTO_RANDOM; 124#endif 125 mr->rangesize++; 126 *flags |= IPT_SAME_OPT_TO; 127 break; 128 129 case '2': 130 if (*flags & IPT_SAME_OPT_NODST) 131 exit_error(PARAMETER_PROBLEM, 132 "Can't specify --nodst twice"); 133 134 mr->info |= IPT_SAME_NODST; 135 *flags |= IPT_SAME_OPT_NODST; 136 break; 137 138#ifdef IP_NAT_RANGE_PROTO_RANDOM 139 case '3': 140 *flags |= IPT_SAME_OPT_RANDOM; 141 for (count=0; count < mr->rangesize; count++) 142 mr->range[count].flags |= IP_NAT_RANGE_PROTO_RANDOM; 143 break; 144#endif 145 default: 146 return 0; 147 } 148 149 return 1; 150} 151 152/* Final check; need --to. */ 153static void final_check(unsigned int flags) 154{ 155 if (!(flags & IPT_SAME_OPT_TO)) 156 exit_error(PARAMETER_PROBLEM, 157 "SAME needs --to"); 158} 159 160/* Prints out the targinfo. */ 161static void 162print(const struct ipt_ip *ip, 163 const struct ipt_entry_target *target, 164 int numeric) 165{ 166 int count; 167 struct ipt_same_info *mr 168 = (struct ipt_same_info *)target->data; 169#ifdef IP_NAT_RANGE_PROTO_RANDOM 170 int random = 0; 171#endif 172 173 printf("same:"); 174 175 for (count = 0; count < mr->rangesize; count++) { 176 struct ip_nat_range *r = &mr->range[count]; 177 struct in_addr a; 178 179 a.s_addr = r->min_ip; 180 181 printf("%s", addr_to_dotted(&a)); 182 a.s_addr = r->max_ip; 183 184 if (r->min_ip == r->max_ip) 185 printf(" "); 186 else 187 printf("-%s ", addr_to_dotted(&a)); 188#ifdef IP_NAT_RANGE_PROTO_RANDOM 189 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) 190 random = 1; 191#endif 192 } 193 194 if (mr->info & IPT_SAME_NODST) 195 printf("nodst "); 196 197#ifdef IP_NAT_RANGE_PROTO_RANDOM 198 if (random) 199 printf("random "); 200#endif 201} 202 203/* Saves the union ipt_targinfo in parsable form to stdout. */ 204static void 205save(const struct ipt_ip *ip, const struct ipt_entry_target *target) 206{ 207 int count; 208 struct ipt_same_info *mr 209 = (struct ipt_same_info *)target->data; 210 211 for (count = 0; count < mr->rangesize; count++) { 212 struct ip_nat_range *r = &mr->range[count]; 213 struct in_addr a; 214 215 a.s_addr = r->min_ip; 216 printf("--to %s", addr_to_dotted(&a)); 217 a.s_addr = r->max_ip; 218 219 if (r->min_ip == r->max_ip) 220 printf(" "); 221 else 222 printf("-%s ", addr_to_dotted(&a)); 223 } 224 225 if (mr->info & IPT_SAME_NODST) 226 printf("--nodst "); 227} 228 229static struct iptables_target same = { 230 .next = NULL, 231 .name = "SAME", 232 .version = IPTABLES_VERSION, 233 .size = IPT_ALIGN(sizeof(struct ipt_same_info)), 234 .userspacesize = IPT_ALIGN(sizeof(struct ipt_same_info)), 235 .help = &help, 236 .init = &init, 237 .parse = &parse, 238 .final_check = &final_check, 239 .print = &print, 240 .save = &save, 241 .extra_opts = opts 242}; 243 244void _init(void) 245{ 246 register_target(&same); 247} 248