xref: /linux/net/bridge/netfilter/ebt_arp.c (revision 2da68a77)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  ebt_arp
4  *
5  *	Authors:
6  *	Bart De Schuymer <bdschuym@pandora.be>
7  *	Tim Gardner <timg@tpi.com>
8  *
9  *  April, 2002
10  *
11  */
12 #include <linux/if_arp.h>
13 #include <linux/if_ether.h>
14 #include <linux/module.h>
15 #include <linux/netfilter/x_tables.h>
16 #include <linux/netfilter_bridge/ebtables.h>
17 #include <linux/netfilter_bridge/ebt_arp.h>
18 
19 static bool
20 ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par)
21 {
22 	const struct ebt_arp_info *info = par->matchinfo;
23 	const struct arphdr *ah;
24 	struct arphdr _arph;
25 
26 	ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
27 	if (ah == NULL)
28 		return false;
29 	if ((info->bitmask & EBT_ARP_OPCODE) &&
30 	    NF_INVF(info, EBT_ARP_OPCODE, info->opcode != ah->ar_op))
31 		return false;
32 	if ((info->bitmask & EBT_ARP_HTYPE) &&
33 	    NF_INVF(info, EBT_ARP_HTYPE, info->htype != ah->ar_hrd))
34 		return false;
35 	if ((info->bitmask & EBT_ARP_PTYPE) &&
36 	    NF_INVF(info, EBT_ARP_PTYPE, info->ptype != ah->ar_pro))
37 		return false;
38 
39 	if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_GRAT)) {
40 		const __be32 *sap, *dap;
41 		__be32 saddr, daddr;
42 
43 		if (ah->ar_pln != sizeof(__be32) || ah->ar_pro != htons(ETH_P_IP))
44 			return false;
45 		sap = skb_header_pointer(skb, sizeof(struct arphdr) +
46 					ah->ar_hln, sizeof(saddr),
47 					&saddr);
48 		if (sap == NULL)
49 			return false;
50 		dap = skb_header_pointer(skb, sizeof(struct arphdr) +
51 					2*ah->ar_hln+sizeof(saddr),
52 					sizeof(daddr), &daddr);
53 		if (dap == NULL)
54 			return false;
55 		if ((info->bitmask & EBT_ARP_SRC_IP) &&
56 		    NF_INVF(info, EBT_ARP_SRC_IP,
57 			    info->saddr != (*sap & info->smsk)))
58 			return false;
59 		if ((info->bitmask & EBT_ARP_DST_IP) &&
60 		    NF_INVF(info, EBT_ARP_DST_IP,
61 			    info->daddr != (*dap & info->dmsk)))
62 			return false;
63 		if ((info->bitmask & EBT_ARP_GRAT) &&
64 		    NF_INVF(info, EBT_ARP_GRAT, *dap != *sap))
65 			return false;
66 	}
67 
68 	if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
69 		const unsigned char *mp;
70 		unsigned char _mac[ETH_ALEN];
71 
72 		if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER))
73 			return false;
74 		if (info->bitmask & EBT_ARP_SRC_MAC) {
75 			mp = skb_header_pointer(skb, sizeof(struct arphdr),
76 						sizeof(_mac), &_mac);
77 			if (mp == NULL)
78 				return false;
79 			if (NF_INVF(info, EBT_ARP_SRC_MAC,
80 				    !ether_addr_equal_masked(mp, info->smaddr,
81 							     info->smmsk)))
82 				return false;
83 		}
84 
85 		if (info->bitmask & EBT_ARP_DST_MAC) {
86 			mp = skb_header_pointer(skb, sizeof(struct arphdr) +
87 						ah->ar_hln + ah->ar_pln,
88 						sizeof(_mac), &_mac);
89 			if (mp == NULL)
90 				return false;
91 			if (NF_INVF(info, EBT_ARP_DST_MAC,
92 				    !ether_addr_equal_masked(mp, info->dmaddr,
93 							     info->dmmsk)))
94 				return false;
95 		}
96 	}
97 
98 	return true;
99 }
100 
101 static int ebt_arp_mt_check(const struct xt_mtchk_param *par)
102 {
103 	const struct ebt_arp_info *info = par->matchinfo;
104 	const struct ebt_entry *e = par->entryinfo;
105 
106 	if ((e->ethproto != htons(ETH_P_ARP) &&
107 	   e->ethproto != htons(ETH_P_RARP)) ||
108 	   e->invflags & EBT_IPROTO)
109 		return -EINVAL;
110 	if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK)
111 		return -EINVAL;
112 	return 0;
113 }
114 
115 static struct xt_match ebt_arp_mt_reg __read_mostly = {
116 	.name		= "arp",
117 	.revision	= 0,
118 	.family		= NFPROTO_BRIDGE,
119 	.match		= ebt_arp_mt,
120 	.checkentry	= ebt_arp_mt_check,
121 	.matchsize	= sizeof(struct ebt_arp_info),
122 	.me		= THIS_MODULE,
123 };
124 
125 static int __init ebt_arp_init(void)
126 {
127 	return xt_register_match(&ebt_arp_mt_reg);
128 }
129 
130 static void __exit ebt_arp_fini(void)
131 {
132 	xt_unregister_match(&ebt_arp_mt_reg);
133 }
134 
135 module_init(ebt_arp_init);
136 module_exit(ebt_arp_fini);
137 MODULE_DESCRIPTION("Ebtables: ARP protocol packet match");
138 MODULE_LICENSE("GPL");
139