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