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