1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * ebt_dnat |
4 | * |
5 | * Authors: |
6 | * Bart De Schuymer <bdschuym@pandora.be> |
7 | * |
8 | * June, 2002 |
9 | * |
10 | */ |
11 | #include <linux/module.h> |
12 | #include <net/sock.h> |
13 | #include "../br_private.h" |
14 | #include <linux/netfilter.h> |
15 | #include <linux/netfilter/x_tables.h> |
16 | #include <linux/netfilter_bridge/ebtables.h> |
17 | #include <linux/netfilter_bridge/ebt_nat.h> |
18 | |
19 | static unsigned int |
20 | ebt_dnat_tg(struct sk_buff *skb, const struct xt_action_param *par) |
21 | { |
22 | const struct ebt_nat_info *info = par->targinfo; |
23 | |
24 | if (skb_ensure_writable(skb, write_len: 0)) |
25 | return EBT_DROP; |
26 | |
27 | ether_addr_copy(dst: eth_hdr(skb)->h_dest, src: info->mac); |
28 | |
29 | if (is_multicast_ether_addr(addr: info->mac)) { |
30 | if (is_broadcast_ether_addr(addr: info->mac)) |
31 | skb->pkt_type = PACKET_BROADCAST; |
32 | else |
33 | skb->pkt_type = PACKET_MULTICAST; |
34 | } else { |
35 | const struct net_device *dev; |
36 | |
37 | switch (xt_hooknum(par)) { |
38 | case NF_BR_BROUTING: |
39 | dev = xt_in(par); |
40 | break; |
41 | case NF_BR_PRE_ROUTING: |
42 | dev = br_port_get_rcu(dev: xt_in(par))->br->dev; |
43 | break; |
44 | default: |
45 | dev = NULL; |
46 | break; |
47 | } |
48 | |
49 | if (!dev) /* NF_BR_LOCAL_OUT */ |
50 | return info->target; |
51 | |
52 | if (ether_addr_equal(addr1: info->mac, addr2: dev->dev_addr)) |
53 | skb->pkt_type = PACKET_HOST; |
54 | else |
55 | skb->pkt_type = PACKET_OTHERHOST; |
56 | } |
57 | |
58 | return info->target; |
59 | } |
60 | |
61 | static int ebt_dnat_tg_check(const struct xt_tgchk_param *par) |
62 | { |
63 | const struct ebt_nat_info *info = par->targinfo; |
64 | unsigned int hook_mask; |
65 | |
66 | if (BASE_CHAIN && info->target == EBT_RETURN) |
67 | return -EINVAL; |
68 | |
69 | hook_mask = par->hook_mask & ~(1 << NF_BR_NUMHOOKS); |
70 | if ((strcmp(par->table, "nat" ) != 0 || |
71 | (hook_mask & ~((1 << NF_BR_PRE_ROUTING) | |
72 | (1 << NF_BR_LOCAL_OUT)))) && |
73 | (strcmp(par->table, "broute" ) != 0 || |
74 | hook_mask & ~(1 << NF_BR_BROUTING))) |
75 | return -EINVAL; |
76 | if (ebt_invalid_target(target: info->target)) |
77 | return -EINVAL; |
78 | return 0; |
79 | } |
80 | |
81 | static struct xt_target ebt_dnat_tg_reg __read_mostly = { |
82 | .name = "dnat" , |
83 | .revision = 0, |
84 | .family = NFPROTO_BRIDGE, |
85 | .hooks = (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_PRE_ROUTING) | |
86 | (1 << NF_BR_LOCAL_OUT) | (1 << NF_BR_BROUTING), |
87 | .target = ebt_dnat_tg, |
88 | .checkentry = ebt_dnat_tg_check, |
89 | .targetsize = sizeof(struct ebt_nat_info), |
90 | .me = THIS_MODULE, |
91 | }; |
92 | |
93 | static int __init ebt_dnat_init(void) |
94 | { |
95 | return xt_register_target(target: &ebt_dnat_tg_reg); |
96 | } |
97 | |
98 | static void __exit ebt_dnat_fini(void) |
99 | { |
100 | xt_unregister_target(target: &ebt_dnat_tg_reg); |
101 | } |
102 | |
103 | module_init(ebt_dnat_init); |
104 | module_exit(ebt_dnat_fini); |
105 | MODULE_DESCRIPTION("Ebtables: Destination MAC address translation" ); |
106 | MODULE_LICENSE("GPL" ); |
107 | |