IP Filter Licence ----------------- /* * Copyright (C) 1993-2003 by Darren Reed. * * The author accepts no responsibility for the use of this software and * provides it on an ``as is'' basis without express or implied warranty. * * Redistribution and use, with or without modification, in source and binary * forms, are permitted provided that this notice is preserved in its entirety * and due credit is given to the original author and the contributors. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied, in part or in whole, and put under another distribution licence * [including the GNU Public Licence.] * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * I hate legalese, don't you ? */ IP FILTER SOFTWARE # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2013 Nexenta Systems, Inc. All rights reserved. # # Copyright (c) 2012, Joyent Inc. All rights reserved. # # cmd/ipf/tools/Makefile # # include ../../Makefile.cmd include ../../Makefile.cmd.64 include ../Makefile.ipf include ../../Makefile.ctf LICENCE= IPFILTER.LICENCE PROG= ipf ipfs ipmon ipnat ippool ipfstat IPFPROG= ipftest IPF_OBJS= ipf.o ipfcomp.o ipfzone.o ipf_y.o ipf_l.o IPFS_OBJS= ipfs.o ipfzone.o IPFSTAT_OBJS= ipfstat.o ipfzone.o IPMON_OBJS= ipmon.o ipfzone.o ipmon_y.o ipmon_l.o IPNAT_OBJS= ipnat.o ipfzone.o ipnat_y.o ipnat_l.o IPPOOL_OBJS= ippool.o ipfzone.o ippool_y.o ippool_l.o IPFTEST_OBJS= ipftest.o ipfzone.o \ ip_fil.o ip_state.o ip_compat.o \ ip_frag.o ip_nat.o ip_nat6.o fil.o \ ip_htable.o ip_lookup.o \ ip_proxy.o ip_auth.o ip_log.o \ ipf_y.o ipf_l.o \ ipnat_y.o ipnat_l.o \ ippool_y.o ippool_l.o \ ip_pool.o radix.o USRLIBIPF= $(ROOTLIB)/ipf USRLIBIPFLICENCE= $(LICENCE:%=$(USRLIBIPF)/%) $(USRLIBIPFLICENCE): FILEMODE= 0644 CFLAGS += -D_ELF64 LDLIBS += -L ../lib -lipf LDLIBS += $(LIBBPF) LDFLAGS += $(MAPFILE.NGB:%=-Wl,-M%) CPPFLAGS += -I. -DIPFILTER_LOOKUP -DIPFILTER_LOG ipfstat.o : CPPFLAGS += -DSTATETOP ipfstat : LDLIBS += -lcurses ipf : LDLIBS += -lsocket -lnsl ipf : OBJS += $(IPF_OBJS) ipfs : OBJS += $(IPFS_OBJS) ipftest : LDLIBS += -lsocket -lnsl -lmd ipftest : OBJS += $(IPFTEST_OBJS) ipfstat : LDLIBS += -lsocket -lnsl -lkvm -lelf ipfstat : OBJS += $(IPFSTAT_OBJS) ipmon : LDLIBS += -lsocket -lnsl ipmon : OBJS += $(IPMON_OBJS) ipnat : LDLIBS += -lsocket -lnsl -lkvm -lelf ipnat : OBJS += $(IPNAT_OBJS) ippool : LDLIBS += -lsocket -lnsl -lkvm -lelf ippool : OBJS += $(IPPOOL_OBJS) # because of labels from yacc ipf_y.o : CERRWARN += -Wno-unused-label ipmon_y.o : CERRWARN += -Wno-unused-label ipnat_y.o : CERRWARN += -Wno-unused-label ippool_y.o : CERRWARN += -Wno-unused-label CLEANFILES += $(IPF_OBJS) $(IPFS_OBJS) $(IPFTEST_OBJS) $(IPFSTAT_OBJS) CLEANFILES += $(IPMON_OBJS) $(IPNAT_OBJS) $(IPPOOL_OBJS) CLOBBERFILES += $(IPFPROG) ROOTIPF= $(ROOTLIB)/ipf ROOTIPFPROG= $(IPFPROG:%=$(ROOTIPF)/%) .KEEP_STATE: all: $(PROG) $(IPFPROG) install: all install_local $(ROOTIPF) $(ROOTUSRSBINPROG) $(ROOTIPFPROG) $(USRLIBIPF): $(INS.dir) $(USRLIBIPF)/% : % $(INS.file) $(ROOTIPF)/%: % $(INS.file) ipf: $(IPF_OBJS) $(LIBIPF) $(MAPFILE.NGB) $(LINK.c) -o ipf $(IPF_OBJS) $(LDLIBS) $(POST_PROCESS) ipf_y.o: ipf_y.c $(COMMONIPF)/netinet/ip_fil.h $(COMMONIPF)/ipf.h \ ipf_y.c ipf_l.h ipf_y.c ipf_y.h: ipf_y.y $(YACC) -d -b ipf ipf_y.y sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.c/' \ ipf.tab.c > ipf_y.c sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.h/' \ ipf.tab.h > ipf_y.h CLEANFILES += ipf.tab.c ipf.tab.h CLEANFILES += ipf_y.c ipf_y.h ipf_l.o: ipf_l.c $(COMMONIPF)/netinet/ip_fil.h $(COMMONIPF)/ipf.h \ ipf_y.h ipf_l.h ipf_l.c: lexer.c $(COMMONIPF)/ipf.h $(COMMONIPF)/netinet/ip_fil.h sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.h/' \ -e 's/lexer.h/ipf_l.h/' lexer.c > $@ ipf_l.h: lexer.h sed -e 's/yy/ipf_yy/g' lexer.h > $@ CLEANFILES += ipf_l.c ipf_l.h ipfs: $(IPFS_OBJS) $(LINK.c) -o ipfs $(IPFS_OBJS) $(LDLIBS) $(POST_PROCESS) ipfstat: $(IPFSTAT_OBJS) $(MAPFILE.NGB) $(LINK.c) -o ipfstat $(IPFSTAT_OBJS) $(LDLIBS) $(POST_PROCESS) ipmon: $(IPMON_OBJS) $(LIBIPF) $(MAPFILE.NGB) $(LINK.c) -o ipmon $(IPMON_OBJS) $(LDLIBS) $(POST_PROCESS) ipmon_y.o: ipmon_y.c $(COMMONIPF)/ipmon.h ipmon_y.h ipmon_l.h ipmon_y.c ipmon_y.h: ipmon_y.y $(YACC) -d -b ipmon ipmon_y.y sed -e 's/yy/ipmon_yy/g' \ -e 's/extern [a-z]* .*();//' \ -e 's/^\(static [a-z]* .*\)();/\1(void);/' \ ipmon.tab.c > ipmon_y.c sed -e 's/yy/ipmon_yy/g' -e 's/y.tab.h/ipmon_y.h/' \ ipmon.tab.h > ipmon_y.h CLEANFILES += ipmon.tab.c ipmon.tab.h CLEANFILES += ipmon_y.c ipmon_y.h ipmon_l.o: ipmon_l.c $(COMMONIPF)/ipmon.h ipmon_y.h ipmon_l.h ipmon_l.c: lexer.c $(COMMONIPF)/ipmon.h sed -e 's/yy/ipmon_yy/g' -e 's/y.tab.h/ipmon_y.h/' \ -e 's/lexer.h/ipmon_l.h/' lexer.c > $@ ipmon_l.h: lexer.h sed -e 's/yy/ipmon_yy/g' lexer.h > $@ CLEANFILES += ipmon_l.c ipmon_l.h ipnat: $(IPNAT_OBJS) $(LIBIPF) $(MAPFILE.NGB) $(LINK.c) -o ipnat $(IPNAT_OBJS) $(LDLIBS) $(POST_PROCESS) ipnat_y.o: ipnat_y.c $(COMMONIPF)/netinet/ip_nat.h ipnat_y.h ipnat_l.h ipnat_y.c ipnat_y.h: ipnat_y.y $(YACC) -d -b ipnat ipnat_y.y sed -e 's/yy/ipnat_yy/g' \ -e 's/extern [a-z]* .*();//' \ -e 's/^\(static [a-z]* .*\)();/\1(void);/' \ ipnat.tab.c > ipnat_y.c sed -e 's/yy/ipnat_yy/g' -e 's/y.tab.h/ipnat_y.h/' \ ipnat.tab.h > ipnat_y.h CLEANFILES += ipnat.tab.c ipnat.tab.h CLEANFILES += ipnat_y.c ipnat_y.h ipnat_l.o: ipnat_l.c $(COMMONIPF)/netinet/ip_nat.h ipnat_l.h ipnat_l.c: lexer.c $(COMMONIPF)/netinet/ip_nat.h sed -e 's/yy/ipnat_yy/g' -e 's/y.tab.h/ipnat_y.h/' \ -e 's/lexer.h/ipnat_l.h/' lexer.c > $@ ipnat_l.h: lexer.h sed -e 's/yy/ipnat_yy/g' lexer.h > $@ CLEANFILES += ipnat_l.c ipnat_l.h ippool: $(IPPOOL_OBJS) $(LIBIPF) $(MAPFILE.NGB) $(LINK.c) -o ippool $(IPPOOL_OBJS) $(LDLIBS) $(POST_PROCESS) ippool_y.o: ippool_y.c $(COMMONIPF)/netinet/ip_pool.h ippool_y.h ippool_l.h ippool_y.c ippool_y.h: ippool_y.y $(YACC) -d -b ippool ippool_y.y sed -e 's/yy/ippool_yy/g' \ -e 's/extern [a-z]* .*();//' \ -e 's/^\(static [a-z]* .*\)();/\1(void);/' \ ippool.tab.c > ippool_y.c sed -e 's/yy/ippool_yy/g' -e 's/y.tab.h/ippool_y.h/' \ ippool.tab.h > ippool_y.h CLEANFILES += ippool.tab.c ippool.tab.h CLEANFILES += ippool_y.c ippool_y.h ippool_l.o: ippool_l.c $(COMMONIPF)/netinet/ip_pool.h ippool_l.h ippool_l.c: lexer.c $(COMMONIPF)/netinet/ip_pool.h sed -e 's/yy/ippool_yy/g' -e 's/y.tab.h/ippool_y.h/' \ -e 's/lexer.h/ippool_l.h/' lexer.c > $@ ippool_l.h: lexer.h sed -e 's/yy/ippool_yy/g' lexer.h > $@ CLEANFILES += ippool_l.c ippool_l.h ipftest: $(IPFTEST_OBJS) $(LIBIPF) $(MAPFILE.NGB) $(LINK.c) $(ZIGNORE) -o ipftest $(IPFTEST_OBJS) $(LDLIBS) $(POST_PROCESS) clean: -$(RM) $(CLEANFILES) # # NOTE: all rules must use relative paths otherwise absolute paths will be # embedded into the binaries making them false positives and # reported by wsdiff # %.o: ../../../uts/common/inet/ipf/%.c $(COMPILE.c) $< $(POST_PROCESS_O) %.o: ../../../common/net/patricia/%.c $(COMPILE.c) $< $(POST_PROCESS_O) install_local: $(USRLIBIPF) $(USRLIBIPFLICENCE) include ../../Makefile.targ /* * Copyright (C) 1993-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifdef SOLARIS #undef SOLARIS #endif #if (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #define SOLARIS (1) #else #define SOLARIS (0) #endif #include #if defined(__FreeBSD__) && !defined(__FreeBSD_version) # if defined(IPFILTER_LKM) # ifndef __FreeBSD_cc_version # include # else # if __FreeBSD_cc_version < 430000 # include # endif # endif # endif #endif #include #if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL) # include #endif #include #define _KERNEL #define KERNEL #ifdef __OpenBSD__ struct file; #endif #include #undef _KERNEL #undef KERNEL #include #include #ifdef __sgi # include #endif #include #if !defined(SOLARIS) # if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) # include # else # include # endif #else # include #endif #ifndef linux # include #endif #include #include #include #include #include #include #include #include #ifdef __hpux # define _NET_ROUTE_INCLUDED #endif #include #ifdef sun # include #endif #if __FreeBSD_version >= 300000 # include #endif #ifdef __sgi #include # ifdef IFF_DRVRLOCK /* IRIX6 */ #include # endif #endif #if defined(__FreeBSD__) # include "radix_ipf.h" #endif #include #include #if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ && \ !defined(__hpux) && !defined(linux) # include #endif #include #include #if !defined(linux) # include #endif #include #if defined(__osf__) # include #endif #if defined(__osf__) || defined(__hpux) || defined(__sgi) # include "radix_ipf_local.h" # define _RADIX_H_ #endif #include #include #include #include #include #ifdef __hpux # undef _NET_ROUTE_INCLUDED #endif #include "netinet/ip_compat.h" #include "netinet/ip_fil.h" #include "netinet/ip_nat.h" #include "netinet/ip_frag.h" #include "netinet/ip_state.h" #include "netinet/ip_proxy.h" #include "netinet/ip_auth.h" #ifdef IPFILTER_SYNC #include "netinet/ip_sync.h" #endif #ifdef IPFILTER_SCAN #include "netinet/ip_scan.h" #endif #include "netinet/ip_pool.h" #ifdef IPFILTER_COMPILED # include "netinet/ip_rules.h" #endif #include "netinet/ipf_stack.h" #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) # include #endif #ifdef __hpux struct rtentry; #endif #include "md5.h" #if !defined(__osf__) extern struct protosw inetsw[]; #endif #include "ipt.h" static struct ifnet **ifneta = NULL; static int nifs = 0; static int frzerostats __P((caddr_t, ipf_stack_t *ifs)); static void fr_setifpaddr __P((struct ifnet *, char *)); void init_ifp __P((void)); #if defined(__sgi) && (IRIX < 60500) static int no_output __P((struct ifnet *, struct mbuf *, struct sockaddr *)); static int write_output __P((struct ifnet *, struct mbuf *, struct sockaddr *)); #else # if TRU64 >= 1885 static int no_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *, char *)); static int write_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *, char *)); # else static int no_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); static int write_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); # endif #endif int iplattach(ifs) ipf_stack_t *ifs; { ifs->ifs_fr_running = 1; return 0; } int ipldetach(ifs) ipf_stack_t *ifs; { ifs->ifs_fr_running = -1; return 0; } static int frzerostats(data, ifs) caddr_t data; ipf_stack_t *ifs; { friostat_t fio; int error; fr_getstat(&fio, ifs); error = copyoutptr(&fio, data, sizeof(fio)); if (error) return EFAULT; bzero((char *)ifs->ifs_frstats, sizeof(*ifs->ifs_frstats) * 2); return 0; } /* * Filter ioctl interface. */ int iplioctl(dev, cmd, data, mode) int dev; ioctlcmd_t cmd; caddr_t data; int mode; { int error = 0, unit = 0, tmp, uid; friostat_t fio; ipf_stack_t *ifs; extern ipf_stack_t *get_ifs(); unit = dev; uid = getuid(); ifs = get_ifs(); SPL_NET(s); if (unit == IPL_LOGNAT) { if (ifs->ifs_fr_running > 0) error = fr_nat_ioctl(data, cmd, mode, uid, NULL, ifs); else error = EIO; SPL_X(s); return error; } if (unit == IPL_LOGSTATE) { if (ifs->ifs_fr_running > 0) error = fr_state_ioctl(data, cmd, mode, uid, NULL, ifs); else error = EIO; SPL_X(s); return error; } if (unit == IPL_LOGAUTH) { if (ifs->ifs_fr_running > 0) { if ((cmd == (ioctlcmd_t)SIOCADAFR) || (cmd == (ioctlcmd_t)SIOCRMAFR)) { if (!(mode & FWRITE)) { error = EPERM; } else { error = frrequest(unit, cmd, data, ifs->ifs_fr_active, 1, ifs); } } else { error = fr_auth_ioctl(data, cmd, mode, uid, NULL, ifs); } } else error = EIO; SPL_X(s); return error; } if (unit == IPL_LOGSYNC) { #ifdef IPFILTER_SYNC if (ifs->ifs_fr_running > 0) error = fr_sync_ioctl(data, cmd, mode); else #endif error = EIO; SPL_X(s); return error; } if (unit == IPL_LOGSCAN) { #ifdef IPFILTER_SCAN if (ifs->ifs_fr_running > 0) error = fr_scan_ioctl(data, cmd, mode); else #endif error = EIO; SPL_X(s); return error; } if (unit == IPL_LOGLOOKUP) { if (ifs->ifs_fr_running > 0) error = ip_lookup_ioctl(data, cmd, mode, uid, NULL, ifs); else error = EIO; SPL_X(s); return error; } switch (cmd) { case FIONREAD : #ifdef IPFILTER_LOG error = COPYOUT(&ifs->ifs_iplused[IPL_LOGIPF], (caddr_t)data, sizeof(ifs->ifs_iplused[IPL_LOGIPF])); #endif break; case SIOCFRENB : if (!(mode & FWRITE)) error = EPERM; else { error = COPYIN(data, &tmp, sizeof(tmp)); if (error) break; if (tmp) error = iplattach(ifs); else error = ipldetach(ifs); } break; case SIOCIPFSET : if (!(mode & FWRITE)) { error = EPERM; break; } /* FALLTHROUGH */ case SIOCIPFGETNEXT : case SIOCIPFGET : error = fr_ipftune(cmd, (void *)data, ifs); break; case SIOCSETFF : if (!(mode & FWRITE)) error = EPERM; else error = COPYIN(data, &ifs->ifs_fr_flags, sizeof(ifs->ifs_fr_flags)); break; case SIOCGETFF : error = COPYOUT(&ifs->ifs_fr_flags, data, sizeof(ifs->ifs_fr_flags)); break; case SIOCFUNCL : error = fr_resolvefunc(data); break; case SIOCINAFR : case SIOCRMAFR : case SIOCADAFR : case SIOCZRLST : if (!(mode & FWRITE)) error = EPERM; else error = frrequest(unit, cmd, data, ifs->ifs_fr_active, 1, ifs); break; case SIOCINIFR : case SIOCRMIFR : case SIOCADIFR : if (!(mode & FWRITE)) error = EPERM; else error = frrequest(unit, cmd, data, 1 - ifs->ifs_fr_active, 1, ifs); break; case SIOCSWAPA : if (!(mode & FWRITE)) error = EPERM; else { *(u_int *)data = ifs->ifs_fr_active; ifs->ifs_fr_active = 1 - ifs->ifs_fr_active; } break; case SIOCGETFS : fr_getstat(&fio, ifs); error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT); break; case SIOCFRZST : if (!(mode & FWRITE)) error = EPERM; else error = frzerostats(data, ifs); break; case SIOCIPFFL : if (!(mode & FWRITE)) error = EPERM; else { error = COPYIN(data, &tmp, sizeof(tmp)); if (!error) { tmp = frflush(unit, 4, tmp, ifs); error = COPYOUT(&tmp, data, sizeof(tmp)); } } break; #ifdef USE_INET6 case SIOCIPFL6 : if (!(mode & FWRITE)) error = EPERM; else { error = COPYIN(data, &tmp, sizeof(tmp)); if (!error) { tmp = frflush(unit, 6, tmp, ifs); error = COPYOUT(&tmp, data, sizeof(tmp)); } } break; #endif case SIOCSTLCK : error = COPYIN(data, &tmp, sizeof(tmp)); if (error == 0) { ifs->ifs_fr_state_lock = tmp; ifs->ifs_fr_nat_lock = tmp; ifs->ifs_fr_frag_lock = tmp; ifs->ifs_fr_auth_lock = tmp; } else error = EFAULT; break; #ifdef IPFILTER_LOG case SIOCIPFFB : if (!(mode & FWRITE)) error = EPERM; else *(int *)data = ipflog_clear(unit, ifs); break; #endif /* IPFILTER_LOG */ case SIOCGFRST : error = fr_outobj(data, fr_fragstats(ifs), IPFOBJ_FRAGSTAT); break; case SIOCFRSYN : if (!(mode & FWRITE)) error = EPERM; else { frsync(IPFSYNC_RESYNC, IPFSYNC_RESYNC, NULL, NULL, ifs); } break; default : error = EINVAL; break; } SPL_X(s); return error; } void fr_forgetifp(ifp, ifs) void *ifp; ipf_stack_t *ifs; { register frentry_t *f; WRITE_ENTER(&ifs->ifs_ipf_mutex); for (f = ifs->ifs_ipacct[0][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; for (f = ifs->ifs_ipacct[1][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; for (f = ifs->ifs_ipfilter[0][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; for (f = ifs->ifs_ipfilter[1][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; #ifdef USE_INET6 for (f = ifs->ifs_ipacct6[0][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; for (f = ifs->ifs_ipacct6[1][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; for (f = ifs->ifs_ipfilter6[0][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; for (f = ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; #endif RWLOCK_EXIT(&ifs->ifs_ipf_mutex); fr_natifpsync(IPFSYNC_OLDIFP, 4, ifp, NULL, ifs); fr_natifpsync(IPFSYNC_OLDIFP, 6, ifp, NULL, ifs); } void fr_resolvedest(fdp, v, ifs) frdest_t *fdp; int v; ipf_stack_t *ifs; { fdp->fd_ifp = NULL; if (*fdp->fd_ifname) { fdp->fd_ifp = GETIFP(fdp->fd_ifname, v, ifs); if (!fdp->fd_ifp) fdp->fd_ifp = (struct ifnet *)-1; } } #if defined(__sgi) && (IRIX < 60500) static int no_output(ifp, m, s) #else # if TRU64 >= 1885 static int no_output (ifp, m, s, rt, cp) char *cp; # else static int no_output(ifp, m, s, rt) # endif struct rtentry *rt; #endif struct ifnet *ifp; struct mbuf *m; struct sockaddr *s; { return 0; } #if defined(__sgi) && (IRIX < 60500) static int write_output(ifp, m, s) #else # if TRU64 >= 1885 static int write_output (ifp, m, s, rt, cp) char *cp; # else static int write_output(ifp, m, s, rt) # endif struct rtentry *rt; #endif struct ifnet *ifp; struct mbuf *m; struct sockaddr *s; { char fname[32]; mb_t *mb; ip_t *ip; int fd; mb = (mb_t *)m; ip = MTOD(mb, ip_t *); #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) sprintf(fname, "/tmp/%s", ifp->if_xname); #else sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); #endif fd = open(fname, O_WRONLY|O_APPEND); if (fd == -1) { perror("open"); return -1; } write(fd, (char *)ip, ntohs(ip->ip_len)); close(fd); return 0; } static void fr_setifpaddr(ifp, addr) struct ifnet *ifp; char *addr; { #ifdef __sgi struct in_ifaddr *ifa; #else struct ifaddr *ifa; #endif #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) if (ifp->if_addrlist.tqh_first != NULL) #else # ifdef __sgi if (ifp->in_ifaddr != NULL) # else if (ifp->if_addrlist != NULL) # endif #endif return; ifa = (struct ifaddr *)malloc(sizeof(*ifa)); #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) ifp->if_addrlist.tqh_first = ifa; #else # ifdef __sgi ifp->in_ifaddr = ifa; # else ifp->if_addrlist = ifa; # endif #endif if (ifa != NULL) { struct sockaddr_in *sin; #ifdef __sgi sin = (struct sockaddr_in *)&ifa->ia_addr; #else sin = (struct sockaddr_in *)&ifa->ifa_addr; #endif sin->sin_addr.s_addr = inet_addr(addr); if (sin->sin_addr.s_addr == 0) abort(); } } /*ARGSUSED*/ struct ifnet *get_unit(name, v, ifs) char *name; int v; ipf_stack_t *ifs; { struct ifnet *ifp, **ifpp, **old_ifneta; char *addr; #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) if (name == NULL) name = "anon0"; addr = strchr(name, '='); if (addr != NULL) *addr++ = '\0'; for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { if (!strcmp(name, ifp->if_xname)) { if (addr != NULL) fr_setifpaddr(ifp, addr); return ifp; } } #else char *s, ifname[LIFNAMSIZ+1]; if (name == NULL) name = "anon0"; addr = strchr(name, '='); if (addr != NULL) *addr++ = '\0'; for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { COPYIFNAME(ifp, ifname, 0); if (!strcmp(name, ifname)) { if (addr != NULL) fr_setifpaddr(ifp, addr); return ifp; } } #endif if (!ifneta) { ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2); if (!ifneta) return NULL; ifneta[1] = NULL; ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp)); if (!ifneta[0]) { free(ifneta); return NULL; } nifs = 1; } else { old_ifneta = ifneta; nifs++; ifneta = (struct ifnet **)realloc(ifneta, (nifs + 1) * sizeof(ifp)); if (!ifneta) { free(old_ifneta); nifs = 0; return NULL; } ifneta[nifs] = NULL; ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp)); if (!ifneta[nifs - 1]) { nifs--; return NULL; } } ifp = ifneta[nifs - 1]; #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) (void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname)); #else for (s = name; *s && !ISDIGIT(*s); s++) ; if (*s && ISDIGIT(*s)) { ifp->if_unit = atoi(s); ifp->if_name = (char *)malloc(s - name + 1); if (ifp->if_name == NULL) { /* * XXX do it more elegantly: free up mem, * return NULL */ perror("malloc"); exit(1); } (void) strncpy(ifp->if_name, name, s - name); ifp->if_name[s - name] = '\0'; } else { ifp->if_name = strdup(name); ifp->if_unit = -1; } #endif ifp->if_output = no_output; if (addr != NULL) { fr_setifpaddr(ifp, addr); } return ifp; } char *get_ifname(ifp) struct ifnet *ifp; { static char ifname[LIFNAMSIZ]; #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(linux) || \ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) sprintf(ifname, "%s", ifp->if_xname); #else sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit); #endif return ifname; } void init_ifp() { struct ifnet *ifp, **ifpp; char fname[32]; int fd; #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { ifp->if_output = write_output; sprintf(fname, "/tmp/%s", ifp->if_xname); fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); if (fd == -1) perror("open"); else close(fd); } #else for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { ifp->if_output = write_output; sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); if (fd == -1) perror("open"); else close(fd); } #endif } int fr_fastroute(m, mpp, fin, fdp) mb_t *m, **mpp; fr_info_t *fin; frdest_t *fdp; { struct ifnet *ifp = fdp->fd_ifp; ip_t *ip = fin->fin_ip; if (!ifp) return 0; /* no routing table out here */ ip->ip_len = htons((u_short)ip->ip_len); ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); ip->ip_sum = 0; #if defined(__sgi) && (IRIX < 60500) (*ifp->if_output)(ifp, (void *)ip, NULL); # if TRU64 >= 1885 (*ifp->if_output)(ifp, (void *)m, NULL, 0, 0); # else (*ifp->if_output)(ifp, (void *)m, NULL, 0); # endif #endif return 0; } int fr_send_reset(fin) fr_info_t *fin; { verbose("- TCP RST sent\n"); return 0; } int fr_send_icmp_err(type, fin, dst) int type; fr_info_t *fin; int dst; { verbose("- ICMP unreachable sent\n"); return 0; } void frsync(command, version, nic, data, ifs) int command, version; void *nic; char *data; ipf_stack_t *ifs; { return; } void m_freem(m) mb_t *m; { return; } void m_copydata(m, off, len, cp) mb_t *m; int off, len; caddr_t cp; { bcopy((char *)m + off, cp, len); } int ipfuiomove(buf, len, rwflag, uio) caddr_t buf; int len, rwflag; struct uio *uio; { int left, ioc, num, offset; struct iovec *io; char *start; if (rwflag == UIO_READ) { left = len; ioc = 0; offset = uio->uio_offset; while ((left > 0) && (ioc < uio->uio_iovcnt)) { io = uio->uio_iov + ioc; num = io->iov_len; if (num > left) num = left; start = (char *)io->iov_base + offset; if (start > (char *)io->iov_base + io->iov_len) { offset -= io->iov_len; ioc++; continue; } bcopy(buf, start, num); uio->uio_resid -= num; uio->uio_offset += num; left -= num; if (left > 0) ioc++; } if (left > 0) return EFAULT; } return 0; } u_32_t fr_newisn(fin) fr_info_t *fin; { static int iss_seq_off = 0; u_char hash[16]; u_32_t newiss; MD5_CTX ctx; /* * Compute the base value of the ISS. It is a hash * of (saddr, sport, daddr, dport, secret). */ MD5Init(&ctx); MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, sizeof(fin->fin_fi.fi_src)); MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, sizeof(fin->fin_fi.fi_dst)); MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); /* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */ MD5Final(hash, &ctx); memcpy(&newiss, hash, sizeof(newiss)); /* * Now increment our "timer", and add it in to * the computed value. * * XXX Use `addin'? * XXX TCP_ISSINCR too large to use? */ iss_seq_off += 0x00010000; newiss += iss_seq_off; return newiss; } /* ------------------------------------------------------------------------ */ /* Function: fr_nextipid */ /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ /* Parameters: fin(I) - pointer to packet information */ /* */ /* Returns the next IPv4 ID to use for this packet. */ /* ------------------------------------------------------------------------ */ INLINE u_short fr_nextipid(fin) fr_info_t *fin; { static u_short ipid = 0; u_short id; ipf_stack_t *ifs = fin->fin_ifs; MUTEX_ENTER(&ifs->ifs_ipf_rw); id = ipid++; MUTEX_EXIT(&ifs->ifs_ipf_rw); return id; } INLINE void fr_checkv4sum(fin) fr_info_t *fin; { if (fr_checkl4sum(fin) == -1) fin->fin_flx |= FI_BAD; } #ifdef USE_INET6 INLINE void fr_checkv6sum(fin) fr_info_t *fin; { if (fr_checkl4sum(fin) == -1) fin->fin_flx |= FI_BAD; } #endif /* * See above for description, except that all addressing is in user space. */ int copyoutptr(src, dst, size) void *src, *dst; size_t size; { caddr_t ca; bcopy(dst, (char *)&ca, sizeof(ca)); bcopy(src, ca, size); return 0; } /* * See above for description, except that all addressing is in user space. */ int copyinptr(src, dst, size) void *src, *dst; size_t size; { caddr_t ca; bcopy(src, (char *)&ca, sizeof(ca)); bcopy(ca, dst, size); return 0; } /* * return the first IP Address associated with an interface */ int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) int v, atype; void *ifptr; struct in_addr *inp, *inpmask; ipf_stack_t *ifs; { struct ifnet *ifp = ifptr; #ifdef __sgi struct in_ifaddr *ifa; #else struct ifaddr *ifa; #endif #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) ifa = ifp->if_addrlist.tqh_first; #else # ifdef __sgi ifa = (struct in_ifaddr *)ifp->in_ifaddr; # else ifa = ifp->if_addrlist; # endif #endif if (ifa != NULL) { struct sockaddr_in *sin, mask; mask.sin_addr.s_addr = 0xffffffff; #ifdef __sgi sin = (struct sockaddr_in *)&ifa->ia_addr; #else sin = (struct sockaddr_in *)&ifa->ifa_addr; #endif return fr_ifpfillv4addr(atype, sin, &mask, inp, inpmask); } return 0; } /* * This function is not meant to be random, rather just produce a * sequence of numbers that isn't linear to show "randomness". */ u_32_t ipf_random() { static u_int last = 0xa5a5a5a5; static int calls = 0; int number; calls++; /* * These are deliberately chosen to ensure that there is some * attempt to test whether the output covers the range in test n18. */ switch (calls) { case 1 : number = 0; break; case 2 : number = 4; break; case 3 : number = 3999; break; case 4 : number = 4000; break; case 5 : number = 48999; break; case 6 : number = 49000; break; default : number = last; last *= calls; last++; number ^= last; break; } return number; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #ifdef __FreeBSD__ # ifndef __FreeBSD_cc_version # include # else # if __FreeBSD_cc_version < 430000 # include # endif # endif #endif #include "ipf.h" #include #include #include "netinet/ipl.h" #include "ipfzone.h" #if !defined(lint) static const char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-2000 Darren Reed"; static const char rcsid[] = "@(#)$Id: ipf.c,v 1.35.2.3 2004/12/15 18:27:17 darrenr Exp $"; #endif #if !defined(__SVR4) && defined(__GNUC__) extern char *index __P((const char *, int)); #endif extern char *optarg; extern int optind; extern frentry_t *frtop; void ipf_frsync __P((void)); void zerostats __P((void)); int main __P((int, char *[])); int opts = 0; int outputc = 0; int use_inet6 = 0; static void procfile __P((char *, char *)), flushfilter __P((char *)); static void set_state __P((u_int)), showstats __P((friostat_t *)); static void packetlogon __P((char *)), swapactive __P((void)); static int opendevice __P((char *, int)); static void closedevice __P((void)); static char *ipfname = IPL_NAME; static void usage __P((void)); static int showversion __P((void)); static int get_flags __P((void)); static void ipf_interceptadd __P((int, ioctlfunc_t, void *)); static int fd = -1; static ioctlfunc_t iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl, ioctl, ioctl, ioctl, ioctl, ioctl }; static void usage() { fprintf(stderr, "usage: ipf [-6AdDEGInoPrRsvVyzZ] %s %s %s", "[-l block|pass|nomatch|state|nat]", "[-cc] [-F i|o|a|s|S|u]", "[-f filename] [-T ] [zonename]\n"); exit(1); } int main(argc,argv) int argc; char *argv[]; { int c; const char *optstr = "6Ac:dDEf:F:GIl:noPrRsT:vVyzZ"; if (argc < 2) usage(); /* * We need to set the zone name before calling the functions * in the switch statement below. Note that ipf.c differs from the other * tools in the ipfilter suite: the zone name is specified as the * last argument, while the other tools use the -z option. ipf * already has a -z option, so the last argument is used instead. */ getzonearg(argc, argv, optstr); while ((c = getopt(argc, argv, optstr)) != -1) { switch (c) { case '?' : usage(); break; #ifdef USE_INET6 case '6' : use_inet6 = 1; break; #endif case 'A' : opts &= ~OPT_INACTIVE; break; case 'c' : if (strcmp(optarg, "c") == 0) outputc = 1; break; case 'E' : set_state((u_int)1); break; case 'D' : set_state((u_int)0); break; case 'd' : opts ^= OPT_DEBUG; break; case 'f' : procfile(argv[0], optarg); break; case 'F' : flushfilter(optarg); break; case 'G' : /* Already handled by getzonearg() above */ break; case 'I' : opts ^= OPT_INACTIVE; break; case 'l' : packetlogon(optarg); break; case 'n' : opts ^= OPT_DONOTHING; break; case 'o' : break; case 'P' : ipfname = IPAUTH_NAME; break; case 'R' : opts ^= OPT_NORESOLVE; break; case 'r' : opts ^= OPT_REMOVE; break; case 's' : swapactive(); break; case 'T' : if (opendevice(ipfname, 1) >= 0) ipf_dotuning(fd, optarg, ioctl); break; case 'v' : opts += OPT_VERBOSE; break; case 'V' : if (showversion()) exit(1); break; case 'y' : ipf_frsync(); break; case 'z' : opts ^= OPT_ZERORULEST; break; case 'Z' : zerostats(); break; } } if (optind < 2) usage(); if (fd != -1) (void) close(fd); return(0); /* NOTREACHED */ } static int opendevice(ipfdev, check) char *ipfdev; int check; { if (opts & OPT_DONOTHING) return -2; if (check && checkrev(ipfname) == -1) { fprintf(stderr, "User/kernel version check failed\n"); return -2; } if (!ipfdev) ipfdev = ipfname; if (fd == -1) if ((fd = open(ipfdev, O_RDWR)) == -1) if ((fd = open(ipfdev, O_RDONLY)) == -1) perror("open device"); if (setzone(fd) != 0) { close(fd); return -2; } return fd; } static void closedevice() { close(fd); fd = -1; } static int get_flags() { int i; if ((opendevice(ipfname, 1) != -2) && (ioctl(fd, SIOCGETFF, &i) == -1)) { perror("SIOCGETFF"); return 0; } return i; } static void set_state(enable) u_int enable; { if (opendevice(ipfname, 0) != -2) if (ioctl(fd, SIOCFRENB, &enable) == -1) { if (errno == EBUSY) fprintf(stderr, "IP FIlter: already initialized\n"); else perror("SIOCFRENB"); } return; } static void procfile(name, file) char *name, *file; { (void) opendevice(ipfname, 1); initparse(); ipf_parsefile(fd, ipf_interceptadd, iocfunctions, file); if (outputc) { printC(0); printC(1); emit(-1, -1, NULL, NULL); } } static void ipf_interceptadd(fd, ioctlfunc, ptr) int fd; ioctlfunc_t ioctlfunc; void *ptr; { if (outputc) printc(ptr); ipf_addrule(fd, ioctlfunc, ptr); } static void packetlogon(opt) char *opt; { int flag, xfd, logopt, change = 0; flag = get_flags(); if (flag != 0) { if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) printf("log flag is currently %#x\n", flag); } flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK); if (strstr(opt, "pass")) { flag |= FF_LOGPASS; if (opts & OPT_VERBOSE) printf("set log flag: pass\n"); change = 1; } if (strstr(opt, "nomatch")) { flag |= FF_LOGNOMATCH; if (opts & OPT_VERBOSE) printf("set log flag: nomatch\n"); change = 1; } if (strstr(opt, "block") || index(opt, 'd')) { flag |= FF_LOGBLOCK; if (opts & OPT_VERBOSE) printf("set log flag: block\n"); change = 1; } if (strstr(opt, "none")) { if (opts & OPT_VERBOSE) printf("disable all log flags\n"); change = 1; } if (change == 1) { if (opendevice(ipfname, 1) != -2 && (ioctl(fd, SIOCSETFF, &flag) != 0)) perror("ioctl(SIOCSETFF)"); } if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { flag = get_flags(); printf("log flags are now %#x\n", flag); } if (strstr(opt, "state")) { if (opts & OPT_VERBOSE) printf("set state log flag\n"); xfd = open(IPSTATE_NAME, O_RDWR); if (xfd >= 0 && setzone(xfd) != 0) { close(xfd); xfd = -1; } if (xfd >= 0) { logopt = 0; if (ioctl(xfd, SIOCGETLG, &logopt)) perror("ioctl(SIOCGETLG)"); else { logopt = 1 - logopt; if (ioctl(xfd, SIOCSETLG, &logopt)) perror("ioctl(SIOCSETLG)"); } close(xfd); } } if (strstr(opt, "nat")) { if (opts & OPT_VERBOSE) printf("set nat log flag\n"); xfd = open(IPNAT_NAME, O_RDWR); if (xfd >= 0 && setzone(xfd) != 0) { close(xfd); xfd = -1; } if (xfd >= 0) { logopt = 0; if (ioctl(xfd, SIOCGETLG, &logopt)) perror("ioctl(SIOCGETLG)"); else { logopt = 1 - logopt; if (ioctl(xfd, SIOCSETLG, &logopt)) perror("ioctl(SIOCSETLG)"); } close(xfd); } } } static void flushfilter(arg) char *arg; { int fl = 0, rem; if (!arg || !*arg) return; if (!strcmp(arg, "s") || !strcmp(arg, "S")) { if (*arg == 'S') fl = FLUSH_TABLE_ALL; else fl = FLUSH_TABLE_CLOSING; rem = fl; closedevice(); if (opendevice(IPSTATE_NAME, 1) == -2) exit(1); if (!(opts & OPT_DONOTHING)) { if (use_inet6) { if (ioctl(fd, SIOCIPFL6, &fl) == -1) { perror("ioctl(SIOCIPFL6)"); exit(1); } } else { if (ioctl(fd, SIOCIPFFL, &fl) == -1) { perror("ioctl(SIOCIPFFL)"); exit(1); } } } if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { printf("remove flags %s (%d)\n", arg, rem); printf("removed %d filter rules\n", fl); } closedevice(); return; } #ifdef SIOCIPFFA if (!strcmp(arg, "u")) { closedevice(); /* * Flush auth rules and packets */ if (opendevice(IPL_AUTH, 1) == -1) perror("open(IPL_AUTH)"); else { if (ioctl(fd, SIOCIPFFA, &fl) == -1) perror("ioctl(SIOCIPFFA)"); } closedevice(); return; } #endif if (strchr(arg, 'i') || strchr(arg, 'I')) fl = FR_INQUE; if (strchr(arg, 'o') || strchr(arg, 'O')) fl = FR_OUTQUE; if (strchr(arg, 'a') || strchr(arg, 'A')) fl = FR_OUTQUE|FR_INQUE; if (opts & OPT_INACTIVE) fl |= FR_INACTIVE; rem = fl; if (opendevice(ipfname, 1) == -2) exit(1); if (!(opts & OPT_DONOTHING)) { if (use_inet6) { if (ioctl(fd, SIOCIPFL6, &fl) == -1) { perror("ioctl(SIOCIPFL6)"); exit(1); } } else { if (ioctl(fd, SIOCIPFFL, &fl) == -1) { perror("ioctl(SIOCIPFFL)"); exit(1); } } } if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "", (rem & FR_OUTQUE) ? "O" : "", rem); printf("removed %d filter rules\n", fl); } return; } static void swapactive() { int in = 2; if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1) perror("ioctl(SIOCSWAPA)"); else printf("Set %d now inactive\n", in); } void ipf_frsync() { int frsyn = 0; if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1) perror("SIOCFRSYN"); else printf("filter sync'd\n"); } void zerostats() { friostat_t fio; friostat_t *fiop = &fio; if (opendevice(ipfname, 1) != -2) { if (ioctl(fd, SIOCFRZST, &fiop) == -1) { perror("ioctl(SIOCFRZST)"); exit(-1); } showstats(fiop); } } /* * read the kernel stats for packets blocked and passed */ static void showstats(fp) friostat_t *fp; { printf("bad packets:\t\tin %lu\tout %lu\n", fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu", fp->f_st[0].fr_block, fp->f_st[0].fr_pass, fp->f_st[0].fr_nom); printf(" counted %lu\n", fp->f_st[0].fr_acct); printf("output packets:\t\tblocked %lu passed %lu nomatch %lu", fp->f_st[1].fr_block, fp->f_st[1].fr_pass, fp->f_st[1].fr_nom); printf(" counted %lu\n", fp->f_st[0].fr_acct); printf(" input packets logged:\tblocked %lu passed %lu\n", fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl); printf("output packets logged:\tblocked %lu passed %lu\n", fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl); printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n", fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip, fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip); } static int showversion() { struct friostat fio; ipfobj_t ipfo; u_32_t flags; char *s; int vfd; bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_size = sizeof(fio); ipfo.ipfo_ptr = (void *)&fio; ipfo.ipfo_type = IPFOBJ_IPFSTAT; printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t)); if ((vfd = open(ipfname, O_RDONLY)) == -1) { perror("open device"); return 1; } if (setzone(vfd) != 0) { close(vfd); return 1; } if (ioctl(vfd, SIOCGETFS, &ipfo)) { perror("ioctl(SIOCGETFS)"); close(vfd); return 1; } close(vfd); flags = get_flags(); printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version), (int)sizeof(fio.f_version), fio.f_version); printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no"); printf("Log Flags: %#x = ", flags); s = ""; if (flags & FF_LOGPASS) { printf("pass"); s = ", "; } if (flags & FF_LOGBLOCK) { printf("%sblock", s); s = ", "; } if (flags & FF_LOGNOMATCH) { printf("%snomatch", s); s = ", "; } if (flags & FF_BLOCKNONIP) { printf("%snonip", s); s = ", "; } if (!*s) printf("none set"); putchar('\n'); printf("Default: "); if (FR_ISPASS(fio.f_defpass)) s = "pass"; else if (FR_ISBLOCK(fio.f_defpass)) s = "block"; else s = "nomatch -> block"; printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un"); printf("Active list: %d\n", fio.f_active); printf("Feature mask: %#x\n", fio.f_features); return 0; } %{ /* * Copyright (C) 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" #include #include #ifdef IPFILTER_BPF # include "pcap-bpf.h" # define _NET_BPF_H_ # include #endif #include "netinet/ip_pool.h" #include "netinet/ip_htable.h" #include "netinet/ipl.h" #include "ipf_l.h" #define YYDEBUG 1 #define DOALL(x) for (fr = frc; fr != NULL; fr = fr->fr_next) { x } #define DOREM(x) for (; fr != NULL; fr = fr->fr_next) { x } #define OPTION_LOG 0x1 #define OPTION_QUICK 0x2 #define OPTION_DUP 0x4 #define OPTION_PROUTE 0x8 #define OPTION_ON 0x10 #define OPTION_REPLYTO 0x20 #define OPTION_FROUTE 0x40 extern int yyerror __P((const char *)); extern int yyparse __P((void)); extern int yylex __P((void)); extern int yydebug; extern FILE *yyin; extern int yylineNum; static void newrule __P((void)); static void setipftype __P((void)); static u_32_t lookuphost __P((char *, i6addr_t *)); static void dobpf __P((int, char *)); static void resetaddr __P((void)); static struct alist_s *newalist __P((struct alist_s *)); static u_int makehash __P((struct alist_s *)); static int makepool __P((struct alist_s *)); static frentry_t *addrule __P((void)); static void setsyslog __P((void)); static void unsetsyslog __P((void)); static void fillgroup __P((frentry_t *)); frentry_t *fr = NULL, *frc = NULL, *frtop = NULL, *frold = NULL; static int ifpflag = 0; static int nowith = 0; static int dynamic = -1; static int pooled = 0; static int hashed = 0; static int nrules = 0; static int newlist = 0; static int added = 0; static int ipffd = -1; static int ruleopts = 0; static int *yycont = 0; static ioctlfunc_t ipfioctl[IPL_LOGSIZE]; static addfunc_t ipfaddfunc = NULL; static struct wordtab ipfwords[96]; static struct wordtab addrwords[4]; static struct wordtab maskwords[5]; static struct wordtab icmpcodewords[17]; static struct wordtab icmptypewords[16]; static struct wordtab ipv4optwords[25]; static struct wordtab ipv4secwords[9]; static struct wordtab ipv6optwords[8]; static struct wordtab logwords[33]; static int set_ipv6_addr = 0; %} %union { char *str; u_32_t num; struct in_addr ipa; frentry_t fr; frtuc_t *frt; struct alist_s *alist; u_short port; struct { u_short p1; u_short p2; int pc; } pc; struct { union i6addr a; union i6addr m; } ipp; union i6addr ip6; }; %type portnum %type facility priority icmpcode seclevel secname icmptype %type opt compare range opttype flagset optlist ipv6hdrlist ipv6hdr %type portc porteq %type ipv4 ipv4_16 ipv4_24 %type hostname mask %type addr ipaddr %type servicename name interfacename %type portrange portcomp %type addrlist poollist %token YY_NUMBER YY_HEX %token YY_STR %token YY_COMMENT %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT %token YY_RANGE_OUT YY_RANGE_IN %token YY_IPV6 %token IPFY_PASS IPFY_BLOCK IPFY_COUNT IPFY_CALL %token IPFY_RETICMP IPFY_RETRST IPFY_RETICMPASDST %token IPFY_IN IPFY_OUT %token IPFY_QUICK IPFY_ON IPFY_OUTVIA IPFY_INVIA %token IPFY_DUPTO IPFY_TO IPFY_FROUTE IPFY_REPLY_TO IPFY_ROUTETO %token IPFY_TOS IPFY_TTL IPFY_PROTO %token IPFY_HEAD IPFY_GROUP %token IPFY_AUTH IPFY_PREAUTH %token IPFY_LOG IPFY_BODY IPFY_FIRST IPFY_LEVEL IPFY_ORBLOCK %token IPFY_LOGTAG IPFY_MATCHTAG IPFY_SETTAG IPFY_SKIP %token IPFY_FROM IPFY_ALL IPFY_ANY IPFY_BPFV4 IPFY_BPFV6 IPFY_POOL IPFY_HASH %token IPFY_PPS %token IPFY_ESP IPFY_AH %token IPFY_WITH IPFY_AND IPFY_NOT IPFY_NO IPFY_OPT %token IPFY_TCPUDP IPFY_TCP IPFY_UDP %token IPFY_FLAGS IPFY_MULTICAST %token IPFY_MASK IPFY_BROADCAST IPFY_NETWORK IPFY_NETMASKED IPFY_PEER %token IPFY_PORT %token IPFY_NOW %token IPFY_ICMP IPFY_ICMPTYPE IPFY_ICMPCODE %token IPFY_IPOPTS IPFY_SHORT IPFY_NAT IPFY_BADSRC IPFY_LOWTTL IPFY_FRAG %token IPFY_MBCAST IPFY_BAD IPFY_BADNAT IPFY_OOW IPFY_NEWISN IPFY_NOICMPERR %token IPFY_KEEP IPFY_STATE IPFY_FRAGS IPFY_LIMIT IPFY_STRICT IPFY_AGE %token IPFY_SYNC IPFY_FRAGBODY %token IPFY_IPOPT_NOP IPFY_IPOPT_RR IPFY_IPOPT_ZSU IPFY_IPOPT_MTUP %token IPFY_IPOPT_MTUR IPFY_IPOPT_ENCODE IPFY_IPOPT_TS IPFY_IPOPT_TR %token IPFY_IPOPT_SEC IPFY_IPOPT_LSRR IPFY_IPOPT_ESEC IPFY_IPOPT_CIPSO %token IPFY_IPOPT_SATID IPFY_IPOPT_SSRR IPFY_IPOPT_ADDEXT IPFY_IPOPT_VISA %token IPFY_IPOPT_IMITD IPFY_IPOPT_EIP IPFY_IPOPT_FINN IPFY_IPOPT_DPS %token IPFY_IPOPT_SDB IPFY_IPOPT_NSAPA IPFY_IPOPT_RTRALRT IPFY_IPOPT_UMP %token IPFY_SECCLASS IPFY_SEC_UNC IPFY_SEC_CONF IPFY_SEC_RSV1 IPFY_SEC_RSV2 %token IPFY_SEC_RSV4 IPFY_SEC_SEC IPFY_SEC_TS IPFY_SEC_RSV3 %token IPF6_V6HDRS IPFY_IPV6OPT IPFY_IPV6OPT_DSTOPTS IPFY_IPV6OPT_HOPOPTS %token IPFY_IPV6OPT_IPV6 IPFY_IPV6OPT_NONE IPFY_IPV6OPT_ROUTING %token IPFY_ICMPT_UNR IPFY_ICMPT_ECHO IPFY_ICMPT_ECHOR IPFY_ICMPT_SQUENCH %token IPFY_ICMPT_REDIR IPFY_ICMPT_TIMEX IPFY_ICMPT_PARAMP IPFY_ICMPT_TIMEST %token IPFY_ICMPT_TIMESTREP IPFY_ICMPT_INFOREQ IPFY_ICMPT_INFOREP %token IPFY_ICMPT_MASKREQ IPFY_ICMPT_MASKREP IPFY_ICMPT_ROUTERAD %token IPFY_ICMPT_ROUTERSOL %token IPFY_ICMPC_NETUNR IPFY_ICMPC_HSTUNR IPFY_ICMPC_PROUNR IPFY_ICMPC_PORUNR %token IPFY_ICMPC_NEEDF IPFY_ICMPC_SRCFAIL IPFY_ICMPC_NETUNK IPFY_ICMPC_HSTUNK %token IPFY_ICMPC_ISOLATE IPFY_ICMPC_NETPRO IPFY_ICMPC_HSTPRO %token IPFY_ICMPC_NETTOS IPFY_ICMPC_HSTTOS IPFY_ICMPC_FLTPRO IPFY_ICMPC_HSTPRE %token IPFY_ICMPC_CUTPRE %token IPFY_FAC_KERN IPFY_FAC_USER IPFY_FAC_MAIL IPFY_FAC_DAEMON IPFY_FAC_AUTH %token IPFY_FAC_SYSLOG IPFY_FAC_LPR IPFY_FAC_NEWS IPFY_FAC_UUCP IPFY_FAC_CRON %token IPFY_FAC_LOCAL0 IPFY_FAC_LOCAL1 IPFY_FAC_LOCAL2 IPFY_FAC_LOCAL3 %token IPFY_FAC_LOCAL4 IPFY_FAC_LOCAL5 IPFY_FAC_LOCAL6 IPFY_FAC_LOCAL7 %token IPFY_FAC_SECURITY IPFY_FAC_FTP IPFY_FAC_AUTHPRIV IPFY_FAC_AUDIT %token IPFY_FAC_LFMT IPFY_FAC_CONSOLE %token IPFY_PRI_EMERG IPFY_PRI_ALERT IPFY_PRI_CRIT IPFY_PRI_ERR IPFY_PRI_WARN %token IPFY_PRI_NOTICE IPFY_PRI_INFO IPFY_PRI_DEBUG %token IPFY_SET_LOOPBACK IPFY_SET %% file: line | assign | file line | file assign ; line: xx rule { while ((fr = frtop) != NULL) { frtop = fr->fr_next; fr->fr_next = NULL; (*ipfaddfunc)(ipffd, ipfioctl[IPL_LOGIPF], fr); fr->fr_next = frold; frold = fr; } resetlexer(); } | YY_COMMENT | set ; xx: { newrule(); } ; assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); resetlexer(); free($1); free($3); yyvarnext = 0; } ; assigning: '=' { yyvarnext = 1; } ; set: IPFY_SET IPFY_SET_LOOPBACK YY_STR ';' { int data; if (frold != NULL) { yyerror("ipf rules before \"set\""); return 0; } if (!strcmp($3, "true")) data = 1; else if (!strcmp($3, "false")) data = 0; else { yyerror("invalid argument for ipf_loopback"); return 0; } if (((opts & OPT_DONOTHING) == 0) && (ioctl(ipffd, SIOCIPFLP, &data) == -1)) perror("ioctl(SIOCIPFLP)"); } ; rule: inrule eol | outrule eol ; eol: | ';' ; inrule: rulehead markin { ruleopts = 0; } inopts rulemain ruletail intag ruletail2 ; outrule: rulehead markout { ruleopts = 0; } outopts rulemain ruletail outtag ruletail2 ; rulehead: collection action | insert collection action ; markin: IPFY_IN { fr->fr_flags |= FR_INQUE; } ; markout: IPFY_OUT { fr->fr_flags |= FR_OUTQUE; } ; rulemain: ipfrule | bpfrule ; ipfrule: tos ttl proto ip ; bpfrule: IPFY_BPFV4 '{' YY_STR '}' { dobpf(4, $3); free($3); } | IPFY_BPFV6 '{' YY_STR '}' { dobpf(6, $3); free($3); } ; ruletail: with keep head group ; ruletail2: pps age new ; intag: settagin matchtagin ; outtag: settagout matchtagout ; insert: '@' YY_NUMBER { fr->fr_hits = (U_QUAD_T)$2 + 1; } ; collection: | YY_NUMBER { fr->fr_collect = $1; } ; action: block | IPFY_PASS { fr->fr_flags |= FR_PASS; } | log | IPFY_COUNT { fr->fr_flags |= FR_ACCOUNT; } | auth | IPFY_SKIP YY_NUMBER { fr->fr_flags |= FR_SKIP; fr->fr_arg = $2; } | IPFY_CALL func | IPFY_CALL IPFY_NOW func { fr->fr_flags |= FR_CALLNOW; } ; block: blocked | blocked blockreturn ; blocked: IPFY_BLOCK { fr->fr_flags = FR_BLOCK; } ; blockreturn: IPFY_RETICMP { fr->fr_flags |= FR_RETICMP; } | IPFY_RETICMP returncode { fr->fr_flags |= FR_RETICMP; } | IPFY_RETICMPASDST { fr->fr_flags |= FR_FAKEICMP; } | IPFY_RETICMPASDST returncode { fr->fr_flags |= FR_FAKEICMP; } | IPFY_RETRST { fr->fr_flags |= FR_RETRST; } ; log: IPFY_LOG { fr->fr_flags |= FR_LOG; } | IPFY_LOG logoptions { fr->fr_flags |= FR_LOG; } ; auth: IPFY_AUTH { fr->fr_flags |= FR_AUTH; } | IPFY_AUTH IPFY_RETRST { fr->fr_flags |= (FR_AUTH|FR_RETRST);} | IPFY_PREAUTH { fr->fr_flags |= FR_PREAUTH; } ; func: YY_STR '/' YY_NUMBER { fr->fr_func = nametokva($1, ipfioctl[IPL_LOGIPF]); fr->fr_arg = $3; free($1); } ; inopts: | inopts inopt ; inopt: logopt { if ( ruleopts & OPTION_LOG ) yyerror("Duplicate log option"); ruleopts |= OPTION_LOG; } | quick { if ( ruleopts & OPTION_QUICK ) yyerror("Duplicate quick option"); ruleopts |= OPTION_QUICK; } | on { if ( ruleopts & OPTION_ON ) yyerror("Duplicate on option"); ruleopts |= OPTION_ON; } | dup { if ( ruleopts & OPTION_DUP ) yyerror("Duplicate dup option"); ruleopts |= OPTION_DUP; } | froute { if ( ruleopts & OPTION_FROUTE ) yyerror("Duplicate froute option"); ruleopts |= OPTION_FROUTE; } | proute { if ( ruleopts & OPTION_PROUTE ) yyerror("Duplicate proute option"); ruleopts |= OPTION_PROUTE; } | replyto { if ( ruleopts & OPTION_REPLYTO ) yyerror("Duplicate replyto option"); ruleopts |= OPTION_REPLYTO; } ; outopts: | outopts outopt ; outopt: logopt { if ( ruleopts & OPTION_LOG ) yyerror("Duplicate log option"); ruleopts |= OPTION_LOG; } | quick { if ( ruleopts & OPTION_QUICK ) yyerror("Duplicate quick option"); ruleopts |= OPTION_QUICK; } | on { if ( ruleopts & OPTION_ON ) yyerror("Duplicate on option"); ruleopts |= OPTION_ON; } | dup { if ( ruleopts & OPTION_DUP ) yyerror("Duplicate dup option"); ruleopts |= OPTION_DUP; } | proute { if ( ruleopts & OPTION_PROUTE ) yyerror("Duplicate proute option"); ruleopts |= OPTION_PROUTE; } | replyto { if ( ruleopts & OPTION_REPLYTO ) yyerror("Duplicate replyto option"); ruleopts |= OPTION_REPLYTO; } ; tos: | settos YY_NUMBER { DOALL(fr->fr_tos = $2; fr->fr_mtos = 0xff;) } | settos YY_HEX { DOALL(fr->fr_tos = $2; fr->fr_mtos = 0xff;) } | settos lstart toslist lend ; settos: IPFY_TOS { setipftype(); } ; toslist: YY_NUMBER { DOALL(fr->fr_tos = $1; fr->fr_mtos = 0xff;) } | YY_HEX { DOREM(fr->fr_tos = $1; fr->fr_mtos = 0xff;) } | toslist lmore YY_NUMBER { DOREM(fr->fr_tos = $3; fr->fr_mtos = 0xff;) } | toslist lmore YY_HEX { DOREM(fr->fr_tos = $3; fr->fr_mtos = 0xff;) } ; ttl: | setttl YY_NUMBER { DOALL(fr->fr_ttl = $2; fr->fr_mttl = 0xff;) } | setttl lstart ttllist lend ; lstart: '(' { newlist = 1; fr = frc; added = 0; } ; lend: ')' { nrules += added; } ; lmore: lanother { if (newlist == 1) { newlist = 0; } fr = addrule(); if (yycont != NULL) *yycont = 1; } ; lanother: | ',' ; setttl: IPFY_TTL { setipftype(); } ; ttllist: YY_NUMBER { DOREM(fr->fr_ttl = $1; fr->fr_mttl = 0xff;) } | ttllist lmore YY_NUMBER { DOREM(fr->fr_ttl = $3; fr->fr_mttl = 0xff;) } ; proto: | protox protocol { yyresetdict(); } ; protox: IPFY_PROTO { setipftype(); fr = frc; yysetdict(NULL); } ; ip: srcdst flags icmp ; group: | IPFY_GROUP YY_STR { DOALL(strncpy(fr->fr_group, $2, \ FR_GROUPLEN); \ fillgroup(fr);); free($2); } | IPFY_GROUP YY_NUMBER { DOALL(sprintf(fr->fr_group, "%d", \ $2); \ fillgroup(fr);) } ; head: | IPFY_HEAD YY_STR { DOALL(strncpy(fr->fr_grhead, $2, \ FR_GROUPLEN);); free($2); } | IPFY_HEAD YY_NUMBER { DOALL(sprintf(fr->fr_grhead, "%d", \ $2);) } ; settagin: | IPFY_SETTAG '(' taginlist ')' ; taginlist: taginspec | taginlist ',' taginspec ; taginspec: logtag |nattag ; nattag: IPFY_NAT '=' YY_STR { DOALL(strncpy(fr->fr_nattag.ipt_tag,\ $3, IPFTAG_LEN);); free($3); } | IPFY_NAT '=' YY_NUMBER { DOALL(sprintf(fr->fr_nattag.ipt_tag,\ "%d", $3 & 0xffffffff);) } ; logtag: IPFY_LOG '=' YY_NUMBER { DOALL(fr->fr_logtag = $3;) } ; settagout: | IPFY_SETTAG '(' tagoutlist ')' ; tagoutlist: tagoutspec | tagoutlist ',' tagoutspec ; tagoutspec: logtag | nattag ; matchtagin: | IPFY_MATCHTAG '(' tagoutlist ')' ; matchtagout: | IPFY_MATCHTAG '(' taginlist ')' ; pps: | IPFY_PPS YY_NUMBER { DOALL(fr->fr_pps = $2;) } ; new: | savegroup file restoregroup ; savegroup: '{' ; restoregroup: '}' ; logopt: log ; quick: IPFY_QUICK { fr->fr_flags |= FR_QUICK; } ; on: IPFY_ON onname | IPFY_ON onname IPFY_INVIA vianame | IPFY_ON onname IPFY_OUTVIA vianame ; onname: interfacename { strncpy(fr->fr_ifnames[0], $1, sizeof(fr->fr_ifnames[0])); free($1); } | interfacename ',' interfacename { strncpy(fr->fr_ifnames[0], $1, sizeof(fr->fr_ifnames[0])); free($1); strncpy(fr->fr_ifnames[1], $3, sizeof(fr->fr_ifnames[1])); free($3); } ; vianame: name { strncpy(fr->fr_ifnames[2], $1, sizeof(fr->fr_ifnames[2])); free($1); } | name ',' name { strncpy(fr->fr_ifnames[2], $1, sizeof(fr->fr_ifnames[2])); free($1); strncpy(fr->fr_ifnames[3], $3, sizeof(fr->fr_ifnames[3])); free($3); } ; dup: IPFY_DUPTO name { strncpy(fr->fr_dif.fd_ifname, $2, sizeof(fr->fr_dif.fd_ifname)); free($2); fr->fr_flags |= FR_DUP; } | IPFY_DUPTO name duptoseparator hostname { strncpy(fr->fr_dif.fd_ifname, $2, sizeof(fr->fr_dif.fd_ifname)); if (use_inet6 == 0) fr->fr_dif.fd_ip = $4.in4; else bcopy(&$4, &fr->fr_dif.fd_ip6, sizeof(fr->fr_dif.fd_ip6)); yyexpectaddr = 0; fr->fr_flags |= FR_DUP; free($2); } | IPFY_DUPTO name duptoseparator YY_IPV6 { strncpy(fr->fr_dif.fd_ifname, $2, sizeof(fr->fr_dif.fd_ifname)); bcopy(&$4, &fr->fr_dif.fd_ip6, sizeof(fr->fr_dif.fd_ip6)); yyexpectaddr = 0; fr->fr_flags |= FR_DUP; free($2); } ; duptoseparator: ':' { yyexpectaddr = 1; yycont = &yyexpectaddr; resetaddr(); } ; froute: IPFY_FROUTE { fr->fr_flags |= FR_FASTROUTE; } ; proute: routeto name { strncpy(fr->fr_tif.fd_ifname, $2, sizeof(fr->fr_tif.fd_ifname)); free($2); } | routeto name duptoseparator hostname { strncpy(fr->fr_tif.fd_ifname, $2, sizeof(fr->fr_tif.fd_ifname)); if (use_inet6 == 0) fr->fr_tif.fd_ip = $4.in4; else bcopy(&$4, &fr->fr_tif.fd_ip6, sizeof(fr->fr_tif.fd_ip6)); yyexpectaddr = 0; free($2); } | routeto name duptoseparator YY_IPV6 { strncpy(fr->fr_tif.fd_ifname, $2, sizeof(fr->fr_tif.fd_ifname)); bcopy(&$4, &fr->fr_tif.fd_ip6, sizeof(fr->fr_tif.fd_ip6)); yyexpectaddr = 0; free($2); } ; routeto: IPFY_TO | IPFY_ROUTETO ; replyto: IPFY_REPLY_TO name { strncpy(fr->fr_rif.fd_ifname, $2, sizeof(fr->fr_rif.fd_ifname)); free($2); } | IPFY_REPLY_TO name duptoseparator hostname { strncpy(fr->fr_rif.fd_ifname, $2, sizeof(fr->fr_rif.fd_ifname)); if (use_inet6 == 0) fr->fr_rif.fd_ip = $4.in4; else bcopy(&$4, &fr->fr_rif.fd_ip6, sizeof(fr->fr_rif.fd_ip6)); yyexpectaddr = 0; free($2); } | IPFY_REPLY_TO name duptoseparator YY_IPV6 { strncpy(fr->fr_rif.fd_ifname, $2, sizeof(fr->fr_rif.fd_ifname)); bcopy(&$4, &fr->fr_rif.fd_ip6, sizeof(fr->fr_rif.fd_ip6)); yyexpectaddr = 0; free($2); } ; logoptions: logoption | logoptions logoption ; logoption: IPFY_BODY { fr->fr_flags |= FR_LOGBODY; } | IPFY_FIRST { fr->fr_flags |= FR_LOGFIRST; } | IPFY_ORBLOCK { fr->fr_flags |= FR_LOGORBLOCK; } | level loglevel { unsetsyslog(); } ; returncode: starticmpcode icmpcode ')' { fr->fr_icode = $2; yyresetdict(); } ; starticmpcode: '(' { yysetdict(icmpcodewords); } ; srcdst: | IPFY_ALL | fromto ; protocol: YY_NUMBER { DOREM(fr->fr_proto = $1; \ fr->fr_mproto = 0xff;) } | YY_STR { if (!strcmp($1, "tcp-udp")) { DOREM(fr->fr_flx |= FI_TCPUDP; \ fr->fr_mflx |= FI_TCPUDP;) } else { int p = getproto($1); if (p == -1) yyerror("protocol unknown"); DOREM(fr->fr_proto = p; \ fr->fr_mproto = 0xff;) } free($1); } | YY_STR nextstring YY_STR { if (!strcmp($1, "tcp") && !strcmp($3, "udp")) { DOREM(fr->fr_flx |= FI_TCPUDP; \ fr->fr_mflx |= FI_TCPUDP;) } else YYERROR; free($1); free($3); } ; nextstring: '/' { yysetdict(NULL); } ; fromto: from srcobject to dstobject { yyexpectaddr = 0; yycont = NULL; } | to dstobject { yyexpectaddr = 0; yycont = NULL; } | from srcobject { yyexpectaddr = 0; yycont = NULL; } ; from: IPFY_FROM { setipftype(); if (fr == NULL) fr = frc; yyexpectaddr = 1; if (yydebug) printf("set yyexpectaddr\n"); yycont = &yyexpectaddr; yysetdict(addrwords); resetaddr(); } ; to: IPFY_TO { if (fr == NULL) fr = frc; yyexpectaddr = 1; if (yydebug) printf("set yyexpectaddr\n"); yycont = &yyexpectaddr; yysetdict(addrwords); resetaddr(); } ; with: | andwith withlist ; andwith: IPFY_WITH { nowith = 0; setipftype(); } | IPFY_AND { nowith = 0; setipftype(); } ; flags: | startflags flagset { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = FR_TCPFMAX;) } | startflags flagset '/' flagset { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) } | startflags '/' flagset { DOALL(fr->fr_tcpf = 0; fr->fr_tcpfm = $3;) } | startflags YY_NUMBER { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = FR_TCPFMAX;) } | startflags '/' YY_NUMBER { DOALL(fr->fr_tcpf = 0; fr->fr_tcpfm = $3;) } | startflags YY_NUMBER '/' YY_NUMBER { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) } | startflags flagset '/' YY_NUMBER { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) } | startflags YY_NUMBER '/' flagset { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) } ; startflags: IPFY_FLAGS { if (frc->fr_type != FR_T_IPF) yyerror("flags with non-ipf type rule"); if (frc->fr_proto != IPPROTO_TCP) yyerror("flags with non-TCP rule"); } ; flagset: YY_STR { $$ = tcpflags($1); free($1); } | YY_HEX { $$ = $1; } ; srcobject: { yyresetdict(); } fromport | srcaddr srcport | '!' srcaddr srcport { DOALL(fr->fr_flags |= FR_NOTSRCIP;) } ; srcaddr: addr { DOREM(bcopy(&($1.a), &fr->fr_ip.fi_src, sizeof($1.a)); \ bcopy(&($1.m), &fr->fr_mip.fi_src, sizeof($1.m)); \ if (dynamic != -1) { \ fr->fr_satype = ifpflag; \ fr->fr_ipf->fri_sifpidx = dynamic; \ } else if (pooled || hashed) \ fr->fr_satype = FRI_LOOKUP;) } | lstart srcaddrlist lend ; srcaddrlist: addr { DOREM(bcopy(&($1.a), &fr->fr_ip.fi_src, sizeof($1.a)); \ bcopy(&($1.m), &fr->fr_mip.fi_src, sizeof($1.m)); \ if (dynamic != -1) { \ fr->fr_satype = ifpflag; \ fr->fr_ipf->fri_sifpidx = dynamic; \ } else if (pooled || hashed) \ fr->fr_satype = FRI_LOOKUP;) } | srcaddrlist lmore addr { DOREM(bcopy(&($3.a), &fr->fr_ip.fi_src, sizeof($3.a)); \ bcopy(&($3.m), &fr->fr_mip.fi_src, sizeof($3.m)); \ if (dynamic != -1) { \ fr->fr_satype = ifpflag; \ fr->fr_ipf->fri_sifpidx = dynamic; \ } else if (pooled || hashed) \ fr->fr_satype = FRI_LOOKUP;) } ; srcport: | portcomp { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1;) } | portrange { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1; \ fr->fr_stop = $1.p2;) } | porteq lstart srcportlist lend { yyresetdict(); } ; fromport: portcomp { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1;) } | portrange { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1; \ fr->fr_stop = $1.p2;) } | porteq lstart srcportlist lend { yyresetdict(); } ; srcportlist: portnum { DOREM(fr->fr_scmp = FR_EQUAL; fr->fr_sport = $1;) } | srcportlist lmore portnum { DOREM(fr->fr_scmp = FR_EQUAL; fr->fr_sport = $3;) } ; dstobject: { yyresetdict(); } toport | dstaddr dstport | '!' dstaddr dstport { DOALL(fr->fr_flags |= FR_NOTDSTIP;) } ; dstaddr: addr { DOREM(bcopy(&($1.a), &fr->fr_ip.fi_dst, sizeof($1.a)); \ bcopy(&($1.m), &fr->fr_mip.fi_dst, sizeof($1.m)); \ if (dynamic != -1) { \ fr->fr_datype = ifpflag; \ fr->fr_ipf->fri_difpidx = dynamic; \ } else if (pooled || hashed) \ fr->fr_datype = FRI_LOOKUP;) } | lstart dstaddrlist lend ; dstaddrlist: addr { DOREM(bcopy(&($1.a), &fr->fr_ip.fi_dst, sizeof($1.a)); \ bcopy(&($1.m), &fr->fr_mip.fi_dst, sizeof($1.m)); \ if (dynamic != -1) { \ fr->fr_datype = ifpflag; \ fr->fr_ipf->fri_difpidx = dynamic; \ } else if (pooled || hashed) \ fr->fr_datype = FRI_LOOKUP;) } | dstaddrlist lmore addr { DOREM(bcopy(&($3.a), &fr->fr_ip.fi_dst, sizeof($3.a)); \ bcopy(&($3.m), &fr->fr_mip.fi_dst, sizeof($3.m)); \ if (dynamic != -1) { \ fr->fr_datype = ifpflag; \ fr->fr_ipf->fri_difpidx = dynamic; \ } else if (pooled || hashed) \ fr->fr_datype = FRI_LOOKUP;) } ; dstport: | portcomp { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1;) } | portrange { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1; \ fr->fr_dtop = $1.p2;) } | porteq lstart dstportlist lend { yyresetdict(); } ; toport: portcomp { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1;) } | portrange { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1; \ fr->fr_dtop = $1.p2;) } | porteq lstart dstportlist lend { yyresetdict(); } ; dstportlist: portnum { DOREM(fr->fr_dcmp = FR_EQUAL; fr->fr_dport = $1;) } | dstportlist lmore portnum { DOREM(fr->fr_dcmp = FR_EQUAL; fr->fr_dport = $3;) } ; addr: pool '/' YY_NUMBER { pooled = 1; yyexpectaddr = 0; $$.a.iplookuptype = IPLT_POOL; $$.a.iplookupnum = $3; } | pool '=' '(' poollist ')' { pooled = 1; yyexpectaddr = 0; $$.a.iplookuptype = IPLT_POOL; $$.a.iplookupnum = makepool($4); } | hash '/' YY_NUMBER { hashed = 1; yyexpectaddr = 0; $$.a.iplookuptype = IPLT_HASH; $$.a.iplookupnum = $3; } | hash '=' '(' addrlist ')' { hashed = 1; yyexpectaddr = 0; $$.a.iplookuptype = IPLT_HASH; $$.a.iplookupnum = makehash($4); } | ipaddr { bcopy(&$1, &$$, sizeof($$)); yyexpectaddr = 0; } ; ipaddr: IPFY_ANY { bzero(&($$), sizeof($$)); yyresetdict(); yyexpectaddr = 0; } | hostname { if (use_inet6 == 0) { $$.a.in4 = $1.in4; $$.m.in4_addr = 0xffffffff; } else { set_ipv6_addr = 1; bcopy(&$1, &$$.a, sizeof($$.a)); fill6bits(128, (u_32_t *)&$$.m); } yyexpectaddr = 0; } | hostname { yyresetdict(); if (use_inet6 == 0) $$.a.in4 = $1.in4; else { set_ipv6_addr = 1; bcopy(&$1, &$$.a, sizeof($$.a)); } } maskspace { yysetdict(maskwords); } mask { if (use_inet6 == 0) { $$.m.in4_addr = $5.in4.s_addr; $$.a.in4_addr &= $5.in4.s_addr; } else bcopy(&$5, &$$.m, sizeof($$.m)); yyresetdict(); yyexpectaddr = 0; } | YY_IPV6 { set_ipv6_addr = 1; bcopy(&$1, &$$.a, sizeof($$.a)); fill6bits(128, (u_32_t *)&$$.m); yyresetdict(); yyexpectaddr = 0; } | YY_IPV6 { set_ipv6_addr = 1; yyresetdict(); bcopy(&$1, &$$.a, sizeof($$.a)); } maskspace { yysetdict(maskwords); } mask { bcopy(&$5, &$$.m, sizeof($$.m)); yyresetdict(); yyexpectaddr = 0; } ; maskspace: '/' | IPFY_MASK ; mask: ipv4 { $$.in4 = $1; } | YY_HEX { $$.in4.s_addr = htonl($1); } | YY_NUMBER { if ((use_inet6 == 0) && ($1 <= 32)) ntomask(4, $1, (u_32_t *)&$$.in4); else if ((use_inet6 != 0) && ($1 <= 128)) ntomask(6, $1, $$.i6); else { yyerror("Bad value specified for netmask"); return 0; } } | IPFY_BROADCAST { if (ifpflag == FRI_DYNAMIC) { bzero(&$$, sizeof($$)); ifpflag = FRI_BROADCAST; } else YYERROR; } | IPFY_NETWORK { if (ifpflag == FRI_DYNAMIC) { bzero(&$$, sizeof($$)); ifpflag = FRI_NETWORK; } else YYERROR; } | IPFY_NETMASKED { if (ifpflag == FRI_DYNAMIC) { bzero(&$$, sizeof($$)); ifpflag = FRI_NETMASKED; } else YYERROR; } | IPFY_PEER { if (ifpflag == FRI_DYNAMIC) { bzero(&$$, sizeof($$)); ifpflag = FRI_PEERADDR; } else YYERROR; } ; hostname: ipv4 { $$.in4 = $1; } | YY_NUMBER { $$.in4.s_addr = $1; } | YY_HEX { $$.in4.s_addr = $1; } | YY_STR { if (lookuphost($1, &$$) == 1) free($1); else { free($1); if (ifpflag != FRI_DYNAMIC) yyerror("Unknown hostname"); } } ; addrlist: ipaddr { $$ = newalist(NULL); if (set_ipv6_addr) $$->al_family = AF_INET6; else $$->al_family = AF_INET; set_ipv6_addr = 0; bcopy(&($1.a), &($$->al_i6addr), sizeof($1.a)); bcopy(&($1.m), &($$->al_i6mask), sizeof($1.m)); } | addrlist ',' ipaddr { $$ = newalist($1); if (set_ipv6_addr) $$->al_family = AF_INET6; else $$->al_family = AF_INET; set_ipv6_addr = 0; bcopy(&($3.a), &($$->al_i6addr), sizeof($3.a)); bcopy(&($3.m), &($$->al_i6mask), sizeof($3.m)); } ; pool: IPFY_POOL { yyexpectaddr = 0; yycont = NULL; yyresetdict(); } ; hash: IPFY_HASH { yyexpectaddr = 0; yycont = NULL; yyresetdict(); } ; poollist: ipaddr { $$ = newalist(NULL); if (set_ipv6_addr) $$->al_family = AF_INET6; else $$->al_family = AF_INET; set_ipv6_addr = 0; bcopy(&($1.a), &($$->al_i6addr), sizeof($1.a)); bcopy(&($1.m), &($$->al_i6mask), sizeof($1.m)); } | '!' ipaddr { $$ = newalist(NULL); $$->al_not = 1; if (set_ipv6_addr) $$->al_family = AF_INET6; else $$->al_family = AF_INET; set_ipv6_addr = 0; bcopy(&($2.a), &($$->al_i6addr), sizeof($2.a)); bcopy(&($2.m), &($$->al_i6mask), sizeof($2.m)); } | poollist ',' ipaddr { $$ = newalist($1); if (set_ipv6_addr) $$->al_family = AF_INET6; else $$->al_family = AF_INET; set_ipv6_addr = 0; bcopy(&($3.a), &($$->al_i6addr), sizeof($3.a)); bcopy(&($3.m), &($$->al_i6mask), sizeof($3.m)); } | poollist ',' '!' ipaddr { $$ = newalist($1); $$->al_not = 1; if (set_ipv6_addr) $$->al_family = AF_INET6; else $$->al_family = AF_INET; set_ipv6_addr = 0; bcopy(&($4.a), &($$->al_i6addr), sizeof($4.a)); bcopy(&($4.m), &($$->al_i6mask), sizeof($4.m)); } ; port: IPFY_PORT { yyexpectaddr = 0; yycont = NULL; } ; portc: port compare { $$ = $2; yysetdict(NULL); } | porteq { $$ = $1; } ; porteq: port '=' { $$ = FR_EQUAL; yysetdict(NULL); } ; portr: IPFY_PORT { yyexpectaddr = 0; yycont = NULL; yysetdict(NULL); } ; portcomp: portc portnum { $$.pc = $1; $$.p1 = $2; yyresetdict(); } ; portrange: portr portnum range portnum { $$.p1 = $2; $$.pc = $3; $$.p2 = $4; yyresetdict(); } ; icmp: | itype icode ; itype: seticmptype icmptype { DOALL(fr->fr_icmp = htons($2 << 8); fr->fr_icmpm = htons(0xff00);); yyresetdict(); } | seticmptype lstart typelist lend { yyresetdict(); } ; seticmptype: IPFY_ICMPTYPE { setipftype(); yysetdict(icmptypewords); } ; icode: | seticmpcode icmpcode { DOALL(fr->fr_icmp |= htons($2); fr->fr_icmpm |= htons(0xff);); yyresetdict(); } | seticmpcode lstart codelist lend { yyresetdict(); } ; seticmpcode: IPFY_ICMPCODE { yysetdict(icmpcodewords); } ; typelist: icmptype { DOREM(fr->fr_icmp = htons($1 << 8); fr->fr_icmpm = htons(0xff00);) } | typelist lmore icmptype { DOREM(fr->fr_icmp = htons($3 << 8); fr->fr_icmpm = htons(0xff00);) } ; codelist: icmpcode { DOREM(fr->fr_icmp |= htons($1); fr->fr_icmpm |= htons(0xff);) } | codelist lmore icmpcode { DOREM(fr->fr_icmp |= htons($3); fr->fr_icmpm |= htons(0xff);) } ; age: | IPFY_AGE YY_NUMBER { DOALL(fr->fr_age[0] = $2; \ fr->fr_age[1] = $2;) } | IPFY_AGE YY_NUMBER '/' YY_NUMBER { DOALL(fr->fr_age[0] = $2; \ fr->fr_age[1] = $4;) } ; keep: | IPFY_KEEP keepstate | IPFY_KEEP keepfrag | IPFY_KEEP keepstate IPFY_KEEP keepfrag | IPFY_KEEP keepfrag IPFY_KEEP keepstate ; keepstate: IPFY_STATE stateoptlist { DOALL(fr->fr_flags |= FR_KEEPSTATE;)} ; keepfrag: IPFY_FRAGS fragoptlist { DOALL(fr->fr_flags |= FR_KEEPFRAG;) } | IPFY_FRAG fragoptlist { DOALL(fr->fr_flags |= FR_KEEPFRAG;) } ; fragoptlist: | '(' fragopts ')' ; fragopts: fragopt lanother fragopts | fragopt ; fragopt: IPFY_STRICT { DOALL(fr->fr_flags |= FR_FRSTRICT;) } ; stateoptlist: | '(' stateopts ')' ; stateopts: stateopt lanother stateopts | stateopt ; stateopt: IPFY_LIMIT YY_NUMBER { DOALL(fr->fr_statemax = $2;) } | IPFY_STRICT { DOALL(if (fr->fr_proto != IPPROTO_TCP) { \ YYERROR; \ } else \ fr->fr_flags |= FR_STSTRICT;) } | IPFY_NEWISN { DOALL(if (fr->fr_proto != IPPROTO_TCP) { \ YYERROR; \ } else \ fr->fr_flags |= FR_NEWISN;) } | IPFY_NOICMPERR { DOALL(fr->fr_flags |= FR_NOICMPERR;) } | IPFY_SYNC { DOALL(fr->fr_flags |= FR_STATESYNC;) } ; portnum: servicename { if (getport(frc, $1, &($$)) == -1) yyerror("service unknown"); else $$ = ntohs($$); free($1); } | YY_NUMBER { if ($1 > 65535) /* Unsigned */ yyerror("invalid port number"); else $$ = $1; } ; withlist: withopt | withlist withopt | withlist ',' withopt ; withopt: opttype { DOALL(fr->fr_flx |= $1; fr->fr_mflx |= $1;) } | notwith opttype { DOALL(fr->fr_mflx |= $2;) } | ipopt ipopts { yyresetdict(); } | notwith ipopt ipopts { yyresetdict(); } | startv6hdrs ipv6hdrs { yyresetdict(); } ; ipopt: IPFY_OPT { yysetdict(ipv4optwords); } ; startv6hdrs: IPF6_V6HDRS { if (use_inet6 == 0) yyerror("only available with IPv6"); yysetdict(ipv6optwords); } ; notwith: IPFY_NOT { nowith = 1; } | IPFY_NO { nowith = 1; } ; opttype: IPFY_IPOPTS { $$ = FI_OPTIONS; } | IPFY_SHORT { $$ = FI_SHORT; } | IPFY_NAT { $$ = FI_NATED; } | IPFY_BAD { $$ = FI_BAD; } | IPFY_BADNAT { $$ = FI_BADNAT; } | IPFY_BADSRC { $$ = FI_BADSRC; } | IPFY_LOWTTL { $$ = FI_LOWTTL; } | IPFY_FRAG { $$ = FI_FRAG; } | IPFY_FRAGBODY { $$ = FI_FRAGBODY; } | IPFY_FRAGS { $$ = FI_FRAG; } | IPFY_MBCAST { $$ = FI_MBCAST; } | IPFY_MULTICAST { $$ = FI_MULTICAST; } | IPFY_BROADCAST { $$ = FI_BROADCAST; } | IPFY_STATE { $$ = FI_STATE; } | IPFY_OOW { $$ = FI_OOW; } ; ipopts: optlist { DOALL(fr->fr_mip.fi_optmsk |= $1; if (!nowith) fr->fr_ip.fi_optmsk |= $1;) } ; optlist: opt { $$ |= $1; } | optlist ',' opt { $$ |= $1 | $3; } ; ipv6hdrs: ipv6hdrlist { DOALL(fr->fr_mip.fi_optmsk |= $1; if (!nowith) fr->fr_ip.fi_optmsk |= $1;) } ; ipv6hdrlist: ipv6hdr { $$ |= $1; } | ipv6hdrlist ',' ipv6hdr { $$ |= $1 | $3; } ; secname: seclevel { $$ |= $1; } | secname ',' seclevel { $$ |= $1 | $3; } ; seclevel: IPFY_SEC_UNC { $$ = secbit(IPSO_CLASS_UNCL); } | IPFY_SEC_CONF { $$ = secbit(IPSO_CLASS_CONF); } | IPFY_SEC_RSV1 { $$ = secbit(IPSO_CLASS_RES1); } | IPFY_SEC_RSV2 { $$ = secbit(IPSO_CLASS_RES2); } | IPFY_SEC_RSV3 { $$ = secbit(IPSO_CLASS_RES3); } | IPFY_SEC_RSV4 { $$ = secbit(IPSO_CLASS_RES4); } | IPFY_SEC_SEC { $$ = secbit(IPSO_CLASS_SECR); } | IPFY_SEC_TS { $$ = secbit(IPSO_CLASS_TOPS); } ; icmptype: YY_NUMBER { $$ = $1; } | IPFY_ICMPT_UNR { $$ = ICMP_UNREACH; } | IPFY_ICMPT_ECHO { $$ = ICMP_ECHO; } | IPFY_ICMPT_ECHOR { $$ = ICMP_ECHOREPLY; } | IPFY_ICMPT_SQUENCH { $$ = ICMP_SOURCEQUENCH; } | IPFY_ICMPT_REDIR { $$ = ICMP_REDIRECT; } | IPFY_ICMPT_TIMEX { $$ = ICMP_TIMXCEED; } | IPFY_ICMPT_PARAMP { $$ = ICMP_PARAMPROB; } | IPFY_ICMPT_TIMEST { $$ = ICMP_TSTAMP; } | IPFY_ICMPT_TIMESTREP { $$ = ICMP_TSTAMPREPLY; } | IPFY_ICMPT_INFOREQ { $$ = ICMP_IREQ; } | IPFY_ICMPT_INFOREP { $$ = ICMP_IREQREPLY; } | IPFY_ICMPT_MASKREQ { $$ = ICMP_MASKREQ; } | IPFY_ICMPT_MASKREP { $$ = ICMP_MASKREPLY; } | IPFY_ICMPT_ROUTERAD { $$ = ICMP_ROUTERADVERT; } | IPFY_ICMPT_ROUTERSOL { $$ = ICMP_ROUTERSOLICIT; } ; icmpcode: YY_NUMBER { $$ = $1; } | IPFY_ICMPC_NETUNR { $$ = ICMP_UNREACH_NET; } | IPFY_ICMPC_HSTUNR { $$ = ICMP_UNREACH_HOST; } | IPFY_ICMPC_PROUNR { $$ = ICMP_UNREACH_PROTOCOL; } | IPFY_ICMPC_PORUNR { $$ = ICMP_UNREACH_PORT; } | IPFY_ICMPC_NEEDF { $$ = ICMP_UNREACH_NEEDFRAG; } | IPFY_ICMPC_SRCFAIL { $$ = ICMP_UNREACH_SRCFAIL; } | IPFY_ICMPC_NETUNK { $$ = ICMP_UNREACH_NET_UNKNOWN; } | IPFY_ICMPC_HSTUNK { $$ = ICMP_UNREACH_HOST_UNKNOWN; } | IPFY_ICMPC_ISOLATE { $$ = ICMP_UNREACH_ISOLATED; } | IPFY_ICMPC_NETPRO { $$ = ICMP_UNREACH_NET_PROHIB; } | IPFY_ICMPC_HSTPRO { $$ = ICMP_UNREACH_HOST_PROHIB; } | IPFY_ICMPC_NETTOS { $$ = ICMP_UNREACH_TOSNET; } | IPFY_ICMPC_HSTTOS { $$ = ICMP_UNREACH_TOSHOST; } | IPFY_ICMPC_FLTPRO { $$ = ICMP_UNREACH_ADMIN_PROHIBIT; } | IPFY_ICMPC_HSTPRE { $$ = 14; } | IPFY_ICMPC_CUTPRE { $$ = 15; } ; opt: IPFY_IPOPT_NOP { $$ = getoptbyvalue(IPOPT_NOP); } | IPFY_IPOPT_RR { $$ = getoptbyvalue(IPOPT_RR); } | IPFY_IPOPT_ZSU { $$ = getoptbyvalue(IPOPT_ZSU); } | IPFY_IPOPT_MTUP { $$ = getoptbyvalue(IPOPT_MTUP); } | IPFY_IPOPT_MTUR { $$ = getoptbyvalue(IPOPT_MTUR); } | IPFY_IPOPT_ENCODE { $$ = getoptbyvalue(IPOPT_ENCODE); } | IPFY_IPOPT_TS { $$ = getoptbyvalue(IPOPT_TS); } | IPFY_IPOPT_TR { $$ = getoptbyvalue(IPOPT_TR); } | IPFY_IPOPT_SEC { $$ = getoptbyvalue(IPOPT_SECURITY); } | IPFY_IPOPT_LSRR { $$ = getoptbyvalue(IPOPT_LSRR); } | IPFY_IPOPT_ESEC { $$ = getoptbyvalue(IPOPT_E_SEC); } | IPFY_IPOPT_CIPSO { $$ = getoptbyvalue(IPOPT_CIPSO); } | IPFY_IPOPT_SATID { $$ = getoptbyvalue(IPOPT_SATID); } | IPFY_IPOPT_SSRR { $$ = getoptbyvalue(IPOPT_SSRR); } | IPFY_IPOPT_ADDEXT { $$ = getoptbyvalue(IPOPT_ADDEXT); } | IPFY_IPOPT_VISA { $$ = getoptbyvalue(IPOPT_VISA); } | IPFY_IPOPT_IMITD { $$ = getoptbyvalue(IPOPT_IMITD); } | IPFY_IPOPT_EIP { $$ = getoptbyvalue(IPOPT_EIP); } | IPFY_IPOPT_FINN { $$ = getoptbyvalue(IPOPT_FINN); } | IPFY_IPOPT_DPS { $$ = getoptbyvalue(IPOPT_DPS); } | IPFY_IPOPT_SDB { $$ = getoptbyvalue(IPOPT_SDB); } | IPFY_IPOPT_NSAPA { $$ = getoptbyvalue(IPOPT_NSAPA); } | IPFY_IPOPT_RTRALRT { $$ = getoptbyvalue(IPOPT_RTRALRT); } | IPFY_IPOPT_UMP { $$ = getoptbyvalue(IPOPT_UMP); } | setsecclass secname { DOALL(fr->fr_mip.fi_secmsk |= $2; if (!nowith) fr->fr_ip.fi_secmsk |= $2;) $$ = 0; yyresetdict(); } ; setsecclass: IPFY_SECCLASS { yysetdict(ipv4secwords); } ; ipv6hdr: IPFY_AH { $$ = getv6optbyvalue(IPPROTO_AH); } | IPFY_IPV6OPT_DSTOPTS { $$ = getv6optbyvalue(IPPROTO_DSTOPTS); } | IPFY_ESP { $$ = getv6optbyvalue(IPPROTO_ESP); } | IPFY_IPV6OPT_HOPOPTS { $$ = getv6optbyvalue(IPPROTO_HOPOPTS); } | IPFY_IPV6OPT_IPV6 { $$ = getv6optbyvalue(IPPROTO_IPV6); } | IPFY_IPV6OPT_NONE { $$ = getv6optbyvalue(IPPROTO_NONE); } | IPFY_IPV6OPT_ROUTING { $$ = getv6optbyvalue(IPPROTO_ROUTING); } | IPFY_FRAG { $$ = getv6optbyvalue(IPPROTO_FRAGMENT); } ; level: IPFY_LEVEL { setsyslog(); } ; loglevel: priority { fr->fr_loglevel = LOG_LOCAL0|$1; } | facility '.' priority { fr->fr_loglevel = $1 | $3; } ; facility: IPFY_FAC_KERN { $$ = LOG_KERN; } | IPFY_FAC_USER { $$ = LOG_USER; } | IPFY_FAC_MAIL { $$ = LOG_MAIL; } | IPFY_FAC_DAEMON { $$ = LOG_DAEMON; } | IPFY_FAC_AUTH { $$ = LOG_AUTH; } | IPFY_FAC_SYSLOG { $$ = LOG_SYSLOG; } | IPFY_FAC_LPR { $$ = LOG_LPR; } | IPFY_FAC_NEWS { $$ = LOG_NEWS; } | IPFY_FAC_UUCP { $$ = LOG_UUCP; } | IPFY_FAC_CRON { $$ = LOG_CRON; } | IPFY_FAC_FTP { $$ = LOG_FTP; } | IPFY_FAC_AUTHPRIV { $$ = LOG_AUTHPRIV; } | IPFY_FAC_AUDIT { $$ = LOG_AUDIT; } | IPFY_FAC_LFMT { $$ = LOG_LFMT; } | IPFY_FAC_LOCAL0 { $$ = LOG_LOCAL0; } | IPFY_FAC_LOCAL1 { $$ = LOG_LOCAL1; } | IPFY_FAC_LOCAL2 { $$ = LOG_LOCAL2; } | IPFY_FAC_LOCAL3 { $$ = LOG_LOCAL3; } | IPFY_FAC_LOCAL4 { $$ = LOG_LOCAL4; } | IPFY_FAC_LOCAL5 { $$ = LOG_LOCAL5; } | IPFY_FAC_LOCAL6 { $$ = LOG_LOCAL6; } | IPFY_FAC_LOCAL7 { $$ = LOG_LOCAL7; } | IPFY_FAC_SECURITY { $$ = LOG_SECURITY; } ; priority: IPFY_PRI_EMERG { $$ = LOG_EMERG; } | IPFY_PRI_ALERT { $$ = LOG_ALERT; } | IPFY_PRI_CRIT { $$ = LOG_CRIT; } | IPFY_PRI_ERR { $$ = LOG_ERR; } | IPFY_PRI_WARN { $$ = LOG_WARNING; } | IPFY_PRI_NOTICE { $$ = LOG_NOTICE; } | IPFY_PRI_INFO { $$ = LOG_INFO; } | IPFY_PRI_DEBUG { $$ = LOG_DEBUG; } ; compare: YY_CMP_EQ { $$ = FR_EQUAL; } | YY_CMP_NE { $$ = FR_NEQUAL; } | YY_CMP_LT { $$ = FR_LESST; } | YY_CMP_LE { $$ = FR_LESSTE; } | YY_CMP_GT { $$ = FR_GREATERT; } | YY_CMP_GE { $$ = FR_GREATERTE; } ; range: YY_RANGE_IN { $$ = FR_INRANGE; } | YY_RANGE_OUT { $$ = FR_OUTRANGE; } | ':' { $$ = FR_INCRANGE; } ; servicename: YY_STR { $$ = $1; } ; interfacename: YY_STR { $$ = $1; } | YY_STR ':' YY_NUMBER { $$ = $1; fprintf(stderr, "%d: Logical interface %s:%d unsupported, " "use the physical interface %s instead.\n", yylineNum, $1, $3, $1); } ; name: YY_STR { $$ = $1; } ; ipv4_16: YY_NUMBER '.' YY_NUMBER { if ($1 > 255 || $3 > 255) { yyerror("Invalid octet string for IP address"); return 0; } $$.s_addr = ($1 << 24) | ($3 << 16); $$.s_addr = htonl($$.s_addr); } ; ipv4_24: ipv4_16 '.' YY_NUMBER { if ($3 > 255) { yyerror("Invalid octet string for IP address"); return 0; } $$.s_addr |= htonl($3 << 8); } ; ipv4: ipv4_24 '.' YY_NUMBER { if ($3 > 255) { yyerror("Invalid octet string for IP address"); return 0; } $$.s_addr |= htonl($3); } | ipv4_24 | ipv4_16 ; %% static struct wordtab ipfwords[96] = { { "age", IPFY_AGE }, { "ah", IPFY_AH }, { "all", IPFY_ALL }, { "and", IPFY_AND }, { "auth", IPFY_AUTH }, { "bad", IPFY_BAD }, { "bad-nat", IPFY_BADNAT }, { "bad-src", IPFY_BADSRC }, { "bcast", IPFY_BROADCAST }, { "block", IPFY_BLOCK }, { "body", IPFY_BODY }, { "bpf-v4", IPFY_BPFV4 }, #ifdef USE_INET6 { "bpf-v6", IPFY_BPFV6 }, #endif { "call", IPFY_CALL }, { "code", IPFY_ICMPCODE }, { "count", IPFY_COUNT }, { "dup-to", IPFY_DUPTO }, { "eq", YY_CMP_EQ }, { "esp", IPFY_ESP }, { "fastroute", IPFY_FROUTE }, { "first", IPFY_FIRST }, { "flags", IPFY_FLAGS }, { "frag", IPFY_FRAG }, { "frag-body", IPFY_FRAGBODY }, { "frags", IPFY_FRAGS }, { "from", IPFY_FROM }, { "ge", YY_CMP_GE }, { "group", IPFY_GROUP }, { "gt", YY_CMP_GT }, { "head", IPFY_HEAD }, { "icmp", IPFY_ICMP }, { "icmp-type", IPFY_ICMPTYPE }, { "in", IPFY_IN }, { "in-via", IPFY_INVIA }, { "intercept_loopback", IPFY_SET_LOOPBACK }, { "ipopt", IPFY_IPOPTS }, { "ipopts", IPFY_IPOPTS }, { "keep", IPFY_KEEP }, { "le", YY_CMP_LE }, { "level", IPFY_LEVEL }, { "limit", IPFY_LIMIT }, { "log", IPFY_LOG }, { "lowttl", IPFY_LOWTTL }, { "lt", YY_CMP_LT }, { "mask", IPFY_MASK }, { "match-tag", IPFY_MATCHTAG }, { "mbcast", IPFY_MBCAST }, { "mcast", IPFY_MULTICAST }, { "multicast", IPFY_MULTICAST }, { "nat", IPFY_NAT }, { "ne", YY_CMP_NE }, { "net", IPFY_NETWORK }, { "newisn", IPFY_NEWISN }, { "no", IPFY_NO }, { "no-icmp-err", IPFY_NOICMPERR }, { "now", IPFY_NOW }, { "not", IPFY_NOT }, { "oow", IPFY_OOW }, { "on", IPFY_ON }, { "opt", IPFY_OPT }, { "or-block", IPFY_ORBLOCK }, { "out", IPFY_OUT }, { "out-via", IPFY_OUTVIA }, { "pass", IPFY_PASS }, { "port", IPFY_PORT }, { "pps", IPFY_PPS }, { "preauth", IPFY_PREAUTH }, { "proto", IPFY_PROTO }, { "quick", IPFY_QUICK }, { "reply-to", IPFY_REPLY_TO }, { "return-icmp", IPFY_RETICMP }, { "return-icmp-as-dest", IPFY_RETICMPASDST }, { "return-rst", IPFY_RETRST }, { "route-to", IPFY_ROUTETO }, { "sec-class", IPFY_SECCLASS }, { "set-tag", IPFY_SETTAG }, { "set", IPFY_SET }, { "skip", IPFY_SKIP }, { "short", IPFY_SHORT }, { "state", IPFY_STATE }, { "state-age", IPFY_AGE }, { "strict", IPFY_STRICT }, { "sync", IPFY_SYNC }, { "tcp", IPFY_TCP }, { "tcp-udp", IPFY_TCPUDP }, { "tos", IPFY_TOS }, { "to", IPFY_TO }, { "ttl", IPFY_TTL }, { "udp", IPFY_UDP }, { "v6hdrs", IPF6_V6HDRS }, { "with", IPFY_WITH }, { NULL, 0 } }; static struct wordtab addrwords[4] = { { "any", IPFY_ANY }, { "hash", IPFY_HASH }, { "pool", IPFY_POOL }, { NULL, 0 } }; static struct wordtab maskwords[5] = { { "broadcast", IPFY_BROADCAST }, { "netmasked", IPFY_NETMASKED }, { "network", IPFY_NETWORK }, { "peer", IPFY_PEER }, { NULL, 0 } }; static struct wordtab icmptypewords[16] = { { "echo", IPFY_ICMPT_ECHO }, { "echorep", IPFY_ICMPT_ECHOR }, { "inforeq", IPFY_ICMPT_INFOREQ }, { "inforep", IPFY_ICMPT_INFOREP }, { "maskrep", IPFY_ICMPT_MASKREP }, { "maskreq", IPFY_ICMPT_MASKREQ }, { "paramprob", IPFY_ICMPT_PARAMP }, { "redir", IPFY_ICMPT_REDIR }, { "unreach", IPFY_ICMPT_UNR }, { "routerad", IPFY_ICMPT_ROUTERAD }, { "routersol", IPFY_ICMPT_ROUTERSOL }, { "squench", IPFY_ICMPT_SQUENCH }, { "timest", IPFY_ICMPT_TIMEST }, { "timestrep", IPFY_ICMPT_TIMESTREP }, { "timex", IPFY_ICMPT_TIMEX }, { NULL, 0 }, }; static struct wordtab icmpcodewords[17] = { { "cutoff-preced", IPFY_ICMPC_CUTPRE }, { "filter-prohib", IPFY_ICMPC_FLTPRO }, { "isolate", IPFY_ICMPC_ISOLATE }, { "needfrag", IPFY_ICMPC_NEEDF }, { "net-prohib", IPFY_ICMPC_NETPRO }, { "net-tos", IPFY_ICMPC_NETTOS }, { "host-preced", IPFY_ICMPC_HSTPRE }, { "host-prohib", IPFY_ICMPC_HSTPRO }, { "host-tos", IPFY_ICMPC_HSTTOS }, { "host-unk", IPFY_ICMPC_HSTUNK }, { "host-unr", IPFY_ICMPC_HSTUNR }, { "net-unk", IPFY_ICMPC_NETUNK }, { "net-unr", IPFY_ICMPC_NETUNR }, { "port-unr", IPFY_ICMPC_PORUNR }, { "proto-unr", IPFY_ICMPC_PROUNR }, { "srcfail", IPFY_ICMPC_SRCFAIL }, { NULL, 0 }, }; static struct wordtab ipv4optwords[25] = { { "addext", IPFY_IPOPT_ADDEXT }, { "cipso", IPFY_IPOPT_CIPSO }, { "dps", IPFY_IPOPT_DPS }, { "e-sec", IPFY_IPOPT_ESEC }, { "eip", IPFY_IPOPT_EIP }, { "encode", IPFY_IPOPT_ENCODE }, { "finn", IPFY_IPOPT_FINN }, { "imitd", IPFY_IPOPT_IMITD }, { "lsrr", IPFY_IPOPT_LSRR }, { "mtup", IPFY_IPOPT_MTUP }, { "mtur", IPFY_IPOPT_MTUR }, { "nop", IPFY_IPOPT_NOP }, { "nsapa", IPFY_IPOPT_NSAPA }, { "rr", IPFY_IPOPT_RR }, { "rtralrt", IPFY_IPOPT_RTRALRT }, { "satid", IPFY_IPOPT_SATID }, { "sdb", IPFY_IPOPT_SDB }, { "sec", IPFY_IPOPT_SEC }, { "ssrr", IPFY_IPOPT_SSRR }, { "tr", IPFY_IPOPT_TR }, { "ts", IPFY_IPOPT_TS }, { "ump", IPFY_IPOPT_UMP }, { "visa", IPFY_IPOPT_VISA }, { "zsu", IPFY_IPOPT_ZSU }, { NULL, 0 }, }; static struct wordtab ipv4secwords[9] = { { "confid", IPFY_SEC_CONF }, { "reserv-1", IPFY_SEC_RSV1 }, { "reserv-2", IPFY_SEC_RSV2 }, { "reserv-3", IPFY_SEC_RSV3 }, { "reserv-4", IPFY_SEC_RSV4 }, { "secret", IPFY_SEC_SEC }, { "topsecret", IPFY_SEC_TS }, { "unclass", IPFY_SEC_UNC }, { NULL, 0 }, }; static struct wordtab ipv6optwords[8] = { { "dstopts", IPFY_IPV6OPT_DSTOPTS }, { "esp", IPFY_ESP }, { "frag", IPFY_FRAG }, { "hopopts", IPFY_IPV6OPT_HOPOPTS }, { "ipv6", IPFY_IPV6OPT_IPV6 }, { "none", IPFY_IPV6OPT_NONE }, { "routing", IPFY_IPV6OPT_ROUTING }, { NULL, 0 }, }; static struct wordtab logwords[33] = { { "kern", IPFY_FAC_KERN }, { "user", IPFY_FAC_USER }, { "mail", IPFY_FAC_MAIL }, { "daemon", IPFY_FAC_DAEMON }, { "auth", IPFY_FAC_AUTH }, { "syslog", IPFY_FAC_SYSLOG }, { "lpr", IPFY_FAC_LPR }, { "news", IPFY_FAC_NEWS }, { "uucp", IPFY_FAC_UUCP }, { "cron", IPFY_FAC_CRON }, { "ftp", IPFY_FAC_FTP }, { "authpriv", IPFY_FAC_AUTHPRIV }, { "audit", IPFY_FAC_AUDIT }, { "logalert", IPFY_FAC_LFMT }, { "console", IPFY_FAC_CONSOLE }, { "security", IPFY_FAC_SECURITY }, { "local0", IPFY_FAC_LOCAL0 }, { "local1", IPFY_FAC_LOCAL1 }, { "local2", IPFY_FAC_LOCAL2 }, { "local3", IPFY_FAC_LOCAL3 }, { "local4", IPFY_FAC_LOCAL4 }, { "local5", IPFY_FAC_LOCAL5 }, { "local6", IPFY_FAC_LOCAL6 }, { "local7", IPFY_FAC_LOCAL7 }, { "emerg", IPFY_PRI_EMERG }, { "alert", IPFY_PRI_ALERT }, { "crit", IPFY_PRI_CRIT }, { "err", IPFY_PRI_ERR }, { "warn", IPFY_PRI_WARN }, { "notice", IPFY_PRI_NOTICE }, { "info", IPFY_PRI_INFO }, { "debug", IPFY_PRI_DEBUG }, { NULL, 0 }, }; int ipf_parsefile(fd, addfunc, iocfuncs, filename) int fd; addfunc_t addfunc; ioctlfunc_t *iocfuncs; char *filename; { FILE *fp = NULL; char *s; yylineNum = 1; yysettab(ipfwords); s = getenv("YYDEBUG"); if (s != NULL) yydebug = atoi(s); else yydebug = 0; if (strcmp(filename, "-")) { fp = fopen(filename, "r"); if (fp == NULL) { fprintf(stderr, "fopen(%s) failed: %s\n", filename, STRERROR(errno)); return -1; } } else fp = stdin; while (ipf_parsesome(fd, addfunc, iocfuncs, fp) == 1) ; if (fp != NULL) fclose(fp); return 0; } int ipf_parsesome(fd, addfunc, iocfuncs, fp) int fd; addfunc_t addfunc; ioctlfunc_t *iocfuncs; FILE *fp; { char *s; int i; ipffd = fd; for (i = 0; i <= IPL_LOGMAX; i++) ipfioctl[i] = iocfuncs[i]; ipfaddfunc = addfunc; if (feof(fp)) return 0; i = fgetc(fp); if (i == EOF) return 0; if (ungetc(i, fp) == 0) return 0; if (feof(fp)) return 0; s = getenv("YYDEBUG"); if (s != NULL) yydebug = atoi(s); else yydebug = 0; yyin = fp; yyparse(); return 1; } static void newrule() { frentry_t *frn; frn = (frentry_t *)calloc(1, sizeof(frentry_t)); if (frn == NULL) yyerror("sorry, out of memory"); for (fr = frtop; fr != NULL && fr->fr_next != NULL; fr = fr->fr_next) ; if (fr != NULL) fr->fr_next = frn; if (frtop == NULL) frtop = frn; fr = frn; frc = frn; fr->fr_loglevel = 0xffff; fr->fr_isc = (void *)-1; fr->fr_logtag = FR_NOLOGTAG; fr->fr_type = FR_T_NONE; if (use_inet6 != 0) fr->fr_v = 6; else fr->fr_v = 4; nrules = 1; } static void setipftype() { for (fr = frc; fr != NULL; fr = fr->fr_next) { if (fr->fr_type == FR_T_NONE) { fr->fr_type = FR_T_IPF; fr->fr_data = (void *)calloc(sizeof(fripf_t), 1); if (fr->fr_data == NULL) yyerror("sorry, out of memory"); fr->fr_dsize = sizeof(fripf_t); fr->fr_ip.fi_v = frc->fr_v; fr->fr_mip.fi_v = 0xf; fr->fr_ipf->fri_sifpidx = -1; fr->fr_ipf->fri_difpidx = -1; } if (fr->fr_type != FR_T_IPF) { fprintf(stderr, "IPF Type not set\n"); } } } static frentry_t *addrule() { frentry_t *f, *f1, *f2; int count; for (f2 = frc; f2->fr_next != NULL; f2 = f2->fr_next) ; count = nrules; if (count == 0) { f = (frentry_t *)calloc(sizeof(*f), 1); if (f == NULL) yyerror("sorry, out of memory"); added++; f2->fr_next = f; bcopy(f2, f, sizeof(*f)); if (f2->fr_caddr != NULL) { f->fr_caddr = malloc(f->fr_dsize); if (f->fr_caddr == NULL) yyerror("sorry, out of memory"); bcopy(f2->fr_caddr, f->fr_caddr, f->fr_dsize); } f->fr_next = NULL; return f; } f = f2; for (f1 = frc; count > 0; count--, f1 = f1->fr_next) { f->fr_next = (frentry_t *)calloc(sizeof(*f), 1); if (f->fr_next == NULL) yyerror("sorry, out of memory"); added++; f = f->fr_next; bcopy(f1, f, sizeof(*f)); f->fr_next = NULL; if (f->fr_caddr != NULL) { f->fr_caddr = malloc(f->fr_dsize); if (f->fr_caddr == NULL) yyerror("sorry, out of memory"); bcopy(f1->fr_caddr, f->fr_caddr, f->fr_dsize); } } return f2->fr_next; } static u_32_t lookuphost(name, addr) char *name; i6addr_t *addr; { int i; hashed = 0; pooled = 0; dynamic = -1; for (i = 0; i < 4; i++) { if (strncmp(name, frc->fr_ifnames[i], sizeof(frc->fr_ifnames[i])) == 0) { ifpflag = FRI_DYNAMIC; dynamic = i; return 0; } } if (gethost(name, addr, use_inet6) == -1) { fprintf(stderr, "unknown name \"%s\"\n", name); return 0; } return 1; } static void dobpf(v, phrase) int v; char *phrase; { #ifdef IPFILTER_BPF struct bpf_program bpf; struct pcap *p; #endif fakebpf_t *fb; u_32_t l; char *s; int i; for (fr = frc; fr != NULL; fr = fr->fr_next) { if (fr->fr_type != FR_T_NONE) { fprintf(stderr, "cannot mix IPF and BPF matching\n"); return; } fr->fr_v = v; fr->fr_type = FR_T_BPFOPC; if (!strncmp(phrase, "\"0x", 2)) { phrase++; fb = malloc(sizeof(fakebpf_t)); if (fb == NULL) yyerror("sorry, out of memory"); for (i = 0, s = strtok(phrase, " \r\n\t"); s != NULL; s = strtok(NULL, " \r\n\t"), i++) { fb = realloc(fb, (i / 4 + 1) * sizeof(*fb)); if (fb == NULL) yyerror("sorry, out of memory"); l = (u_32_t)strtol(s, NULL, 0); switch (i & 3) { case 0 : fb[i / 4].fb_c = l & 0xffff; break; case 1 : fb[i / 4].fb_t = l & 0xff; break; case 2 : fb[i / 4].fb_f = l & 0xff; break; case 3 : fb[i / 4].fb_k = l; break; } } if ((i & 3) != 0) { fprintf(stderr, "Odd number of bytes in BPF code\n"); exit(1); } i--; fr->fr_dsize = (i / 4 + 1) * sizeof(*fb); fr->fr_data = fb; return; } #ifdef IPFILTER_BPF bzero((char *)&bpf, sizeof(bpf)); p = pcap_open_dead(DLT_RAW, 1); if (!p) { fprintf(stderr, "pcap_open_dead failed\n"); return; } if (pcap_compile(p, &bpf, phrase, 1, 0xffffffff)) { pcap_perror(p, "ipf"); pcap_close(p); fprintf(stderr, "pcap parsing failed (%s)\n", phrase); return; } pcap_close(p); fr->fr_dsize = bpf.bf_len * sizeof(struct bpf_insn); fr->fr_data = malloc(fr->fr_dsize); if (fr->fr_data == NULL) yyerror("sorry, out of memory"); bcopy((char *)bpf.bf_insns, fr->fr_data, fr->fr_dsize); if (!bpf_validate(fr->fr_data, bpf.bf_len)) { fprintf(stderr, "BPF validation failed\n"); return; } #endif } #ifdef IPFILTER_BPF if (opts & OPT_DEBUG) bpf_dump(&bpf, 0); #else fprintf(stderr, "BPF filter expressions not supported\n"); exit(1); #endif } static void resetaddr() { hashed = 0; pooled = 0; dynamic = -1; } static alist_t *newalist(ptr) alist_t *ptr; { alist_t *al; al = malloc(sizeof(*al)); if (al == NULL) return NULL; al->al_not = 0; al->al_next = ptr; return al; } static int makepool(list) alist_t *list; { ip_pool_node_t *n, *top; ip_pool_t pool; alist_t *a; int num; if (list == NULL) return 0; top = calloc(1, sizeof(*top)); if (top == NULL) return 0; for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) { n->ipn_addr.adf_family = a->al_family; n->ipn_mask.adf_family = a->al_family; (void *)bcopy((void *)&a->al_i6addr, (void *)&n->ipn_addr.adf_addr, sizeof(n->ipn_addr.adf_addr)); (void *)bcopy((void *)&a->al_i6mask, (void *)&n->ipn_mask.adf_addr, sizeof(n->ipn_mask.adf_addr)); n->ipn_info = a->al_not; if (a->al_next != NULL) { n->ipn_next = calloc(1, sizeof(*n)); if (n->ipn_next == NULL) yyerror("sorry, out of memory"); n = n->ipn_next; } } bzero((char *)&pool, sizeof(pool)); pool.ipo_unit = IPL_LOGIPF; pool.ipo_list = top; num = load_pool(&pool, ipfioctl[IPL_LOGLOOKUP]); while ((n = top) != NULL) { top = n->ipn_next; free(n); } return num; } static u_int makehash(list) alist_t *list; { iphtent_t *n, *top; iphtable_t iph; alist_t *a; int num; if (list == NULL) return 0; top = calloc(1, sizeof(*top)); if (top == NULL) return 0; for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) { n->ipe_family = a->al_family; (void *)bcopy((void *)&a->al_i6addr, (void *)&n->ipe_addr, sizeof(n->ipe_addr)); (void *)bcopy((void *)&a->al_i6mask, (void *)&n->ipe_mask, sizeof(n->ipe_mask)); n->ipe_value = 0; if (a->al_next != NULL) { n->ipe_next = calloc(1, sizeof(*n)); if (n->ipe_next == NULL) yyerror("sorry, out of memory"); n = n->ipe_next; } } bzero((char *)&iph, sizeof(iph)); iph.iph_unit = IPL_LOGIPF; iph.iph_type = IPHASH_LOOKUP; *iph.iph_name = '\0'; if (load_hash(&iph, top, ipfioctl[IPL_LOGLOOKUP]) == 0) sscanf(iph.iph_name, "%u", &num); else num = 0; while ((n = top) != NULL) { top = n->ipe_next; free(n); } return num; } void ipf_addrule(fd, ioctlfunc, ptr) int fd; ioctlfunc_t ioctlfunc; void *ptr; { ioctlcmd_t add, del; frentry_t *fr; ipfobj_t obj; fr = ptr; add = 0; del = 0; bzero((char *)&obj, sizeof(obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_size = sizeof(*fr); obj.ipfo_type = IPFOBJ_FRENTRY; obj.ipfo_ptr = ptr; if ((opts & OPT_DONOTHING) != 0) fd = -1; if (opts & OPT_ZERORULEST) { add = SIOCZRLST; } else if (opts & OPT_INACTIVE) { add = (u_int)fr->fr_hits ? SIOCINIFR : SIOCADIFR; del = SIOCRMIFR; } else { add = (u_int)fr->fr_hits ? SIOCINAFR : SIOCADAFR; del = SIOCRMAFR; } if (fr && (opts & OPT_OUTQUE)) fr->fr_flags |= FR_OUTQUE; if (fr->fr_hits) fr->fr_hits--; if (fr && (opts & OPT_VERBOSE)) printfr(fr, ioctlfunc); if (opts & OPT_DEBUG) { binprint(fr, sizeof(*fr)); if (fr->fr_data != NULL) binprint(fr->fr_data, fr->fr_dsize); } if ((opts & OPT_ZERORULEST) != 0) { if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { if ((opts & OPT_DONOTHING) == 0) { fprintf(stderr, "%d:", yylineNum); perror("ioctl(SIOCZRLST)"); } } else { #ifdef USE_QUAD_T printf("hits %qd bytes %qd ", (long long)fr->fr_hits, (long long)fr->fr_bytes); #else printf("hits %ld bytes %ld ", fr->fr_hits, fr->fr_bytes); #endif printfr(fr, ioctlfunc); } } else if ((opts & OPT_REMOVE) != 0) { if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) { if ((opts & OPT_DONOTHING) != 0) { fprintf(stderr, "%d:", yylineNum); perror("ioctl(delete rule)"); } } } else { if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { if (!(opts & OPT_DONOTHING)) { fprintf(stderr, "%d:", yylineNum); perror("ioctl(add/insert rule)"); } } } } static void setsyslog() { yysetdict(logwords); yybreakondot = 1; } static void unsetsyslog() { yyresetdict(); yybreakondot = 0; } static void fillgroup(fr) frentry_t *fr; { frentry_t *f; for (f = frold; f != NULL; f = f->fr_next) if (strncmp(f->fr_grhead, fr->fr_group, FR_GROUPLEN) == 0) break; if (f == NULL) return; /* * Only copy down matching fields if the rules are of the same type * and are of ipf type. The only fields that are copied are those * that impact the rule parsing itself, eg. need for knowing what the * protocol should be for rules with port comparisons in them. */ if (f->fr_type != fr->fr_type || f->fr_type != FR_T_IPF) return; if (fr->fr_v == 0 && f->fr_v != 0) fr->fr_v = f->fr_v; if (fr->fr_mproto == 0 && f->fr_mproto != 0) fr->fr_mproto = f->fr_mproto; if (fr->fr_proto == 0 && f->fr_proto != 0) fr->fr_proto = f->fr_proto; if ((fr->fr_mproto == 0) && ((fr->fr_flx & FI_TCPUDP) == 0) && ((f->fr_flx & FI_TCPUDP) != 0)) fr->fr_flx |= FI_TCPUDP; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2017 Gary Mills */ #include "ipf.h" typedef struct { int c; int e; int n; int p; int s; } mc_t; static char *portcmp[] = { "*", "==", "!=", "<", ">", "<=", ">=", "**", "***" }; static int count = 0; int intcmp __P((const void *, const void *)); static void indent __P((FILE *, int)); static void printeq __P((FILE *, char *, int, int, int)); static void printipeq __P((FILE *, char *, int, int, int)); static void addrule __P((FILE *, frentry_t *)); static void printhooks __P((FILE *, int, int, frgroup_t *)); static void emitheader __P((frgroup_t *, u_int, u_int)); static void emitGroup __P((int, int, void *, frentry_t *, char *, u_int, u_int)); static void emittail __P((void)); static void printCgroup __P((int, frentry_t *, mc_t *, char *)); #define FRC_IFN 0 #define FRC_V 1 #define FRC_P 2 #define FRC_FL 3 #define FRC_TOS 4 #define FRC_TTL 5 #define FRC_SRC 6 #define FRC_DST 7 #define FRC_TCP 8 #define FRC_SP 9 #define FRC_DP 10 #define FRC_OPT 11 #define FRC_SEC 12 #define FRC_ATH 13 #define FRC_ICT 14 #define FRC_ICC 15 #define FRC_MAX 16 static FILE *cfile = NULL; /* * This is called once per filter rule being loaded to emit data structures * required. */ void printc(fr) frentry_t *fr; { u_long *ulp; char *and; FILE *fp; int i; if (fr->fr_v != 4) return; if ((fr->fr_type != FR_T_IPF) && (fr->fr_type != FR_T_NONE)) return; if ((fr->fr_type == FR_T_IPF) && ((fr->fr_datype != FRI_NORMAL) || (fr->fr_satype != FRI_NORMAL))) return; if (cfile == NULL) cfile = fopen("ip_rules.c", "w"); if (cfile == NULL) return; fp = cfile; if (count == 0) { fprintf(fp, "/*\n"); fprintf(fp, "* Copyright (C) 1993-2000 by Darren Reed.\n"); fprintf(fp, "*\n"); fprintf(fp, "* Redistribution and use in source and binary forms are permitted\n"); fprintf(fp, "* provided that this notice is preserved and due credit is given\n"); fprintf(fp, "* to the original author and the contributors.\n"); fprintf(fp, "*/\n\n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)\n"); fprintf(fp, "# include \n"); fprintf(fp, "#endif\n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux)\n"); fprintf(fp, "# include \n"); fprintf(fp, "#endif\n"); fprintf(fp, "#if defined(__FreeBSD__) && (__FreeBSD_version > 220000)\n"); fprintf(fp, "# include \n"); fprintf(fp, "#else\n"); fprintf(fp, "# include \n"); fprintf(fp, "#endif /* FreeBSD */\n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \"netinet/ip_compat.h\"\n"); fprintf(fp, "#include \"netinet/ip_fil.h\"\n\n"); fprintf(fp, "#include \"netinet/ip_rules.h\"\n\n"); fprintf(fp, "#ifndef _KERNEL\n"); fprintf(fp, "# include \n"); fprintf(fp, "#endif /* _KERNEL */\n"); fprintf(fp, "\n"); fprintf(fp, "#ifdef IPFILTER_COMPILED\n"); } addrule(fp, fr); fr->fr_type |= FR_T_BUILTIN; and = ""; fr->fr_ref = 1; i = sizeof(*fr); if (i & -(1 - sizeof(*ulp))) i += sizeof(u_long); for (i /= sizeof(u_long), ulp = (u_long *)fr; i > 0; i--) { fprintf(fp, "%s%#lx", and, *ulp++); and = ", "; } fprintf(fp, "\n};\n"); fr->fr_type &= ~FR_T_BUILTIN; count++; fflush(fp); } static frgroup_t *groups = NULL; static void addrule(fp, fr) FILE *fp; frentry_t *fr; { frentry_t *f, **fpp; frgroup_t *g; u_long *ulp; char *and; int i; f = (frentry_t *)malloc(sizeof(*f)); if (f == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } bcopy((char *)fr, (char *)f, sizeof(*fr)); if (fr->fr_ipf) { f->fr_ipf = (fripf_t *)malloc(sizeof(*f->fr_ipf)); if (f->fr_ipf == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } bcopy((char *)fr->fr_ipf, (char *)f->fr_ipf, sizeof(*fr->fr_ipf)); } f->fr_next = NULL; for (g = groups; g != NULL; g = g->fg_next) if ((strncmp(g->fg_name, f->fr_group, FR_GROUPLEN) == 0) && (g->fg_flags == (f->fr_flags & FR_INOUT))) break; if (g == NULL) { g = (frgroup_t *)calloc(1, sizeof(*g)); if (g == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } g->fg_next = groups; groups = g; g->fg_head = f; bcopy(f->fr_group, g->fg_name, FR_GROUPLEN); g->fg_ref = 0; g->fg_flags = f->fr_flags & FR_INOUT; } for (fpp = &g->fg_start; *fpp != NULL; ) fpp = &((*fpp)->fr_next); *fpp = f; if (fr->fr_dsize > 0) { fprintf(fp, "\ static u_long ipf%s_rule_data_%s_%u[] = {\n", f->fr_flags & FR_INQUE ? "in" : "out", g->fg_name, g->fg_ref); and = ""; i = fr->fr_dsize; ulp = fr->fr_data; for (i /= sizeof(u_long); i > 0; i--) { fprintf(fp, "%s%#lx", and, *ulp++); and = ", "; } fprintf(fp, "\n};\n"); } fprintf(fp, "\nstatic u_long %s_rule_%s_%d[] = {\n", f->fr_flags & FR_INQUE ? "in" : "out", g->fg_name, g->fg_ref); g->fg_ref++; for (g = groups; g != NULL; g = g->fg_next) if ((strncmp(g->fg_name, f->fr_grhead, FR_GROUPLEN) == 0) && g->fg_flags == (f->fr_flags & FR_INOUT)) break; if (g == NULL) { g = (frgroup_t *)calloc(1, sizeof(*g)); if (g == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } g->fg_next = groups; groups = g; g->fg_head = f; bcopy(f->fr_grhead, g->fg_name, FR_GROUPLEN); g->fg_ref = 0; g->fg_flags = f->fr_flags & FR_INOUT; } } int intcmp(c1, c2) const void *c1, *c2; { const mc_t *i1 = (const mc_t *)c1, *i2 = (const mc_t *)c2; if (i1->n == i2->n) { return i1->c - i2->c; } return i2->n - i1->n; } static void indent(fp, in) FILE *fp; int in; { for (; in; in--) fputc('\t', fp); } static void printeq(fp, var, m, max, v) FILE *fp; char *var; int m, max, v; { if (m == max) fprintf(fp, "%s == %#x) {\n", var, v); else fprintf(fp, "(%s & %#x) == %#x) {\n", var, m, v); } /* * Parameters: var - IP# being compared * fl - 0 for positive match, 1 for negative match * m - netmask * v - required address */ static void printipeq(fp, var, fl, m, v) FILE *fp; char *var; int fl, m, v; { if (m == 0xffffffff) fprintf(fp, "%s ", var); else fprintf(fp, "(%s & %#x) ", var, m); fprintf(fp, "%c", fl ? '!' : '='); fprintf(fp, "= %#x) {\n", v); } void emit(num, dir, v, fr) int num, dir; void *v; frentry_t *fr; { u_int incnt, outcnt; frgroup_t *g; frentry_t *f; for (g = groups; g != NULL; g = g->fg_next) { if (dir == 0 || dir == -1) { if ((g->fg_flags & FR_INQUE) == 0) continue; for (incnt = 0, f = g->fg_start; f != NULL; f = f->fr_next) incnt++; emitGroup(num, dir, v, fr, g->fg_name, incnt, 0); } if (dir == 1 || dir == -1) { if ((g->fg_flags & FR_OUTQUE) == 0) continue; for (outcnt = 0, f = g->fg_start; f != NULL; f = f->fr_next) outcnt++; emitGroup(num, dir, v, fr, g->fg_name, 0, outcnt); } } if (num == -1 && dir == -1) { for (g = groups; g != NULL; g = g->fg_next) { if ((g->fg_flags & FR_INQUE) != 0) { for (incnt = 0, f = g->fg_start; f != NULL; f = f->fr_next) incnt++; if (incnt > 0) emitheader(g, incnt, 0); } if ((g->fg_flags & FR_OUTQUE) != 0) { for (outcnt = 0, f = g->fg_start; f != NULL; f = f->fr_next) outcnt++; if (outcnt > 0) emitheader(g, 0, outcnt); } } emittail(); fprintf(cfile, "#endif /* IPFILTER_COMPILED */\n"); } } static void emitheader(grp, incount, outcount) frgroup_t *grp; u_int incount, outcount; { static FILE *fph = NULL; frgroup_t *g; if (fph == NULL) { fph = fopen("ip_rules.h", "w"); if (fph == NULL) return; fprintf(fph, "extern int ipfrule_add __P((void));\n"); fprintf(fph, "extern int ipfrule_remove __P((void));\n"); } printhooks(cfile, incount, outcount, grp); if (incount) { fprintf(fph, "\n\ extern frentry_t *ipfrule_match_in_%s __P((fr_info_t *, u_32_t *));\n\ extern frentry_t *ipf_rules_in_%s[%d];\n", grp->fg_name, grp->fg_name, incount); for (g = groups; g != grp; g = g->fg_next) if ((strncmp(g->fg_name, grp->fg_name, FR_GROUPLEN) == 0) && g->fg_flags == grp->fg_flags) break; if (g == grp) { fprintf(fph, "\n\ extern int ipfrule_add_in_%s __P((void));\n\ extern int ipfrule_remove_in_%s __P((void));\n", grp->fg_name, grp->fg_name); } } if (outcount) { fprintf(fph, "\n\ extern frentry_t *ipfrule_match_out_%s __P((fr_info_t *, u_32_t *));\n\ extern frentry_t *ipf_rules_out_%s[%d];\n", grp->fg_name, grp->fg_name, outcount); for (g = groups; g != grp; g = g->fg_next) if ((strncmp(g->fg_name, grp->fg_name, FR_GROUPLEN) == 0) && g->fg_flags == grp->fg_flags) break; if (g == grp) { fprintf(fph, "\n\ extern int ipfrule_add_out_%s __P((void));\n\ extern int ipfrule_remove_out_%s __P((void));\n", grp->fg_name, grp->fg_name); } } } static void emittail() { frgroup_t *g; fprintf(cfile, "\n\ int ipfrule_add()\n\ {\n\ int err;\n\ \n"); for (g = groups; g != NULL; g = g->fg_next) fprintf(cfile, "\ err = ipfrule_add_%s_%s();\n\ if (err != 0)\n\ return err;\n", (g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name); fprintf(cfile, "\ return 0;\n"); fprintf(cfile, "}\n\ \n"); fprintf(cfile, "\n\ int ipfrule_remove()\n\ {\n\ int err;\n\ \n"); for (g = groups; g != NULL; g = g->fg_next) fprintf(cfile, "\ err = ipfrule_remove_%s_%s();\n\ if (err != 0)\n\ return err;\n", (g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name); fprintf(cfile, "\ return 0;\n"); fprintf(cfile, "}\n"); } static void emitGroup(num, dir, v, fr, group, incount, outcount) int num, dir; void *v; frentry_t *fr; char *group; u_int incount, outcount; { static FILE *fp = NULL; static int header[2] = { 0, 0 }; static char egroup[FR_GROUPLEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; static int openfunc = 0; static mc_t *n = NULL; static int sin = 0; frentry_t *f; frgroup_t *g; fripf_t *ipf; int i, in, j; mc_t *m = v; if (fp == NULL) fp = cfile; if (fp == NULL) return; if (strncmp(egroup, group, FR_GROUPLEN)) { for (sin--; sin > 0; sin--) { indent(fp, sin); fprintf(fp, "}\n"); } if (openfunc == 1) { fprintf(fp, "\treturn fr;\n}\n"); openfunc = 0; if (n != NULL) { free(n); n = NULL; } } sin = 0; header[0] = 0; header[1] = 0; strncpy(egroup, group, FR_GROUPLEN); } else if (openfunc == 1 && num < 0) { if (n != NULL) { free(n); n = NULL; } for (sin--; sin > 0; sin--) { indent(fp, sin); fprintf(fp, "}\n"); } if (openfunc == 1) { fprintf(fp, "\treturn fr;\n}\n"); openfunc = 0; } } if (dir == -1) return; for (g = groups; g != NULL; g = g->fg_next) { if (dir == 0 && (g->fg_flags & FR_INQUE) == 0) continue; else if (dir == 1 && (g->fg_flags & FR_OUTQUE) == 0) continue; if (strncmp(g->fg_name, group, FR_GROUPLEN) != 0) continue; break; } /* * Output the array of pointers to rules for this group. */ if (num == -2 && dir == 0 && header[0] == 0 && incount != 0) { fprintf(fp, "\nfrentry_t *ipf_rules_in_%s[%d] = {", group, incount); for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { if ((f->fr_flags & FR_INQUE) == 0) continue; if ((i & 1) == 0) { fprintf(fp, "\n\t"); } fprintf(fp, "(frentry_t *)&in_rule_%s_%d", f->fr_group, i); if (i + 1 < incount) fprintf(fp, ", "); i++; } fprintf(fp, "\n};\n"); } if (num == -2 && dir == 1 && header[1] == 0 && outcount != 0) { fprintf(fp, "\nfrentry_t *ipf_rules_out_%s[%d] = {", group, outcount); for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { if ((f->fr_flags & FR_OUTQUE) == 0) continue; if ((i & 1) == 0) { fprintf(fp, "\n\t"); } fprintf(fp, "(frentry_t *)&out_rule_%s_%d", f->fr_group, i); if (i + 1 < outcount) fprintf(fp, ", "); i++; } fprintf(fp, "\n};\n"); fp = NULL; } if (num < 0) return; in = 0; ipf = fr->fr_ipf; /* * If the function header has not been printed then print it now. */ if (header[dir] == 0) { int pdst = 0, psrc = 0; openfunc = 1; fprintf(fp, "\nfrentry_t *ipfrule_match_%s_%s(fin, passp)\n", (dir == 0) ? "in" : "out", group); fprintf(fp, "fr_info_t *fin;\n"); fprintf(fp, "u_32_t *passp;\n"); fprintf(fp, "{\n"); fprintf(fp, "\tfrentry_t *fr = NULL;\n"); /* * Print out any variables that need to be declared. */ for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { if (incount + outcount > m[FRC_SRC].e + 1) psrc = 1; if (incount + outcount > m[FRC_DST].e + 1) pdst = 1; } if (psrc == 1) fprintf(fp, "\tu_32_t src = ntohl(%s);\n", "fin->fin_fi.fi_saddr"); if (pdst == 1) fprintf(fp, "\tu_32_t dst = ntohl(%s);\n", "fin->fin_fi.fi_daddr"); } for (i = 0; i < FRC_MAX; i++) { switch(m[i].c) { case FRC_IFN : if (*fr->fr_ifname) m[i].s = 1; break; case FRC_V : if (ipf != NULL && ipf->fri_mip.fi_v != 0) m[i].s = 1; break; case FRC_FL : if (ipf != NULL && ipf->fri_mip.fi_flx != 0) m[i].s = 1; break; case FRC_P : if (ipf != NULL && ipf->fri_mip.fi_p != 0) m[i].s = 1; break; case FRC_TTL : if (ipf != NULL && ipf->fri_mip.fi_ttl != 0) m[i].s = 1; break; case FRC_TOS : if (ipf != NULL && ipf->fri_mip.fi_tos != 0) m[i].s = 1; break; case FRC_TCP : if (ipf == NULL) break; if ((ipf->fri_ip.fi_p == IPPROTO_TCP) && fr->fr_tcpfm != 0) m[i].s = 1; break; case FRC_SP : if (ipf == NULL) break; if (fr->fr_scmp == FR_INRANGE) m[i].s = 1; else if (fr->fr_scmp == FR_OUTRANGE) m[i].s = 1; else if (fr->fr_scmp != 0) m[i].s = 1; break; case FRC_DP : if (ipf == NULL) break; if (fr->fr_dcmp == FR_INRANGE) m[i].s = 1; else if (fr->fr_dcmp == FR_OUTRANGE) m[i].s = 1; else if (fr->fr_dcmp != 0) m[i].s = 1; break; case FRC_SRC : if (ipf == NULL) break; if (fr->fr_satype == FRI_LOOKUP) { ; } else if ((fr->fr_smask != 0) || (fr->fr_flags & FR_NOTSRCIP) != 0) m[i].s = 1; break; case FRC_DST : if (ipf == NULL) break; if (fr->fr_datype == FRI_LOOKUP) { ; } else if ((fr->fr_dmask != 0) || (fr->fr_flags & FR_NOTDSTIP) != 0) m[i].s = 1; break; case FRC_OPT : if (ipf == NULL) break; if (fr->fr_optmask != 0) m[i].s = 1; break; case FRC_SEC : if (ipf == NULL) break; if (fr->fr_secmask != 0) m[i].s = 1; break; case FRC_ATH : if (ipf == NULL) break; if (fr->fr_authmask != 0) m[i].s = 1; break; case FRC_ICT : if (ipf == NULL) break; if ((fr->fr_icmpm & 0xff00) != 0) m[i].s = 1; break; case FRC_ICC : if (ipf == NULL) break; if ((fr->fr_icmpm & 0xff) != 0) m[i].s = 1; break; } } if (!header[dir]) { fprintf(fp, "\n"); header[dir] = 1; sin = 0; } qsort(m, FRC_MAX, sizeof(mc_t), intcmp); if (n) { /* * Calculate the indentation interval upto the last common * common comparison being made. */ for (i = 0, in = 1; i < FRC_MAX; i++) { if (n[i].c != m[i].c) break; if (n[i].s != m[i].s) break; if (n[i].s) { if (n[i].n && (n[i].n > n[i].e)) { m[i].p++; in += m[i].p; break; } if (n[i].e > 0) { in++; } else break; } } if (sin != in) { for (j = sin - 1; j >= in; j--) { indent(fp, j); fprintf(fp, "}\n"); } } } else { in = 1; i = 0; } /* * print out C code that implements a filter rule. */ for (; i < FRC_MAX; i++) { switch(m[i].c) { case FRC_IFN : if (m[i].s) { indent(fp, in); fprintf(fp, "if (fin->fin_ifp == "); fprintf(fp, "ipf_rules_%s_%s[%d]->fr_ifa) {\n", dir ? "out" : "in", group, num); in++; } break; case FRC_V : if (m[i].s) { indent(fp, in); fprintf(fp, "if (fin->fin_v == %d) {\n", ipf->fri_ip.fi_v); in++; } break; case FRC_FL : if (m[i].s) { indent(fp, in); fprintf(fp, "if ("); printeq(fp, "fin->fin_flx", ipf->fri_mip.fi_flx, 0xf, ipf->fri_ip.fi_flx); in++; } break; case FRC_P : if (m[i].s) { indent(fp, in); fprintf(fp, "if (fin->fin_p == %d) {\n", ipf->fri_ip.fi_p); in++; } break; case FRC_TTL : if (m[i].s) { indent(fp, in); fprintf(fp, "if ("); printeq(fp, "fin->fin_ttl", ipf->fri_mip.fi_ttl, 0xff, ipf->fri_ip.fi_ttl); in++; } break; case FRC_TOS : if (m[i].s) { indent(fp, in); fprintf(fp, "if (fin->fin_tos"); printeq(fp, "fin->fin_tos", ipf->fri_mip.fi_tos, 0xff, ipf->fri_ip.fi_tos); in++; } break; case FRC_TCP : if (m[i].s) { indent(fp, in); fprintf(fp, "if ("); printeq(fp, "fin->fin_tcpf", fr->fr_tcpfm, 0xff, fr->fr_tcpf); in++; } break; case FRC_SP : if (!m[i].s) break; if (fr->fr_scmp == FR_INRANGE) { indent(fp, in); fprintf(fp, "if ((fin->fin_data[0] > %d) && ", fr->fr_sport); fprintf(fp, "(fin->fin_data[0] < %d)", fr->fr_stop); fprintf(fp, ") {\n"); in++; } else if (fr->fr_scmp == FR_OUTRANGE) { indent(fp, in); fprintf(fp, "if ((fin->fin_data[0] < %d) || ", fr->fr_sport); fprintf(fp, "(fin->fin_data[0] > %d)", fr->fr_stop); fprintf(fp, ") {\n"); in++; } else if (fr->fr_scmp) { indent(fp, in); fprintf(fp, "if (fin->fin_data[0] %s %d)", portcmp[fr->fr_scmp], fr->fr_sport); fprintf(fp, " {\n"); in++; } break; case FRC_DP : if (!m[i].s) break; if (fr->fr_dcmp == FR_INRANGE) { indent(fp, in); fprintf(fp, "if ((fin->fin_data[1] > %d) && ", fr->fr_dport); fprintf(fp, "(fin->fin_data[1] < %d)", fr->fr_dtop); fprintf(fp, ") {\n"); in++; } else if (fr->fr_dcmp == FR_OUTRANGE) { indent(fp, in); fprintf(fp, "if ((fin->fin_data[1] < %d) || ", fr->fr_dport); fprintf(fp, "(fin->fin_data[1] > %d)", fr->fr_dtop); fprintf(fp, ") {\n"); in++; } else if (fr->fr_dcmp) { indent(fp, in); fprintf(fp, "if (fin->fin_data[1] %s %d)", portcmp[fr->fr_dcmp], fr->fr_dport); fprintf(fp, " {\n"); in++; } break; case FRC_SRC : if (!m[i].s) break; if (fr->fr_satype == FRI_LOOKUP) { ; } else if ((fr->fr_smask != 0) || (fr->fr_flags & FR_NOTSRCIP) != 0) { indent(fp, in); fprintf(fp, "if ("); printipeq(fp, "src", fr->fr_flags & FR_NOTSRCIP, fr->fr_smask, fr->fr_saddr); in++; } break; case FRC_DST : if (!m[i].s) break; if (fr->fr_datype == FRI_LOOKUP) { ; } else if ((fr->fr_dmask != 0) || (fr->fr_flags & FR_NOTDSTIP) != 0) { indent(fp, in); fprintf(fp, "if ("); printipeq(fp, "dst", fr->fr_flags & FR_NOTDSTIP, fr->fr_dmask, fr->fr_daddr); in++; } break; case FRC_OPT : if (m[i].s) { indent(fp, in); fprintf(fp, "if ("); printeq(fp, "fin->fin_fi.fi_optmsk", fr->fr_optmask, 0xffffffff, fr->fr_optbits); in++; } break; case FRC_SEC : if (m[i].s) { indent(fp, in); fprintf(fp, "if ("); printeq(fp, "fin->fin_fi.fi_secmsk", fr->fr_secmask, 0xffff, fr->fr_secbits); in++; } break; case FRC_ATH : if (m[i].s) { indent(fp, in); fprintf(fp, "if ("); printeq(fp, "fin->fin_fi.fi_authmsk", fr->fr_authmask, 0xffff, fr->fr_authbits); in++; } break; case FRC_ICT : if (m[i].s) { indent(fp, in); fprintf(fp, "if ("); printeq(fp, "fin->fin_data[0]", fr->fr_icmpm & 0xff00, 0xffff, fr->fr_icmp & 0xff00); in++; } break; case FRC_ICC : if (m[i].s) { indent(fp, in); fprintf(fp, "if ("); printeq(fp, "fin->fin_data[0]", fr->fr_icmpm & 0xff, 0xffff, fr->fr_icmp & 0xff); in++; } break; } } indent(fp, in); if (fr->fr_flags & FR_QUICK) { fprintf(fp, "return (frentry_t *)&%s_rule_%s_%d;\n", fr->fr_flags & FR_INQUE ? "in" : "out", fr->fr_group, num); } else { fprintf(fp, "fr = (frentry_t *)&%s_rule_%s_%d;\n", fr->fr_flags & FR_INQUE ? "in" : "out", fr->fr_group, num); } if (n == NULL) { n = (mc_t *)malloc(sizeof(*n) * FRC_MAX); if (n == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } } bcopy((char *)m, (char *)n, sizeof(*n) * FRC_MAX); sin = in; } void printC(dir) int dir; { static mc_t *m = NULL; frgroup_t *g; if (m == NULL) { m = (mc_t *)calloc(1, sizeof(*m) * FRC_MAX); if (m == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } } for (g = groups; g != NULL; g = g->fg_next) { if ((dir == 0) && ((g->fg_flags & FR_INQUE) != 0)) printCgroup(dir, g->fg_start, m, g->fg_name); if ((dir == 1) && ((g->fg_flags & FR_OUTQUE) != 0)) printCgroup(dir, g->fg_start, m, g->fg_name); } emit(-1, dir, m, NULL); } /* * Now print out code to implement all of the rules. */ static void printCgroup(dir, top, m, group) int dir; frentry_t *top; mc_t *m; char *group; { frentry_t *fr, *fr1; int i, n, rn; u_int count; for (count = 0, fr1 = top; fr1 != NULL; fr1 = fr1->fr_next) { if ((dir == 0) && ((fr1->fr_flags & FR_INQUE) != 0)) count++; else if ((dir == 1) && ((fr1->fr_flags & FR_OUTQUE) != 0)) count++; } if (dir == 0) emitGroup(-2, dir, m, fr1, group, count, 0); else if (dir == 1) emitGroup(-2, dir, m, fr1, group, 0, count); /* * Before printing each rule, check to see how many of its fields are * matched by subsequent rules. */ for (fr1 = top, rn = 0; fr1 != NULL; fr1 = fr1->fr_next, rn++) { if (!dir && !(fr1->fr_flags & FR_INQUE)) continue; if (dir && !(fr1->fr_flags & FR_OUTQUE)) continue; n = 0xfffffff; for (i = 0; i < FRC_MAX; i++) m[i].e = 0; qsort(m, FRC_MAX, sizeof(mc_t), intcmp); for (i = 0; i < FRC_MAX; i++) { m[i].c = i; m[i].e = 0; m[i].n = 0; m[i].s = 0; } for (fr = fr1->fr_next; fr; fr = fr->fr_next) { if (!dir && !(fr->fr_flags & FR_INQUE)) continue; if (dir && !(fr->fr_flags & FR_OUTQUE)) continue; if ((n & 0x0001) && !strcmp(fr1->fr_ifname, fr->fr_ifname)) { m[FRC_IFN].e++; m[FRC_IFN].n++; } else n &= ~0x0001; if ((n & 0x0002) && (fr1->fr_v == fr->fr_v)) { m[FRC_V].e++; m[FRC_V].n++; } else n &= ~0x0002; if ((n & 0x0004) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && (fr1->fr_mip.fi_flx == fr->fr_mip.fi_flx) && (fr1->fr_ip.fi_flx == fr->fr_ip.fi_flx)) { m[FRC_FL].e++; m[FRC_FL].n++; } else n &= ~0x0004; if ((n & 0x0008) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && (fr1->fr_proto == fr->fr_proto)) { m[FRC_P].e++; m[FRC_P].n++; } else n &= ~0x0008; if ((n & 0x0010) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && (fr1->fr_ttl == fr->fr_ttl)) { m[FRC_TTL].e++; m[FRC_TTL].n++; } else n &= ~0x0010; if ((n & 0x0020) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && (fr1->fr_tos == fr->fr_tos)) { m[FRC_TOS].e++; m[FRC_TOS].n++; } else n &= ~0x0020; if ((n & 0x0040) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && ((fr1->fr_tcpfm == fr->fr_tcpfm) && (fr1->fr_tcpf == fr->fr_tcpf))) { m[FRC_TCP].e++; m[FRC_TCP].n++; } else n &= ~0x0040; if ((n & 0x0080) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && ((fr1->fr_scmp == fr->fr_scmp) && (fr1->fr_stop == fr->fr_stop) && (fr1->fr_sport == fr->fr_sport))) { m[FRC_SP].e++; m[FRC_SP].n++; } else n &= ~0x0080; if ((n & 0x0100) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && ((fr1->fr_dcmp == fr->fr_dcmp) && (fr1->fr_dtop == fr->fr_dtop) && (fr1->fr_dport == fr->fr_dport))) { m[FRC_DP].e++; m[FRC_DP].n++; } else n &= ~0x0100; if ((n & 0x0200) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && ((fr1->fr_satype == FRI_LOOKUP) && (fr->fr_satype == FRI_LOOKUP) && (fr1->fr_srcnum == fr->fr_srcnum))) { m[FRC_SRC].e++; m[FRC_SRC].n++; } else if ((n & 0x0200) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && (((fr1->fr_flags & FR_NOTSRCIP) == (fr->fr_flags & FR_NOTSRCIP)))) { if ((fr1->fr_smask == fr->fr_smask) && (fr1->fr_saddr == fr->fr_saddr)) m[FRC_SRC].e++; else n &= ~0x0200; if (fr1->fr_smask && (fr1->fr_saddr & fr1->fr_smask) == (fr->fr_saddr & fr1->fr_smask)) { m[FRC_SRC].n++; n |= 0x0200; } } else { n &= ~0x0200; } if ((n & 0x0400) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && ((fr1->fr_datype == FRI_LOOKUP) && (fr->fr_datype == FRI_LOOKUP) && (fr1->fr_dstnum == fr->fr_dstnum))) { m[FRC_DST].e++; m[FRC_DST].n++; } else if ((n & 0x0400) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && (((fr1->fr_flags & FR_NOTDSTIP) == (fr->fr_flags & FR_NOTDSTIP)))) { if ((fr1->fr_dmask == fr->fr_dmask) && (fr1->fr_daddr == fr->fr_daddr)) m[FRC_DST].e++; else n &= ~0x0400; if (fr1->fr_dmask && (fr1->fr_daddr & fr1->fr_dmask) == (fr->fr_daddr & fr1->fr_dmask)) { m[FRC_DST].n++; n |= 0x0400; } } else { n &= ~0x0400; } if ((n & 0x0800) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && (fr1->fr_optmask == fr->fr_optmask) && (fr1->fr_optbits == fr->fr_optbits)) { m[FRC_OPT].e++; m[FRC_OPT].n++; } else n &= ~0x0800; if ((n & 0x1000) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && (fr1->fr_secmask == fr->fr_secmask) && (fr1->fr_secbits == fr->fr_secbits)) { m[FRC_SEC].e++; m[FRC_SEC].n++; } else n &= ~0x1000; if ((n & 0x10000) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && (fr1->fr_authmask == fr->fr_authmask) && (fr1->fr_authbits == fr->fr_authbits)) { m[FRC_ATH].e++; m[FRC_ATH].n++; } else n &= ~0x10000; if ((n & 0x20000) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && ((fr1->fr_icmpm & 0xff00) == (fr->fr_icmpm & 0xff00)) && ((fr1->fr_icmp & 0xff00) == (fr->fr_icmp & 0xff00))) { m[FRC_ICT].e++; m[FRC_ICT].n++; } else n &= ~0x20000; if ((n & 0x40000) && (fr->fr_type == fr1->fr_type) && (fr->fr_type == FR_T_IPF) && ((fr1->fr_icmpm & 0xff) == (fr->fr_icmpm & 0xff)) && ((fr1->fr_icmp & 0xff) == (fr->fr_icmp & 0xff))) { m[FRC_ICC].e++; m[FRC_ICC].n++; } else n &= ~0x40000; } /*msort(m);*/ if (dir == 0) emitGroup(rn, dir, m, fr1, group, count, 0); else if (dir == 1) emitGroup(rn, dir, m, fr1, group, 0, count); } } static void printhooks(fp, in, out, grp) FILE *fp; int in; int out; frgroup_t *grp; { frentry_t *fr; char *group; int dogrp, i; char *instr; group = grp->fg_name; dogrp = 0; if (in && out) { fprintf(stderr, "printhooks called with both in and out set\n"); exit(1); } if (in) { instr = "in"; } else if (out) { instr = "out"; } else { instr = "???"; } fprintf(fp, "static frentry_t ipfrule_%s_%s;\n", instr, group); fprintf(fp, "\ \n\ int ipfrule_add_%s_%s()\n", instr, group); fprintf(fp, "\ {\n\ int i, j, err = 0, max;\n\ frentry_t *fp;\n"); if (dogrp) fprintf(fp, "\ frgroup_t *fg;\n"); fprintf(fp, "\n"); for (i = 0, fr = grp->fg_start; fr != NULL; i++, fr = fr->fr_next) if (fr->fr_dsize > 0) { fprintf(fp, "\ ipf_rules_%s_%s[%d]->fr_data = &ipf%s_rule_data_%s_%u;\n", instr, grp->fg_name, i, instr, grp->fg_name, i); } fprintf(fp, "\ max = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *);\n\ for (i = 0; i < max; i++) {\n\ fp = ipf_rules_%s_%s[i];\n\ fp->fr_next = NULL;\n", instr, group, instr, group); fprintf(fp, "\ for (j = i + 1; j < max; j++)\n\ if (strncmp(fp->fr_group,\n\ ipf_rules_%s_%s[j]->fr_group,\n\ FR_GROUPLEN) == 0) {\n\ fp->fr_next = ipf_rules_%s_%s[j];\n\ break;\n\ }\n", instr, group, instr, group); if (dogrp) fprintf(fp, "\ \n\ if (fp->fr_grhead != 0) {\n\ fg = fr_addgroup(fp->fr_grhead, fp, FR_INQUE,\n\ IPL_LOGIPF, 0);\n\ if (fg != NULL)\n\ fp->fr_grp = &fg->fg_start;\n\ }\n"); fprintf(fp, "\ }\n\ \n\ fp = &ipfrule_%s_%s;\n", instr, group); fprintf(fp, "\ bzero((char *)fp, sizeof(*fp));\n\ fp->fr_type = FR_T_CALLFUNC|FR_T_BUILTIN;\n\ fp->fr_flags = FR_%sQUE|FR_NOMATCH;\n\ fp->fr_data = (void *)ipf_rules_%s_%s[0];\n", (in != 0) ? "IN" : "OUT", instr, group); fprintf(fp, "\ fp->fr_dsize = sizeof(ipf_rules_%s_%s[0]);\n", instr, group); fprintf(fp, "\ fp->fr_v = 4;\n\ fp->fr_func = (ipfunc_t)ipfrule_match_%s_%s;\n\ err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_active, 0);\n", instr, group); fprintf(fp, "\treturn err;\n}\n"); fprintf(fp, "\n\n\ int ipfrule_remove_%s_%s()\n", instr, group); fprintf(fp, "\ {\n\ int err = 0, i;\n\ frentry_t *fp;\n\ \n\ /*\n\ * Try to remove the %sbound rule.\n", instr); fprintf(fp, "\ */\n\ if (ipfrule_%s_%s.fr_ref > 0) {\n", instr, group); fprintf(fp, "\ err = EBUSY;\n\ } else {\n"); fprintf(fp, "\ i = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *) - 1;\n\ for (; i >= 0; i--) {\n\ fp = ipf_rules_%s_%s[i];\n\ if (fp->fr_ref > 1) {\n\ err = EBUSY;\n\ break;\n\ }\n\ }\n\ }\n\ if (err == 0)\n\ err = frrequest(IPL_LOGIPF, SIOCDELFR,\n\ (caddr_t)&ipfrule_%s_%s, fr_active, 0);\n", instr, group, instr, group, instr, group); fprintf(fp, "\ if (err)\n\ return err;\n\ \n\n"); fprintf(fp, "\treturn err;\n}\n"); } /* * Copyright (C) 1999-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #ifdef __FreeBSD__ # ifndef __FreeBSD_cc_version # include # else # if __FreeBSD_cc_version < 430000 # include # endif # endif #endif #include #include #include #include #include #if !defined(__SVR4) && !defined(__GNUC__) #include #endif #include #include #include #include #include #include #include #include #include #include #include #if __FreeBSD_version >= 300000 # include #endif #include #include #include #include #include "ipf.h" #include "netinet/ipl.h" #include "ipfzone.h" #if !defined(lint) static const char rcsid[] = "@(#)Id: ipfs.c,v 1.12 2003/12/01 01:56:53 darrenr Exp"; #endif #ifndef IPF_SAVEDIR # define IPF_SAVEDIR "/var/db/ipf" #endif #ifndef IPF_NATFILE # define IPF_NATFILE "ipnat.ipf" #endif #ifndef IPF_STATEFILE # define IPF_STATEFILE "ipstate.ipf" #endif #if !defined(__SVR4) && defined(__GNUC__) extern char *index __P((const char *, int)); #endif extern char *optarg; extern int optind; int main __P((int, char *[])); void usage __P((void)); int changestateif __P((char *, char *)); int changenatif __P((char *, char *)); int readstate __P((int, char *)); int readnat __P((int, char *)); int writestate __P((int, char *)); int opendevice __P((char *)); void closedevice __P((int)); int setlock __P((int, int)); int writeall __P((char *)); int readall __P((char *)); int writenat __P((int, char *)); int opts = 0; char *progname; void usage() { const char *zoneopt = "[-G|-z zonename] "; fprintf(stderr, "usage: %s %s[-nv] -l\n", progname, zoneopt); fprintf(stderr, "usage: %s %s[-nv] -u\n", progname, zoneopt); fprintf(stderr, "usage: %s %s[-nv] [-d ] -R\n", progname, zoneopt); fprintf(stderr, "usage: %s %s[-nv] [-d ] -W\n", progname, zoneopt); fprintf(stderr, "usage: %s %s[-nv] [-N|-S] [-f ] -r\n", progname, zoneopt); fprintf(stderr, "usage: %s %s[-nv] [-N|-S] [-f ] -w\n", progname, zoneopt); fprintf(stderr, "usage: %s %s[-nv] [-N|-S] -f -i ,\n", progname, zoneopt); exit(1); } /* * Change interface names in state information saved out to disk. */ int changestateif(ifs, fname) char *ifs, *fname; { int fd, olen, nlen, rw; ipstate_save_t ips; off_t pos; char *s; s = strchr(ifs, ','); if (!s) usage(); *s++ = '\0'; nlen = strlen(s); olen = strlen(ifs); if (nlen >= sizeof(ips.ips_is.is_ifname) || olen >= sizeof(ips.ips_is.is_ifname)) usage(); fd = open(fname, O_RDWR); if (fd == -1) { perror("open"); exit(1); } for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) { rw = 0; if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) { strcpy(ips.ips_is.is_ifname[0], s); rw = 1; } if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) { strcpy(ips.ips_is.is_ifname[1], s); rw = 1; } if (rw == 1) { if (lseek(fd, pos, SEEK_SET) != pos) { perror("lseek"); exit(1); } if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) { perror("write"); exit(1); } } pos = lseek(fd, 0, SEEK_CUR); } close(fd); return 0; } /* * Change interface names in NAT information saved out to disk. */ int changenatif(ifs, fname) char *ifs, *fname; { int fd, olen, nlen, rw; nat_save_t ipn; nat_t *nat; off_t pos; char *s; s = strchr(ifs, ','); if (!s) usage(); *s++ = '\0'; nlen = strlen(s); olen = strlen(ifs); nat = &ipn.ipn_nat; if (nlen >= sizeof(nat->nat_ifnames[0]) || olen >= sizeof(nat->nat_ifnames[0])) usage(); fd = open(fname, O_RDWR); if (fd == -1) { perror("open"); exit(1); } for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) { rw = 0; if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) { strcpy(nat->nat_ifnames[0], s); rw = 1; } if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) { strcpy(nat->nat_ifnames[1], s); rw = 1; } if (rw == 1) { if (lseek(fd, pos, SEEK_SET) != pos) { perror("lseek"); exit(1); } if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) { perror("write"); exit(1); } } pos = lseek(fd, 0, SEEK_CUR); } close(fd); return 0; } int main(argc,argv) int argc; char *argv[]; { int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0; char *dirname = NULL, *filename = NULL, *ifs = NULL; progname = argv[0]; while ((c = getopt(argc, argv, "d:f:G:lNnSRruvWwz:")) != -1) switch (c) { case 'd' : if ((set == 0) && !dirname && !filename) dirname = optarg; else usage(); break; case 'f' : if ((set == 0) && !dirname && !filename) filename = optarg; else usage(); break; case 'G' : setzonename_global(optarg); break; case 'i' : ifs = optarg; set = 1; break; case 'l' : if (filename || dirname || set) usage(); lock = 1; set = 1; break; case 'n' : opts |= OPT_DONOTHING; break; case 'N' : if ((ns >= 0) || dirname || (rw != -1) || set) usage(); ns = 0; set = 1; break; case 'r' : if (dirname || (rw != -1) || (ns == -1)) usage(); rw = 0; set = 1; break; case 'R' : rw = 2; set = 1; break; case 'S' : if ((ns >= 0) || dirname || (rw != -1) || set) usage(); ns = 1; set = 1; break; case 'u' : if (filename || dirname || set) usage(); lock = 0; set = 1; break; case 'v' : opts |= OPT_VERBOSE; break; case 'w' : if (dirname || (rw != -1) || (ns == -1)) usage(); rw = 1; set = 1; break; case 'W' : rw = 3; set = 1; break; case 'z' : setzonename(optarg); break; case '?' : default : usage(); } if (ifs) { if (!filename || ns < 0) usage(); if (ns == 0) return changenatif(ifs, filename); else return changestateif(ifs, filename); } if ((ns >= 0) || (lock >= 0)) { if (lock >= 0) devfd = opendevice(NULL); else if (ns >= 0) { if (ns == 1) devfd = opendevice(IPSTATE_NAME); else if (ns == 0) devfd = opendevice(IPNAT_NAME); } if (devfd == -1) exit(1); } if (lock >= 0) err = setlock(devfd, lock); else if (rw >= 0) { if (rw & 1) { /* WRITE */ if (rw & 2) err = writeall(dirname); else { if (ns == 0) err = writenat(devfd, filename); else if (ns == 1) err = writestate(devfd, filename); } } else { if (rw & 2) err = readall(dirname); else { if (ns == 0) err = readnat(devfd, filename); else if (ns == 1) err = readstate(devfd, filename); } } } return err; } int opendevice(ipfdev) char *ipfdev; { int fd = -1; if (opts & OPT_DONOTHING) return -2; if (!ipfdev) ipfdev = IPL_NAME; if ((fd = open(ipfdev, O_RDWR)) == -1) if ((fd = open(ipfdev, O_RDONLY)) == -1) perror("open device"); if (setzone(fd) != 0) { close(fd); fd = -1; } return fd; } void closedevice(fd) int fd; { close(fd); } int setlock(fd, lock) int fd, lock; { if (opts & OPT_VERBOSE) printf("Turn lock %s\n", lock ? "on" : "off"); if (!(opts & OPT_DONOTHING)) { if (ioctl(fd, SIOCSTLCK, &lock) == -1) { perror("SIOCSTLCK"); return 1; } if (opts & OPT_VERBOSE) printf("Lock now %s\n", lock ? "on" : "off"); } return 0; } int writestate(fd, file) int fd; char *file; { ipstate_save_t ips, *ipsp; ipfobj_t obj; int wfd = -1; if (!file) file = IPF_STATEFILE; wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); if (wfd == -1) { fprintf(stderr, "%s ", file); perror("state:open"); return 1; } ipsp = &ips; bzero((char *)&obj, sizeof(obj)); bzero((char *)ipsp, sizeof(ips)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_size = sizeof(*ipsp); obj.ipfo_type = IPFOBJ_STATESAVE; obj.ipfo_ptr = ipsp; do { if (opts & OPT_VERBOSE) printf("Getting state from addr %p\n", ips.ips_next); if (ioctl(fd, SIOCSTGET, &obj)) { if (errno == ENOENT) break; perror("state:SIOCSTGET"); close(wfd); return 1; } if (opts & OPT_VERBOSE) printf("Got state next %p\n", ips.ips_next); if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) { perror("state:write"); close(wfd); return 1; } } while (ips.ips_next != NULL); close(wfd); return 0; } int readstate(fd, file) int fd; char *file; { ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL; int sfd = -1, i; ipfobj_t obj; if (!file) file = IPF_STATEFILE; sfd = open(file, O_RDONLY, 0600); if (sfd == -1) { fprintf(stderr, "%s ", file); perror("open"); return 1; } bzero((char *)&ips, sizeof(ips)); /* * 1. Read all state information in. */ do { i = read(sfd, &ips, sizeof(ips)); if (i == -1) { perror("read"); close(sfd); return 1; } if (i == 0) break; if (i != sizeof(ips)) { fprintf(stderr, "state:incomplete read: %d != %d\n", i, (int)sizeof(ips)); close(sfd); return 1; } is = (ipstate_save_t *)malloc(sizeof(*is)); if(!is) { fprintf(stderr, "malloc failed\n"); return 1; } bcopy((char *)&ips, (char *)is, sizeof(ips)); /* * Check to see if this is the first state entry that will * reference a particular rule and if so, flag it as such * else just adjust the rule pointer to become a pointer to * the other. We do this so we have a means later for tracking * who is referencing us when we get back the real pointer * in is_rule after doing the ioctl. */ for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next) if (is1->ips_rule == is->ips_rule) break; if (is1 == NULL) is->ips_is.is_flags |= SI_NEWFR; else is->ips_rule = (void *)&is1->ips_rule; /* * Use a tail-queue type list (add things to the end).. */ is->ips_next = NULL; if (!ipshead) ipshead = is; if (ipstail) ipstail->ips_next = is; ipstail = is; } while (1); close(sfd); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_size = sizeof(*is); obj.ipfo_type = IPFOBJ_STATESAVE; for (is = ipshead; is; is = is->ips_next) { if (opts & OPT_VERBOSE) printf("Loading new state table entry\n"); if (is->ips_is.is_flags & SI_NEWFR) { if (opts & OPT_VERBOSE) printf("Loading new filter rule\n"); } obj.ipfo_ptr = is; if (!(opts & OPT_DONOTHING)) if (ioctl(fd, SIOCSTPUT, &obj)) { perror("SIOCSTPUT"); return 1; } if (is->ips_is.is_flags & SI_NEWFR) { if (opts & OPT_VERBOSE) printf("Real rule addr %p\n", is->ips_rule); for (is1 = is->ips_next; is1; is1 = is1->ips_next) if (is1->ips_rule == (frentry_t *)&is->ips_rule) is1->ips_rule = is->ips_rule; } } return 0; } int readnat(fd, file) int fd; char *file; { nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL; ipfobj_t obj; int nfd, i; nat_t *nat; char *s; int n; nfd = -1; in = NULL; ipnhead = NULL; ipntail = NULL; if (!file) file = IPF_NATFILE; nfd = open(file, O_RDONLY); if (nfd == -1) { fprintf(stderr, "%s ", file); perror("nat:open"); return 1; } bzero((char *)&ipn, sizeof(ipn)); /* * 1. Read all state information in. */ do { i = read(nfd, &ipn, sizeof(ipn)); if (i == -1) { perror("read"); close(nfd); return 1; } if (i == 0) break; if (i != sizeof(ipn)) { fprintf(stderr, "nat:incomplete read: %d != %d\n", i, (int)sizeof(ipn)); close(nfd); return 1; } in = (nat_save_t *)malloc(ipn.ipn_dsize); if (!in) break; if (ipn.ipn_dsize > sizeof(ipn)) { n = ipn.ipn_dsize - sizeof(ipn); if (n > 0) { s = in->ipn_data + sizeof(in->ipn_data); i = read(nfd, s, n); if (i == 0) break; if (i != n) { fprintf(stderr, "nat:incomplete read: %d != %d\n", i, n); close(nfd); return 1; } } } bcopy((char *)&ipn, (char *)in, sizeof(ipn)); /* * Check to see if this is the first NAT entry that will * reference a particular rule and if so, flag it as such * else just adjust the rule pointer to become a pointer to * the other. We do this so we have a means later for tracking * who is referencing us when we get back the real pointer * in is_rule after doing the ioctl. */ nat = &in->ipn_nat; if (nat->nat_fr != NULL) { for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next) if (in1->ipn_rule == nat->nat_fr) break; if (in1 == NULL) nat->nat_flags |= SI_NEWFR; else nat->nat_fr = &in1->ipn_fr; } /* * Use a tail-queue type list (add things to the end).. */ in->ipn_next = NULL; if (!ipnhead) ipnhead = in; if (ipntail) ipntail->ipn_next = in; ipntail = in; } while (1); close(nfd); nfd = -1; obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_NATSAVE; for (in = ipnhead; in; in = in->ipn_next) { if (opts & OPT_VERBOSE) printf("Loading new NAT table entry\n"); nat = &in->ipn_nat; if (nat->nat_flags & SI_NEWFR) { if (opts & OPT_VERBOSE) printf("Loading new filter rule\n"); } obj.ipfo_ptr = in; obj.ipfo_size = in->ipn_dsize; if (!(opts & OPT_DONOTHING)) if (ioctl(fd, SIOCSTPUT, &obj)) { fprintf(stderr, "in=%p:", in); perror("SIOCSTPUT"); return 1; } if (nat->nat_flags & SI_NEWFR) { if (opts & OPT_VERBOSE) printf("Real rule addr %p\n", nat->nat_fr); for (in1 = in->ipn_next; in1; in1 = in1->ipn_next) if (in1->ipn_rule == &in->ipn_fr) in1->ipn_rule = nat->nat_fr; } } return 0; } int writenat(fd, file) int fd; char *file; { nat_save_t *ipnp = NULL, *next = NULL; ipfobj_t obj; int nfd = -1; natget_t ng; if (!file) file = IPF_NATFILE; nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); if (nfd == -1) { fprintf(stderr, "%s ", file); perror("nat:open"); return 1; } obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_NATSAVE; do { if (opts & OPT_VERBOSE) printf("Getting nat from addr %p\n", ipnp); ng.ng_ptr = next; ng.ng_sz = 0; if (ioctl(fd, SIOCSTGSZ, &ng)) { perror("nat:SIOCSTGSZ"); close(nfd); if (ipnp != NULL) free(ipnp); return 1; } if (opts & OPT_VERBOSE) printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr); if (ng.ng_sz == 0) break; if (!ipnp) ipnp = malloc(ng.ng_sz); else ipnp = realloc((char *)ipnp, ng.ng_sz); if (!ipnp) { fprintf(stderr, "malloc for %d bytes failed\n", ng.ng_sz); break; } bzero((char *)ipnp, ng.ng_sz); obj.ipfo_size = ng.ng_sz; obj.ipfo_ptr = ipnp; ipnp->ipn_dsize = ng.ng_sz; ipnp->ipn_next = next; if (ioctl(fd, SIOCSTGET, &obj)) { if (errno == ENOENT) break; perror("nat:SIOCSTGET"); close(nfd); free(ipnp); return 1; } if (opts & OPT_VERBOSE) printf("Got nat next %p ipn_dsize %d ng_sz %d\n", ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz); if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) { perror("nat:write"); close(nfd); free(ipnp); return 1; } next = ipnp->ipn_next; } while (ipnp && next); if (ipnp != NULL) free(ipnp); close(nfd); return 0; } int writeall(dirname) char *dirname; { int fd, devfd; if (!dirname) dirname = IPF_SAVEDIR; if (chdir(dirname)) { fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname); perror("chdir(IPF_SAVEDIR)"); return 1; } fd = opendevice(NULL); if (fd == -1) return 1; if (setlock(fd, 1)) { close(fd); return 1; } devfd = opendevice(IPSTATE_NAME); if (devfd == -1) goto bad; if (writestate(devfd, NULL)) goto bad; close(devfd); devfd = opendevice(IPNAT_NAME); if (devfd == -1) goto bad; if (writenat(devfd, NULL)) goto bad; close(devfd); if (setlock(fd, 0)) { close(fd); return 1; } close(fd); return 0; bad: setlock(fd, 0); close(fd); return 1; } int readall(dirname) char *dirname; { int fd, devfd; if (!dirname) dirname = IPF_SAVEDIR; if (chdir(dirname)) { perror("chdir(IPF_SAVEDIR)"); return 1; } fd = opendevice(NULL); if (fd == -1) return 1; if (setlock(fd, 1)) { close(fd); return 1; } devfd = opendevice(IPSTATE_NAME); if (devfd == -1) return 1; if (readstate(devfd, NULL)) return 1; close(devfd); devfd = opendevice(IPNAT_NAME); if (devfd == -1) return 1; if (readnat(devfd, NULL)) return 1; close(devfd); if (setlock(fd, 0)) { close(fd); return 1; } return 0; } /* * Copyright (C) 1993-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #ifdef __FreeBSD__ # ifndef __FreeBSD_cc_version # include # else # if __FreeBSD_cc_version < 430000 # include # endif # endif #endif #include #include #ifdef linux # include #else # include #endif #include #if defined(sun) && (defined(__svr4__) || defined(__SVR4)) # include #endif #include "ipf.h" #include "netinet/ipl.h" #if defined(STATETOP) # if defined(_BSDI_VERSION) # undef STATETOP # endif # if defined(__FreeBSD__) && \ (!defined(__FreeBSD_version) || (__FreeBSD_version < 430000)) # undef STATETOP # endif # if defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105000000) # undef STATETOP # endif # if defined(sun) # if defined(__svr4__) || defined(__SVR4) # include # else # undef STATETOP /* NOT supported on SunOS4 */ # endif # endif #endif #if defined(STATETOP) && !defined(linux) # include # include #endif #ifdef STATETOP # include # include # if defined(SOLARIS) || defined(__NetBSD__) || defined(_BSDI_VERSION) || \ defined(__sgi) # ifdef ERR # undef ERR # endif # undef ISASCII # undef ISPRINT # include # else /* SOLARIS */ # include # endif /* SOLARIS */ #endif /* STATETOP */ #include "kmem.h" #if defined(__NetBSD__) || (__OpenBSD__) # include #endif #include "ipfzone.h" #if !defined(lint) static const char sccsid[] = "@(#)fils.c 1.21 4/20/96 (C) 1993-2000 Darren Reed"; static const char rcsid[] = "@(#)$Id: ipfstat.c,v 1.44.2.12 2005/06/12 07:18:46 darrenr Exp $"; #endif #ifdef __hpux # define nlist nlist64 #endif extern char *optarg; extern int optind; extern int opterr; #define PRINTF (void)printf #define FPRINTF (void)fprintf static char *filters[4] = { "ipfilter(in)", "ipfilter(out)", "ipacct(in)", "ipacct(out)" }; static int state_logging = -1; int opts = 0; int use_inet6 = 0; int live_kernel = 1; int state_fd = -1; int ipf_fd = -1; #ifdef STATETOP #define STSTRSIZE 80 #define STGROWSIZE 16 #define HOSTNMLEN 40 #define STSORT_PR 0 #define STSORT_PKTS 1 #define STSORT_BYTES 2 #define STSORT_TTL 3 #define STSORT_SRCIP 4 #define STSORT_SRCPT 5 #define STSORT_DSTIP 6 #define STSORT_DSTPT 7 #define STSORT_MAX STSORT_DSTPT #define STSORT_DEFAULT STSORT_BYTES typedef struct statetop { i6addr_t st_src; i6addr_t st_dst; u_short st_sport; u_short st_dport; u_char st_p; u_char st_v; u_char st_state[2]; U_QUAD_T st_pkts; U_QUAD_T st_bytes; u_long st_age; } statetop_t; #endif int main __P((int, char *[])); static void showstats __P((friostat_t *, u_32_t)); static void showfrstates __P((ipfrstat_t *, u_long)); static void showlist __P((friostat_t *)); static void showipstates __P((ips_stat_t *)); static void showauthstates __P((fr_authstat_t *)); static void showgroups __P((friostat_t *)); static void usage __P((char *)); static void printlivelist __P((int, int, frentry_t *, char *, char *)); static void printdeadlist __P((int, int, frentry_t *, char *, char *)); static void printlist __P((frentry_t *, char *)); static void parse_ipportstr __P((const char *, i6addr_t *, int *)); static void ipfstate_live __P((char *, friostat_t **, ips_stat_t **, ipfrstat_t **, fr_authstat_t **, u_32_t *)); static void ipfstate_dead __P((char *, friostat_t **, ips_stat_t **, ipfrstat_t **, fr_authstat_t **, u_32_t *)); #ifdef STATETOP static void topipstates __P((i6addr_t, i6addr_t, int, int, int, int, int, int)); static void sig_break __P((int)); static void sig_resize __P((int)); static char *getip __P((int, i6addr_t *)); static char *ttl_to_string __P((long)); static int sort_p __P((const void *, const void *)); static int sort_pkts __P((const void *, const void *)); static int sort_bytes __P((const void *, const void *)); static int sort_ttl __P((const void *, const void *)); static int sort_srcip __P((const void *, const void *)); static int sort_srcpt __P((const void *, const void *)); static int sort_dstip __P((const void *, const void *)); static int sort_dstpt __P((const void *, const void *)); #endif static void usage(name) char *name; { #ifdef USE_INET6 fprintf(stderr, "Usage: %s [-6aAdfghIilnoRsv]\n", name); #else fprintf(stderr, "Usage: %s [-aAdfghIilnoRsv]\n", name); #endif fprintf(stderr, " %s [-M corefile] [-N symbol-list]\n", name); #ifdef USE_INET6 fprintf(stderr, " %s -t [-6C] ", name); #else fprintf(stderr, " %s -t [-C] ", name); #endif fprintf(stderr, "[-G|-z zonename] "); fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n"); exit(1); } int main(argc,argv) int argc; char *argv[]; { fr_authstat_t frauthst; fr_authstat_t *frauthstp = &frauthst; friostat_t fio; friostat_t *fiop = &fio; ips_stat_t ipsst; ips_stat_t *ipsstp = &ipsst; ipfrstat_t ifrst; ipfrstat_t *ifrstp = &ifrst; char *device = IPL_NAME, *memf = NULL; char *options, *kern = NULL; int c, myoptind; int protocol = -1; /* -1 = wild card for any protocol */ int refreshtime = 1; /* default update time */ int sport = -1; /* -1 = wild card for any source port */ int dport = -1; /* -1 = wild card for any dest port */ int topclosed = 0; /* do not show closed tcp sessions */ i6addr_t saddr, daddr; u_32_t frf; #ifdef USE_INET6 options = "6aACdfgG:hIilnostvD:M:N:P:RS:T:z:"; #else options = "aACdfgG:hIilnostvD:M:N:P:RS:T:z:"; #endif saddr.in4.s_addr = INADDR_ANY; /* default any v4 source addr */ daddr.in4.s_addr = INADDR_ANY; /* default any v4 dest addr */ #ifdef USE_INET6 saddr.in6 = in6addr_any; /* default any v6 source addr */ daddr.in6 = in6addr_any; /* default any v6 dest addr */ #endif /* Don't warn about invalid flags when we run getopt for the 1st time */ opterr = 0; /* * Parse these four arguments now lest there be any buffer overflows * in the parsing of the rest. */ myoptind = optind; while ((c = getopt(argc, argv, options)) != -1) { switch (c) { case 'G' : setzonename_global(optarg); break; case 'M' : memf = optarg; live_kernel = 0; break; case 'N' : kern = optarg; live_kernel = 0; break; case 'z' : setzonename(optarg); break; } } optind = myoptind; if (live_kernel == 1) { if ((state_fd = open(IPSTATE_NAME, O_RDONLY)) == -1) { perror("open(IPSTATE_NAME)"); exit(-1); } if (setzone(state_fd) != 0) { close(state_fd); exit(-1); } if ((ipf_fd = open(device, O_RDONLY)) == -1) { fprintf(stderr, "open(%s)", device); perror(""); exit(-1); } if (setzone(ipf_fd) != 0) { close(ipf_fd); exit(-1); } } if (kern != NULL || memf != NULL) { (void)setgid(getgid()); (void)setreuid(getuid(), getuid()); if (openkmem(kern, memf) == -1) exit(-1); } if (live_kernel == 1) (void) checkrev(device); (void)setgid(getgid()); (void)setreuid(getuid(), getuid()); opterr = 1; while ((c = getopt(argc, argv, options)) != -1) { switch (c) { #ifdef USE_INET6 case '6' : use_inet6 = 1; break; #endif case 'a' : opts |= OPT_ACCNT|OPT_SHOWLIST; break; case 'A' : opts |= OPT_AUTHSTATS; break; case 'C' : topclosed = 1; break; case 'd' : opts |= OPT_DEBUG; break; case 'D' : parse_ipportstr(optarg, &daddr, &dport); break; case 'f' : opts |= OPT_FRSTATES; break; case 'g' : opts |= OPT_GROUPS; break; case 'G' : /* Already handled by getzoneopt() above */ break; case 'h' : opts |= OPT_HITS; break; case 'i' : opts |= OPT_INQUE|OPT_SHOWLIST; break; case 'I' : opts |= OPT_INACTIVE; break; case 'l' : opts |= OPT_SHOWLIST; break; case 'M' : break; case 'N' : break; case 'n' : opts |= OPT_SHOWLINENO; break; case 'o' : opts |= OPT_OUTQUE|OPT_SHOWLIST; break; case 'P' : protocol = getproto(optarg); if (protocol == -1) { fprintf(stderr, "%s: Invalid protocol: %s\n", argv[0], optarg); exit(-2); } break; case 'R' : opts |= OPT_NORESOLVE; break; case 's' : opts |= OPT_IPSTATES; break; case 'S' : parse_ipportstr(optarg, &saddr, &sport); break; case 't' : #ifdef STATETOP opts |= OPT_STATETOP; break; #else fprintf(stderr, "%s: state top facility not compiled in\n", argv[0]); exit(-2); #endif case 'T' : if (!sscanf(optarg, "%d", &refreshtime) || (refreshtime <= 0)) { fprintf(stderr, "%s: Invalid refreshtime < 1 : %s\n", argv[0], optarg); exit(-2); } break; case 'v' : opts |= OPT_VERBOSE; opts |= OPT_UNDEF; break; case 'z' : /* Already handled by getzoneopt() above */ break; default : usage(argv[0]); break; } } if (live_kernel == 1) { bzero((char *)&fio, sizeof(fio)); bzero((char *)&ipsst, sizeof(ipsst)); bzero((char *)&ifrst, sizeof(ifrst)); ipfstate_live(device, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf); } else ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf); if (opts & OPT_IPSTATES) { showipstates(ipsstp); } else if (opts & OPT_SHOWLIST) { showlist(fiop); if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){ opts &= ~OPT_OUTQUE; showlist(fiop); } } else if (opts & OPT_FRSTATES) showfrstates(ifrstp, fiop->f_ticks); #ifdef STATETOP else if (opts & OPT_STATETOP) topipstates(saddr, daddr, sport, dport, protocol, use_inet6 ? 6 : 4, refreshtime, topclosed); #endif else if (opts & OPT_AUTHSTATS) showauthstates(frauthstp); else if (opts & OPT_GROUPS) showgroups(fiop); else showstats(fiop, frf); return 0; } /* * Fill in the stats structures from the live kernel, using a combination * of ioctl's and copying directly from kernel memory. */ static void ipfstate_live(device, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp) char *device; friostat_t **fiopp; ips_stat_t **ipsstpp; ipfrstat_t **ifrstpp; fr_authstat_t **frauthstpp; u_32_t *frfp; { ipfobj_t ipfo; if (checkrev(device) == -1) { fprintf(stderr, "User/kernel version check failed\n"); exit(1); } if ((opts & OPT_AUTHSTATS) == 0) { bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_size = sizeof(friostat_t); ipfo.ipfo_ptr = (void *)*fiopp; ipfo.ipfo_type = IPFOBJ_IPFSTAT; if (ioctl(ipf_fd, SIOCGETFS, &ipfo) == -1) { perror("ioctl(ipf:SIOCGETFS)"); exit(-1); } if (ioctl(ipf_fd, SIOCGETFF, frfp) == -1) perror("ioctl(SIOCGETFF)"); } if ((opts & OPT_IPSTATES) != 0) { bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_size = sizeof(ips_stat_t); ipfo.ipfo_ptr = (void *)*ipsstpp; ipfo.ipfo_type = IPFOBJ_STATESTAT; if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { perror("ioctl(state:SIOCGETFS)"); exit(-1); } if (ioctl(state_fd, SIOCGETLG, &state_logging) == -1) { perror("ioctl(state:SIOCGETLG)"); exit(-1); } } if ((opts & OPT_FRSTATES) != 0) { bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_size = sizeof(ipfrstat_t); ipfo.ipfo_ptr = (void *)*ifrstpp; ipfo.ipfo_type = IPFOBJ_FRAGSTAT; if (ioctl(ipf_fd, SIOCGFRST, &ipfo) == -1) { perror("ioctl(SIOCGFRST)"); exit(-1); } } if (opts & OPT_VERBOSE) PRINTF("opts %#x name %s\n", opts, device); if ((opts & OPT_AUTHSTATS) != 0) { if (ipf_fd >= 0) { close(ipf_fd); ipf_fd = -1; } device = IPAUTH_NAME; if ((ipf_fd = open(device, O_RDONLY)) == -1) { perror("open"); exit(-1); } if (setzone(ipf_fd) != 0) { close(ipf_fd); exit(-1); } bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_size = sizeof(fr_authstat_t); ipfo.ipfo_ptr = (void *)*frauthstpp; ipfo.ipfo_type = IPFOBJ_AUTHSTAT; if (ioctl(ipf_fd, SIOCATHST, &ipfo) == -1) { perror("ioctl(SIOCATHST)"); exit(-1); } } } /* * Build up the stats structures from data held in the "core" memory. * This is mainly useful when looking at data in crash dumps and ioctl's * just won't work any more. */ static void ipfstate_dead(kernel, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp) char *kernel; friostat_t **fiopp; ips_stat_t **ipsstpp; ipfrstat_t **ifrstpp; fr_authstat_t **frauthstpp; u_32_t *frfp; { static fr_authstat_t frauthst, *frauthstp; static ips_stat_t ipsst, *ipsstp; static ipfrstat_t ifrst, *ifrstp; static friostat_t fio, *fiop; int temp; void *rules[2][2]; struct nlist deadlist[43] = { { "fr_authstats" }, /* 0 */ { "fae_list" }, { "ipauth" }, { "fr_authlist" }, { "fr_authstart" }, { "fr_authend" }, /* 5 */ { "fr_authnext" }, { "fr_auth" }, { "fr_authused" }, { "fr_authsize" }, { "fr_defaultauthage" }, /* 10 */ { "fr_authpkts" }, { "fr_auth_lock" }, { "frstats" }, { "ips_stats" }, { "ips_num" }, /* 15 */ { "ips_wild" }, { "ips_list" }, { "ips_table" }, { "fr_statemax" }, { "fr_statesize" }, /* 20 */ { "fr_state_doflush" }, { "fr_state_lock" }, { "ipfr_heads" }, { "ipfr_nattab" }, { "ipfr_stats" }, /* 25 */ { "ipfr_inuse" }, { "fr_ipfrttl" }, { "fr_frag_lock" }, { "ipfr_timer_id" }, { "fr_nat_lock" }, /* 30 */ { "ipfilter" }, { "ipfilter6" }, { "ipacct" }, { "ipacct6" }, { "ipl_frouteok" }, /* 35 */ { "fr_running" }, { "ipfgroups" }, { "fr_active" }, { "fr_pass" }, { "fr_flags" }, /* 40 */ { "ipstate_logging" }, { NULL } }; frauthstp = &frauthst; ipsstp = &ipsst; ifrstp = &ifrst; fiop = &fio; *frfp = 0; *fiopp = fiop; *ipsstpp = ipsstp; *ifrstpp = ifrstp; *frauthstpp = frauthstp; bzero((char *)fiop, sizeof(*fiop)); bzero((char *)ipsstp, sizeof(*ipsstp)); bzero((char *)ifrstp, sizeof(*ifrstp)); bzero((char *)frauthstp, sizeof(*frauthstp)); if (nlist(kernel, deadlist) == -1) { fprintf(stderr, "nlist error\n"); return; } /* * This is for SIOCGETFF. */ kmemcpy((char *)frfp, (u_long)deadlist[40].n_value, sizeof(*frfp)); /* * f_locks is a combination of the lock variable from each part of * ipfilter (state, auth, nat, fragments). */ kmemcpy((char *)fiop, (u_long)deadlist[13].n_value, sizeof(*fiop)); kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[22].n_value, sizeof(fiop->f_locks[0])); kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[30].n_value, sizeof(fiop->f_locks[1])); kmemcpy((char *)&fiop->f_locks[2], (u_long)deadlist[28].n_value, sizeof(fiop->f_locks[2])); kmemcpy((char *)&fiop->f_locks[3], (u_long)deadlist[12].n_value, sizeof(fiop->f_locks[3])); /* * Get pointers to each list of rules (active, inactive, in, out) */ kmemcpy((char *)&rules, (u_long)deadlist[31].n_value, sizeof(rules)); fiop->f_fin[0] = rules[0][0]; fiop->f_fin[1] = rules[0][1]; fiop->f_fout[0] = rules[1][0]; fiop->f_fout[1] = rules[1][1]; /* * Same for IPv6, except make them null if support for it is not * being compiled in. */ #ifdef USE_INET6 kmemcpy((char *)&rules, (u_long)deadlist[32].n_value, sizeof(rules)); fiop->f_fin6[0] = rules[0][0]; fiop->f_fin6[1] = rules[0][1]; fiop->f_fout6[0] = rules[1][0]; fiop->f_fout6[1] = rules[1][1]; #else fiop->f_fin6[0] = NULL; fiop->f_fin6[1] = NULL; fiop->f_fout6[0] = NULL; fiop->f_fout6[1] = NULL; #endif /* * Now get accounting rules pointers. */ kmemcpy((char *)&rules, (u_long)deadlist[33].n_value, sizeof(rules)); fiop->f_acctin[0] = rules[0][0]; fiop->f_acctin[1] = rules[0][1]; fiop->f_acctout[0] = rules[1][0]; fiop->f_acctout[1] = rules[1][1]; #ifdef USE_INET6 kmemcpy((char *)&rules, (u_long)deadlist[34].n_value, sizeof(rules)); fiop->f_acctin6[0] = rules[0][0]; fiop->f_acctin6[1] = rules[0][1]; fiop->f_acctout6[0] = rules[1][0]; fiop->f_acctout6[1] = rules[1][1]; #else fiop->f_acctin6[0] = NULL; fiop->f_acctin6[1] = NULL; fiop->f_acctout6[0] = NULL; fiop->f_acctout6[1] = NULL; #endif /* * A collection of "global" variables used inside the kernel which * are all collected in friostat_t via ioctl. */ kmemcpy((char *)&fiop->f_froute, (u_long)deadlist[35].n_value, sizeof(fiop->f_froute)); kmemcpy((char *)&fiop->f_running, (u_long)deadlist[36].n_value, sizeof(fiop->f_running)); kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[37].n_value, sizeof(fiop->f_groups)); kmemcpy((char *)&fiop->f_active, (u_long)deadlist[38].n_value, sizeof(fiop->f_active)); kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[39].n_value, sizeof(fiop->f_defpass)); /* * Build up the state information stats structure. */ kmemcpy((char *)ipsstp, (u_long)deadlist[14].n_value, sizeof(*ipsstp)); kmemcpy((char *)&temp, (u_long)deadlist[15].n_value, sizeof(temp)); ipsstp->iss_active = temp; ipsstp->iss_table = (void *)deadlist[18].n_value; ipsstp->iss_list = (void *)deadlist[17].n_value; /* * Build up the authentiation information stats structure. */ kmemcpy((char *)frauthstp, (u_long)deadlist[0].n_value, sizeof(*frauthstp)); frauthstp->fas_faelist = (void *)deadlist[1].n_value; /* * Build up the fragment information stats structure. */ kmemcpy((char *)ifrstp, (u_long)deadlist[25].n_value, sizeof(*ifrstp)); ifrstp->ifs_table = (void *)deadlist[23].n_value; ifrstp->ifs_nattab = (void *)deadlist[24].n_value; kmemcpy((char *)&ifrstp->ifs_inuse, (u_long)deadlist[26].n_value, sizeof(ifrstp->ifs_inuse)); /* * Get logging on/off switches */ kmemcpy((char *)&state_logging, (u_long)deadlist[41].n_value, sizeof(state_logging)); } /* * Display the kernel stats for packets blocked and passed and other * associated running totals which are kept. */ static void showstats(fp, frf) struct friostat *fp; u_32_t frf; { PRINTF("bad packets:\t\tin %lu\tout %lu\n", fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); #ifdef USE_INET6 PRINTF(" IPv6 packets:\t\tin %lu out %lu\n", fp->f_st[0].fr_ipv6, fp->f_st[1].fr_ipv6); #endif PRINTF(" input packets:\t\tblocked %lu passed %lu nomatch %lu", fp->f_st[0].fr_block, fp->f_st[0].fr_pass, fp->f_st[0].fr_nom); PRINTF(" counted %lu short %lu\n", fp->f_st[0].fr_acct, fp->f_st[0].fr_short); PRINTF("output packets:\t\tblocked %lu passed %lu nomatch %lu", fp->f_st[1].fr_block, fp->f_st[1].fr_pass, fp->f_st[1].fr_nom); PRINTF(" counted %lu short %lu\n", fp->f_st[1].fr_acct, fp->f_st[1].fr_short); PRINTF(" input packets logged:\tblocked %lu passed %lu\n", fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl); PRINTF("output packets logged:\tblocked %lu passed %lu\n", fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl); PRINTF(" packets logged:\tinput %lu output %lu\n", fp->f_st[0].fr_pkl, fp->f_st[1].fr_pkl); PRINTF(" log failures:\t\tinput %lu output %lu\n", fp->f_st[0].fr_skip, fp->f_st[1].fr_skip); PRINTF("fragment state(in):\tkept %lu\tlost %lu\tnot fragmented %lu\n", fp->f_st[0].fr_nfr, fp->f_st[0].fr_bnfr, fp->f_st[0].fr_cfr); PRINTF("fragment state(out):\tkept %lu\tlost %lu\tnot fragmented %lu\n", fp->f_st[1].fr_nfr, fp->f_st[1].fr_bnfr, fp->f_st[0].fr_cfr); PRINTF("packet state(in):\tkept %lu\tlost %lu\n", fp->f_st[0].fr_ads, fp->f_st[0].fr_bads); PRINTF("packet state(out):\tkept %lu\tlost %lu\n", fp->f_st[1].fr_ads, fp->f_st[1].fr_bads); PRINTF("ICMP replies:\t%lu\tTCP RSTs sent:\t%lu\n", fp->f_st[0].fr_ret, fp->f_st[1].fr_ret); PRINTF("Invalid source(in):\t%lu\n", fp->f_st[0].fr_badsrc); PRINTF("Result cache hits(in):\t%lu\t(out):\t%lu\n", fp->f_st[0].fr_chit, fp->f_st[1].fr_chit); PRINTF("IN Pullups succeeded:\t%lu\tfailed:\t%lu\n", fp->f_st[0].fr_pull[0], fp->f_st[0].fr_pull[1]); PRINTF("OUT Pullups succeeded:\t%lu\tfailed:\t%lu\n", fp->f_st[1].fr_pull[0], fp->f_st[1].fr_pull[1]); PRINTF("Fastroute successes:\t%lu\tfailures:\t%lu\n", fp->f_froute[0], fp->f_froute[1]); PRINTF("TCP cksum fails(in):\t%lu\t(out):\t%lu\n", fp->f_st[0].fr_tcpbad, fp->f_st[1].fr_tcpbad); PRINTF("IPF Ticks:\t%lu\n", fp->f_ticks); PRINTF("Packet log flags set: (%#x)\n", frf); if (frf & FF_LOGPASS) PRINTF("\tpackets passed through filter\n"); if (frf & FF_LOGBLOCK) PRINTF("\tpackets blocked by filter\n"); if (frf & FF_LOGNOMATCH) PRINTF("\tpackets not matched by filter\n"); if (!frf) PRINTF("\tnone\n"); } /* * Print out a list of rules from the kernel, starting at the one passed. */ static void printlivelist(out, set, fp, group, comment) int out, set; frentry_t *fp; char *group, *comment; { frgroup_t *grtop, *grtail, *g; struct frentry fb, *fg; int n; ipfruleiter_t rule; ipfobj_t obj; u_long array[1000]; fb.fr_next = fp; n = 0; grtop = NULL; grtail = NULL; rule.iri_ver = use_inet6? AF_INET6 : AF_INET; rule.iri_inout = out; rule.iri_active = set; rule.iri_nrules = 1; rule.iri_rule = &fb; if (group != NULL) strncpy(rule.iri_group, group, FR_GROUPLEN); else rule.iri_group[0] = '\0'; bzero((char *)&obj, sizeof(obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_IPFITER; obj.ipfo_size = sizeof(rule); obj.ipfo_ptr = &rule; do { memset(array, 0xff, sizeof(array)); fp = (frentry_t *)array; rule.iri_rule = fp; if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) { perror("ioctl(SIOCIPFITER)"); return; } if (fp->fr_data != NULL) fp->fr_data = (char *)fp + sizeof(*fp); n++; if (opts & (OPT_HITS|OPT_VERBOSE)) #ifdef USE_QUAD_T PRINTF("%qu ", (unsigned long long) fp->fr_hits); #else PRINTF("%lu ", fp->fr_hits); #endif if (opts & (OPT_ACCNT|OPT_VERBOSE)) #ifdef USE_QUAD_T PRINTF("%qu ", (unsigned long long) fp->fr_bytes); #else PRINTF("%lu ", fp->fr_bytes); #endif if (opts & OPT_SHOWLINENO) PRINTF("@%d ", n); printfr(fp, ioctl); if (opts & OPT_DEBUG) { binprint(fp, sizeof(*fp)); if (fp->fr_data != NULL && fp->fr_dsize > 0) binprint(fp->fr_data, fp->fr_dsize); } if (fp->fr_grhead[0] != '\0') { g = calloc(1, sizeof(*g)); if (g != NULL) { strncpy(g->fg_name, fp->fr_grhead, FR_GROUPLEN); if (grtop == NULL) { grtop = g; grtail = g; } else { grtail->fg_next = g; grtail = g; } } } } while (fp->fr_next != NULL); while ((g = grtop) != NULL) { printlivelist(out, set, NULL, g->fg_name, comment); grtop = g->fg_next; free(g); } } static void printdeadlist(out, set, fp, group, comment) int out, set; frentry_t *fp; char *group, *comment; { frgroup_t *grtop, *grtail, *g; struct frentry fb, *fg; char *data; u_32_t type; int n; fb.fr_next = fp; n = 0; grtop = NULL; grtail = NULL; do { fp = fb.fr_next; if (kmemcpy((char *)&fb, (u_long)fb.fr_next, sizeof(fb)) == -1) { perror("kmemcpy"); return; } data = NULL; type = fb.fr_type & ~FR_T_BUILTIN; if (type == FR_T_IPF || type == FR_T_BPFOPC) { if (fb.fr_dsize) { data = malloc(fb.fr_dsize); if (kmemcpy(data, (u_long)fb.fr_data, fb.fr_dsize) == -1) { perror("kmemcpy"); return; } fb.fr_data = data; } } n++; if (opts & (OPT_HITS|OPT_VERBOSE)) #ifdef USE_QUAD_T PRINTF("%qu ", (unsigned long long) fb.fr_hits); #else PRINTF("%lu ", fb.fr_hits); #endif if (opts & (OPT_ACCNT|OPT_VERBOSE)) #ifdef USE_QUAD_T PRINTF("%qu ", (unsigned long long) fb.fr_bytes); #else PRINTF("%lu ", fb.fr_bytes); #endif if (opts & OPT_SHOWLINENO) PRINTF("@%d ", n); printfr(fp, ioctl); if (opts & OPT_DEBUG) { binprint(fp, sizeof(*fp)); if (fb.fr_data != NULL && fb.fr_dsize > 0) binprint(fb.fr_data, fb.fr_dsize); } if (data != NULL) free(data); if (fb.fr_grhead[0] != '\0') { g = calloc(1, sizeof(*g)); if (g != NULL) { strncpy(g->fg_name, fb.fr_grhead, FR_GROUPLEN); if (grtop == NULL) { grtop = g; grtail = g; } else { grtail->fg_next = g; grtail = g; } } } if (type == FR_T_CALLFUNC) { printdeadlist(out, set, fb.fr_data, group, "# callfunc: "); } } while (fb.fr_next != NULL); while ((g = grtop) != NULL) { printdeadlist(out, set, NULL, g->fg_name, comment); grtop = g->fg_next; free(g); } } /* * print out all of the asked for rule sets, using the stats struct as * the base from which to get the pointers. */ static void showlist(fiop) struct friostat *fiop; { struct frentry *fp = NULL; int i, set; set = fiop->f_active; if (opts & OPT_INACTIVE) set = 1 - set; if (opts & OPT_ACCNT) { #ifdef USE_INET6 if ((use_inet6) && (opts & OPT_OUTQUE)) { i = F_ACOUT; fp = (struct frentry *)fiop->f_acctout6[set]; } else if ((use_inet6) && (opts & OPT_INQUE)) { i = F_ACIN; fp = (struct frentry *)fiop->f_acctin6[set]; } else #endif if (opts & OPT_OUTQUE) { i = F_ACOUT; fp = (struct frentry *)fiop->f_acctout[set]; } else if (opts & OPT_INQUE) { i = F_ACIN; fp = (struct frentry *)fiop->f_acctin[set]; } else { FPRINTF(stderr, "No -i or -o given with -a\n"); return; } } else { #ifdef USE_INET6 if ((use_inet6) && (opts & OPT_OUTQUE)) { i = F_OUT; fp = (struct frentry *)fiop->f_fout6[set]; } else if ((use_inet6) && (opts & OPT_INQUE)) { i = F_IN; fp = (struct frentry *)fiop->f_fin6[set]; } else #endif if (opts & OPT_OUTQUE) { i = F_OUT; fp = (struct frentry *)fiop->f_fout[set]; } else if (opts & OPT_INQUE) { i = F_IN; fp = (struct frentry *)fiop->f_fin[set]; } else return; } if (opts & OPT_VERBOSE) FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i); if (opts & OPT_VERBOSE) PRINTF("fp %p set %d\n", fp, set); if (!fp) { FPRINTF(stderr, "empty list for %s%s\n", (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]); return; } if (live_kernel == 1) printlivelist(i, set, fp, NULL, NULL); else printdeadlist(i, set, fp, NULL, NULL); } /* * Display ipfilter stateful filtering information */ static void showipstates(ipsp) ips_stat_t *ipsp; { u_long minlen, maxlen, totallen, *buckets; int i, sz; sz = sizeof(*buckets) * ipsp->iss_statesize; buckets = (u_long *)malloc(sz); if (buckets == NULL) { perror("malloc"); exit(1); } if (kmemcpy((char *)buckets, (u_long)ipsp->iss_bucketlen, sz)) { free(buckets); return; } /* * If a list of states hasn't been asked for, only print out stats */ if (!(opts & OPT_SHOWLIST)) { PRINTF("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n", ipsp->iss_tcp, ipsp->iss_udp, ipsp->iss_icmp); PRINTF("\t%lu hits\n\t%lu misses\n", ipsp->iss_hits, ipsp->iss_miss); PRINTF("\t%lu maximum\n\t%lu no memory\n", ipsp->iss_max, ipsp->iss_nomem); PRINTF("\t%lu active\n\t%lu expired\n", ipsp->iss_active, ipsp->iss_expire); PRINTF("\t%lu closed\n\t%u orphans\n", ipsp->iss_fin, ipsp->iss_orphans); PRINTF("State logging %sabled\n", state_logging ? "en" : "dis"); PRINTF("\nState table bucket statistics:\n"); PRINTF("\t%lu in use\n\t%lu max bucket\n", ipsp->iss_inuse, ipsp->iss_bucketfull); minlen = ipsp->iss_max; totallen = 0; maxlen = 0; for (i = 0; i < ipsp->iss_statesize; i++) { if (buckets[i] > maxlen) maxlen = buckets[i]; if (buckets[i] < minlen) minlen = buckets[i]; totallen += buckets[i]; } PRINTF("\t%2.2f%% bucket usage\n\t%lu minimal length\n", ((float)ipsp->iss_inuse / ipsp->iss_statesize) * 100.0, minlen); PRINTF("\t%lu maximal length\n\t%.3f average length\n", maxlen, ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse : 0.0); #define ENTRIES_PER_LINE 5 if (opts & OPT_VERBOSE) { PRINTF("\nCurrent bucket sizes :\n"); for (i = 0; i < ipsp->iss_statesize; i++) { if ((i % ENTRIES_PER_LINE) == 0) PRINTF("\t"); PRINTF("%4d -> %4lu", i, buckets[i]); if ((i % ENTRIES_PER_LINE) == (ENTRIES_PER_LINE - 1)) PRINTF("\n"); else PRINTF(" "); } PRINTF("\n"); } PRINTF("\n"); free(buckets); return; } /* * Print out all the state information currently held in the kernel. */ while (ipsp->iss_list != NULL) { ipsp->iss_list = printstate(ipsp->iss_list, opts, ipsp->iss_ticks); } free(buckets); } #ifdef STATETOP static int handle_resize = 0, handle_break = 0; static void topipstates(saddr, daddr, sport, dport, protocol, ver, refreshtime, topclosed) i6addr_t saddr; i6addr_t daddr; int sport; int dport; int protocol; int ver; int refreshtime; int topclosed; { char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE]; int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT; int i, j, winy, tsentry, maxx, maxy, redraw = 0, ret = 0; int len, srclen, dstlen, forward = 1, c = 0; ips_stat_t ipsst, *ipsstp = &ipsst; statetop_t *tstable = NULL, *tp; const char *errstr = ""; ipstate_t ips; ipfobj_t ipfo; struct timeval selecttimeout; char hostnm[HOSTNMLEN]; struct protoent *proto; fd_set readfd; time_t t; /* install signal handlers */ signal(SIGINT, sig_break); signal(SIGQUIT, sig_break); signal(SIGTERM, sig_break); signal(SIGWINCH, sig_resize); /* init ncurses stuff */ initscr(); cbreak(); noecho(); curs_set(0); timeout(0); getmaxyx(stdscr, maxy, maxx); /* init hostname */ gethostname(hostnm, sizeof(hostnm) - 1); hostnm[sizeof(hostnm) - 1] = '\0'; /* init ipfobj_t stuff */ bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_size = sizeof(*ipsstp); ipfo.ipfo_ptr = (void *)ipsstp; ipfo.ipfo_type = IPFOBJ_STATESTAT; /* repeat until user aborts */ while ( 1 ) { /* get state table */ bzero((char *)&ipsst, sizeof(ipsst)); if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { errstr = "ioctl(SIOCGETFS)"; ret = -1; goto out; } /* clear the history */ tsentry = -1; /* reset max str len */ srclen = dstlen = 0; /* read the state table and store in tstable */ for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) { if (kmemcpy((char *)&ips, (u_long)ipsstp->iss_list, sizeof(ips))) break; if (ips.is_v != ver) continue; /* check v4 src/dest addresses */ if (ips.is_v == 4) { if ((saddr.in4.s_addr != INADDR_ANY && saddr.in4.s_addr != ips.is_saddr) || (daddr.in4.s_addr != INADDR_ANY && daddr.in4.s_addr != ips.is_daddr)) continue; } #ifdef USE_INET6 /* check v6 src/dest addresses */ if (ips.is_v == 6) { if ((IP6_NEQ(&saddr, &in6addr_any) && IP6_NEQ(&saddr, &ips.is_src)) || (IP6_NEQ(&daddr, &in6addr_any) && IP6_NEQ(&daddr, &ips.is_dst))) continue; } #endif /* check protocol */ if (protocol > 0 && protocol != ips.is_p) continue; /* check ports if protocol is TCP or UDP */ if (((ips.is_p == IPPROTO_TCP) || (ips.is_p == IPPROTO_UDP)) && (((sport > 0) && (htons(sport) != ips.is_sport)) || ((dport > 0) && (htons(dport) != ips.is_dport)))) continue; /* show closed TCP sessions ? */ if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) && (ips.is_state[0] >= IPF_TCPS_LAST_ACK) && (ips.is_state[1] >= IPF_TCPS_LAST_ACK)) continue; /* * if necessary make room for this state * entry */ tsentry++; if (!maxtsentries || tsentry == maxtsentries) { maxtsentries += STGROWSIZE; tstable = realloc(tstable, maxtsentries * sizeof(statetop_t)); if (tstable == NULL) { perror("realloc"); exit(-1); } } /* get max src/dest address string length */ len = strlen(getip(ips.is_v, &ips.is_src)); if (srclen < len) srclen = len; len = strlen(getip(ips.is_v, &ips.is_dst)); if (dstlen < len) dstlen = len; /* fill structure */ tp = tstable + tsentry; tp->st_src = ips.is_src; tp->st_dst = ips.is_dst; tp->st_p = ips.is_p; tp->st_v = ips.is_v; tp->st_state[0] = ips.is_state[0]; tp->st_state[1] = ips.is_state[1]; if (forward) { tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1]; tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1]; } else { tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3]; tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3]; } tp->st_age = ips.is_die - ipsstp->iss_ticks; if ((ips.is_p == IPPROTO_TCP) || (ips.is_p == IPPROTO_UDP)) { tp->st_sport = ips.is_sport; tp->st_dport = ips.is_dport; } } /* sort the array */ if (tsentry != -1) { switch (sorting) { case STSORT_PR: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_p); break; case STSORT_PKTS: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_pkts); break; case STSORT_BYTES: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_bytes); break; case STSORT_TTL: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_ttl); break; case STSORT_SRCIP: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_srcip); break; case STSORT_SRCPT: qsort(tstable, tsentry +1, sizeof(statetop_t), sort_srcpt); break; case STSORT_DSTIP: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_dstip); break; case STSORT_DSTPT: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_dstpt); break; default: break; } } /* handle window resizes */ if (handle_resize) { endwin(); initscr(); cbreak(); noecho(); curs_set(0); timeout(0); getmaxyx(stdscr, maxy, maxx); redraw = 1; handle_resize = 0; } /* stop program? */ if (handle_break) break; /* print title */ erase(); attron(A_BOLD); winy = 0; move(winy,0); sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION); for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++) printw(" "); printw("%s", str1); attroff(A_BOLD); /* just for fun add a clock */ move(winy, maxx - 8); t = time(NULL); strftime(str1, 80, "%T", localtime(&t)); printw("%s\n", str1); /* * print the display filters, this is placed in the loop, * because someday I might add code for changing these * while the programming is running :-) */ if (sport >= 0) sprintf(str1, "%s,%d", getip(ver, &saddr), sport); else sprintf(str1, "%s", getip(ver, &saddr)); if (dport >= 0) sprintf(str2, "%s,%d", getip(ver, &daddr), dport); else sprintf(str2, "%s", getip(ver, &daddr)); if (protocol < 0) strcpy(str3, "any"); else if ((proto = getprotobynumber(protocol)) != NULL) sprintf(str3, "%s", proto->p_name); else sprintf(str3, "%d", protocol); switch (sorting) { case STSORT_PR: sprintf(str4, "proto"); break; case STSORT_PKTS: sprintf(str4, "# pkts"); break; case STSORT_BYTES: sprintf(str4, "# bytes"); break; case STSORT_TTL: sprintf(str4, "ttl"); break; case STSORT_SRCIP: sprintf(str4, "src ip"); break; case STSORT_SRCPT: sprintf(str4, "src port"); break; case STSORT_DSTIP: sprintf(str4, "dest ip"); break; case STSORT_DSTPT: sprintf(str4, "dest port"); break; default: sprintf(str4, "unknown"); break; } if (reverse) strcat(str4, " (reverse)"); winy += 2; move(winy,0); printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n", str1, str2, str3, str4); /* * For an IPv4 IP address we need at most 15 characters, * 4 tuples of 3 digits, separated by 3 dots. Enforce this * length, so the colums do not change positions based * on the size of the IP address. This length makes the * output fit in a 80 column terminal. * We are lacking a good solution for IPv6 addresses (that * can be longer that 15 characters), so we do not enforce * a maximum on the IP field size. */ if (srclen < 15) srclen = 15; if (dstlen < 15) dstlen = 15; /* print column description */ winy += 2; move(winy,0); attron(A_BOLD); printw("%-*s %-*s %3s %4s %7s %9s %9s\n", srclen + 6, "Source IP", dstlen + 6, "Destination IP", "ST", "PR", "#pkts", "#bytes", "ttl"); attroff(A_BOLD); /* print all the entries */ tp = tstable; if (reverse) tp += tsentry; if (tsentry > maxy - 6) tsentry = maxy - 6; for (i = 0; i <= tsentry; i++) { /* print src/dest and port */ if ((tp->st_p == IPPROTO_TCP) || (tp->st_p == IPPROTO_UDP)) { sprintf(str1, "%s,%hu", getip(tp->st_v, &tp->st_src), ntohs(tp->st_sport)); sprintf(str2, "%s,%hu", getip(tp->st_v, &tp->st_dst), ntohs(tp->st_dport)); } else { sprintf(str1, "%s", getip(tp->st_v, &tp->st_src)); sprintf(str2, "%s", getip(tp->st_v, &tp->st_dst)); } winy++; move(winy, 0); printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2); /* print state */ sprintf(str1, "%X/%X", tp->st_state[0], tp->st_state[1]); printw(" %3s", str1); /* print protocol */ proto = getprotobynumber(tp->st_p); if (proto) { strncpy(str1, proto->p_name, 4); str1[4] = '\0'; } else { sprintf(str1, "%d", tp->st_p); } /* just print icmp for IPv6-ICMP */ if (tp->st_p == IPPROTO_ICMPV6) strcpy(str1, "icmp"); printw(" %4s", str1); /* print #pkt/#bytes */ #ifdef USE_QUAD_T printw(" %7qu %9qu", (unsigned long long) tp->st_pkts, (unsigned long long) tp->st_bytes); #else printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes); #endif printw(" %9s", ttl_to_string(tp->st_age)); if (reverse) tp--; else tp++; } /* screen data structure is filled, now update the screen */ if (redraw) clearok(stdscr,1); if (refresh() == ERR) break; if (redraw) { clearok(stdscr,0); redraw = 0; } /* wait for key press or a 1 second time out period */ selecttimeout.tv_sec = refreshtime; selecttimeout.tv_usec = 0; FD_ZERO(&readfd); FD_SET(0, &readfd); select(1, &readfd, NULL, NULL, &selecttimeout); /* if key pressed, read all waiting keys */ if (FD_ISSET(0, &readfd)) { c = wgetch(stdscr); if (c == ERR) continue; if (ISALPHA(c) && ISUPPER(c)) c = TOLOWER(c); if (c == 'l') { redraw = 1; } else if (c == 'q') { break; } else if (c == 'r') { reverse = !reverse; } else if (c == 'b') { forward = 0; } else if (c == 'f') { forward = 1; } else if (c == 's') { if (++sorting > STSORT_MAX) sorting = 0; } } } /* while */ out: printw("\n"); refresh(); endwin(); free(tstable); if (ret != 0) perror(errstr); } #endif /* * Show fragment cache information that's held in the kernel. */ static void showfrstates(ifsp, ticks) ipfrstat_t *ifsp; u_long ticks; { struct ipfr *ipfrtab[IPFT_SIZE], ifr; int i; /* * print out the numeric statistics */ PRINTF("IP fragment states:\n\t%lu new\n\t%lu expired\n\t%lu hits\n", ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits); PRINTF("\t%lu retrans\n\t%lu too short\n", ifsp->ifs_retrans0, ifsp->ifs_short); PRINTF("\t%lu no memory\n\t%lu already exist\n", ifsp->ifs_nomem, ifsp->ifs_exists); PRINTF("\t%lu inuse\n", ifsp->ifs_inuse); if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table, sizeof(ipfrtab))) return; /* * Print out the contents (if any) of the fragment cache table. */ PRINTF("\n"); for (i = 0; i < IPFT_SIZE; i++) while (ipfrtab[i] != NULL) { if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], sizeof(ifr)) == -1) break; ifr.ipfr_ttl -= ticks; printfraginfo("", &ifr); ipfrtab[i] = ifr.ipfr_next; } /* * Print out the contents (if any) of the NAT fragment cache table. */ if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,sizeof(ipfrtab))) return; for (i = 0; i < IPFT_SIZE; i++) while (ipfrtab[i] != NULL) { if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], sizeof(ifr)) == -1) break; ifr.ipfr_ttl -= ticks; printfraginfo("NAT: ", &ifr); ipfrtab[i] = ifr.ipfr_next; } } /* * Show stats on how auth within IPFilter has been used */ static void showauthstates(asp) fr_authstat_t *asp; { frauthent_t *frap, fra; #ifdef USE_QUAD_T printf("Authorisation hits: %qu\tmisses %qu\n", (unsigned long long) asp->fas_hits, (unsigned long long) asp->fas_miss); #else printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits, asp->fas_miss); #endif printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n", asp->fas_nospace, asp->fas_added, asp->fas_sendfail, asp->fas_sendok); printf("queok %ld\nquefail %ld\nexpire %ld\n", asp->fas_queok, asp->fas_quefail, asp->fas_expire); frap = asp->fas_faelist; while (frap) { if (kmemcpy((char *)&fra, (u_long)frap, sizeof(fra)) == -1) break; printf("age %ld\t", fra.fae_age); printfr(&fra.fae_fr, ioctl); frap = fra.fae_next; } } /* * Display groups used for each of filter rules, accounting rules and * authentication, separately. */ static void showgroups(fiop) struct friostat *fiop; { static char *gnames[3] = { "Filter", "Accounting", "Authentication" }; static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH }; frgroup_t *fp, grp; int on, off, i; on = fiop->f_active; off = 1 - on; for (i = 0; i < 3; i++) { printf("%s groups (active):\n", gnames[i]); for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL; fp = grp.fg_next) if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) break; else printf("%s\n", grp.fg_name); printf("%s groups (inactive):\n", gnames[i]); for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL; fp = grp.fg_next) if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) break; else printf("%s\n", grp.fg_name); } } static void parse_ipportstr(argument, ip, port) const char *argument; i6addr_t *ip; int *port; { char *s, *comma; int ok = 0; /* make working copy of argument, Theoretically you must be able * to write to optarg, but that seems very ugly to me.... */ s = strdup(argument); if (s == NULL) return; /* get port */ if ((comma = strchr(s, ',')) != NULL) { if (!strcasecmp(comma + 1, "any")) { *port = -1; } else if (!sscanf(comma + 1, "%d", port) || (*port < 0) || (*port > 65535)) { fprintf(stderr, "Invalid port specfication in %s\n", argument); free(s); exit(-2); } *comma = '\0'; } /* get ip address */ if (!strcasecmp(s, "any")) { ip->in4.s_addr = INADDR_ANY; #ifdef USE_INET6 ip->in6 = in6addr_any; } else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) { ok = 1; #endif } else if (inet_aton(s, &ip->in4)) ok = 1; if (ok == 0) { fprintf(stderr, "Invalid IP address: %s\n", s); free(s); exit(-2); } /* free allocated memory */ free(s); } #ifdef STATETOP static void sig_resize(s) int s; { handle_resize = 1; } static void sig_break(s) int s; { handle_break = 1; } static char *getip(v, addr) int v; i6addr_t *addr; { #ifdef USE_INET6 static char hostbuf[MAXHOSTNAMELEN+1]; #endif if (v == 4) return inet_ntoa(addr->in4); #ifdef USE_INET6 (void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1); hostbuf[MAXHOSTNAMELEN] = '\0'; return hostbuf; #else return "IPv6"; #endif } static char *ttl_to_string(ttl) long int ttl; { static char ttlbuf[STSTRSIZE]; int hours, minutes, seconds; /* ttl is in half seconds */ ttl /= 2; hours = ttl / 3600; ttl = ttl % 3600; minutes = ttl / 60; seconds = ttl % 60; if (hours > 0) sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds); else sprintf(ttlbuf, "%2d:%02d", minutes, seconds); return ttlbuf; } static int sort_pkts(a, b) const void *a; const void *b; { register const statetop_t *ap = a; register const statetop_t *bp = b; if (ap->st_pkts == bp->st_pkts) return 0; else if (ap->st_pkts < bp->st_pkts) return 1; return -1; } static int sort_bytes(a, b) const void *a; const void *b; { register const statetop_t *ap = a; register const statetop_t *bp = b; if (ap->st_bytes == bp->st_bytes) return 0; else if (ap->st_bytes < bp->st_bytes) return 1; return -1; } static int sort_p(a, b) const void *a; const void *b; { register const statetop_t *ap = a; register const statetop_t *bp = b; if (ap->st_p == bp->st_p) return 0; else if (ap->st_p < bp->st_p) return 1; return -1; } static int sort_ttl(a, b) const void *a; const void *b; { register const statetop_t *ap = a; register const statetop_t *bp = b; if (ap->st_age == bp->st_age) return 0; else if (ap->st_age < bp->st_age) return 1; return -1; } static int sort_srcip(a, b) const void *a; const void *b; { register const statetop_t *ap = a; register const statetop_t *bp = b; #ifdef USE_INET6 if (use_inet6) { if (IP6_EQ(&ap->st_src, &bp->st_src)) return 0; else if (IP6_GT(&ap->st_src, &bp->st_src)) return 1; } else #endif { if (ntohl(ap->st_src.in4.s_addr) == ntohl(bp->st_src.in4.s_addr)) return 0; else if (ntohl(ap->st_src.in4.s_addr) > ntohl(bp->st_src.in4.s_addr)) return 1; } return -1; } static int sort_srcpt(a, b) const void *a; const void *b; { register const statetop_t *ap = a; register const statetop_t *bp = b; if (htons(ap->st_sport) == htons(bp->st_sport)) return 0; else if (htons(ap->st_sport) > htons(bp->st_sport)) return 1; return -1; } static int sort_dstip(a, b) const void *a; const void *b; { register const statetop_t *ap = a; register const statetop_t *bp = b; #ifdef USE_INET6 if (use_inet6) { if (IP6_EQ(&ap->st_dst, &bp->st_dst)) return 0; else if (IP6_GT(&ap->st_dst, &bp->st_dst)) return 1; } else #endif { if (ntohl(ap->st_dst.in4.s_addr) == ntohl(bp->st_dst.in4.s_addr)) return 0; else if (ntohl(ap->st_dst.in4.s_addr) > ntohl(bp->st_dst.in4.s_addr)) return 1; } return -1; } static int sort_dstpt(a, b) const void *a; const void *b; { register const statetop_t *ap = a; register const statetop_t *bp = b; if (htons(ap->st_dport) == htons(bp->st_dport)) return 0; else if (htons(ap->st_dport) > htons(bp->st_dport)) return 1; return -1; } #endif /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" #include "ipt.h" #include #include extern char *optarg; extern struct frentry *ipfilter[2][2]; extern struct ipread snoop, etherf, tcpd, pcap, iptext, iphex; extern struct ifnet *get_unit __P((char *, int, ipf_stack_t *)); extern void init_ifp __P((void)); int opts = OPT_DONOTHING; int use_inet6 = 0; int pfil_delayed_copy = 0; int main __P((int, char *[])); int loadrules __P((char *, int)); int kmemcpy __P((char *, long, int)); int kstrncpy __P((char *, long, int n)); void dumpnat __P((ipf_stack_t *ifs)); void dumpstate __P((ipf_stack_t *ifs)); void dumplookups __P((ipf_stack_t *ifs)); void dumpgroups __P((ipf_stack_t *ifs)); void drain_log __P((char *, ipf_stack_t *ifs)); void fixv4sums __P((mb_t *, ip_t *)); ipf_stack_t *get_ifs __P((void)); ipf_stack_t *create_ifs __P((void)); #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(SOLARIS) || \ (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \ defined(__osf__) || defined(linux) int ipftestioctl __P((int, ioctlcmd_t, ...)); int ipnattestioctl __P((int, ioctlcmd_t, ...)); int ipstatetestioctl __P((int, ioctlcmd_t, ...)); int ipauthtestioctl __P((int, ioctlcmd_t, ...)); int ipscantestioctl __P((int, ioctlcmd_t, ...)); int ipsynctestioctl __P((int, ioctlcmd_t, ...)); int ipooltestioctl __P((int, ioctlcmd_t, ...)); #else int ipftestioctl __P((dev_t, ioctlcmd_t, void *)); int ipnattestioctl __P((dev_t, ioctlcmd_t, void *)); int ipstatetestioctl __P((dev_t, ioctlcmd_t, void *)); int ipauthtestioctl __P((dev_t, ioctlcmd_t, void *)); int ipsynctestioctl __P((dev_t, ioctlcmd_t, void *)); int ipscantestioctl __P((dev_t, ioctlcmd_t, void *)); int ipooltestioctl __P((dev_t, ioctlcmd_t, void *)); #endif static ioctlfunc_t iocfunctions[IPL_LOGSIZE] = { ipftestioctl, ipnattestioctl, ipstatetestioctl, ipauthtestioctl, ipsynctestioctl, ipscantestioctl, ipooltestioctl, NULL }; int main(argc,argv) int argc; char *argv[]; { char *datain, *iface, *ifname, *logout; int fd, i, dir, c, loaded, dump, hlen; struct ifnet *ifp; struct ipread *r; mb_t mb, *m; ip_t *ip; ipf_stack_t *ifs; m = &mb; dir = 0; dump = 0; hlen = 0; loaded = 0; r = &iptext; iface = NULL; logout = NULL; ifname = "anon0"; datain = NULL; initparse(); ifs = create_ifs(); #if defined(IPFILTER_DEFAULT_BLOCK) ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH; #else ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; #endif ipftuneable_alloc(ifs); MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex"); MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock"); RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex"); RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock"); RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); RWLOCK_INIT(&ifs->ifs_ipf_frcache, "ipf rule cache rwlock"); fr_loginit(ifs); fr_authinit(ifs); fr_fraginit(ifs); fr_stateinit(ifs); fr_natinit(ifs); appr_init(ifs); ip_lookup_init(ifs); ifs->ifs_fr_running = 1; while ((c = getopt(argc, argv, "6bdDF:i:I:l:N:P:or:RT:vxX")) != -1) switch (c) { case '6' : #ifdef USE_INET6 use_inet6 = 1; #else fprintf(stderr, "IPv6 not supported\n"); exit(1); #endif break; case 'b' : opts |= OPT_BRIEF; break; case 'd' : opts |= OPT_DEBUG; break; case 'D' : dump = 1; break; case 'F' : if (strcasecmp(optarg, "pcap") == 0) r = &pcap; else if (strcasecmp(optarg, "etherfind") == 0) r = ðerf; else if (strcasecmp(optarg, "snoop") == 0) r = &snoop; else if (strcasecmp(optarg, "tcpdump") == 0) r = &tcpd; else if (strcasecmp(optarg, "hex") == 0) r = &iphex; else if (strcasecmp(optarg, "text") == 0) r = &iptext; break; case 'i' : datain = optarg; break; case 'I' : ifname = optarg; break; case 'l' : logout = optarg; break; case 'o' : opts |= OPT_SAVEOUT; break; case 'r' : if (ipf_parsefile(-1, ipf_addrule, iocfunctions, optarg) == -1) return -1; loaded = 1; break; case 'R' : opts |= OPT_NORESOLVE; break; case 'v' : opts |= OPT_VERBOSE; break; case 'N' : if (ipnat_parsefile(-1, ipnat_addrule, ipnattestioctl, optarg) == -1) return -1; loaded = 1; opts |= OPT_NAT; break; case 'P' : if (ippool_parsefile(-1, optarg, ipooltestioctl) == -1) return -1; loaded = 1; break; case 'T' : ipf_dotuning(-1, optarg, ipftestioctl); break; case 'x' : opts |= OPT_HEX; break; } if (loaded == 0) { (void)fprintf(stderr,"no rules loaded\n"); exit(-1); } if (opts & OPT_SAVEOUT) init_ifp(); if (datain) fd = (*r->r_open)(datain); else fd = (*r->r_open)("-"); if (fd < 0) exit(-1); ip = MTOD(m, ip_t *); while ((i = (*r->r_readip)(MTOD(m, char *), sizeof(m->mb_buf), &iface, &dir)) > 0) { if (iface == NULL || *iface == '\0') iface = ifname; ifp = get_unit(iface, IP_V(ip), ifs); if (ifp == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } if (!use_inet6) { ip->ip_off = ntohs(ip->ip_off); ip->ip_len = ntohs(ip->ip_len); if (r->r_flags & R_DO_CKSUM) fixv4sums(m, ip); hlen = IP_HL(ip) << 2; } #ifdef USE_INET6 else hlen = sizeof(ip6_t); #endif /* ipfr_slowtimer(); */ m = &mb; m->mb_len = i; i = fr_check(ip, hlen, ifp, dir, &m, ifs); if ((opts & OPT_NAT) == 0) switch (i) { case -4 : (void)printf("preauth"); break; case -3 : (void)printf("account"); break; case -2 : (void)printf("auth"); break; case -1 : (void)printf("block"); break; case 0 : (void)printf("pass"); break; case 1 : (void)printf("nomatch"); break; case 3 : (void)printf("block return-rst"); break; case 4 : (void)printf("block return-icmp"); break; case 5 : (void)printf("block return-icmp-as-dest"); break; default : (void)printf("recognised return %#x\n", i); break; } if (!use_inet6) { ip->ip_off = htons(ip->ip_off); ip->ip_len = htons(ip->ip_len); } if (!(opts & OPT_BRIEF)) { putchar(' '); printpacket(ip); printf("--------------"); } else if ((opts & (OPT_BRIEF|OPT_NAT)) == (OPT_NAT|OPT_BRIEF)) printpacket(ip); if (dir && (ifp != NULL) && IP_V(ip) && (m != NULL)) #if defined(__sgi) && (IRIX < 60500) (*ifp->if_output)(ifp, (void *)m, NULL); #else # if TRU64 >= 1885 (*ifp->if_output)(ifp, (void *)m, NULL, 0, 0); # else (*ifp->if_output)(ifp, (void *)m, NULL, 0); # endif #endif if ((opts & (OPT_BRIEF|OPT_NAT)) != (OPT_NAT|OPT_BRIEF)) putchar('\n'); dir = 0; if (iface != ifname) { free(iface); iface = ifname; } m = &mb; } (*r->r_close)(); if (logout != NULL) { drain_log(logout, ifs); } if (dump == 1) { dumpnat(ifs); dumpstate(ifs); dumplookups(ifs); dumpgroups(ifs); } fr_deinitialise(ifs); return 0; } #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(SOLARIS) || \ (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \ defined(__osf__) || defined(linux) int ipftestioctl(int dev, ioctlcmd_t cmd, ...) { caddr_t data; va_list ap; int i; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGIPF, cmd, data, FWRITE|FREAD); if (opts & OPT_DEBUG) fprintf(stderr, "iplioctl(IPF,%#x,%p) = %d\n", (u_int)cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipnattestioctl(int dev, ioctlcmd_t cmd, ...) { caddr_t data; va_list ap; int i; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGNAT, cmd, data, FWRITE|FREAD); if (opts & OPT_DEBUG) fprintf(stderr, "iplioctl(NAT,%#x,%p) = %d\n", (u_int)cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipstatetestioctl(int dev, ioctlcmd_t cmd, ...) { caddr_t data; va_list ap; int i; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGSTATE, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(STATE,%#x,%p) = %d\n", (u_int)cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipauthtestioctl(int dev, ioctlcmd_t cmd, ...) { caddr_t data; va_list ap; int i; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGAUTH, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(AUTH,%#x,%p) = %d\n", (u_int)cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipscantestioctl(int dev, ioctlcmd_t cmd, ...) { caddr_t data; va_list ap; int i; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGSCAN, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(SCAN,%#x,%p) = %d\n", (u_int)cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipsynctestioctl(int dev, ioctlcmd_t cmd, ...) { caddr_t data; va_list ap; int i; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGSYNC, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(SYNC,%#x,%p) = %d\n", (u_int)cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipooltestioctl(int dev, ioctlcmd_t cmd, ...) { caddr_t data; va_list ap; int i; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGLOOKUP, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(POOL,%#x,%p) = %d\n", (u_int)cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } #else int ipftestioctl(dev, cmd, data) dev_t dev; ioctlcmd_t cmd; void *data; { int i; i = iplioctl(IPL_LOGIPF, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(IPF,%#x,%p) = %d\n", cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipnattestioctl(dev, cmd, data) dev_t dev; ioctlcmd_t cmd; void *data; { int i; i = iplioctl(IPL_LOGNAT, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(NAT,%#x,%p) = %d\n", cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipstatetestioctl(dev, cmd, data) dev_t dev; ioctlcmd_t cmd; void *data; { int i; i = iplioctl(IPL_LOGSTATE, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(STATE,%#x,%p) = %d\n", cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipauthtestioctl(dev, cmd, data) dev_t dev; ioctlcmd_t cmd; void *data; { int i; i = iplioctl(IPL_LOGAUTH, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(AUTH,%#x,%p) = %d\n", cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipsynctestioctl(dev, cmd, data) dev_t dev; ioctlcmd_t cmd; void *data; { int i; i = iplioctl(IPL_LOGSYNC, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(SYNC,%#x,%p) = %d\n", cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipscantestioctl(dev, cmd, data) dev_t dev; ioctlcmd_t cmd; void *data; { int i; i = iplioctl(IPL_LOGSCAN, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(SCAN,%#x,%p) = %d\n", cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipooltestioctl(dev, cmd, data) dev_t dev; ioctlcmd_t cmd; void *data; { int i; i = iplioctl(IPL_LOGLOOKUP, cmd, data, FWRITE|FREAD); if (opts & OPT_DEBUG) fprintf(stderr, "iplioctl(POOL,%#x,%p) = %d\n", cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } #endif int kmemcpy(addr, offset, size) char *addr; long offset; int size; { bcopy((char *)offset, addr, size); return 0; } int kstrncpy(buf, pos, n) char *buf; long pos; int n; { char *ptr; ptr = (char *)pos; while ((n-- > 0) && (*buf++ = *ptr++)) ; return 0; } /* * Display the built up NAT table rules and mapping entries. */ void dumpnat(ifs) ipf_stack_t *ifs; { ipnat_t *ipn; nat_t *nat; printf("List of active MAP/Redirect filters:\n"); for (ipn = ifs->ifs_nat_list; ipn != NULL; ipn = ipn->in_next) printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); printf("\nList of active sessions:\n"); for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { printactivenat(nat, opts, 0); if (nat->nat_aps) printaps(nat->nat_aps, opts); } } /* * Display the built up state table rules and mapping entries. */ void dumpstate(ifs) ipf_stack_t *ifs; { ipstate_t *ips; printf("List of active state sessions:\n"); for (ips = ifs->ifs_ips_list; ips != NULL; ) ips = printstate(ips, opts & (OPT_DEBUG|OPT_VERBOSE), ifs->ifs_fr_ticks); } void dumplookups(ifs) ipf_stack_t *ifs; { iphtable_t *iph; ip_pool_t *ipl; int i; printf("List of configured pools\n"); for (i = 0; i < IPL_LOGSIZE; i++) for (ipl = ifs->ifs_ip_pool_list[i]; ipl != NULL; ipl = ipl->ipo_next) printpool(ipl, bcopywrap, NULL, opts); printf("List of configured hash tables\n"); for (i = 0; i < IPL_LOGSIZE; i++) for (iph = ifs->ifs_ipf_htables[i]; iph != NULL; iph = iph->iph_next) printhash(iph, bcopywrap, NULL, opts); } void dumpgroups(ifs) ipf_stack_t *ifs; { frgroup_t *fg; frentry_t *fr; int i; printf("List of groups configured (set 0)\n"); for (i = 0; i < IPL_LOGSIZE; i++) for (fg = ifs->ifs_ipfgroups[i][0]; fg != NULL; fg = fg->fg_next) { printf("Dev.%d. Group %s Ref %d Flags %#x\n", i, fg->fg_name, fg->fg_ref, fg->fg_flags); for (fr = fg->fg_start; fr != NULL; fr = fr->fr_next) { #ifdef USE_QUAD_T printf("%qu ",(unsigned long long)fr->fr_hits); #else printf("%ld ", fr->fr_hits); #endif printfr(fr, ipftestioctl); } } printf("List of groups configured (set 1)\n"); for (i = 0; i < IPL_LOGSIZE; i++) for (fg = ifs->ifs_ipfgroups[i][1]; fg != NULL; fg = fg->fg_next) { printf("Dev.%d. Group %s Ref %d Flags %#x\n", i, fg->fg_name, fg->fg_ref, fg->fg_flags); for (fr = fg->fg_start; fr != NULL; fr = fr->fr_next) { #ifdef USE_QUAD_T printf("%qu ",(unsigned long long)fr->fr_hits); #else printf("%ld ", fr->fr_hits); #endif printfr(fr, ipftestioctl); } } } void drain_log(filename, ifs) char *filename; ipf_stack_t *ifs; { char buffer[DEFAULT_IPFLOGSIZE]; struct iovec iov; struct uio uio; size_t resid; int fd, i; fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644); if (fd == -1) { perror("drain_log:open"); return; } for (i = 0; i <= IPL_LOGMAX; i++) while (1) { bzero((char *)&iov, sizeof(iov)); iov.iov_base = buffer; iov.iov_len = sizeof(buffer); bzero((char *)&uio, sizeof(uio)); uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_resid = iov.iov_len; resid = uio.uio_resid; if (ipflog_read(i, &uio, ifs) == 0) { /* * If nothing was read then break out. */ if (uio.uio_resid == resid) break; write(fd, buffer, resid - uio.uio_resid); } else break; } close(fd); } void fixv4sums(m, ip) mb_t *m; ip_t *ip; { u_char *csump, *hdr; ip->ip_sum = 0; ip->ip_sum = ipf_cksum((u_short *)ip, IP_HL(ip) << 2); csump = (u_char *)ip; csump += IP_HL(ip) << 2; switch (ip->ip_p) { case IPPROTO_TCP : hdr = csump; csump += offsetof(tcphdr_t, th_sum); break; case IPPROTO_UDP : hdr = csump; csump += offsetof(udphdr_t, uh_sum); break; default : csump = NULL; hdr = NULL; break; } if (hdr != NULL) { *csump = 0; *(u_short *)csump = fr_cksum(m, ip, ip->ip_p, hdr); } } ipf_stack_t *gifs; /* * Allocate and keep pointer for get_ifs() */ ipf_stack_t * create_ifs() { ipf_stack_t *ifs; KMALLOCS(ifs, ipf_stack_t *, sizeof (*ifs)); bzero(ifs, sizeof (*ifs)); gifs = ifs; return (ifs); } ipf_stack_t * get_ifs() { return (gifs); } /* * Copyright (c) 2014 Joyent, Inc. All rights reserved. * Use is subject to license terms. * * See the IPFILTER.LICENCE file for details on licensing. */ #include #include #include #include #include #include #include "netinet/ip_fil.h" #include "ipfzone.h" static ipfzoneobj_t ipzo; static boolean_t do_setzone = 0; static int num_setzones = 0; extern int errno; extern int opterr; extern int optind; extern char *optarg; /* * Get the zonename if it's the last argument and set the zonename * in ipfzo to it. This is used by ipf(8) only - all of the other tools * specify the zone with the -z option, and therefore use getzoneopt() below. */ void getzonearg(int argc, char *argv[], const char *optstr) { int c; /* * Don't warn about unknown options - let subsequent calls to * getopt() handle this. */ opterr = 0; /* * getopt is also used here to set optind so that we can * determine if the last argument belongs to a flag or is * actually a zonename. */ while ((c = getopt(argc, argv, optstr)) != -1) { if (c == 'G') ipzo.ipfz_gz = 1; } if (optind < argc) setzonename(argv[optind]); /* * Reset optind and opterr so the next getopt call will go through all * of argv again and warn about unknown options. */ optind = 1; opterr = 1; } /* * Get a -z option from argv and set the zonename in ipfzo accordingly */ void getzoneopt(int argc, char *argv[], const char *optstr) { int c; /* * Don't warn about unknown options - let subsequent calls to * getopt() handle this. */ opterr = 0; while ((c = getopt(argc, argv, optstr)) != -1) { if (c == 'G') setzonename_global(optarg); if (c == 'z') setzonename(optarg); } /* * Reset optind and opterr so the next getopt call will go through all * of argv again and warn about unknown options. */ optind = 1; opterr = 1; } /* * Set the zonename in ipfzo to the given string: this is the zone all further * ioctls will act on. */ void setzonename(const char *zonename) { memcpy(ipzo.ipfz_zonename, zonename, sizeof (ipzo.ipfz_zonename)); do_setzone = B_TRUE; num_setzones++; } /* * Set the zonename in ipfo, and the gz flag. This indicates that we want all * further ioctls to act on the GZ-controlled stack for that zone. */ void setzonename_global(const char *zonename) { setzonename(zonename); ipzo.ipfz_gz = 1; } /* * Set the zone that all further ioctls will operate on. See the "GZ-controlled * and per-zone stacks" note at the top of ip_fil_solaris.c for further * explanation. */ int setzone(int fd) { if (!do_setzone) return (0); if (num_setzones > 1) { (void) fprintf(stderr, "Only one of -G and -z may be set\n"); return (-1); } if (ipzo.ipfz_gz == 1 && getzoneidbyname(ipzo.ipfz_zonename) == GLOBAL_ZONEID) { (void) fprintf(stderr, "-G cannot be used with the global zone\n"); return (-1); } if (ioctl(fd, SIOCIPFZONESET, &ipzo) == -1) { switch (errno) { case ENODEV: (void) fprintf(stderr, "Could not find running zone: %s\n", ipzo.ipfz_zonename); break; case EACCES: (void) fprintf(stderr, "Permission denied setting zone: %s\n", ipzo.ipfz_zonename); break; default: perror("Error setting zone"); } return (-1); } return (0); } /* * Copyright (c) 2013 Joyent, Inc. All rights reserved. * Use is subject to license terms. * * See the IPFILTER.LICENCE file for details on licensing. */ #ifndef __IPFZONE_H__ #define __IPFZONE_H__ void getzonearg(int, char *[], const char *); void getzoneopt(int, char *[], const char *); int setzone(int); void setzonename(const char *); void setzonename_global(const char *); #endif /* __IPFZONE_H__ */ /* * Copyright (C) 2001-2008 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #ifdef SOLARIS #undef SOLARIS #endif #if (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #define SOLARIS (1) #else #define SOLARIS (0) #endif #include #include #include #include #include #define _KERNEL #include #undef _KERNEL #include #include #include #include #include #include #include #include #if !defined(__SVR4) && !defined(__svr4__) # if (__FreeBSD_version >= 300000) # include # else # include # endif #else # include # include #endif #if !defined(__hpux) && (!defined(__SVR4) && !defined(__GNUC__)) # include #endif #include #include #include #include #include #include #include #if !defined(__hpux) && !defined(linux) # include #endif #include #include #include #ifdef __hpux # undef NOERROR #endif #include #if !defined(linux) # include # include #endif #include #include #include #include #include "netinet/ip_compat.h" #include #include "netinet/ip_fil.h" #include "netinet/ip_nat.h" #include "netinet/ip_state.h" #include "netinet/ip_proxy.h" #include "ipmon.h" #include "ipfzone.h" #if !defined(lint) static const char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-2000 Darren Reed"; static const char rcsid[] = "@(#)$Id: ipmon.c,v 1.33.2.10 2005/06/18 02:41:35 darrenr Exp $"; #endif #if defined(sun) && !defined(SOLARIS2) #define STRERROR(x) sys_errlist[x] extern char *sys_errlist[]; #else #define STRERROR(x) strerror(x) #endif struct flags { int value; char flag; }; typedef struct icmp_subtype { int ist_val; char *ist_name; } icmp_subtype_t; typedef struct icmp_type { int it_val; struct icmp_subtype *it_subtable; size_t it_stsize; char *it_name; } icmp_type_t; #define IST_SZ(x) (sizeof(x)/sizeof(icmp_subtype_t)) struct flags tcpfl[] = { { TH_ACK, 'A' }, { TH_RST, 'R' }, { TH_SYN, 'S' }, { TH_FIN, 'F' }, { TH_URG, 'U' }, { TH_PUSH,'P' }, { TH_ECN, 'E' }, { TH_CWR, 'C' }, { 0, '\0' } }; #if defined(__hpux) || (defined(SOLARIS) && (SOLARIS2 < 10)) static char *pidfile = "/etc/ipf/ipmon.pid"; #else # if (BSD >= 199306) || defined(SOLARIS) static char *pidfile = "/var/run/ipmon.pid"; # else static char *pidfile = "/etc/ipmon.pid"; # endif #endif static char line[2048]; static int opts = 0; static char *logfile = NULL; static FILE *binarylog = NULL; static char *binarylogfile = NULL; static int donehup = 0; static void usage __P((char *)); static void handlehup __P((int)); static void flushlogs __P((char *, FILE *)); static void print_log __P((int, FILE *, char *, int)); static void print_ipflog __P((FILE *, char *, int)); static void print_natlog __P((FILE *, char *, int)); static void print_statelog __P((FILE *, char *, int)); static int read_log __P((int, int *, char *, int)); static void write_pid __P((char *)); static char *icmpname __P((u_int, u_int)); static char *icmpname6 __P((u_int, u_int)); static icmp_type_t *find_icmptype __P((int, icmp_type_t *, size_t)); static icmp_subtype_t *find_icmpsubtype __P((int, icmp_subtype_t *, size_t)); #ifdef __hpux static struct tm *get_tm __P((u_32_t)); #else static struct tm *get_tm __P((time_t)); #endif char *hostname __P((int, int, u_32_t *)); char *portname __P((int, char *, u_int)); int main __P((int, char *[])); static void logopts __P((int, char *)); static void init_tabs __P((void)); static char *getproto __P((u_int)); static char **protocols = NULL; static char **udp_ports = NULL; static char **tcp_ports = NULL; static char *conf_file = NULL; #define OPT_SYSLOG 0x001 #define OPT_RESOLVE 0x002 #define OPT_HEXBODY 0x004 #define OPT_VERBOSE 0x008 #define OPT_HEXHDR 0x010 #define OPT_TAIL 0x020 #define OPT_NAT 0x080 #define OPT_STATE 0x100 #define OPT_FILTER 0x200 #define OPT_PORTNUM 0x400 #define OPT_LOGALL (OPT_NAT|OPT_STATE|OPT_FILTER) #define OPT_LOGBODY 0x800 #define HOSTNAME_V4(a,b) hostname((a), 4, (u_32_t *)&(b)) #ifndef LOGFAC #define LOGFAC LOG_LOCAL0 #endif static icmp_subtype_t icmpunreachnames[] = { { ICMP_UNREACH_NET, "net" }, { ICMP_UNREACH_HOST, "host" }, { ICMP_UNREACH_PROTOCOL, "protocol" }, { ICMP_UNREACH_PORT, "port" }, { ICMP_UNREACH_NEEDFRAG, "needfrag" }, { ICMP_UNREACH_SRCFAIL, "srcfail" }, { ICMP_UNREACH_NET_UNKNOWN, "net_unknown" }, { ICMP_UNREACH_HOST_UNKNOWN, "host_unknown" }, { ICMP_UNREACH_NET, "isolated" }, { ICMP_UNREACH_NET_PROHIB, "net_prohib" }, { ICMP_UNREACH_NET_PROHIB, "host_prohib" }, { ICMP_UNREACH_TOSNET, "tosnet" }, { ICMP_UNREACH_TOSHOST, "toshost" }, { ICMP_UNREACH_ADMIN_PROHIBIT, "admin_prohibit" }, { -2, NULL } }; static icmp_subtype_t redirectnames[] = { { ICMP_REDIRECT_NET, "net" }, { ICMP_REDIRECT_HOST, "host" }, { ICMP_REDIRECT_TOSNET, "tosnet" }, { ICMP_REDIRECT_TOSHOST, "toshost" }, { -2, NULL } }; static icmp_subtype_t timxceednames[] = { { ICMP_TIMXCEED_INTRANS, "transit" }, { ICMP_TIMXCEED_REASS, "reassem" }, { -2, NULL } }; static icmp_subtype_t paramnames[] = { { ICMP_PARAMPROB_ERRATPTR, "errata_pointer" }, { ICMP_PARAMPROB_OPTABSENT, "optmissing" }, { ICMP_PARAMPROB_LENGTH, "length" }, { -2, NULL } }; static icmp_type_t icmptypes[] = { { ICMP_ECHOREPLY, NULL, 0, "echoreply" }, { -1, NULL, 0, NULL }, { -1, NULL, 0, NULL }, { ICMP_UNREACH, icmpunreachnames, IST_SZ(icmpunreachnames),"unreach" }, { ICMP_SOURCEQUENCH, NULL, 0, "sourcequench" }, { ICMP_REDIRECT, redirectnames, IST_SZ(redirectnames), "redirect" }, { -1, NULL, 0, NULL }, { -1, NULL, 0, NULL }, { ICMP_ECHO, NULL, 0, "echo" }, { ICMP_ROUTERADVERT, NULL, 0, "routeradvert" }, { ICMP_ROUTERSOLICIT, NULL, 0, "routersolicit" }, { ICMP_TIMXCEED, timxceednames, IST_SZ(timxceednames), "timxceed" }, { ICMP_PARAMPROB, paramnames, IST_SZ(paramnames), "paramprob" }, { ICMP_TSTAMP, NULL, 0, "timestamp" }, { ICMP_TSTAMPREPLY, NULL, 0, "timestampreply" }, { ICMP_IREQ, NULL, 0, "inforeq" }, { ICMP_IREQREPLY, NULL, 0, "inforeply" }, { ICMP_MASKREQ, NULL, 0, "maskreq" }, { ICMP_MASKREPLY, NULL, 0, "maskreply" }, { -2, NULL, 0, NULL } }; static icmp_subtype_t icmpredirect6[] = { { ICMP6_DST_UNREACH_NOROUTE, "noroute" }, { ICMP6_DST_UNREACH_ADMIN, "admin" }, { ICMP6_DST_UNREACH_NOTNEIGHBOR, "neighbour" }, { ICMP6_DST_UNREACH_ADDR, "address" }, { ICMP6_DST_UNREACH_NOPORT, "noport" }, { -2, NULL } }; static icmp_subtype_t icmptimexceed6[] = { { ICMP6_TIME_EXCEED_TRANSIT, "intransit" }, { ICMP6_TIME_EXCEED_REASSEMBLY, "reassem" }, { -2, NULL } }; static icmp_subtype_t icmpparamprob6[] = { { ICMP6_PARAMPROB_HEADER, "header" }, { ICMP6_PARAMPROB_NEXTHEADER, "nextheader" }, { ICMP6_PARAMPROB_OPTION, "option" }, { -2, NULL } }; static icmp_subtype_t icmpquerysubject6[] = { { ICMP6_NI_SUBJ_IPV6, "ipv6" }, { ICMP6_NI_SUBJ_FQDN, "fqdn" }, { ICMP6_NI_SUBJ_IPV4, "ipv4" }, { -2, NULL }, }; static icmp_subtype_t icmpnodeinfo6[] = { { ICMP6_NI_SUCCESS, "success" }, { ICMP6_NI_REFUSED, "refused" }, { ICMP6_NI_UNKNOWN, "unknown" }, { -2, NULL } }; static icmp_subtype_t icmprenumber6[] = { { ICMP6_ROUTER_RENUMBERING_COMMAND, "command" }, { ICMP6_ROUTER_RENUMBERING_RESULT, "result" }, { ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET, "seqnum_reset" }, { -2, NULL } }; static icmp_type_t icmptypes6[] = { { 0, NULL, 0, NULL }, { ICMP6_DST_UNREACH, icmpredirect6, IST_SZ(icmpredirect6), "unreach" }, { ICMP6_PACKET_TOO_BIG, NULL, 0, "toobig" }, { ICMP6_TIME_EXCEEDED, icmptimexceed6, IST_SZ(icmptimexceed6), "timxceed" }, { ICMP6_PARAM_PROB, icmpparamprob6, IST_SZ(icmpparamprob6), "paramprob" }, { ICMP6_ECHO_REQUEST, NULL, 0, "echo" }, { ICMP6_ECHO_REPLY, NULL, 0, "echoreply" }, { ICMP6_MEMBERSHIP_QUERY, icmpquerysubject6, IST_SZ(icmpquerysubject6), "groupmemberquery" }, { ICMP6_MEMBERSHIP_REPORT,NULL, 0, "groupmemberreport" }, { ICMP6_MEMBERSHIP_REDUCTION,NULL, 0, "groupmemberterm" }, { ND_ROUTER_SOLICIT, NULL, 0, "routersolicit" }, { ND_ROUTER_ADVERT, NULL, 0, "routeradvert" }, { ND_NEIGHBOR_SOLICIT, NULL, 0, "neighborsolicit" }, { ND_NEIGHBOR_ADVERT, NULL, 0, "neighboradvert" }, { ND_REDIRECT, NULL, 0, "redirect" }, { ICMP6_ROUTER_RENUMBERING, icmprenumber6, IST_SZ(icmprenumber6), "routerrenumber" }, { ICMP6_WRUREQUEST, NULL, 0, "whoareyourequest" }, { ICMP6_WRUREPLY, NULL, 0, "whoareyoureply" }, { ICMP6_FQDN_QUERY, NULL, 0, "fqdnquery" }, { ICMP6_FQDN_REPLY, NULL, 0, "fqdnreply" }, { ICMP6_NI_QUERY, icmpnodeinfo6, IST_SZ(icmpnodeinfo6), "nodeinforequest" }, { ICMP6_NI_REPLY, NULL, 0, "nodeinforeply" }, { MLD6_MTRACE_RESP, NULL, 0, "mtraceresponse" }, { MLD6_MTRACE, NULL, 0, "mtracerequest" }, { -2, NULL, 0, NULL } }; static icmp_subtype_t *find_icmpsubtype(type, table, tablesz) int type; icmp_subtype_t *table; size_t tablesz; { icmp_subtype_t *ist; int i; if (tablesz < 2) return NULL; if ((type < 0) || (type > table[tablesz - 2].ist_val)) return NULL; i = type; if (table[type].ist_val == type) return table + type; for (i = 0, ist = table; ist->ist_val != -2; i++, ist++) if (ist->ist_val == type) return ist; return NULL; } static icmp_type_t *find_icmptype(type, table, tablesz) int type; icmp_type_t *table; size_t tablesz; { icmp_type_t *it; int i; if (tablesz < 2) return NULL; if ((type < 0) || (type > table[tablesz - 2].it_val)) return NULL; i = type; if (table[type].it_val == type) return table + type; for (i = 0, it = table; it->it_val != -2; i++, it++) if (it->it_val == type) return it; return NULL; } static void handlehup(sig) int sig; { signal(SIGHUP, handlehup); donehup = 1; } static void init_tabs() { struct protoent *p; struct servent *s; char *name, **tab; int port, i; if (protocols != NULL) { for (i = 0; i < 256; i++) if (protocols[i] != NULL) { free(protocols[i]); protocols[i] = NULL; } free(protocols); protocols = NULL; } protocols = (char **)malloc(256 * sizeof(*protocols)); if (protocols != NULL) { bzero((char *)protocols, 256 * sizeof(*protocols)); setprotoent(1); while ((p = getprotoent()) != NULL) if (p->p_proto >= 0 && p->p_proto <= 255 && p->p_name != NULL && protocols[p->p_proto] == NULL) protocols[p->p_proto] = strdup(p->p_name); endprotoent(); #if defined(_AIX51) if (protocols[0]) free(protocols[0]); if (protocols[252]) free(protocols[252]); protocols[0] = "ip"; protocols[252] = NULL; #endif } if (udp_ports != NULL) { for (i = 0; i < 65536; i++) if (udp_ports[i] != NULL) { free(udp_ports[i]); udp_ports[i] = NULL; } free(udp_ports); udp_ports = NULL; } udp_ports = (char **)malloc(65536 * sizeof(*udp_ports)); if (udp_ports != NULL) bzero((char *)udp_ports, 65536 * sizeof(*udp_ports)); if (tcp_ports != NULL) { for (i = 0; i < 65536; i++) if (tcp_ports[i] != NULL) { free(tcp_ports[i]); tcp_ports[i] = NULL; } free(tcp_ports); tcp_ports = NULL; } tcp_ports = (char **)malloc(65536 * sizeof(*tcp_ports)); if (tcp_ports != NULL) bzero((char *)tcp_ports, 65536 * sizeof(*tcp_ports)); setservent(1); while ((s = getservent()) != NULL) { if (s->s_proto == NULL) continue; else if (!strcmp(s->s_proto, "tcp")) { port = ntohs(s->s_port); name = s->s_name; tab = tcp_ports; } else if (!strcmp(s->s_proto, "udp")) { port = ntohs(s->s_port); name = s->s_name; tab = udp_ports; } else continue; if ((port < 0 || port > 65535) || (name == NULL)) continue; if (tab != NULL) tab[port] = strdup(name); } endservent(); } static char *getproto(p) u_int p; { static char pnum[4]; char *s; p &= 0xff; s = protocols ? protocols[p] : NULL; if (s == NULL) { sprintf(pnum, "%u", p); s = pnum; } return s; } static int read_log(fd, lenp, buf, bufsize) int fd, bufsize, *lenp; char *buf; { int nr; nr = read(fd, buf, bufsize); if (!nr) return 2; if ((nr < 0) && (errno != EINTR)) return -1; *lenp = nr; return 0; } char *hostname(res, v, ip) int res, v; u_32_t *ip; { # define MAX_INETA 16 static char hname[MAXHOSTNAMELEN + MAX_INETA + 3]; #ifdef USE_INET6 static char hostbuf[MAXHOSTNAMELEN+1]; #endif struct hostent *hp; struct in_addr ipa; if (v == 4) { ipa.s_addr = *ip; if (!res) return inet_ntoa(ipa); hp = gethostbyaddr((char *)ip, sizeof(*ip), AF_INET); if (!hp) return inet_ntoa(ipa); sprintf(hname, "%.*s[%s]", MAXHOSTNAMELEN, hp->h_name, inet_ntoa(ipa)); return hname; } #ifdef USE_INET6 (void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1); hostbuf[MAXHOSTNAMELEN] = '\0'; return hostbuf; #else return "IPv6"; #endif } char *portname(res, proto, port) int res; char *proto; u_int port; { static char pname[8]; char *s; port = ntohs(port); port &= 0xffff; (void) sprintf(pname, "%u", port); if (!res || (opts & OPT_PORTNUM)) return pname; s = NULL; if (!strcmp(proto, "tcp")) s = tcp_ports[port]; else if (!strcmp(proto, "udp")) s = udp_ports[port]; if (s == NULL) s = pname; return s; } static char *icmpname(type, code) u_int type; u_int code; { static char name[80]; icmp_subtype_t *ist; icmp_type_t *it; char *s; s = NULL; it = find_icmptype(type, icmptypes, sizeof(icmptypes) / sizeof(*it)); if (it != NULL) s = it->it_name; if (s == NULL) sprintf(name, "icmptype(%d)/", type); else sprintf(name, "%s/", s); ist = NULL; if (it != NULL && it->it_subtable != NULL) ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize); if (ist != NULL && ist->ist_name != NULL) strcat(name, ist->ist_name); else sprintf(name + strlen(name), "%d", code); return name; } static char *icmpname6(type, code) u_int type; u_int code; { static char name[80]; icmp_subtype_t *ist; icmp_type_t *it; char *s; s = NULL; it = find_icmptype(type, icmptypes6, sizeof(icmptypes6) / sizeof(*it)); if (it != NULL) s = it->it_name; if (s == NULL) sprintf(name, "icmpv6type(%d)/", type); else sprintf(name, "%s/", s); ist = NULL; if (it != NULL && it->it_subtable != NULL) ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize); if (ist != NULL && ist->ist_name != NULL) strcat(name, ist->ist_name); else sprintf(name + strlen(name), "%d", code); return name; } void dumphex(log, dopts, buf, len) FILE *log; int dopts; char *buf; int len; { char hline[80]; int i, j, k; u_char *s = (u_char *)buf, *t = (u_char *)hline; if (buf == NULL || len == 0) return; *hline = '\0'; for (i = len, j = 0; i; i--, j++, s++) { if (j && !(j & 0xf)) { *t++ = '\n'; *t = '\0'; if (!(dopts & OPT_SYSLOG)) fputs(hline, log); else syslog(LOG_INFO, "%s", hline); t = (u_char *)hline; *t = '\0'; } sprintf((char *)t, "%02x", *s & 0xff); t += 2; if (!((j + 1) & 0xf)) { s -= 15; sprintf((char *)t, " "); t += 8; for (k = 16; k; k--, s++) *t++ = (ISPRINT(*s) ? *s : '.'); s--; } if ((j + 1) & 0xf) *t++ = ' ';; } if (j & 0xf) { for (k = 16 - (j & 0xf); k; k--) { *t++ = ' '; *t++ = ' '; *t++ = ' '; } sprintf((char *)t, " "); t += 7; s -= j & 0xf; for (k = j & 0xf; k; k--, s++) *t++ = (ISPRINT(*s) ? *s : '.'); *t++ = '\n'; *t = '\0'; } if (!(dopts & OPT_SYSLOG)) { fputs(hline, log); fflush(log); } else syslog(LOG_INFO, "%s", hline); } static struct tm *get_tm(sec) #ifdef __hpux u_32_t sec; #else time_t sec; #endif { struct tm *tm; time_t t; t = sec; tm = localtime(&t); return tm; } static void print_natlog(log, buf, blen) FILE *log; char *buf; int blen; { struct natlog *nl; iplog_t *ipl = (iplog_t *)buf; char *t = line; struct tm *tm; int res, i, len; char *proto; nl = (struct natlog *)((char *)ipl + sizeof(*ipl)); res = (opts & OPT_RESOLVE) ? 1 : 0; tm = get_tm(ipl->ipl_sec); len = sizeof(line); if (!(opts & OPT_SYSLOG)) { (void) strftime(t, len, "%d/%m/%Y ", tm); i = strlen(t); len -= i; t += i; } (void) strftime(t, len, "%T", tm); t += strlen(t); (void) sprintf(t, ".%-.6ld @%hd ", ipl->ipl_usec, nl->nlg_rule + 1); t += strlen(t); if (nl->nlg_type == NL_NEWMAP) strcpy(t, "NAT:MAP "); else if (nl->nlg_type == NL_NEWRDR) strcpy(t, "NAT:RDR "); else if (nl->nlg_type == NL_FLUSH) strcpy(t, "NAT:FLUSH "); else if (nl->nlg_type == NL_EXPIRE) strcpy(t, "NAT:EXPIRE "); else if (nl->nlg_type == NL_NEWBIMAP) strcpy(t, "NAT:BIMAP "); else if (nl->nlg_type == NL_NEWBLOCK) strcpy(t, "NAT:MAPBLOCK "); else if (nl->nlg_type == NL_CLONE) strcpy(t, "NAT:CLONE "); else sprintf(t, "Type: %d ", nl->nlg_type); t += strlen(t); proto = getproto(nl->nlg_p); (void) sprintf(t, "%s,%s <- -> ", hostname(res, nl->nlg_v, (u_32_t *)&nl->nlg_inip), portname(res, proto, (u_int)nl->nlg_inport)); t += strlen(t); (void) sprintf(t, "%s,%s ", hostname(res, nl->nlg_v, (u_32_t *)&nl->nlg_outip), portname(res, proto, (u_int)nl->nlg_outport)); t += strlen(t); (void) sprintf(t, "[%s,%s]", hostname(res, nl->nlg_v, (u_32_t *)&nl->nlg_origip), portname(res, proto, (u_int)nl->nlg_origport)); t += strlen(t); if (nl->nlg_type == NL_EXPIRE) { #ifdef USE_QUAD_T (void) sprintf(t, " Pkts %qd/%qd Bytes %qd/%qd", (long long)nl->nlg_pkts[0], (long long)nl->nlg_pkts[1], (long long)nl->nlg_bytes[0], (long long)nl->nlg_bytes[1]); #else (void) sprintf(t, " Pkts %ld/%ld Bytes %ld/%ld", nl->nlg_pkts[0], nl->nlg_pkts[1], nl->nlg_bytes[0], nl->nlg_bytes[1]); #endif t += strlen(t); } *t++ = '\n'; *t++ = '\0'; if (opts & OPT_SYSLOG) syslog(LOG_INFO, "%s", line); else (void) fprintf(log, "%s", line); } static void print_statelog(log, buf, blen) FILE *log; char *buf; int blen; { struct ipslog *sl; iplog_t *ipl = (iplog_t *)buf; char *t = line, *proto; struct tm *tm; int res, i, len; sl = (struct ipslog *)((char *)ipl + sizeof(*ipl)); res = (opts & OPT_RESOLVE) ? 1 : 0; tm = get_tm(ipl->ipl_sec); len = sizeof(line); if (!(opts & OPT_SYSLOG)) { (void) strftime(t, len, "%d/%m/%Y ", tm); i = strlen(t); len -= i; t += i; } (void) strftime(t, len, "%T", tm); t += strlen(t); (void) sprintf(t, ".%-.6ld ", ipl->ipl_usec); t += strlen(t); if (sl->isl_type == ISL_NEW) strcpy(t, "STATE:NEW "); else if (sl->isl_type == ISL_CLONE) strcpy(t, "STATE:CLONED "); else if (sl->isl_type == ISL_EXPIRE) { if ((sl->isl_p == IPPROTO_TCP) && (sl->isl_state[0] > IPF_TCPS_ESTABLISHED || sl->isl_state[1] > IPF_TCPS_ESTABLISHED)) strcpy(t, "STATE:CLOSE "); else strcpy(t, "STATE:EXPIRE "); } else if (sl->isl_type == ISL_FLUSH) strcpy(t, "STATE:FLUSH "); else if (sl->isl_type == ISL_INTERMEDIATE) strcpy(t, "STATE:INTERMEDIATE "); else if (sl->isl_type == ISL_REMOVE) strcpy(t, "STATE:REMOVE "); else if (sl->isl_type == ISL_KILLED) strcpy(t, "STATE:KILLED "); else sprintf(t, "Type: %d ", sl->isl_type); t += strlen(t); proto = getproto(sl->isl_p); if (sl->isl_p == IPPROTO_TCP || sl->isl_p == IPPROTO_UDP) { (void) sprintf(t, "%s,%s -> ", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src), portname(res, proto, (u_int)sl->isl_sport)); t += strlen(t); (void) sprintf(t, "%s,%s PR %s", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), portname(res, proto, (u_int)sl->isl_dport), proto); } else if (sl->isl_p == IPPROTO_ICMP) { (void) sprintf(t, "%s -> ", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src)); t += strlen(t); (void) sprintf(t, "%s PR icmp %d", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), sl->isl_itype); } else if (sl->isl_p == IPPROTO_ICMPV6) { (void) sprintf(t, "%s -> ", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src)); t += strlen(t); (void) sprintf(t, "%s PR icmpv6 %d", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), sl->isl_itype); } else { (void) sprintf(t, "%s -> ", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src)); t += strlen(t); (void) sprintf(t, "%s PR %s", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), proto); } t += strlen(t); if (sl->isl_tag != FR_NOLOGTAG) { (void) sprintf(t, " tag %u", sl->isl_tag); t += strlen(t); } if (sl->isl_type != ISL_NEW) { sprintf(t, #ifdef USE_QUAD_T #ifdef PRId64 " Forward: Pkts in %" PRId64 " Bytes in %" PRId64 " Pkts out %" PRId64 " Bytes out %" PRId64 " Backward: Pkts in %" PRId64 " Bytes in %" PRId64 " Pkts out %" PRId64 " Bytes out %" PRId64, #else " Forward: Pkts in %qd Bytes in %qd Pkts out %qd Bytes out %qd Backward: Pkts in %qd Bytes in %qd Pkts out %qd Bytes out %qd", #endif /* PRId64 */ #else " Forward: Pkts in %ld Bytes in %ld Pkts out %ld Bytes out %ld Backward: Pkts in %ld Bytes in %ld Pkts out %ld Bytes out %ld", #endif sl->isl_pkts[0], sl->isl_bytes[0], sl->isl_pkts[1], sl->isl_bytes[1], sl->isl_pkts[2], sl->isl_bytes[2], sl->isl_pkts[3], sl->isl_bytes[3]); t += strlen(t); } *t++ = '\n'; *t++ = '\0'; if (opts & OPT_SYSLOG) syslog(LOG_INFO, "%s", line); else (void) fprintf(log, "%s", line); } static void print_log(logtype, log, buf, blen) FILE *log; char *buf; int logtype, blen; { iplog_t *ipl; char *bp = NULL, *bpo = NULL; int psize; while (blen > 0) { ipl = (iplog_t *)buf; if ((u_long)ipl & (sizeof(long)-1)) { if (bp) bpo = bp; bp = (char *)malloc(blen); if (bp == NULL) { perror("malloc"); exit(1); } bcopy((char *)ipl, bp, blen); if (bpo) { free(bpo); bpo = NULL; } buf = bp; continue; } psize = ipl->ipl_dsize; if (psize > blen) break; if (binarylog) { fwrite(buf, psize, 1, binarylog); fflush(binarylog); } if (logtype == IPL_LOGIPF) { if (ipl->ipl_magic == IPL_MAGIC) print_ipflog(log, buf, psize); } else if (logtype == IPL_LOGNAT) { if (ipl->ipl_magic == IPL_MAGIC_NAT) print_natlog(log, buf, psize); } else if (logtype == IPL_LOGSTATE) { if (ipl->ipl_magic == IPL_MAGIC_STATE) print_statelog(log, buf, psize); } blen -= psize; buf += psize; } if (bp) free(bp); return; } static void print_ipflog(log, buf, blen) FILE *log; char *buf; int blen; { tcphdr_t *tp; struct icmp *ic; struct icmp *icmp; struct tm *tm; char *t, *proto; int i, v, lvl, res, len, off, plen, ipoff, defaction; ip_t *ipc, *ip; u_32_t *s, *d; u_short hl, p; ipflog_t *ipf; iplog_t *ipl; #ifdef USE_INET6 ip6_t *ip6; #endif ipl = (iplog_t *)buf; ipf = (ipflog_t *)((char *)buf + sizeof(*ipl)); ip = (ip_t *)((char *)ipf + sizeof(*ipf)); v = IP_V(ip); res = (opts & OPT_RESOLVE) ? 1 : 0; t = line; *t = '\0'; tm = get_tm(ipl->ipl_sec); len = sizeof(line); if (!(opts & OPT_SYSLOG)) { (void) strftime(t, len, "%d/%m/%Y ", tm); i = strlen(t); len -= i; t += i; } (void) strftime(t, len, "%T", tm); t += strlen(t); (void) sprintf(t, ".%-.6ld ", ipl->ipl_usec); t += strlen(t); if (ipl->ipl_count > 1) { (void) sprintf(t, "%dx ", ipl->ipl_count); t += strlen(t); } #if (defined(MENTAT) || \ (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) || \ (defined(OpenBSD) && (OpenBSD >= 199603))) || defined(linux) { char ifname[sizeof(ipf->fl_ifname) + 1]; strncpy(ifname, ipf->fl_ifname, sizeof(ipf->fl_ifname)); ifname[sizeof(ipf->fl_ifname)] = '\0'; (void) sprintf(t, "%s", ifname); t += strlen(t); # if defined(MENTAT) || defined(linux) if (ISALPHA(*(t - 1))) { sprintf(t, "%d", ipf->fl_unit); t += strlen(t); } # endif } #else for (len = 0; len < 3; len++) if (ipf->fl_ifname[len] == '\0') break; if (ipf->fl_ifname[len]) len++; (void) sprintf(t, "%*.*s%u", len, len, ipf->fl_ifname, ipf->fl_unit); t += strlen(t); #endif #if defined(__sgi) || defined(_AIX51) || defined(__powerpc__) || \ defined(__arm__) if ((ipf->fl_group[0] == 255) && (ipf->fl_group[1] == '\0')) #else if ((ipf->fl_group[0] == -1) && (ipf->fl_group[1] == '\0')) #endif strcat(t, " @-1:"); else if (ipf->fl_group[0] == '\0') (void) strcpy(t, " @0:"); else (void) sprintf(t, " @%s:", ipf->fl_group); t += strlen(t); if (ipf->fl_rule == 0xffffffff) strcat(t, "-1 "); else (void) sprintf(t, "%u ", ipf->fl_rule + 1); t += strlen(t); lvl = LOG_NOTICE; if (ipf->fl_lflags & FI_SHORT) { *t++ = 'S'; lvl = LOG_ERR; } if (FR_ISPASS(ipf->fl_flags)) { if (ipf->fl_flags & FR_LOGP) *t++ = 'p'; else *t++ = 'P'; } else if (FR_ISBLOCK(ipf->fl_flags)) { if (ipf->fl_flags & FR_LOGB) *t++ = 'b'; else *t++ = 'B'; lvl = LOG_WARNING; } else if ((ipf->fl_flags & FR_LOGMASK) == FR_LOG) { *t++ = 'L'; lvl = LOG_INFO; } else if (ipf->fl_flags & FF_LOGNOMATCH) { *t++ = 'n'; } else { *t++ = '?'; lvl = LOG_EMERG; } if (ipf->fl_loglevel != 0xffff) lvl = ipf->fl_loglevel; *t++ = ' '; *t = '\0'; if (v == 6) { #ifdef USE_INET6 off = 0; ipoff = 0; hl = sizeof(ip6_t); ip6 = (ip6_t *)ip; p = (u_short)ip6->ip6_nxt; s = (u_32_t *)&ip6->ip6_src; d = (u_32_t *)&ip6->ip6_dst; plen = hl + ntohs(ip6->ip6_plen); #else sprintf(t, "ipv6"); goto printipflog; #endif } else if (v == 4) { hl = IP_HL(ip) << 2; ipoff = ip->ip_off; off = ipoff & IP_OFFMASK; p = (u_short)ip->ip_p; s = (u_32_t *)&ip->ip_src; d = (u_32_t *)&ip->ip_dst; plen = ip->ip_len; } else { goto printipflog; } proto = getproto(p); if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !off) { tp = (tcphdr_t *)((char *)ip + hl); if (!(ipf->fl_lflags & FI_SHORT)) { (void) sprintf(t, "%s,%s -> ", hostname(res, v, s), portname(res, proto, (u_int)tp->th_sport)); t += strlen(t); (void) sprintf(t, "%s,%s PR %s len %hu %hu", hostname(res, v, d), portname(res, proto, (u_int)tp->th_dport), proto, hl, plen); t += strlen(t); if (p == IPPROTO_TCP) { *t++ = ' '; *t++ = '-'; for (i = 0; tcpfl[i].value; i++) if (tp->th_flags & tcpfl[i].value) *t++ = tcpfl[i].flag; if (opts & OPT_VERBOSE) { (void) sprintf(t, " %lu %lu %hu", (u_long)(ntohl(tp->th_seq)), (u_long)(ntohl(tp->th_ack)), ntohs(tp->th_win)); t += strlen(t); } } *t = '\0'; } else { (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR %s len %hu %hu", hostname(res, v, d), proto, hl, plen); } } else if ((p == IPPROTO_ICMPV6) && !off && (v == 6)) { ic = (struct icmp *)((char *)ip + hl); (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR icmpv6 len %hu %hu icmpv6 %s", hostname(res, v, d), hl, plen, icmpname6(ic->icmp_type, ic->icmp_code)); } else if ((p == IPPROTO_ICMP) && !off && (v == 4)) { ic = (struct icmp *)((char *)ip + hl); (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR icmp len %hu %hu icmp %s", hostname(res, v, d), hl, plen, icmpname(ic->icmp_type, ic->icmp_code)); if (ic->icmp_type == ICMP_UNREACH || ic->icmp_type == ICMP_SOURCEQUENCH || ic->icmp_type == ICMP_PARAMPROB || ic->icmp_type == ICMP_REDIRECT || ic->icmp_type == ICMP_TIMXCEED) { ipc = &ic->icmp_ip; i = ntohs(ipc->ip_len); /* * XXX - try to guess endian of ip_len in ICMP * returned data. */ if (i > 1500) i = ipc->ip_len; ipoff = ntohs(ipc->ip_off); proto = getproto(ipc->ip_p); if (!(ipoff & IP_OFFMASK) && ((ipc->ip_p == IPPROTO_TCP) || (ipc->ip_p == IPPROTO_UDP))) { tp = (tcphdr_t *)((char *)ipc + hl); t += strlen(t); (void) sprintf(t, " for %s,%s -", HOSTNAME_V4(res, ipc->ip_src), portname(res, proto, (u_int)tp->th_sport)); t += strlen(t); (void) sprintf(t, " %s,%s PR %s len %hu %hu", HOSTNAME_V4(res, ipc->ip_dst), portname(res, proto, (u_int)tp->th_dport), proto, IP_HL(ipc) << 2, i); } else if (!(ipoff & IP_OFFMASK) && (ipc->ip_p == IPPROTO_ICMP)) { icmp = (icmphdr_t *)((char *)ipc + hl); t += strlen(t); (void) sprintf(t, " for %s -", HOSTNAME_V4(res, ipc->ip_src)); t += strlen(t); (void) sprintf(t, " %s PR icmp len %hu %hu icmp %d/%d", HOSTNAME_V4(res, ipc->ip_dst), IP_HL(ipc) << 2, i, icmp->icmp_type, icmp->icmp_code); } else { t += strlen(t); (void) sprintf(t, " for %s -", HOSTNAME_V4(res, ipc->ip_src)); t += strlen(t); (void) sprintf(t, " %s PR %s len %hu (%hu)", HOSTNAME_V4(res, ipc->ip_dst), proto, IP_HL(ipc) << 2, i); t += strlen(t); if (ipoff & IP_OFFMASK) { (void) sprintf(t, "(frag %d:%hu@%hu%s%s)", ntohs(ipc->ip_id), i - (IP_HL(ipc) << 2), (ipoff & IP_OFFMASK) << 3, ipoff & IP_MF ? "+" : "", ipoff & IP_DF ? "-" : ""); } } } } else { (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR %s len %hu (%hu)", hostname(res, v, d), proto, hl, plen); t += strlen(t); if (off & IP_OFFMASK) (void) sprintf(t, " (frag %d:%hu@%hu%s%s)", ntohs(ip->ip_id), plen - hl, (off & IP_OFFMASK) << 3, ipoff & IP_MF ? "+" : "", ipoff & IP_DF ? "-" : ""); } t += strlen(t); printipflog: if (ipf->fl_flags & FR_KEEPSTATE) { (void) strcpy(t, " K-S"); t += strlen(t); } if (ipf->fl_flags & FR_KEEPFRAG) { (void) strcpy(t, " K-F"); t += strlen(t); } if (ipf->fl_dir == 0) strcpy(t, " IN"); else if (ipf->fl_dir == 1) strcpy(t, " OUT"); t += strlen(t); if (ipf->fl_logtag != 0) { sprintf(t, " log-tag %d", ipf->fl_logtag); t += strlen(t); } if (ipf->fl_nattag.ipt_num[0] != 0) { strcpy(t, " nat-tag "); t += strlen(t); strncpy(t, ipf->fl_nattag.ipt_tag, sizeof(ipf->fl_nattag)); t += strlen(t); } if ((ipf->fl_lflags & FI_LOWTTL) != 0) { strcpy(t, " low-ttl"); t += 8; } if ((ipf->fl_lflags & FI_OOW) != 0) { if (ipf->fl_lflags & FI_NEG_OOW) { strcpy(t, " NEG_OOW"); t += sizeof (" NEG_OOW") - 1; } else { strcpy(t, " OOW"); t += sizeof (" OOW") - 1; } } if ((ipf->fl_lflags & FI_BAD) != 0) { strcpy(t, " bad"); t += 4; } if ((ipf->fl_lflags & FI_NATED) != 0) { strcpy(t, " NAT"); t += 4; } if ((ipf->fl_lflags & FI_BADNAT) != 0) { strcpy(t, " bad-NAT"); t += 8; } if ((ipf->fl_lflags & FI_BADSRC) != 0) { strcpy(t, " bad-src"); t += 8; } if ((ipf->fl_lflags & FI_MULTICAST) != 0) { strcpy(t, " multicast"); t += 10; } if ((ipf->fl_lflags & FI_BROADCAST) != 0) { strcpy(t, " broadcast"); t += 10; } if ((ipf->fl_lflags & (FI_MULTICAST|FI_BROADCAST|FI_MBCAST)) == FI_MBCAST) { strcpy(t, " mbcast"); t += 7; } *t++ = '\n'; *t++ = '\0'; defaction = 0; if (conf_file != NULL) defaction = check_action(buf, line, opts, lvl); if (defaction == 0) { if (opts & OPT_SYSLOG) syslog(lvl, "%s", line); else (void) fprintf(log, "%s", line); if (opts & OPT_HEXHDR) dumphex(log, opts, buf, sizeof(iplog_t) + sizeof(*ipf)); if (opts & OPT_HEXBODY) dumphex(log, opts, (char *)ip, ipf->fl_plen + ipf->fl_hlen); else if ((opts & OPT_LOGBODY) && (ipf->fl_flags & FR_LOGBODY)) dumphex(log, opts, (char *)ip + ipf->fl_hlen, ipf->fl_plen); } } static void usage(prog) char *prog; { fprintf(stderr, "%s: [-abDFhnpstvxX] %s %s %s %s %s %s %s\n", prog, "[-G|-z zonename]", "[-N device]", "[ [-o [NSI]] [-O [NSI]]", "[-P pidfile]", "[-S device]", "[-f device]", "filename"); exit(1); } static void write_pid(file) char *file; { FILE *fp = NULL; int fd; if ((fd = open(file, O_CREAT|O_TRUNC|O_WRONLY, 0644)) >= 0) { fp = fdopen(fd, "w"); if (fp == NULL) { close(fd); fprintf(stderr, "unable to open/create pid file: %s\n", file); return; } fprintf(fp, "%d", getpid()); fclose(fp); } } static void flushlogs(file, log) char *file; FILE *log; { int fd, flushed = 0; if ((fd = open(file, O_RDWR)) == -1) { (void) fprintf(stderr, "%s: open: %s\n", file, STRERROR(errno)); exit(1); } if (setzone(fd) != 0) { close(fd); exit(1); } if (ioctl(fd, SIOCIPFFB, &flushed) == 0) { printf("%d bytes flushed from log buffer\n", flushed); fflush(stdout); } else perror("SIOCIPFFB"); (void) close(fd); if (flushed) { if (opts & OPT_SYSLOG) syslog(LOG_INFO, "%d bytes flushed from log\n", flushed); else if (log != stdout) fprintf(log, "%d bytes flushed from log\n", flushed); } } static void logopts(turnon, options) int turnon; char *options; { int flags = 0; char *s; for (s = options; *s; s++) { switch (*s) { case 'N' : flags |= OPT_NAT; break; case 'S' : flags |= OPT_STATE; break; case 'I' : flags |= OPT_FILTER; break; default : fprintf(stderr, "Unknown log option %c\n", *s); exit(1); } } if (turnon) opts |= flags; else opts &= ~(flags); } int main(argc, argv) int argc; char *argv[]; { struct stat sb; FILE *log = stdout; FILE *fp; int fd[3], doread, n, i; int tr, nr, regular[3], c; int fdt[3], devices = 0, make_daemon = 0; char buf[DEFAULT_IPFLOGSIZE], *iplfile[3], *s; extern int optind; extern char *optarg; const char *optstr = "?abB:C:Df:G:FhnN:o:O:pP:sS:tvxXz:"; fd[0] = fd[1] = fd[2] = -1; fdt[0] = fdt[1] = fdt[2] = -1; iplfile[0] = IPL_NAME; iplfile[1] = IPNAT_NAME; iplfile[2] = IPSTATE_NAME; /* * We need to set the zone name before calling openlog in * the switch statement below */ getzoneopt(argc, argv, optstr); while ((c = getopt(argc, argv, optstr)) != -1) switch (c) { case 'a' : opts |= OPT_LOGALL; fdt[0] = IPL_LOGIPF; fdt[1] = IPL_LOGNAT; fdt[2] = IPL_LOGSTATE; break; case 'b' : opts |= OPT_LOGBODY; break; case 'B' : binarylogfile = optarg; binarylog = fopen(optarg, "a"); break; case 'C' : conf_file = optarg; break; case 'D' : make_daemon = 1; break; case 'f' : case 'I' : opts |= OPT_FILTER; fdt[0] = IPL_LOGIPF; iplfile[0] = optarg; break; case 'F' : flushlogs(iplfile[0], log); flushlogs(iplfile[1], log); flushlogs(iplfile[2], log); break; case 'G' : /* Already handled by getzoneopt() above */ break; case 'n' : opts |= OPT_RESOLVE; break; case 'N' : opts |= OPT_NAT; fdt[1] = IPL_LOGNAT; iplfile[1] = optarg; break; case 'o' : case 'O' : logopts(c == 'o', optarg); fdt[0] = fdt[1] = fdt[2] = -1; if (opts & OPT_FILTER) fdt[0] = IPL_LOGIPF; if (opts & OPT_NAT) fdt[1] = IPL_LOGNAT; if (opts & OPT_STATE) fdt[2] = IPL_LOGSTATE; break; case 'p' : opts |= OPT_PORTNUM; break; case 'P' : pidfile = optarg; break; case 's' : s = strrchr(argv[0], '/'); if (s == NULL) s = argv[0]; else s++; openlog(s, LOG_NDELAY|LOG_PID, LOGFAC); s = NULL; opts |= OPT_SYSLOG; log = NULL; break; case 'S' : opts |= OPT_STATE; fdt[2] = IPL_LOGSTATE; iplfile[2] = optarg; break; case 't' : opts |= OPT_TAIL; break; case 'v' : opts |= OPT_VERBOSE; break; case 'x' : opts |= OPT_HEXBODY; break; case 'X' : opts |= OPT_HEXHDR; break; case 'z' : /* Already handled by getzoneopt() above */ break; default : case 'h' : case '?' : usage(argv[0]); } init_tabs(); if (conf_file) if (load_config(conf_file) == -1) exit(1); /* * Default action is to only open the filter log file. */ if ((fdt[0] == -1) && (fdt[1] == -1) && (fdt[2] == -1)) fdt[0] = IPL_LOGIPF; for (i = 0; i < 3; i++) { if (fdt[i] == -1) continue; if (!strcmp(iplfile[i], "-")) fd[i] = 0; else { if ((fd[i] = open(iplfile[i], O_RDONLY)) == -1) { (void) fprintf(stderr, "%s: open: %s\n", iplfile[i], STRERROR(errno)); exit(1); /* NOTREACHED */ } if (fstat(fd[i], &sb) == -1) { (void) fprintf(stderr, "%d: fstat: %s\n", fd[i], STRERROR(errno)); exit(1); /* NOTREACHED */ } if (setzone(fd[i]) != 0) { close(fd[i]); exit(1); } if (!(regular[i] = !S_ISCHR(sb.st_mode))) devices++; } } if (!(opts & OPT_SYSLOG)) { logfile = argv[optind]; log = logfile ? fopen(logfile, "a") : stdout; if (log == NULL) { (void) fprintf(stderr, "%s: fopen: %s\n", argv[optind], STRERROR(errno)); exit(1); /* NOTREACHED */ } setvbuf(log, NULL, _IONBF, 0); } else log = NULL; if (make_daemon && ((log != stdout) || (opts & OPT_SYSLOG))) { #if BSD >= 199306 daemon(0, !(opts & OPT_SYSLOG)); #else int pid; if ((pid = fork()) > 0) exit(0); if (pid < 0) { (void) fprintf(stderr, "%s: fork() failed: %s\n", argv[0], STRERROR(errno)); exit(1); /* NOTREACHED */ } setsid(); if ((opts & OPT_SYSLOG)) close(2); #endif /* !BSD */ close(0); close(1); } write_pid(pidfile); signal(SIGHUP, handlehup); for (doread = 1; doread; ) { nr = 0; for (i = 0; i < 3; i++) { tr = 0; if (fdt[i] == -1) continue; if (!regular[i]) { if (ioctl(fd[i], FIONREAD, &tr) == -1) { if (opts & OPT_SYSLOG) syslog(LOG_CRIT, "ioctl(FIONREAD): %m"); else perror("ioctl(FIONREAD)"); exit(1); /* NOTREACHED */ } } else { tr = (lseek(fd[i], 0, SEEK_CUR) < sb.st_size); if (!tr && !(opts & OPT_TAIL)) doread = 0; } if (!tr) continue; nr += tr; tr = read_log(fd[i], &n, buf, sizeof(buf)); if (donehup) { if (logfile && (fp = fopen(logfile, "a"))) { fclose(log); log = fp; } if (binarylogfile && (fp = fopen(binarylogfile, "a"))) { fclose(binarylog); binarylog = fp; } init_tabs(); if (conf_file != NULL) load_config(conf_file); donehup = 0; } switch (tr) { case -1 : if (opts & OPT_SYSLOG) syslog(LOG_CRIT, "read: %m\n"); else perror("read"); doread = 0; break; case 1 : if (opts & OPT_SYSLOG) syslog(LOG_CRIT, "aborting logging\n"); else fprintf(log, "aborting logging\n"); doread = 0; break; case 2 : break; case 0 : if (n > 0) { print_log(fdt[i], log, buf, n); if (!(opts & OPT_SYSLOG)) fflush(log); } break; } } if (!nr && ((opts & OPT_TAIL) || devices)) sleep(1); } return(0); /* NOTREACHED */ } /* * Copyright (C) 1993-2005 by Darren Reed. * See the IPFILTER.LICENCE file for details on licencing. */ %{ #include "ipf.h" #include #undef OPT_NAT #undef OPT_VERBOSE #include "ipmon_l.h" #include "ipmon.h" #define YYDEBUG 1 extern int yyerror __P((const char *)); extern int yyparse __P((void)); extern int yylex __P((void)); extern int yydebug; extern FILE *yyin; extern int yylineNum; typedef struct opt { struct opt *o_next; int o_line; int o_type; int o_num; char *o_str; struct in_addr o_ip; } opt_t; static void build_action __P((struct opt *)); static opt_t *new_opt __P((int)); static void free_action __P((ipmon_action_t *)); static ipmon_action_t *alist = NULL; %} %union { char *str; u_32_t num; struct in_addr addr; struct opt *opt; union i6addr ip6; } %token YY_NUMBER YY_HEX %token YY_STR %token YY_IPV6 %token YY_COMMENT %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT %token YY_RANGE_OUT YY_RANGE_IN %token IPM_MATCH IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT %token IPM_EVERY IPM_EXECUTE IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT %token IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE %token IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_LOGTAG IPM_WITH %token IPM_DO IPM_SAVE IPM_SYSLOG IPM_NOTHING IPM_RAW IPM_TYPE IPM_NAT %token IPM_STATE IPM_NATTAG IPM_IPF %type ipv4 %type direction dstip dstport every execute group interface %type protocol result rule srcip srcport logtag matching %type matchopt nattag type doopt doing save syslog nothing %type saveopts saveopt typeopt %% file: line | assign | file line | file assign ; line: IPM_MATCH '{' matching '}' IPM_DO '{' doing '}' ';' { build_action($3); resetlexer(); } | IPM_COMMENT | YY_COMMENT ; assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); resetlexer(); free($1); free($3); } ; assigning: '=' { yyvarnext = 1; } ; matching: matchopt { $$ = $1; } | matchopt ',' matching { $1->o_next = $3; $$ = $1; } ; matchopt: direction { $$ = $1; } | dstip { $$ = $1; } | dstport { $$ = $1; } | every { $$ = $1; } | group { $$ = $1; } | interface { $$ = $1; } | protocol { $$ = $1; } | result { $$ = $1; } | rule { $$ = $1; } | srcip { $$ = $1; } | srcport { $$ = $1; } | logtag { $$ = $1; } | nattag { $$ = $1; } | type { $$ = $1; } ; doing: doopt { $$ = $1; } | doopt ',' doing { $1->o_next = $3; $$ = $1; } ; doopt: execute { $$ = $1; } | save { $$ = $1; } | syslog { $$ = $1; } | nothing { $$ = $1; } ; direction: IPM_DIRECTION '=' IPM_IN { $$ = new_opt(IPM_DIRECTION); $$->o_num = IPM_IN; } | IPM_DIRECTION '=' IPM_OUT { $$ = new_opt(IPM_DIRECTION); $$->o_num = IPM_OUT; } ; dstip: IPM_DSTIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_DSTIP); $$->o_ip = $3; $$->o_num = $5; } ; dstport: IPM_DSTPORT '=' YY_NUMBER { $$ = new_opt(IPM_DSTPORT); $$->o_num = $3; } | IPM_DSTPORT '=' YY_STR { $$ = new_opt(IPM_DSTPORT); $$->o_str = $3; } ; every: IPM_EVERY IPM_SECOND { $$ = new_opt(IPM_SECOND); $$->o_num = 1; } | IPM_EVERY YY_NUMBER IPM_SECONDS { $$ = new_opt(IPM_SECOND); $$->o_num = $2; } | IPM_EVERY IPM_PACKET { $$ = new_opt(IPM_PACKET); $$->o_num = 1; } | IPM_EVERY YY_NUMBER IPM_PACKETS { $$ = new_opt(IPM_PACKET); $$->o_num = $2; } ; group: IPM_GROUP '=' YY_NUMBER { $$ = new_opt(IPM_GROUP); $$->o_num = $3; } | IPM_GROUP '=' YY_STR { $$ = new_opt(IPM_GROUP); $$->o_str = $3; } ; interface: IPM_INTERFACE '=' YY_STR { $$ = new_opt(IPM_INTERFACE); $$->o_str = $3; } ; logtag: IPM_LOGTAG '=' YY_NUMBER { $$ = new_opt(IPM_LOGTAG); $$->o_num = $3; } ; nattag: IPM_NATTAG '=' YY_STR { $$ = new_opt(IPM_NATTAG); $$->o_str = $3; } ; protocol: IPM_PROTOCOL '=' YY_NUMBER { $$ = new_opt(IPM_PROTOCOL); $$->o_num = $3; } | IPM_PROTOCOL '=' YY_STR { $$ = new_opt(IPM_PROTOCOL); $$->o_num = getproto($3); free($3); } ; result: IPM_RESULT '=' YY_STR { $$ = new_opt(IPM_RESULT); $$->o_str = $3; } ; rule: IPM_RULE '=' YY_NUMBER { $$ = new_opt(IPM_RULE); $$->o_num = YY_NUMBER; } ; srcip: IPM_SRCIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_SRCIP); $$->o_ip = $3; $$->o_num = $5; } ; srcport: IPM_SRCPORT '=' YY_NUMBER { $$ = new_opt(IPM_SRCPORT); $$->o_num = $3; } | IPM_SRCPORT '=' YY_STR { $$ = new_opt(IPM_SRCPORT); $$->o_str = $3; } ; type: IPM_TYPE '=' typeopt { $$ = new_opt(IPM_TYPE); $$->o_num = $3; } ; typeopt: IPM_IPF { $$ = IPL_MAGIC; } | IPM_NAT { $$ = IPL_MAGIC_NAT; } | IPM_STATE { $$ = IPL_MAGIC_STATE; } ; execute: IPM_EXECUTE YY_STR { $$ = new_opt(IPM_EXECUTE); $$->o_str = $2; } ; save: IPM_SAVE saveopts YY_STR { $$ = new_opt(IPM_SAVE); $$->o_num = $2; $$->o_str = $3; } ; saveopts: { $$ = 0; } | saveopt { $$ = $1; } | saveopt ',' saveopts { $$ = $1 | $3; } ; saveopt: IPM_RAW { $$ = IPMDO_SAVERAW; } ; syslog: IPM_SYSLOG { $$ = new_opt(IPM_SYSLOG); } ; nothing: IPM_NOTHING { $$ = 0; } ; ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { yyerror("Invalid octet string for IP address"); return 0; } $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; $$.s_addr = htonl($$.s_addr); } %% static struct wordtab yywords[] = { { "body", IPM_BODY }, { "direction", IPM_DIRECTION }, { "do", IPM_DO }, { "dstip", IPM_DSTIP }, { "dstport", IPM_DSTPORT }, { "every", IPM_EVERY }, { "execute", IPM_EXECUTE }, { "group", IPM_GROUP }, { "in", IPM_IN }, { "interface", IPM_INTERFACE }, { "ipf", IPM_IPF }, { "logtag", IPM_LOGTAG }, { "match", IPM_MATCH }, { "nat", IPM_NAT }, { "nattag", IPM_NATTAG }, { "no", IPM_NO }, { "nothing", IPM_NOTHING }, { "out", IPM_OUT }, { "packet", IPM_PACKET }, { "packets", IPM_PACKETS }, { "protocol", IPM_PROTOCOL }, { "result", IPM_RESULT }, { "rule", IPM_RULE }, { "save", IPM_SAVE }, { "raw", IPM_RAW }, { "second", IPM_SECOND }, { "seconds", IPM_SECONDS }, { "srcip", IPM_SRCIP }, { "srcport", IPM_SRCPORT }, { "state", IPM_STATE }, { "syslog", IPM_SYSLOG }, { "with", IPM_WITH }, { NULL, 0 } }; static int macflags[17][2] = { { IPM_DIRECTION, IPMAC_DIRECTION }, { IPM_DSTIP, IPMAC_DSTIP }, { IPM_DSTPORT, IPMAC_DSTPORT }, { IPM_GROUP, IPMAC_GROUP }, { IPM_INTERFACE, IPMAC_INTERFACE }, { IPM_LOGTAG, IPMAC_LOGTAG }, { IPM_NATTAG, IPMAC_NATTAG }, { IPM_PACKET, IPMAC_EVERY }, { IPM_PROTOCOL, IPMAC_PROTOCOL }, { IPM_RESULT, IPMAC_RESULT }, { IPM_RULE, IPMAC_RULE }, { IPM_SECOND, IPMAC_EVERY }, { IPM_SRCIP, IPMAC_SRCIP }, { IPM_SRCPORT, IPMAC_SRCPORT }, { IPM_TYPE, IPMAC_TYPE }, { IPM_WITH, IPMAC_WITH }, { 0, 0 } }; static opt_t *new_opt(type) int type; { opt_t *o; o = (opt_t *)malloc(sizeof(*o)); if (o == NULL) yyerror("sorry, out of memory"); o->o_type = type; o->o_line = yylineNum; o->o_num = 0; o->o_str = (char *)0; o->o_next = NULL; return o; } static void build_action(olist) opt_t *olist; { ipmon_action_t *a; opt_t *o; char c; int i; a = (ipmon_action_t *)calloc(1, sizeof(*a)); if (a == NULL) return; while ((o = olist) != NULL) { /* * Check to see if the same comparator is being used more than * once per matching statement. */ for (i = 0; macflags[i][0]; i++) if (macflags[i][0] == o->o_type) break; if (macflags[i][1] & a->ac_mflag) { fprintf(stderr, "%s redfined on line %d\n", yykeytostr(o->o_type), yylineNum); if (o->o_str != NULL) free(o->o_str); olist = o->o_next; free(o); continue; } a->ac_mflag |= macflags[i][1]; switch (o->o_type) { case IPM_DIRECTION : a->ac_direction = o->o_num; break; case IPM_DSTIP : a->ac_dip = o->o_ip.s_addr; a->ac_dmsk = htonl(0xffffffff << (32 - o->o_num)); break; case IPM_DSTPORT : a->ac_dport = htons(o->o_num); break; case IPM_EXECUTE : a->ac_exec = o->o_str; c = *o->o_str; if (c== '"'|| c == '\'') { if (o->o_str[strlen(o->o_str) - 1] == c) { a->ac_run = strdup(o->o_str + 1); a->ac_run[strlen(a->ac_run) - 1] ='\0'; } else a->ac_run = o->o_str; } else a->ac_run = o->o_str; o->o_str = NULL; break; case IPM_INTERFACE : a->ac_iface = o->o_str; o->o_str = NULL; break; case IPM_GROUP : if (o->o_str != NULL) strncpy(a->ac_group, o->o_str, FR_GROUPLEN); else sprintf(a->ac_group, "%d", o->o_num); break; case IPM_LOGTAG : a->ac_logtag = o->o_num; break; case IPM_NATTAG : strncpy(a->ac_nattag, o->o_str, sizeof(a->ac_nattag)); break; case IPM_PACKET : a->ac_packet = o->o_num; break; case IPM_PROTOCOL : a->ac_proto = o->o_num; break; case IPM_RULE : a->ac_rule = o->o_num; break; case IPM_RESULT : if (!strcasecmp(o->o_str, "pass")) a->ac_result = IPMR_PASS; else if (!strcasecmp(o->o_str, "block")) a->ac_result = IPMR_BLOCK; else if (!strcasecmp(o->o_str, "nomatch")) a->ac_result = IPMR_NOMATCH; else if (!strcasecmp(o->o_str, "log")) a->ac_result = IPMR_LOG; break; case IPM_SECOND : a->ac_second = o->o_num; break; case IPM_SRCIP : a->ac_sip = o->o_ip.s_addr; a->ac_smsk = htonl(0xffffffff << (32 - o->o_num)); break; case IPM_SRCPORT : a->ac_sport = htons(o->o_num); break; case IPM_SAVE : if (a->ac_savefile != NULL) { fprintf(stderr, "%s redfined on line %d\n", yykeytostr(o->o_type), yylineNum); break; } a->ac_savefile = strdup(o->o_str); a->ac_savefp = fopen(o->o_str, "a"); a->ac_dflag |= o->o_num & IPMDO_SAVERAW; break; case IPM_SYSLOG : if (a->ac_syslog != 0) { fprintf(stderr, "%s redfined on line %d\n", yykeytostr(o->o_type), yylineNum); break; } a->ac_syslog = 1; break; case IPM_TYPE : a->ac_type = o->o_num; break; case IPM_WITH : break; default : break; } olist = o->o_next; if (o->o_str != NULL) free(o->o_str); free(o); } a->ac_next = alist; alist = a; } int check_action(buf, log, opts, lvl) char *buf, *log; int opts, lvl; { ipmon_action_t *a; struct timeval tv; ipflog_t *ipf; tcphdr_t *tcp; iplog_t *ipl; int matched; u_long t1; ip_t *ip; matched = 0; ipl = (iplog_t *)buf; ipf = (ipflog_t *)(ipl +1); ip = (ip_t *)(ipf + 1); tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2)); for (a = alist; a != NULL; a = a->ac_next) { if ((a->ac_mflag & IPMAC_DIRECTION) != 0) { if (a->ac_direction == IPM_IN) { if ((ipf->fl_flags & FR_INQUE) == 0) continue; } else if (a->ac_direction == IPM_OUT) { if ((ipf->fl_flags & FR_OUTQUE) == 0) continue; } } if ((a->ac_type != 0) && (a->ac_type != ipl->ipl_magic)) continue; if ((a->ac_mflag & IPMAC_EVERY) != 0) { gettimeofday(&tv, NULL); t1 = tv.tv_sec - a->ac_lastsec; if (tv.tv_usec <= a->ac_lastusec) t1--; if (a->ac_second != 0) { if (t1 < a->ac_second) continue; a->ac_lastsec = tv.tv_sec; a->ac_lastusec = tv.tv_usec; } if (a->ac_packet != 0) { if (a->ac_pktcnt == 0) a->ac_pktcnt++; else if (a->ac_pktcnt == a->ac_packet) { a->ac_pktcnt = 0; continue; } else { a->ac_pktcnt++; continue; } } } if ((a->ac_mflag & IPMAC_DSTIP) != 0) { if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip) continue; } if ((a->ac_mflag & IPMAC_DSTPORT) != 0) { if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP) continue; if (tcp->th_dport != a->ac_dport) continue; } if ((a->ac_mflag & IPMAC_GROUP) != 0) { if (strncmp(a->ac_group, ipf->fl_group, FR_GROUPLEN) != 0) continue; } if ((a->ac_mflag & IPMAC_INTERFACE) != 0) { if (strcmp(a->ac_iface, ipf->fl_ifname)) continue; } if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) { if (a->ac_proto != ip->ip_p) continue; } if ((a->ac_mflag & IPMAC_RESULT) != 0) { if ((ipf->fl_flags & FF_LOGNOMATCH) != 0) { if (a->ac_result != IPMR_NOMATCH) continue; } else if (FR_ISPASS(ipf->fl_flags)) { if (a->ac_result != IPMR_PASS) continue; } else if (FR_ISBLOCK(ipf->fl_flags)) { if (a->ac_result != IPMR_BLOCK) continue; } else { /* Log only */ if (a->ac_result != IPMR_LOG) continue; } } if ((a->ac_mflag & IPMAC_RULE) != 0) { if (a->ac_rule != ipf->fl_rule) continue; } if ((a->ac_mflag & IPMAC_SRCIP) != 0) { if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip) continue; } if ((a->ac_mflag & IPMAC_SRCPORT) != 0) { if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP) continue; if (tcp->th_sport != a->ac_sport) continue; } if ((a->ac_mflag & IPMAC_LOGTAG) != 0) { if (a->ac_logtag != ipf->fl_logtag) continue; } if ((a->ac_mflag & IPMAC_NATTAG) != 0) { if (strncmp(a->ac_nattag, ipf->fl_nattag.ipt_tag, IPFTAG_LEN) != 0) continue; } matched = 1; /* * It matched so now execute the command */ if (a->ac_syslog != 0) { syslog(lvl, "%s", log); } if (a->ac_savefp != NULL) { if (a->ac_dflag & IPMDO_SAVERAW) fwrite(ipl, 1, ipl->ipl_dsize, a->ac_savefp); else fputs(log, a->ac_savefp); } if (a->ac_exec != NULL) { switch (fork()) { case 0 : { FILE *pi; pi = popen(a->ac_run, "w"); if (pi != NULL) { fprintf(pi, "%s\n", log); if ((opts & OPT_HEXHDR) != 0) { dumphex(pi, 0, buf, sizeof(*ipl) + sizeof(*ipf)); } if ((opts & OPT_HEXBODY) != 0) { dumphex(pi, 0, (char *)ip, ipf->fl_hlen + ipf->fl_plen); } pclose(pi); } exit(1); } case -1 : break; default : break; } } } return matched; } static void free_action(a) ipmon_action_t *a; { if (a->ac_savefile != NULL) { free(a->ac_savefile); a->ac_savefile = NULL; } if (a->ac_savefp != NULL) { fclose(a->ac_savefp); a->ac_savefp = NULL; } if (a->ac_exec != NULL) { free(a->ac_exec); if (a->ac_run == a->ac_exec) a->ac_run = NULL; a->ac_exec = NULL; } if (a->ac_run != NULL) { free(a->ac_run); a->ac_run = NULL; } if (a->ac_iface != NULL) { free(a->ac_iface); a->ac_iface = NULL; } a->ac_next = NULL; free(a); } int load_config(file) char *file; { ipmon_action_t *a; FILE *fp; char *s; s = getenv("YYDEBUG"); if (s != NULL) yydebug = atoi(s); else yydebug = 0; while ((a = alist) != NULL) { alist = a->ac_next; free_action(a); } yylineNum = 1; (void) yysettab(yywords); fp = fopen(file, "r"); if (!fp) { perror("load_config:fopen:"); return -1; } yyin = fp; while (!feof(fp)) yyparse(); fclose(fp); return 0; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #include #include #include #include #include #if !defined(__SVR4) && !defined(__svr4__) #include #else #include #endif #include #include #include #include #include #include #define _KERNEL #include #undef _KERNEL #include #include #if defined(sun) && (defined(__svr4__) || defined(__SVR4)) #include #include #endif #include #include #include #include #include #if __FreeBSD_version >= 300000 #include #endif #include #include #include #include #include #if defined(linux) #include #else #include #endif #include "ipf.h" #include "netinet/ipl.h" #include "kmem.h" #include "ipfzone.h" #ifdef __hpux #define nlist nlist64 #endif #if defined(sun) && !SOLARIS2 #define STRERROR(x) sys_errlist[x] extern char *sys_errlist[]; #else #define STRERROR(x) strerror(x) #endif int use_inet6 = 0; extern char thishost[MAXHOSTNAMELEN]; extern char *optarg; void dostats __P((int, natstat_t *, int, int)); void flushtable __P((int, int)); void usage __P((char *)); int main __P((int, char *[])); void showhostmap __P((natstat_t *nsp)); void natstat_dead __P((natstat_t *, char *)); void dostats_live __P((int, natstat_t *, int)); void showhostmap_live __P((int, natstat_t *)); int opts; void usage(char *name) { fprintf(stderr, "Usage: %s [-CdFhlnrRsv] [-f filename]", name); fprintf(stderr, " [-G|-z zonename]\n"); exit(1); } int main(int argc, char *argv[]) { char *file, *core, *kernel; natstat_t ns, *nsp; int fd, c, mode; ipfobj_t obj; fd = -1; opts = 0; nsp = &ns; file = NULL; core = NULL; kernel = NULL; mode = O_RDWR; while ((c = getopt(argc, argv, "CdFf:G:hlM:N:nrRsvz:")) != -1) switch (c) { case 'C' : opts |= OPT_CLEAR; break; case 'd' : opts |= OPT_DEBUG; break; case 'f' : file = optarg; break; case 'F' : opts |= OPT_FLUSH; break; case 'G' : setzonename_global(optarg); break; case 'h' : opts |= OPT_HITS; break; case 'l' : opts |= OPT_LIST; mode = O_RDONLY; break; case 'M' : core = optarg; break; case 'N' : kernel = optarg; break; case 'n' : opts |= OPT_DONOTHING; mode = O_RDONLY; break; case 'R' : opts |= OPT_NORESOLVE; break; case 'r' : opts |= OPT_REMOVE; break; case 's' : opts |= OPT_STAT; mode = O_RDONLY; break; case 'v' : opts |= OPT_VERBOSE; break; case 'z' : setzonename(optarg); break; default : usage(argv[0]); } initparse(); if ((kernel != NULL) || (core != NULL)) { (void) setgid(getgid()); (void) setreuid(getuid(), getuid()); } bzero((char *)&ns, sizeof (ns)); if ((opts & OPT_DONOTHING) == 0) { if (checkrev(IPL_NAME) == -1) { fprintf(stderr, "User/kernel version check failed\n"); exit(1); } } if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) { #ifdef notdef if (openkmem(kernel, core) == -1) exit(1); #endif if (((fd = open(IPNAT_NAME, mode)) == -1) && ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) { (void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME, STRERROR(errno)); exit(1); } if (setzone(fd) != 0) { close(fd); exit(1); } bzero((char *)&obj, sizeof (obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_size = sizeof (*nsp); obj.ipfo_type = IPFOBJ_NATSTAT; obj.ipfo_ptr = (void *)nsp; if (ioctl(fd, SIOCGNATS, &obj) == -1) { perror("ioctl(SIOCGNATS)"); exit(1); } (void) setgid(getgid()); (void) setreuid(getuid(), getuid()); } else if ((kernel != NULL) || (core != NULL)) { if (openkmem(kernel, core) == -1) exit(1); natstat_dead(nsp, kernel); if (opts & (OPT_LIST|OPT_STAT)) dostats(fd, nsp, opts, 0); exit(0); } if (opts & (OPT_FLUSH|OPT_CLEAR)) flushtable(fd, opts); if (file) { ipnat_parsefile(fd, ipnat_addrule, ioctl, file); } if (opts & (OPT_LIST|OPT_STAT)) dostats(fd, nsp, opts, 1); return (0); } /* * Read NAT statistic information in using a symbol table and memory file * rather than doing ioctl's. */ void natstat_dead(natstat_t *nsp, char *kernel) { struct nlist nat_nlist[10] = { { "nat_table" }, /* 0 */ { "nat_list" }, { "maptable" }, { "ipf_nattable_sz" }, { "ipf_natrules_sz" }, { "ipf_rdrrules_sz" }, /* 5 */ { "ipf_hostmap_sz" }, { "nat_instances" }, { "ap_sess_list" }, { NULL } }; void *tables[2]; if (nlist(kernel, nat_nlist) == -1) { fprintf(stderr, "nlist error\n"); return; } /* * Normally the ioctl copies all of these values into the structure * for us, before returning it to userland, so here we must copy each * one in individually. */ kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof (tables)); nsp->ns_table[0] = tables[0]; nsp->ns_table[1] = tables[1]; kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value, sizeof (nsp->ns_list)); kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value, sizeof (nsp->ns_maptable)); kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value, sizeof (nsp->ns_nattab_sz)); kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value, sizeof (nsp->ns_rultab_sz)); kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value, sizeof (nsp->ns_rdrtab_sz)); kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value, sizeof (nsp->ns_hostmap_sz)); kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value, sizeof (nsp->ns_instances)); kmemcpy((char *)&nsp->ns_apslist, nat_nlist[8].n_value, sizeof (nsp->ns_apslist)); } /* * Display NAT statistics. */ void dostats(int fd, natstat_t *nsp, int opts, int alive) { nat_t *np, nat; ipnat_t ipn; /* * Show statistics ? */ if (opts & OPT_STAT) { printf("mapped\tin\t%lu\tout\t%lu\n", nsp->ns_mapped[0], nsp->ns_mapped[1]); printf("added\t%lu\texpired\t%lu\n", nsp->ns_added, nsp->ns_expire); printf("no memory\t%lu\tbad nat\t%lu\n", nsp->ns_memfail, nsp->ns_badnat); printf("inuse\t%lu\norphans\t%u\nrules\t%lu\n", nsp->ns_inuse, nsp->ns_orphans, nsp->ns_rules); printf("wilds\t%u\n", nsp->ns_wilds); if (opts & OPT_VERBOSE) printf("table %p list %p\n", nsp->ns_table, nsp->ns_list); } /* * Show list of NAT rules and NAT sessions ? */ if (opts & OPT_LIST) { if (alive) { dostats_live(fd, nsp, opts); return; } printf("List of active MAP/Redirect filters:\n"); while (nsp->ns_list) { if (kmemcpy((char *)&ipn, (long)nsp->ns_list, sizeof (ipn))) { perror("kmemcpy"); break; } if (opts & OPT_HITS) printf("%lu ", ipn.in_hits); printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); nsp->ns_list = ipn.in_next; } printf("\nList of active sessions:\n"); for (np = nsp->ns_instances; np; np = nat.nat_next) { if (kmemcpy((char *)&nat, (long)np, sizeof (nat))) break; printactivenat(&nat, opts, 0); if (nat.nat_aps) printaps(nat.nat_aps, opts); } if (opts & OPT_VERBOSE) showhostmap(nsp); } } /* * Display the active host mapping table. */ void showhostmap(natstat_t *nsp) { hostmap_t hm, *hmp, **maptable; uint_t hv; printf("\nList of active host mappings:\n"); maptable = (hostmap_t **)malloc(sizeof (hostmap_t *) * nsp->ns_hostmap_sz); if (maptable == NULL) { perror("malloc"); exit(1); } if (kmemcpy((char *)maptable, (ulong_t)nsp->ns_maptable, sizeof (hostmap_t *) * nsp->ns_hostmap_sz)) { perror("kmemcpy (maptable)"); return; } for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) { hmp = maptable[hv]; while (hmp) { if (kmemcpy((char *)&hm, (ulong_t)hmp, sizeof (hm))) { perror("kmemcpy (hostmap)"); return; } printhostmap(&hm, hv); hmp = hm.hm_next; } } free(maptable); } /* * Issue an ioctl to flush either the NAT rules table or the active mapping * table or both. */ void flushtable(int fd, int opts) { int n = 0; if (opts & OPT_FLUSH) { n = FLUSH_TABLE_ALL; if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) perror("ioctl(SIOCFLNAT)"); else printf("%d entries flushed from NAT table\n", n); } if (opts & OPT_CLEAR) { n = FLUSH_LIST; if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) perror("ioctl(SIOCCNATL)"); else printf("%d entries flushed from NAT list\n", n); } } /* * Display NAT statistics. */ void dostats_live(int fd, natstat_t *nsp, int opts) { ipfgeniter_t iter; ipfobj_t obj; ipnat_t ipn; nat_t nat; bzero((char *)&obj, sizeof (obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_GENITER; obj.ipfo_size = sizeof (iter); obj.ipfo_ptr = &iter; iter.igi_type = IPFGENITER_IPNAT; iter.igi_nitems = 1; iter.igi_data = &ipn; /* * Show list of NAT rules and NAT sessions ? */ printf("List of active MAP/Redirect filters:\n"); while (nsp->ns_list) { if (ioctl(fd, SIOCGENITER, &obj) == -1) break; if (opts & OPT_HITS) printf("%lu ", ipn.in_hits); printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); nsp->ns_list = ipn.in_next; } printf("\nList of active sessions:\n"); iter.igi_type = IPFGENITER_NAT; iter.igi_nitems = 1; iter.igi_data = &nat; while (nsp->ns_instances != NULL) { if (ioctl(fd, SIOCGENITER, &obj) == -1) break; printactivenat(&nat, opts, 1); if (nat.nat_aps) printaps(nat.nat_aps, opts); nsp->ns_instances = nat.nat_next; } if (opts & OPT_VERBOSE) showhostmap_live(fd, nsp); } /* * Display the active host mapping table. */ void showhostmap_live(int fd, natstat_t *nsp) { hostmap_t hm, *hmp; ipfgeniter_t iter; ipfobj_t obj; bzero((char *)&obj, sizeof (obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_GENITER; obj.ipfo_size = sizeof (iter); obj.ipfo_ptr = &iter; iter.igi_type = IPFGENITER_HOSTMAP; iter.igi_nitems = 1; iter.igi_data = &hm; printf("\nList of active host mappings:\n"); while (nsp->ns_maplist != NULL) { if (ioctl(fd, SIOCGENITER, &obj) == -1) break; printhostmap(&hm, 0); nsp->ns_maplist = hm.hm_next; } } %{ /* * Copyright (C) 2001-2008 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifdef __FreeBSD__ # ifndef __FreeBSD_cc_version # include # else # if __FreeBSD_cc_version < 430000 # include # endif # endif #endif #include #include #include #include #include #if !defined(__SVR4) && !defined(__GNUC__) #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #if __FreeBSD_version >= 300000 # include #endif #include #include #include #include "ipf.h" #include "netinet/ipl.h" #include "ipnat_l.h" #define YYDEBUG 1 extern int yyerror __P((const char *)); extern int yyparse __P((void)); extern int yylex __P((void)); extern int yydebug; extern FILE *yyin; extern int yylineNum; static ipnat_t *nattop = NULL; static ipnat_t *nat = NULL; static int natfd = -1; static ioctlfunc_t natioctlfunc = NULL; static addfunc_t nataddfunc = NULL; static void newnatrule __P((void)); static void setnatproto __P((int)); %} %union { char *str; u_32_t num; struct { i6addr_t a; int v; } ipa; frentry_t fr; frtuc_t *frt; u_short port; struct { u_short p1; u_short p2; int pc; } pc; struct { i6addr_t a; i6addr_t m; int v; } ipp; union i6addr ip6; }; %token YY_NUMBER YY_HEX %token YY_STR %token YY_COMMENT %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT %token YY_RANGE_OUT YY_RANGE_IN %token YY_IPV6 %token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE %token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY %token IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY %token IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG %token IPNY_TLATE IPNY_SEQUENTIAL %type portspec %type hexnumber compare range proto %type saddr daddr sobject dobject mapfrom rdrfrom dip %type hostname ipv4 ipaddr %type addr rhaddr %type portstuff %% file: line | assign | file line | file assign ; line: xx rule { while ((nat = nattop) != NULL) { if (nat->in_v == 0) nat->in_v = 4; nattop = nat->in_next; (*nataddfunc)(natfd, natioctlfunc, nat); free(nat); } resetlexer(); } | YY_COMMENT ; assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); resetlexer(); free($1); free($3); } ; assigning: '=' { yyvarnext = 1; } ; xx: { newnatrule(); } ; rule: map eol | mapblock eol | redir eol ; eol: | ';' ; map: mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions { if ($3.v != 0 && $3.v != $5.v && $5.v != 0) yyerror("1.address family mismatch"); bcopy(&$3.a, &nat->in_in[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_in[1], sizeof($3.a)); bcopy(&$5.a, &nat->in_out[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_out[1], sizeof($5.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); if ((nat->in_flags & IPN_TCPUDP) == 0) setnatproto(nat->in_p); if (((nat->in_redir & NAT_MAPBLK) != 0) || ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) nat_setgroupmap(nat); } | mapit ifnames addr IPNY_TLATE rhaddr mapport mapoptions { if ($3.v != 0 && $3.v != $5.v && $5.v != 0) yyerror("2.address family mismatch"); bcopy(&$3.a, &nat->in_in[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_in[1], sizeof($3.a)); bcopy(&$5.a, &nat->in_out[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_out[1], sizeof($5.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); if ((nat->in_flags & IPN_TCPUDPICMPQ) == 0) setnatproto(nat->in_p); if (((nat->in_redir & NAT_MAPBLK) != 0) || ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) nat_setgroupmap(nat); } | mapit ifnames mapfrom IPNY_TLATE rhaddr proxy mapoptions { if ($3 != 0 && $3 != $5.v && $5.v != 0) yyerror("3.address family mismatch"); bcopy(&$5.a, &nat->in_out[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_out[1], sizeof($5.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); if ((nat->in_flags & IPN_TCPUDP) == 0) setnatproto(nat->in_p); if (((nat->in_redir & NAT_MAPBLK) != 0) || ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) nat_setgroupmap(nat); } | mapit ifnames mapfrom IPNY_TLATE rhaddr mapport mapoptions { if ($3 != 0 && $3 != $5.v && $5.v != 0) yyerror("4.address family mismatch"); bcopy(&$5.a, &nat->in_out[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_out[1], sizeof($5.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); if ((nat->in_flags & IPN_TCPUDPICMPQ) == 0) setnatproto(nat->in_p); if (((nat->in_redir & NAT_MAPBLK) != 0) || ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) nat_setgroupmap(nat); } ; mapblock: mapblockit ifnames addr IPNY_TLATE addr ports mapoptions { if ($3.v != 0 && $3.v != $5.v && $5.v != 0) yyerror("5.address family mismatch"); bcopy(&$3.a, &nat->in_in[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_in[1], sizeof($3.a)); bcopy(&$5.a, &nat->in_out[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_out[1], sizeof($5.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); if ((nat->in_flags & IPN_TCPUDP) == 0) setnatproto(nat->in_p); if (((nat->in_redir & NAT_MAPBLK) != 0) || ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) nat_setgroupmap(nat); } ; redir: rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions { if ($6 != 0 && $3.v != 0 && $6 != $3.v) yyerror("6.address family mismatch"); bcopy(&$3.a, &nat->in_out[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_out[1], sizeof($3.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); if ((nat->in_p == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) && (nat->in_pmin != 0 || nat->in_pmax != 0 || nat->in_pnext != 0)) setnatproto(IPPROTO_TCP); } | rdrit ifnames rdrfrom IPNY_TLATE dip nport setproto rdroptions { if ($5 != 0 && $3 != 0 && $5 != $3) yyerror("7.address family mismatch"); if ((nat->in_p == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) && (nat->in_pmin != 0 || nat->in_pmax != 0 || nat->in_pnext != 0)) setnatproto(IPPROTO_TCP); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); } | rdrit ifnames addr IPNY_TLATE dip setproto rdroptions { if ($5 != 0 && $3.v != 0 && $5 != $3.v) yyerror("8.address family mismatch"); bcopy(&$3.a, &nat->in_out[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_out[1], sizeof($3.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); } ; proxy: | IPNY_PROXY IPNY_PORT portspec YY_STR '/' proto { strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel)); if (nat->in_dcmp == 0) { nat->in_dport = htons($3); } else if ($3 != nat->in_dport) { yyerror("proxy port numbers not consistant"); } setnatproto($6); free($4); } | IPNY_PROXY IPNY_PORT YY_STR YY_STR '/' proto { int pnum; strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel)); pnum = getportproto($3, $6); if (pnum == -1) yyerror("invalid port number"); nat->in_dport = pnum; setnatproto($6); free($3); free($4); } ; setproto: | proto { if (nat->in_p != 0 || nat->in_flags & IPN_TCPUDP) yyerror("protocol set twice"); setnatproto($1); } | IPNY_TCPUDP { if (nat->in_p != 0 || nat->in_flags & IPN_TCPUDP) yyerror("protocol set twice"); nat->in_flags |= IPN_TCPUDP; nat->in_p = 0; } | IPNY_TCP '/' IPNY_UDP { if (nat->in_p != 0 || nat->in_flags & IPN_TCPUDP) yyerror("protocol set twice"); nat->in_flags |= IPN_TCPUDP; nat->in_p = 0; } ; rhaddr: addr { $$.a = $1.a; $$.m = $1.m; $$.v = $1.v; if ($$.v == 0) $$.v = nat->in_v; yyexpectaddr = 0; } | IPNY_RANGE hostname '-' hostname { if ($2.v != 0 && $4.v != 0 && $4.v != $2.v) yyerror("9.address family " "mismatch"); $$.v = $2.v; $$.a = $2.a; $$.m = $4.a; nat->in_flags |= IPN_IPRANGE; yyexpectaddr = 0; } ; dip: hostname { bcopy(&$1.a, &nat->in_in[0], sizeof($1.a)); if ($1.v == 0) $1.v = nat->in_v; if ($1.v == 4) { nat->in_inmsk = 0xffffffff; } else { nat->in_in[1].i6[0] = 0xffffffff; nat->in_in[1].i6[1] = 0xffffffff; nat->in_in[1].i6[2] = 0xffffffff; nat->in_in[1].i6[3] = 0xffffffff; } $$ = $1.v; } | hostname '/' YY_NUMBER { if ($1.v == 0) $1.v = nat->in_v; if ($1.v == 4 && ($1.a.in4.s_addr != 0 || ($3 != 0 && $3 != 32))) yyerror("Invalid mask for dip"); else if ($1.v == 6 && ($1.a.in4.s_addr != 0 || ($3 != 0 && $3 != 128))) yyerror("Invalid mask for dip"); else if ($1.v == 0 ) { if ($1.a.in4.s_addr == 0 && ($3 == 32 || $3 == 0)) $1.v = 4; else if ($3 == 128) $1.v = 6; } bcopy(&$1.a, &nat->in_in[0], sizeof($1.a)); ntomask($1.v, $3, (u_32_t *)&nat->in_in[1]); nat->in_in[0].i6[0] &= nat->in_in[1].i6[0]; nat->in_in[0].i6[0] &= nat->in_in[1].i6[1]; nat->in_in[0].i6[0] &= nat->in_in[1].i6[2]; nat->in_in[0].i6[0] &= nat->in_in[1].i6[3]; nat->in_v = $1.v; $$ = $1.v; } | hostname ',' { yyexpectaddr = 1; } hostname { if ($1.v != $4.v) yyerror("10.address family " "mismatch"); $$ = $1.v; nat->in_flags |= IPN_SPLIT; bcopy(&$1.a, &nat->in_in[0], sizeof($1.a)); bcopy(&$4.a, &nat->in_in[1], sizeof($4.a)); yyexpectaddr = 0; } ; portspec: YY_NUMBER { if ($1 > 65535) /* Unsigned */ yyerror("invalid port number"); else $$ = $1; } | YY_STR { if (getport(NULL, $1, &($$)) == -1) yyerror("invalid port number"); $$ = ntohs($$); } ; dport: | IPNY_PORT portspec { nat->in_pmin = htons($2); nat->in_pmax = htons($2); } | IPNY_PORT portspec '-' portspec { nat->in_pmin = htons($2); nat->in_pmax = htons($4); } | IPNY_PORT portspec ':' portspec { nat->in_pmin = htons($2); nat->in_pmax = htons($4); } ; nport: IPNY_PORT portspec { nat->in_pnext = htons($2); } | IPNY_PORT '=' portspec { nat->in_pnext = htons($3); nat->in_flags |= IPN_FIXEDDPORT; } ; ports: | IPNY_PORTS YY_NUMBER { nat->in_pmin = $2; } | IPNY_PORTS IPNY_AUTO { nat->in_flags |= IPN_AUTOPORTMAP; } ; mapit: IPNY_MAP { nat->in_redir = NAT_MAP; } | IPNY_BIMAP { nat->in_redir = NAT_BIMAP; } ; rdrit: IPNY_RDR { nat->in_redir = NAT_REDIRECT; } ; mapblockit: IPNY_MAPBLOCK { nat->in_redir = NAT_MAPBLK; } ; mapfrom: from sobject IPNY_TO dobject { if ($2 != 0 && $4 != 0 && $2 != $4) yyerror("11.address family " "mismatch"); $$ = $2; } | from sobject '!' IPNY_TO dobject { if ($2 != 0 && $5 != 0 && $2 != $5) yyerror("12.address family " "mismatch"); nat->in_flags |= IPN_NOTDST; $$ = $2; } ; rdrfrom: from sobject IPNY_TO dobject { if ($2 != 0 && $4 != 0 && $2 != $4) yyerror("13.address family " "mismatch"); $$ = $2; } | '!' from sobject IPNY_TO dobject { if ($3 != 0 && $5 != 0 && $3 != $5) yyerror("14.address family " "mismatch"); nat->in_flags |= IPN_NOTSRC; $$ = $3; } ; from: IPNY_FROM { nat->in_flags |= IPN_FILTER; yyexpectaddr = 1; } ; ifnames: ifname { yyexpectaddr = 1; } | ifname ',' otherifname { yyexpectaddr = 1; } ; ifname: YY_STR { strncpy(nat->in_ifnames[0], $1, sizeof(nat->in_ifnames[0])); nat->in_ifnames[0][LIFNAMSIZ - 1] = '\0'; free($1); } ; otherifname: YY_STR { strncpy(nat->in_ifnames[1], $1, sizeof(nat->in_ifnames[1])); nat->in_ifnames[1][LIFNAMSIZ - 1] = '\0'; free($1); } ; mapport: IPNY_PORTMAP tcpudp portspec ':' portspec randport { nat->in_pmin = htons($3); nat->in_pmax = htons($5); } | IPNY_PORTMAP tcpudp IPNY_AUTO randport { nat->in_flags |= IPN_AUTOPORTMAP; nat->in_pmin = htons(1024); nat->in_pmax = htons(65535); } | IPNY_ICMPIDMAP YY_STR YY_NUMBER ':' YY_NUMBER { if (strcmp($2, "icmp") != 0) { yyerror("icmpidmap not followed by icmp"); } free($2); if ($3 < 0 || $3 > 65535) yyerror("invalid ICMP Id number"); if ($5 < 0 || $5 > 65535) yyerror("invalid ICMP Id number"); nat->in_flags = IPN_ICMPQUERY; nat->in_pmin = htons($3); nat->in_pmax = htons($5); } ; randport: | IPNY_SEQUENTIAL { nat->in_flags |= IPN_SEQUENTIAL; } ; sobject: saddr { $$ = $1; } | saddr IPNY_PORT portstuff { nat->in_sport = $3.p1; nat->in_stop = $3.p2; nat->in_scmp = $3.pc; $$ = $1; } ; saddr: addr { if (nat->in_redir == NAT_REDIRECT) { bcopy(&$1.a, &nat->in_src[0], sizeof($1.a)); bcopy(&$1.m, &nat->in_src[1], sizeof($1.a)); } else { bcopy(&$1.a, &nat->in_in[0], sizeof($1.a)); bcopy(&$1.m, &nat->in_in[1], sizeof($1.a)); } $$ = $1.v; } ; dobject: daddr { $$ = $1; } | daddr IPNY_PORT portstuff { nat->in_dport = $3.p1; nat->in_dtop = $3.p2; nat->in_dcmp = $3.pc; if (nat->in_redir == NAT_REDIRECT) nat->in_pmin = htons($3.p1); } ; daddr: addr { if (nat->in_redir == NAT_REDIRECT) { bcopy(&$1.a, &nat->in_out[0], sizeof($1.a)); bcopy(&$1.m, &nat->in_out[1], sizeof($1.a)); } else { bcopy(&$1.a, &nat->in_src[0], sizeof($1.a)); bcopy(&$1.m, &nat->in_src[1], sizeof($1.a)); } $$ = $1.v; } ; addr: IPNY_ANY { yyexpectaddr = 0; bzero(&$$.a, sizeof($$.a)); bzero(&$$.m, sizeof($$.a)); $$.v = nat->in_v; } | hostname { $$.a = $1.a; $$.v = $1.v; if ($$.v == 4) { $$.m.in4.s_addr = 0xffffffff; } else { $$.m.i6[0] = 0xffffffff; $$.m.i6[1] = 0xffffffff; $$.m.i6[2] = 0xffffffff; $$.m.i6[3] = 0xffffffff; } yyexpectaddr = 0; } | hostname '/' YY_NUMBER { $$.a = $1.a; if ($1.v == 0) { if ($1.a.in4.s_addr != 0) yyerror("invalid addr"); if ($3 == 0 || $3 == 32) $1.v = 4; else if ($3 == 128) $1.v = 6; else yyerror("invalid mask"); nat->in_v = $1.v; } ntomask($1.v, $3, (u_32_t *)&$$.m); $$.a.i6[0] &= $$.m.i6[0]; $$.a.i6[1] &= $$.m.i6[1]; $$.a.i6[2] &= $$.m.i6[2]; $$.a.i6[3] &= $$.m.i6[3]; $$.v = $1.v; yyexpectaddr = 0; } | hostname '/' ipaddr { if ($1.v != $3.v) { yyerror("1.address family " "mismatch"); } $$.a = $1.a; $$.m = $3.a; $$.a.i6[0] &= $$.m.i6[0]; $$.a.i6[1] &= $$.m.i6[1]; $$.a.i6[2] &= $$.m.i6[2]; $$.a.i6[3] &= $$.m.i6[3]; $$.v = $1.v; yyexpectaddr = 0; } | hostname '/' hexnumber { $$.a = $1.a; $$.m.in4.s_addr = htonl($3); $$.a.in4.s_addr &= $$.m.in4.s_addr; $$.v = 4; } | hostname IPNY_MASK ipaddr { if ($1.v != $3.v) { yyerror("2.address family " "mismatch"); } $$.a = $1.a; $$.m = $3.a; $$.a.i6[0] &= $$.m.i6[0]; $$.a.i6[1] &= $$.m.i6[1]; $$.a.i6[2] &= $$.m.i6[2]; $$.a.i6[3] &= $$.m.i6[3]; $$.v = $1.v; yyexpectaddr = 0; } | hostname IPNY_MASK hexnumber { $$.a = $1.a; $$.m.in4.s_addr = htonl($3); $$.a.in4.s_addr &= $$.m.in4.s_addr; $$.v = 4; } ; portstuff: compare portspec { $$.pc = $1; $$.p1 = $2; } | portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; } ; mapoptions: rr frag age mssclamp nattag setproto ; rdroptions: rr frag age sticky mssclamp rdrproxy nattag ; nattag: | IPNY_TAG YY_STR { strncpy(nat->in_tag.ipt_tag, $2, sizeof(nat->in_tag.ipt_tag)); } rr: | IPNY_ROUNDROBIN { nat->in_flags |= IPN_ROUNDR; } ; frag: | IPNY_FRAG { nat->in_flags |= IPN_FRAG; } ; age: | IPNY_AGE YY_NUMBER { nat->in_age[0] = $2; nat->in_age[1] = $2; } | IPNY_AGE YY_NUMBER '/' YY_NUMBER { nat->in_age[0] = $2; nat->in_age[1] = $4; } ; sticky: | IPNY_STICKY { if (!(nat->in_flags & IPN_ROUNDR) && !(nat->in_flags & IPN_SPLIT)) { fprintf(stderr, "'sticky' for use with round-robin/IP splitting only\n"); } else nat->in_flags |= IPN_STICKY; } ; mssclamp: | IPNY_MSSCLAMP YY_NUMBER { nat->in_mssclamp = $2; } ; tcpudp: | IPNY_TCP { setnatproto(IPPROTO_TCP); } | IPNY_UDP { setnatproto(IPPROTO_UDP); } | IPNY_TCPUDP { nat->in_flags |= IPN_TCPUDP; nat->in_p = 0; } | IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP; nat->in_p = 0; } ; rdrproxy: IPNY_PROXY YY_STR { strncpy(nat->in_plabel, $2, sizeof(nat->in_plabel)); nat->in_dport = nat->in_pnext; nat->in_dport = htons(nat->in_dport); free($2); } | proxy { if (nat->in_plabel[0] != '\0') { nat->in_pmin = nat->in_dport; nat->in_pmax = nat->in_pmin; nat->in_pnext = nat->in_pmin; } } ; proto: YY_NUMBER { $$ = $1; } | IPNY_TCP { $$ = IPPROTO_TCP; } | IPNY_UDP { $$ = IPPROTO_UDP; } | YY_STR { $$ = getproto($1); free($1); } ; hexnumber: YY_HEX { $$ = $1; } ; hostname: YY_STR { i6addr_t addr; if (gethost($1, &addr, 0) == 0) { $$.a = addr; $$.v = 4; } else if (gethost($1, &addr, 1) == 0) { $$.a = addr; $$.v = 6; } else { yyerror("Unknown hostname"); } if ($$.v != 0) nat->in_v = $$.v; free($1); } | YY_NUMBER { bzero(&$$.a, sizeof($$.a)); $$.a.in4.s_addr = htonl($1); if ($$.a.in4.s_addr != 0) $$.v = 4; else $$.v = nat->in_v; if ($$.v != 0) nat->in_v = $$.v; } | ipv4 { $$ = $1; nat->in_v = 4; } | YY_IPV6 { $$.a = $1; $$.v = 6; nat->in_v = 6; } | YY_NUMBER YY_IPV6 { $$.a = $2; $$.v = 6; } ; compare: '=' { $$ = FR_EQUAL; } | YY_CMP_EQ { $$ = FR_EQUAL; } | YY_CMP_NE { $$ = FR_NEQUAL; } | YY_CMP_LT { $$ = FR_LESST; } | YY_CMP_LE { $$ = FR_LESSTE; } | YY_CMP_GT { $$ = FR_GREATERT; } | YY_CMP_GE { $$ = FR_GREATERTE; } range: YY_RANGE_OUT { $$ = FR_OUTRANGE; } | YY_RANGE_IN { $$ = FR_INRANGE; } ; ipaddr: ipv4 { $$ = $1; } | YY_IPV6 { $$.a = $1; $$.v = 6; } ; ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { yyerror("Invalid octet string for IP address"); return 0; } $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; $$.a.in4.s_addr = htonl($$.a.in4.s_addr); $$.v = 4; } ; %% static wordtab_t yywords[] = { { "age", IPNY_AGE }, { "any", IPNY_ANY }, { "auto", IPNY_AUTO }, { "bimap", IPNY_BIMAP }, { "frag", IPNY_FRAG }, { "from", IPNY_FROM }, { "icmpidmap", IPNY_ICMPIDMAP }, { "mask", IPNY_MASK }, { "map", IPNY_MAP }, { "map-block", IPNY_MAPBLOCK }, { "mssclamp", IPNY_MSSCLAMP }, { "netmask", IPNY_MASK }, { "port", IPNY_PORT }, { "portmap", IPNY_PORTMAP }, { "ports", IPNY_PORTS }, { "proxy", IPNY_PROXY }, { "range", IPNY_RANGE }, { "rdr", IPNY_RDR }, { "round-robin",IPNY_ROUNDROBIN }, { "sequential", IPNY_SEQUENTIAL }, { "sticky", IPNY_STICKY }, { "tag", IPNY_TAG }, { "tcp", IPNY_TCP }, { "tcpudp", IPNY_TCPUDP }, { "to", IPNY_TO }, { "udp", IPNY_UDP }, { "-", '-' }, { "->", IPNY_TLATE }, { "eq", YY_CMP_EQ }, { "ne", YY_CMP_NE }, { "lt", YY_CMP_LT }, { "gt", YY_CMP_GT }, { "le", YY_CMP_LE }, { "ge", YY_CMP_GE }, { NULL, 0 } }; int ipnat_parsefile(fd, addfunc, ioctlfunc, filename) int fd; addfunc_t addfunc; ioctlfunc_t ioctlfunc; char *filename; { FILE *fp = NULL; char *s; (void) yysettab(yywords); s = getenv("YYDEBUG"); if (s) yydebug = atoi(s); else yydebug = 0; if (strcmp(filename, "-")) { fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "fopen(%s) failed: %s\n", filename, STRERROR(errno)); return -1; } } else fp = stdin; while (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1) ; if (fp != NULL) fclose(fp); return 0; } int ipnat_parsesome(fd, addfunc, ioctlfunc, fp) int fd; addfunc_t addfunc; ioctlfunc_t ioctlfunc; FILE *fp; { char *s; int i; yylineNum = 1; natfd = fd; nataddfunc = addfunc; natioctlfunc = ioctlfunc; if (feof(fp)) return 0; i = fgetc(fp); if (i == EOF) return 0; if (ungetc(i, fp) == EOF) return 0; if (feof(fp)) return 0; s = getenv("YYDEBUG"); if (s) yydebug = atoi(s); else yydebug = 0; yyin = fp; yyparse(); return 1; } static void newnatrule() { ipnat_t *n; n = calloc(1, sizeof(*n)); if (n == NULL) return; if (nat == NULL) nattop = nat = n; else { nat->in_next = n; nat = n; } } static void setnatproto(p) int p; { nat->in_p = p; switch (p) { case IPPROTO_TCP : nat->in_flags |= IPN_TCP; nat->in_flags &= ~IPN_UDP; break; case IPPROTO_UDP : nat->in_flags |= IPN_UDP; nat->in_flags &= ~IPN_TCP; break; case IPPROTO_ICMP : nat->in_flags &= ~IPN_TCPUDP; if (!(nat->in_flags & IPN_ICMPQUERY)) { nat->in_dcmp = 0; nat->in_scmp = 0; nat->in_pmin = 0; nat->in_pmax = 0; nat->in_pnext = 0; } break; default : if ((nat->in_redir & NAT_MAPBLK) == 0) { /* Only reset dcmp/scmp in case dport/sport not set */ if (0 == nat->in_tuc.ftu_dport) nat->in_dcmp = 0; if (0 == nat->in_tuc.ftu_sport) nat->in_scmp = 0; nat->in_pmin = 0; nat->in_pmax = 0; nat->in_pnext = 0; nat->in_flags &= ~IPN_TCPUDP; } break; } if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT) nat->in_flags &= ~IPN_FIXEDDPORT; } void ipnat_addrule(fd, ioctlfunc, ptr) int fd; ioctlfunc_t ioctlfunc; void *ptr; { ioctlcmd_t add, del; ipfobj_t obj; ipnat_t *ipn; ipn = ptr; bzero((char *)&obj, sizeof(obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_size = sizeof(ipnat_t); obj.ipfo_type = IPFOBJ_IPNAT; obj.ipfo_ptr = ptr; add = 0; del = 0; if ((opts & OPT_DONOTHING) != 0) fd = -1; if (opts & OPT_ZERORULEST) { add = SIOCZRLST; } else if (opts & OPT_INACTIVE) { add = SIOCADNAT; del = SIOCRMNAT; } else { add = SIOCADNAT; del = SIOCRMNAT; } if (ipn && (opts & OPT_VERBOSE)) printnat(ipn, opts); if (opts & OPT_DEBUG) binprint(ipn, sizeof(*ipn)); if ((opts & OPT_ZERORULEST) != 0) { if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { if ((opts & OPT_DONOTHING) == 0) { fprintf(stderr, "%d:", yylineNum); perror("ioctl(SIOCZRLST)"); } } else { #ifdef USE_QUAD_T /* printf("hits %qd bytes %qd ", (long long)fr->fr_hits, (long long)fr->fr_bytes); */ #else /* printf("hits %ld bytes %ld ", fr->fr_hits, fr->fr_bytes); */ #endif printnat(ipn, opts); } } else if ((opts & OPT_REMOVE) != 0) { if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) { if ((opts & OPT_DONOTHING) == 0) { fprintf(stderr, "%d:", yylineNum); perror("ioctl(delete nat rule)"); } } } else { if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { if ((opts & OPT_DONOTHING) == 0) { fprintf(stderr, "%d:", yylineNum); perror("ioctl(add/insert nat rule)"); } } } } /* * Copyright (C) 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. * Copyright 2017 Gary Mills */ #include #include #include #include #if defined(BSD) && (BSD >= 199306) # include #endif #include #include #if __FreeBSD_version >= 300000 # include #endif #include #include #include #include #include #include #include #include #include #include #include "ipf.h" #include "netinet/ipl.h" #include "netinet/ip_lookup.h" #include "netinet/ip_pool.h" #include "netinet/ip_htable.h" #include "kmem.h" #include "ipfzone.h" extern int ippool_yyparse __P((void)); extern int ippool_yydebug; extern FILE *ippool_yyin; extern char *optarg; extern int lineNum; void showpools __P((ip_pool_stat_t *)); void usage __P((char *)); int main __P((int, char **)); int poolcommand __P((int, int, char *[])); int poolnodecommand __P((int, int, char *[])); int loadpoolfile __P((int, char *[], char *)); int poollist __P((int, char *[])); int poolflush __P((int, char *[])); int poolstats __P((int, char *[])); int gettype __P((char *, u_int *)); int getrole __P((char *)); void poollist_dead __P((int, char *, int, char *, char *)); void showpools_live(int, int, ip_pool_stat_t *, char *, int); void showhashs_live(int, int, iphtstat_t *, char *, int); int opts = 0; int fd = -1; int use_inet6 = 0; void usage(prog) char *prog; { const char *zoneopt = "[-G|-z zonename] "; fprintf(stderr, "Usage:\t%s\n", prog); fprintf(stderr, "\t\t\t-a [-dnv] %s[-m ] [-o ] -i [/netmask]\n", zoneopt); fprintf(stderr, "\t\t\t-A [-dnv] %s[-m ] [-o ] [-S ] [-t ]\n", zoneopt); fprintf(stderr, "\t\t\t-f %s[-dnuv]\n", zoneopt); fprintf(stderr, "\t\t\t-F [-dv] %s[-o ] [-t ]\n", zoneopt); fprintf(stderr, "\t\t\t-l [-dv] %s[-m ] [-t ]\n", zoneopt); fprintf(stderr, "\t\t\t-r [-dnv] %s[-m ] [-o ] -i [/netmask]\n", zoneopt); fprintf(stderr, "\t\t\t-R [-dnv] %s[-m ] [-o ] [-t ]\n", zoneopt); fprintf(stderr, "\t\t\t-s [-dtv] %s[-M ] [-N ]\n", zoneopt); exit(1); } int main(argc, argv) int argc; char *argv[]; { int err; if (argc < 2) usage(argv[0]); switch (getopt(argc, argv, "aAf:FlrRs")) { case 'a' : err = poolnodecommand(0, argc, argv); break; case 'A' : err = poolcommand(0, argc, argv); break; case 'f' : err = loadpoolfile(argc, argv, optarg); break; case 'F' : err = poolflush(argc, argv); break; case 'l' : err = poollist(argc, argv); break; case 'r' : err = poolnodecommand(1, argc, argv); break; case 'R' : err = poolcommand(1, argc, argv); break; case 's' : err = poolstats(argc, argv); break; default : exit(1); } return err; } int poolnodecommand(remove, argc, argv) int remove, argc; char *argv[]; { char *poolname = NULL, *s; int err, c, ipset, role; ip_pool_node_t node; struct in_addr mask; ipset = 0; role = IPL_LOGIPF; bzero((char *)&node, sizeof(node)); while ((c = getopt(argc, argv, "di:G:m:no:Rvz:")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; ippool_yydebug++; break; case 'G' : setzonename_global(optarg); break; case 'i' : s = strchr(optarg, '/'); if (s == NULL) mask.s_addr = 0xffffffff; else if (strchr(s, '.') == NULL) { if (ntomask(4, atoi(s + 1), &mask.s_addr) != 0) return -1; } else { mask.s_addr = inet_addr(s + 1); } if (s != NULL) *s = '\0'; ipset = 1; node.ipn_addr.adf_len = sizeof(node.ipn_addr); node.ipn_addr.adf_addr.in4.s_addr = inet_addr(optarg); node.ipn_mask.adf_len = sizeof(node.ipn_mask); node.ipn_mask.adf_addr.in4.s_addr = mask.s_addr; break; case 'm' : poolname = optarg; break; case 'n' : opts |= OPT_DONOTHING; break; case 'o' : role = getrole(optarg); if (role == IPL_LOGNONE) return -1; break; case 'R' : opts |= OPT_NORESOLVE; break; case 'v' : opts |= OPT_VERBOSE; break; case 'z' : setzonename(optarg); break; } if (opts & OPT_DEBUG) fprintf(stderr, "poolnodecommand: opts = %#x\n", opts); if (ipset == 0) return -1; if (poolname == NULL) { fprintf(stderr, "poolname not given with add/remove node\n"); return -1; } if (remove == 0) err = load_poolnode(0, poolname, &node, ioctl); else err = remove_poolnode(0, poolname, &node, ioctl); return err; } int poolcommand(remove, argc, argv) int remove, argc; char *argv[]; { int type, role, c, err; char *poolname; iphtable_t iph; ip_pool_t pool; err = 1; role = 0; type = 0; poolname = NULL; role = IPL_LOGIPF; bzero((char *)&iph, sizeof(iph)); bzero((char *)&pool, sizeof(pool)); while ((c = getopt(argc, argv, "dG:m:no:RS:t:vz:")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; ippool_yydebug++; break; case 'G' : setzonename_global(optarg); break; case 'm' : poolname = optarg; break; case 'n' : opts |= OPT_DONOTHING; break; case 'o' : role = getrole(optarg); if (role == IPL_LOGNONE) { fprintf(stderr, "unknown role '%s'\n", optarg); return -1; } break; case 'R' : opts |= OPT_NORESOLVE; break; case 'S' : iph.iph_seed = atoi(optarg); break; case 't' : type = gettype(optarg, &iph.iph_type); if (type == IPLT_NONE) { fprintf(stderr, "unknown type '%s'\n", optarg); return -1; } break; case 'v' : opts |= OPT_VERBOSE; break; case 'z' : setzonename(optarg); break; } if (opts & OPT_DEBUG) fprintf(stderr, "poolcommand: opts = %#x\n", opts); if (poolname == NULL) { fprintf(stderr, "poolname not given with add/remove pool\n"); return -1; } if (type == IPLT_HASH) { strncpy(iph.iph_name, poolname, sizeof(iph.iph_name)); iph.iph_name[sizeof(iph.iph_name) - 1] = '\0'; iph.iph_unit = role; } else if (type == IPLT_POOL) { strncpy(pool.ipo_name, poolname, sizeof(pool.ipo_name)); pool.ipo_name[sizeof(pool.ipo_name) - 1] = '\0'; pool.ipo_unit = role; } if (remove == 0) { switch (type) { case IPLT_HASH : err = load_hash(&iph, NULL, ioctl); break; case IPLT_POOL : err = load_pool(&pool, ioctl); break; } } else { switch (type) { case IPLT_HASH : err = remove_hash(&iph, ioctl); break; case IPLT_POOL : err = remove_pool(&pool, ioctl); break; } } return err; } int loadpoolfile(argc, argv, infile) int argc; char *argv[], *infile; { int c; infile = optarg; while ((c = getopt(argc, argv, "dG:nRuvz:")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; ippool_yydebug++; break; case 'G' : setzonename_global(optarg); break; case 'n' : opts |= OPT_DONOTHING; break; case 'R' : opts |= OPT_NORESOLVE; break; case 'u' : opts |= OPT_REMOVE; break; case 'v' : opts |= OPT_VERBOSE; break; case 'z' : setzonename(optarg); break; } if (opts & OPT_DEBUG) fprintf(stderr, "loadpoolfile: opts = %#x\n", opts); if (!(opts & OPT_DONOTHING) && (fd == -1)) { fd = open(IPLOOKUP_NAME, O_RDWR); if (fd == -1) { perror("open(IPLOOKUP_NAME)"); exit(1); } if (setzone(fd) != 0) { close(fd); exit(1); } } if (ippool_parsefile(fd, infile, ioctl) != 0) return -1; return 0; } int poollist(argc, argv) int argc; char *argv[]; { char *kernel, *core, *poolname; int c, role, type, live_kernel; ip_pool_stat_t plstat; iphtstat_t htstat; iphtable_t *hptr; iplookupop_t op; ip_pool_t *ptr; core = NULL; kernel = NULL; live_kernel = 1; type = IPLT_ALL; poolname = NULL; role = IPL_LOGALL; while ((c = getopt(argc, argv, "dG:m:M:N:o:Rt:vz:")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; break; case 'G' : setzonename_global(optarg); break; case 'm' : poolname = optarg; break; case 'M' : live_kernel = 0; core = optarg; break; case 'N' : live_kernel = 0; kernel = optarg; break; case 'o' : role = getrole(optarg); if (role == IPL_LOGNONE) { fprintf(stderr, "unknown role '%s'\n", optarg); return -1; } break; case 'R' : opts |= OPT_NORESOLVE; break; case 't' : type = gettype(optarg, NULL); if (type == IPLT_NONE) { fprintf(stderr, "unknown type '%s'\n", optarg); return -1; } break; case 'v' : opts |= OPT_VERBOSE; break; case 'z' : setzonename(optarg); break; } if (opts & OPT_DEBUG) fprintf(stderr, "poollist: opts = %#x\n", opts); if (!(opts & OPT_DONOTHING) && (fd == -1)) { fd = open(IPLOOKUP_NAME, O_RDWR); if (fd == -1) { perror("open(IPLOOKUP_NAME)"); exit(1); } if (setzone(fd) != 0) { close(fd); exit(1); } } bzero((char *)&op, sizeof(op)); if (poolname != NULL) { strncpy(op.iplo_name, poolname, sizeof(op.iplo_name)); op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; } op.iplo_unit = role; if (live_kernel == 0) { poollist_dead(role, poolname, type, kernel, core); return (0); } if (type == IPLT_ALL || type == IPLT_POOL) { op.iplo_type = IPLT_POOL; op.iplo_size = sizeof(plstat); op.iplo_struct = &plstat; op.iplo_name[0] = '\0'; op.iplo_arg = 0; if (role != IPL_LOGALL) { op.iplo_unit = role; c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { perror("ioctl(SIOCLOOKUPSTAT)"); return -1; } showpools_live(fd, role, &plstat, poolname, opts); } else { for (role = 0; role <= IPL_LOGMAX; role++) { op.iplo_unit = role; c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { perror("ioctl(SIOCLOOKUPSTAT)"); return -1; } showpools_live(fd, role, &plstat, poolname, opts); } role = IPL_LOGALL; } } if (type == IPLT_ALL || type == IPLT_HASH) { op.iplo_type = IPLT_HASH; op.iplo_size = sizeof(htstat); op.iplo_struct = &htstat; op.iplo_name[0] = '\0'; op.iplo_arg = 0; if (role != IPL_LOGALL) { op.iplo_unit = role; c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { perror("ioctl(SIOCLOOKUPSTAT)"); return -1; } showhashs_live(fd, role, &htstat, poolname, opts); } else { for (role = 0; role <= IPL_LOGMAX; role++) { op.iplo_unit = role; c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { perror("ioctl(SIOCLOOKUPSTAT)"); return -1; } showhashs_live(fd, role, &htstat, poolname, opts); } } } return 0; } void poollist_dead(role, poolname, type, kernel, core) int role, type; char *poolname, *kernel, *core; { iphtable_t *hptr; ip_pool_t *ptr; if (openkmem(kernel, core) == -1) exit(-1); if (type == IPLT_ALL || type == IPLT_POOL) { ip_pool_t *pools[IPL_LOGSIZE]; struct nlist names[2] = { { "ip_pool_list" } , { "" } }; if (nlist(kernel, names) != 1) return; bzero(&pools, sizeof(pools)); if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools))) return; if (role != IPL_LOGALL) { ptr = pools[role]; while (ptr != NULL) { ptr = printpool(ptr, kmemcpywrap, poolname, opts); } } else { for (role = 0; role <= IPL_LOGMAX; role++) { ptr = pools[role]; while (ptr != NULL) { ptr = printpool(ptr, kmemcpywrap, poolname, opts); } } role = IPL_LOGALL; } } if (type == IPLT_ALL || type == IPLT_HASH) { iphtable_t *tables[IPL_LOGSIZE]; struct nlist names[2] = { { "ipf_htables" } , { "" } }; if (nlist(kernel, names) != 1) return; bzero(&tables, sizeof(tables)); if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables))) return; if (role != IPL_LOGALL) { hptr = tables[role]; while (hptr != NULL) { hptr = printhash(hptr, kmemcpywrap, poolname, opts); } } else { for (role = 0; role <= IPL_LOGMAX; role++) { hptr = tables[role]; while (hptr != NULL) { hptr = printhash(hptr, kmemcpywrap, poolname, opts); } } } } } void showpools_live(fd, role, plstp, poolname, opts) int fd, role; ip_pool_stat_t *plstp; char *poolname; int opts; { ipflookupiter_t iter; ip_pool_t pool; ipfobj_t obj; obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_LOOKUPITER; obj.ipfo_size = sizeof(iter); obj.ipfo_ptr = &iter; iter.ili_type = IPLT_POOL; iter.ili_otype = IPFLOOKUPITER_LIST; iter.ili_ival = IPFGENITER_LOOKUP; iter.ili_data = &pool; iter.ili_unit = role; *iter.ili_name = '\0'; while (plstp->ipls_list[role] != NULL) { if (ioctl(fd, SIOCLOOKUPITER, &obj)) { perror("ioctl(SIOCLOOKUPITER)"); break; } (void) printpool_live(&pool, fd, poolname, opts); plstp->ipls_list[role] = pool.ipo_next; } } int poolstats(argc, argv) int argc; char *argv[]; { int c, type, role; ip_pool_stat_t plstat; iphtstat_t htstat; iplookupop_t op; type = IPLT_ALL; role = IPL_LOGALL; bzero((char *)&op, sizeof(op)); while ((c = getopt(argc, argv, "dG:M:N:o:t:vz:")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; break; case 'G' : setzonename_global(optarg); break; case 'M' : break; case 'N' : break; case 'o' : role = getrole(optarg); if (role == IPL_LOGNONE) { fprintf(stderr, "unknown role '%s'\n", optarg); return -1; } break; case 't' : type = gettype(optarg, NULL); if (type != IPLT_POOL) { fprintf(stderr, "-s not supported for this type yet\n"); return -1; } break; case 'v' : opts |= OPT_VERBOSE; break; case 'z' : setzonename(optarg); break; } if (opts & OPT_DEBUG) fprintf(stderr, "poolstats: opts = %#x\n", opts); if (!(opts & OPT_DONOTHING) && (fd == -1)) { fd = open(IPLOOKUP_NAME, O_RDWR); if (fd == -1) { perror("open(IPLOOKUP_NAME)"); exit(1); } if (setzone(fd) != 0) { close(fd); exit(1); } } if (type == IPLT_ALL || type == IPLT_POOL) { op.iplo_type = IPLT_POOL; op.iplo_struct = &plstat; op.iplo_size = sizeof(plstat); if (!(opts & OPT_DONOTHING)) { c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { perror("ioctl(SIOCLOOKUPSTAT)"); return -1; } printf("Pools:\t%lu\n", plstat.ipls_pools); printf("Nodes:\t%lu\n", plstat.ipls_nodes); } } if (type == IPLT_ALL || type == IPLT_HASH) { op.iplo_type = IPLT_HASH; op.iplo_struct = &htstat; op.iplo_size = sizeof(htstat); if (!(opts & OPT_DONOTHING)) { c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { perror("ioctl(SIOCLOOKUPSTAT)"); return -1; } printf("Hash Tables:\t%lu\n", htstat.iphs_numtables); printf("Nodes:\t%lu\n", htstat.iphs_numnodes); printf("Out of Memory:\t%lu\n", htstat.iphs_nomem); } } return 0; } int poolflush(argc, argv) int argc; char *argv[]; { int c, role, type, arg; iplookupflush_t flush; arg = IPLT_ALL; type = IPLT_ALL; role = IPL_LOGALL; while ((c = getopt(argc, argv, "do:t:vz:")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; break; case 'o' : role = getrole(optarg); if (role == IPL_LOGNONE) { fprintf(stderr, "unknown role '%s'\n", optarg); return -1; } break; case 't' : type = gettype(optarg, NULL); if (type == IPLT_NONE) { fprintf(stderr, "unknown type '%s'\n", optarg); return -1; } break; case 'v' : opts |= OPT_VERBOSE; break; case 'z' : setzonename(optarg); break; } if (opts & OPT_DEBUG) fprintf(stderr, "poolflush: opts = %#x\n", opts); if (!(opts & OPT_DONOTHING) && (fd == -1)) { fd = open(IPLOOKUP_NAME, O_RDWR); if (fd == -1) { perror("open(IPLOOKUP_NAME)"); exit(1); } if (setzone(fd) != 0) { close(fd); exit(1); } } bzero((char *)&flush, sizeof(flush)); flush.iplf_type = type; flush.iplf_unit = role; flush.iplf_arg = arg; if (!(opts & OPT_DONOTHING)) { if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) { perror("ioctl(SIOCLOOKUPFLUSH)"); exit(1); } } printf("%u object%s flushed\n", flush.iplf_count, (flush.iplf_count == 1) ? "" : "s"); return 0; } int getrole(rolename) char *rolename; { int role; if (!strcasecmp(rolename, "ipf")) { role = IPL_LOGIPF; #if 0 } else if (!strcasecmp(rolename, "nat")) { role = IPL_LOGNAT; } else if (!strcasecmp(rolename, "state")) { role = IPL_LOGSTATE; } else if (!strcasecmp(rolename, "auth")) { role = IPL_LOGAUTH; } else if (!strcasecmp(rolename, "sync")) { role = IPL_LOGSYNC; } else if (!strcasecmp(rolename, "scan")) { role = IPL_LOGSCAN; } else if (!strcasecmp(rolename, "pool")) { role = IPL_LOGLOOKUP; } else if (!strcasecmp(rolename, "count")) { role = IPL_LOGCOUNT; #endif } else { role = IPL_LOGNONE; } return role; } int gettype(typename, minor) char *typename; u_int *minor; { int type; if (!strcasecmp(optarg, "tree")) { type = IPLT_POOL; } else if (!strcasecmp(optarg, "hash")) { type = IPLT_HASH; if (minor != NULL) *minor = IPHASH_LOOKUP; } else if (!strcasecmp(optarg, "group-map")) { type = IPLT_HASH; if (minor != NULL) *minor = IPHASH_GROUPMAP; } else { type = IPLT_NONE; } return type; } void showhashs_live(fd, role, htstp, poolname, opts) int fd, role; iphtstat_t *htstp; char *poolname; int opts; { ipflookupiter_t iter; iphtable_t table; ipfobj_t obj; obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_LOOKUPITER; obj.ipfo_size = sizeof(iter); obj.ipfo_ptr = &iter; iter.ili_type = IPLT_HASH; iter.ili_otype = IPFLOOKUPITER_LIST; iter.ili_ival = IPFGENITER_LOOKUP; iter.ili_data = &table; iter.ili_unit = role; *iter.ili_name = '\0'; while (htstp->iphs_tables != NULL) { if (ioctl(fd, SIOCLOOKUPITER, &obj)) { perror("ioctl(SIOCLOOKUPITER)"); break; } printhash_live(&table, fd, poolname, opts); htstp->iphs_tables = table.iph_next; } } %{ /* * Copyright (C) 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #if defined(BSD) && (BSD >= 199306) # include #endif #include #include #if __FreeBSD_version >= 300000 # include #endif #include #include #include #include #include #include #include #include #include #include "ipf.h" #include "netinet/ip_lookup.h" #include "netinet/ip_pool.h" #include "netinet/ip_htable.h" #include "ippool_l.h" #include "kmem.h" #define YYDEBUG 1 extern int yyparse __P((void)); extern int yydebug; extern FILE *yyin; static iphtable_t ipht; static iphtent_t iphte; static ip_pool_t iplo; static ioctlfunc_t poolioctl = NULL; static char poolname[FR_GROUPLEN]; static int set_ipv6_addr = 0; %} %union { char *str; u_32_t num; struct in_addr addr; struct alist_s *alist; union i6addr adrmsk[2]; iphtent_t *ipe; ip_pool_node_t *ipp; union i6addr ip6; } %token YY_NUMBER YY_HEX %token YY_STR %token YY_COMMENT %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT %token YY_RANGE_OUT YY_RANGE_IN %token YY_IPV6 %token IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT %token IPT_TABLE IPT_GROUPMAP IPT_HASH %token IPT_ROLE IPT_TYPE IPT_TREE %token IPT_GROUP IPT_SIZE IPT_SEED IPT_NUM IPT_NAME %type role table inout %type ipftree range addrlist %type addrmask %type ipfgroup ipfhash hashlist hashentry %type groupentry setgrouplist grouplist %type ipaddr mask ipv4 %type number setgroup %% file: line | assign | file line | file assign ; line: table role ipftree eol { iplo.ipo_unit = $2; iplo.ipo_list = $3; load_pool(&iplo, poolioctl); resetlexer(); } | table role ipfhash eol { ipht.iph_unit = $2; ipht.iph_type = IPHASH_LOOKUP; load_hash(&ipht, $3, poolioctl); resetlexer(); } | groupmap role number ipfgroup eol { ipht.iph_unit = $2; strncpy(ipht.iph_name, $3, sizeof(ipht.iph_name)); ipht.iph_type = IPHASH_GROUPMAP; load_hash(&ipht, $4, poolioctl); resetlexer(); } | YY_COMMENT ; eol: ';' ; assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); resetlexer(); free($1); free($3); } ; assigning: '=' { yyvarnext = 1; } ; table: IPT_TABLE { bzero((char *)&ipht, sizeof(ipht)); bzero((char *)&iphte, sizeof(iphte)); bzero((char *)&iplo, sizeof(iplo)); *ipht.iph_name = '\0'; iplo.ipo_flags = IPHASH_ANON; iplo.ipo_name[0] = '\0'; } ; groupmap: IPT_GROUPMAP inout { bzero((char *)&ipht, sizeof(ipht)); bzero((char *)&iphte, sizeof(iphte)); *ipht.iph_name = '\0'; ipht.iph_unit = IPHASH_GROUPMAP; ipht.iph_flags = $2; } ; inout: IPT_IN { $$ = FR_INQUE; } | IPT_OUT { $$ = FR_OUTQUE; } ; role: IPT_ROLE '=' IPT_IPF { $$ = IPL_LOGIPF; } | IPT_ROLE '=' IPT_NAT { $$ = IPL_LOGNAT; } | IPT_ROLE '=' IPT_AUTH { $$ = IPL_LOGAUTH; } | IPT_ROLE '=' IPT_COUNT { $$ = IPL_LOGCOUNT; } ; ipftree: IPT_TYPE '=' IPT_TREE number start addrlist end { strncpy(iplo.ipo_name, $4, sizeof(iplo.ipo_name)); $$ = $6; } ; ipfhash: IPT_TYPE '=' IPT_HASH number hashopts start hashlist end { strncpy(ipht.iph_name, $4, sizeof(ipht.iph_name)); $$ = $7; } ; ipfgroup: setgroup hashopts start grouplist end { iphtent_t *e; for (e = $4; e != NULL; e = e->ipe_next) if (e->ipe_group[0] == '\0') strncpy(e->ipe_group, $1, FR_GROUPLEN); $$ = $4; } | hashopts start setgrouplist end { $$ = $3; } ; number: IPT_NUM '=' YY_NUMBER { snprintf(poolname, FR_GROUPLEN, "%u", $3); $$ = poolname; } | IPT_NAME '=' YY_STR { $$ = $3; } | { $$ = ""; } ; setgroup: IPT_GROUP '=' YY_STR { char tmp[FR_GROUPLEN+1]; strncpy(tmp, $3, FR_GROUPLEN); $$ = strdup(tmp); } | IPT_GROUP '=' YY_NUMBER { char tmp[FR_GROUPLEN+1]; snprintf(tmp, FR_GROUPLEN, "%u", $3); $$ = strdup(tmp); } ; hashopts: | size | seed | size seed ; addrlist: ';' { $$ = NULL; } | range next addrlist { $1->ipn_next = $3; $$ = $1; } | range next { $$ = $1; } | range ; grouplist: ';' { $$ = NULL; } | groupentry next grouplist { $$ = $1; $1->ipe_next = $3; } | addrmask next grouplist { $$ = calloc(1, sizeof(iphtent_t)); if ($$ == NULL) yyerror("sorry, out of memory"); if (set_ipv6_addr) $$->ipe_family = AF_INET6; else $$->ipe_family = AF_INET; bcopy((char *)&($1[0]), (char *)&($$->ipe_addr), sizeof($$->ipe_addr)); bcopy((char *)&($1[1]), (char *)&($$->ipe_mask), sizeof($$->ipe_mask)); set_ipv6_addr = 0; $$->ipe_next = $3; } | groupentry next { $$ = $1; } | addrmask next { $$ = calloc(1, sizeof(iphtent_t)); if ($$ == NULL) yyerror("sorry, out of memory"); if (set_ipv6_addr) $$->ipe_family = AF_INET6; else $$->ipe_family = AF_INET; bcopy((char *)&($1[0]), (char *)&($$->ipe_addr), sizeof($$->ipe_addr)); bcopy((char *)&($1[1]), (char *)&($$->ipe_mask), sizeof($$->ipe_mask)); set_ipv6_addr = 0; } ; setgrouplist: ';' { $$ = NULL; } | groupentry next { $$ = $1; } | groupentry next setgrouplist { $1->ipe_next = $3; $$ = $1; } ; groupentry: addrmask ',' setgroup { $$ = calloc(1, sizeof(iphtent_t)); if ($$ == NULL) yyerror("sorry, out of memory"); if (set_ipv6_addr) $$->ipe_family = AF_INET6; else $$->ipe_family = AF_INET; bcopy((char *)&($1[0]), (char *)&($$->ipe_addr), sizeof($$->ipe_addr)); bcopy((char *)&($1[1]), (char *)&($$->ipe_mask), sizeof($$->ipe_mask)); set_ipv6_addr = 0; strncpy($$->ipe_group, $3, FR_GROUPLEN); free($3); } ; range: addrmask { $$ = calloc(1, sizeof(*$$)); if ($$ == NULL) yyerror("sorry, out of memory"); $$->ipn_info = 0; $$->ipn_addr.adf_len = sizeof($$->ipn_addr); $$->ipn_mask.adf_len = sizeof($$->ipn_mask); if (set_ipv6_addr) { $$->ipn_addr.adf_family = AF_INET6; $$->ipn_addr.adf_addr = $1[0]; $$->ipn_mask.adf_addr = $1[1]; } else { $$->ipn_addr.adf_family = AF_INET; $$->ipn_addr.adf_addr.in4.s_addr = $1[0].in4.s_addr; $$->ipn_mask.adf_addr.in4.s_addr = $1[1].in4.s_addr; } set_ipv6_addr = 0; } | '!' addrmask { $$ = calloc(1, sizeof(*$$)); if ($$ == NULL) yyerror("sorry, out of memory"); $$->ipn_info = 1; $$->ipn_addr.adf_len = sizeof($$->ipn_addr); $$->ipn_mask.adf_len = sizeof($$->ipn_mask); if (set_ipv6_addr) { $$->ipn_addr.adf_family = AF_INET6; $$->ipn_addr.adf_addr = $2[0]; $$->ipn_mask.adf_addr = $2[1]; } else { $$->ipn_addr.adf_family = AF_INET; $$->ipn_addr.adf_addr.in4.s_addr = $2[0].in4.s_addr; $$->ipn_mask.adf_addr.in4.s_addr = $2[1].in4.s_addr; } set_ipv6_addr = 0; } hashlist: ';' { $$ = NULL; } | hashentry next { $$ = $1; } | hashentry next hashlist { $1->ipe_next = $3; $$ = $1; } ; hashentry: addrmask { $$ = calloc(1, sizeof(iphtent_t)); if ($$ == NULL) yyerror("sorry, out of memory"); if (set_ipv6_addr) $$->ipe_family = AF_INET6; else $$->ipe_family = AF_INET; bcopy((char *)&($1[0]), (char *)&($$->ipe_addr), sizeof($$->ipe_addr)); bcopy((char *)&($1[1]), (char *)&($$->ipe_mask), sizeof($$->ipe_mask)); } ; addrmask: ipaddr '/' mask { $$[0] = $1; $$[1] = $3; yyexpectaddr = 0; } | ipaddr { $$[0] = $1; yyexpectaddr = 0; if (set_ipv6_addr) fill6bits(128, (u_32_t *)$$[1].in6.s6_addr); else $$[1].in4.s_addr = 0xffffffff; } ; ipaddr: ipv4 { $$ = $1; } | YY_NUMBER { $$.in4.s_addr = htonl($1); } | YY_IPV6 { set_ipv6_addr = 1; bcopy(&$1, &$$, sizeof($$)); yyexpectaddr = 0; } | YY_STR { if (gethost($1, &$$, 0) == -1) yyerror("Unknown hostname"); } ; mask: YY_NUMBER { if (set_ipv6_addr) ntomask(6, $1, (u_32_t *)$$.in6.s6_addr); else ntomask(4, $1, (u_32_t *)&$$.in4.s_addr); } | ipv4 { $$ = $1; } ; start: '{' { yyexpectaddr = 1; } ; end: '}' { yyexpectaddr = 0; } ; next: ',' { yyexpectaddr = 1; } | ';' { yyexpectaddr = 1; } ; size: IPT_SIZE '=' YY_NUMBER { ipht.iph_size = $3; } ; seed: IPT_SEED '=' YY_NUMBER { ipht.iph_seed = $3; } ; ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { yyerror("Invalid octet string for IP address"); return 0; } $$.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; $$.in4.s_addr = htonl($$.in4.s_addr); } ; %% static wordtab_t yywords[] = { { "auth", IPT_AUTH }, { "count", IPT_COUNT }, { "group", IPT_GROUP }, { "group-map", IPT_GROUPMAP }, { "hash", IPT_HASH }, { "in", IPT_IN }, { "ipf", IPT_IPF }, { "name", IPT_NAME }, { "nat", IPT_NAT }, { "number", IPT_NUM }, { "out", IPT_OUT }, { "role", IPT_ROLE }, { "seed", IPT_SEED }, { "size", IPT_SIZE }, { "table", IPT_TABLE }, { "tree", IPT_TREE }, { "type", IPT_TYPE }, { NULL, 0 } }; int ippool_parsefile(fd, filename, iocfunc) int fd; char *filename; ioctlfunc_t iocfunc; { FILE *fp = NULL; char *s; yylineNum = 1; (void) yysettab(yywords); s = getenv("YYDEBUG"); if (s) yydebug = atoi(s); else yydebug = 0; if (strcmp(filename, "-")) { fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "fopen(%s) failed: %s\n", filename, STRERROR(errno)); return -1; } } else fp = stdin; while (ippool_parsesome(fd, fp, iocfunc) == 1) ; if (fp != NULL) fclose(fp); return 0; } int ippool_parsesome(fd, fp, iocfunc) int fd; FILE *fp; ioctlfunc_t iocfunc; { char *s; int i; poolioctl = iocfunc; if (feof(fp)) return 0; i = fgetc(fp); if (i == EOF) return 0; if (ungetc(i, fp) == EOF) return 0; if (feof(fp)) return 0; s = getenv("YYDEBUG"); if (s) yydebug = atoi(s); else yydebug = 0; yyin = fp; yyparse(); return 1; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * $Id: kmem.h,v 2.5 2002/08/21 22:57:36 darrenr Exp $ */ #ifndef __KMEM_H__ #define __KMEM_H__ #ifndef __P # ifdef __STDC__ # define __P(x) x # else # define __P(x) () # endif #endif extern int openkmem __P((char *, char *)); extern int kmemcpy __P((char *, long, int)); extern int kstrncpy __P((char *, long, int)); #if defined(__NetBSD__) || defined(__OpenBSD) # include #endif #ifdef _PATH_KMEM # define KMEM _PATH_KMEM #else # define KMEM "/dev/kmem" #endif #endif /* __KMEM_H__ */ extern long string_start; extern long string_end; extern char *string_val; extern long pos; #define YY_INPUT(buf, result, max_size) \ if (pos >= string_start && pos <= string_end) { \ buf[0] = string_val[pos - string_start]; \ pos++; \ result = 1; \ } else if ( yy_current_buffer->yy_is_interactive ) \ { \ int c = '*', n; \ for ( n = 0; n < 1 && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ pos++; \ } \ else if ( ((result = fread( buf, 1, 1, yyin )) == 0) \ && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); #ifdef input # undef input # define input() (((pos >= string_start) && (pos < string_end)) ? \ yysptr = yysbuf, string_val[pos++ - string_start] : \ ((yytchar = yysptr > yysbuf ? U(*--yysptr) : \ getc(yyin)) == 10 ? (pos++, yylineno++, yytchar) : \ yytchar) == EOF ? (pos++, 0) : (pos++, yytchar)) #endif #ifdef lex_input # undef lex_input # define lex_input() (((pos >= string_start) && (pos < string_end)) ? \ yysptr = yysbuf, string_val[pos++ - string_start] : \ ((yytchar = yysptr > yysbuf ? U(*--yysptr) : \ getc(yyin)) == 10 ? (pos++, yylineno++, yytchar) : \ yytchar) == EOF ? (pos++, 0) : (pos++, yytchar)) #endif #ifdef unput # undef unput # define unput(c) { if (pos > 0) pos--; \ yytchar = (c); if (yytchar == '\n') yylineno--; \ *yysptr++ = yytchar; } #endif /* * Copyright (C) 2002-2008 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "ipf.h" #ifdef IPFILTER_SCAN #include "netinet/ip_scan.h" #endif #include #include #ifdef TEST_LEXER #define NO_YACC union { int num; char *str; struct in_addr ipa; i6addr_t ip6; } yylval; #endif #include "lexer.h" #include "y.tab.h" FILE *yyin; #define ishex(c) (ISDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || \ ((c) >= 'A' && (c) <= 'F')) #define TOOLONG -3 extern int string_start; extern int string_end; extern char *string_val; extern int pos; extern int yydebug; char *yystr = NULL; int yytext[YYBUFSIZ+1]; char yychars[YYBUFSIZ+1]; int yylineNum = 1; int yypos = 0; int yylast = -1; int yyexpectaddr = 0; int yybreakondot = 0; int yyvarnext = 0; int yytokentype = 0; wordtab_t *yywordtab = NULL; int yysavedepth = 0; wordtab_t *yysavewords[30]; static wordtab_t *yyfindkey __P((char *)); static int yygetc __P((int)); static void yyunputc __P((int)); static int yyswallow __P((int)); static char *yytexttostr __P((int, int)); static void yystrtotext __P((char *)); static char *yytexttochar __P((void)); static int yygetc(int docont) { int c; if (yypos < yylast) { c = yytext[yypos++]; if (c == '\n') yylineNum++; return (c); } if (yypos == YYBUFSIZ) return (TOOLONG); if (pos >= string_start && pos <= string_end) { c = string_val[pos - string_start]; yypos++; } else { c = fgetc(yyin); if (docont && (c == '\\')) { c = fgetc(yyin); if (c == '\n') { yylineNum++; c = fgetc(yyin); } } } if (c == '\n') yylineNum++; yytext[yypos++] = c; yylast = yypos; yytext[yypos] = '\0'; return (c); } static void yyunputc(int c) { if (c == '\n') yylineNum--; yytext[--yypos] = c; } static int yyswallow(int last) { int c; while (((c = yygetc(0)) > '\0') && (c != last)) ; if (c != EOF) yyunputc(c); if (c == last) return (0); return (-1); } static char *yytexttochar(void) { int i; for (i = 0; i < yypos; i++) yychars[i] = (char)(yytext[i] & 0xff); yychars[i] = '\0'; return (yychars); } static void yystrtotext(char *str) { int len; char *s; len = strlen(str); if (len > YYBUFSIZ) len = YYBUFSIZ; for (s = str; *s != '\0' && len > 0; s++, len--) yytext[yylast++] = *s; yytext[yylast] = '\0'; } static char *yytexttostr(int offset, int max) { char *str; int i; if ((yytext[offset] == '\'' || yytext[offset] == '"') && (yytext[offset] == yytext[offset + max - 1])) { offset++; max--; } if (max > yylast) max = yylast; str = malloc(max + 1); if (str != NULL) { for (i = offset; i < max; i++) str[i - offset] = (char)(yytext[i] & 0xff); str[i - offset] = '\0'; } return (str); } int yylex(void) { int c, n, isbuilding, rval, lnext, nokey = 0; char *name; isbuilding = 0; lnext = 0; rval = 0; if (yystr != NULL) { free(yystr); yystr = NULL; } nextchar: c = yygetc(0); if (yydebug > 1) printf("yygetc = (%x) %c [%*.*s]\n", c, c, yypos, yypos, yytexttochar()); switch (c) { case '\n' : lnext = 0; nokey = 0; /* FALLTHROUGH */ case '\t' : case '\r' : case ' ' : if (isbuilding == 1) { yyunputc(c); goto done; } if (yylast > yypos) { bcopy(yytext + yypos, yytext, sizeof (yytext[0]) * (yylast - yypos + 1)); } yylast -= yypos; yypos = 0; lnext = 0; nokey = 0; goto nextchar; case '\\' : if (lnext == 0) { lnext = 1; if (yylast == yypos) { yylast--; yypos--; } else yypos--; if (yypos == 0) nokey = 1; goto nextchar; } break; } if (lnext == 1) { lnext = 0; if ((isbuilding == 0) && !ISALNUM(c)) { return (c); } goto nextchar; } switch (c) { case '#' : if (isbuilding == 1) { yyunputc(c); goto done; } yyswallow('\n'); rval = YY_COMMENT; goto done; case '$' : if (isbuilding == 1) { yyunputc(c); goto done; } n = yygetc(0); if (n == '{') { if (yyswallow('}') == -1) { rval = -2; goto done; } (void) yygetc(0); } else { if (!ISALPHA(n)) { yyunputc(n); break; } do { n = yygetc(1); } while (ISALPHA(n) || ISDIGIT(n) || n == '_'); yyunputc(n); } name = yytexttostr(1, yypos); /* skip $ */ if (name != NULL) { string_val = get_variable(name, NULL, yylineNum); free(name); if (string_val != NULL) { name = yytexttostr(yypos, yylast); if (name != NULL) { yypos = 0; yylast = 0; yystrtotext(string_val); yystrtotext(name); free(string_val); free(name); goto nextchar; } free(string_val); } } break; case '\'': case '"' : if (isbuilding == 1) { goto done; } do { n = yygetc(1); if (n == EOF || n == TOOLONG) { rval = -2; goto done; } if (n == '\n') { yyunputc(' '); yypos++; } } while (n != c); rval = YY_STR; goto done; /* NOTREACHED */ case EOF : yylineNum = 1; yypos = 0; yylast = -1; yyexpectaddr = 0; yybreakondot = 0; yyvarnext = 0; yytokentype = 0; return (0); } if (strchr("=,/;{}()@", c) != NULL) { if (isbuilding == 1) { yyunputc(c); goto done; } rval = c; goto done; } else if (c == '.') { if (isbuilding == 0) { rval = c; goto done; } if (yybreakondot != 0) { yyunputc(c); goto done; } } switch (c) { case '-' : if (yyexpectaddr) break; if (isbuilding == 1) break; n = yygetc(0); if (n == '>') { isbuilding = 1; goto done; } yyunputc(n); rval = '-'; goto done; case '!' : if (isbuilding == 1) { yyunputc(c); goto done; } n = yygetc(0); if (n == '=') { rval = YY_CMP_NE; goto done; } yyunputc(n); rval = '!'; goto done; case '<' : if (yyexpectaddr) break; if (isbuilding == 1) { yyunputc(c); goto done; } n = yygetc(0); if (n == '=') { rval = YY_CMP_LE; goto done; } if (n == '>') { rval = YY_RANGE_OUT; goto done; } yyunputc(n); rval = YY_CMP_LT; goto done; case '>' : if (yyexpectaddr) break; if (isbuilding == 1) { yyunputc(c); goto done; } n = yygetc(0); if (n == '=') { rval = YY_CMP_GE; goto done; } if (n == '<') { rval = YY_RANGE_IN; goto done; } yyunputc(n); rval = YY_CMP_GT; goto done; } /* * Now for the reason this is here...IPv6 address parsing. * The longest string we can expect is of this form: * 0000:0000:0000:0000:0000:0000:000.000.000.000 * not: * 0000:0000:0000:0000:0000:0000:0000:0000 */ #ifdef USE_INET6 if (isbuilding == 0 && (ishex(c) || c == ':')) { char ipv6buf[45 + 1], *s, oc; int start; start = yypos; s = ipv6buf; oc = c; /* * Perhaps we should implement stricter controls on what we * swallow up here, but surely it would just be duplicating * the code in inet_pton() anyway. */ do { *s++ = c; c = yygetc(1); } while ((ishex(c) || c == ':' || c == '.') && (s - ipv6buf < 46)); yyunputc(c); *s = '\0'; if (inet_pton(AF_INET6, ipv6buf, &yylval.ip6) == 1) { rval = YY_IPV6; yyexpectaddr = 0; goto done; } yypos = start; c = oc; } #endif if (c == ':') { if (isbuilding == 1) { yyunputc(c); goto done; } rval = ':'; goto done; } if (isbuilding == 0 && c == '0') { n = yygetc(0); if (n == 'x') { do { n = yygetc(1); } while (ishex(n)); yyunputc(n); rval = YY_HEX; goto done; } yyunputc(n); } /* * No negative numbers with leading - sign.. */ if (isbuilding == 0 && ISDIGIT(c)) { do { n = yygetc(1); } while (ISDIGIT(n)); yyunputc(n); rval = YY_NUMBER; goto done; } isbuilding = 1; goto nextchar; done: yystr = yytexttostr(0, yypos); if (yydebug) printf("isbuilding %d yyvarnext %d nokey %d\n", isbuilding, yyvarnext, nokey); if (isbuilding == 1) { wordtab_t *w; w = NULL; isbuilding = 0; if ((yyvarnext == 0) && (nokey == 0)) { w = yyfindkey(yystr); if (w == NULL && yywordtab != NULL) { yyresetdict(); w = yyfindkey(yystr); } } else yyvarnext = 0; if (w != NULL) rval = w->w_value; else rval = YY_STR; } if (rval == YY_STR && yysavedepth > 0) yyresetdict(); yytokentype = rval; if (yydebug) printf("lexed(%s) [%d,%d,%d] => %d @%d\n", yystr, string_start, string_end, pos, rval, yysavedepth); switch (rval) { case YY_NUMBER : sscanf(yystr, "%u", &yylval.num); break; case YY_HEX : sscanf(yystr, "0x%x", (uint_t *)&yylval.num); break; case YY_STR : yylval.str = strdup(yystr); break; default : break; } if (yylast > 0) { bcopy(yytext + yypos, yytext, sizeof (yytext[0]) * (yylast - yypos + 1)); yylast -= yypos; yypos = 0; } return (rval); } static wordtab_t *yyfindkey(char *key) { wordtab_t *w; if (yywordtab == NULL) return (NULL); for (w = yywordtab; w->w_word != 0; w++) if (strcasecmp(key, w->w_word) == 0) return (w); return (NULL); } char * yykeytostr(int num) { wordtab_t *w; if (yywordtab == NULL) return (""); for (w = yywordtab; w->w_word; w++) if (w->w_value == num) return (w->w_word); return (""); } wordtab_t * yysettab(wordtab_t *words) { wordtab_t *save; save = yywordtab; yywordtab = words; return (save); } int yyerror(const char *msg) { char *txt, letter[2]; int freetxt = 0; if (yytokentype < 256) { letter[0] = yytokentype; letter[1] = '\0'; txt = letter; } else if (yytokentype == YY_STR || yytokentype == YY_HEX || yytokentype == YY_NUMBER) { if (yystr == NULL) { txt = yytexttostr(yypos, YYBUFSIZ); if (txt == NULL) { fprintf(stderr, "sorry, out of memory," " bailing out\n"); exit(1); } freetxt = 1; } else txt = yystr; } else { txt = yykeytostr(yytokentype); if (txt == NULL) { fprintf(stderr, "sorry, out of memory," " bailing out\n"); exit(1); } } fprintf(stderr, "%s error at \"%s\", line %d\n", msg, txt, yylineNum); if (freetxt == 1) free(txt); exit(1); } void yysetdict(wordtab_t *newdict) { if (yysavedepth == sizeof (yysavewords) / sizeof (yysavewords[0])) { fprintf(stderr, "%d: at maximum dictionary depth\n", yylineNum); return; } yysavewords[yysavedepth++] = yysettab(newdict); if (yydebug) printf("yysavedepth++ => %d\n", yysavedepth); } void yyresetdict(void) { if (yydebug) printf("yyresetdict(%d)\n", yysavedepth); if (yysavedepth > 0) { yysettab(yysavewords[--yysavedepth]); if (yydebug) printf("yysavedepth-- => %d\n", yysavedepth); } } #ifdef TEST_LEXER int main(int argc, char *argv[]) { int n; yyin = stdin; while ((n = yylex()) != 0) printf("%d.n = %d [%s] %d %d\n", yylineNum, n, yystr, yypos, yylast); } #endif #ifndef LEXER_H #define LEXER_H typedef struct wordtab { char *w_word; int w_value; } wordtab_t; #ifdef NO_YACC #define YY_COMMENT 1000 #define YY_CMP_NE 1001 #define YY_CMP_LE 1002 #define YY_RANGE_OUT 1003 #define YY_CMP_GE 1004 #define YY_RANGE_IN 1005 #define YY_HEX 1006 #define YY_NUMBER 1007 #define YY_IPV6 1008 #define YY_STR 1009 #define YY_IPADDR 1010 #endif #define YYBUFSIZ 8192 extern wordtab_t *yysettab __P((wordtab_t *)); extern void yysetdict __P((wordtab_t *)); extern int yylex __P((void)); extern int yyerror __P((const char *)); extern char *yykeytostr __P((int)); extern void yyresetdict __P((void)); extern FILE *yyin; extern int yylineNum; extern int yyexpectaddr; extern int yybreakondot; extern int yyvarnext; #endif /* LEXER_H */