diff -cr ip_fil3.4.4/HISTORY ip_fil3.4.5/HISTORY *** ip_fil3.4.4/HISTORY Mon May 22 23:31:30 2000 --- ip_fil3.4.5/HISTORY Sat Jun 10 00:10:34 2000 *************** *** 20,25 **** --- 20,39 ---- # and especially those who have found the time to port IP Filter to new # platforms. # + 3.4.5 10/06/2000 - Released + + mention -sl in ipfstat.8 + + fix/support '!' in from/to rules (rdr) for NAT + + add from/to support to rdr NAT rules + + don't send ICMP errors in response to ICMP errors + + fix sunos5 compilation for "ipfstat-top" and cleanup ipfboot + + input accounting list used for both outbound and inbound packets + 3.4.4 23/05/2000 - Released don't add TCP state if it is an RST packet and (attempt) to send out diff -cr ip_fil3.4.4/SunOS5/Makefile ip_fil3.4.5/SunOS5/Makefile *** ip_fil3.4.4/SunOS5/Makefile Tue Mar 14 12:09:36 2000 --- ip_fil3.4.5/SunOS5/Makefile Mon Jun 5 23:11:08 2000 *************** *** 59,65 **** pkg: ipf.pkg ipfstat: $(FILS) ! $(CC) $(DEBUG) $(CFLAGS) $(FILS) -o $@ $(LIBS) ipf.exe: $(IPF) $(CC) $(DEBUG) $(CFLAGS) $(IPF) -o $@ $(LIBS) --- 59,65 ---- pkg: ipf.pkg ipfstat: $(FILS) ! $(CC) $(DEBUG) $(CFLAGS) $(FILS) -o $@ $(LIBS) $(STATETOP_LIB) ipf.exe: $(IPF) $(CC) $(DEBUG) $(CFLAGS) $(IPF) -o $@ $(LIBS) *************** *** 81,87 **** (cd test; make ) fils.o: $(TOP)/fils.c $(TOP)/ip_fil.h $(TOP)/ipf.h ! $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/fils.c -o $@ ipfs.o: $(TOP)/ipfs.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_state.h \ $(TOP)/ip_nat.h --- 81,88 ---- (cd test; make ) fils.o: $(TOP)/fils.c $(TOP)/ip_fil.h $(TOP)/ipf.h ! $(CC) $(DEBUG) $(CFLAGS) $(STATETOP_CFLAGS) $(STATETOP_INC) \ ! -c $(TOP)/fils.c -o $@ ipfs.o: $(TOP)/ipfs.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_state.h \ $(TOP)/ip_nat.h diff -cr ip_fil3.4.4/SunOS5/ipfboot ip_fil3.4.5/SunOS5/ipfboot *** ip_fil3.4.4/SunOS5/ipfboot Mon Mar 13 22:33:19 2000 --- ip_fil3.4.5/SunOS5/ipfboot Sat Jun 10 02:01:58 2000 *************** *** 9,18 **** ipf -F a echo "constructing minimal name resolution rules..." NAMESERVERS=`cat /etc/resolv.conf | nawk '/nameserver/ {printf "%s ", $2}'` ! for NS in $NAMESERVERS ! do ! IF_TO_NS=`/usr/sbin/route -n get $NS | nawk '/interface/ {print $NF}'` ! IP_TO_NS=`ifconfig hme0 | head -2 | tail -1 | nawk '{print $2}'` echo "pass out quick proto udp from $IP_TO_NS to $NS port = 53 keep state" | \ ipf -f - done --- 9,19 ---- ipf -F a echo "constructing minimal name resolution rules..." NAMESERVERS=`cat /etc/resolv.conf | nawk '/nameserver/ {printf "%s ", $2}'` ! for NS in $NAMESERVERS ; do ! IF_TO_NS=`/usr/sbin/route -n get $NS | \ ! nawk '$1 == "interface:" { print $NF ; exit }'` ! IP_TO_NS=`ifconfig $IF_TO_NS | \ ! nawk 'NR == "2" { print $2 ; exit }'` echo "pass out quick proto udp from $IP_TO_NS to $NS port = 53 keep state" | \ ipf -f - done *************** *** 28,35 **** fi modload /usr/kernel/drv/ipf if [ -r ${IPFILCONF} ]; then ! BLOCK_DEFAULT=`/sbin/ipf -V | grep Default | nawk '{print $2}'` ! if [ x$BLOCK_DEFAULT = "xblock" ] ; then block_default_workaround fi ipf -IFa -f ${IPFILCONF} --- 29,36 ---- fi modload /usr/kernel/drv/ipf if [ -r ${IPFILCONF} ]; then ! if `/sbin/ipf -V | \ ! nawk '$1 == "Default:" && $2 == "pass" { exit 1 }'` ; then block_default_workaround fi ipf -IFa -f ${IPFILCONF} *************** *** 45,51 **** echo "$0: load of ${IPNATCONF} failed" fi fi ! # ipmon -sn & ;; stop) --- 46,52 ---- echo "$0: load of ${IPNATCONF} failed" fi fi ! ipmon -sn & ;; stop) *************** *** 74,79 **** --- 75,90 ---- fi ;; + reipf) + if [ -r ${IPFILCONF} ]; then + ipf -I -Fa -f ${IPFILCONF} + if [ $? != 0 ]; then + echo "$0: reload of ${IPFILCONF} into alternate set failed" + else + ipf -s + fi + fi + ;; *) echo "Usage: $0 (start|stop|reload)" >&2 exit 1 diff -cr ip_fil3.4.4/SunOS5/pkginfo ip_fil3.4.5/SunOS5/pkginfo *** ip_fil3.4.4/SunOS5/pkginfo Mon May 22 20:27:18 2000 --- ip_fil3.4.5/SunOS5/pkginfo Sat Jun 10 00:10:36 2000 *************** *** 5,11 **** PKG=ipf NAME=IP Filter ARCH=ARCH_updated_by_sed_when_package_is_built ! VERSION=3.4.4 CATEGORY=system DESC=This package contains tools for building a firewall VENDOR=Darren Reed --- 5,11 ---- PKG=ipf NAME=IP Filter ARCH=ARCH_updated_by_sed_when_package_is_built ! VERSION=3.4.5 CATEGORY=system DESC=This package contains tools for building a firewall VENDOR=Darren Reed diff -cr ip_fil3.4.4/fil.c ip_fil3.4.5/fil.c *** ip_fil3.4.4/fil.c Mon May 22 20:26:09 2000 --- ip_fil3.4.5/fil.c Sat Jun 10 00:07:47 2000 *************** *** 7,13 **** */ #if !defined(lint) static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.8 2000/05/22 10:26:09 darrenr Exp $"; #endif #if defined(_KERNEL) && defined(__FreeBSD_version) && \ --- 7,13 ---- */ #if !defined(lint) static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.10 2000/06/09 14:07:47 darrenr Exp $"; #endif #if defined(_KERNEL) && defined(__FreeBSD_version) && \ *************** *** 115,124 **** # if SOLARIS # define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, \ ip, qif) - # define SEND_RESET(ip, qif, if, fin) send_reset(fin, ip, qif) # else /* SOLARIS */ # define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) - # define SEND_RESET(ip, qif, if, fin) send_reset(fin, ip) # endif /* SOLARIS || __sgi */ #endif /* _KERNEL */ --- 115,122 ---- *************** *** 975,984 **** if (out && (pass & FR_PASS)) { #ifdef USE_INET6 if (v == 6) ! list = ipacct6[0][fr_active]; else #endif ! list = ipacct[0][fr_active]; if ((fin->fin_fr = list) && (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { ATOMIC_INCL(frstats[1].fr_acct); --- 973,982 ---- if (out && (pass & FR_PASS)) { #ifdef USE_INET6 if (v == 6) ! list = ipacct6[1][fr_active]; else #endif ! list = ipacct[1][fr_active]; if ((fin->fin_fr = list) && (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { ATOMIC_INCL(frstats[1].fr_acct); *************** *** 1123,1133 **** if (((pass & FR_FASTROUTE) && !out) || (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { ! if (ipfr_fastroute(qif, ip, m, mp, fin, fdp) == 0) m = *mp = NULL; } if (mc) ! ipfr_fastroute(qif, ip, mc, mp, fin, &fr->fr_dif); } # endif /* !SOLARIS */ return (pass & FR_PASS) ? 0 : error; --- 1121,1131 ---- if (((pass & FR_FASTROUTE) && !out) || (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { ! if (ipfr_fastroute(ip, m, mp, fin, fdp) == 0) m = *mp = NULL; } if (mc) ! ipfr_fastroute(ip, mc, mp, fin, &fr->fr_dif); } # endif /* !SOLARIS */ return (pass & FR_PASS) ? 0 : error; *************** *** 1359,1365 **** * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 ! * $Id: fil.c,v 2.35.2.8 2000/05/22 10:26:09 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, --- 1357,1363 ---- * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 ! * $Id: fil.c,v 2.35.2.10 2000/06/09 14:07:47 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, diff -cr ip_fil3.4.4/ip_fil.c ip_fil3.4.5/ip_fil.c *** ip_fil3.4.4/ip_fil.c Mon May 22 23:31:31 2000 --- ip_fil3.4.5/ip_fil.c Fri May 26 06:16:44 2000 *************** *** 7,13 **** */ #if !defined(lint) static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.9 2000/05/22 12:48:28 darrenr Exp $"; #endif #ifndef SOLARIS --- 7,13 ---- */ #if !defined(lint) static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.10 2000/05/25 20:16:44 darrenr Exp $"; #endif #ifndef SOLARIS *************** *** 1088,1093 **** --- 1088,1106 ---- m = NULL; ifp = fin->fin_ifp; if (fin->fin_v == 4) { + if ((oip->ip_p == IPPROTO_ICMP) && + !(fin->fin_fi.fi_fl & FI_SHORT)) + switch (ntohs(fin->fin_data[0]) >> 8) + { + case ICMP_ECHO : + case ICMP_TSTAMP : + case ICMP_IREQ : + case ICMP_MASKREQ : + break; + default : + return 0; + } + # if (BSD < 199306) || defined(__sgi) avail = MLEN; m = m_get(M_DONTWAIT, MT_HEADER); diff -cr ip_fil3.4.4/ip_fil.h ip_fil3.4.5/ip_fil.h *** ip_fil3.4.4/ip_fil.h Mon May 22 20:26:13 2000 --- ip_fil3.4.5/ip_fil.h Mon Jun 5 23:12:42 2000 *************** *** 6,12 **** * to the original author and the contributors. * * @(#)ip_fil.h 1.35 6/5/96 ! * $Id: ip_fil.h,v 2.29.2.2 2000/05/22 10:26:13 darrenr Exp $ */ #ifndef __IP_FIL_H__ --- 6,12 ---- * to the original author and the contributors. * * @(#)ip_fil.h 1.35 6/5/96 ! * $Id: ip_fil.h,v 2.29.2.3 2000/06/05 13:12:42 darrenr Exp $ */ #ifndef __IP_FIL_H__ *************** *** 519,526 **** extern int iplopen __P((dev_t *, int, int, cred_t *)); extern int iplclose __P((dev_t, int, int, cred_t *)); extern int ipfsync __P((void)); ! extern int ipfr_fastroute __P((qif_t *, ip_t *, mblk_t *, mblk_t **, ! fr_info_t *, frdest_t *)); extern void copyin_mblk __P((mblk_t *, size_t, size_t, char *)); extern void copyout_mblk __P((mblk_t *, size_t, size_t, char *)); extern int fr_qin __P((queue_t *, mblk_t *)); --- 519,526 ---- extern int iplopen __P((dev_t *, int, int, cred_t *)); extern int iplclose __P((dev_t, int, int, cred_t *)); extern int ipfsync __P((void)); ! extern int ipfr_fastroute __P((ip_t *, mblk_t *, mblk_t **, ! fr_info_t *, frdest_t *)); extern void copyin_mblk __P((mblk_t *, size_t, size_t, char *)); extern void copyout_mblk __P((mblk_t *, size_t, size_t, char *)); extern int fr_qin __P((queue_t *, mblk_t *)); *************** *** 529,536 **** # else /* SOLARIS */ extern int fr_check __P((ip_t *, int, void *, int, mb_t **)); extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **)); - extern int send_reset __P((struct ip *, fr_info_t *)); - extern int send_icmp_err __P((ip_t *, int, fr_info_t *, int)); extern int ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *)); extern size_t mbufchainlen __P((mb_t *)); # ifdef __sgi --- 529,534 ---- diff -cr ip_fil3.4.4/ip_frag.c ip_fil3.4.5/ip_frag.c *** ip_fil3.4.4/ip_frag.c Sat May 6 01:10:23 2000 --- ip_fil3.4.5/ip_frag.c Wed Jun 7 01:49:15 2000 *************** *** 7,13 **** */ #if !defined(lint) static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.3 2000/05/05 15:10:23 darrenr Exp $"; #endif #if defined(KERNEL) && !defined(_KERNEL) --- 7,13 ---- */ #if !defined(lint) static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.4 2000/06/06 15:49:15 darrenr Exp $"; #endif #if defined(KERNEL) && !defined(_KERNEL) *************** *** 143,148 **** --- 143,151 ---- { ipfr_t **fp, *fra, frag; u_int idx; + + if (ipfr_inuse >= IPFT_SIZE) + return NULL; frag.ipfr_p = ip->ip_p; idx = ip->ip_p; diff -cr ip_fil3.4.4/ip_nat.c ip_fil3.4.5/ip_nat.c *** ip_fil3.4.4/ip_nat.c Sat May 20 01:54:44 2000 --- ip_fil3.4.5/ip_nat.c Mon Jun 5 23:09:54 2000 *************** *** 9,15 **** */ #if !defined(lint) static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.10 2000/05/19 15:54:44 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) --- 9,15 ---- */ #if !defined(lint) static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.12 2000/06/05 13:09:54 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) *************** *** 1714,1727 **** if (np->in_p && ip->ip_p != np->in_p) return 0; if (fin->fin_out) { ! if (!(np->in_redir && (NAT_MAP|NAT_MAPBLK))) return 0; ! if ((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip) return 0; ! if ((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip) return 0; } else { ! if (!(np->in_redir && NAT_REDIRECT)) return 0; } --- 1714,1735 ---- if (np->in_p && ip->ip_p != np->in_p) return 0; if (fin->fin_out) { ! if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) return 0; ! if (((fin->fin_fi.fi_saddr & np->in_inmsk) == np->in_inip) ! ^ (np->in_flags & IPN_NOTSRC)) return 0; ! if (((fin->fin_fi.fi_daddr & np->in_srcmsk) == np->in_srcip) ! ^ (np->in_flags & IPN_NOTDST)) return 0; } else { ! if (!(np->in_redir & NAT_REDIRECT)) ! return 0; ! if (((fin->fin_fi.fi_saddr & np->in_srcmsk) == np->in_srcip) ! ^ (np->in_flags & IPN_NOTSRC)) ! return 0; ! if (((fin->fin_fi.fi_daddr & np->in_inmsk) == np->in_inip) ! ^ (np->in_flags & IPN_NOTDST)) return 0; } diff -cr ip_fil3.4.4/ip_nat.h ip_fil3.4.5/ip_nat.h *** ip_fil3.4.4/ip_nat.h Mon May 15 16:50:14 2000 --- ip_fil3.4.5/ip_nat.h Mon May 29 03:27:08 2000 *************** *** 6,12 **** * to the original author and the contributors. * * @(#)ip_nat.h 1.5 2/4/96 ! * $Id: ip_nat.h,v 2.17.2.1 2000/05/15 06:50:14 darrenr Exp $ */ #ifndef __IP_NAT_H__ --- 6,12 ---- * to the original author and the contributors. * * @(#)ip_nat.h 1.5 2/4/96 ! * $Id: ip_nat.h,v 2.17.2.2 2000/05/28 17:27:08 darrenr Exp $ */ #ifndef __IP_NAT_H__ *************** *** 212,222 **** #define IPN_RF (IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR) #define IPN_AUTOPORTMAP 0x010 #define IPN_IPRANGE 0x020 ! #define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|\ ! IPN_SPLIT|IPN_ROUNDR|IPN_FILTER) #define IPN_FILTER 0x040 #define IPN_SPLIT 0x080 #define IPN_ROUNDR 0x100 typedef struct natlog { --- 212,224 ---- #define IPN_RF (IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR) #define IPN_AUTOPORTMAP 0x010 #define IPN_IPRANGE 0x020 ! #define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|IPN_SPLIT|\ ! IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST) #define IPN_FILTER 0x040 #define IPN_SPLIT 0x080 #define IPN_ROUNDR 0x100 + #define IPN_NOTSRC 0x080000 + #define IPN_NOTDST 0x100000 typedef struct natlog { diff -cr ip_fil3.4.4/ipl.h ip_fil3.4.5/ipl.h *** ip_fil3.4.4/ipl.h Mon May 22 20:26:16 2000 --- ip_fil3.4.5/ipl.h Sat Jun 10 00:10:33 2000 *************** *** 6,17 **** * to the original author and the contributors. * * @(#)ipl.h 1.21 6/5/96 ! * $Id: ipl.h,v 2.15.2.5 2000/05/22 10:26:16 darrenr Exp $ */ #ifndef __IPL_H__ #define __IPL_H__ ! #define IPL_VERSION "IP Filter: v3.4.4" #endif --- 6,17 ---- * to the original author and the contributors. * * @(#)ipl.h 1.21 6/5/96 ! * $Id: ipl.h,v 2.15.2.6 2000/06/09 14:10:33 darrenr Exp $ */ #ifndef __IPL_H__ #define __IPL_H__ ! #define IPL_VERSION "IP Filter: v3.4.5" #endif diff -cr ip_fil3.4.4/man/ipfstat.8 ip_fil3.4.5/man/ipfstat.8 *** ip_fil3.4.4/man/ipfstat.8 Mon Feb 28 19:27:53 2000 --- ip_fil3.4.5/man/ipfstat.8 Sat Jun 3 14:56:52 2000 *************** *** 99,106 **** protocol are specified. .TP .B \-s ! Show packet/flow state information (statistics) and held state information (in ! the kernel) if any is present. .TP .BR \-S \0 This option is only valid in combination with \fB\-t\fP. Limit the state top --- 99,108 ---- protocol are specified. .TP .B \-s ! Show packet/flow state information (statistics only). ! .TP ! .B \-sl ! Show held state information (in the kernel) if any is present (no statistics). .TP .BR \-S \0 This option is only valid in combination with \fB\-t\fP. Limit the state top diff -cr ip_fil3.4.4/natparse.c ip_fil3.4.5/natparse.c *** ip_fil3.4.4/natparse.c Sat Apr 29 04:08:00 2000 --- ip_fil3.4.5/natparse.c Mon Jun 5 23:12:06 2000 *************** *** 54,60 **** #if !defined(lint) static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: natparse.c,v 1.17.2.1 2000/04/28 18:08:00 darrenr Exp $"; #endif --- 54,60 ---- #if !defined(lint) static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: natparse.c,v 1.17.2.2 2000/06/05 13:12:06 darrenr Exp $"; #endif *************** *** 103,108 **** --- 103,110 ---- printf(" %s ", np->in_ifname); if (np->in_flags & IPN_FILTER) { + if (np->in_flags & IPN_NOTSRC) + printf("! "); printf("from "); if (np->in_redir == NAT_REDIRECT) printhostmask(4, (u_32_t *)&np->in_srcip, *************** *** 113,118 **** --- 115,122 ---- if (np->in_scmp) printportcmp(np->in_p, &np->in_tuc.ftu_src); + if (np->in_flags & IPN_NOTDST) + printf(" !"); printf(" to "); if (np->in_redir == NAT_REDIRECT) printhostmask(4, (u_32_t *)&np->in_inip, *************** *** 312,318 **** ipn.in_ifname[sizeof(ipn.in_ifname) - 1] = '\0'; cpp++; ! if (!strcasecmp(*cpp, "from")) { ipn.in_flags |= IPN_FILTER; cpp++; if (ipn.in_redir == NAT_REDIRECT) { --- 316,337 ---- ipn.in_ifname[sizeof(ipn.in_ifname) - 1] = '\0'; cpp++; ! if (!strcasecmp(*cpp, "from") || (**cpp == '!')) { ! if (!strcmp(*cpp, "!")) { ! cpp++; ! if (strcasecmp(*cpp, "from")) { ! fprintf(stderr, "Missing from after !\n"); ! return NULL; ! } ! ipn.in_flags |= IPN_NOTSRC; ! } else if (**cpp == '!') { ! if (strcasecmp(*cpp + 1, "from")) { ! fprintf(stderr, "Missing from after !\n"); ! return NULL; ! } ! ipn.in_flags |= IPN_NOTSRC; ! } ! ipn.in_flags |= IPN_FILTER; cpp++; if (ipn.in_redir == NAT_REDIRECT) { *************** *** 331,336 **** --- 350,363 ---- } } + if (!strcmp(*cpp, "!")) { + cpp++; + ipn.in_flags |= IPN_NOTDST; + } else if (**cpp == '!') { + (*cpp)++; + ipn.in_flags |= IPN_NOTDST; + } + if (strcasecmp(*cpp, "to")) { fprintf(stderr, "%d: unexpected keyword (%s) - to\n", linenum, *cpp); *************** *** 741,747 **** fp = stdin; while (fgets(line, sizeof(line) - 1, fp)) { ! linenum++; line[sizeof(line) - 1] = '\0'; if ((s = strchr(line, '\n'))) *s = '\0'; --- 768,774 ---- fp = stdin; while (fgets(line, sizeof(line) - 1, fp)) { ! linenum++; line[sizeof(line) - 1] = '\0'; if ((s = strchr(line, '\n'))) *s = '\0';