]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/ipfilter/mlo_ipl.c
MFC r368207,368607:
[FreeBSD/stable/10.git] / contrib / ipfilter / mlo_ipl.c
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
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
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
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
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
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
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
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
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)
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 }