1f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson#include <stdio.h> 2f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson#include <string.h> 3f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson#include <stdlib.h> 45d9678ad3eabc34ac40dfe055d7f6a8e44445a5aJan Engelhardt#include <xtables.h> 5e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy#include <linux/netfilter/nf_nat.h> 6a2a7f2b531cc582ab6cc3c2b73715ed1d58b9eabJan Engelhardt#include <linux/netfilter_ipv4/ipt_SAME.h> 7f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 88d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardtenum { 98d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt O_TO_ADDR = 0, 108d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt O_NODST, 118d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt O_RANDOM, 123964023f8640b60456373825b326b91badd7a058Jan Engelhardt F_TO_ADDR = 1 << O_TO_ADDR, 133964023f8640b60456373825b326b91badd7a058Jan Engelhardt F_RANDOM = 1 << O_RANDOM, 148d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt}; 158d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt 161d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void SAME_help(void) 17f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson{ 18f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson printf( 198b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"SAME target options:\n" 2018f1aff721e19486d87342abb594831b08b1083eHarald Welte" --to <ipaddr>-<ipaddr>\n" 21cf655eb194951a93e4e1371747273c12466c1952Harald Welte" Addresses to map source to.\n" 2205e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte" May be specified more than\n" 2305e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte" once for multiple ranges.\n" 24cf655eb194951a93e4e1371747273c12466c1952Harald Welte" --nodst\n" 25cf655eb194951a93e4e1371747273c12466c1952Harald Welte" Don't use destination-ip in\n" 26ae4b0b3aa70c67f2eff303a3e75834e45c3794a7Eric Leblond" source selection\n" 27ae4b0b3aa70c67f2eff303a3e75834e45c3794a7Eric Leblond" --random\n" 288b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt" Randomize source port\n"); 29f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson} 30f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 318d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardtstatic const struct xt_option_entry SAME_opts[] = { 328d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt {.name = "to", .id = O_TO_ADDR, .type = XTTYPE_STRING, 338d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt .flags = XTOPT_MAND}, 348d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt {.name = "nodst", .id = O_NODST, .type = XTTYPE_NONE}, 358d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, 368d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt XTOPT_TABLEEND, 37f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson}; 38f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 39f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson/* Parses range of IPs */ 40e62f426c7ead7c0025d15860df97426db6509942Patrick McHardystatic void parse_to(const char *orig_arg, struct nf_nat_ipv4_range *range) 41f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson{ 428d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt char *dash, *arg; 43bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt const struct in_addr *ip; 44f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 458d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt arg = strdup(orig_arg); 468d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt if (arg == NULL) 478d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt xtables_error(RESOURCE_PROBLEM, "strdup"); 48e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy range->flags |= NF_NAT_RANGE_MAP_IPS; 49f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson dash = strchr(arg, '-'); 5005e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte 51f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson if (dash) 52f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson *dash = '\0'; 53f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 541e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt ip = xtables_numeric_to_ipaddr(arg); 55f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson if (!ip) 561829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", 57f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson arg); 58f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson range->min_ip = ip->s_addr; 5905e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte 6005e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte if (dash) { 611e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt ip = xtables_numeric_to_ipaddr(dash+1); 6205e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte if (!ip) 631829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", 6405e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte dash+1); 6505e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte } 66f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson range->max_ip = ip->s_addr; 6705e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte if (dash) 6805e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte if (range->min_ip > range->max_ip) 691829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, "Bad IP range \"%s-%s\"\n", 7005e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte arg, dash+1); 718d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt free(arg); 72f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson} 73f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 748d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardtstatic void SAME_parse(struct xt_option_call *cb) 75f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson{ 768d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt struct ipt_same_info *mr = cb->data; 77e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy unsigned int count; 78f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 798d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt xtables_option_parse(cb); 808d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt switch (cb->entry->id) { 818d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt case O_TO_ADDR: 8205e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte if (mr->rangesize == IPT_SAME_MAX_RANGE) 831829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 8405e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte "Too many ranges specified, maximum " 8505e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte "is %i ranges.\n", 8605e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte IPT_SAME_MAX_RANGE); 878d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt parse_to(cb->arg, &mr->range[mr->rangesize]); 8805e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte mr->rangesize++; 89cf655eb194951a93e4e1371747273c12466c1952Harald Welte break; 908d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt case O_NODST: 91cf655eb194951a93e4e1371747273c12466c1952Harald Welte mr->info |= IPT_SAME_NODST; 92cf655eb194951a93e4e1371747273c12466c1952Harald Welte break; 93e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy case O_RANDOM: 94e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy for (count=0; count < mr->rangesize; count++) 95e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy mr->range[count].flags |= NF_NAT_RANGE_PROTO_RANDOM; 96e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy break; 97f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson } 98f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson} 99f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 1003964023f8640b60456373825b326b91badd7a058Jan Engelhardtstatic void SAME_fcheck(struct xt_fcheck_call *cb) 1013964023f8640b60456373825b326b91badd7a058Jan Engelhardt{ 1023964023f8640b60456373825b326b91badd7a058Jan Engelhardt static const unsigned int f = F_TO_ADDR | F_RANDOM; 1033964023f8640b60456373825b326b91badd7a058Jan Engelhardt struct ipt_same_info *mr = cb->data; 1043964023f8640b60456373825b326b91badd7a058Jan Engelhardt unsigned int count; 1053964023f8640b60456373825b326b91badd7a058Jan Engelhardt 1063964023f8640b60456373825b326b91badd7a058Jan Engelhardt if ((cb->xflags & f) == f) 1073964023f8640b60456373825b326b91badd7a058Jan Engelhardt for (count = 0; count < mr->rangesize; ++count) 108e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy mr->range[count].flags |= NF_NAT_RANGE_PROTO_RANDOM; 1093964023f8640b60456373825b326b91badd7a058Jan Engelhardt} 1103964023f8640b60456373825b326b91badd7a058Jan Engelhardt 1111d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void SAME_print(const void *ip, const struct xt_entry_target *target, 1121d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt int numeric) 113f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson{ 1147a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt unsigned int count; 11569f564e3890976461de0016cd81171ff8bfa8353Jan Engelhardt const struct ipt_same_info *mr = (const void *)target->data; 116dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt int random_selection = 0; 11705e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte 11873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" same:"); 11973866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt 12005e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte for (count = 0; count < mr->rangesize; count++) { 121e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy const struct nf_nat_ipv4_range *r = &mr->range[count]; 12205e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte struct in_addr a; 123f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 12405e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte a.s_addr = r->min_ip; 125f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 126e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt printf("%s", xtables_ipaddr_to_numeric(&a)); 12705e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte a.s_addr = r->max_ip; 12805e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte 12973866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt if (r->min_ip != r->max_ip) 13073866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf("-%s", xtables_ipaddr_to_numeric(&a)); 131e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) 132dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt random_selection = 1; 13305e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte } 134cf655eb194951a93e4e1371747273c12466c1952Harald Welte 135cf655eb194951a93e4e1371747273c12466c1952Harald Welte if (mr->info & IPT_SAME_NODST) 13673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" nodst"); 137ae4b0b3aa70c67f2eff303a3e75834e45c3794a7Eric Leblond 138dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt if (random_selection) 13973866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" random"); 140f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson} 141f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 1421d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void SAME_save(const void *ip, const struct xt_entry_target *target) 143f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson{ 1447a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt unsigned int count; 14569f564e3890976461de0016cd81171ff8bfa8353Jan Engelhardt const struct ipt_same_info *mr = (const void *)target->data; 146dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt int random_selection = 0; 147f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 14805e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte for (count = 0; count < mr->rangesize; count++) { 149e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy const struct nf_nat_ipv4_range *r = &mr->range[count]; 15005e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte struct in_addr a; 15105e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte 15205e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte a.s_addr = r->min_ip; 15373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" --to %s", xtables_ipaddr_to_numeric(&a)); 15405e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte a.s_addr = r->max_ip; 15505e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte 15673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt if (r->min_ip != r->max_ip) 15773866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf("-%s", xtables_ipaddr_to_numeric(&a)); 158e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) 159dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt random_selection = 1; 16005e0b01bd1cd4035893c33c7084164bd8fab37c8Harald Welte } 161cf655eb194951a93e4e1371747273c12466c1952Harald Welte 162cf655eb194951a93e4e1371747273c12466c1952Harald Welte if (mr->info & IPT_SAME_NODST) 16373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" --nodst"); 1649c67defe98f04f72f19dfd09c8030e1de4b8bf0fPatrick McHardy 165dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt if (random_selection) 16673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" --random"); 167f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson} 168f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 1698b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardtstatic struct xtables_target same_tg_reg = { 1708caee8b9e34fed4562fcff553197c161fc9d9979Pablo Neira .name = "SAME", 1718b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt .version = XTABLES_VERSION, 17203d99486d8283552705b58dc55b6085dffc38792Jan Engelhardt .family = NFPROTO_IPV4, 1738b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt .size = XT_ALIGN(sizeof(struct ipt_same_info)), 1748b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt .userspacesize = XT_ALIGN(sizeof(struct ipt_same_info)), 1751d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .help = SAME_help, 1768d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt .x6_parse = SAME_parse, 1773964023f8640b60456373825b326b91badd7a058Jan Engelhardt .x6_fcheck = SAME_fcheck, 1781d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .print = SAME_print, 1791d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .save = SAME_save, 1808d14aeb8c4c3dc8ce9264b04b97f2e8634c1f381Jan Engelhardt .x6_options = SAME_opts, 181f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson}; 182f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson 183f419f759735f33721a9506230d9444fb3dce5024Martin Josefssonvoid _init(void) 184f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson{ 1858b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt xtables_register_target(&same_tg_reg); 186f419f759735f33721a9506230d9444fb3dce5024Martin Josefsson} 187