1#include <stdio.h> 2#include <string.h> 3#include <stdlib.h> 4#include <xtables.h> 5#include <linux/netfilter/nf_nat.h> 6#include <linux/netfilter_ipv4/ipt_SAME.h> 7 8enum { 9 O_TO_ADDR = 0, 10 O_NODST, 11 O_RANDOM, 12 F_TO_ADDR = 1 << O_TO_ADDR, 13 F_RANDOM = 1 << O_RANDOM, 14}; 15 16static void SAME_help(void) 17{ 18 printf( 19"SAME target options:\n" 20" --to <ipaddr>-<ipaddr>\n" 21" Addresses to map source to.\n" 22" May be specified more than\n" 23" once for multiple ranges.\n" 24" --nodst\n" 25" Don't use destination-ip in\n" 26" source selection\n" 27" --random\n" 28" Randomize source port\n"); 29} 30 31static const struct xt_option_entry SAME_opts[] = { 32 {.name = "to", .id = O_TO_ADDR, .type = XTTYPE_STRING, 33 .flags = XTOPT_MAND}, 34 {.name = "nodst", .id = O_NODST, .type = XTTYPE_NONE}, 35 {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, 36 XTOPT_TABLEEND, 37}; 38 39/* Parses range of IPs */ 40static void parse_to(const char *orig_arg, struct nf_nat_ipv4_range *range) 41{ 42 char *dash, *arg; 43 const struct in_addr *ip; 44 45 arg = strdup(orig_arg); 46 if (arg == NULL) 47 xtables_error(RESOURCE_PROBLEM, "strdup"); 48 range->flags |= NF_NAT_RANGE_MAP_IPS; 49 dash = strchr(arg, '-'); 50 51 if (dash) 52 *dash = '\0'; 53 54 ip = xtables_numeric_to_ipaddr(arg); 55 if (!ip) 56 xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", 57 arg); 58 range->min_ip = ip->s_addr; 59 60 if (dash) { 61 ip = xtables_numeric_to_ipaddr(dash+1); 62 if (!ip) 63 xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", 64 dash+1); 65 } 66 range->max_ip = ip->s_addr; 67 if (dash) 68 if (range->min_ip > range->max_ip) 69 xtables_error(PARAMETER_PROBLEM, "Bad IP range \"%s-%s\"\n", 70 arg, dash+1); 71 free(arg); 72} 73 74static void SAME_parse(struct xt_option_call *cb) 75{ 76 struct ipt_same_info *mr = cb->data; 77 unsigned int count; 78 79 xtables_option_parse(cb); 80 switch (cb->entry->id) { 81 case O_TO_ADDR: 82 if (mr->rangesize == IPT_SAME_MAX_RANGE) 83 xtables_error(PARAMETER_PROBLEM, 84 "Too many ranges specified, maximum " 85 "is %i ranges.\n", 86 IPT_SAME_MAX_RANGE); 87 parse_to(cb->arg, &mr->range[mr->rangesize]); 88 mr->rangesize++; 89 break; 90 case O_NODST: 91 mr->info |= IPT_SAME_NODST; 92 break; 93 case O_RANDOM: 94 for (count=0; count < mr->rangesize; count++) 95 mr->range[count].flags |= NF_NAT_RANGE_PROTO_RANDOM; 96 break; 97 } 98} 99 100static void SAME_fcheck(struct xt_fcheck_call *cb) 101{ 102 static const unsigned int f = F_TO_ADDR | F_RANDOM; 103 struct ipt_same_info *mr = cb->data; 104 unsigned int count; 105 106 if ((cb->xflags & f) == f) 107 for (count = 0; count < mr->rangesize; ++count) 108 mr->range[count].flags |= NF_NAT_RANGE_PROTO_RANDOM; 109} 110 111static void SAME_print(const void *ip, const struct xt_entry_target *target, 112 int numeric) 113{ 114 unsigned int count; 115 const struct ipt_same_info *mr = (const void *)target->data; 116 int random_selection = 0; 117 118 printf(" same:"); 119 120 for (count = 0; count < mr->rangesize; count++) { 121 const struct nf_nat_ipv4_range *r = &mr->range[count]; 122 struct in_addr a; 123 124 a.s_addr = r->min_ip; 125 126 printf("%s", xtables_ipaddr_to_numeric(&a)); 127 a.s_addr = r->max_ip; 128 129 if (r->min_ip != r->max_ip) 130 printf("-%s", xtables_ipaddr_to_numeric(&a)); 131 if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) 132 random_selection = 1; 133 } 134 135 if (mr->info & IPT_SAME_NODST) 136 printf(" nodst"); 137 138 if (random_selection) 139 printf(" random"); 140} 141 142static void SAME_save(const void *ip, const struct xt_entry_target *target) 143{ 144 unsigned int count; 145 const struct ipt_same_info *mr = (const void *)target->data; 146 int random_selection = 0; 147 148 for (count = 0; count < mr->rangesize; count++) { 149 const struct nf_nat_ipv4_range *r = &mr->range[count]; 150 struct in_addr a; 151 152 a.s_addr = r->min_ip; 153 printf(" --to %s", xtables_ipaddr_to_numeric(&a)); 154 a.s_addr = r->max_ip; 155 156 if (r->min_ip != r->max_ip) 157 printf("-%s", xtables_ipaddr_to_numeric(&a)); 158 if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) 159 random_selection = 1; 160 } 161 162 if (mr->info & IPT_SAME_NODST) 163 printf(" --nodst"); 164 165 if (random_selection) 166 printf(" --random"); 167} 168 169static struct xtables_target same_tg_reg = { 170 .name = "SAME", 171 .version = XTABLES_VERSION, 172 .family = NFPROTO_IPV4, 173 .size = XT_ALIGN(sizeof(struct ipt_same_info)), 174 .userspacesize = XT_ALIGN(sizeof(struct ipt_same_info)), 175 .help = SAME_help, 176 .x6_parse = SAME_parse, 177 .x6_fcheck = SAME_fcheck, 178 .print = SAME_print, 179 .save = SAME_save, 180 .x6_options = SAME_opts, 181}; 182 183void _init(void) 184{ 185 xtables_register_target(&same_tg_reg); 186} 187