10e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy/* 20e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> 30e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy * 40e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy * Based on Rusty Russell's IPv4 MASQUERADE target. Development of IPv6 NAT 50e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy * funded by Astaro. 60e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy */ 70e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 80e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <stdio.h> 90e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <netdb.h> 100e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <string.h> 110e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <stdlib.h> 120e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <getopt.h> 130e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <xtables.h> 140e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <limits.h> /* INT_MAX in ip_tables.h */ 150e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <linux/netfilter_ipv6/ip6_tables.h> 160e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <linux/netfilter/nf_nat.h> 170e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 180e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardyenum { 190e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy O_TO_PORTS = 0, 200e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy O_RANDOM, 210e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy}; 220e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 230e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic void MASQUERADE_help(void) 240e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy{ 250e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy printf( 260e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy"MASQUERADE target options:\n" 270e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy" --to-ports <port>[-<port>]\n" 280e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy" Port (range) to map to.\n" 290e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy" --random\n" 300e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy" Randomize source port.\n"); 310e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy} 320e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 330e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic const struct xt_option_entry MASQUERADE_opts[] = { 340e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, 350e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, 360e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy XTOPT_TABLEEND, 370e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy}; 380e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 390e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy/* Parses ports */ 400e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic void 410e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardyparse_ports(const char *arg, struct nf_nat_range *r) 420e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy{ 430e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy char *end; 440e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy unsigned int port, maxport; 450e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 460e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy r->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 470e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 480e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) 490e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); 500e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 510e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy switch (*end) { 520e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy case '\0': 530e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy r->min_proto.tcp.port 540e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy = r->max_proto.tcp.port 550e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy = htons(port); 560e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy return; 570e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy case '-': 580e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX)) 590e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy break; 600e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 610e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy if (maxport < port) 620e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy break; 630e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 640e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy r->min_proto.tcp.port = htons(port); 650e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy r->max_proto.tcp.port = htons(maxport); 660e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy return; 670e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy default: 680e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy break; 690e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy } 700e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); 710e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy} 720e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 730e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic void MASQUERADE_parse(struct xt_option_call *cb) 740e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy{ 750e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy const struct ip6t_entry *entry = cb->xt_entry; 760e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy struct nf_nat_range *r = cb->data; 770e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy int portok; 780e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 790e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy if (entry->ipv6.proto == IPPROTO_TCP || 800e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy entry->ipv6.proto == IPPROTO_UDP || 810e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy entry->ipv6.proto == IPPROTO_SCTP || 820e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy entry->ipv6.proto == IPPROTO_DCCP || 830e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy entry->ipv6.proto == IPPROTO_ICMP) 840e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy portok = 1; 850e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy else 860e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy portok = 0; 870e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 880e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy xtables_option_parse(cb); 890e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy switch (cb->entry->id) { 900e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy case O_TO_PORTS: 910e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy if (!portok) 920e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy xtables_error(PARAMETER_PROBLEM, 930e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy "Need TCP, UDP, SCTP or DCCP with port specification"); 940e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy parse_ports(cb->arg, r); 950e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy break; 960e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy case O_RANDOM: 970e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy r->flags |= NF_NAT_RANGE_PROTO_RANDOM; 980e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy break; 990e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy } 1000e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy} 1010e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 1020e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic void 1030e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardyMASQUERADE_print(const void *ip, const struct xt_entry_target *target, 1040e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy int numeric) 1050e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy{ 1060e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy const struct nf_nat_range *r = (const void *)target->data; 1070e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 1080e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { 1090e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy printf(" masq ports: "); 1100e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy printf("%hu", ntohs(r->min_proto.tcp.port)); 1110e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy if (r->max_proto.tcp.port != r->min_proto.tcp.port) 1120e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy printf("-%hu", ntohs(r->max_proto.tcp.port)); 1130e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy } 1140e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 1150e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) 1160e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy printf(" random"); 1170e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy} 1180e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 1190e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic void 1200e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardyMASQUERADE_save(const void *ip, const struct xt_entry_target *target) 1210e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy{ 1220e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy const struct nf_nat_range *r = (const void *)target->data; 1230e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 1240e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { 1250e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy printf(" --to-ports %hu", ntohs(r->min_proto.tcp.port)); 1260e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy if (r->max_proto.tcp.port != r->min_proto.tcp.port) 1270e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy printf("-%hu", ntohs(r->max_proto.tcp.port)); 1280e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy } 1290e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 1300e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) 1310e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy printf(" --random"); 1320e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy} 1330e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 1347a0992da44cfb6cab0ccd1beadcf326df8773552Pablo Neira Ayusostatic int MASQUERADE_xlate(struct xt_xlate *xl, 1357a0992da44cfb6cab0ccd1beadcf326df8773552Pablo Neira Ayuso const struct xt_xlate_tg_params *params) 136c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj{ 1377a0992da44cfb6cab0ccd1beadcf326df8773552Pablo Neira Ayuso const struct nf_nat_range *r = (const void *)params->target->data; 138c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj 139c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj xt_xlate_add(xl, "masquerade"); 140c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj 141c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { 142c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj xt_xlate_add(xl, " to :%hu", ntohs(r->min_proto.tcp.port)); 143c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj if (r->max_proto.tcp.port != r->min_proto.tcp.port) 144c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj xt_xlate_add(xl, "-%hu", ntohs(r->max_proto.tcp.port)); 145c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj } 146c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj 147c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj xt_xlate_add(xl, " "); 148c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) 149c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj xt_xlate_add(xl, "random "); 150c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj 151c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj return 1; 152c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj} 153c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj 1540e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic struct xtables_target masquerade_tg_reg = { 1550e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy .name = "MASQUERADE", 1560e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy .version = XTABLES_VERSION, 1570e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy .family = NFPROTO_IPV6, 1580e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy .size = XT_ALIGN(sizeof(struct nf_nat_range)), 1590e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), 1600e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy .help = MASQUERADE_help, 1610e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy .x6_parse = MASQUERADE_parse, 1620e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy .print = MASQUERADE_print, 1630e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy .save = MASQUERADE_save, 1640e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy .x6_options = MASQUERADE_opts, 165c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj .xlate = MASQUERADE_xlate, 1660e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy}; 1670e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy 1680e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardyvoid _init(void) 1690e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy{ 1700e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy xtables_register_target(&masquerade_tg_reg); 1710e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy} 172