16a03354eSMatthew Dillon /*
24408d548SBill Yuan  * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
36a03354eSMatthew Dillon  *
46a03354eSMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
59187b359SBill Yuan  * by Bill Yuan <bycn82@dragonflybsd.org>
66a03354eSMatthew Dillon  *
76a03354eSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
86a03354eSMatthew Dillon  * modification, are permitted provided that the following conditions
96a03354eSMatthew Dillon  * are met:
106a03354eSMatthew Dillon  *
116a03354eSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
126a03354eSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
136a03354eSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
146a03354eSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
156a03354eSMatthew Dillon  *    the documentation and/or other materials provided with the
166a03354eSMatthew Dillon  *    distribution.
176a03354eSMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
186a03354eSMatthew Dillon  *    contributors may be used to endorse or promote products derived
196a03354eSMatthew Dillon  *    from this software without specific, prior written permission.
206a03354eSMatthew Dillon  *
216a03354eSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
226a03354eSMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
236a03354eSMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
246a03354eSMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
256a03354eSMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
266a03354eSMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
276a03354eSMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
286a03354eSMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
296a03354eSMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
306a03354eSMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
316a03354eSMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
326a03354eSMatthew Dillon  * SUCH DAMAGE.
336a03354eSMatthew Dillon  */
346a03354eSMatthew Dillon 
354408d548SBill Yuan #include "opt_ipfw.h"
364408d548SBill Yuan #include "opt_inet.h"
374408d548SBill Yuan #ifndef INET
384408d548SBill Yuan #error IPFIREWALL3 requires INET.
394408d548SBill Yuan #endif /* INET */
404408d548SBill Yuan 
416a03354eSMatthew Dillon #include <sys/param.h>
426a03354eSMatthew Dillon #include <sys/kernel.h>
436a03354eSMatthew Dillon #include <sys/malloc.h>
446a03354eSMatthew Dillon #include <sys/mbuf.h>
456a03354eSMatthew Dillon #include <sys/socketvar.h>
466a03354eSMatthew Dillon #include <sys/sysctl.h>
476a03354eSMatthew Dillon #include <sys/systimer.h>
486a03354eSMatthew Dillon 
496a03354eSMatthew Dillon #include <net/ethernet.h>
506a03354eSMatthew Dillon #include <net/netmsg2.h>
516a03354eSMatthew Dillon #include <net/netisr2.h>
526a03354eSMatthew Dillon #include <net/route.h>
53bff82488SAaron LI #include <net/if.h>
546a03354eSMatthew Dillon 
556a03354eSMatthew Dillon #include <netinet/in_var.h>
566a03354eSMatthew Dillon #include <netinet/ip_var.h>
576a03354eSMatthew Dillon 
586a03354eSMatthew Dillon #include <net/ipfw3/ip_fw.h>
594408d548SBill Yuan #include <net/ipfw3_basic/ip_fw3_table.h>
606a03354eSMatthew Dillon 
616a03354eSMatthew Dillon #include "ip_fw3_layer2.h"
626a03354eSMatthew Dillon 
634408d548SBill Yuan extern struct ipfw3_context      *fw3_ctx[MAXCPU];
646a03354eSMatthew Dillon 
656a03354eSMatthew Dillon void
check_layer2(int * cmd_ctl,int * cmd_val,struct ip_fw_args ** args,struct ip_fw ** f,ipfw_insn * cmd,uint16_t ip_len)666a03354eSMatthew Dillon check_layer2(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
676a03354eSMatthew Dillon 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
686a03354eSMatthew Dillon {
696a03354eSMatthew Dillon 	*cmd_val = ((*args)->eh != NULL);
706a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
716a03354eSMatthew Dillon }
726a03354eSMatthew Dillon 
736a03354eSMatthew Dillon void
check_mac(int * cmd_ctl,int * cmd_val,struct ip_fw_args ** args,struct ip_fw ** f,ipfw_insn * cmd,uint16_t ip_len)746a03354eSMatthew Dillon check_mac(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
756a03354eSMatthew Dillon 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
766a03354eSMatthew Dillon {
776a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
786a03354eSMatthew Dillon 	if ((*args)->eh != NULL) {
796a03354eSMatthew Dillon 		uint32_t *want = (uint32_t *)((ipfw_insn_mac *)cmd)->addr;
806a03354eSMatthew Dillon 		uint32_t *mask = (uint32_t *)((ipfw_insn_mac *)cmd)->mask;
816a03354eSMatthew Dillon 		uint32_t *hdr = (uint32_t *)(*args)->eh;
826a03354eSMatthew Dillon 		*cmd_val =
836a03354eSMatthew Dillon 			(want[0] == (hdr[0] & mask[0]) &&
846a03354eSMatthew Dillon 			 want[1] == (hdr[1] & mask[1]) &&
856a03354eSMatthew Dillon 			 want[2] == (hdr[2] & mask[2]));
866a03354eSMatthew Dillon 	} else {
876a03354eSMatthew Dillon 		*cmd_val = IP_FW_NOT_MATCH;
886a03354eSMatthew Dillon 	}
896a03354eSMatthew Dillon }
906a03354eSMatthew Dillon 
91ab88ebe4SBill Yuan void
check_mac_from(int * cmd_ctl,int * cmd_val,struct ip_fw_args ** args,struct ip_fw ** f,ipfw_insn * cmd,uint16_t ip_len)92ab88ebe4SBill Yuan check_mac_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
93ab88ebe4SBill Yuan 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
94ab88ebe4SBill Yuan {
95ab88ebe4SBill Yuan 	*cmd_ctl = IP_FW_CTL_NO;
96ab88ebe4SBill Yuan 	if ((*args)->eh != NULL) {
97ab88ebe4SBill Yuan 		uint16_t *want = (uint16_t *)((ipfw_insn_mac *)cmd)->addr;
98ab88ebe4SBill Yuan 		uint16_t *mask = (uint16_t *)((ipfw_insn_mac *)cmd)->mask;
99ab88ebe4SBill Yuan 		uint16_t *hdr = (uint16_t *)(*args)->eh;
100ab88ebe4SBill Yuan 		*cmd_val =
101ab88ebe4SBill Yuan 			(want[3] == (hdr[3] & mask[3]) &&
102ab88ebe4SBill Yuan 			 want[4] == (hdr[4] & mask[4]) &&
103ab88ebe4SBill Yuan 			 want[5] == (hdr[5] & mask[5]));
104ab88ebe4SBill Yuan 	} else {
105ab88ebe4SBill Yuan 		*cmd_val = IP_FW_NOT_MATCH;
106ab88ebe4SBill Yuan 	}
107ab88ebe4SBill Yuan }
108ab88ebe4SBill Yuan 
109ab88ebe4SBill Yuan void
check_mac_from_lookup(int * cmd_ctl,int * cmd_val,struct ip_fw_args ** args,struct ip_fw ** f,ipfw_insn * cmd,uint16_t ip_len)110ab88ebe4SBill Yuan check_mac_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
111ab88ebe4SBill Yuan 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
112ab88ebe4SBill Yuan {
1134408d548SBill Yuan         struct ipfw3_context *ctx = fw3_ctx[mycpuid];
1144408d548SBill Yuan         struct ipfw3_table_context *table_ctx;
115ab88ebe4SBill Yuan         struct radix_node_head *rnh;
116ab88ebe4SBill Yuan         struct table_mac_entry *ent = NULL;
117ab88ebe4SBill Yuan 
118ab88ebe4SBill Yuan         table_ctx = ctx->table_ctx;
119ab88ebe4SBill Yuan         table_ctx += cmd->arg1;
120ab88ebe4SBill Yuan         rnh = table_ctx->node;
121ab88ebe4SBill Yuan 
122ab88ebe4SBill Yuan         *cmd_ctl = IP_FW_CTL_NO;
123ab88ebe4SBill Yuan         *cmd_val = IP_FW_NOT_MATCH;
124ab88ebe4SBill Yuan         if ((*args)->eh != NULL) {
125ab88ebe4SBill Yuan                 struct sockaddr sa;
126ab88ebe4SBill Yuan                 sa.sa_len = 8;
127ab88ebe4SBill Yuan                 strncpy(sa.sa_data, (*args)->eh->ether_shost, 6);
128*d8449084SAaron LI                 ent = (struct table_mac_entry *)rnh->rnh_lookup(&sa, NULL, rnh);
129ab88ebe4SBill Yuan                 if (ent != NULL)
130ab88ebe4SBill Yuan                         *cmd_val = IP_FW_MATCH;
131ab88ebe4SBill Yuan         }
132ab88ebe4SBill Yuan }
133ab88ebe4SBill Yuan 
134ab88ebe4SBill Yuan void
check_mac_to(int * cmd_ctl,int * cmd_val,struct ip_fw_args ** args,struct ip_fw ** f,ipfw_insn * cmd,uint16_t ip_len)135ab88ebe4SBill Yuan check_mac_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
136ab88ebe4SBill Yuan 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
137ab88ebe4SBill Yuan {
138ab88ebe4SBill Yuan 	*cmd_ctl = IP_FW_CTL_NO;
139ab88ebe4SBill Yuan 	if ((*args)->eh != NULL) {
140ab88ebe4SBill Yuan 		uint16_t *want = (uint16_t *)((ipfw_insn_mac *)cmd)->addr;
141ab88ebe4SBill Yuan 		uint16_t *mask = (uint16_t *)((ipfw_insn_mac *)cmd)->mask;
142ab88ebe4SBill Yuan 		uint16_t *hdr = (uint16_t *)(*args)->eh;
143ab88ebe4SBill Yuan 		*cmd_val =
144ab88ebe4SBill Yuan 			(want[0] == (hdr[0] & mask[0]) &&
145ab88ebe4SBill Yuan 			 want[1] == (hdr[1] & mask[1]) &&
146ab88ebe4SBill Yuan 			 want[2] == (hdr[2] & mask[2]));
147ab88ebe4SBill Yuan 	} else {
148ab88ebe4SBill Yuan 		*cmd_val = IP_FW_NOT_MATCH;
149ab88ebe4SBill Yuan 	}
150ab88ebe4SBill Yuan }
151ab88ebe4SBill Yuan 
152ab88ebe4SBill Yuan void
check_mac_to_lookup(int * cmd_ctl,int * cmd_val,struct ip_fw_args ** args,struct ip_fw ** f,ipfw_insn * cmd,uint16_t ip_len)153ab88ebe4SBill Yuan check_mac_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
154ab88ebe4SBill Yuan 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
155ab88ebe4SBill Yuan {
1564408d548SBill Yuan         struct ipfw3_context *ctx = fw3_ctx[mycpuid];
1574408d548SBill Yuan         struct ipfw3_table_context *table_ctx;
158ab88ebe4SBill Yuan         struct radix_node_head *rnh;
159ab88ebe4SBill Yuan         struct table_mac_entry *ent = NULL;
160ab88ebe4SBill Yuan 
161ab88ebe4SBill Yuan         table_ctx = ctx->table_ctx;
162ab88ebe4SBill Yuan         table_ctx += cmd->arg1;
163ab88ebe4SBill Yuan         rnh = table_ctx->node;
164ab88ebe4SBill Yuan 
165ab88ebe4SBill Yuan         *cmd_ctl = IP_FW_CTL_NO;
166ab88ebe4SBill Yuan         *cmd_val = IP_FW_NOT_MATCH;
167ab88ebe4SBill Yuan         if ((*args)->eh != NULL) {
168ab88ebe4SBill Yuan                 struct sockaddr sa;
169ab88ebe4SBill Yuan                 sa.sa_len = 8;
170ab88ebe4SBill Yuan                 strncpy(sa.sa_data, (*args)->eh->ether_dhost, 6);
171*d8449084SAaron LI                 ent = (struct table_mac_entry *)rnh->rnh_lookup(&sa, NULL, rnh);
172ab88ebe4SBill Yuan                 if (ent != NULL)
173ab88ebe4SBill Yuan                         *cmd_val = IP_FW_MATCH;
174ab88ebe4SBill Yuan         }
175ab88ebe4SBill Yuan }
176ab88ebe4SBill Yuan 
1776a03354eSMatthew Dillon static int
ip_fw3_layer2_init(void)1784408d548SBill Yuan ip_fw3_layer2_init(void)
1796a03354eSMatthew Dillon {
1804408d548SBill Yuan 	ip_fw3_register_module(MODULE_LAYER2_ID, MODULE_LAYER2_NAME);
1814408d548SBill Yuan 	ip_fw3_register_filter_funcs(MODULE_LAYER2_ID,
1826a03354eSMatthew Dillon 			O_LAYER2_LAYER2, (filter_func)check_layer2);
1834408d548SBill Yuan 	ip_fw3_register_filter_funcs(MODULE_LAYER2_ID,
1846a03354eSMatthew Dillon 			O_LAYER2_MAC, (filter_func)check_mac);
1854408d548SBill Yuan         ip_fw3_register_filter_funcs(MODULE_LAYER2_ID,
186ab88ebe4SBill Yuan 			O_LAYER2_MAC_SRC, (filter_func)check_mac_from);
1874408d548SBill Yuan         ip_fw3_register_filter_funcs(MODULE_LAYER2_ID,
188ab88ebe4SBill Yuan 			O_LAYER2_MAC_DST, (filter_func)check_mac_to);
1894408d548SBill Yuan         ip_fw3_register_filter_funcs(MODULE_LAYER2_ID,
190ab88ebe4SBill Yuan 			O_LAYER2_MAC_SRC_LOOKUP,
191ab88ebe4SBill Yuan 			(filter_func)check_mac_from_lookup);
1924408d548SBill Yuan         ip_fw3_register_filter_funcs(MODULE_LAYER2_ID,
193ab88ebe4SBill Yuan 			O_LAYER2_MAC_DST_LOOKUP,
194ab88ebe4SBill Yuan 			(filter_func)check_mac_to_lookup);
1956a03354eSMatthew Dillon 	return 0;
1966a03354eSMatthew Dillon }
1976a03354eSMatthew Dillon 
1986a03354eSMatthew Dillon static int
ip_fw3_layer2_stop(void)1994408d548SBill Yuan ip_fw3_layer2_stop(void)
2006a03354eSMatthew Dillon {
2014408d548SBill Yuan 	return ip_fw3_unregister_module(MODULE_LAYER2_ID);
2026a03354eSMatthew Dillon }
2036a03354eSMatthew Dillon 
2046a03354eSMatthew Dillon static int
ipfw3_layer2_modevent(module_t mod,int type,void * data)2056a03354eSMatthew Dillon ipfw3_layer2_modevent(module_t mod, int type, void *data)
2066a03354eSMatthew Dillon {
2076a03354eSMatthew Dillon 	switch (type) {
2086a03354eSMatthew Dillon 		case MOD_LOAD:
2094408d548SBill Yuan 			return ip_fw3_layer2_init();
2106a03354eSMatthew Dillon 		case MOD_UNLOAD:
2114408d548SBill Yuan 			return ip_fw3_layer2_stop();
2126a03354eSMatthew Dillon 		default:
2136a03354eSMatthew Dillon 			break;
2146a03354eSMatthew Dillon 	}
2156a03354eSMatthew Dillon 	return 0;
2166a03354eSMatthew Dillon }
2176a03354eSMatthew Dillon 
2186a03354eSMatthew Dillon static moduledata_t ipfw3_layer2_mod = {
2196a03354eSMatthew Dillon 	"ipfw3_layer2",
2206a03354eSMatthew Dillon 	ipfw3_layer2_modevent,
2216a03354eSMatthew Dillon 	NULL
2226a03354eSMatthew Dillon };
2236a03354eSMatthew Dillon DECLARE_MODULE(ipfw3_layer2, ipfw3_layer2_mod, SI_SUB_PROTO_END, SI_ORDER_ANY);
2246a03354eSMatthew Dillon MODULE_DEPEND(ipfw3_layer2, ipfw3_basic, 1, 1, 1);
2256a03354eSMatthew Dillon MODULE_VERSION(ipfw3_layer2, 1);
226