ipfw3: support bpf filter in layer4 module
[dragonfly.git] / sys / net / ipfw3_layer4 / ip_fw3_layer4.c
CommitLineData
105c533e
BY
1/*
2 * Copyright (c) 2015 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Bill Yuan <bycn82@gmail.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/malloc.h>
38#include <sys/socketvar.h>
39#include <sys/sysctl.h>
40#include <sys/systimer.h>
41#include <sys/param.h>
42#include <sys/ucred.h>
43
44#include <netinet/in_var.h>
45#include <netinet/ip_var.h>
46#include <netinet/in.h>
47#include <netinet/in_systm.h>
48#include <netinet/in_var.h>
49#include <netinet/in_pcb.h>
50#include <netinet/ip.h>
51#include <netinet/ip_var.h>
52#include <netinet/ip_icmp.h>
53#include <netinet/tcp.h>
54#include <netinet/tcp_timer.h>
55#include <netinet/tcp_var.h>
56#include <netinet/tcpip.h>
57#include <netinet/udp.h>
58#include <netinet/udp_var.h>
59#include <netinet/if_ether.h>
60
e895e94d 61#include <net/bpf.h>
105c533e
BY
62#include <net/ethernet.h>
63#include <net/netmsg2.h>
64#include <net/netisr2.h>
65#include <net/route.h>
66
6a03354e 67#include <net/ipfw3/ip_fw.h>
105c533e 68
6a03354e 69#include "ip_fw3_layer4.h"
105c533e
BY
70
71void
72check_tcpflag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
73 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
74void
75check_uid(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
76 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
77void
78check_gid(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
79 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
dee12dda
BY
80void
81check_established(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
82 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
e895e94d
BY
83void
84check_bpf(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
85 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
105c533e
BY
86
87/*
88 * ipfw_match_guid can match the gui and uid
89 */
90static int
91ipfw_match_guid(const struct ipfw_flow_id *fid, struct ifnet *oif,
92 int opcode, uid_t uid)
93{
94 struct in_addr src_ip, dst_ip;
95 struct inpcbinfo *pi;
96 boolean_t wildcard;
97 struct inpcb *pcb;
98
99 if (fid->proto == IPPROTO_TCP) {
100 wildcard = FALSE;
101 pi = &tcbinfo[mycpuid];
102 } else if (fid->proto == IPPROTO_UDP) {
103 wildcard = TRUE;
104 pi = &udbinfo[mycpuid];
105 } else {
106 return 0;
107 }
108
109 /*
110 * Values in 'fid' are in host byte order
111 */
112 dst_ip.s_addr = htonl(fid->dst_ip);
113 src_ip.s_addr = htonl(fid->src_ip);
114 if (oif) {
115 pcb = in_pcblookup_hash(pi,
116 dst_ip, htons(fid->dst_port),
117 src_ip, htons(fid->src_port),
118 wildcard, oif);
119 } else {
120 pcb = in_pcblookup_hash(pi,
121 src_ip, htons(fid->src_port),
122 dst_ip, htons(fid->dst_port),
123 wildcard, NULL);
124 }
125 if (pcb == NULL || pcb->inp_socket == NULL) {
126 return 0;
127 }
128
129 if (opcode == O_LAYER4_UID) {
130#define socheckuid(a,b) ((a)->so_cred->cr_uid != (b))
131 return !socheckuid(pcb->inp_socket, uid);
132#undef socheckuid
133 } else {
134 return groupmember(uid, pcb->inp_socket->so_cred);
135 }
136}
137
138void
139check_tcpflag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
140 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
141{
142 /* XXX TODO check tcpflag */
143 *cmd_val = 0;
144 *cmd_ctl = IP_FW_CTL_NO;
145}
146
147void
148check_uid(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
149 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
150{
151 *cmd_val = ipfw_match_guid(&(*args)->f_id, (*args)->oif, cmd->opcode,
152 (uid_t)((ipfw_insn_u32 *)cmd)->d[0]);
153 *cmd_ctl = IP_FW_CTL_NO;
154}
155
156void
157check_gid(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
158 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
159{
160 *cmd_val = ipfw_match_guid(&(*args)->f_id, (*args)->oif, cmd->opcode,
161 (gid_t)((ipfw_insn_u32 *)cmd)->d[0]);
162 *cmd_ctl = IP_FW_CTL_NO;
163}
164
dee12dda
BY
165/*
166 * match TCP packets which have all tcpflag except SYN.
167 */
168void check_established(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
169 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
170{
171 struct ipfw_flow_id *fid;
172 struct mbuf *m = (*args)->m;
173 struct ip *ip = mtod(m, struct ip *);
174
175 *cmd_ctl = IP_FW_CTL_NO;
176 fid = &(*args)->f_id;
177 if (fid->proto == IPPROTO_TCP) {
178 /* offset == 0 && */
179 if ((L3HDR(struct tcphdr, ip)->th_flags &
180 (TH_RST | TH_ACK | TH_SYN)) != TH_SYN) {
181 *cmd_val = IP_FW_MATCH;
182 return;
183 }
184 }
185 *cmd_val = IP_FW_NOT_MATCH;
186}
187
e895e94d
BY
188void
189check_bpf(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
190 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
191{
192 u_int slen = 0;
193 struct mbuf *m = (*args)->m;
194 ipfw_insn_bpf *bpf = (ipfw_insn_bpf *)cmd;
195 *cmd_ctl = IP_FW_CTL_NO;
196 slen = bpf_filter(bpf->bf_insn, (u_char *)m, m_lengthm(m, NULL), 0);
197 if (slen != 0)
198 *cmd_val = IP_FW_MATCH;
199 else
200 *cmd_val = IP_FW_NOT_MATCH;
201}
202
203
105c533e 204static int
6a03354e 205ipfw3_layer4_init(void)
105c533e
BY
206{
207 register_ipfw_module(MODULE_LAYER4_ID, MODULE_LAYER4_NAME);
208 register_ipfw_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_TCPFLAG,
209 (filter_func)check_tcpflag);
210 register_ipfw_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_UID,
211 (filter_func)check_uid);
212 register_ipfw_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_GID,
213 (filter_func)check_gid);
dee12dda
BY
214 register_ipfw_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_ESTABLISHED,
215 (filter_func)check_established);
e895e94d
BY
216 register_ipfw_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_BPF,
217 (filter_func)check_bpf);
105c533e
BY
218 return 0;
219}
220
221static int
6a03354e 222ipfw3_layer4_stop(void)
105c533e
BY
223{
224 return unregister_ipfw_module(MODULE_LAYER4_ID);
225}
226
227static int
6a03354e 228ipfw3_layer4_modevent(module_t mod, int type, void *data)
105c533e
BY
229{
230 switch (type) {
231 case MOD_LOAD:
6a03354e 232 return ipfw3_layer4_init();
105c533e 233 case MOD_UNLOAD:
6a03354e 234 return ipfw3_layer4_stop();
105c533e
BY
235 default:
236 break;
237 }
238 return 0;
239}
240
6a03354e
MD
241static moduledata_t ipfw3_layer4_mod = {
242 "ipfw3_layer4",
243 ipfw3_layer4_modevent,
105c533e
BY
244 NULL
245};
6a03354e
MD
246DECLARE_MODULE(ipfw3_layer4, ipfw3_layer4_mod, SI_SUB_PROTO_END, SI_ORDER_ANY);
247MODULE_DEPEND(ipfw3_layer4, ipfw3_basic, 1, 1, 1);
248MODULE_VERSION(ipfw3_layer4, 1);