2 * Copyright (C) 1993-2001, 2003 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
6 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
7 * Use is subject to license terms.
11 #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
14 #include <sys/param.h>
15 #if defined(__FreeBSD__) && !defined(__FreeBSD_version)
16 # if defined(IPFILTER_LKM)
17 # ifndef __FreeBSD_cc_version
18 # include <osreldate.h>
20 # if __FreeBSD_cc_version < 430000
21 # include <osreldate.h>
26 #include <sys/errno.h>
27 #if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL)
28 # include <sys/kern_svcs.h>
30 #include <sys/types.h>
40 #include <sys/ioctl.h>
42 # include <sys/ptimers.h>
46 # if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
47 # include <sys/dirent.h>
52 # include <sys/filio.h>
55 # include <sys/protosw.h>
57 #include <sys/socket.h>
65 #include <arpa/inet.h>
68 # define _NET_ROUTE_INCLUDED
74 #if __FreeBSD_version >= 300000
75 # include <net/if_var.h>
78 #include <sys/debug.h>
79 # ifdef IFF_DRVRLOCK /* IRIX6 */
80 #include <sys/hashing.h>
83 #if defined(__FreeBSD__)
84 # include "radix_ipf.h"
86 #include <net/route.h>
87 #include <netinet/in.h>
88 #if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ && \
89 !defined(__hpux) && !defined(linux)
90 # include <netinet/in_var.h>
92 #include <netinet/in_systm.h>
93 #include <netinet/ip.h>
95 # include <netinet/ip_var.h>
97 #include <netinet/tcp.h>
99 # include <netinet/tcp_timer.h>
101 #if defined(__osf__) || defined(__hpux) || defined(__sgi)
102 # include "radix_ipf_local.h"
105 #include <netinet/udp.h>
106 #include <netinet/tcpip.h>
107 #include <netinet/ip_icmp.h>
111 # undef _NET_ROUTE_INCLUDED
113 #include "netinet/ip_compat.h"
114 #include "netinet/ip_fil.h"
115 #include "netinet/ip_nat.h"
116 #include "netinet/ip_frag.h"
117 #include "netinet/ip_state.h"
118 #include "netinet/ip_proxy.h"
119 #include "netinet/ip_auth.h"
121 #include "netinet/ip_sync.h"
124 #include "netinet/ip_scan.h"
126 #include "netinet/ip_pool.h"
127 #ifdef IPFILTER_COMPILED
128 # include "netinet/ip_rules.h"
130 #include "netinet/ipf_stack.h"
131 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
132 # include <sys/malloc.h>
140 #if !defined(__osf__)
141 extern struct protosw inetsw
[];
145 static struct ifnet
**ifneta
= NULL
;
148 static int frzerostats
__P((caddr_t
, ipf_stack_t
*ifs
));
149 static void fr_setifpaddr
__P((struct ifnet
*, char *));
150 void init_ifp
__P((void));
151 #if defined(__sgi) && (IRIX < 60500)
152 static int no_output
__P((struct ifnet
*, struct mbuf
*,
154 static int write_output
__P((struct ifnet
*, struct mbuf
*,
158 static int no_output
__P((struct ifnet
*, struct mbuf
*,
159 struct sockaddr
*, struct rtentry
*, char *));
160 static int write_output
__P((struct ifnet
*, struct mbuf
*,
161 struct sockaddr
*, struct rtentry
*, char *));
163 static int no_output
__P((struct ifnet
*, struct mbuf
*,
164 struct sockaddr
*, struct rtentry
*));
165 static int write_output
__P((struct ifnet
*, struct mbuf
*,
166 struct sockaddr
*, struct rtentry
*));
174 ifs
->ifs_fr_running
= 1;
182 ifs
->ifs_fr_running
= -1;
187 static int frzerostats(data
, ifs
)
194 fr_getstat(&fio
, ifs
);
195 error
= copyoutptr(&fio
, data
, sizeof(fio
));
199 bzero((char *)ifs
->ifs_frstats
, sizeof(*ifs
->ifs_frstats
) * 2);
206 * Filter ioctl interface.
208 int iplioctl(dev
, cmd
, data
, mode
)
214 int error
= 0, unit
= 0, tmp
, uid
;
217 extern ipf_stack_t
*get_ifs();
226 if (unit
== IPL_LOGNAT
) {
227 if (ifs
->ifs_fr_running
> 0)
228 error
= fr_nat_ioctl(data
, cmd
, mode
, uid
, NULL
, ifs
);
234 if (unit
== IPL_LOGSTATE
) {
235 if (ifs
->ifs_fr_running
> 0)
236 error
= fr_state_ioctl(data
, cmd
, mode
, uid
, NULL
, ifs
);
242 if (unit
== IPL_LOGAUTH
) {
243 if (ifs
->ifs_fr_running
> 0) {
244 if ((cmd
== (ioctlcmd_t
)SIOCADAFR
) ||
245 (cmd
== (ioctlcmd_t
)SIOCRMAFR
)) {
246 if (!(mode
& FWRITE
)) {
249 error
= frrequest(unit
, cmd
, data
,
250 ifs
->ifs_fr_active
, 1, ifs
);
253 error
= fr_auth_ioctl(data
, cmd
, mode
, uid
,
261 if (unit
== IPL_LOGSYNC
) {
263 if (ifs
->ifs_fr_running
> 0)
264 error
= fr_sync_ioctl(data
, cmd
, mode
);
271 if (unit
== IPL_LOGSCAN
) {
273 if (ifs
->ifs_fr_running
> 0)
274 error
= fr_scan_ioctl(data
, cmd
, mode
);
281 if (unit
== IPL_LOGLOOKUP
) {
282 if (ifs
->ifs_fr_running
> 0)
283 error
= ip_lookup_ioctl(data
, cmd
, mode
, uid
,
295 error
= COPYOUT(&ifs
->ifs_iplused
[IPL_LOGIPF
], (caddr_t
)data
,
296 sizeof(ifs
->ifs_iplused
[IPL_LOGIPF
]));
300 if (!(mode
& FWRITE
))
303 error
= COPYIN(data
, &tmp
, sizeof(tmp
));
307 error
= iplattach(ifs
);
309 error
= ipldetach(ifs
);
313 if (!(mode
& FWRITE
)) {
318 case SIOCIPFGETNEXT
:
320 error
= fr_ipftune(cmd
, (void *)data
, ifs
);
323 if (!(mode
& FWRITE
))
326 error
= COPYIN(data
, &ifs
->ifs_fr_flags
,
327 sizeof(ifs
->ifs_fr_flags
));
330 error
= COPYOUT(&ifs
->ifs_fr_flags
, data
,
331 sizeof(ifs
->ifs_fr_flags
));
334 error
= fr_resolvefunc(data
);
340 if (!(mode
& FWRITE
))
343 error
= frrequest(unit
, cmd
, data
,
344 ifs
->ifs_fr_active
, 1, ifs
);
349 if (!(mode
& FWRITE
))
352 error
= frrequest(unit
, cmd
, data
,
353 1 - ifs
->ifs_fr_active
, 1, ifs
);
356 if (!(mode
& FWRITE
))
359 *(u_int
*)data
= ifs
->ifs_fr_active
;
360 ifs
->ifs_fr_active
= 1 - ifs
->ifs_fr_active
;
364 fr_getstat(&fio
, ifs
);
365 error
= fr_outobj(data
, &fio
, IPFOBJ_IPFSTAT
);
368 if (!(mode
& FWRITE
))
371 error
= frzerostats(data
, ifs
);
374 if (!(mode
& FWRITE
))
377 error
= COPYIN(data
, &tmp
, sizeof(tmp
));
379 tmp
= frflush(unit
, 4, tmp
, ifs
);
380 error
= COPYOUT(&tmp
, data
, sizeof(tmp
));
386 if (!(mode
& FWRITE
))
389 error
= COPYIN(data
, &tmp
, sizeof(tmp
));
391 tmp
= frflush(unit
, 6, tmp
, ifs
);
392 error
= COPYOUT(&tmp
, data
, sizeof(tmp
));
398 error
= COPYIN(data
, &tmp
, sizeof(tmp
));
400 ifs
->ifs_fr_state_lock
= tmp
;
401 ifs
->ifs_fr_nat_lock
= tmp
;
402 ifs
->ifs_fr_frag_lock
= tmp
;
403 ifs
->ifs_fr_auth_lock
= tmp
;
409 if (!(mode
& FWRITE
))
412 *(int *)data
= ipflog_clear(unit
, ifs
);
414 #endif /* IPFILTER_LOG */
416 error
= fr_outobj(data
, fr_fragstats(ifs
), IPFOBJ_FRAGSTAT
);
419 if (!(mode
& FWRITE
))
422 frsync(IPFSYNC_RESYNC
, IPFSYNC_RESYNC
, NULL
, NULL
, ifs
);
434 void fr_forgetifp(ifp
, ifs
)
438 register frentry_t
*f
;
440 WRITE_ENTER(&ifs
->ifs_ipf_mutex
);
441 for (f
= ifs
->ifs_ipacct
[0][ifs
->ifs_fr_active
]; (f
!= NULL
);
443 if (f
->fr_ifa
== ifp
)
444 f
->fr_ifa
= (void *)-1;
445 for (f
= ifs
->ifs_ipacct
[1][ifs
->ifs_fr_active
]; (f
!= NULL
);
447 if (f
->fr_ifa
== ifp
)
448 f
->fr_ifa
= (void *)-1;
449 for (f
= ifs
->ifs_ipfilter
[0][ifs
->ifs_fr_active
]; (f
!= NULL
);
451 if (f
->fr_ifa
== ifp
)
452 f
->fr_ifa
= (void *)-1;
453 for (f
= ifs
->ifs_ipfilter
[1][ifs
->ifs_fr_active
]; (f
!= NULL
);
455 if (f
->fr_ifa
== ifp
)
456 f
->fr_ifa
= (void *)-1;
458 for (f
= ifs
->ifs_ipacct6
[0][ifs
->ifs_fr_active
]; (f
!= NULL
);
460 if (f
->fr_ifa
== ifp
)
461 f
->fr_ifa
= (void *)-1;
462 for (f
= ifs
->ifs_ipacct6
[1][ifs
->ifs_fr_active
]; (f
!= NULL
);
464 if (f
->fr_ifa
== ifp
)
465 f
->fr_ifa
= (void *)-1;
466 for (f
= ifs
->ifs_ipfilter6
[0][ifs
->ifs_fr_active
]; (f
!= NULL
);
468 if (f
->fr_ifa
== ifp
)
469 f
->fr_ifa
= (void *)-1;
470 for (f
= ifs
->ifs_ipfilter6
[1][ifs
->ifs_fr_active
]; (f
!= NULL
);
472 if (f
->fr_ifa
== ifp
)
473 f
->fr_ifa
= (void *)-1;
475 RWLOCK_EXIT(&ifs
->ifs_ipf_mutex
);
476 fr_natifpsync(IPFSYNC_OLDIFP
, 4, ifp
, NULL
, ifs
);
477 fr_natifpsync(IPFSYNC_OLDIFP
, 6, ifp
, NULL
, ifs
);
481 void fr_resolvedest(fdp
, v
, ifs
)
488 if (*fdp
->fd_ifname
) {
489 fdp
->fd_ifp
= GETIFP(fdp
->fd_ifname
, v
, ifs
);
491 fdp
->fd_ifp
= (struct ifnet
*)-1;
496 #if defined(__sgi) && (IRIX < 60500)
497 static int no_output(ifp
, m
, s
)
500 static int no_output (ifp
, m
, s
, rt
, cp
)
503 static int no_output(ifp
, m
, s
, rt
)
515 #if defined(__sgi) && (IRIX < 60500)
516 static int write_output(ifp
, m
, s
)
519 static int write_output (ifp
, m
, s
, rt
, cp
)
522 static int write_output(ifp
, m
, s
, rt
)
536 ip
= MTOD(mb
, ip_t
*);
538 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
539 (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
540 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
541 sprintf(fname
, "/tmp/%s", ifp
->if_xname
);
543 sprintf(fname
, "/tmp/%s%d", ifp
->if_name
, ifp
->if_unit
);
545 fd
= open(fname
, O_WRONLY
|O_APPEND
);
550 write(fd
, (char *)ip
, ntohs(ip
->ip_len
));
556 static void fr_setifpaddr(ifp
, addr
)
561 struct in_ifaddr
*ifa
;
566 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
567 if (ifp
->if_addrlist
.tqh_first
!= NULL
)
570 if (ifp
->in_ifaddr
!= NULL
)
572 if (ifp
->if_addrlist
!= NULL
)
577 ifa
= (struct ifaddr
*)malloc(sizeof(*ifa
));
578 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
579 ifp
->if_addrlist
.tqh_first
= ifa
;
582 ifp
->in_ifaddr
= ifa
;
584 ifp
->if_addrlist
= ifa
;
589 struct sockaddr_in
*sin
;
592 sin
= (struct sockaddr_in
*)&ifa
->ia_addr
;
594 sin
= (struct sockaddr_in
*)&ifa
->ifa_addr
;
596 sin
->sin_addr
.s_addr
= inet_addr(addr
);
597 if (sin
->sin_addr
.s_addr
== 0)
603 struct ifnet
*get_unit(name
, v
, ifs
)
608 struct ifnet
*ifp
, **ifpp
, **old_ifneta
;
610 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
611 (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
612 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
617 addr
= strchr(name
, '=');
621 for (ifpp
= ifneta
; ifpp
&& (ifp
= *ifpp
); ifpp
++) {
622 if (!strcmp(name
, ifp
->if_xname
)) {
624 fr_setifpaddr(ifp
, addr
);
629 char *s
, ifname
[LIFNAMSIZ
+1];
634 addr
= strchr(name
, '=');
638 for (ifpp
= ifneta
; ifpp
&& (ifp
= *ifpp
); ifpp
++) {
639 COPYIFNAME(ifp
, ifname
, 0);
640 if (!strcmp(name
, ifname
)) {
642 fr_setifpaddr(ifp
, addr
);
649 ifneta
= (struct ifnet
**)malloc(sizeof(ifp
) * 2);
653 ifneta
[0] = (struct ifnet
*)calloc(1, sizeof(*ifp
));
662 ifneta
= (struct ifnet
**)reallocarray(ifneta
, nifs
+ 1,
670 ifneta
[nifs
- 1] = (struct ifnet
*)malloc(sizeof(*ifp
));
671 if (!ifneta
[nifs
- 1]) {
676 ifp
= ifneta
[nifs
- 1];
678 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
679 (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
680 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
681 (void) strncpy(ifp
->if_xname
, name
, sizeof(ifp
->if_xname
));
683 for (s
= name
; *s
&& !ISDIGIT(*s
); s
++)
685 if (*s
&& ISDIGIT(*s
)) {
686 ifp
->if_unit
= atoi(s
);
687 ifp
->if_name
= (char *)malloc(s
- name
+ 1);
688 if (ifp
->if_name
== NULL
) {
690 * XXX do it more elegantly: free up mem,
696 (void) strncpy(ifp
->if_name
, name
, s
- name
);
697 ifp
->if_name
[s
- name
] = '\0';
699 ifp
->if_name
= strdup(name
);
703 ifp
->if_output
= no_output
;
706 fr_setifpaddr(ifp
, addr
);
713 char *get_ifname(ifp
)
716 static char ifname
[LIFNAMSIZ
];
718 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(linux) || \
719 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
720 sprintf(ifname
, "%s", ifp
->if_xname
);
722 sprintf(ifname
, "%s%d", ifp
->if_name
, ifp
->if_unit
);
731 struct ifnet
*ifp
, **ifpp
;
735 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
736 (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
737 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
738 for (ifpp
= ifneta
; ifpp
&& (ifp
= *ifpp
); ifpp
++) {
739 ifp
->if_output
= write_output
;
740 sprintf(fname
, "/tmp/%s", ifp
->if_xname
);
741 fd
= open(fname
, O_WRONLY
|O_CREAT
|O_EXCL
|O_TRUNC
, 0600);
749 for (ifpp
= ifneta
; ifpp
&& (ifp
= *ifpp
); ifpp
++) {
750 ifp
->if_output
= write_output
;
751 sprintf(fname
, "/tmp/%s%d", ifp
->if_name
, ifp
->if_unit
);
752 fd
= open(fname
, O_WRONLY
|O_CREAT
|O_EXCL
|O_TRUNC
, 0600);
762 int fr_fastroute(m
, mpp
, fin
, fdp
)
767 struct ifnet
*ifp
= fdp
->fd_ifp
;
768 ip_t
*ip
= fin
->fin_ip
;
771 return 0; /* no routing table out here */
773 ip
->ip_len
= htons((u_short
)ip
->ip_len
);
774 ip
->ip_off
= htons((u_short
)(ip
->ip_off
| IP_MF
));
776 #if defined(__sgi) && (IRIX < 60500)
777 (*ifp
->if_output
)(ifp
, (void *)ip
, NULL
);
779 (*ifp
->if_output
)(ifp
, (void *)m
, NULL
, 0, 0);
781 (*ifp
->if_output
)(ifp
, (void *)m
, NULL
, 0);
788 int fr_send_reset(fin
)
791 verbose("- TCP RST sent\n");
796 int fr_send_icmp_err(type
, fin
, dst
)
801 verbose("- ICMP unreachable sent\n");
806 void frsync(command
, version
, nic
, data
, ifs
)
807 int command
, version
;
823 void m_copydata(m
, off
, len
, cp
)
828 bcopy((char *)m
+ off
, cp
, len
);
832 int ipfuiomove(buf
, len
, rwflag
, uio
)
837 int left
, ioc
, num
, offset
;
841 if (rwflag
== UIO_READ
) {
845 offset
= uio
->uio_offset
;
847 while ((left
> 0) && (ioc
< uio
->uio_iovcnt
)) {
848 io
= uio
->uio_iov
+ ioc
;
852 start
= (char *)io
->iov_base
+ offset
;
853 if (start
> (char *)io
->iov_base
+ io
->iov_len
) {
854 offset
-= io
->iov_len
;
858 bcopy(buf
, start
, num
);
859 uio
->uio_resid
-= num
;
860 uio
->uio_offset
+= num
;
872 u_32_t
fr_newisn(fin
)
875 static int iss_seq_off
= 0;
881 * Compute the base value of the ISS. It is a hash
882 * of (saddr, sport, daddr, dport, secret).
886 MD5Update(&ctx
, (u_char
*) &fin
->fin_fi
.fi_src
,
887 sizeof(fin
->fin_fi
.fi_src
));
888 MD5Update(&ctx
, (u_char
*) &fin
->fin_fi
.fi_dst
,
889 sizeof(fin
->fin_fi
.fi_dst
));
890 MD5Update(&ctx
, (u_char
*) &fin
->fin_dat
, sizeof(fin
->fin_dat
));
892 /* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */
894 MD5Final(hash
, &ctx
);
896 memcpy(&newiss
, hash
, sizeof(newiss
));
899 * Now increment our "timer", and add it in to
900 * the computed value.
903 * XXX TCP_ISSINCR too large to use?
905 iss_seq_off
+= 0x00010000;
906 newiss
+= iss_seq_off
;
911 /* ------------------------------------------------------------------------ */
912 /* Function: fr_nextipid */
913 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */
914 /* Parameters: fin(I) - pointer to packet information */
916 /* Returns the next IPv4 ID to use for this packet. */
917 /* ------------------------------------------------------------------------ */
918 INLINE u_short
fr_nextipid(fin
)
921 static u_short ipid
= 0;
923 ipf_stack_t
*ifs
= fin
->fin_ifs
;
925 MUTEX_ENTER(&ifs
->ifs_ipf_rw
);
927 MUTEX_EXIT(&ifs
->ifs_ipf_rw
);
933 INLINE
void fr_checkv4sum(fin
)
936 if (fr_checkl4sum(fin
) == -1)
937 fin
->fin_flx
|= FI_BAD
;
942 INLINE
void fr_checkv6sum(fin
)
945 if (fr_checkl4sum(fin
) == -1)
946 fin
->fin_flx
|= FI_BAD
;
952 * See above for description, except that all addressing is in user space.
954 int copyoutptr(src
, dst
, size
)
960 bcopy(dst
, (char *)&ca
, sizeof(ca
));
961 bcopy(src
, ca
, size
);
967 * See above for description, except that all addressing is in user space.
969 int copyinptr(src
, dst
, size
)
975 bcopy(src
, (char *)&ca
, sizeof(ca
));
976 bcopy(ca
, dst
, size
);
982 * return the first IP Address associated with an interface
984 int fr_ifpaddr(v
, atype
, ifptr
, inp
, inpmask
, ifs
)
987 struct in_addr
*inp
, *inpmask
;
990 struct ifnet
*ifp
= ifptr
;
992 struct in_ifaddr
*ifa
;
997 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
998 ifa
= ifp
->if_addrlist
.tqh_first
;
1001 ifa
= (struct in_ifaddr
*)ifp
->in_ifaddr
;
1003 ifa
= ifp
->if_addrlist
;
1007 struct sockaddr_in
*sin
, mask
;
1009 mask
.sin_addr
.s_addr
= 0xffffffff;
1012 sin
= (struct sockaddr_in
*)&ifa
->ia_addr
;
1014 sin
= (struct sockaddr_in
*)&ifa
->ifa_addr
;
1017 return fr_ifpfillv4addr(atype
, sin
, &mask
, inp
, inpmask
);
1024 * This function is not meant to be random, rather just produce a
1025 * sequence of numbers that isn't linear to show "randomness".
1029 static u_int last
= 0xa5a5a5a5;
1030 static int calls
= 0;
1036 * These are deliberately chosen to ensure that there is some
1037 * attempt to test whether the output covers the range in test n18.