blob: 1f932949f0e44616d1d669a7247278fb60c93786 [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* Shared library add-on to iptables to add masquerade support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
Jan Engelhardt5d9678a2008-11-20 10:15:35 +01007#include <xtables.h>
Marc Bouchere6869a82000-03-20 06:03:29 +00008#include <linux/netfilter_ipv4/ip_tables.h>
Patrick McHardy40d54752007-04-18 07:00:36 +00009#include <linux/netfilter/nf_nat.h>
Marc Bouchere6869a82000-03-20 06:03:29 +000010
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000011static void MASQUERADE_help(void)
Marc Bouchere6869a82000-03-20 06:03:29 +000012{
13 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020014"MASQUERADE target options:\n"
Marc Bouchere6869a82000-03-20 06:03:29 +000015" --to-ports <port>[-<port>]\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000016" Port (range) to map to.\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000017" --random\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020018" Randomize source port.\n");
Marc Bouchere6869a82000-03-20 06:03:29 +000019}
20
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000021static const struct option MASQUERADE_opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000022 { "to-ports", 1, NULL, '1' },
23 { "random", 0, NULL, '2' },
Max Kellermann9ee386a2008-01-29 13:48:05 +000024 { .name = NULL }
Marc Bouchere6869a82000-03-20 06:03:29 +000025};
26
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000027static void MASQUERADE_init(struct xt_entry_target *t)
Marc Bouchere6869a82000-03-20 06:03:29 +000028{
29 struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data;
30
31 /* Actually, it's 0, but it's ignored at the moment. */
32 mr->rangesize = 1;
33
Marc Bouchere6869a82000-03-20 06:03:29 +000034}
35
36/* Parses ports */
37static void
38parse_ports(const char *arg, struct ip_nat_multi_range *mr)
39{
40 const char *dash;
41 int port;
42
43 mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
44
45 port = atoi(arg);
Yasuyuki KOZAKAI1d095f82003-10-30 06:36:49 +000046 if (port <= 0 || port > 65535)
Marc Bouchere6869a82000-03-20 06:03:29 +000047 exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", arg);
48
49 dash = strchr(arg, '-');
50 if (!dash) {
51 mr->range[0].min.tcp.port
52 = mr->range[0].max.tcp.port
Rusty Russellf9b2e662000-04-19 11:24:02 +000053 = htons(port);
Marc Bouchere6869a82000-03-20 06:03:29 +000054 } else {
55 int maxport;
56
57 maxport = atoi(dash + 1);
58 if (maxport == 0 || maxport > 65535)
59 exit_error(PARAMETER_PROBLEM,
60 "Port `%s' not valid\n", dash+1);
61 if (maxport < port)
62 /* People are stupid. Present reader excepted. */
63 exit_error(PARAMETER_PROBLEM,
64 "Port range `%s' funky\n", arg);
Rusty Russellf9b2e662000-04-19 11:24:02 +000065 mr->range[0].min.tcp.port = htons(port);
66 mr->range[0].max.tcp.port = htons(maxport);
Marc Bouchere6869a82000-03-20 06:03:29 +000067 }
68}
69
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000070static int MASQUERADE_parse(int c, char **argv, int invert, unsigned int *flags,
71 const void *e, struct xt_entry_target **target)
Marc Bouchere6869a82000-03-20 06:03:29 +000072{
Yasuyuki KOZAKAIac8b2712007-07-24 06:06:59 +000073 const struct ipt_entry *entry = e;
Marc Bouchere6869a82000-03-20 06:03:29 +000074 int portok;
75 struct ip_nat_multi_range *mr
76 = (struct ip_nat_multi_range *)(*target)->data;
77
78 if (entry->ip.proto == IPPROTO_TCP
Patrick McHardy36d870c2005-07-22 06:39:45 +000079 || entry->ip.proto == IPPROTO_UDP
Patrick McHardy5a942f92008-11-04 13:22:40 +010080 || entry->ip.proto == IPPROTO_SCTP
81 || entry->ip.proto == IPPROTO_DCCP
Patrick McHardy36d870c2005-07-22 06:39:45 +000082 || entry->ip.proto == IPPROTO_ICMP)
Marc Bouchere6869a82000-03-20 06:03:29 +000083 portok = 1;
84 else
85 portok = 0;
86
87 switch (c) {
88 case '1':
89 if (!portok)
90 exit_error(PARAMETER_PROBLEM,
Patrick McHardy5a942f92008-11-04 13:22:40 +010091 "Need TCP, UDP, SCTP or DCCP with port specification");
Marc Bouchere6869a82000-03-20 06:03:29 +000092
Harald Welteb77f1da2002-03-14 11:35:58 +000093 if (check_inverse(optarg, &invert, NULL, 0))
Marc Bouchere6869a82000-03-20 06:03:29 +000094 exit_error(PARAMETER_PROBLEM,
95 "Unexpected `!' after --to-ports");
96
97 parse_ports(optarg, mr);
98 return 1;
99
Eric Leblondae4b0b32007-02-24 15:11:33 +0000100 case '2':
101 mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
102 return 1;
Eric Leblondae4b0b32007-02-24 15:11:33 +0000103
Marc Bouchere6869a82000-03-20 06:03:29 +0000104 default:
105 return 0;
106 }
107}
108
Marc Bouchere6869a82000-03-20 06:03:29 +0000109static void
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000110MASQUERADE_print(const void *ip, const struct xt_entry_target *target,
111 int numeric)
Marc Bouchere6869a82000-03-20 06:03:29 +0000112{
113 struct ip_nat_multi_range *mr
114 = (struct ip_nat_multi_range *)target->data;
115 struct ip_nat_range *r = &mr->range[0];
116
Marc Bouchere6869a82000-03-20 06:03:29 +0000117 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
Rusty Russellf9b2e662000-04-19 11:24:02 +0000118 printf("masq ports: ");
119 printf("%hu", ntohs(r->min.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000120 if (r->max.tcp.port != r->min.tcp.port)
Rusty Russellf9b2e662000-04-19 11:24:02 +0000121 printf("-%hu", ntohs(r->max.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000122 printf(" ");
123 }
Eric Leblondae4b0b32007-02-24 15:11:33 +0000124
Patrick McHardye656e262007-04-18 12:56:05 +0000125 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
Patrick McHardy9c67def2007-04-18 14:00:11 +0000126 printf("random ");
Marc Bouchere6869a82000-03-20 06:03:29 +0000127}
128
Marc Bouchere6869a82000-03-20 06:03:29 +0000129static void
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000130MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
Marc Bouchere6869a82000-03-20 06:03:29 +0000131{
132 struct ip_nat_multi_range *mr
133 = (struct ip_nat_multi_range *)target->data;
134 struct ip_nat_range *r = &mr->range[0];
135
136 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
A. van Schie4b5566b2002-04-01 07:51:25 +0000137 printf("--to-ports %hu", ntohs(r->min.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000138 if (r->max.tcp.port != r->min.tcp.port)
Rusty Russellf9b2e662000-04-19 11:24:02 +0000139 printf("-%hu", ntohs(r->max.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000140 printf(" ");
141 }
Patrick McHardy9c67def2007-04-18 14:00:11 +0000142
143 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
144 printf("--random ");
Marc Bouchere6869a82000-03-20 06:03:29 +0000145}
146
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200147static struct xtables_target masquerade_tg_reg = {
Pablo Neira8caee8b2004-12-28 13:11:59 +0000148 .name = "MASQUERADE",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200149 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100150 .family = NFPROTO_IPV4,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200151 .size = XT_ALIGN(sizeof(struct ip_nat_multi_range)),
152 .userspacesize = XT_ALIGN(sizeof(struct ip_nat_multi_range)),
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000153 .help = MASQUERADE_help,
154 .init = MASQUERADE_init,
155 .parse = MASQUERADE_parse,
156 .print = MASQUERADE_print,
157 .save = MASQUERADE_save,
158 .extra_opts = MASQUERADE_opts,
Marc Bouchere6869a82000-03-20 06:03:29 +0000159};
160
161void _init(void)
162{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200163 xtables_register_target(&masquerade_tg_reg);
Marc Bouchere6869a82000-03-20 06:03:29 +0000164}