libipt_MASQUERADE.c revision 7278461dfad72e2008585dd0bac0e889e5bba99e
1e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Shared library add-on to iptables to add masquerade support. */ 2e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdio.h> 3e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <netdb.h> 4e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <string.h> 5e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdlib.h> 6e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <getopt.h> 75d9678ad3eabc34ac40dfe055d7f6a8e44445a5aJan Engelhardt#include <xtables.h> 84e41854423b529d3107c23b85434d50a75d08057Jan Engelhardt#include <limits.h> /* INT_MAX in ip_tables.h */ 9e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <linux/netfilter_ipv4/ip_tables.h> 10978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardt#include <net/netfilter/nf_nat.h> 11e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 121d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void MASQUERADE_help(void) 13e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 14e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf( 158b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"MASQUERADE target options:\n" 16e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher" --to-ports <port>[-<port>]\n" 17ae4b0b3aa70c67f2eff303a3e75834e45c3794a7Eric Leblond" Port (range) to map to.\n" 18ae4b0b3aa70c67f2eff303a3e75834e45c3794a7Eric Leblond" --random\n" 198b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt" Randomize source port.\n"); 20e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 21e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 221d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic const struct option MASQUERADE_opts[] = { 23500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy { "to-ports", 1, NULL, '1' }, 24500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy { "random", 0, NULL, '2' }, 259ee386a1b6d7704b259460152c959ab0e79e02aaMax Kellermann { .name = NULL } 26e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}; 27e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 281d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void MASQUERADE_init(struct xt_entry_target *t) 29e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 30978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardt struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data; 31e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 32e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Actually, it's 0, but it's ignored at the moment. */ 33e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher mr->rangesize = 1; 34e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 35e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 36e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 37e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Parses ports */ 38e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void 39978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardtparse_ports(const char *arg, struct nf_nat_multi_range *mr) 40e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 417278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin char *end; 427278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin unsigned int port, maxport; 43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; 45e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 467278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) 477278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); 48e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 497278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin switch (*end) { 507278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin case '\0': 51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher mr->range[0].min.tcp.port 52e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher = mr->range[0].max.tcp.port 53f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell = htons(port); 547278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin return; 557278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin case '-': 567278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX)) 577278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin break; 58e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 59e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (maxport < port) 607278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin break; 617278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin 62f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell mr->range[0].min.tcp.port = htons(port); 63f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell mr->range[0].max.tcp.port = htons(maxport); 647278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin return; 657278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin default: 667278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin break; 67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 687278461dfad72e2008585dd0bac0e889e5bba99eDmitry V. Levin xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); 69e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 70e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 711d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic int MASQUERADE_parse(int c, char **argv, int invert, unsigned int *flags, 721d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt const void *e, struct xt_entry_target **target) 73e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 74ac8b2718daf8a79a59b181f6e62495f307ae86b9Yasuyuki KOZAKAI const struct ipt_entry *entry = e; 75e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int portok; 76978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardt struct nf_nat_multi_range *mr 77978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardt = (struct nf_nat_multi_range *)(*target)->data; 78e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (entry->ip.proto == IPPROTO_TCP 8036d870c76621b94d51816d09eb8fd05e0fb0a0abPatrick McHardy || entry->ip.proto == IPPROTO_UDP 815a942f9501f7ce287e1c37c553eb02a1e269e081Patrick McHardy || entry->ip.proto == IPPROTO_SCTP 825a942f9501f7ce287e1c37c553eb02a1e269e081Patrick McHardy || entry->ip.proto == IPPROTO_DCCP 8336d870c76621b94d51816d09eb8fd05e0fb0a0abPatrick McHardy || entry->ip.proto == IPPROTO_ICMP) 84e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher portok = 1; 85e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher else 86e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher portok = 0; 87e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher switch (c) { 89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher case '1': 90e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!portok) 911829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 925a942f9501f7ce287e1c37c553eb02a1e269e081Patrick McHardy "Need TCP, UDP, SCTP or DCCP with port specification"); 93e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 94bf97128c7262f17a02fec41cdae75b472ba77f88Jan Engelhardt if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) 951829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 96e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher "Unexpected `!' after --to-ports"); 97e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 98e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher parse_ports(optarg, mr); 99e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 101ae4b0b3aa70c67f2eff303a3e75834e45c3794a7Eric Leblond case '2': 102ae4b0b3aa70c67f2eff303a3e75834e45c3794a7Eric Leblond mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; 103ae4b0b3aa70c67f2eff303a3e75834e45c3794a7Eric Leblond return 1; 104ae4b0b3aa70c67f2eff303a3e75834e45c3794a7Eric Leblond 105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher default: 106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 110e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void 1111d5b63d12984d12c8d87242179855e17657be16dJan EngelhardtMASQUERADE_print(const void *ip, const struct xt_entry_target *target, 1121d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt int numeric) 113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 11469f564e3890976461de0016cd81171ff8bfa8353Jan Engelhardt const struct nf_nat_multi_range *mr = (const void *)target->data; 11569f564e3890976461de0016cd81171ff8bfa8353Jan Engelhardt const struct nf_nat_range *r = &mr->range[0]; 116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { 118f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell printf("masq ports: "); 119f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell printf("%hu", ntohs(r->min.tcp.port)); 120e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (r->max.tcp.port != r->min.tcp.port) 121f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell printf("-%hu", ntohs(r->max.tcp.port)); 122e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf(" "); 123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 124ae4b0b3aa70c67f2eff303a3e75834e45c3794a7Eric Leblond 125e656e265bc67a55f6e51aa07118f96c058a97798Patrick McHardy if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) 1269c67defe98f04f72f19dfd09c8030e1de4b8bf0fPatrick McHardy printf("random "); 127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void 1301d5b63d12984d12c8d87242179855e17657be16dJan EngelhardtMASQUERADE_save(const void *ip, const struct xt_entry_target *target) 131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 13269f564e3890976461de0016cd81171ff8bfa8353Jan Engelhardt const struct nf_nat_multi_range *mr = (const void *)target->data; 13369f564e3890976461de0016cd81171ff8bfa8353Jan Engelhardt const struct nf_nat_range *r = &mr->range[0]; 134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { 1364b5566b718ccd52a11d5eabe1de9b1f4ff10ce41A. van Schie printf("--to-ports %hu", ntohs(r->min.tcp.port)); 137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (r->max.tcp.port != r->min.tcp.port) 138f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell printf("-%hu", ntohs(r->max.tcp.port)); 139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf(" "); 140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1419c67defe98f04f72f19dfd09c8030e1de4b8bf0fPatrick McHardy 1429c67defe98f04f72f19dfd09c8030e1de4b8bf0fPatrick McHardy if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) 1439c67defe98f04f72f19dfd09c8030e1de4b8bf0fPatrick McHardy printf("--random "); 144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1468b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardtstatic struct xtables_target masquerade_tg_reg = { 1478caee8b9e34fed4562fcff553197c161fc9d9979Pablo Neira .name = "MASQUERADE", 1488b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt .version = XTABLES_VERSION, 14903d99486d8283552705b58dc55b6085dffc38792Jan Engelhardt .family = NFPROTO_IPV4, 150978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardt .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 151978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardt .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 1521d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .help = MASQUERADE_help, 1531d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .init = MASQUERADE_init, 1541d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .parse = MASQUERADE_parse, 1551d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .print = MASQUERADE_print, 1561d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .save = MASQUERADE_save, 1571d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .extra_opts = MASQUERADE_opts, 158e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}; 159e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid _init(void) 161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1628b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt xtables_register_target(&masquerade_tg_reg); 163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 164