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