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