1255332Scy/* $FreeBSD$ */
2255332Scy
3255332Scy/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5255332Scy *
6255332Scy * See the IPFILTER.LICENCE file for details on licencing.
7255332Scy *
8255332Scy */
9255332Scy/*
10255332Scy * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate
11255332Scy * its own major char number! Way cool patch!
12255332Scy */
13255332Scy
14255332Scy
15255332Scy#include <sys/param.h>
16255332Scy
17255332Scy/*
18255332Scy * Post NetBSD 1.2 has the PFIL interface for packet filters.  This turns
19255332Scy * on those hooks.  We don't need any special mods with this!
20255332Scy */
21255332Scy#if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \
22255332Scy    (defined(NetBSD1_2) && NetBSD1_2 > 1)
23255332Scy# define NETBSD_PF
24255332Scy#endif
25255332Scy
26255332Scy#include <sys/systm.h>
27255332Scy#include <sys/conf.h>
28255332Scy#include <sys/file.h>
29255332Scy#include <sys/stat.h>
30255332Scy#include <sys/proc.h>
31255332Scy#include <sys/uio.h>
32255332Scy#include <sys/kernel.h>
33255332Scy#include <sys/vnode.h>
34255332Scy#include <sys/namei.h>
35255332Scy#include <sys/malloc.h>
36255332Scy#include <sys/mount.h>
37255332Scy#include <sys/exec.h>
38255332Scy#include <sys/mbuf.h>
39255332Scy#include <net/if.h>
40255332Scy#include <netinet/in_systm.h>
41255332Scy#include <netinet/in.h>
42255332Scy#include <netinet/ip.h>
43255332Scy#include <net/route.h>
44255332Scy#include <netinet/ip_var.h>
45255332Scy#include <netinet/tcp.h>
46255332Scy#include <netinet/tcpip.h>
47255332Scy#include <sys/lkm.h>
48255332Scy#include <sys/poll.h>
49255332Scy#include <sys/select.h>
50255332Scy#include "ipl.h"
51255332Scy#include "ip_compat.h"
52255332Scy#include "ip_fil.h"
53255332Scy#include "ip_auth.h"
54255332Scy#include "ip_state.h"
55255332Scy#include "ip_nat.h"
56255332Scy#include "ip_sync.h"
57255332Scy
58255332Scy#if !defined(__NetBSD_Version__) || __NetBSD_Version__ < 103050000
59255332Scy#define vn_lock(v,f) VOP_LOCK(v)
60255332Scy#endif
61255332Scy
62255332Scy#if !defined(VOP_LEASE) && defined(LEASE_CHECK)
63255332Scy#define	VOP_LEASE	LEASE_CHECK
64255332Scy#endif
65255332Scy
66255332Scy
67255332Scyextern	int	lkmenodev __P((void));
68255332Scy
69255332Scy#if NetBSD >= 199706
70255332Scyint	ipflkm_lkmentry __P((struct lkm_table *, int, int));
71255332Scy#else
72255332Scyint	xxxinit __P((struct lkm_table *, int, int));
73255332Scy#endif
74255332Scystatic	int	ipf_unload __P((void));
75255332Scystatic	int	ipf_load __P((void));
76255332Scystatic	int	ipf_remove __P((void));
77255332Scystatic	int	ipfaction __P((struct lkm_table *, int));
78255332Scystatic	char	*ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
79255332Scy				    IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
80255332Scy				    IPLOOKUP_NAME, NULL };
81255332Scy
82255332Scyint				ipf_major = 0;
83255332Scyextern	ipf_main_softc_t	ipfmain;
84255332Scyextern	const struct cdevsw ipl_cdevsw;
85255332Scy
86255332Scy#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000)
87255332ScyMOD_DEV(IPL_VERSION, "ipf", NULL, -1, &ipl_cdevsw, -1);
88255332Scy#else
89255332ScyMOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw);
90255332Scy#endif
91255332Scy
92255332Scyextern int vd_unuseddev __P((void));
93255332Scyextern struct cdevsw cdevsw[];
94255332Scyextern int nchrdev;
95255332Scy
96255332Scy
97255332Scyint
98255332Scy#if NetBSD >= 199706
99255332Scyipflkm_lkmentry(lkmtp, cmd, ver)
100255332Scy#else
101255332Scyxxxinit(lkmtp, cmd, ver)
102255332Scy#endif
103255332Scy	struct lkm_table *lkmtp;
104255332Scy	int cmd, ver;
105255332Scy{
106255332Scy	DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction);
107255332Scy}
108255332Scy
109255332Scy
110255332Scystatic int
111255332Scyipfaction(lkmtp, cmd)
112255332Scy	struct lkm_table *lkmtp;
113255332Scy	int cmd;
114255332Scy{
115255332Scy#if !defined(__NetBSD__) || (__NetBSD_Version__ < 106080000)
116255332Scy	int i;
117255332Scy#endif
118255332Scy	struct lkm_dev *args = lkmtp->private.lkm_dev;
119255332Scy	int err = 0;
120255332Scy
121255332Scy	switch (cmd)
122255332Scy	{
123255332Scy	case LKM_E_LOAD :
124255332Scy		if (lkmexists(lkmtp))
125255332Scy			return EEXIST;
126255332Scy
127255332Scy#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000)
128255332Scy# if (__NetBSD_Version__ < 200000000)
129255332Scy		err = devsw_attach(args->lkm_devname,
130255332Scy				   args->lkm_bdev, &args->lkm_bdevmaj,
131255332Scy				   args->lkm_cdev, &args->lkm_cdevmaj);
132255332Scy		if (err != 0)
133255332Scy			return (err);
134255332Scy# endif
135255332Scy		ipf_major = args->lkm_cdevmaj;
136255332Scy#else
137255332Scy		for (i = 0; i < nchrdev; i++)
138255332Scy			if (cdevsw[i].d_open == (dev_type_open((*)))lkmenodev ||
139255332Scy			    cdevsw[i].d_open == ipfopen)
140255332Scy				break;
141255332Scy		if (i == nchrdev) {
142255332Scy			printf("IP Filter: No free cdevsw slots\n");
143255332Scy			return ENODEV;
144255332Scy		}
145255332Scy
146255332Scy		ipf_major = i;
147255332Scy		args->lkm_offset = i;   /* slot in cdevsw[] */
148255332Scy#endif
149255332Scy		printf("IP Filter: loaded into slot %d\n", ipf_major);
150255332Scy		return ipf_load();
151255332Scy	case LKM_E_UNLOAD :
152255332Scy#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000)
153255332Scy		devsw_detach(args->lkm_bdev, args->lkm_cdev);
154255332Scy		args->lkm_bdevmaj = -1;
155255332Scy		args->lkm_cdevmaj = -1;
156255332Scy#endif
157255332Scy		err = ipf_unload();
158255332Scy		if (!err)
159255332Scy			printf("IP Filter: unloaded from slot %d\n",
160255332Scy			       ipf_major);
161255332Scy		break;
162255332Scy	case LKM_E_STAT :
163255332Scy		break;
164255332Scy	default:
165255332Scy		err = EIO;
166255332Scy		break;
167255332Scy	}
168255332Scy	return err;
169255332Scy}
170255332Scy
171255332Scy
172255332Scystatic int
173255332Scyipf_remove()
174255332Scy{
175255332Scy	char *name;
176255332Scy	struct nameidata nd;
177255332Scy	int error, i;
178255332Scy
179255332Scy        for (i = 0; (name = ipf_devfiles[i]); i++) {
180255332Scy#if (__NetBSD_Version__ > 106009999)
181255332Scy# if (__NetBSD_Version__ > 399001400)
182255332Scy#  if (__NetBSD_Version__ > 499001400)
183255332Scy		NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE,
184255332Scy		       name);
185255332Scy#  else
186255332Scy		NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE,
187255332Scy		       name, curlwp);
188255332Scy#  endif
189255332Scy# else
190255332Scy		NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE,
191255332Scy		       name, curproc);
192255332Scy# endif
193255332Scy#else
194255332Scy		NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
195255332Scy#endif
196255332Scy		if ((error = namei(&nd)))
197255332Scy			return (error);
198255332Scy#if (__NetBSD_Version__ > 399001400)
199255332Scy# if (__NetBSD_Version__ > 399002000)
200255332Scy#  if (__NetBSD_Version__ < 499001400)
201255332Scy		VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_cred, LEASE_WRITE);
202255332Scy#  endif
203255332Scy# else
204255332Scy		VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE);
205255332Scy# endif
206255332Scy#else
207255332Scy		VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
208255332Scy#endif
209255332Scy#if !defined(__NetBSD_Version__) || (__NetBSD_Version__ < 106000000)
210255332Scy		vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY);
211255332Scy#endif
212255332Scy#if (__NetBSD_Version__ >= 399002000)
213255332Scy# if (__NetBSD_Version__ < 499001400)
214255332Scy		VOP_LEASE(nd.ni_vp, curlwp, curlwp->l_cred, LEASE_WRITE);
215255332Scy# endif
216255332Scy#else
217255332Scy# if (__NetBSD_Version__ > 399001400)
218255332Scy		VOP_LEASE(nd.ni_vp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE);
219255332Scy# else
220255332Scy		VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
221255332Scy# endif
222255332Scy#endif
223255332Scy		(void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
224255332Scy	}
225255332Scy	return 0;
226255332Scy}
227255332Scy
228255332Scy
229255332Scystatic int
230255332Scyipf_unload()
231255332Scy{
232255332Scy	int error = 0;
233255332Scy
234255332Scy	/*
235255332Scy	 * Unloading - remove the filter rule check from the IP
236255332Scy	 * input/output stream.
237255332Scy	 */
238255332Scy	if (ipfmain.ipf_refcnt)
239255332Scy		error = EBUSY;
240255332Scy	else if (ipfmain.ipf_running >= 0) {
241255332Scy		error = ipfdetach(&ipfmain);
242255332Scy		if (error == 0) {
243255332Scy			ipf_destroy_all(&ipfmain);
244255332Scy			ipf_unload_all();
245255332Scy		}
246255332Scy	}
247255332Scy
248255332Scy	if (error == 0) {
249255332Scy		ipfmain.ipf_running = -2;
250255332Scy		error = ipf_remove();
251255332Scy		printf("%s unloaded\n", ipfilter_version);
252255332Scy	}
253255332Scy	return error;
254255332Scy}
255255332Scy
256255332Scy
257255332Scystatic int
258255332Scyipf_load()
259255332Scy{
260255332Scy	struct nameidata nd;
261255332Scy	struct vattr vattr;
262255332Scy	int error = 0, fmode = S_IFCHR|0600, i;
263255332Scy	char *name;
264255332Scy
265255332Scy	/*
266255332Scy	 * XXX Remove existing device nodes prior to creating new ones
267255332Scy	 * XXX using the assigned LKM device slot's major number.  In a
268255332Scy	 * XXX perfect world we could use the ones specified by cdevsw[].
269255332Scy	 */
270255332Scy	(void)ipf_remove();
271255332Scy
272255332Scy	bzero((char *)&ipfmain, sizeof(ipfmain));
273255332Scy        error = ipf_load_all();
274255332Scy	if (error != 0)
275255332Scy		return error;
276255332Scy	if (ipf_create_all(&ipfmain) == NULL) {
277255332Scy		ipf_unload_all();
278255332Scy		return EIO;
279255332Scy	}
280255332Scy
281255332Scy	error = ipfattach(&ipfmain);
282255332Scy	if (error != 0) {
283255332Scy		(void) ipf_unload();
284255332Scy		return error;
285255332Scy	}
286255332Scy
287255332Scy	for (i = 0; (error == 0) && (name = ipf_devfiles[i]); i++) {
288255332Scy#if (__NetBSD_Version__ > 399001400)
289255332Scy# if (__NetBSD_Version__ > 499001400)
290255332Scy		NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name);
291255332Scy# else
292255332Scy		NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curlwp);
293255332Scy# endif
294255332Scy#else
295255332Scy		NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
296255332Scy#endif
297255332Scy		if ((error = namei(&nd)))
298255332Scy			break;
299255332Scy		if (nd.ni_vp != NULL) {
300255332Scy			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
301255332Scy			if (nd.ni_dvp == nd.ni_vp)
302255332Scy				vrele(nd.ni_dvp);
303255332Scy			else
304255332Scy				vput(nd.ni_dvp);
305255332Scy			vrele(nd.ni_vp);
306255332Scy			error = EEXIST;
307255332Scy			break;
308255332Scy		}
309255332Scy		VATTR_NULL(&vattr);
310255332Scy		vattr.va_type = VCHR;
311255332Scy		vattr.va_mode = (fmode & 07777);
312255332Scy		vattr.va_rdev = (ipf_major << 8) | i;
313255332Scy#if (__NetBSD_Version__ > 399001400)
314255332Scy# if (__NetBSD_Version__ >= 399002000)
315255332Scy#  if (__NetBSD_Version__ < 499001400)
316255332Scy		VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_cred, LEASE_WRITE);
317255332Scy#  endif
318255332Scy# else
319255332Scy		VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE);
320255332Scy# endif
321255332Scy#else
322255332Scy		VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
323255332Scy#endif
324255332Scy		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
325255332Scy		if (error == 0)
326255332Scy			vput(nd.ni_vp);
327255332Scy	}
328255332Scy
329255332Scy	if (error == 0) {
330255332Scy		char *defpass;
331255332Scy
332255332Scy		if (FR_ISPASS(ipfmain.ipf_pass))
333255332Scy			defpass = "pass";
334255332Scy		else if (FR_ISBLOCK(ipfmain.ipf_pass))
335255332Scy			defpass = "block";
336255332Scy		else
337255332Scy			defpass = "no-match -> block";
338255332Scy
339255332Scy		printf("%s initialized.  Default = %s all, Logging = %s%s\n",
340255332Scy			ipfilter_version, defpass,
341255332Scy#ifdef IPFILTER_LOG
342255332Scy			"enabled",
343255332Scy#else
344255332Scy			"disabled",
345255332Scy#endif
346255332Scy#ifdef IPFILTER_COMPILED
347255332Scy			" (COMPILED)"
348255332Scy#else
349255332Scy			""
350255332Scy#endif
351255332Scy			);
352255332Scy		ipfmain.ipf_running = 1;
353255332Scy	}
354255332Scy	return error;
355255332Scy}
356