]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/ip_fil.c
This commit was generated by cvs2svn to compensate for changes in r34742,
[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.5 1997/11/24 10:02:02 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__)
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         ro->ro_rt->rt_use++;
937
938         /*
939          * For input packets which are being "fastrouted", they won't
940          * go back through output filtering and miss their chance to get
941          * NAT'd.
942          */
943         (void) ip_natout(ip, hlen, fin);
944         if (fin->fin_out)
945                 ip->ip_sum = 0;
946         /*
947          * If small enough for interface, can just send directly.
948          */
949         if (ip->ip_len <= ifp->if_mtu) {
950 # ifndef sparc
951                 ip->ip_id = htons(ip->ip_id);
952                 ip->ip_len = htons(ip->ip_len);
953                 ip->ip_off = htons(ip->ip_off);
954 # endif
955                 if (!ip->ip_sum)
956                         ip->ip_sum = in_cksum(m, hlen);
957 # if    BSD >= 199306
958                 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
959                                           ro->ro_rt);
960 # else
961                 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);
962 # endif
963                 goto done;
964         }
965         /*
966          * Too large for interface; fragment if possible.
967          * Must be able to put at least 8 bytes per fragment.
968          */
969         if (ip->ip_off & IP_DF) {
970                 error = EMSGSIZE;
971                 goto bad;
972         }
973         len = (ifp->if_mtu - hlen) &~ 7;
974         if (len < 8) {
975                 error = EMSGSIZE;
976                 goto bad;
977         }
978
979     {
980         int mhlen, firstlen = len;
981         struct mbuf **mnext = &m->m_act;
982
983         /*
984          * Loop through length of segment after first fragment,
985          * make new header and copy data of each part and link onto chain.
986          */
987         m0 = m;
988         mhlen = sizeof (struct ip);
989         for (off = hlen + len; off < ip->ip_len; off += len) {
990                 MGET(m, M_DONTWAIT, MT_HEADER);
991                 if (m == 0) {
992                         error = ENOBUFS;
993                         goto bad;
994                 }
995 # if BSD >= 199306
996                 m->m_data += max_linkhdr;
997 # else
998                 m->m_off = MMAXOFF - hlen;
999 # endif
1000                 mhip = mtod(m, struct ip *);
1001                 bcopy((char *)ip, (char *)mhip, sizeof(*ip));
1002                 if (hlen > sizeof (struct ip)) {
1003                         mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
1004                         mhip->ip_hl = mhlen >> 2;
1005                 }
1006                 m->m_len = mhlen;
1007                 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
1008                 if (ip->ip_off & IP_MF)
1009                         mhip->ip_off |= IP_MF;
1010                 if (off + len >= ip->ip_len)
1011                         len = ip->ip_len - off;
1012                 else
1013                         mhip->ip_off |= IP_MF;
1014                 mhip->ip_len = htons((u_short)(len + mhlen));
1015                 m->m_next = m_copy(m0, off, len);
1016                 if (m->m_next == 0) {
1017                         error = ENOBUFS;        /* ??? */
1018                         goto sendorfree;
1019                 }
1020 # ifndef sparc
1021                 mhip->ip_off = htons((u_short)mhip->ip_off);
1022 # endif
1023                 mhip->ip_sum = 0;
1024                 mhip->ip_sum = in_cksum(m, mhlen);
1025                 *mnext = m;
1026                 mnext = &m->m_act;
1027         }
1028         /*
1029          * Update first fragment by trimming what's been copied out
1030          * and updating header, then send each fragment (in order).
1031          */
1032         m_adj(m0, hlen + firstlen - ip->ip_len);
1033         ip->ip_len = htons((u_short)(hlen + firstlen));
1034         ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
1035         ip->ip_sum = 0;
1036         ip->ip_sum = in_cksum(m0, hlen);
1037 sendorfree:
1038         for (m = m0; m; m = m0) {
1039                 m0 = m->m_act;
1040                 m->m_act = 0;
1041                 if (error == 0)
1042 # if BSD >= 199306
1043                         error = (*ifp->if_output)(ifp, m,
1044                             (struct sockaddr *)dst, ro->ro_rt);
1045 # else
1046                         error = (*ifp->if_output)(ifp, m,
1047                             (struct sockaddr *)dst);
1048 # endif
1049                 else
1050                         m_freem(m);
1051         }
1052     }   
1053 done:
1054         if (!error)
1055                 ipl_frouteok[0]++;
1056         else
1057                 ipl_frouteok[1]++;
1058
1059         if (ro->ro_rt) {
1060                 RTFREE(ro->ro_rt);
1061         }
1062         return;
1063 bad:
1064         m_freem(m);
1065         goto done;
1066 }
1067 #else /* #ifdef _KERNEL */
1068
1069
1070 #ifdef __sgi
1071 static int no_output __P((struct ifnet *ifp, struct mbuf *m,
1072                            struct sockaddr *s))
1073 #else
1074 static int no_output __P((struct ifnet *ifp, struct mbuf *m,
1075                            struct sockaddr *s, struct rtentry *rt))
1076 #endif
1077 {
1078         return 0;
1079 }
1080
1081
1082 # ifdef __STDC__
1083 #ifdef __sgi
1084 static int write_output __P((struct ifnet *ifp, struct mbuf *m,
1085                              struct sockaddr *s))
1086 #else
1087 static int write_output __P((struct ifnet *ifp, struct mbuf *m,
1088                              struct sockaddr *s, struct rtentry *rt))
1089 #endif
1090 {
1091 # if !(defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1092         (defined(OpenBSD) && (OpenBSD >= 199603))
1093         ip_t *ip = (ip_t *)m;
1094 #  endif
1095 # else
1096 static int write_output(ifp, ip)
1097 struct ifnet *ifp;
1098 ip_t *ip;
1099 {
1100 # endif
1101         FILE *fp;
1102         char fname[32];
1103
1104 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1105         (defined(OpenBSD) && (OpenBSD >= 199603))
1106         sprintf(fname, "/tmp/%s", ifp->if_xname);
1107         if ((fp = fopen(fname, "a"))) {
1108                 fclose(fp);
1109         }
1110 # else
1111         sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
1112         if ((fp = fopen(fname, "a"))) {
1113                 fwrite((char *)ip, ntohs(ip->ip_len), 1, fp);
1114                 fclose(fp);
1115         }
1116 # endif
1117         return 0;
1118 }
1119
1120
1121 struct ifnet *get_unit(name)
1122 char *name;
1123 {
1124         struct ifnet *ifp, **ifa;
1125 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1126         (defined(OpenBSD) && (OpenBSD >= 199603))
1127         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
1128                 if (!strcmp(name, ifp->if_xname))
1129                         return ifp;
1130         }
1131 # else
1132         char ifname[32], *s;
1133
1134         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
1135                 (void) sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
1136                 if (!strcmp(name, ifname))
1137                         return ifp;
1138         }
1139 # endif
1140
1141         if (!ifneta) {
1142                 ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
1143                 ifneta[1] = NULL;
1144                 ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
1145                 nifs = 1;
1146         } else {
1147                 nifs++;
1148                 ifneta = (struct ifnet **)realloc(ifneta,
1149                                                   (nifs + 1) * sizeof(*ifa));
1150                 ifneta[nifs] = NULL;
1151                 ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
1152         }
1153         ifp = ifneta[nifs - 1];
1154
1155 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1156         (defined(OpenBSD) && (OpenBSD >= 199603))
1157         strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
1158 # else
1159         for (s = name; *s && !isdigit(*s); s++)
1160                 ;
1161         if (*s && isdigit(*s)) {
1162                 ifp->if_unit = atoi(s);
1163                 ifp->if_name = (char *)malloc(s - name + 1);
1164                 strncpy(ifp->if_name, name, s - name);
1165                 ifp->if_name[s - name] = '\0';
1166         } else {
1167                 ifp->if_name = strdup(name);
1168                 ifp->if_unit = -1;
1169         }
1170 # endif
1171         ifp->if_output = no_output;
1172         return ifp;
1173 }
1174
1175
1176
1177 void init_ifp()
1178 {
1179         FILE *fp;
1180         struct ifnet *ifp, **ifa;
1181         char fname[32];
1182 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1183         (defined(OpenBSD) && (OpenBSD >= 199603))
1184         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
1185                 ifp->if_output = write_output;
1186                 sprintf(fname, "/tmp/%s", ifp->if_xname);
1187                 if ((fp = fopen(fname, "w")))
1188                         fclose(fp);
1189         }
1190 # else
1191
1192         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
1193                 ifp->if_output = write_output;
1194                 sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
1195                 if ((fp = fopen(fname, "w")))
1196                         fclose(fp);
1197         }
1198 # endif
1199 }
1200
1201
1202 void ipfr_fastroute(ip, fin, fdp)
1203 ip_t *ip;
1204 fr_info_t *fin;
1205 frdest_t *fdp;
1206 {
1207         struct ifnet *ifp = fdp->fd_ifp;
1208
1209         if (!ifp)
1210                 return; /* no routing table out here */
1211
1212         ip->ip_len = htons((u_short)ip->ip_len);
1213         ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
1214         ip->ip_sum = 0;
1215 #ifdef __sgi
1216         (*ifp->if_output)(ifp, (void *)ip, NULL);
1217 #else
1218         (*ifp->if_output)(ifp, (void *)ip, NULL, 0);
1219 #endif
1220 }
1221
1222
1223 int ipllog __P((void))
1224 {
1225         verbose("l");
1226         return 0;
1227 }
1228
1229
1230 int send_reset(ip, ifp)
1231 ip_t *ip;
1232 struct ifnet *ifp;
1233 {
1234         verbose("- TCP RST sent\n");
1235         return 0;
1236 }
1237
1238
1239 int icmp_error(ip, ifp)
1240 ip_t *ip;
1241 struct ifnet *ifp;
1242 {
1243         verbose("- TCP RST sent\n");
1244         return 0;
1245 }
1246 #endif /* _KERNEL */