xref: /NextBSD/contrib/ipfilter/mlo_ipl.c (revision e1dd16d965b177f109afb771e59432e36f335d0a)
1 /* $FreeBSD$ */
2 
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  *
8  */
9 
10 #include <sys/param.h>
11 #include <sys/systm.h>
12 #include <sys/conf.h>
13 #include <sys/file.h>
14 #include <sys/stat.h>
15 #include <sys/proc.h>
16 #include <sys/uio.h>
17 #include <sys/kernel.h>
18 #include <sys/vnode.h>
19 #include <sys/namei.h>
20 #include <sys/malloc.h>
21 #include <sys/mount.h>
22 #include <sys/exec.h>
23 #include <sys/mbuf.h>
24 #include <net/if.h>
25 #include <netinet/in_systm.h>
26 #include <netinet/in.h>
27 #include <netinet/ip.h>
28 #include <net/route.h>
29 #include <netinet/ip_var.h>
30 #include <netinet/tcp.h>
31 #include <netinet/tcpip.h>
32 #include <sys/lkm.h>
33 #include "ipl.h"
34 #include "ip_compat.h"
35 #include "ip_fil.h"
36 
37 #define vn_lock(v,f) VOP_LOCK(v)
38 
39 #if !defined(VOP_LEASE) && defined(LEASE_CHECK)
40 #define	VOP_LEASE	LEASE_CHECK
41 #endif
42 
43 
44 extern	int	lkmenodev __P((void));
45 
46 #if OpenBSD >= 200311
47 int	if_ipf_lkmentry __P((struct lkm_table *, int, int));
48 #else
49 int	if_ipf __P((struct lkm_table *, int, int));
50 #endif
51 static	int	ipf_unload __P((void));
52 static	int	ipf_load __P((void));
53 static	int	ipf_remove __P((void));
54 static	int	ipfaction __P((struct lkm_table *, int));
55 static	char	*ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
56 				    IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
57 				    IPLOOKUP_NAME, NULL };
58 
59 
60 struct	cdevsw	ipfdevsw =
61 {
62 	ipfopen,		/* open */
63 	ipfclose,		/* close */
64 	ipfread,		/* read */
65 	(void *)nullop,		/* write */
66 	ipfioctl,		/* ioctl */
67 	(void *)nullop,		/* stop */
68 	(void *)NULL,		/* tty */
69 	(void *)nullop,		/* select */
70 	(void *)nullop,		/* mmap */
71 	NULL			/* strategy */
72 };
73 
74 int	ipf_major = 0;
75 
76 MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipfdevsw);
77 
78 extern int vd_unuseddev __P((void));
79 extern struct cdevsw cdevsw[];
80 extern int nchrdev;
81 
82 
83 #if OpenBSD >= 200311
if_ipf_lkmentry(lkmtp,cmd,ver)84 int if_ipf_lkmentry (lkmtp, cmd, ver)
85 #else
86 int if_ipf(lkmtp, cmd, ver)
87 #endif
88 	struct lkm_table *lkmtp;
89 	int cmd, ver;
90 {
91 	DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction);
92 }
93 
94 int lkmexists __P((struct lkm_table *)); /* defined in /sys/kern/kern_lkm.c */
95 
ipfaction(lkmtp,cmd)96 static int ipfaction(lkmtp, cmd)
97 	struct lkm_table *lkmtp;
98 	int cmd;
99 {
100 	int i;
101 	struct lkm_dev *args = lkmtp->private.lkm_dev;
102 	int err = 0;
103 
104 	switch (cmd)
105 	{
106 	case LKM_E_LOAD :
107 		if (lkmexists(lkmtp))
108 			return EEXIST;
109 
110 		for (i = 0; i < nchrdev; i++)
111 			if (cdevsw[i].d_open == (dev_type_open((*)))lkmenodev ||
112 			    cdevsw[i].d_open == ipfopen)
113 				break;
114 		if (i == nchrdev) {
115 			printf("IP Filter: No free cdevsw slots\n");
116 			return ENODEV;
117 		}
118 
119 		ipf_major = i;
120 		args->lkm_offset = i;   /* slot in cdevsw[] */
121 		printf("IP Filter: loaded into slot %d\n", ipf_major);
122 		return ipf_load();
123 	case LKM_E_UNLOAD :
124 		err = ipf_unload();
125 		if (!err)
126 			printf("IP Filter: unloaded from slot %d\n",
127 			       ipf_major);
128 		break;
129 	case LKM_E_STAT :
130 		break;
131 	default:
132 		err = EIO;
133 		break;
134 	}
135 	return err;
136 }
137 
138 
ipf_remove()139 static int ipf_remove()
140 {
141 	struct nameidata nd;
142 	int error, i;
143 	char *name;
144 
145         for (i = 0; (name = ipf_devfiles[i]); i++) {
146 #if OpenBSD >= 200311
147 		NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE,
148 		       name, curproc);
149 #else
150 		NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
151 #endif
152 		if ((error = namei(&nd)))
153 			return (error);
154 		VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
155 #if OpenBSD < 200311
156 		VOP_LOCK(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY, curproc);
157 		VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
158 #else
159 		(void)uvm_vnp_uncache(nd.ni_vp);
160 
161 		VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
162 		VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
163 #endif
164 		(void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
165 	}
166 	return 0;
167 }
168 
169 
ipf_unload()170 static int ipf_unload()
171 {
172 	int error = 0;
173 
174 	/*
175 	 * Unloading - remove the filter rule check from the IP
176 	 * input/output stream.
177 	 */
178         if (ipf_refcnt)
179                 error = EBUSY;
180 	else if (ipf_running >= 0)
181 		error = ipfdetach();
182 
183 	if (error == 0) {
184 		ipf_running = -2;
185 		error = ipf_remove();
186 		printf("%s unloaded\n", ipfilter_version);
187 	}
188 	return error;
189 }
190 
191 
ipf_load()192 static int ipf_load()
193 {
194 	struct nameidata nd;
195 	struct vattr vattr;
196 	int error = 0, fmode = S_IFCHR|0600, i;
197 	char *name;
198 
199 	/*
200 	 * XXX Remove existing device nodes prior to creating new ones
201 	 * XXX using the assigned LKM device slot's major number.  In a
202 	 * XXX perfect world we could use the ones specified by cdevsw[].
203 	 */
204 	(void)ipf_remove();
205 
206 	error = ipfattach();
207 
208 	for (i = 0; (error == 0) && (name = ipf_devfiles[i]); i++) {
209 		NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
210 		if ((error = namei(&nd)))
211 			break;
212 		if (nd.ni_vp != NULL) {
213 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
214 			if (nd.ni_dvp == nd.ni_vp)
215 				vrele(nd.ni_dvp);
216 			else
217 				vput(nd.ni_dvp);
218 			vrele(nd.ni_vp);
219 			error = EEXIST;
220 			break;
221 		}
222 		VATTR_NULL(&vattr);
223 		vattr.va_type = VCHR;
224 		vattr.va_mode = (fmode & 07777);
225 		vattr.va_rdev = (ipf_major << 8) | i;
226 		VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
227 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
228 	}
229 
230 	if (error == 0) {
231 		char *defpass;
232 
233 		if (FR_ISPASS(ipf_pass))
234 			defpass = "pass";
235 		else if (FR_ISBLOCK(ipf_pass))
236 			defpass = "block";
237 		else
238 			defpass = "no-match -> block";
239 
240 		printf("%s initialized.  Default = %s all, Logging = %s%s\n",
241 			ipfilter_version, defpass,
242 #ifdef IPFILTER_LOG
243 			"enabled",
244 #else
245 			"disabled",
246 #endif
247 #ifdef IPFILTER_COMPILED
248 			" (COMPILED)"
249 #else
250 			""
251 #endif
252 			);
253 		ipf_running = 1;
254 	}
255 	return error;
256 }
257 
258 
259 /*
260  * routines below for saving IP headers to buffer
261  */
262 int
ipfopen(dev,flags,devtype,p)263 ipfopen(dev, flags, devtype, p)
264 	dev_t dev;
265 	int flags;
266 	int devtype;
267 	struct proc *p;
268 {
269 	u_int min = GET_MINOR(dev);
270 	int error;
271 
272 	if (IPL_LOGMAX < min) {
273 		error = ENXIO;
274 	} else {
275 		switch (unit)
276 		{
277 		case IPL_LOGIPF :
278 		case IPL_LOGNAT :
279 		case IPL_LOGSTATE :
280 		case IPL_LOGAUTH :
281 		case IPL_LOGLOOKUP :
282 		case IPL_LOGSYNC :
283 #ifdef IPFILTER_SCAN
284 		case IPL_LOGSCAN :
285 #endif
286 			error = 0;
287 			break;
288 		default :
289 			error = ENXIO;
290 			break;
291 		}
292 	}
293 	return error;
294 }
295 
296 
297 int
ipfclose(dev,flags,devtype,p)298 ipfclose(dev, flags, devtype, p)
299 	dev_t dev;
300 	int flags;
301 	int devtype;
302 	struct proc *p;
303 {
304 	u_int   min = GET_MINOR(dev);
305 
306 	if (IPL_LOGMAX < min)
307 		min = ENXIO;
308 	else
309 		min = 0;
310 	return min;
311 }
312 
313 
314 /*
315  * ipfread/ipflog
316  * both of these must operate with at least splnet() lest they be
317  * called during packet processing and cause an inconsistancy to appear in
318  * the filter lists.
319  */
320 int
ipfread(dev,uio,ioflag)321 ipfread(dev, uio, ioflag)
322 	dev_t dev;
323 	register struct uio *uio;
324 	int ioflag;
325 {
326 
327 	if (ipf_running < 1)
328 		return EIO;
329 
330 	if (GET_MINOR(dev) == IPL_LOGSYNC)
331 		return ipfsync_read(uio);
332 
333 #ifdef IPFILTER_LOG
334 	return ipflog_read(GET_MINOR(dev), uio);
335 #else
336 	return ENXIO;
337 #endif
338 }
339 
340 
341 /*
342  * ipfwrite
343  * both of these must operate with at least splnet() lest they be
344  * called during packet processing and cause an inconsistancy to appear in
345  * the filter lists.
346  */
347 int
348 #if (BSD >= 199306)
ipfwrite(dev,uio,ioflag)349 ipfwrite(dev, uio, ioflag)
350 	int ioflag;
351 #else
352 ipfwrite(dev, uio)
353 #endif
354 	dev_t dev;
355 	register struct uio *uio;
356 {
357 
358 	if (ipf_running < 1)
359 		return EIO;
360 
361 	if (GET_MINOR(dev) == IPL_LOGSYNC)
362 		return ipfsync_write(uio);
363 	return ENXIO;
364 }
365