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