1e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdio.h> 2e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <netdb.h> 3e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <string.h> 4e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdlib.h> 5e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <getopt.h> 65d9678ad3eabc34ac40dfe055d7f6a8e44445a5aJan Engelhardt#include <xtables.h> 74e41854423b529d3107c23b85434d50a75d08057Jan Engelhardt#include <limits.h> /* INT_MAX in ip_tables.h */ 8e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <linux/netfilter_ipv4/ip_tables.h> 9e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy#include <linux/netfilter/nf_nat.h> 10e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 11bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardtenum { 12bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt O_TO_PORTS = 0, 13bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt O_RANDOM, 14bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt}; 15bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt 161d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void MASQUERADE_help(void) 17e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 18e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf( 198b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"MASQUERADE target options:\n" 20e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher" --to-ports <port>[-<port>]\n" 21ae4b0b3aa70c67f2eff303a3e75834e45c3794a7Eric Leblond" Port (range) to map to.\n" 22ae4b0b3aa70c67f2eff303a3e75834e45c3794a7Eric Leblond" --random\n" 238b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt" Randomize source port.\n"); 24e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 25e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 26bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardtstatic const struct xt_option_entry MASQUERADE_opts[] = { 27bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, 28bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, 29bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt XTOPT_TABLEEND, 30e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}; 31e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 321d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void MASQUERADE_init(struct xt_entry_target *t) 33e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 34e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data; 35e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 36e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Actually, it's 0, but it's ignored at the moment. */ 37e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher mr->rangesize = 1; 38e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 39e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 40e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Parses ports */ 41e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void 42e62f426c7ead7c0025d15860df97426db6509942Patrick McHardyparse_ports(const char *arg, struct nf_nat_ipv4_multi_range_compat *mr) 43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 447278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin char *end; 457278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin unsigned int port, maxport; 46e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 47e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy mr->range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 48e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 497278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) 507278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); 51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 527278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin switch (*end) { 537278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin case '\0': 54e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher mr->range[0].min.tcp.port 55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher = mr->range[0].max.tcp.port 56f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell = htons(port); 577278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin return; 587278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin case '-': 597278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX)) 607278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin break; 61e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 62e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (maxport < port) 637278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin break; 647278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin 65f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell mr->range[0].min.tcp.port = htons(port); 66f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell mr->range[0].max.tcp.port = htons(maxport); 677278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin return; 687278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin default: 697278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin break; 70e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 717278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); 72e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 73e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 74bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardtstatic void MASQUERADE_parse(struct xt_option_call *cb) 75e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 76bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt const struct ipt_entry *entry = cb->xt_entry; 77e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int portok; 78e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy struct nf_nat_ipv4_multi_range_compat *mr = cb->data; 79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (entry->ip.proto == IPPROTO_TCP 8136d870c76621b94d51816d09eb8fd05e0fb0a0abPatrick McHardy || entry->ip.proto == IPPROTO_UDP 825a942f9501f7ce287e1c37c553eb02a1e269e081Patrick McHardy || entry->ip.proto == IPPROTO_SCTP 835a942f9501f7ce287e1c37c553eb02a1e269e081Patrick McHardy || entry->ip.proto == IPPROTO_DCCP 8436d870c76621b94d51816d09eb8fd05e0fb0a0abPatrick McHardy || entry->ip.proto == IPPROTO_ICMP) 85e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher portok = 1; 86e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher else 87e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher portok = 0; 88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 89bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt xtables_option_parse(cb); 90bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt switch (cb->entry->id) { 91bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt case O_TO_PORTS: 92e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!portok) 931829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 945a942f9501f7ce287e1c37c553eb02a1e269e081Patrick McHardy "Need TCP, UDP, SCTP or DCCP with port specification"); 95bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt parse_ports(cb->arg, mr); 96bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt break; 97bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt case O_RANDOM: 98e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; 99bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt break; 100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void 1041d5b63d12984d12c8d87242179855e17657be16dJan EngelhardtMASQUERADE_print(const void *ip, const struct xt_entry_target *target, 1051d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt int numeric) 106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 107e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; 108e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy const struct nf_nat_ipv4_range *r = &mr->range[0]; 109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 110e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { 11173866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" masq ports: "); 112f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell printf("%hu", ntohs(r->min.tcp.port)); 113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (r->max.tcp.port != r->min.tcp.port) 114f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell printf("-%hu", ntohs(r->max.tcp.port)); 115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 116ae4b0b3aa70c67f2eff303a3e75834e45c3794a7Eric Leblond 117e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) 11873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" random"); 119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 120e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void 1221d5b63d12984d12c8d87242179855e17657be16dJan EngelhardtMASQUERADE_save(const void *ip, const struct xt_entry_target *target) 123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 124e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; 125e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy const struct nf_nat_ipv4_range *r = &mr->range[0]; 126e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 127e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { 12873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" --to-ports %hu", ntohs(r->min.tcp.port)); 129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (r->max.tcp.port != r->min.tcp.port) 130f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell printf("-%hu", ntohs(r->max.tcp.port)); 131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1329c67defe98f04f72f19dfd09c8030e1de4b8bf0fPatrick McHardy 133e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) 13473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" --random"); 135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1378b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardtstatic struct xtables_target masquerade_tg_reg = { 1388caee8b9e34fed4562fcff553197c161fc9d9979Pablo Neira .name = "MASQUERADE", 1398b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt .version = XTABLES_VERSION, 14003d99486d8283552705b58dc55b6085dffc38792Jan Engelhardt .family = NFPROTO_IPV4, 141e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), 142e62f426c7ead7c0025d15860df97426db6509942Patrick McHardy .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), 1431d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .help = MASQUERADE_help, 1441d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .init = MASQUERADE_init, 145bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt .x6_parse = MASQUERADE_parse, 1461d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .print = MASQUERADE_print, 1471d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .save = MASQUERADE_save, 148bf07750fd4fc5f5e603e59e72d62696d2389e9b3Jan Engelhardt .x6_options = MASQUERADE_opts, 149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}; 150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid _init(void) 152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1538b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt xtables_register_target(&masquerade_tg_reg); 154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 155