FreeBSD/Linux Kernel Cross Reference
sys/netinet/ip_fil.c
1 /*
2 * Copyright (C) 1993-1997 by Darren Reed.
3 *
4 * Redistribution and use in source and binary forms are permitted
5 * provided that this notice is preserved and due credit is given
6 * to the original author and the contributors.
7 */
8 #if !defined(lint)
9 static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed";
10 static const char rcsid[] = "@(#)$FreeBSD$";
11 #endif
12
13 #include "opt_ipfilter.h"
14
15 #ifndef SOLARIS
16 #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
17 #endif
18
19 #if defined(KERNEL) && !defined(_KERNEL)
20 # define _KERNEL
21 #endif
22 #ifdef __FreeBSD__
23 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
24 # define __FreeBSD_version 300000 /* this will do as a hack */
25 # else
26 # include <osreldate.h>
27 # endif
28 #endif
29 #ifndef _KERNEL
30 # include <stdio.h>
31 # include <string.h>
32 # include <stdlib.h>
33 # include <ctype.h>
34 #endif
35 #include <sys/errno.h>
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/file.h>
39 #if __FreeBSD_version >= 220000 && defined(_KERNEL)
40 # include <sys/fcntl.h>
41 # include <sys/filio.h>
42 #else
43 # include <sys/ioctl.h>
44 #endif
45 #include <sys/time.h>
46 #ifdef _KERNEL
47 # include <sys/systm.h>
48 #endif
49 #include <sys/uio.h>
50 #if !SOLARIS
51 # if (NetBSD > 199609) || (OpenBSD > 199603) || __FreeBSD_version >= 220000
52 # include <sys/dirent.h>
53 # else
54 # include <sys/dir.h>
55 # endif
56 # include <sys/mbuf.h>
57 #else
58 # include <sys/filio.h>
59 #endif
60 #include <sys/protosw.h>
61 #include <sys/socket.h>
62
63 #include <net/if.h>
64 #ifdef sun
65 # include <net/af.h>
66 #endif
67 #if __FreeBSD_version >= 300000
68 # include <net/if_var.h>
69 # include <sys/malloc.h>
70 #endif
71 #ifdef __sgi
72 #include <sys/debug.h>
73 # ifdef IFF_DRVRLOCK /* IRIX6 */
74 #include <sys/hashing.h>
75 # endif
76 #endif
77 #include <net/route.h>
78 #include <netinet/in.h>
79 #if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */
80 #include <netinet/in_var.h>
81 #endif
82 #include <netinet/in_systm.h>
83 #include <netinet/ip.h>
84 #include <netinet/ip_var.h>
85 #include <netinet/tcp.h>
86 #include <netinet/udp.h>
87 #include <netinet/tcpip.h>
88 #include <netinet/ip_icmp.h>
89 #ifndef _KERNEL
90 # include <syslog.h>
91 #endif
92 #include "netinet/ip_compat.h"
93 #include "netinet/ip_fil.h"
94 #include "netinet/ip_proxy.h"
95 #include "netinet/ip_nat.h"
96 #include "netinet/ip_frag.h"
97 #include "netinet/ip_state.h"
98 #include "netinet/ip_auth.h"
99 #ifndef MIN
100 #define MIN(a,b) (((a)<(b))?(a):(b))
101 #endif
102 #if !SOLARIS && defined(_KERNEL)
103 extern int ip_optcopy __P((struct ip *, struct ip *));
104 #endif
105
106
107 extern struct protosw inetsw[];
108
109 #ifndef _KERNEL
110 # include "ipt.h"
111 static struct ifnet **ifneta = NULL;
112 static int nifs = 0;
113 #else
114 # if (BSD < 199306) && !defined(__sgi)
115 static int (*fr_saveslowtimo) __P((void));
116 # else
117 static void (*fr_saveslowtimo) __P((void));
118 # endif
119 # if (BSD < 199306) || defined(__sgi)
120 extern int tcp_ttl;
121 # endif
122 #endif
123
124 int ipl_inited = 0;
125 int ipl_unreach = ICMP_UNREACH_FILTER;
126 u_long ipl_frouteok[2] = {0, 0};
127
128 static void fixskip __P((frentry_t **, frentry_t *, int));
129 static void frzerostats __P((caddr_t));
130 static void frsync __P((void));
131 #if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
132 static int frrequest __P((int, u_long, caddr_t, int));
133 #else
134 static int frrequest __P((int, int, caddr_t, int));
135 #endif
136 #ifdef _KERNEL
137 static int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **));
138 #else
139 int ipllog __P((void));
140 void init_ifp __P((void));
141 # ifdef __sgi
142 static int no_output __P((struct ifnet *, struct mbuf *,
143 struct sockaddr *));
144 static int write_output __P((struct ifnet *, struct mbuf *,
145 struct sockaddr *));
146 # else
147 static int no_output __P((struct ifnet *, struct mbuf *,
148 struct sockaddr *, struct rtentry *));
149 static int write_output __P((struct ifnet *, struct mbuf *,
150 struct sockaddr *, struct rtentry *));
151 # endif
152 #endif
153
154 #if (_BSDI_VERSION >= 199510) && defined(_KERNEL)
155 # include <sys/device.h>
156 # include <sys/conf.h>
157
158 struct cfdriver iplcd = {
159 NULL, "ipl", NULL, NULL, DV_DULL, 0
160 };
161
162 struct devsw iplsw = {
163 &iplcd,
164 iplopen, iplclose, iplread, nowrite, iplioctl, noselect, nommap,
165 nostrat, nodump, nopsize, 0,
166 nostop
167 };
168 #endif /* _BSDI_VERSION >= 199510 && _KERNEL */
169
170 #if defined(__NetBSD__) || defined(__OpenBSD__) || (_BSDI_VERSION >= 199701)
171 # include <sys/conf.h>
172 # if defined(NETBSD_PF)
173 # include <net/pfil.h>
174 /*
175 * We provide the fr_checkp name just to minimize changes later.
176 */
177 int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
178 # endif /* NETBSD_PF */
179 #endif /* __NetBSD__ */
180
181 #ifdef _KERNEL
182 # if defined(IPFILTER_LKM) && !defined(__sgi)
183 int iplidentify(s)
184 char *s;
185 {
186 if (strcmp(s, "ipl") == 0)
187 return 1;
188 return 0;
189 }
190 # endif /* IPFILTER_LKM */
191
192
193 /*
194 * Try to detect the case when compiling for NetBSD with pseudo-device
195 */
196 # if defined(__NetBSD__) && defined(PFIL_HOOKS)
197 void
198 ipfilterattach(count)
199 int count;
200 {
201 iplattach();
202 }
203 # endif
204
205
206 int iplattach()
207 {
208 char *defpass;
209 int s;
210 # ifdef __sgi
211 int error;
212 # endif
213
214 SPL_NET(s);
215 if (ipl_inited || (fr_checkp == fr_check)) {
216 printf("IP Filter: already initialized\n");
217 SPL_X(s);
218 return EBUSY;
219 }
220
221 # ifdef NETBSD_PF
222 pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
223 # endif
224
225 # ifdef __sgi
226 error = ipfilter_sgi_attach();
227 if (error) {
228 SPL_X(s);
229 return error;
230 }
231 # endif
232
233 ipl_inited = 1;
234 bzero((char *)frcache, sizeof(frcache));
235 bzero((char *)nat_table, sizeof(nat_table));
236 fr_savep = fr_checkp;
237 fr_checkp = fr_check;
238 fr_saveslowtimo = inetsw[0].pr_slowtimo;
239 inetsw[0].pr_slowtimo = ipfr_slowtimer;
240
241 # ifdef IPFILTER_LOG
242 ipflog_init();
243 # endif
244 SPL_X(s);
245 if (fr_pass & FR_PASS)
246 defpass = "pass";
247 else if (fr_pass & FR_BLOCK)
248 defpass = "block";
249 else
250 defpass = "no-match -> block";
251
252 printf("IP Filter: initialized. Default = %s all, Logging = %s\n",
253 defpass,
254 # ifdef IPFILTER_LOG
255 "enabled");
256 # else
257 "disabled");
258 # endif
259 return 0;
260 }
261
262
263 /*
264 * Disable the filter by removing the hooks from the IP input/output
265 * stream.
266 */
267 int ipldetach()
268 {
269 int s, i = FR_INQUE|FR_OUTQUE;
270
271 SPL_NET(s);
272 if (!ipl_inited)
273 {
274 printf("IP Filter: not initialized\n");
275 SPL_X(s);
276 return 0;
277 }
278
279 fr_checkp = fr_savep;
280 inetsw[0].pr_slowtimo = fr_saveslowtimo;
281 frflush(IPL_LOGIPF, &i);
282 ipl_inited = 0;
283
284 # ifdef NETBSD_PF
285 pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
286 # endif
287
288 # ifdef __sgi
289 ipfilter_sgi_detach();
290 # endif
291
292 ipfr_unload();
293 ip_natunload();
294 fr_stateunload();
295 fr_authunload();
296
297 SPL_X(s);
298 return 0;
299 }
300 #endif /* _KERNEL */
301
302
303 static void frzerostats(data)
304 caddr_t data;
305 {
306 struct friostat fio;
307
308 bcopy((char *)frstats, (char *)fio.f_st,
309 sizeof(struct filterstats) * 2);
310 fio.f_fin[0] = ipfilter[0][0];
311 fio.f_fin[1] = ipfilter[0][1];
312 fio.f_fout[0] = ipfilter[1][0];
313 fio.f_fout[1] = ipfilter[1][1];
314 fio.f_acctin[0] = ipacct[0][0];
315 fio.f_acctin[1] = ipacct[0][1];
316 fio.f_acctout[0] = ipacct[1][0];
317 fio.f_acctout[1] = ipacct[1][1];
318 fio.f_active = fr_active;
319 fio.f_froute[0] = ipl_frouteok[0];
320 fio.f_froute[1] = ipl_frouteok[1];
321 IWCOPY((caddr_t)&fio, data, sizeof(fio));
322 bzero((char *)frstats, sizeof(*frstats) * 2);
323 }
324
325
326 /*
327 * Filter ioctl interface.
328 */
329 #ifdef __sgi
330 int IPL_EXTERN(ioctl)(dev_t dev, int cmd, caddr_t data, int mode
331 # ifdef _KERNEL
332 , cred_t *cp, int *rp
333 # endif
334 )
335 #else
336 int IPL_EXTERN(ioctl)(dev, cmd, data, mode
337 #if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
338 (__FreeBSD_version >= 220000)) && defined(_KERNEL)
339 , p)
340 struct proc *p;
341 #else
342 )
343 #endif
344 dev_t dev;
345 #if defined(__NetBSD__) || defined(__OpenBSD__) || \
346 (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300003)
347 u_long cmd;
348 #else
349 int cmd;
350 #endif
351 caddr_t data;
352 int mode;
353 #endif /* __sgi */
354 {
355 #if defined(_KERNEL) && !SOLARIS
356 int s;
357 #endif
358 int error = 0, unit = 0, tmp;
359
360 #ifdef _KERNEL
361 unit = GET_MINOR(dev);
362 if ((IPL_LOGMAX < unit) || (unit < 0))
363 return ENXIO;
364 #endif
365
366 SPL_NET(s);
367
368 if (unit == IPL_LOGNAT) {
369 error = nat_ioctl(data, cmd, mode);
370 SPL_X(s);
371 return error;
372 }
373 if (unit == IPL_LOGSTATE) {
374 error = fr_state_ioctl(data, cmd, mode);
375 SPL_X(s);
376 return error;
377 }
378 switch (cmd) {
379 case FIONREAD :
380 #ifdef IPFILTER_LOG
381 IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data,
382 sizeof(iplused[IPL_LOGIPF]));
383 #endif
384 break;
385 #if !defined(IPFILTER_LKM) && defined(_KERNEL)
386 case SIOCFRENB :
387 {
388 u_int enable;
389
390 if (!(mode & FWRITE))
391 error = EPERM;
392 else {
393 IRCOPY(data, (caddr_t)&enable, sizeof(enable));
394 if (enable)
395 error = iplattach();
396 else
397 error = ipldetach();
398 }
399 break;
400 }
401 #endif
402 case SIOCSETFF :
403 if (!(mode & FWRITE))
404 error = EPERM;
405 else
406 IRCOPY(data, (caddr_t)&fr_flags, sizeof(fr_flags));
407 break;
408 case SIOCGETFF :
409 IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags));
410 break;
411 case SIOCINAFR :
412 case SIOCRMAFR :
413 case SIOCADAFR :
414 case SIOCZRLST :
415 if (!(mode & FWRITE))
416 error = EPERM;
417 else
418 error = frrequest(unit, cmd, data, fr_active);
419 break;
420 case SIOCINIFR :
421 case SIOCRMIFR :
422 case SIOCADIFR :
423 if (!(mode & FWRITE))
424 error = EPERM;
425 else
426 error = frrequest(unit, cmd, data, 1 - fr_active);
427 break;
428 case SIOCSWAPA :
429 if (!(mode & FWRITE))
430 error = EPERM;
431 else {
432 bzero((char *)frcache, sizeof(frcache[0]) * 2);
433 *(u_int *)data = fr_active;
434 fr_active = 1 - fr_active;
435 }
436 break;
437 case SIOCGETFS :
438 {
439 struct friostat fio;
440
441 bcopy((char *)frstats, (char *)fio.f_st,
442 sizeof(struct filterstats) * 2);
443 fio.f_fin[0] = ipfilter[0][0];
444 fio.f_fin[1] = ipfilter[0][1];
445 fio.f_fout[0] = ipfilter[1][0];
446 fio.f_fout[1] = ipfilter[1][1];
447 fio.f_acctin[0] = ipacct[0][0];
448 fio.f_acctin[1] = ipacct[0][1];
449 fio.f_acctout[0] = ipacct[1][0];
450 fio.f_acctout[1] = ipacct[1][1];
451 fio.f_auth = ipauth;
452 fio.f_active = fr_active;
453 fio.f_froute[0] = ipl_frouteok[0];
454 fio.f_froute[1] = ipl_frouteok[1];
455 IWCOPY((caddr_t)&fio, data, sizeof(fio));
456 break;
457 }
458 case SIOCFRZST :
459 if (!(mode & FWRITE))
460 error = EPERM;
461 else
462 frzerostats(data);
463 break;
464 case SIOCIPFFL :
465 if (!(mode & FWRITE))
466 error = EPERM;
467 else {
468 IRCOPY(data, (caddr_t)&tmp, sizeof(tmp));
469 frflush(unit, &tmp);
470 IWCOPY((caddr_t)&tmp, data, sizeof(tmp));
471 }
472 break;
473 #ifdef IPFILTER_LOG
474 case SIOCIPFFB :
475 if (!(mode & FWRITE))
476 error = EPERM;
477 else
478 *(int *)data = ipflog_clear(unit);
479 break;
480 #endif /* IPFILTER_LOG */
481 case SIOCGFRST :
482 IWCOPY((caddr_t)ipfr_fragstats(), data, sizeof(ipfrstat_t));
483 break;
484 case SIOCAUTHW :
485 case SIOCAUTHR :
486 if (!(mode & FWRITE)) {
487 error = EPERM;
488 break;
489 }
490 case SIOCATHST :
491 error = fr_auth_ioctl(data, cmd, NULL, NULL);
492 break;
493 case SIOCFRSYN :
494 if (!(mode & FWRITE))
495 error = EPERM;
496 else {
497 #if defined(_KERNEL) && defined(__sgi)
498 ipfsync();
499 #endif
500 frsync();
501 }
502 break;
503 default :
504 error = EINVAL;
505 break;
506 }
507 SPL_X(s);
508 return error;
509 }
510
511
512 static void frsync()
513 {
514 #ifdef _KERNEL
515 struct ifnet *ifp;
516
517 # if (__FreeBSD_version >= 300000)
518 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
519 # elif defined(__OpenBSD__) || (NetBSD >= 199511)
520 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
521 # else
522 for (ifp = ifnet; ifp; ifp = ifp->if_next)
523 # endif
524 ip_natsync(ifp);
525 #endif
526 }
527
528
529 static void fixskip(listp, rp, addremove)
530 frentry_t **listp, *rp;
531 int addremove;
532 {
533 frentry_t *fp;
534 int rules = 0, rn = 0;
535
536 for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rules++)
537 ;
538
539 if (!fp)
540 return;
541
542 for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++)
543 if (fp->fr_skip && (rn + fp->fr_skip >= rules))
544 fp->fr_skip += addremove;
545 }
546
547
548 static int frrequest(unit, req, data, set)
549 int unit;
550 #if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
551 u_long req;
552 #else
553 int req;
554 #endif
555 int set;
556 caddr_t data;
557 {
558 register frentry_t *fp, *f, **fprev;
559 register frentry_t **ftail;
560 frentry_t frd;
561 frdest_t *fdp;
562 frgroup_t *fg = NULL;
563 int error = 0, in, group;
564
565 fp = &frd;
566 IRCOPY(data, (caddr_t)fp, sizeof(*fp));
567
568 /*
569 * Check that the group number does exist and that if a head group
570 * has been specified, doesn't exist.
571 */
572 if (fp->fr_grhead &&
573 fr_findgroup(fp->fr_grhead, fp->fr_flags, unit, set, NULL))
574 return EEXIST;
575 if (fp->fr_group &&
576 !fr_findgroup(fp->fr_group, fp->fr_flags, unit, set, NULL))
577 return ESRCH;
578
579 in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
580
581 if (unit == IPL_LOGAUTH)
582 ftail = fprev = &ipauth;
583 else if (fp->fr_flags & FR_ACCOUNT)
584 ftail = fprev = &ipacct[in][set];
585 else if (fp->fr_flags & (FR_OUTQUE|FR_INQUE))
586 ftail = fprev = &ipfilter[in][set];
587 else
588 return ESRCH;
589
590 if ((group = fp->fr_group)) {
591 if (!(fg = fr_findgroup(group, fp->fr_flags, unit, set, NULL)))
592 return ESRCH;
593 ftail = fprev = fg->fg_start;
594 }
595
596 bzero((char *)frcache, sizeof(frcache[0]) * 2);
597
598 if (*fp->fr_ifname) {
599 fp->fr_ifa = GETUNIT(fp->fr_ifname);
600 if (!fp->fr_ifa)
601 fp->fr_ifa = (void *)-1;
602 }
603
604 fdp = &fp->fr_dif;
605 fp->fr_flags &= ~FR_DUP;
606 if (*fdp->fd_ifname) {
607 fdp->fd_ifp = GETUNIT(fdp->fd_ifname);
608 if (!fdp->fd_ifp)
609 fdp->fd_ifp = (struct ifnet *)-1;
610 else
611 fp->fr_flags |= FR_DUP;
612 }
613
614 fdp = &fp->fr_tif;
615 if (*fdp->fd_ifname) {
616 fdp->fd_ifp = GETUNIT(fdp->fd_ifname);
617 if (!fdp->fd_ifp)
618 fdp->fd_ifp = (struct ifnet *)-1;
619 }
620
621 /*
622 * Look for a matching filter rule, but don't include the next or
623 * interface pointer in the comparison (fr_next, fr_ifa).
624 */
625 for (; (f = *ftail); ftail = &f->fr_next)
626 if (bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip,
627 FR_CMPSIZ) == 0)
628 break;
629
630 /*
631 * If zero'ing statistics, copy current to caller and zero.
632 */
633 if (req == SIOCZRLST) {
634 if (!f)
635 return ESRCH;
636 IWCOPY((caddr_t)f, data, sizeof(*f));
637 f->fr_hits = 0;
638 f->fr_bytes = 0;
639 return 0;
640 }
641
642 if (!f) {
643 ftail = fprev;
644 if (req != SIOCINAFR && req != SIOCINIFR)
645 while ((f = *ftail))
646 ftail = &f->fr_next;
647 else if (fp->fr_hits)
648 while (--fp->fr_hits && (f = *ftail))
649 ftail = &f->fr_next;
650 f = NULL;
651 }
652
653 if (req == SIOCDELFR || req == SIOCRMIFR) {
654 if (!f)
655 error = ESRCH;
656 else {
657 if (f->fr_ref > 1)
658 return EBUSY;
659 if (fg && fg->fg_head)
660 fg->fg_head->fr_ref--;
661 if (unit == IPL_LOGAUTH)
662 return fr_auth_ioctl(data, req, f, ftail);
663 if (f->fr_grhead)
664 fr_delgroup(f->fr_grhead, fp->fr_flags, unit,
665 set);
666 fixskip(fprev, f, -1);
667 *ftail = f->fr_next;
668 KFREE(f);
669 }
670 } else {
671 if (f)
672 error = EEXIST;
673 else {
674 if (unit == IPL_LOGAUTH)
675 return fr_auth_ioctl(data, req, f, ftail);
676 KMALLOC(f, frentry_t *, sizeof(*f));
677 if (f != NULL) {
678 if (fg && fg->fg_head)
679 fg->fg_head->fr_ref++;
680 bcopy((char *)fp, (char *)f, sizeof(*f));
681 f->fr_ref = 1;
682 f->fr_hits = 0;
683 f->fr_next = *ftail;
684 *ftail = f;
685 if (req == SIOCINIFR || req == SIOCINAFR)
686 fixskip(fprev, f, 1);
687 f->fr_grp = NULL;
688 if ((group = f->fr_grhead))
689 fg = fr_addgroup(group, f, unit, set);
690 } else
691 error = ENOMEM;
692 }
693 }
694 return (error);
695 }
696
697
698 #ifdef _KERNEL
699 /*
700 * routines below for saving IP headers to buffer
701 */
702 #ifdef __sgi
703 # ifdef _KERNEL
704 int IPL_EXTERN(open)(dev_t *pdev, int flags, int devtype, cred_t *cp)
705 # else
706 int IPL_EXTERN(open)(dev_t dev, int flags)
707 # endif
708 #else
709 int IPL_EXTERN(open)(dev, flags
710 # if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
711 (__FreeBSD_version >= 220000)) && defined(_KERNEL)
712 , devtype, p)
713 int devtype;
714 struct proc *p;
715 # else
716 )
717 # endif
718 dev_t dev;
719 int flags;
720 #endif /* __sgi */
721 {
722 #if defined(__sgi) && defined(_KERNEL)
723 u_int min = geteminor(*pdev);
724 #else
725 u_int min = GET_MINOR(dev);
726 #endif
727
728 if (IPL_LOGMAX < min)
729 min = ENXIO;
730 else
731 min = 0;
732 return min;
733 }
734
735
736 #ifdef __sgi
737 int IPL_EXTERN(close)(dev_t dev, int flags, int devtype, cred_t *cp)
738 #else
739 int IPL_EXTERN(close)(dev, flags
740 # if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
741 (__FreeBSD_version >= 220000)) && defined(_KERNEL)
742 , devtype, p)
743 int devtype;
744 struct proc *p;
745 # else
746 )
747 # endif
748 dev_t dev;
749 int flags;
750 #endif /* __sgi */
751 {
752 u_int min = GET_MINOR(dev);
753
754 if (2 < min)
755 min = ENXIO;
756 else
757 min = 0;
758 return min;
759 }
760
761 /*
762 * iplread/ipllog
763 * both of these must operate with at least splnet() lest they be
764 * called during packet processing and cause an inconsistancy to appear in
765 * the filter lists.
766 */
767 #ifdef __sgi
768 int IPL_EXTERN(read)(dev_t dev, uio_t *uio, cred_t *crp)
769 #else
770 # if BSD >= 199306
771 int IPL_EXTERN(read)(dev, uio, ioflag)
772 int ioflag;
773 # else
774 int IPL_EXTERN(read)(dev, uio)
775 # endif
776 dev_t dev;
777 register struct uio *uio;
778 #endif /* __sgi */
779 {
780 # ifdef IPFILTER_LOG
781 return ipflog_read(GET_MINOR(dev), uio);
782 # else
783 return ENXIO;
784 # endif
785 }
786
787
788 /*
789 * send_reset - this could conceivably be a call to tcp_respond(), but that
790 * requires a large amount of setting up and isn't any more efficient.
791 */
792 int send_reset(ti)
793 struct tcpiphdr *ti;
794 {
795 struct tcpiphdr *tp;
796 struct tcphdr *tcp;
797 struct mbuf *m;
798 int tlen = 0, err;
799 ip_t *ip;
800 # if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
801 struct route ro;
802 # endif
803
804 if (ti->ti_flags & TH_RST)
805 return -1; /* feedback loop */
806 # if (BSD < 199306) || defined(__sgi)
807 m = m_get(M_DONTWAIT, MT_HEADER);
808 # else
809 m = m_gethdr(M_DONTWAIT, MT_HEADER);
810 m->m_data += max_linkhdr;
811 # endif
812 if (m == NULL)
813 return -1;
814
815 if (ti->ti_flags & TH_SYN)
816 tlen = 1;
817 m->m_len = sizeof (struct tcpiphdr);
818 # if BSD >= 199306
819 m->m_pkthdr.len = sizeof (struct tcpiphdr);
820 m->m_pkthdr.rcvif = (struct ifnet *)0;
821 # endif
822 bzero(mtod(m, char *), sizeof(struct tcpiphdr));
823 ip = mtod(m, struct ip *);
824 tp = mtod(m, struct tcpiphdr *);
825 tcp = (struct tcphdr *)((char *)ip + sizeof(struct ip));
826
827 ip->ip_src.s_addr = ti->ti_dst.s_addr;
828 ip->ip_dst.s_addr = ti->ti_src.s_addr;
829 tcp->th_dport = ti->ti_sport;
830 tcp->th_sport = ti->ti_dport;
831 tcp->th_ack = htonl(ntohl(ti->ti_seq) + tlen);
832 tcp->th_off = sizeof(struct tcphdr) >> 2;
833 tcp->th_flags = TH_RST|TH_ACK;
834 tp->ti_pr = ((struct ip *)ti)->ip_p;
835 tp->ti_len = htons(sizeof(struct tcphdr));
836 tcp->th_sum = in_cksum(m, sizeof(struct tcpiphdr));
837
838 ip->ip_tos = ((struct ip *)ti)->ip_tos;
839 ip->ip_p = ((struct ip *)ti)->ip_p;
840 ip->ip_len = sizeof (struct tcpiphdr);
841 # if (BSD < 199306) || defined(__sgi)
842 ip->ip_ttl = tcp_ttl;
843 # else
844 ip->ip_ttl = ip_defttl;
845 # endif
846
847 # if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
848 bzero((char *)&ro, sizeof(ro));
849 err = ip_output(m, (struct mbuf *)0, &ro, 0, 0);
850 if (ro.ro_rt)
851 RTFREE(ro.ro_rt);
852 # else
853 /*
854 * extra 0 in case of multicast
855 */
856 err = ip_output(m, (struct mbuf *)0, 0, 0, 0);
857 # endif
858 return err;
859 }
860
861
862 # if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000) && !defined(__sgi)
863 # if (BSD < 199306)
864 int iplinit __P((void));
865
866 int
867 # else
868 void iplinit __P((void));
869
870 void
871 # endif
872 iplinit()
873 {
874 (void) iplattach();
875 ip_init();
876 }
877 # endif /* ! __NetBSD__ */
878
879
880 size_t mbufchainlen(m0)
881 register struct mbuf *m0;
882 {
883 register size_t len = 0;
884
885 for (; m0; m0 = m0->m_next)
886 len += m0->m_len;
887 return len;
888 }
889
890
891 void ipfr_fastroute(m0, fin, fdp)
892 struct mbuf *m0;
893 fr_info_t *fin;
894 frdest_t *fdp;
895 {
896 register struct ip *ip, *mhip;
897 register struct mbuf *m = m0;
898 register struct route *ro;
899 struct ifnet *ifp = fdp->fd_ifp;
900 int len, off, error = 0;
901 int hlen = fin->fin_hlen;
902 struct route iproute;
903 struct sockaddr_in *dst;
904
905 ip = mtod(m0, struct ip *);
906 /*
907 * Route packet.
908 */
909 ro = &iproute;
910 bzero((caddr_t)ro, sizeof (*ro));
911 dst = (struct sockaddr_in *)&ro->ro_dst;
912 dst->sin_family = AF_INET;
913 dst->sin_addr = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst;
914 # ifdef __bsdi__
915 dst->sin_len = sizeof(*dst);
916 # endif
917 # if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \
918 !defined(__OpenBSD__)
919 # ifdef RTF_CLONING
920 rtalloc_ign(ro, RTF_CLONING);
921 # else
922 rtalloc_ign(ro, RTF_PRCLONING);
923 # endif
924 # else
925 rtalloc(ro);
926 # endif
927 if (!ifp) {
928 if (!(fin->fin_fr->fr_flags & FR_FASTROUTE)) {
929 error = -2;
930 goto bad;
931 }
932 if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
933 if (in_localaddr(ip->ip_dst))
934 error = EHOSTUNREACH;
935 else
936 error = ENETUNREACH;
937 goto bad;
938 }
939 if (ro->ro_rt->rt_flags & RTF_GATEWAY)
940 dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway;
941 }
942 if (ro->ro_rt)
943 ro->ro_rt->rt_use++;
944
945 /*
946 * For input packets which are being "fastrouted", they won't
947 * go back through output filtering and miss their chance to get
948 * NAT'd.
949 */
950 (void) ip_natout(ip, hlen, fin);
951 if (fin->fin_out)
952 ip->ip_sum = 0;
953 /*
954 * If small enough for interface, can just send directly.
955 */
956 if (ip->ip_len <= ifp->if_mtu) {
957 # ifndef sparc
958 ip->ip_id = htons(ip->ip_id);
959 ip->ip_len = htons(ip->ip_len);
960 ip->ip_off = htons(ip->ip_off);
961 # endif
962 if (!ip->ip_sum)
963 ip->ip_sum = in_cksum(m, hlen);
964 # if BSD >= 199306
965 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
966 ro->ro_rt);
967 # else
968 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);
969 # endif
970 goto done;
971 }
972 /*
973 * Too large for interface; fragment if possible.
974 * Must be able to put at least 8 bytes per fragment.
975 */
976 if (ip->ip_off & IP_DF) {
977 error = EMSGSIZE;
978 goto bad;
979 }
980 len = (ifp->if_mtu - hlen) &~ 7;
981 if (len < 8) {
982 error = EMSGSIZE;
983 goto bad;
984 }
985
986 {
987 int mhlen, firstlen = len;
988 struct mbuf **mnext = &m->m_act;
989
990 /*
991 * Loop through length of segment after first fragment,
992 * make new header and copy data of each part and link onto chain.
993 */
994 m0 = m;
995 mhlen = sizeof (struct ip);
996 for (off = hlen + len; off < ip->ip_len; off += len) {
997 MGET(m, M_DONTWAIT, MT_HEADER);
998 if (m == 0) {
999 error = ENOBUFS;
1000 goto bad;
1001 }
1002 # if BSD >= 199306
1003 m->m_data += max_linkhdr;
1004 # else
1005 m->m_off = MMAXOFF - hlen;
1006 # endif
1007 mhip = mtod(m, struct ip *);
1008 bcopy((char *)ip, (char *)mhip, sizeof(*ip));
1009 if (hlen > sizeof (struct ip)) {
1010 mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
1011 mhip->ip_hl = mhlen >> 2;
1012 }
1013 m->m_len = mhlen;
1014 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
1015 if (ip->ip_off & IP_MF)
1016 mhip->ip_off |= IP_MF;
1017 if (off + len >= ip->ip_len)
1018 len = ip->ip_len - off;
1019 else
1020 mhip->ip_off |= IP_MF;
1021 mhip->ip_len = htons((u_short)(len + mhlen));
1022 m->m_next = m_copy(m0, off, len);
1023 if (m->m_next == 0) {
1024 error = ENOBUFS; /* ??? */
1025 goto sendorfree;
1026 }
1027 # ifndef sparc
1028 mhip->ip_off = htons((u_short)mhip->ip_off);
1029 # endif
1030 mhip->ip_sum = 0;
1031 mhip->ip_sum = in_cksum(m, mhlen);
1032 *mnext = m;
1033 mnext = &m->m_act;
1034 }
1035 /*
1036 * Update first fragment by trimming what's been copied out
1037 * and updating header, then send each fragment (in order).
1038 */
1039 m_adj(m0, hlen + firstlen - ip->ip_len);
1040 ip->ip_len = htons((u_short)(hlen + firstlen));
1041 ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
1042 ip->ip_sum = 0;
1043 ip->ip_sum = in_cksum(m0, hlen);
1044 sendorfree:
1045 for (m = m0; m; m = m0) {
1046 m0 = m->m_act;
1047 m->m_act = 0;
1048 if (error == 0)
1049 # if BSD >= 199306
1050 error = (*ifp->if_output)(ifp, m,
1051 (struct sockaddr *)dst, ro->ro_rt);
1052 # else
1053 error = (*ifp->if_output)(ifp, m,
1054 (struct sockaddr *)dst);
1055 # endif
1056 else
1057 m_freem(m);
1058 }
1059 }
1060 done:
1061 if (!error)
1062 ipl_frouteok[0]++;
1063 else
1064 ipl_frouteok[1]++;
1065
1066 if (ro->ro_rt) {
1067 RTFREE(ro->ro_rt);
1068 }
1069 return;
1070 bad:
1071 m_freem(m);
1072 goto done;
1073 }
1074 #else /* #ifdef _KERNEL */
1075
1076
1077 #ifdef __sgi
1078 static int no_output __P((struct ifnet *ifp, struct mbuf *m,
1079 struct sockaddr *s))
1080 #else
1081 static int no_output __P((struct ifnet *ifp, struct mbuf *m,
1082 struct sockaddr *s, struct rtentry *rt))
1083 #endif
1084 {
1085 return 0;
1086 }
1087
1088
1089 # ifdef __STDC__
1090 #ifdef __sgi
1091 static int write_output __P((struct ifnet *ifp, struct mbuf *m,
1092 struct sockaddr *s))
1093 #else
1094 static int write_output __P((struct ifnet *ifp, struct mbuf *m,
1095 struct sockaddr *s, struct rtentry *rt))
1096 #endif
1097 {
1098 # if !(defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1099 (defined(OpenBSD) && (OpenBSD >= 199603))
1100 ip_t *ip = (ip_t *)m;
1101 # endif
1102 # else
1103 static int write_output(ifp, ip)
1104 struct ifnet *ifp;
1105 ip_t *ip;
1106 {
1107 # endif
1108 FILE *fp;
1109 char fname[32];
1110
1111 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1112 (defined(OpenBSD) && (OpenBSD >= 199603))
1113 snprintf(fname, sizeof(fname), "/tmp/%s", ifp->if_xname);
1114 if ((fp = fopen(fname, "a"))) {
1115 fclose(fp);
1116 }
1117 # else
1118 snprintf(fname, sizeof(fname), "/tmp/%s%d", ifp->if_name, ifp->if_unit);
1119 if ((fp = fopen(fname, "a"))) {
1120 fwrite((char *)ip, ntohs(ip->ip_len), 1, fp);
1121 fclose(fp);
1122 }
1123 # endif
1124 return 0;
1125 }
1126
1127
1128 struct ifnet *get_unit(name)
1129 char *name;
1130 {
1131 struct ifnet *ifp, **ifa;
1132 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1133 (defined(OpenBSD) && (OpenBSD >= 199603))
1134 for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
1135 if (!strcmp(name, ifp->if_xname))
1136 return ifp;
1137 }
1138 # else
1139 char ifname[32], *s;
1140
1141 for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
1142 (void) snprintf(ifname, sizeof(ifname),
1143 "%s%d", ifp->if_name, ifp->if_unit);
1144 if (!strcmp(name, ifname))
1145 return ifp;
1146 }
1147 # endif
1148
1149 if (!ifneta) {
1150 ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
1151 ifneta[1] = NULL;
1152 ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
1153 nifs = 1;
1154 } else {
1155 nifs++;
1156 ifneta = (struct ifnet **)realloc(ifneta,
1157 (nifs + 1) * sizeof(*ifa));
1158 ifneta[nifs] = NULL;
1159 ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
1160 }
1161 ifp = ifneta[nifs - 1];
1162
1163 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1164 (defined(OpenBSD) && (OpenBSD >= 199603))
1165 strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
1166 # else
1167 for (s = name; *s && !isdigit(*s); s++)
1168 ;
1169 if (*s && isdigit(*s)) {
1170 ifp->if_unit = atoi(s);
1171 ifp->if_name = (char *)malloc(s - name + 1);
1172 strncpy(ifp->if_name, name, s - name);
1173 ifp->if_name[s - name] = '\0';
1174 } else {
1175 ifp->if_name = strdup(name);
1176 ifp->if_unit = -1;
1177 }
1178 # endif
1179 ifp->if_output = no_output;
1180 return ifp;
1181 }
1182
1183
1184
1185 void init_ifp()
1186 {
1187 FILE *fp;
1188 struct ifnet *ifp, **ifa;
1189 char fname[32];
1190 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1191 (defined(OpenBSD) && (OpenBSD >= 199603))
1192 for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
1193 ifp->if_output = write_output;
1194 snprintf(fname, sizeof(fname), "/tmp/%s", ifp->if_xname);
1195 if ((fp = fopen(fname, "w")))
1196 fclose(fp);
1197 }
1198 # else
1199
1200 for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
1201 ifp->if_output = write_output;
1202 snprintf(fname, sizeof(fname),
1203 "/tmp/%s%d", ifp->if_name, ifp->if_unit);
1204 if ((fp = fopen(fname, "w")))
1205 fclose(fp);
1206 }
1207 # endif
1208 }
1209
1210
1211 void ipfr_fastroute(ip, fin, fdp)
1212 ip_t *ip;
1213 fr_info_t *fin;
1214 frdest_t *fdp;
1215 {
1216 struct ifnet *ifp = fdp->fd_ifp;
1217
1218 if (!ifp)
1219 return; /* no routing table out here */
1220
1221 ip->ip_len = htons((u_short)ip->ip_len);
1222 ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
1223 ip->ip_sum = 0;
1224 #ifdef __sgi
1225 (*ifp->if_output)(ifp, (void *)ip, NULL);
1226 #else
1227 (*ifp->if_output)(ifp, (void *)ip, NULL, 0);
1228 #endif
1229 }
1230
1231
1232 int ipllog __P((void))
1233 {
1234 verbose("l");
1235 return 0;
1236 }
1237
1238
1239 int send_reset(ip, ifp)
1240 ip_t *ip;
1241 struct ifnet *ifp;
1242 {
1243 verbose("- TCP RST sent\n");
1244 return 0;
1245 }
1246
1247
1248 int icmp_error(ip, ifp)
1249 ip_t *ip;
1250 struct ifnet *ifp;
1251 {
1252 verbose("- TCP RST sent\n");
1253 return 0;
1254 }
1255 #endif /* _KERNEL */
Cache object: 17b1792ac4106e01d2ba216efcbbfd0c
|