libipt_SAME.c revision 8b7c64d6ba156a99008fcd810cba874c73294333
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 SAME_help(void) 15{ 16 printf( 17"SAME target options:\n" 18" --to <ipaddr>-<ipaddr>\n" 19" Addresses to map source to.\n" 20" May be specified more than\n" 21" once for multiple ranges.\n" 22" --nodst\n" 23" Don't use destination-ip in\n" 24" source selection\n" 25" --random\n" 26" Randomize source port\n"); 27} 28 29static const struct option SAME_opts[] = { 30 { "to", 1, NULL, '1' }, 31 { "nodst", 0, NULL, '2'}, 32 { "random", 0, NULL, '3' }, 33 { .name = NULL } 34}; 35 36/* Initialize the target. */ 37static void SAME_init(struct xt_entry_target *t) 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 */ 49static void 50parse_to(char *arg, struct ip_nat_range *range) 51{ 52 char *dash; 53 const 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 = numeric_to_ipaddr(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 = numeric_to_ipaddr(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#define IPT_SAME_OPT_RANDOM 0x04 83 84/* Function which parses command options; returns true if it 85 ate an option */ 86static int SAME_parse(int c, char **argv, int invert, unsigned int *flags, 87 const void *entry, struct xt_entry_target **target) 88{ 89 struct ipt_same_info *mr 90 = (struct ipt_same_info *)(*target)->data; 91 unsigned int count; 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 /* WTF do we need this for? */ 106 if (*flags & IPT_SAME_OPT_RANDOM) 107 mr->range[mr->rangesize].flags 108 |= IP_NAT_RANGE_PROTO_RANDOM; 109 mr->rangesize++; 110 *flags |= IPT_SAME_OPT_TO; 111 break; 112 113 case '2': 114 if (*flags & IPT_SAME_OPT_NODST) 115 exit_error(PARAMETER_PROBLEM, 116 "Can't specify --nodst twice"); 117 118 mr->info |= IPT_SAME_NODST; 119 *flags |= IPT_SAME_OPT_NODST; 120 break; 121 122 case '3': 123 *flags |= IPT_SAME_OPT_RANDOM; 124 for (count=0; count < mr->rangesize; count++) 125 mr->range[count].flags |= IP_NAT_RANGE_PROTO_RANDOM; 126 break; 127 128 default: 129 return 0; 130 } 131 132 return 1; 133} 134 135/* Final check; need --to. */ 136static void SAME_check(unsigned int flags) 137{ 138 if (!(flags & IPT_SAME_OPT_TO)) 139 exit_error(PARAMETER_PROBLEM, 140 "SAME needs --to"); 141} 142 143/* Prints out the targinfo. */ 144static void SAME_print(const void *ip, const struct xt_entry_target *target, 145 int numeric) 146{ 147 unsigned int count; 148 struct ipt_same_info *mr 149 = (struct ipt_same_info *)target->data; 150 int random_selection = 0; 151 152 printf("same:"); 153 154 for (count = 0; count < mr->rangesize; count++) { 155 struct ip_nat_range *r = &mr->range[count]; 156 struct in_addr a; 157 158 a.s_addr = r->min_ip; 159 160 printf("%s", ipaddr_to_numeric(&a)); 161 a.s_addr = r->max_ip; 162 163 if (r->min_ip == r->max_ip) 164 printf(" "); 165 else 166 printf("-%s ", ipaddr_to_numeric(&a)); 167 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) 168 random_selection = 1; 169 } 170 171 if (mr->info & IPT_SAME_NODST) 172 printf("nodst "); 173 174 if (random_selection) 175 printf("random "); 176} 177 178/* Saves the union ipt_targinfo in parsable form to stdout. */ 179static void SAME_save(const void *ip, const struct xt_entry_target *target) 180{ 181 unsigned int count; 182 struct ipt_same_info *mr 183 = (struct ipt_same_info *)target->data; 184 int random_selection = 0; 185 186 for (count = 0; count < mr->rangesize; count++) { 187 struct ip_nat_range *r = &mr->range[count]; 188 struct in_addr a; 189 190 a.s_addr = r->min_ip; 191 printf("--to %s", ipaddr_to_numeric(&a)); 192 a.s_addr = r->max_ip; 193 194 if (r->min_ip == r->max_ip) 195 printf(" "); 196 else 197 printf("-%s ", ipaddr_to_numeric(&a)); 198 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) 199 random_selection = 1; 200 } 201 202 if (mr->info & IPT_SAME_NODST) 203 printf("--nodst "); 204 205 if (random_selection) 206 printf("--random "); 207} 208 209static struct xtables_target same_tg_reg = { 210 .name = "SAME", 211 .version = XTABLES_VERSION, 212 .family = PF_INET, 213 .size = XT_ALIGN(sizeof(struct ipt_same_info)), 214 .userspacesize = XT_ALIGN(sizeof(struct ipt_same_info)), 215 .help = SAME_help, 216 .init = SAME_init, 217 .parse = SAME_parse, 218 .final_check = SAME_check, 219 .print = SAME_print, 220 .save = SAME_save, 221 .extra_opts = SAME_opts, 222}; 223 224void _init(void) 225{ 226 xtables_register_target(&same_tg_reg); 227} 228