xref: /dflybsd-src/sys/net/ipfw3_layer4/ip_fw3_layer4.c (revision 502d982c7d2fa8a5f352ab7ee72e877d7b541538)
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/systm.h>
426a03354eSMatthew Dillon #include <sys/kernel.h>
436a03354eSMatthew Dillon #include <sys/malloc.h>
446a03354eSMatthew Dillon #include <sys/socketvar.h>
456a03354eSMatthew Dillon #include <sys/sysctl.h>
466a03354eSMatthew Dillon #include <sys/systimer.h>
476a03354eSMatthew Dillon #include <sys/param.h>
486a03354eSMatthew Dillon #include <sys/ucred.h>
496a03354eSMatthew Dillon 
50*bff82488SAaron LI #include <net/if.h>
51*bff82488SAaron LI #include <net/bpf.h>
52*bff82488SAaron LI #include <net/ethernet.h>
53*bff82488SAaron LI #include <net/netmsg2.h>
54*bff82488SAaron LI #include <net/netisr2.h>
55*bff82488SAaron LI #include <net/route.h>
56*bff82488SAaron LI 
576a03354eSMatthew Dillon #include <netinet/in_var.h>
586a03354eSMatthew Dillon #include <netinet/ip_var.h>
596a03354eSMatthew Dillon #include <netinet/in.h>
606a03354eSMatthew Dillon #include <netinet/in_systm.h>
616a03354eSMatthew Dillon #include <netinet/in_pcb.h>
626a03354eSMatthew Dillon #include <netinet/ip.h>
636a03354eSMatthew Dillon #include <netinet/ip_icmp.h>
646a03354eSMatthew Dillon #include <netinet/tcp.h>
656a03354eSMatthew Dillon #include <netinet/tcp_timer.h>
666a03354eSMatthew Dillon #include <netinet/tcp_var.h>
676a03354eSMatthew Dillon #include <netinet/tcpip.h>
686a03354eSMatthew Dillon #include <netinet/udp.h>
696a03354eSMatthew Dillon #include <netinet/udp_var.h>
706a03354eSMatthew Dillon #include <netinet/if_ether.h>
716a03354eSMatthew Dillon 
726a03354eSMatthew Dillon #include <net/ipfw3/ip_fw.h>
736a03354eSMatthew Dillon 
746a03354eSMatthew Dillon #include "ip_fw3_layer4.h"
756a03354eSMatthew Dillon 
766a03354eSMatthew Dillon void
776a03354eSMatthew Dillon check_tcpflag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
786a03354eSMatthew Dillon 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
796a03354eSMatthew Dillon void
806a03354eSMatthew Dillon check_uid(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
816a03354eSMatthew Dillon 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
826a03354eSMatthew Dillon void
836a03354eSMatthew Dillon check_gid(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
846a03354eSMatthew Dillon 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
85dee12ddaSBill Yuan void
86dee12ddaSBill Yuan check_established(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
87dee12ddaSBill Yuan 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
88e895e94dSBill Yuan void
89e895e94dSBill Yuan check_bpf(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
90e895e94dSBill Yuan 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
916a03354eSMatthew Dillon 
926a03354eSMatthew Dillon /*
934408d548SBill Yuan  * ip_fw3_match_guid can match the gui and uid
946a03354eSMatthew Dillon  */
956a03354eSMatthew Dillon static int
ip_fw3_match_guid(const struct ipfw_flow_id * fid,struct ifnet * oif,int opcode,uid_t uid)964408d548SBill Yuan ip_fw3_match_guid(const struct ipfw_flow_id *fid, struct ifnet *oif,
976a03354eSMatthew Dillon 		int opcode, uid_t uid)
986a03354eSMatthew Dillon {
996a03354eSMatthew Dillon 	struct in_addr src_ip, dst_ip;
1006a03354eSMatthew Dillon 	struct inpcbinfo *pi;
1016a03354eSMatthew Dillon 	boolean_t wildcard;
1026a03354eSMatthew Dillon 	struct inpcb *pcb;
1036a03354eSMatthew Dillon 
1046a03354eSMatthew Dillon 	if (fid->proto == IPPROTO_TCP) {
1056a03354eSMatthew Dillon 		wildcard = FALSE;
1066a03354eSMatthew Dillon 		pi = &tcbinfo[mycpuid];
1076a03354eSMatthew Dillon 	} else if (fid->proto == IPPROTO_UDP) {
1086a03354eSMatthew Dillon 		wildcard = TRUE;
1096a03354eSMatthew Dillon 		pi = &udbinfo[mycpuid];
1106a03354eSMatthew Dillon 	} else {
1116a03354eSMatthew Dillon 		return 0;
1126a03354eSMatthew Dillon 	}
1136a03354eSMatthew Dillon 
1146a03354eSMatthew Dillon 	/*
1156a03354eSMatthew Dillon 	 * Values in 'fid' are in host byte order
1166a03354eSMatthew Dillon 	 */
1176a03354eSMatthew Dillon 	dst_ip.s_addr = htonl(fid->dst_ip);
1186a03354eSMatthew Dillon 	src_ip.s_addr = htonl(fid->src_ip);
1196a03354eSMatthew Dillon 	if (oif) {
1206a03354eSMatthew Dillon 		pcb = in_pcblookup_hash(pi,
1216a03354eSMatthew Dillon 				dst_ip, htons(fid->dst_port),
1226a03354eSMatthew Dillon 				src_ip, htons(fid->src_port),
1236a03354eSMatthew Dillon 				wildcard, oif);
1246a03354eSMatthew Dillon 	} else {
1256a03354eSMatthew Dillon 		pcb = in_pcblookup_hash(pi,
1266a03354eSMatthew Dillon 				src_ip, htons(fid->src_port),
1276a03354eSMatthew Dillon 				dst_ip, htons(fid->dst_port),
1286a03354eSMatthew Dillon 				wildcard, NULL);
1296a03354eSMatthew Dillon 	}
1306a03354eSMatthew Dillon 	if (pcb == NULL || pcb->inp_socket == NULL) {
1316a03354eSMatthew Dillon 		return 0;
1326a03354eSMatthew Dillon 	}
1336a03354eSMatthew Dillon 
1346a03354eSMatthew Dillon 	if (opcode == O_LAYER4_UID) {
1356a03354eSMatthew Dillon #define socheckuid(a,b)	((a)->so_cred->cr_uid != (b))
1366a03354eSMatthew Dillon 		return !socheckuid(pcb->inp_socket, uid);
1376a03354eSMatthew Dillon #undef socheckuid
1386a03354eSMatthew Dillon 	} else  {
1396a03354eSMatthew Dillon 		return groupmember(uid, pcb->inp_socket->so_cred);
1406a03354eSMatthew Dillon 	}
1416a03354eSMatthew Dillon }
1426a03354eSMatthew Dillon 
1436a03354eSMatthew Dillon void
check_tcpflag(int * cmd_ctl,int * cmd_val,struct ip_fw_args ** args,struct ip_fw ** f,ipfw_insn * cmd,uint16_t ip_len)1446a03354eSMatthew Dillon check_tcpflag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1456a03354eSMatthew Dillon 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
1466a03354eSMatthew Dillon {
1476a03354eSMatthew Dillon 	/* XXX TODO check tcpflag */
1486a03354eSMatthew Dillon 	*cmd_val = 0;
1496a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
1506a03354eSMatthew Dillon }
1516a03354eSMatthew Dillon 
1526a03354eSMatthew Dillon void
check_uid(int * cmd_ctl,int * cmd_val,struct ip_fw_args ** args,struct ip_fw ** f,ipfw_insn * cmd,uint16_t ip_len)1536a03354eSMatthew Dillon check_uid(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1546a03354eSMatthew Dillon 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
1556a03354eSMatthew Dillon {
1564408d548SBill Yuan 	*cmd_val = ip_fw3_match_guid(&(*args)->f_id, (*args)->oif, cmd->opcode,
1576a03354eSMatthew Dillon 				(uid_t)((ipfw_insn_u32 *)cmd)->d[0]);
1586a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
1596a03354eSMatthew Dillon }
1606a03354eSMatthew Dillon 
1616a03354eSMatthew Dillon void
check_gid(int * cmd_ctl,int * cmd_val,struct ip_fw_args ** args,struct ip_fw ** f,ipfw_insn * cmd,uint16_t ip_len)1626a03354eSMatthew Dillon check_gid(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1636a03354eSMatthew Dillon 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
1646a03354eSMatthew Dillon {
1654408d548SBill Yuan 	*cmd_val = ip_fw3_match_guid(&(*args)->f_id, (*args)->oif, cmd->opcode,
1666a03354eSMatthew Dillon 				(gid_t)((ipfw_insn_u32 *)cmd)->d[0]);
1676a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
1686a03354eSMatthew Dillon }
1696a03354eSMatthew Dillon 
170dee12ddaSBill Yuan /*
171dee12ddaSBill Yuan  * match TCP packets which have all tcpflag except SYN.
172dee12ddaSBill Yuan  */
check_established(int * cmd_ctl,int * cmd_val,struct ip_fw_args ** args,struct ip_fw ** f,ipfw_insn * cmd,uint16_t ip_len)173dee12ddaSBill Yuan void check_established(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
174dee12ddaSBill Yuan 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
175dee12ddaSBill Yuan {
176dee12ddaSBill Yuan 	struct ipfw_flow_id *fid;
177dee12ddaSBill Yuan 	struct mbuf *m = (*args)->m;
178dee12ddaSBill Yuan 	struct ip *ip = mtod(m, struct ip *);
179dee12ddaSBill Yuan 
180dee12ddaSBill Yuan 	*cmd_ctl = IP_FW_CTL_NO;
181dee12ddaSBill Yuan 	fid = &(*args)->f_id;
182dee12ddaSBill Yuan 	if (fid->proto == IPPROTO_TCP) {
183dee12ddaSBill Yuan 		/* offset == 0 && */
184dee12ddaSBill Yuan 		if ((L3HDR(struct tcphdr, ip)->th_flags &
185dee12ddaSBill Yuan 				(TH_RST | TH_ACK | TH_SYN)) != TH_SYN) {
186dee12ddaSBill Yuan 			*cmd_val = IP_FW_MATCH;
187dee12ddaSBill Yuan 			return;
188dee12ddaSBill Yuan 		}
189dee12ddaSBill Yuan 	}
190dee12ddaSBill Yuan 	*cmd_val = IP_FW_NOT_MATCH;
191dee12ddaSBill Yuan }
192dee12ddaSBill Yuan 
193e895e94dSBill Yuan void
check_bpf(int * cmd_ctl,int * cmd_val,struct ip_fw_args ** args,struct ip_fw ** f,ipfw_insn * cmd,uint16_t ip_len)194e895e94dSBill Yuan check_bpf(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
195e895e94dSBill Yuan 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
196e895e94dSBill Yuan {
197e895e94dSBill Yuan 	u_int slen = 0;
198e895e94dSBill Yuan 	struct mbuf *m = (*args)->m;
199e895e94dSBill Yuan 	ipfw_insn_bpf *bpf = (ipfw_insn_bpf *)cmd;
200e895e94dSBill Yuan 	*cmd_ctl = IP_FW_CTL_NO;
201e895e94dSBill Yuan 	slen = bpf_filter(bpf->bf_insn, (u_char *)m, m_lengthm(m, NULL), 0);
202e895e94dSBill Yuan 	if (slen != 0)
203e895e94dSBill Yuan 		*cmd_val = IP_FW_MATCH;
204e895e94dSBill Yuan 	else
205e895e94dSBill Yuan 		*cmd_val = IP_FW_NOT_MATCH;
206e895e94dSBill Yuan }
207e895e94dSBill Yuan 
208e895e94dSBill Yuan 
2096a03354eSMatthew Dillon static int
ip_fw3_layer4_init(void)2104408d548SBill Yuan ip_fw3_layer4_init(void)
2116a03354eSMatthew Dillon {
2124408d548SBill Yuan 	ip_fw3_register_module(MODULE_LAYER4_ID, MODULE_LAYER4_NAME);
2134408d548SBill Yuan 	ip_fw3_register_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_TCPFLAG,
2146a03354eSMatthew Dillon 			(filter_func)check_tcpflag);
2154408d548SBill Yuan 	ip_fw3_register_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_UID,
2166a03354eSMatthew Dillon 			(filter_func)check_uid);
2174408d548SBill Yuan 	ip_fw3_register_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_GID,
2186a03354eSMatthew Dillon 			(filter_func)check_gid);
2194408d548SBill Yuan 	ip_fw3_register_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_ESTABLISHED,
220dee12ddaSBill Yuan 			(filter_func)check_established);
2214408d548SBill Yuan 	ip_fw3_register_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_BPF,
222e895e94dSBill Yuan 			(filter_func)check_bpf);
2236a03354eSMatthew Dillon 	return 0;
2246a03354eSMatthew Dillon }
2256a03354eSMatthew Dillon 
2266a03354eSMatthew Dillon static int
ip_fw3_layer4_stop(void)2274408d548SBill Yuan ip_fw3_layer4_stop(void)
2286a03354eSMatthew Dillon {
2294408d548SBill Yuan 	return ip_fw3_unregister_module(MODULE_LAYER4_ID);
2306a03354eSMatthew Dillon }
2316a03354eSMatthew Dillon 
2326a03354eSMatthew Dillon static int
ipfw3_layer4_modevent(module_t mod,int type,void * data)2336a03354eSMatthew Dillon ipfw3_layer4_modevent(module_t mod, int type, void *data)
2346a03354eSMatthew Dillon {
2356a03354eSMatthew Dillon 	switch (type) {
2366a03354eSMatthew Dillon 	case MOD_LOAD:
2374408d548SBill Yuan 		return ip_fw3_layer4_init();
2386a03354eSMatthew Dillon 	case MOD_UNLOAD:
2394408d548SBill Yuan 		return ip_fw3_layer4_stop();
2406a03354eSMatthew Dillon 	default:
2416a03354eSMatthew Dillon 		break;
2426a03354eSMatthew Dillon 	}
2436a03354eSMatthew Dillon 	return 0;
2446a03354eSMatthew Dillon }
2456a03354eSMatthew Dillon 
2466a03354eSMatthew Dillon static moduledata_t ipfw3_layer4_mod = {
2476a03354eSMatthew Dillon 	"ipfw3_layer4",
2486a03354eSMatthew Dillon 	ipfw3_layer4_modevent,
2496a03354eSMatthew Dillon 	NULL
2506a03354eSMatthew Dillon };
2516a03354eSMatthew Dillon DECLARE_MODULE(ipfw3_layer4, ipfw3_layer4_mod, SI_SUB_PROTO_END, SI_ORDER_ANY);
2526a03354eSMatthew Dillon MODULE_DEPEND(ipfw3_layer4, ipfw3_basic, 1, 1, 1);
2536a03354eSMatthew Dillon MODULE_VERSION(ipfw3_layer4, 1);
254