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