blob: e6afbf8f3a3f84f5d5b7f8757abe2ddab1cb2400 [file] [log] [blame]
Bart De Schuymerff587202005-02-08 20:02:28 +00001/* ebt_nat
2 *
3 * Authors:
4 * Bart De Schuymer <bdschuym@pandora.be>
5 *
6 * June, 2002
7 */
8
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00009#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000012#include <getopt.h>
13#include "../include/ebtables_u.h"
Bart De Schuymer57633b12010-12-18 16:15:49 +000014#include <netinet/ether.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000015#include <linux/netfilter_bridge/ebt_nat.h>
16
Bart De Schuymer9cfd6542002-08-13 16:08:08 +000017static int to_source_supplied, to_dest_supplied;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000018
19#define NAT_S '1'
20#define NAT_D '1'
21#define NAT_S_TARGET '2'
22#define NAT_D_TARGET '2'
Bart De Schuymer726edb92006-12-15 11:38:26 +000023#define NAT_S_ARP '3'
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000024static struct option opts_s[] =
25{
26 { "to-source" , required_argument, 0, NAT_S },
27 { "to-src" , required_argument, 0, NAT_S },
Bart De Schuymer9cfd6542002-08-13 16:08:08 +000028 { "snat-target" , required_argument, 0, NAT_S_TARGET },
Bart De Schuymer726edb92006-12-15 11:38:26 +000029 { "snat-arp" , no_argument, 0, NAT_S_ARP },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000030 { 0 }
31};
32
33static struct option opts_d[] =
34{
35 { "to-destination", required_argument, 0, NAT_D },
36 { "to-dst" , required_argument, 0, NAT_D },
Bart De Schuymer9cfd6542002-08-13 16:08:08 +000037 { "dnat-target" , required_argument, 0, NAT_D_TARGET },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000038 { 0 }
39};
40
41static void print_help_s()
42{
43 printf(
44 "snat options:\n"
45 " --to-src address : MAC address to map source to\n"
Bart De Schuymer726edb92006-12-15 11:38:26 +000046 " --snat-target target : ACCEPT, DROP, RETURN or CONTINUE\n"
47 " --snat-arp : also change src address in arp msg\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000048}
49
50static void print_help_d()
51{
52 printf(
53 "dnat options:\n"
54 " --to-dst address : MAC address to map destination to\n"
Bart De Schuymerb26649e2002-07-25 14:51:54 +000055 " --dnat-target target : ACCEPT, DROP, RETURN or CONTINUE\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000056}
57
58static void init_s(struct ebt_entry_target *target)
59{
60 struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
61
62 to_source_supplied = 0;
63 natinfo->target = EBT_ACCEPT;
Bart De Schuymer2f0d7482003-06-04 06:23:49 +000064 return;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000065}
66
67static void init_d(struct ebt_entry_target *target)
68{
69 struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
70
71 to_dest_supplied = 0;
72 natinfo->target = EBT_ACCEPT;
73 return;
74}
75
76#define OPT_SNAT 0x01
77#define OPT_SNAT_TARGET 0x02
Bart De Schuymer726edb92006-12-15 11:38:26 +000078#define OPT_SNAT_ARP 0x04
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000079static int parse_s(int c, char **argv, int argc,
80 const struct ebt_u_entry *entry, unsigned int *flags,
81 struct ebt_entry_target **target)
82{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000083 struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
Bart De Schuymer41830412002-06-05 19:41:28 +000084 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000085
86 switch (c) {
87 case NAT_S:
Bart De Schuymerff587202005-02-08 20:02:28 +000088 ebt_check_option2(flags, OPT_SNAT);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000089 to_source_supplied = 1;
Bart De Schuymer41830412002-06-05 19:41:28 +000090 if (!(addr = ether_aton(optarg)))
Bart De Schuymerff587202005-02-08 20:02:28 +000091 ebt_print_error2("Problem with specified --to-source mac");
Bart De Schuymer41830412002-06-05 19:41:28 +000092 memcpy(natinfo->mac, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000093 break;
94 case NAT_S_TARGET:
Bart De Schuymer726edb92006-12-15 11:38:26 +000095 { int tmp;
Bart De Schuymerff587202005-02-08 20:02:28 +000096 ebt_check_option2(flags, OPT_SNAT_TARGET);
Bart De Schuymer726edb92006-12-15 11:38:26 +000097 if (FILL_TARGET(optarg, tmp))
Bart De Schuymerff587202005-02-08 20:02:28 +000098 ebt_print_error2("Illegal --snat-target target");
Bart De Schuymer726edb92006-12-15 11:38:26 +000099 natinfo->target = (natinfo->target & ~EBT_VERDICT_BITS) | (tmp & EBT_VERDICT_BITS);
100 }
101 break;
102 case NAT_S_ARP:
103 ebt_check_option2(flags, OPT_SNAT_ARP);
104 natinfo->target ^= NAT_ARP_BIT;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000105 break;
106 default:
107 return 0;
108 }
109 return 1;
110}
111
112#define OPT_DNAT 0x01
113#define OPT_DNAT_TARGET 0x02
114static int parse_d(int c, char **argv, int argc,
115 const struct ebt_u_entry *entry, unsigned int *flags,
116 struct ebt_entry_target **target)
117{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000118 struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
Bart De Schuymer41830412002-06-05 19:41:28 +0000119 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000120
121 switch (c) {
122 case NAT_D:
Bart De Schuymerff587202005-02-08 20:02:28 +0000123 ebt_check_option2(flags, OPT_DNAT);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000124 to_dest_supplied = 1;
Bart De Schuymer41830412002-06-05 19:41:28 +0000125 if (!(addr = ether_aton(optarg)))
Bart De Schuymerff587202005-02-08 20:02:28 +0000126 ebt_print_error2("Problem with specified --to-destination mac");
Bart De Schuymer41830412002-06-05 19:41:28 +0000127 memcpy(natinfo->mac, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000128 break;
129 case NAT_D_TARGET:
Bart De Schuymerff587202005-02-08 20:02:28 +0000130 ebt_check_option2(flags, OPT_DNAT_TARGET);
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000131 if (FILL_TARGET(optarg, natinfo->target))
Bart De Schuymerff587202005-02-08 20:02:28 +0000132 ebt_print_error2("Illegal --dnat-target target");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000133 break;
134 default:
135 return 0;
136 }
137 return 1;
138}
139
140static void final_check_s(const struct ebt_u_entry *entry,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +0000141 const struct ebt_entry_target *target, const char *name,
Bart De Schuymerc9b52932002-08-24 13:26:34 +0000142 unsigned int hookmask, unsigned int time)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000143{
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000144 struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
145
Bart De Schuymer726edb92006-12-15 11:38:26 +0000146 if (BASE_CHAIN && (natinfo->target | ~EBT_VERDICT_BITS) == EBT_RETURN) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000147 ebt_print_error("--snat-target RETURN not allowed on base chain");
148 return;
149 }
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000150 CLEAR_BASE_CHAIN_BIT;
Bart De Schuymerff587202005-02-08 20:02:28 +0000151 if ((hookmask & ~(1 << NF_BR_POST_ROUTING)) || strcmp(name, "nat")) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000152 ebt_print_error("Wrong chain for snat");
Bart De Schuymerff587202005-02-08 20:02:28 +0000153 } else if (time == 0 && to_source_supplied == 0)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000154 ebt_print_error("No snat address supplied");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000155}
156
157static void final_check_d(const struct ebt_u_entry *entry,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +0000158 const struct ebt_entry_target *target, const char *name,
Bart De Schuymerc9b52932002-08-24 13:26:34 +0000159 unsigned int hookmask, unsigned int time)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000160{
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000161 struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
162
Bart De Schuymerff587202005-02-08 20:02:28 +0000163 if (BASE_CHAIN && natinfo->target == EBT_RETURN) {
164 ebt_print_error("--dnat-target RETURN not allowed on base chain");
165 return;
166 }
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000167 CLEAR_BASE_CHAIN_BIT;
Bart De Schuymerc9b52932002-08-24 13:26:34 +0000168 if (((hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))
169 || strcmp(name, "nat")) &&
Bart De Schuymerff587202005-02-08 20:02:28 +0000170 ((hookmask & ~(1 << NF_BR_BROUTING)) || strcmp(name, "broute"))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000171 ebt_print_error("Wrong chain for dnat");
Bart De Schuymer726edb92006-12-15 11:38:26 +0000172 } else if (time == 0 && to_dest_supplied == 0)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000173 ebt_print_error("No dnat address supplied");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000174}
175
176static void print_s(const struct ebt_u_entry *entry,
177 const struct ebt_entry_target *target)
178{
179 struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000180
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000181 printf("--to-src ");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000182 ebt_print_mac(natinfo->mac);
Bart De Schuymer726edb92006-12-15 11:38:26 +0000183 if (!(natinfo->target&NAT_ARP_BIT))
184 printf(" --snat-arp");
185 printf(" --snat-target %s", TARGET_NAME((natinfo->target|~EBT_VERDICT_BITS)));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000186}
187
188static void print_d(const struct ebt_u_entry *entry,
189 const struct ebt_entry_target *target)
190{
191 struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000192
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000193 printf("--to-dst ");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000194 ebt_print_mac(natinfo->mac);
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000195 printf(" --dnat-target %s", TARGET_NAME(natinfo->target));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000196}
197
198static int compare(const struct ebt_entry_target *t1,
199 const struct ebt_entry_target *t2)
200{
201 struct ebt_nat_info *natinfo1 = (struct ebt_nat_info *)t1->data;
202 struct ebt_nat_info *natinfo2 = (struct ebt_nat_info *)t2->data;
203
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000204 return !memcmp(natinfo1->mac, natinfo2->mac, sizeof(natinfo1->mac)) &&
205 natinfo1->target == natinfo2->target;
206}
207
208static struct ebt_u_target snat_target =
209{
Bart De Schuymerfbdebad2008-02-03 19:58:44 +0000210 .name = "snat",
Bart De Schuymer7cf1cca2003-08-30 16:20:19 +0000211 .size = sizeof(struct ebt_nat_info),
212 .help = print_help_s,
213 .init = init_s,
214 .parse = parse_s,
215 .final_check = final_check_s,
216 .print = print_s,
217 .compare = compare,
218 .extra_ops = opts_s,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000219};
220
221static struct ebt_u_target dnat_target =
222{
Bart De Schuymerfbdebad2008-02-03 19:58:44 +0000223 .name = "dnat",
Bart De Schuymer7cf1cca2003-08-30 16:20:19 +0000224 .size = sizeof(struct ebt_nat_info),
225 .help = print_help_d,
226 .init = init_d,
227 .parse = parse_d,
228 .final_check = final_check_d,
229 .print = print_d,
230 .compare = compare,
231 .extra_ops = opts_d,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000232};
233
Bart De Schuymer64182a32004-01-21 20:39:54 +0000234void _init(void)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000235{
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000236 ebt_register_target(&snat_target);
237 ebt_register_target(&dnat_target);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000238}