]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / contrib / ipfilter / netinet / ip_fil_freebsd.c
1 /*      $FreeBSD$       */
2
3 /*
4  * Copyright (C) 1993-2003 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #if !defined(lint)
9 static const char sccsid[] = "@(#)ip_fil.c      2.41 6/5/96 (C) 1993-2000 Darren Reed";
10 static const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.50 2007/09/20 12:51:50 darrenr Exp $";
11 #endif
12
13 #if defined(KERNEL) || defined(_KERNEL)
14 # undef KERNEL
15 # undef _KERNEL
16 # define        KERNEL  1
17 # define        _KERNEL 1
18 #endif
19 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \
20     !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
21 # include "opt_inet6.h"
22 #endif
23 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \
24     !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
25 # include "opt_random_ip_id.h"
26 #endif
27 #include <sys/param.h>
28 #if defined(__FreeBSD__) && !defined(__FreeBSD_version)
29 # if defined(IPFILTER_LKM)
30 #  ifndef __FreeBSD_cc_version
31 #   include <osreldate.h>
32 #  else
33 #   if __FreeBSD_cc_version < 430000
34 #    include <osreldate.h>
35 #   endif
36 #  endif
37 # endif
38 #endif
39 #include <sys/errno.h>
40 #include <sys/types.h>
41 #include <sys/file.h>
42 #if __FreeBSD_version >= 220000
43 # include <sys/fcntl.h>
44 # include <sys/filio.h>
45 #else
46 # include <sys/ioctl.h>
47 #endif
48 #include <sys/time.h>
49 #include <sys/systm.h>
50 #if (__FreeBSD_version >= 300000)
51 # include <sys/dirent.h>
52 #else
53 # include <sys/dir.h>
54 #endif
55 #if !defined(__hpux)
56 # include <sys/mbuf.h>
57 #endif
58 #include <sys/protosw.h>
59 #include <sys/socket.h>
60 #if __FreeBSD_version >= 500043
61 # include <sys/selinfo.h>
62 #else
63 # include <sys/select.h>
64 #endif
65
66 #include <net/if.h>
67 #if __FreeBSD_version >= 300000
68 # include <net/if_var.h>
69 # if __FreeBSD_version >= 500043
70 #  include <net/netisr.h>
71 # endif
72 # if !defined(IPFILTER_LKM)
73 #  include "opt_ipfilter.h"
74 # endif
75 #endif
76 #include <net/route.h>
77 #include <netinet/in.h>
78 #include <netinet/in_var.h>
79 #include <netinet/in_systm.h>
80 #include <netinet/ip.h>
81 #include <netinet/ip_var.h>
82 #include <netinet/tcp.h>
83 #if defined(__osf__)
84 # include <netinet/tcp_timer.h>
85 #endif
86 #include <netinet/udp.h>
87 #include <netinet/tcpip.h>
88 #include <netinet/ip_icmp.h>
89 #ifndef _KERNEL
90 # include "netinet/ipf.h"
91 #endif
92 #include "netinet/ip_compat.h"
93 #ifdef USE_INET6
94 # include <netinet/icmp6.h>
95 #endif
96 #include "netinet/ip_fil.h"
97 #include "netinet/ip_nat.h"
98 #include "netinet/ip_frag.h"
99 #include "netinet/ip_state.h"
100 #include "netinet/ip_proxy.h"
101 #include "netinet/ip_auth.h"
102 #ifdef  IPFILTER_SYNC
103 #include "netinet/ip_sync.h"
104 #endif
105 #ifdef  IPFILTER_SCAN
106 #include "netinet/ip_scan.h"
107 #endif
108 #include "netinet/ip_pool.h"
109 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
110 # include <sys/malloc.h>
111 #endif
112 #include <sys/kernel.h>
113 #ifdef CSUM_DATA_VALID
114 #include <machine/in_cksum.h>
115 #endif
116 extern  int     ip_optcopy __P((struct ip *, struct ip *));
117
118 #if (__FreeBSD_version > 460000)
119 extern  int     path_mtu_discovery;
120 #endif
121
122 # ifdef IPFILTER_M_IPFILTER
123 MALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
124 # endif
125
126
127 #if !defined(__osf__)
128 extern  struct  protosw inetsw[];
129 #endif
130
131 static  int     (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **));
132 static  int     fr_send_ip __P((fr_info_t *, mb_t *, mb_t **));
133 # ifdef USE_MUTEXES
134 ipfmutex_t      ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert;
135 ipfmutex_t      ipf_nat_new, ipf_natio, ipf_timeoutlock;
136 ipfrwlock_t     ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache, ipf_tokens;
137 ipfrwlock_t     ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
138 # endif
139 int             ipf_locks_done = 0;
140
141 #if (__FreeBSD_version >= 300000)
142 struct callout_handle fr_slowtimer_ch;
143 #endif
144 struct  selinfo ipfselwait[IPL_LOGSIZE];
145
146 #if (__FreeBSD_version >= 500011)
147 # include <sys/conf.h>
148 # if defined(NETBSD_PF)
149 #  include <net/pfil.h>
150 #  include <netinet/ipprotosw.h>
151 /*
152  * We provide the fr_checkp name just to minimize changes later.
153  */
154 int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
155 # endif /* NETBSD_PF */
156 #endif /* __FreeBSD_version >= 500011 */
157
158
159 #if (__FreeBSD_version >= 502103)
160 static eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag;
161
162 static void ipf_ifevent(void *arg);
163
164 static void ipf_ifevent(arg)
165 void *arg;
166 {
167         frsync(NULL);
168 }
169 #endif
170
171
172 #if (__FreeBSD_version >= 501108) && defined(_KERNEL)
173
174 static int
175 fr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
176 {
177         struct ip *ip = mtod(*mp, struct ip *);
178         return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp);
179 }
180
181 # ifdef USE_INET6
182 #  include <netinet/ip6.h>
183
184 static int
185 fr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
186 {
187         return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr),
188             ifp, (dir == PFIL_OUT), mp));
189 }
190 # endif
191 #endif /* __FreeBSD_version >= 501108 */
192 #if     defined(IPFILTER_LKM)
193 int iplidentify(s)
194 char *s;
195 {
196         if (strcmp(s, "ipl") == 0)
197                 return 1;
198         return 0;
199 }
200 #endif /* IPFILTER_LKM */
201
202
203 int ipfattach()
204 {
205 #ifdef USE_SPL
206         int s;
207 #endif
208
209         SPL_NET(s);
210         if (fr_running > 0) {
211                 SPL_X(s);
212                 return EBUSY;
213         }
214
215         MUTEX_INIT(&ipf_rw, "ipf rw mutex");
216         MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex");
217         RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
218         RWLOCK_INIT(&ipf_tokens, "ipf token rwlock");
219         ipf_locks_done = 1;
220
221         if (fr_initialise() < 0) {
222                 SPL_X(s);
223                 return EIO;
224         }
225
226
227         if (fr_checkp != fr_check) {
228                 fr_savep = fr_checkp;
229                 fr_checkp = fr_check;
230         }
231
232         bzero((char *)ipfselwait, sizeof(ipfselwait));
233         bzero((char *)frcache, sizeof(frcache));
234         fr_running = 1;
235
236         if (fr_control_forwarding & 1)
237                 ipforwarding = 1;
238
239         SPL_X(s);
240 #if (__FreeBSD_version >= 300000)
241         fr_slowtimer_ch = timeout(fr_slowtimer, NULL,
242                                     (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
243 #else
244         timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
245 #endif
246         return 0;
247 }
248
249
250 /*
251  * Disable the filter by removing the hooks from the IP input/output
252  * stream.
253  */
254 int ipfdetach()
255 {
256 #ifdef USE_SPL
257         int s;
258 #endif
259         if (fr_control_forwarding & 2)
260                 ipforwarding = 0;
261
262         SPL_NET(s);
263
264 #if (__FreeBSD_version >= 300000)
265         if (fr_slowtimer_ch.callout != NULL)
266                 untimeout(fr_slowtimer, NULL, fr_slowtimer_ch);
267         bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch));
268 #else
269         untimeout(fr_slowtimer, NULL);
270 #endif /* FreeBSD */
271
272 #ifndef NETBSD_PF
273         if (fr_checkp != NULL)
274                 fr_checkp = fr_savep;
275         fr_savep = NULL;
276 #endif
277
278         fr_deinitialise();
279
280         fr_running = -2;
281
282         (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
283         (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
284
285         if (ipf_locks_done == 1) {
286                 MUTEX_DESTROY(&ipf_timeoutlock);
287                 MUTEX_DESTROY(&ipf_rw);
288                 RW_DESTROY(&ipf_ipidfrag);
289                 RW_DESTROY(&ipf_tokens);
290                 ipf_locks_done = 0;
291         }
292
293         SPL_X(s);
294
295         return 0;
296 }
297
298
299 /*
300  * Filter ioctl interface.
301  */
302 int iplioctl(dev, cmd, data, mode
303 # if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000))
304 , p)
305 #  if (__FreeBSD_version >= 500024)
306 struct thread *p;
307 #   if (__FreeBSD_version >= 500043)
308 #    define     p_uid   td_ucred->cr_ruid
309 #   else
310 #    define     p_uid   t_proc->p_cred->p_ruid
311 #   endif
312 #  else
313 struct proc *p;
314 #   define      p_uid   p_cred->p_ruid
315 #  endif /* __FreeBSD_version >= 500024 */
316 # else
317 )
318 # endif
319 #if defined(_KERNEL) && (__FreeBSD_version >= 502116)
320 struct cdev *dev;
321 #else
322 dev_t dev;
323 #endif
324 ioctlcmd_t cmd;
325 caddr_t data;
326 int mode;
327 {
328         int error = 0, unit = 0;
329         SPL_INT(s);
330
331 #if (BSD >= 199306) && defined(_KERNEL)
332         if ((securelevel >= 3) && (mode & FWRITE))
333                 return EPERM;
334 #endif
335
336         unit = GET_MINOR(dev);
337         if ((IPL_LOGMAX < unit) || (unit < 0))
338                 return ENXIO;
339
340         if (fr_running <= 0) {
341                 if (unit != IPL_LOGIPF)
342                         return EIO;
343                 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
344                     cmd != SIOCIPFSET && cmd != SIOCFRENB && 
345                     cmd != SIOCGETFS && cmd != SIOCGETFF)
346                         return EIO;
347         }
348
349         SPL_NET(s);
350         READ_ENTER(&ipf_global);
351
352         error = fr_ioctlswitch(unit, data, cmd, mode, p->p_uid, p);
353         if (error != -1) {
354                 RWLOCK_EXIT(&ipf_global);
355                 SPL_X(s);
356                 return error;
357         }
358
359         RWLOCK_EXIT(&ipf_global);
360         SPL_X(s);
361
362         return error;
363 }
364
365
366 #if 0
367 void fr_forgetifp(ifp)
368 void *ifp;
369 {
370         register frentry_t *f;
371
372         WRITE_ENTER(&ipf_mutex);
373         for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
374                 if (f->fr_ifa == ifp)
375                         f->fr_ifa = (void *)-1;
376         for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
377                 if (f->fr_ifa == ifp)
378                         f->fr_ifa = (void *)-1;
379         for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
380                 if (f->fr_ifa == ifp)
381                         f->fr_ifa = (void *)-1;
382         for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
383                 if (f->fr_ifa == ifp)
384                         f->fr_ifa = (void *)-1;
385 #ifdef USE_INET6
386         for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
387                 if (f->fr_ifa == ifp)
388                         f->fr_ifa = (void *)-1;
389         for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
390                 if (f->fr_ifa == ifp)
391                         f->fr_ifa = (void *)-1;
392         for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
393                 if (f->fr_ifa == ifp)
394                         f->fr_ifa = (void *)-1;
395         for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
396                 if (f->fr_ifa == ifp)
397                         f->fr_ifa = (void *)-1;
398 #endif
399         RWLOCK_EXIT(&ipf_mutex);
400         fr_natsync(ifp);
401 }
402 #endif
403
404
405 /*
406  * routines below for saving IP headers to buffer
407  */
408 int iplopen(dev, flags
409 #if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
410 , devtype, p)
411 int devtype;
412 # if (__FreeBSD_version >= 500024)
413 struct thread *p;
414 # else
415 struct proc *p;
416 # endif /* __FreeBSD_version >= 500024 */
417 #else
418 )
419 #endif
420 #if defined(_KERNEL) && (__FreeBSD_version >= 502116)
421 struct cdev *dev;
422 #else
423 dev_t dev;
424 #endif
425 int flags;
426 {
427         u_int min = GET_MINOR(dev);
428
429         if (IPL_LOGMAX < min)
430                 min = ENXIO;
431         else
432                 min = 0;
433         return min;
434 }
435
436
437 int iplclose(dev, flags
438 #if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
439 , devtype, p)
440 int devtype;
441 # if (__FreeBSD_version >= 500024)
442 struct thread *p;
443 # else
444 struct proc *p;
445 # endif /* __FreeBSD_version >= 500024 */
446 #else
447 )
448 #endif
449 #if defined(_KERNEL) && (__FreeBSD_version >= 502116)
450 struct cdev *dev;
451 #else
452 dev_t dev;
453 #endif
454 int flags;
455 {
456         u_int   min = GET_MINOR(dev);
457
458         if (IPL_LOGMAX < min)
459                 min = ENXIO;
460         else
461                 min = 0;
462         return min;
463 }
464
465 /*
466  * iplread/ipllog
467  * both of these must operate with at least splnet() lest they be
468  * called during packet processing and cause an inconsistancy to appear in
469  * the filter lists.
470  */
471 #if (BSD >= 199306)
472 int iplread(dev, uio, ioflag)
473 int ioflag;
474 #else
475 int iplread(dev, uio)
476 #endif
477 #if defined(_KERNEL) && (__FreeBSD_version >= 502116)
478 struct cdev *dev;
479 #else
480 dev_t dev;
481 #endif
482 register struct uio *uio;
483 {
484         u_int   xmin = GET_MINOR(dev);
485
486         if (fr_running < 1)
487                 return EIO;
488
489         if (xmin < 0)
490                 return ENXIO;
491
492 # ifdef IPFILTER_SYNC
493         if (xmin == IPL_LOGSYNC)
494                 return ipfsync_read(uio);
495 # endif
496
497 #ifdef IPFILTER_LOG
498         return ipflog_read(xmin, uio);
499 #else
500         return ENXIO;
501 #endif
502 }
503
504
505 /*
506  * iplwrite
507  * both of these must operate with at least splnet() lest they be
508  * called during packet processing and cause an inconsistancy to appear in
509  * the filter lists.
510  */
511 #if (BSD >= 199306)
512 int iplwrite(dev, uio, ioflag)
513 int ioflag;
514 #else
515 int iplwrite(dev, uio)
516 #endif
517 #if defined(_KERNEL) && (__FreeBSD_version >= 502116)
518 struct cdev *dev;
519 #else
520 dev_t dev;
521 #endif
522 register struct uio *uio;
523 {
524
525         if (fr_running < 1)
526                 return EIO;
527
528 #ifdef  IPFILTER_SYNC
529         if (GET_MINOR(dev) == IPL_LOGSYNC)
530                 return ipfsync_write(uio);
531 #endif
532         return ENXIO;
533 }
534
535
536 /*
537  * fr_send_reset - this could conceivably be a call to tcp_respond(), but that
538  * requires a large amount of setting up and isn't any more efficient.
539  */
540 int fr_send_reset(fin)
541 fr_info_t *fin;
542 {
543         struct tcphdr *tcp, *tcp2;
544         int tlen = 0, hlen;
545         struct mbuf *m;
546 #ifdef USE_INET6
547         ip6_t *ip6;
548 #endif
549         ip_t *ip;
550
551         tcp = fin->fin_dp;
552         if (tcp->th_flags & TH_RST)
553                 return -1;              /* feedback loop */
554
555         if (fr_checkl4sum(fin) == -1)
556                 return -1;
557
558         tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
559                         ((tcp->th_flags & TH_SYN) ? 1 : 0) +
560                         ((tcp->th_flags & TH_FIN) ? 1 : 0);
561
562 #ifdef USE_INET6
563         hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
564 #else
565         hlen = sizeof(ip_t);
566 #endif
567 #ifdef MGETHDR
568         MGETHDR(m, M_DONTWAIT, MT_HEADER);
569 #else
570         MGET(m, M_DONTWAIT, MT_HEADER);
571 #endif
572         if (m == NULL)
573                 return -1;
574         if (sizeof(*tcp2) + hlen > MLEN) {
575                 MCLGET(m, M_DONTWAIT);
576                 if ((m->m_flags & M_EXT) == 0) {
577                         FREE_MB_T(m);
578                         return -1;
579                 }
580         }
581
582         m->m_len = sizeof(*tcp2) + hlen;
583 #if (BSD >= 199103)
584         m->m_data += max_linkhdr;
585         m->m_pkthdr.len = m->m_len;
586         m->m_pkthdr.rcvif = (struct ifnet *)0;
587 #endif
588         ip = mtod(m, struct ip *);
589         bzero((char *)ip, hlen);
590 #ifdef USE_INET6
591         ip6 = (ip6_t *)ip;
592 #endif
593         tcp2 = (struct tcphdr *)((char *)ip + hlen);
594         tcp2->th_sport = tcp->th_dport;
595         tcp2->th_dport = tcp->th_sport;
596
597         if (tcp->th_flags & TH_ACK) {
598                 tcp2->th_seq = tcp->th_ack;
599                 tcp2->th_flags = TH_RST;
600                 tcp2->th_ack = 0;
601         } else {
602                 tcp2->th_seq = 0;
603                 tcp2->th_ack = ntohl(tcp->th_seq);
604                 tcp2->th_ack += tlen;
605                 tcp2->th_ack = htonl(tcp2->th_ack);
606                 tcp2->th_flags = TH_RST|TH_ACK;
607         }
608         TCP_X2_A(tcp2, 0);
609         TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
610         tcp2->th_win = tcp->th_win;
611         tcp2->th_sum = 0;
612         tcp2->th_urp = 0;
613
614 #ifdef USE_INET6
615         if (fin->fin_v == 6) {
616                 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
617                 ip6->ip6_plen = htons(sizeof(struct tcphdr));
618                 ip6->ip6_nxt = IPPROTO_TCP;
619                 ip6->ip6_hlim = 0;
620                 ip6->ip6_src = fin->fin_dst6;
621                 ip6->ip6_dst = fin->fin_src6;
622                 tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
623                                          sizeof(*ip6), sizeof(*tcp2));
624                 return fr_send_ip(fin, m, &m);
625         }
626 #endif
627         ip->ip_p = IPPROTO_TCP;
628         ip->ip_len = htons(sizeof(struct tcphdr));
629         ip->ip_src.s_addr = fin->fin_daddr;
630         ip->ip_dst.s_addr = fin->fin_saddr;
631         tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
632         ip->ip_len = hlen + sizeof(*tcp2);
633         return fr_send_ip(fin, m, &m);
634 }
635
636
637 static int fr_send_ip(fin, m, mpp)
638 fr_info_t *fin;
639 mb_t *m, **mpp;
640 {
641         fr_info_t fnew;
642         ip_t *ip, *oip;
643         int hlen;
644
645         ip = mtod(m, ip_t *);
646         bzero((char *)&fnew, sizeof(fnew));
647
648         IP_V_A(ip, fin->fin_v);
649         switch (fin->fin_v)
650         {
651         case 4 :
652                 fnew.fin_v = 4;
653                 oip = fin->fin_ip;
654                 IP_HL_A(ip, sizeof(*oip) >> 2);
655                 ip->ip_tos = oip->ip_tos;
656                 ip->ip_id = fin->fin_ip->ip_id;
657 #if (__FreeBSD_version > 460000)
658                 ip->ip_off = path_mtu_discovery ? IP_DF : 0;
659 #else
660                 ip->ip_off = 0;
661 #endif
662                 ip->ip_ttl = ip_defttl;
663                 ip->ip_sum = 0;
664                 hlen = sizeof(*oip);
665                 break;
666 #ifdef USE_INET6
667         case 6 :
668         {
669                 ip6_t *ip6 = (ip6_t *)ip;
670
671                 ip6->ip6_vfc = 0x60;
672                 ip6->ip6_hlim = IPDEFTTL;
673
674                 fnew.fin_v = 6;
675                 hlen = sizeof(*ip6);
676                 break;
677         }
678 #endif
679         default :
680                 return EINVAL;
681         }
682 #ifdef IPSEC
683         m->m_pkthdr.rcvif = NULL;
684 #endif
685
686         fnew.fin_ifp = fin->fin_ifp;
687         fnew.fin_flx = FI_NOCKSUM;
688         fnew.fin_m = m;
689         fnew.fin_ip = ip;
690         fnew.fin_mp = mpp;
691         fnew.fin_hlen = hlen;
692         fnew.fin_dp = (char *)ip + hlen;
693         (void) fr_makefrip(hlen, ip, &fnew);
694
695         return fr_fastroute(m, mpp, &fnew, NULL);
696 }
697
698
699 int fr_send_icmp_err(type, fin, dst)
700 int type;
701 fr_info_t *fin;
702 int dst;
703 {
704         int err, hlen, xtra, iclen, ohlen, avail, code;
705         struct in_addr dst4;
706         struct icmp *icmp;
707         struct mbuf *m;
708         void *ifp;
709 #ifdef USE_INET6
710         ip6_t *ip6;
711         struct in6_addr dst6;
712 #endif
713         ip_t *ip, *ip2;
714
715         if ((type < 0) || (type >= ICMP_MAXTYPE))
716                 return -1;
717
718         code = fin->fin_icode;
719 #ifdef USE_INET6
720         if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
721                 return -1;
722 #endif
723
724         if (fr_checkl4sum(fin) == -1)
725                 return -1;
726 #ifdef MGETHDR
727         MGETHDR(m, M_DONTWAIT, MT_HEADER);
728 #else
729         MGET(m, M_DONTWAIT, MT_HEADER);
730 #endif
731         if (m == NULL)
732                 return -1;
733         avail = MHLEN;
734
735         xtra = 0;
736         hlen = 0;
737         ohlen = 0;
738         ifp = fin->fin_ifp;
739         if (fin->fin_v == 4) {
740                 if ((fin->fin_p == IPPROTO_ICMP) &&
741                     !(fin->fin_flx & FI_SHORT))
742                         switch (ntohs(fin->fin_data[0]) >> 8)
743                         {
744                         case ICMP_ECHO :
745                         case ICMP_TSTAMP :
746                         case ICMP_IREQ :
747                         case ICMP_MASKREQ :
748                                 break;
749                         default :
750                                 FREE_MB_T(m);
751                                 return 0;
752                         }
753
754                 if (dst == 0) {
755                         if (fr_ifpaddr(4, FRI_NORMAL, ifp,
756                                        &dst4, NULL) == -1) {
757                                 FREE_MB_T(m);
758                                 return -1;
759                         }
760                 } else
761                         dst4.s_addr = fin->fin_daddr;
762
763                 hlen = sizeof(ip_t);
764                 ohlen = fin->fin_hlen;
765                 if (fin->fin_hlen < fin->fin_plen)
766                         xtra = MIN(fin->fin_dlen, 8);
767                 else
768                         xtra = 0;
769         }
770
771 #ifdef USE_INET6
772         else if (fin->fin_v == 6) {
773                 hlen = sizeof(ip6_t);
774                 ohlen = sizeof(ip6_t);
775                 type = icmptoicmp6types[type];
776                 if (type == ICMP6_DST_UNREACH)
777                         code = icmptoicmp6unreach[code];
778
779                 if (hlen + sizeof(*icmp) + max_linkhdr +
780                     fin->fin_plen > avail) {
781                         MCLGET(m, M_DONTWAIT);
782                         if ((m->m_flags & M_EXT) == 0) {
783                                 FREE_MB_T(m);
784                                 return -1;
785                         }
786                         avail = MCLBYTES;
787                 }
788                 xtra = MIN(fin->fin_plen,
789                            avail - hlen - sizeof(*icmp) - max_linkhdr);
790                 if (dst == 0) {
791                         if (fr_ifpaddr(6, FRI_NORMAL, ifp,
792                                        (struct in_addr *)&dst6, NULL) == -1) {
793                                 FREE_MB_T(m);
794                                 return -1;
795                         }
796                 } else
797                         dst6 = fin->fin_dst6;
798         }
799 #endif
800         else {
801                 FREE_MB_T(m);
802                 return -1;
803         }
804
805         iclen = hlen + sizeof(*icmp);
806         avail -= (max_linkhdr + iclen);
807         if (avail < 0) {
808                 FREE_MB_T(m);
809                 return -1;
810         }
811         if (xtra > avail)
812                 xtra = avail;
813         iclen += xtra;
814         m->m_data += max_linkhdr;
815         m->m_pkthdr.rcvif = (struct ifnet *)0;
816         m->m_pkthdr.len = iclen;
817         m->m_len = iclen;
818         ip = mtod(m, ip_t *);
819         icmp = (struct icmp *)((char *)ip + hlen);
820         ip2 = (ip_t *)&icmp->icmp_ip;
821
822         icmp->icmp_type = type;
823         icmp->icmp_code = fin->fin_icode;
824         icmp->icmp_cksum = 0;
825 #ifdef icmp_nextmtu
826         if (type == ICMP_UNREACH &&
827             fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
828                 icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu);
829 #endif
830
831         bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
832
833 #ifdef USE_INET6
834         ip6 = (ip6_t *)ip;
835         if (fin->fin_v == 6) {
836                 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
837                 ip6->ip6_plen = htons(iclen - hlen);
838                 ip6->ip6_nxt = IPPROTO_ICMPV6;
839                 ip6->ip6_hlim = 0;
840                 ip6->ip6_src = dst6;
841                 ip6->ip6_dst = fin->fin_src6;
842                 if (xtra > 0)
843                         bcopy((char *)fin->fin_ip + ohlen,
844                               (char *)&icmp->icmp_ip + ohlen, xtra);
845                 icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
846                                              sizeof(*ip6), iclen - hlen);
847         } else
848 #endif
849         {
850                 ip2->ip_len = htons(ip2->ip_len);
851                 ip2->ip_off = htons(ip2->ip_off);
852                 ip->ip_p = IPPROTO_ICMP;
853                 ip->ip_src.s_addr = dst4.s_addr;
854                 ip->ip_dst.s_addr = fin->fin_saddr;
855
856                 if (xtra > 0)
857                         bcopy((char *)fin->fin_ip + ohlen,
858                               (char *)&icmp->icmp_ip + ohlen, xtra);
859                 icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
860                                              sizeof(*icmp) + 8);
861                 ip->ip_len = iclen;
862                 ip->ip_p = IPPROTO_ICMP;
863         }
864         err = fr_send_ip(fin, m, &m);
865         return err;
866 }
867
868
869 #if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000)
870 # if    (BSD < 199306)
871 int iplinit __P((void));
872
873 int
874 # else
875 void iplinit __P((void));
876
877 void
878 # endif
879 iplinit()
880 {
881         if (ipfattach() != 0)
882                 printf("IP Filter failed to attach\n");
883         ip_init();
884 }
885 #endif /* __FreeBSD_version < 300000 */
886
887
888 int fr_fastroute(m0, mpp, fin, fdp)
889 mb_t *m0, **mpp;
890 fr_info_t *fin;
891 frdest_t *fdp;
892 {
893         register struct ip *ip, *mhip;
894         register struct mbuf *m = m0;
895         register struct route *ro;
896         int len, off, error = 0, hlen, code;
897         struct ifnet *ifp, *sifp;
898         struct sockaddr_in *dst;
899         struct route iproute;
900         u_short ip_off;
901         frentry_t *fr;
902
903         ro = NULL;
904
905 #ifdef M_WRITABLE
906         /*
907         * HOT FIX/KLUDGE:
908         *
909         * If the mbuf we're about to send is not writable (because of
910         * a cluster reference, for example) we'll need to make a copy
911         * of it since this routine modifies the contents.
912         *
913         * If you have non-crappy network hardware that can transmit data
914         * from the mbuf, rather than making a copy, this is gonna be a
915         * problem.
916         */
917         if (M_WRITABLE(m) == 0) {
918                 m0 = m_dup(m, M_DONTWAIT);
919                 if (m0 != 0) {
920                         FREE_MB_T(m);
921                         m = m0;
922                         *mpp = m;
923                 } else {
924                         error = ENOBUFS;
925                         FREE_MB_T(m);
926                         goto done;
927                 }
928         }
929 #endif
930
931 #ifdef USE_INET6
932         if (fin->fin_v == 6) {
933                 /*
934                  * currently "to <if>" and "to <if>:ip#" are not supported
935                  * for IPv6
936                  */
937 #if  (__FreeBSD_version >= 490000)
938                 return ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
939 #else
940                 return ip6_output(m0, NULL, NULL, 0, NULL, NULL);
941 #endif
942         }
943 #endif
944
945         hlen = fin->fin_hlen;
946         ip = mtod(m0, struct ip *);
947
948         /*
949          * Route packet.
950          */
951         ro = &iproute;
952         bzero((caddr_t)ro, sizeof (*ro));
953         dst = (struct sockaddr_in *)&ro->ro_dst;
954         dst->sin_family = AF_INET;
955         dst->sin_addr = ip->ip_dst;
956
957         fr = fin->fin_fr;
958         if (fdp != NULL)
959                 ifp = fdp->fd_ifp;
960         else
961                 ifp = fin->fin_ifp;
962
963         if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) {
964                 error = -2;
965                 goto bad;
966         }
967
968         if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
969                 dst->sin_addr = fdp->fd_ip;
970
971         dst->sin_len = sizeof(*dst);
972         in_rtalloc(ro, 0);
973
974         if ((ifp == NULL) && (ro->ro_rt != NULL))
975                 ifp = ro->ro_rt->rt_ifp;
976
977         if ((ro->ro_rt == NULL) || (ifp == NULL)) {
978                 if (in_localaddr(ip->ip_dst))
979                         error = EHOSTUNREACH;
980                 else
981                         error = ENETUNREACH;
982                 goto bad;
983         }
984         if (ro->ro_rt->rt_flags & RTF_GATEWAY)
985                 dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
986         if (ro->ro_rt)
987                 ro->ro_rt->rt_use++;
988
989         /*
990          * For input packets which are being "fastrouted", they won't
991          * go back through output filtering and miss their chance to get
992          * NAT'd and counted.  Duplicated packets aren't considered to be
993          * part of the normal packet stream, so do not NAT them or pass
994          * them through stateful checking, etc.
995          */
996         if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) {
997                 sifp = fin->fin_ifp;
998                 fin->fin_ifp = ifp;
999                 fin->fin_out = 1;
1000                 (void) fr_acctpkt(fin, NULL);
1001                 fin->fin_fr = NULL;
1002                 if (!fr || !(fr->fr_flags & FR_RETMASK)) {
1003                         u_32_t pass;
1004
1005                         if (fr_checkstate(fin, &pass) != NULL)
1006                                 fr_statederef((ipstate_t **)&fin->fin_state);
1007                 }
1008
1009                 switch (fr_checknatout(fin, NULL))
1010                 {
1011                 case 0 :
1012                         break;
1013                 case 1 :
1014                         fr_natderef((nat_t **)&fin->fin_nat);
1015                         ip->ip_sum = 0;
1016                         break;
1017                 case -1 :
1018                         error = -1;
1019                         goto done;
1020                         break;
1021                 }
1022
1023                 fin->fin_ifp = sifp;
1024                 fin->fin_out = 0;
1025         } else
1026                 ip->ip_sum = 0;
1027         /*
1028          * If small enough for interface, can just send directly.
1029          */
1030         if (ip->ip_len <= ifp->if_mtu) {
1031                 ip->ip_len = htons(ip->ip_len);
1032                 ip->ip_off = htons(ip->ip_off);
1033
1034                 if (!ip->ip_sum)
1035                         ip->ip_sum = in_cksum(m, hlen);
1036                 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
1037                                           ro->ro_rt);
1038                 goto done;
1039         }
1040         /*
1041          * Too large for interface; fragment if possible.
1042          * Must be able to put at least 8 bytes per fragment.
1043          */
1044         ip_off = ntohs(ip->ip_off);
1045         if (ip_off & IP_DF) {
1046                 error = EMSGSIZE;
1047                 goto bad;
1048         }
1049         len = (ifp->if_mtu - hlen) &~ 7;
1050         if (len < 8) {
1051                 error = EMSGSIZE;
1052                 goto bad;
1053         }
1054
1055     {
1056         int mhlen, firstlen = len;
1057         struct mbuf **mnext = &m->m_act;
1058
1059         /*
1060          * Loop through length of segment after first fragment,
1061          * make new header and copy data of each part and link onto chain.
1062          */
1063         m0 = m;
1064         mhlen = sizeof (struct ip);
1065         for (off = hlen + len; off < ip->ip_len; off += len) {
1066 #ifdef MGETHDR
1067                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
1068 #else
1069                 MGET(m, M_DONTWAIT, MT_HEADER);
1070 #endif
1071                 if (m == 0) {
1072                         m = m0;
1073                         error = ENOBUFS;
1074                         goto bad;
1075                 }
1076                 m->m_data += max_linkhdr;
1077                 mhip = mtod(m, struct ip *);
1078                 bcopy((char *)ip, (char *)mhip, sizeof(*ip));
1079                 if (hlen > sizeof (struct ip)) {
1080                         mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
1081                         IP_HL_A(mhip, mhlen >> 2);
1082                 }
1083                 m->m_len = mhlen;
1084                 mhip->ip_off = ((off - hlen) >> 3) + ip_off;
1085                 if (off + len >= ip->ip_len)
1086                         len = ip->ip_len - off;
1087                 else
1088                         mhip->ip_off |= IP_MF;
1089                 mhip->ip_len = htons((u_short)(len + mhlen));
1090                 *mnext = m;
1091                 m->m_next = m_copy(m0, off, len);
1092                 if (m->m_next == 0) {
1093                         error = ENOBUFS;        /* ??? */
1094                         goto sendorfree;
1095                 }
1096                 m->m_pkthdr.len = mhlen + len;
1097                 m->m_pkthdr.rcvif = NULL;
1098                 mhip->ip_off = htons((u_short)mhip->ip_off);
1099                 mhip->ip_sum = 0;
1100                 mhip->ip_sum = in_cksum(m, mhlen);
1101                 mnext = &m->m_act;
1102         }
1103         /*
1104          * Update first fragment by trimming what's been copied out
1105          * and updating header, then send each fragment (in order).
1106          */
1107         m_adj(m0, hlen + firstlen - ip->ip_len);
1108         ip->ip_len = htons((u_short)(hlen + firstlen));
1109         ip->ip_off = htons((u_short)IP_MF);
1110         ip->ip_sum = 0;
1111         ip->ip_sum = in_cksum(m0, hlen);
1112 sendorfree:
1113         for (m = m0; m; m = m0) {
1114                 m0 = m->m_act;
1115                 m->m_act = 0;
1116                 if (error == 0)
1117                         error = (*ifp->if_output)(ifp, m,
1118                             (struct sockaddr *)dst, ro->ro_rt);
1119                 else
1120                         FREE_MB_T(m);
1121         }
1122     }   
1123 done:
1124         if (!error)
1125                 fr_frouteok[0]++;
1126         else
1127                 fr_frouteok[1]++;
1128
1129         if ((ro != NULL) && (ro->ro_rt != NULL)) {
1130                 RTFREE(ro->ro_rt);
1131         }
1132         *mpp = NULL;
1133         return 0;
1134 bad:
1135         if (error == EMSGSIZE) {
1136                 sifp = fin->fin_ifp;
1137                 code = fin->fin_icode;
1138                 fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
1139                 fin->fin_ifp = ifp;
1140                 (void) fr_send_icmp_err(ICMP_UNREACH, fin, 1);
1141                 fin->fin_ifp = sifp;
1142                 fin->fin_icode = code;
1143         }
1144         FREE_MB_T(m);
1145         goto done;
1146 }
1147
1148
1149 int fr_verifysrc(fin)
1150 fr_info_t *fin;
1151 {
1152         struct sockaddr_in *dst;
1153         struct route iproute;
1154
1155         bzero((char *)&iproute, sizeof(iproute));
1156         dst = (struct sockaddr_in *)&iproute.ro_dst;
1157         dst->sin_len = sizeof(*dst);
1158         dst->sin_family = AF_INET;
1159         dst->sin_addr = fin->fin_src;
1160         in_rtalloc(&iproute, 0);
1161         if (iproute.ro_rt == NULL)
1162                 return 0;
1163         return (fin->fin_ifp == iproute.ro_rt->rt_ifp);
1164 }
1165
1166
1167 /*
1168  * return the first IP Address associated with an interface
1169  */
1170 int fr_ifpaddr(v, atype, ifptr, inp, inpmask)
1171 int v, atype;
1172 void *ifptr;
1173 struct in_addr *inp, *inpmask;
1174 {
1175 #ifdef USE_INET6
1176         struct in6_addr *inp6 = NULL;
1177 #endif
1178         struct sockaddr *sock, *mask;
1179         struct sockaddr_in *sin;
1180         struct ifaddr *ifa;
1181         struct ifnet *ifp;
1182
1183         if ((ifptr == NULL) || (ifptr == (void *)-1))
1184                 return -1;
1185
1186         sin = NULL;
1187         ifp = ifptr;
1188
1189         if (v == 4)
1190                 inp->s_addr = 0;
1191 #ifdef USE_INET6
1192         else if (v == 6)
1193                 bzero((char *)inp, sizeof(struct in6_addr));
1194 #endif
1195 #if  (__FreeBSD_version >= 300000)
1196         ifa = TAILQ_FIRST(&ifp->if_addrhead);
1197 #else
1198         ifa = ifp->if_addrlist;
1199 #endif /* __FreeBSD_version >= 300000 */
1200
1201         sock = ifa->ifa_addr;
1202         while (sock != NULL && ifa != NULL) {
1203                 sin = (struct sockaddr_in *)sock;
1204                 if ((v == 4) && (sin->sin_family == AF_INET))
1205                         break;
1206 #ifdef USE_INET6
1207                 if ((v == 6) && (sin->sin_family == AF_INET6)) {
1208                         inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
1209                         if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
1210                             !IN6_IS_ADDR_LOOPBACK(inp6))
1211                                 break;
1212                 }
1213 #endif
1214 #if (__FreeBSD_version >= 300000)
1215                 ifa = TAILQ_NEXT(ifa, ifa_link);
1216 #else
1217                 ifa = ifa->ifa_next;
1218 #endif /* __FreeBSD_version >= 300000 */
1219                 if (ifa != NULL)
1220                         sock = ifa->ifa_addr;
1221         }
1222
1223         if (ifa == NULL || sin == NULL)
1224                 return -1;
1225
1226         mask = ifa->ifa_netmask;
1227         if (atype == FRI_BROADCAST)
1228                 sock = ifa->ifa_broadaddr;
1229         else if (atype == FRI_PEERADDR)
1230                 sock = ifa->ifa_dstaddr;
1231
1232         if (sock == NULL)
1233                 return -1;
1234
1235 #ifdef USE_INET6
1236         if (v == 6) {
1237                 return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
1238                                         (struct sockaddr_in6 *)mask,
1239                                         inp, inpmask);
1240         }
1241 #endif
1242         return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
1243                                 (struct sockaddr_in *)mask, inp, inpmask);
1244 }
1245
1246
1247 u_32_t fr_newisn(fin)
1248 fr_info_t *fin;
1249 {
1250         u_32_t newiss;
1251 #if  (__FreeBSD_version >= 400000)
1252         newiss = arc4random();
1253 #else
1254         static iss_seq_off = 0;
1255         u_char hash[16];
1256         MD5_CTX ctx;
1257
1258         /*
1259          * Compute the base value of the ISS.  It is a hash
1260          * of (saddr, sport, daddr, dport, secret).
1261          */
1262         MD5Init(&ctx);
1263
1264         MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
1265                   sizeof(fin->fin_fi.fi_src));
1266         MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
1267                   sizeof(fin->fin_fi.fi_dst));
1268         MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
1269
1270         MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret));
1271
1272         MD5Final(hash, &ctx);
1273
1274         memcpy(&newiss, hash, sizeof(newiss));
1275
1276         /*
1277          * Now increment our "timer", and add it in to
1278          * the computed value.
1279          *
1280          * XXX Use `addin'?
1281          * XXX TCP_ISSINCR too large to use?
1282          */
1283         iss_seq_off += 0x00010000;
1284         newiss += iss_seq_off;
1285 #endif
1286         return newiss;
1287 }
1288
1289
1290 /* ------------------------------------------------------------------------ */
1291 /* Function:    fr_nextipid                                                 */
1292 /* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
1293 /* Parameters:  fin(I) - pointer to packet information                      */
1294 /*                                                                          */
1295 /* Returns the next IPv4 ID to use for this packet.                         */
1296 /* ------------------------------------------------------------------------ */
1297 u_short fr_nextipid(fin)
1298 fr_info_t *fin;
1299 {
1300 #ifndef RANDOM_IP_ID
1301         static u_short ipid = 0;
1302         u_short id;
1303
1304         MUTEX_ENTER(&ipf_rw);
1305         id = ipid++;
1306         MUTEX_EXIT(&ipf_rw);
1307 #else
1308         u_short id;
1309
1310         id = ip_randomid();
1311 #endif
1312
1313         return id;
1314 }
1315
1316
1317 INLINE void fr_checkv4sum(fin)
1318 fr_info_t *fin;
1319 {
1320 #ifdef CSUM_DATA_VALID
1321         int manual = 0;
1322         u_short sum;
1323         ip_t *ip;
1324         mb_t *m;
1325
1326         if ((fin->fin_flx & FI_NOCKSUM) != 0)
1327                 return;
1328
1329         if (fin->fin_cksum != 0)
1330                 return;
1331
1332         m = fin->fin_m;
1333         if (m == NULL) {
1334                 manual = 1;
1335                 goto skipauto;
1336         }
1337         ip = fin->fin_ip;
1338
1339         if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
1340                 if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
1341                         sum = m->m_pkthdr.csum_data;
1342                 else
1343                         sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
1344                                         htonl(m->m_pkthdr.csum_data +
1345                                         fin->fin_ip->ip_len + fin->fin_p));
1346                 sum ^= 0xffff;
1347                 if (sum != 0) {
1348                         fin->fin_flx |= FI_BAD;
1349                         fin->fin_cksum = -1;
1350                 } else {
1351                         fin->fin_cksum = 1;
1352                 }
1353         } else
1354                 manual = 1;
1355 skipauto:
1356 # ifdef IPFILTER_CKSUM
1357         if (manual != 0)
1358                 if (fr_checkl4sum(fin) == -1)
1359                         fin->fin_flx |= FI_BAD;
1360 # else
1361         ;
1362 # endif
1363 #else
1364 # ifdef IPFILTER_CKSUM
1365         if (fr_checkl4sum(fin) == -1)
1366                 fin->fin_flx |= FI_BAD;
1367 # endif
1368 #endif
1369 }
1370
1371
1372 #ifdef USE_INET6
1373 INLINE void fr_checkv6sum(fin)
1374 fr_info_t *fin;
1375 {
1376 # ifdef IPFILTER_CKSUM
1377         if (fr_checkl4sum(fin) == -1)
1378                 fin->fin_flx |= FI_BAD;
1379 # endif
1380 }
1381 #endif /* USE_INET6 */
1382
1383
1384 size_t mbufchainlen(m0)
1385 struct mbuf *m0;
1386 {
1387         size_t len;
1388
1389         if ((m0->m_flags & M_PKTHDR) != 0) {
1390                 len = m0->m_pkthdr.len;
1391         } else {
1392                 struct mbuf *m;
1393
1394                 for (m = m0, len = 0; m != NULL; m = m->m_next)
1395                         len += m->m_len;
1396         }
1397         return len;
1398 }
1399
1400
1401 /* ------------------------------------------------------------------------ */
1402 /* Function:    fr_pullup                                                   */
1403 /* Returns:     NULL == pullup failed, else pointer to protocol header      */
1404 /* Parameters:  m(I)   - pointer to buffer where data packet starts         */
1405 /*              fin(I) - pointer to packet information                      */
1406 /*              len(I) - number of bytes to pullup                          */
1407 /*                                                                          */
1408 /* Attempt to move at least len bytes (from the start of the buffer) into a */
1409 /* single buffer for ease of access.  Operating system native functions are */
1410 /* used to manage buffers - if necessary.  If the entire packet ends up in  */
1411 /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has  */
1412 /* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
1413 /* and ONLY if the pullup succeeds.                                         */
1414 /*                                                                          */
1415 /* We assume that 'min' is a pointer to a buffer that is part of the chain  */
1416 /* of buffers that starts at *fin->fin_mp.                                  */
1417 /* ------------------------------------------------------------------------ */
1418 void *fr_pullup(min, fin, len)
1419 mb_t *min;
1420 fr_info_t *fin;
1421 int len;
1422 {
1423         int out = fin->fin_out, dpoff, ipoff;
1424         mb_t *m = min;
1425         char *ip;
1426
1427         if (m == NULL)
1428                 return NULL;
1429
1430         ip = (char *)fin->fin_ip;
1431         if ((fin->fin_flx & FI_COALESCE) != 0)
1432                 return ip;
1433
1434         ipoff = fin->fin_ipoff;
1435         if (fin->fin_dp != NULL)
1436                 dpoff = (char *)fin->fin_dp - (char *)ip;
1437         else
1438                 dpoff = 0;
1439
1440         if (M_LEN(m) < len) {
1441 #ifdef MHLEN
1442                 /*
1443                  * Assume that M_PKTHDR is set and just work with what is left
1444                  * rather than check..
1445                  * Should not make any real difference, anyway.
1446                  */
1447                 if (len > MHLEN)
1448 #else
1449                 if (len > MLEN)
1450 #endif
1451                 {
1452 #ifdef HAVE_M_PULLDOWN
1453                         if (m_pulldown(m, 0, len, NULL) == NULL)
1454                                 m = NULL;
1455 #else
1456                         FREE_MB_T(*fin->fin_mp);
1457                         m = NULL;
1458 #endif
1459                 } else
1460                 {
1461                         m = m_pullup(m, len);
1462                 }
1463                 *fin->fin_mp = m;
1464                 if (m == NULL) {
1465                         fin->fin_m = NULL;
1466                         ATOMIC_INCL(frstats[out].fr_pull[1]);
1467                         return NULL;
1468                 }
1469
1470                 while (M_LEN(m) == 0) {
1471                         m = m->m_next;
1472                 }
1473                 fin->fin_m = m;
1474                 ip = MTOD(m, char *) + ipoff;
1475         }
1476
1477         ATOMIC_INCL(frstats[out].fr_pull[0]);
1478         fin->fin_ip = (ip_t *)ip;
1479         if (fin->fin_dp != NULL)
1480                 fin->fin_dp = (char *)fin->fin_ip + dpoff;
1481
1482         if (len == fin->fin_plen)
1483                 fin->fin_flx |= FI_COALESCE;
1484         return ip;
1485 }
1486
1487
1488 int ipf_inject(fin, m)
1489 fr_info_t *fin;
1490 mb_t *m;
1491 {
1492         int error = 0;
1493
1494         if (fin->fin_out == 0) {
1495 #if (__FreeBSD_version >= 501000)
1496                 netisr_dispatch(NETISR_IP, m);
1497 #else
1498                 struct ifqueue *ifq;
1499
1500                 ifq = &ipintrq;
1501
1502 # ifdef _IF_QFULL
1503                 if (_IF_QFULL(ifq))
1504 # else
1505                 if (IF_QFULL(ifq))
1506 # endif
1507                 {
1508 # ifdef _IF_DROP
1509                         _IF_DROP(ifq);
1510 # else
1511                         IF_DROP(ifq);
1512 # endif
1513                         FREE_MB_T(m);
1514                         error = ENOBUFS;
1515                 } else {
1516                         IF_ENQUEUE(ifq, m);
1517                 }
1518 #endif
1519         } else {
1520                 fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len);
1521                 fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off);
1522 #if (__FreeBSD_version >= 470102)
1523                 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
1524 #else
1525                 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
1526 #endif
1527         }
1528
1529         return error;
1530 }
1531
1532 int ipf_pfil_unhook(void) {
1533 #if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1534 # if __FreeBSD_version >= 501108
1535         struct pfil_head *ph_inet;
1536 #  ifdef USE_INET6
1537         struct pfil_head *ph_inet6;
1538 #  endif
1539 # endif
1540 #endif
1541
1542 #ifdef NETBSD_PF
1543 # if (__FreeBSD_version >= 500011)
1544 #  if (__FreeBSD_version >= 501108)
1545         ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1546         if (ph_inet != NULL)
1547                 pfil_remove_hook((void *)fr_check_wrapper, NULL,
1548                     PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1549 #  else
1550         pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1551             &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
1552 #  endif
1553 # else
1554         pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK);
1555 # endif
1556 # ifdef USE_INET6
1557 #  if (__FreeBSD_version >= 501108)
1558         ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1559         if (ph_inet6 != NULL)
1560                 pfil_remove_hook((void *)fr_check_wrapper6, NULL,
1561                     PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1562 #  else
1563         pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1564                                  &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
1565 #  endif
1566 # endif
1567 #endif
1568
1569         return (0);
1570 }
1571
1572 int ipf_pfil_hook(void) {
1573 #if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1574 # if __FreeBSD_version >= 501108
1575         struct pfil_head *ph_inet;
1576 #  ifdef USE_INET6
1577         struct pfil_head *ph_inet6;
1578 #  endif
1579 # endif
1580 #endif
1581
1582 # ifdef NETBSD_PF
1583 #  if __FreeBSD_version >= 500011
1584 #   if __FreeBSD_version >= 501108
1585         ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1586 #    ifdef USE_INET6
1587         ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1588 #    endif
1589         if (ph_inet == NULL
1590 #    ifdef USE_INET6
1591             && ph_inet6 == NULL
1592 #    endif
1593            )
1594                 return ENODEV;
1595
1596         if (ph_inet != NULL)
1597                 pfil_add_hook((void *)fr_check_wrapper, NULL,
1598                     PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1599 #  else
1600         pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1601                               &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
1602 #  endif
1603 #  else
1604         pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK);
1605 #  endif
1606 #  ifdef USE_INET6
1607 #   if __FreeBSD_version >= 501108
1608         if (ph_inet6 != NULL)
1609                 pfil_add_hook((void *)fr_check_wrapper6, NULL,
1610                                       PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1611 #   else
1612         pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1613                               &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
1614 #   endif
1615 #  endif
1616 # endif
1617         return (0);
1618 }
1619
1620 void
1621 ipf_event_reg(void)
1622 {
1623 #if (__FreeBSD_version >= 502103)
1624         ipf_arrivetag =  EVENTHANDLER_REGISTER(ifnet_arrival_event, \
1625                                                ipf_ifevent, NULL, \
1626                                                EVENTHANDLER_PRI_ANY);
1627         ipf_departtag =  EVENTHANDLER_REGISTER(ifnet_departure_event, \
1628                                                ipf_ifevent, NULL, \
1629                                                EVENTHANDLER_PRI_ANY);
1630         ipf_clonetag =  EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
1631                                               NULL, EVENTHANDLER_PRI_ANY);
1632 #endif
1633 }
1634
1635 void
1636 ipf_event_dereg(void)
1637 {
1638 #if (__FreeBSD_version >= 502103)
1639         if (ipf_arrivetag != NULL) {
1640                 EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag);
1641         }
1642         if (ipf_departtag != NULL) {
1643                 EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag);
1644         }
1645         if (ipf_clonetag != NULL) {
1646                 EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag);
1647         }
1648 #endif
1649 }