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