diff --git a/sys/netinet/ip_auth.h b/sys/netinet/ip_auth.h index c80b462df148..d56ed2f2150d 100644 --- a/sys/netinet/ip_auth.h +++ b/sys/netinet/ip_auth.h @@ -1,4 +1,4 @@ -/* $NetBSD: ip_auth.h,v 1.1.1.1 1997/07/06 04:58:52 thorpej Exp $ */ +/* $NetBSD: ip_auth.h,v 1.1.1.2 1997/09/21 16:49:28 veego Exp $ */ /* * (C)opyright 1997 by Darren Reed & Guido Van Rooij. @@ -7,7 +7,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * Id: ip_auth.h,v 2.0.2.8 1997/06/23 04:52:53 darrenr Exp + * Id: ip_auth.h,v 2.0.2.8 1997/06/23 04:52:53 darrenr Exp * */ #ifndef __IP_AUTH_H__ diff --git a/sys/netinet/ip_log.c b/sys/netinet/ip_log.c new file mode 100644 index 000000000000..279d1feae011 --- /dev/null +++ b/sys/netinet/ip_log.c @@ -0,0 +1,432 @@ +/* $NetBSD: ip_log.c,v 1.1.1.1 1997/09/21 16:49:48 veego Exp $ */ + +/* + * (C)opyright 1997 by Darren Reed. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. + * + * Id: ip_log.c,v 2.0.2.6 1997/09/10 13:08:18 darrenr Exp + */ +#ifdef IPFILTER_LOG +# ifndef SOLARIS +# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +# endif + +# ifdef __FreeBSD__ +# if defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL +# endif +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include +# else +# include +# endif +# endif +# ifndef _KERNEL +# include +# include +# include +# include +# endif +# include +# include +# include +# include +# if __FreeBSD_version >= 220000 && defined(_KERNEL) +# include +# include +# else +# include +# endif +# include +# ifdef _KERNEL +# include +# endif +# include +# if !SOLARIS +# if NetBSD > 199609 +# include +# else +# include +# endif +# include +# else +# include +# include +# include +# include +# include +# include +# include +# include +# include +# endif +# include +# include + +# include +# ifdef sun +# include +# endif +# if __FreeBSD_version >= 300000 +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# ifndef _KERNEL +# include +# endif +# include "netinet/ip_compat.h" +# include "netinet/ip_fil.h" +# include "netinet/ip_proxy.h" +# include "netinet/ip_nat.h" +# include "netinet/ip_frag.h" +# include "netinet/ip_state.h" +# include "netinet/ip_auth.h" +# ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +# endif + + +#if SOLARIS +extern kmutex_t ipl_mutex; +extern kcondvar_t iplwait; +#endif + +iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1]; +int iplused[IPL_LOGMAX+1]; +u_long iplcrc[IPL_LOGMAX+1]; +u_long iplcrcinit; + + +/* + * Initialise log buffers & pointers. Also iniialised the CRC to a local + * secret for use in calculating the "last log checksum". + */ +void ipflog_init() +{ + struct timeval tv; + int i; + + for (i = IPL_LOGMAX; i >= 0; i--) { + iplt[i] = NULL; + iplh[i] = &iplt[i]; + iplused[i] = 0; + } +# if BSD >= 199306 || defined(__FreeBSD__) + microtime(&tv); +# else + uniqtime(&tv); +# endif + iplcrcinit = tv.tv_sec ^ (tv.tv_usec << 8) ^ tv.tv_usec; +} + + +/* + * ipflog + * Create a log record for a packet given that it has been triggered by a + * rule (or the default setting). Calculate the transport protocol header + * size using predetermined size of a couple of popular protocols and thus + * how much data to copy into the log, including part of the data body if + * requested. + */ +int ipflog(flags, ip, fin, m) +u_int flags; +ip_t *ip; +fr_info_t *fin; +mb_t *m; +{ + ipflog_t ipfl; + register int mlen, hlen; + u_long crc; + size_t sizes[2]; + void *ptrs[2]; + int types[2]; +# if SOLARIS + ill_t *ifp = fin->fin_ifp; +# else + struct ifnet *ifp = fin->fin_ifp; +# endif + + /* + * calculate header size. + */ + hlen = fin->fin_hlen; + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) + hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); + else if (ip->ip_p == IPPROTO_ICMP) { + struct icmp *icmp = (struct icmp *)((char *)ip + hlen); + + /* + * For ICMP, if the packet is an error packet, also include + * the information about the packet which caused the error. + */ + switch (icmp->icmp_type) + { + case ICMP_UNREACH : + case ICMP_SOURCEQUENCH : + case ICMP_REDIRECT : + case ICMP_TIMXCEED : + case ICMP_PARAMPROB : + hlen += MIN(sizeof(struct icmp) + 8, fin->fin_dlen); + break; + default : + hlen += MIN(sizeof(struct icmp), fin->fin_dlen); + break; + } + } + /* + * Get the interface number and name to which this packet is + * currently associated. + */ +# if SOLARIS + ipfl.fl_unit = (u_char)ifp->ill_ppa; + bcopy(ifp->ill_name, ipfl.fl_ifname, MIN(ifp->ill_name_length, 4)); + mlen = (flags & FR_LOGBODY) ? MIN(msgdsize(m) - hlen, 128) : 0; +# else +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) + strncpy(ipfl.fl_ifname, ifp->if_xname, IFNAMSIZ); +# else + ipfl.fl_unit = (u_char)ifp->if_unit; + if ((ipfl.fl_ifname[0] = ifp->if_name[0])) + if ((ipfl.fl_ifname[1] = ifp->if_name[1])) + if ((ipfl.fl_ifname[2] = ifp->if_name[2])) + ipfl.fl_ifname[3] = ifp->if_name[3]; +# endif + mlen = (flags & FR_LOGBODY) ? MIN(ip->ip_len - hlen, 128) : 0; +# endif + ipfl.fl_plen = (u_char)mlen; + ipfl.fl_hlen = (u_char)hlen; + ipfl.fl_rule = fin->fin_rule; + ipfl.fl_flags = flags; + ptrs[0] = (void *)&ipfl; + sizes[0] = sizeof(ipfl); + types[0] = 0; +#if SOLARIS + /* + * Are we copied from the mblk or an aligned array ? + */ + if (ip == (ip_t *)m->b_rptr) { + ptrs[1] = m; + sizes[1] = hlen + mlen; + types[1] = 1; + } else { + ptrs[1] = ip; + sizes[1] = hlen + mlen; + types[1] = 0; + } +#else + ptrs[1] = m; + sizes[1] = hlen + mlen; + types[1] = 1; +#endif + crc = (ipf_cksum((u_short *)fin, FI_CSIZE) << 8) + iplcrcinit; + return ipllog(IPL_LOGIPF, crc, ptrs, sizes, types, 2); +} + + +/* + * ipllog + */ +int ipllog(dev, crc, items, itemsz, types, cnt) +int dev; +u_long crc; +void **items; +size_t *itemsz; +int *types, cnt; +{ + iplog_t *ipl; + caddr_t buf, s; + int len, i; + + /* + * Check to see if this log record has a CRC which matches the last + * record logged. If it does, just up the count on the previous one + * rather than create a new one. + */ + if (crc) { + MUTEX_ENTER(&ipl_mutex); + if ((iplcrc[dev] == crc) && *iplh[dev]) { + (*iplh[dev])->ipl_count++; + MUTEX_EXIT(&ipl_mutex); + return 1; + } + iplcrc[dev] = crc; + MUTEX_EXIT(&ipl_mutex); + } + + /* + * Get the total amount of data to be logged. + */ + for (i = 0, len = sizeof(iplog_t); i < cnt; i++) + len += itemsz[i]; + + /* + * check that we have space to record this information and can + * allocate that much. + */ + KMALLOC(buf, caddr_t, len); + if (!buf) + return 0; + MUTEX_ENTER(&ipl_mutex); + if ((iplused[dev] + len) > IPLLOGSIZE) { + MUTEX_EXIT(&ipl_mutex); + KFREES(buf, len); + return 0; + } + iplused[dev] += len; + MUTEX_EXIT(&ipl_mutex); + + /* + * advance the log pointer to the next empty record and deduct the + * amount of space we're going to use. + */ + ipl = (iplog_t *)buf; + ipl->ipl_count = 1; + ipl->ipl_next = NULL; + ipl->ipl_dsize = len; +# if SOLARIS + uniqtime((struct timeval *)&ipl->ipl_sec); +# else +# ifdef sun + uniqtime((struct timeval *)&ipl->ipl_sec); +# endif +# if BSD >= 199306 || defined(__FreeBSD__) + microtime((struct timeval *)&ipl->ipl_sec); +# endif +# endif + + /* + * Loop through all the items to be logged, copying each one to the + * buffer. Use bcopy for normal data or the mb_t copyout routine. + */ + for (i = 0, s = buf + sizeof(*ipl); i < cnt; i++) { + if (types[i] == 0) + bcopy(items[i], s, itemsz[i]); + else if (types[i] == 1) { +# if SOLARIS + copyout_mblk(items[i], 0, itemsz[i], s); +# else + m_copydata(items[i], 0, itemsz[i], s); +# endif + } + s += itemsz[i]; + } + MUTEX_ENTER(&ipl_mutex); + *iplh[dev] = ipl; + iplh[dev] = &ipl->ipl_next; +# if SOLARIS + cv_signal(&iplwait); + mutex_exit(&ipl_mutex); +# else + wakeup(iplh[dev]); +# endif + return 1; +} + + +int ipflog_read(unit, uio) +int unit; +struct uio *uio; +{ + iplog_t *ipl; + int error = 0, dlen; +# if defined(_KERNEL) && !SOLARIS + int s; +# endif + + /* + * Sanity checks. Make sure the minor # is valid and we're copying + * a valid chunk of data. + */ + if ((IPL_LOGMAX < unit) || (unit < 0)) + return ENXIO; + if (!uio->uio_resid) + return 0; + if ((uio->uio_resid < sizeof(iplog_t)) || + (uio->uio_resid > IPLLOGSIZE)) + return EINVAL; + + /* + * Lock the log so we can snapshot the variables. Wait for a signal + * if the log is empty. + */ + SPLNET(s); + MUTEX_ENTER(&ipl_mutex); + +# if SOLARIS && defined(_KERNEL) + while (!iplused[unit]) + if (!cv_wait_sig(&iplwait, &ipl_mutex)) { + MUTEX_EXIT(&ipl_mutex); + return EINTR; + } +# else + while (!iplused[unit]) { + SPLX(s); + error = SLEEP(iplh[unit], "ipl sleep"); + if (error) + return error; + SPLNET(s); + } +# endif + +# if BSD >= 199306 || defined(__FreeBSD__) + uio->uio_rw = UIO_READ; +# endif + + while ((ipl = iplt[unit])) { + dlen = ipl->ipl_dsize; + if (dlen + sizeof(iplog_t) > uio->uio_resid) + break; + /* + * Don't hold the mutex over the uiomove call. + */ + iplt[unit] = ipl->ipl_next; + MUTEX_EXIT(&ipl_mutex); + SPLX(s); + error = UIOMOVE((caddr_t)ipl, ipl->ipl_dsize, UIO_READ, uio); + KFREES((caddr_t)ipl, ipl->ipl_dsize); + if (error) + break; + SPLNET(s); + MUTEX_ENTER(&ipl_mutex); + iplused[unit] -= dlen; + } + if (!ipl) + iplh[unit] = &iplt[unit]; + + if (!error) { + MUTEX_EXIT(&ipl_mutex); + SPLX(s); + } + return error; +} + + +int ipflog_clear(unit) +int unit; +{ + iplog_t *ipl; + int used; + + while ((ipl = iplt[unit])) { + iplt[unit] = ipl->ipl_next; + KFREES((caddr_t)ipl, ipl->ipl_dsize); + } + iplh[unit] = &iplt[unit]; + used = iplused[unit]; + iplused[unit] = 0; + iplcrc[unit] = 0; + return used; +} +#endif /* IPFILTER_LOG */ diff --git a/usr.sbin/ipf/ipf/ipf.4 b/usr.sbin/ipf/ipf/ipf.4 index ebeacebb0b16..6cf9f204ef89 100644 --- a/usr.sbin/ipf/ipf/ipf.4 +++ b/usr.sbin/ipf/ipf/ipf.4 @@ -2,7 +2,8 @@ .SH NAME ipf \- packet filtering kernel interface .SH SYNOPSIS -#include +#include +#include .SH IOCTLS .PP To add and delete rules to the filter list, three 'basic' ioctls are provided @@ -41,10 +42,17 @@ which it is inserted is stored in the "fr_hits" field, below. .nf typedef struct frentry { struct frentry *fr_next; + u_short fr_group; /* group to which this rule belongs */ + u_short fr_head; /* group # which this rule starts */ + struct frentry *fr_grp; + int fr_ref; /* reference count - for grouping */ struct ifnet *fr_ifa; - u_long fr_hits; - u_long fr_bytes; /* this is only incremented when a packet */ - /* stops matching on this rule */ + /* + * These are only incremented when a packet matches this rule and + * it is the last match + */ + U_QUAD_T fr_hits; + U_QUAD_T fr_bytes; /* * Fields after this may not change whilst in the kernel. */ @@ -64,6 +72,7 @@ typedef struct frentry { u_short fr_stop; /* top port for <> and >< */ u_short fr_dtop; /* top port for <> and >< */ u_long fr_flags; /* per-rule flags && options (see below) */ + int fr_skip; /* # of rules to skip */ int (*fr_func)(); /* call this function */ char fr_icode; /* return ICMP code */ char fr_ifname[IFNAMSIZ]; @@ -81,26 +90,31 @@ be put in the "fr_hits" field (the first rule is number 0). Flags which are recognised in fr_pass: .nf - FR_BLOCK 0x00001 /* do not allow packet to pass */ - FR_PASS 0x00002 /* allow packet to pass */ - FR_OUTQUE 0x00004 /* outgoing packets */ - FR_INQUE 0x00008 /* ingoing packets */ - FR_LOG 0x00010 /* Log */ - FR_LOGP 0x00011 /* Log-pass */ - FR_LOGB 0x00012 /* Log-fail */ - FR_LOGBODY 0x00020 /* log the body of packets too */ - FR_LOGFIRST 0x00040 /* log only the first packet to match */ - FR_RETRST 0x00080 /* return a TCP RST packet if blocked */ - FR_RETICMP 0x00100 /* return an ICMP packet if blocked */ - FR_NOMATCH 0x00200 /* no match occured */ - FR_ACCOUNT 0x00400 /* count packet bytes */ - FR_KEEPFRAG 0x00800 - FR_KEEPSTATE 0x01000 /* keep packet flow state information */ - FR_INACTIVE 0x02000 - FR_QUICK 0x04000 /* quick-match and return */ - FR_FASTROUTE 0x08000 - FR_CALLNOW 0x10000 - FR_DUP 0x20000 /* duplicate the packet (not Solaris2) + FR_BLOCK 0x000001 /* do not allow packet to pass */ + FR_PASS 0x000002 /* allow packet to pass */ + FR_OUTQUE 0x000004 /* outgoing packets */ + FR_INQUE 0x000008 /* ingoing packets */ + FR_LOG 0x000010 /* Log */ + FR_LOGP 0x000011 /* Log-pass */ + FR_LOGB 0x000012 /* Log-fail */ + FR_LOGBODY 0x000020 /* log the body of packets too */ + FR_LOGFIRST 0x000040 /* log only the first packet to match */ + FR_RETRST 0x000080 /* return a TCP RST packet if blocked */ + FR__RETICMP 0x000100 /* return an ICMP packet if blocked */ + FR_NOMATCH 0x000200 /* no match occured */ + FR_ACCOUNT 0x000400 /* count packet bytes */ + FR_KEEPFRAG 0x000800 /* keep fragment information */ + FR_KEEPSTATE 0x001000 /* keep `connection' state information */ + FR_INACTIVE 0x002000 + FR_QUICK 0x004000 /* match & stop processing list */ + FR_FASTROUTE 0x008000 /* bypass normal routing */ + FR_CALLNOW 0x010000 /* call another function (fr_func) if matches */ + FR_DUP 0x020000 /* duplicate the packet */ + FR_LOGORBLOCK 0x040000 /* block the packet if it can't be logged */ + FR_NOTSRCIP 0x080000 /* not the src IP# */ + FR_NOTDSTIP 0x100000 /* not the dst IP# */ + FR_AUTH 0x200000 /* use authentication */ + FR_PREAUTH 0x400000 /* require preauthentication */ .fi .PP @@ -134,8 +148,10 @@ Takes an unsigned integer as the parameter. The flags are then set to those provided (clearing/setting all in one). .nf - FF_LOGPASS 1 - FF_LOGBLOCK 2 + FF_LOGPASS 0x10000000 + FF_LOGBLOCK 0x20000000 + FF_LOGNOMATCH 0x40000000 + FF_BLOCKNONIP 0x80000000 /* Solaris 2.x only */ .fi .IP SIOCGETFF 16 Takes a pointer to an unsigned integer as the parameter. A copy of the @@ -149,10 +165,14 @@ through the kernel. To retrieve this structure, use this ioctl: ioctl(fd, SIOCGETFS, struct friostat *) -struct friostat { - struct filterstats f_st[2]; - struct frentry *f_fin; - struct frentry *f_fout; +struct friostat { + struct filterstats f_st[2]; + struct frentry *f_fin[2]; + struct frentry *f_fout[2]; + struct frentry *f_acctin[2]; + struct frentry *f_acctout[2]; + struct frentry *f_auth; + int f_active; }; struct filterstats { @@ -172,6 +192,7 @@ struct filterstats { u_long fr_bads; /* bad attempts to allocate packet state */ u_long fr_ads; /* new packet state kept */ u_long fr_chit; /* cached hit */ + u_long fr_pull[2]; /* good and bad pullup attempts */ #if SOLARIS u_long fr_bad; /* bad IP packets to the filter */ u_long fr_notip; /* packets passed through no on ip queue */ diff --git a/usr.sbin/ipf/ipf/ipf.5 b/usr.sbin/ipf/ipf/ipf.5 index 5ba80548ff5d..c202be71f6a0 100644 --- a/usr.sbin/ipf/ipf/ipf.5 +++ b/usr.sbin/ipf/ipf/ipf.5 @@ -18,28 +18,26 @@ The format used by \fBipf\fP for construction of filtering rules can be described using the following grammar in BNF: \fC .nf -filter-rule = [ insert ] action in-out [ options ] [ match ] [ keep ] +filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ] + [ proto ] [ ip ] [ group ]. insert = "@" decnumber . -action = block | "pass" | log | "count" | skip | "auth" | "preauth" | call . +action = block | "pass" | log | "count" | skip | auth | call . in-out = "in" | "out" . options = [ log ] [ "quick" ] [ "on" interface-name [ dup ] [ froute ] ] . -match = [ tos ] [ ttl ] [ proto ] [ ip ] . -keep = "keep state" | "keep frags" . +tos = "tos" decnumber | "tos" hexnumber . +ttl = "ttl" decnumber . +proto = "proto" protocol . +ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] . +group = [ "head" decnumber ] [ "group" decnumber ] . block = "block" [ "return-icmp"[return-code] | "return-rst" ] . -log = "log" [ "body" ] [ "first" ] [ "or-block" ] . -call = "call" [ "now" ] function-name . +auth = "auth" | "preauth" . +log = "log" [ "body" ] [ "first" ] [ "or-block" ] . +call = "call" [ "now" ] function-name . skip = "skip" decnumber . - -dup = "dup-to" interface-name[":"ipaddr] . +dup = "dup-to" interface-name[":"ipaddr] . froute = "fastroute" | "to" interface-name . - -tos = "tos" decnumber | "tos" hexnumber . -ttl = "ttl" decnumber . -proto = "proto" protocol . -ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] . - protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber . srcdst = "all" | fromto . fromto = "from" object "to" object . @@ -48,11 +46,11 @@ object = addr [ port-comp | port-range ] . addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . port-comp = "port" compare port-num . port-range = "port" port-num range port-num . - flags = "flags" flag { flag } [ "/" flag { flag } ] . with = "with" | "and" . icmp = "icmp-type" icmp-type [ "code" decnumber ] . return-code = "("icmp-code")" . +keep = "keep" "state" | "keep" "frags" . nummask = host-name [ "/" decnumber ] . host-name = ipaddr | hostname | "any" . @@ -73,16 +71,16 @@ icmp-type = "unreach" | "echo" | "echorep" | "squench" | "redir" | icmp-code = decumber | "net-unr" | "host-unr" | "proto-unr" | "port-unr" | "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" | "net-prohib" | "host-prohib" | "net-tos" | "host-tos" . -optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | "tr" | - "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | "addext" | - "visa" | "imitd" | "eip" | "finn" . +optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | + "tr" | "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | + "addext" | "visa" | "imitd" | "eip" | "finn" . hexnumber = "0" "x" hexstring . hexstring = hexdigit [ hexstring ] . decnumber = digit [ decnumber ] . -compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" | "gt" | - "le" | "ge" . +compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" | + "gt" | "le" | "ge" . range = "<>" | "><" . hexdigit = digit | "a" | "b" | "c" | "d" | "e" | "f" . digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" . @@ -95,19 +93,10 @@ not make sense (such as tcp \fBflags\fP for non-TCP packets). .SH FILTER RULES .PP The "briefest" valid rules are (currently) no-ops and are of the form: -.nf - block in - pass in - log in - count in -.fi -.PP -These are supposed to be the same as, but currently differ from: -.\" XXX How, why do they differ?? .nf block in all - pass in from any to any - log in all + pass in all + log out all count in all .fi .PP @@ -154,6 +143,12 @@ must conform to a specific calling interface. Customised actions and semantics can thus be implemented to supplement those available. This feature is for use by knowledgeable hackers, and is not currently documented. +.TP +.B "skip " +.TP +.B auth +.TP +.B preauth .PP The next word must be either \fBin\fP or \fBout\fP. Each packet moving through the kernel is either inbound (just been received on an @@ -222,7 +217,6 @@ packets with different Type-Of-Service values can be filtered. Individual service levels or combinations can be filtered upon. The value for the TOS mask can either be represented as a hex number or a decimal integer value. -.\" XXX TOS mask?? not in grammar! .TP .B ttl packets may also be selected by their Time-To-Live value. The value given in @@ -357,8 +351,9 @@ with which they are associated can be used. The most important from a security point of view is the ICMP redirect. .SH KEEP HISTORY .PP -The last parameter which can be set for a filter rule is whether on not to -record historical information for that packet, and what sort to keep. The following information can be kept: +The second last parameter which can be set for a filter rule is whether on not +to record historical information for that packet, and what sort to keep. The +following information can be kept: .TP .B state keeps information about the flow of a communication session. State can @@ -370,6 +365,23 @@ fragments. .PP allowing packets which match these to flow straight through, rather than going through the access control list. +.SH GROUPS +The last pair of parameters control filter rule "grouping". By default, all +filter rules are placed in group 0 if no other group is specified. To add a +rule to a non-default group, the group must first be started by creating a +group \fIhead\fP. If a packet matches a rule which is the \fIhead\fP of a +group, the filter processing then switches to the group, using that rule as +the default for the group. If \fBquick\fP is used with a \fBhead\fP rule, rule +processing isn't stopped until it has returned from processing the group. +.PP +A rule may be both the head for a new group and a member of a non-default +group (\fBhead\fP and \fBgroup\fP may be used together in a rule). +.TP +.B "head " +indicates that a new group (number n) should be created. +.TP +.B "group " +indicates that the rule should be put in group (number n) rather than group 0. .SH LOGGING .PP When a packet is logged, with either the \fBlog\fP action or option, @@ -428,7 +440,42 @@ rule such as: pass in quick from any to any port < 1024 .fi .PP -would be needed before the first block. +would be needed before the first block. To create a new group for +processing all inbould packets on le0/le1/lo0, with the default being to block +all inbound packets, we would do something like: +.LP +.nf + block in all + block in on le0 quick all head 100 + block in on le1 quick all head 200 + block in on lo0 quick all head 300 +.fi +.PP + +and to then allow ICMP packets in on le0, only, we would do: +.LP +.nf + pass in proto icmp all group 100 +.fi +.PP +Note that because only inbound packets on le0 are used processed by group 100, +there is no need to respecify the interface name. Likewise, we could further +breakup processing of TCP, etc, as follows: +.LP +.nf + block in proto tcp all head 110 group 100 + pass in from any to any port = 23 group 110 +.fi +.PP +and so on. The last line, if written without the groups would be: +.LP +.nf + pass in on le0 proto tcp from any to any port = telnet +.fi +.PP +Note, that if we wanted to say "port = telnet", "proto tcp" would +need to be specified as the parser interprets each rule on its own and +qualifies all service/port names with the protocol specified. .SH FILES /etc/services .br diff --git a/usr.sbin/ipf/ipf/ipf.8 b/usr.sbin/ipf/ipf/ipf.8 index 5ea06fa74c35..9246b3500802 100644 --- a/usr.sbin/ipf/ipf/ipf.8 +++ b/usr.sbin/ipf/ipf/ipf.8 @@ -87,8 +87,8 @@ recognised as IP packets. They will be printed out on the console. Turn verbose mode on. Displays information relating to rule processing. .TP .B \-y -(SOLARIS 2 ONLY) Manually resync the in-kernel interface list maintained -by IP Filter with the current interface status list. +Manually resync the in-kernel interface list maintained by IP Filter with +the current interface status list. .TP .B \-z For each rule in the input file, reset the statistics for it to zero and diff --git a/usr.sbin/ipf/ipf/ipf.h b/usr.sbin/ipf/ipf/ipf.h index d5adddb5d7a2..3acb90502d4a 100644 --- a/usr.sbin/ipf/ipf/ipf.h +++ b/usr.sbin/ipf/ipf/ipf.h @@ -1,4 +1,4 @@ -/* $NetBSD: ipf.h,v 1.1.1.5 1997/07/05 05:12:40 darrenr Exp $ */ +/* $NetBSD: ipf.h,v 1.1.1.6 1997/09/21 16:47:51 veego Exp $ */ /* * (C)opyright 1993-1997 by Darren Reed. @@ -8,7 +8,7 @@ * to the original author and the contributors. * * @(#)ipf.h 1.12 6/5/96 - * $Id: ipf.h,v 1.1.1.5 1997/07/05 05:12:40 darrenr Exp $ + * Id: ipf.h,v 2.0.2.9 1997/08/26 12:52:46 darrenr Exp */ #ifndef __IPF_H__ @@ -36,6 +36,7 @@ #define OPT_ZERORULEST 0x10000 #define OPT_SAVEOUT 0x20000 #define OPT_AUTHSTATS 0x40000 +#define OPT_RAW 0x80000 #ifndef __P # ifdef __STDC__ @@ -60,7 +61,7 @@ struct ipopt_names { }; -extern u_32_t buildopts __P((char *, char *)); +extern u_32_t buildopts __P((char *, char *, int)); extern u_32_t hostnum __P((char *, int *)); extern u_32_t optname __P((char ***, u_short *)); extern void printpacket __P((struct ip *)); diff --git a/usr.sbin/ipf/ipf/opt.c b/usr.sbin/ipf/ipf/opt.c index 2caf059749e6..4ee0f5c649db 100644 --- a/usr.sbin/ipf/ipf/opt.c +++ b/usr.sbin/ipf/ipf/opt.c @@ -1,4 +1,4 @@ -/* $NetBSD: opt.c,v 1.1.1.5 1997/07/05 05:12:39 darrenr Exp $ */ +/* $NetBSD: opt.c,v 1.1.1.6 1997/09/21 16:47:50 veego Exp $ */ /* * (C)opyright 1993,1994,1995 by Darren Reed. @@ -9,6 +9,7 @@ */ #include #include +#include #include #include #include @@ -19,12 +20,13 @@ #include #include #include +#include #include #include "ipf.h" #if !defined(lint) && defined(LIBC_SCCS) static char sccsid[] = "@(#)opt.c 1.8 4/10/96 (C) 1993-1995 Darren Reed"; -static char rcsid[] = "$Id: opt.c,v 1.1.1.5 1997/07/05 05:12:39 darrenr Exp $"; +static char rcsid[] = "Id: opt.c,v 2.0.2.7 1997/09/10 13:08:23 darrenr Exp "; #endif extern int opts; @@ -65,7 +67,9 @@ struct ipopt_names secclass[] = { { 0, 0, 0, NULL } /* must be last */ }; + static u_char seclevel __P((char *)); +int addipopt __P((char *, struct ipopt_names *, int, char *)); static u_char seclevel(slevel) char *slevel; @@ -84,14 +88,70 @@ char *slevel; } -u_32_t buildopts(cp, op) +int addipopt(op, io, len, class) +char *op; +struct ipopt_names *io; +int len; +char *class; +{ + int olen = len; + struct in_addr ipadr; + u_short val; + u_char lvl; + char *s; + + if ((len + io->on_siz) > 48) { + fprintf(stderr, "options too long\n"); + return 0; + } + len += io->on_siz; + *op++ = io->on_value; + if (io->on_siz > 1) { + s = op; + *op++ = io->on_siz; + *op++ = IPOPT_MINOFF; + + if (class) { + switch (io->on_value) + { + case IPOPT_SECURITY : + lvl = seclevel(class); + *(op - 1) = lvl; + break; + case IPOPT_LSRR : + case IPOPT_SSRR : + ipadr.s_addr = inet_addr(class); + s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4; + bcopy((char *)&ipadr, op, sizeof(ipadr)); + break; + case IPOPT_SATID : + val = atoi(class); + bcopy((char *)&val, op, 2); + break; + } + } + + op += io->on_siz - 3; + if (len & 3) { + *op++ = IPOPT_NOP; + len++; + } + } + if (opts & OPT_DEBUG) + fprintf(stderr, "bo: %s %d %#x: %d\n", + io->on_name, io->on_value, io->on_bit, len); + return len - olen; +} + + +u_32_t buildopts(cp, op, len) char *cp, *op; +int len; { struct ipopt_names *io; - u_char lvl; u_32_t msk = 0; char *s, *t; - int len = 0; + int inc; for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) { if ((t = strchr(s, '='))) @@ -99,30 +159,10 @@ char *cp, *op; for (io = ionames; io->on_name; io++) { if (strcasecmp(s, io->on_name) || (msk & io->on_bit)) continue; - if ((len + io->on_siz) > 48) { - fprintf(stderr, "options too long\n"); - return 0; + if ((inc = addipopt(op, io, len, t))) { + op += inc; + len += inc; } - len += io->on_siz; - *op++ = io->on_value; - if (io->on_siz > 1) { - *op++ = io->on_siz; - *op++ = IPOPT_MINOFF; - - if (t && !strcasecmp(s, "sec-class")) { - lvl = seclevel(t); - *(op - 1) = lvl; - } - op += io->on_siz - 3; - if (len & 3) { - *op++ = IPOPT_NOP; - len++; - } - } - if (opts & OPT_DEBUG) - fprintf(stderr, "bo: %s %d %#x: %d\n", - io->on_name, io->on_value, - io->on_bit, len); msk |= io->on_bit; break; } diff --git a/usr.sbin/ipf/ipfstat/ipfstat.8 b/usr.sbin/ipf/ipfstat/ipfstat.8 index db23e39eed71..c8679f1c0a21 100644 --- a/usr.sbin/ipf/ipfstat/ipfstat.8 +++ b/usr.sbin/ipf/ipfstat/ipfstat.8 @@ -4,7 +4,7 @@ ipfstat \- reports on packet filter statistics and filter list .SH SYNOPSIS .B ipfstat [ -.B \-hIinov +.B \-aAfhIinosv ] [ .B \-d @@ -24,6 +24,9 @@ accumulated over time as the kernel has put packets through the filter. .B \-a Display the accounting filter list and show bytes counted against each rule. .TP +.B \-A +Display packet authentication statistics. +.TP .BR \-d \0 Use a device other than \fB/dev/ipl\fP for interfacing with the kernel. .TP @@ -68,6 +71,6 @@ kernel. .br /vmunix .SH SEE ALSO -ipf(1), ipfstat(1) +ipf(1) .SH BUGS none known. diff --git a/usr.sbin/ipf/ipfstat/kmem.c b/usr.sbin/ipf/ipfstat/kmem.c index 839c0009cc87..0282da853b97 100644 --- a/usr.sbin/ipf/ipfstat/kmem.c +++ b/usr.sbin/ipf/ipfstat/kmem.c @@ -1,4 +1,4 @@ -/* $NetBSD: kmem.c,v 1.1.1.5 1997/07/05 05:12:43 darrenr Exp $ */ +/* $NetBSD: kmem.c,v 1.1.1.6 1997/09/21 16:47:59 veego Exp $ */ /* * (C)opyright 1993,1994,1995 by Darren Reed. @@ -22,7 +22,7 @@ #if !defined(lint) && defined(LIBC_SCCS) static char sccsid[] = "@(#)kmem.c 1.4 1/12/96 (C) 1992 Darren Reed"; -static char rcsid[] = "$Id: kmem.c,v 1.1.1.5 1997/07/05 05:12:43 darrenr Exp $"; +static char rcsid[] = "Id: kmem.c,v 2.0.2.3 1997/03/10 08:10:37 darrenr Exp "; #endif static int kmemfd = -1; diff --git a/usr.sbin/ipf/ipfstat/kmem.h b/usr.sbin/ipf/ipfstat/kmem.h index 85fcaefcc3ec..d1a89bfae6f8 100644 --- a/usr.sbin/ipf/ipfstat/kmem.h +++ b/usr.sbin/ipf/ipfstat/kmem.h @@ -1,4 +1,4 @@ -/* $NetBSD: kmem.h,v 1.1.1.5 1997/07/05 05:12:44 darrenr Exp $ */ +/* $NetBSD: kmem.h,v 1.1.1.6 1997/09/21 16:48:00 veego Exp $ */ /* * (C)opyright 1993-1997 by Darren Reed. @@ -6,7 +6,7 @@ * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. - * $Id: kmem.h,v 1.1.1.5 1997/07/05 05:12:44 darrenr Exp $ + * Id: kmem.h,v 2.0.2.5 1997/04/30 13:49:35 darrenr Exp */ #ifndef __KMEM_H__ diff --git a/usr.sbin/ipf/ipftest/ipft_ef.c b/usr.sbin/ipf/ipftest/ipft_ef.c index 736541a08839..bed16027144f 100644 --- a/usr.sbin/ipf/ipftest/ipft_ef.c +++ b/usr.sbin/ipf/ipftest/ipft_ef.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipft_ef.c,v 1.1.1.5 1997/07/05 05:12:48 darrenr Exp $ */ +/* $NetBSD: ipft_ef.c,v 1.1.1.6 1997/09/21 16:48:07 veego Exp $ */ /* * (C)opyright 1993,1994,1995 by Darren Reed. @@ -51,7 +51,7 @@ etherfind -n -t #if !defined(lint) && defined(LIBC_SCCS) static char sccsid[] = "@(#)ipft_ef.c 1.6 2/4/96 (C)1995 Darren Reed"; -static char rcsid[] = "$Id: ipft_ef.c,v 1.1.1.5 1997/07/05 05:12:48 darrenr Exp $"; +static char rcsid[] = "Id: ipft_ef.c,v 2.0.2.4 1997/04/30 13:55:06 darrenr Exp "; #endif static int etherf_open __P((char *)); diff --git a/usr.sbin/ipf/ipftest/ipft_hx.c b/usr.sbin/ipf/ipftest/ipft_hx.c index 15a1e742e9dc..5d1ae55a57be 100644 --- a/usr.sbin/ipf/ipftest/ipft_hx.c +++ b/usr.sbin/ipf/ipftest/ipft_hx.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipft_hx.c,v 1.1.1.5 1997/07/05 05:13:01 darrenr Exp $ */ +/* $NetBSD: ipft_hx.c,v 1.1.1.6 1997/09/21 16:48:13 veego Exp $ */ /* * (C)opyright 1995 by Darren Reed. @@ -42,7 +42,7 @@ #if !defined(lint) && defined(LIBC_SCCS) static char sccsid[] = "@(#)ipft_hx.c 1.1 3/9/96 (C) 1996 Darren Reed"; -static char rcsid[] = "$Id: ipft_hx.c,v 1.1.1.5 1997/07/05 05:13:01 darrenr Exp $"; +static char rcsid[] = "Id: ipft_hx.c,v 2.0.2.5 1997/07/20 11:10:32 darrenr Exp "; #endif extern int opts; @@ -113,19 +113,24 @@ int cnt, *dir; * interpret start of line as possibly "[ifname]" or * "[in/out,ifname]". */ - *ifn = NULL; - *dir = 0; + if (ifn) + *ifn = NULL; + if (dir) + *dir = 0; if ((*buf == '[') && (s = index(line, ']'))) { t = buf + 1; if (t - s > 0) { if ((u = index(t, ',')) && (u < s)) { u++; - *ifn = u; - if (*t == 'i') - *dir = 0; - else if (*t == 'o') - *dir = 1; - } else + if (ifn) + *ifn = u; + if (dir) { + if (*t == 'i') + *dir = 0; + else if (*t == 'o') + *dir = 1; + } + } else if (ifn) *ifn = t; *s++ = '\0'; } diff --git a/usr.sbin/ipf/ipftest/ipft_pc.c b/usr.sbin/ipf/ipftest/ipft_pc.c index a3cebf286059..b620201f5582 100644 --- a/usr.sbin/ipf/ipftest/ipft_pc.c +++ b/usr.sbin/ipf/ipftest/ipft_pc.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipft_pc.c,v 1.1.1.5 1997/07/05 05:12:50 darrenr Exp $ */ +/* $NetBSD: ipft_pc.c,v 1.1.1.6 1997/09/21 16:48:09 veego Exp $ */ /* * (C)opyright 1993-1996 by Darren Reed. @@ -33,7 +33,7 @@ #include "pcap.h" #if !defined(lint) && defined(LIBC_SCCS) -static char rcsid[] = "$Id: ipft_pc.c,v 1.1.1.5 1997/07/05 05:12:50 darrenr Exp $"; +static char rcsid[] = "Id: ipft_pc.c,v 2.0.2.4 1997/04/30 13:55:09 darrenr Exp "; #endif struct llc { diff --git a/usr.sbin/ipf/ipftest/ipft_sn.c b/usr.sbin/ipf/ipftest/ipft_sn.c index 26380c888e81..af343b8a2826 100644 --- a/usr.sbin/ipf/ipftest/ipft_sn.c +++ b/usr.sbin/ipf/ipftest/ipft_sn.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipft_sn.c,v 1.1.1.5 1997/07/05 05:12:47 darrenr Exp $ */ +/* $NetBSD: ipft_sn.c,v 1.1.1.6 1997/09/21 16:48:06 veego Exp $ */ /* * (C)opyright 1993,1994,1995 by Darren Reed. @@ -37,7 +37,7 @@ #include "snoop.h" #if !defined(lint) && defined(LIBC_SCCS) -static char rcsid[] = "$Id: ipft_sn.c,v 1.1.1.5 1997/07/05 05:12:47 darrenr Exp $"; +static char rcsid[] = "Id: ipft_sn.c,v 2.0.2.4 1997/04/30 13:55:10 darrenr Exp "; #endif struct llc { diff --git a/usr.sbin/ipf/ipftest/ipft_td.c b/usr.sbin/ipf/ipftest/ipft_td.c index 794dd104f377..eb751908669e 100644 --- a/usr.sbin/ipf/ipftest/ipft_td.c +++ b/usr.sbin/ipf/ipftest/ipft_td.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipft_td.c,v 1.1.1.5 1997/07/05 05:12:49 darrenr Exp $ */ +/* $NetBSD: ipft_td.c,v 1.1.1.6 1997/09/21 16:48:08 veego Exp $ */ /* * (C)opyright 1993,1994,1995 by Darren Reed. @@ -60,7 +60,7 @@ tcpdump -nqte #if !defined(lint) && defined(LIBC_SCCS) static char sccsid[] = "@(#)ipft_td.c 1.8 2/4/96 (C)1995 Darren Reed"; -static char rcsid[] = "$Id: ipft_td.c,v 1.1.1.5 1997/07/05 05:12:49 darrenr Exp $"; +static char rcsid[] = "Id: ipft_td.c,v 2.0.2.4 1997/04/30 13:55:12 darrenr Exp "; #endif static int tcpd_open __P((char *)); diff --git a/usr.sbin/ipf/ipftest/ipft_tx.c b/usr.sbin/ipf/ipftest/ipft_tx.c index edbd7a897cc3..20d45f8c31c9 100644 --- a/usr.sbin/ipf/ipftest/ipft_tx.c +++ b/usr.sbin/ipf/ipftest/ipft_tx.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipft_tx.c,v 1.1.1.5 1997/07/05 05:12:51 darrenr Exp $ */ +/* $NetBSD: ipft_tx.c,v 1.1.1.6 1997/09/21 16:48:10 veego Exp $ */ /* * (C)opyright 1995 by Darren Reed. @@ -43,7 +43,7 @@ #if !defined(lint) && defined(LIBC_SCCS) static char sccsid[] = "@(#)ipft_tx.c 1.7 6/5/96 (C) 1993 Darren Reed"; -static char rcsid[] = "$Id: ipft_tx.c,v 1.1.1.5 1997/07/05 05:12:51 darrenr Exp $"; +static char rcsid[] = "Id: ipft_tx.c,v 2.0.2.7 1997/08/26 12:52:03 darrenr Exp "; #endif extern int opts; @@ -328,7 +328,7 @@ int *out; u_long olen; cpp++; - olen = buildopts(*cpp, ipopts); + olen = buildopts(*cpp, ipopts, (ip->ip_hl - 5) << 2); if (olen) { bcopy(ipopts, (char *)(ip + 1), olen); ip->ip_hl += olen >> 2; diff --git a/usr.sbin/ipf/ipftest/ipt.h b/usr.sbin/ipf/ipftest/ipt.h index 5a5d4ee17aa1..4a84424969ca 100644 --- a/usr.sbin/ipf/ipftest/ipt.h +++ b/usr.sbin/ipf/ipftest/ipt.h @@ -1,4 +1,4 @@ -/* $NetBSD: ipt.h,v 1.1.1.5 1997/07/05 05:13:02 darrenr Exp $ */ +/* $NetBSD: ipt.h,v 1.1.1.6 1997/09/21 16:48:14 veego Exp $ */ /* * (C)opyright 1993-1997 by Darren Reed. @@ -6,7 +6,7 @@ * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. - * $Id: ipt.h,v 1.1.1.5 1997/07/05 05:13:02 darrenr Exp $ + * Id: ipt.h,v 2.0.2.6 1997/04/30 13:49:22 darrenr Exp */ #ifndef __IPT_H__ diff --git a/usr.sbin/ipf/ipftest/misc.c b/usr.sbin/ipf/ipftest/misc.c index 6eba05dc5216..6f71a555ad08 100644 --- a/usr.sbin/ipf/ipftest/misc.c +++ b/usr.sbin/ipf/ipftest/misc.c @@ -1,4 +1,4 @@ -/* $NetBSD: misc.c,v 1.1.1.5 1997/07/05 05:12:57 darrenr Exp $ */ +/* $NetBSD: misc.c,v 1.1.1.6 1997/09/21 16:48:11 veego Exp $ */ /* * (C)opyright 1993,1994,1995 by Darren Reed. @@ -43,7 +43,7 @@ #if !defined(lint) && defined(LIBC_SCCS) static char sccsid[] = "@(#)misc.c 1.3 2/4/96 (C) 1995 Darren Reed"; -static char rcsid[] = "$Id: misc.c,v 1.1.1.5 1997/07/05 05:12:57 darrenr Exp $"; +static char rcsid[] = "Id: misc.c,v 2.0.2.6 1997/04/30 13:54:24 darrenr Exp "; #endif extern int opts; diff --git a/usr.sbin/ipf/ipftest/pcap.h b/usr.sbin/ipf/ipftest/pcap.h index 9a835af20a77..eb1a45301a11 100644 --- a/usr.sbin/ipf/ipftest/pcap.h +++ b/usr.sbin/ipf/ipftest/pcap.h @@ -1,4 +1,4 @@ -/* $NetBSD: pcap.h,v 1.1.1.2 1997/05/27 22:17:14 thorpej Exp $ */ +/* $NetBSD: pcap.h,v 1.1.1.3 1997/09/21 16:48:16 veego Exp $ */ /* * (C)opyright 1993-1997 by Darren Reed. diff --git a/usr.sbin/ipf/ipftest/snoop.h b/usr.sbin/ipf/ipftest/snoop.h index 73e8e2dbe641..111a9d91451d 100644 --- a/usr.sbin/ipf/ipftest/snoop.h +++ b/usr.sbin/ipf/ipftest/snoop.h @@ -1,4 +1,4 @@ -/* $NetBSD: snoop.h,v 1.1.1.5 1997/07/05 05:13:02 darrenr Exp $ */ +/* $NetBSD: snoop.h,v 1.1.1.6 1997/09/21 16:48:15 veego Exp $ */ /* * (C)opyright 1993-1997 by Darren Reed. @@ -13,7 +13,7 @@ /* * written to comply with the RFC (1761) from Sun. - * $Id: snoop.h,v 1.1.1.5 1997/07/05 05:13:02 darrenr Exp $ + * Id: snoop.h,v 2.0.2.4 1997/04/30 13:49:52 darrenr Exp */ struct snoophdr { char s_id[8]; diff --git a/usr.sbin/ipf/ipftest/test/Makefile b/usr.sbin/ipf/ipftest/test/Makefile index f2e3ca908638..a0e07e76bea4 100644 --- a/usr.sbin/ipf/ipftest/test/Makefile +++ b/usr.sbin/ipf/ipftest/test/Makefile @@ -1,11 +1,9 @@ # # (C)opyright 1993-1996 by Darren Reed. # -# This code may be freely distributed as long as it retains this notice -# and is not changed in any way. The author accepts no responsibility -# for the use of this software. I hate legaleese, don't you ? -# -# where to put things. +# Redistribution and use in source and binary forms are permitted +# provided that this notice is preserved and due credit is given +# to the original author and the contributors. # BINDEST=/usr/local/bin SBINDEST=/sbin @@ -26,13 +24,13 @@ ptests: i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 @(cd ..; make ipftest; ) 1 2 3 4 5 6 7 8 9 10 11 14: - @./dotest $@ + @/bin/sh ./dotest $@ 12: - @./hextest $@ + @/bin/sh ./hextest $@ i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11: - @./itest $@ + @/bin/sh ./itest $@ clean: /bin/rm -f 1 2 3 4 5 6 7 8 9 10 11 12 results/* diff --git a/usr.sbin/ipf/ipmon/ipmon.8 b/usr.sbin/ipf/ipmon/ipmon.8 index e793352a60e5..32f4cbdfc549 100644 --- a/usr.sbin/ipf/ipmon/ipmon.8 +++ b/usr.sbin/ipf/ipmon/ipmon.8 @@ -4,9 +4,11 @@ ipmon \- monitors /dev/ipl for logged packets .SH SYNOPSIS .B ipmon [ -.B \-asfnSN +.B \-aFhnNsStvxX ] [ - +.B "\-f " +] [ +.B ] .SH DESCRIPTION .LP @@ -20,6 +22,24 @@ via syslog have the day, month and year removed from the message, but the time (including microseconds), as recorded in the log, is still included. .SH OPTIONS .TP +.B \-a +Open all of the device logfiles for reading log entries from. All entries +are displayed to the same output 'device' (stderr or syslog). +.TP +.B "\-f " +specify an alternative device/file from which to read the log information. +.TP +.B \-F +Flush the current packet log buffer. The number of bytes flushed is displayed, +even should the result be zero. +.TP +.B \-n +IP addresses and port numbers will be mapped, where possible, back into +hostnames and service names. +.TP +.B \-N +Treat the logfile as being composed of NAT log records. +.TP .B \-s Packet information read in will be sent through syslogd rather than saved to a file. The following levels are used: @@ -38,22 +58,17 @@ than pass or block. \- packets which have been logged and which can be considered "short". .TP -.B \-a -Open all of the device logfiles for reading log entries from. -.TP -.B \-f -Flush the current packet log buffer. The number of bytes flushed is displayed, -even should the result be zero. -.TP -.B \-n -IP addresses and port numbers will be mapped, where possible, back into -hostnames and service names. -.TP -.B \-N -Treat the logfile as being composed of NAT log records. -.TP .B \-S Treat the logfile as being composed of state log records. +.TP +.B \-t +read the input file/device in a manner akin to tail(1). +.TP +.B \-x +show the packet data in hex. +.TP +.B \-X +show the log header record data in hex. .SH DIAGNOSTICS \fBipmon\fP expects data that it reads to be consistant with how it should be saved and will abort if it fails an assertion which detects an anomoly in the diff --git a/usr.sbin/ipf/ipnat/ipnat.4 b/usr.sbin/ipf/ipnat/ipnat.4 index 3346ef973029..ea789365ffd8 100644 --- a/usr.sbin/ipf/ipnat/ipnat.4 +++ b/usr.sbin/ipf/ipnat/ipnat.4 @@ -2,7 +2,10 @@ .SH NAME ipnat \- Network Address Translation kernel interface .SH SYNOPSIS -#include +#include +#include +#include +#include .SH IOCTLS .PP To add and delete rules to the NAT list, two 'basic' ioctls are provided diff --git a/usr.sbin/ipf/ipresend/ipresend.1 b/usr.sbin/ipf/ipresend/ipresend.1 new file mode 100644 index 000000000000..40f98256209f --- /dev/null +++ b/usr.sbin/ipf/ipresend/ipresend.1 @@ -0,0 +1,107 @@ +.TH IPRESEND 1 +.SH NAME +ipresend \- resend IP packets out to network +.SH SYNOPSIS +.B ipsend +[ +.B \-EHPRSTX +] [ +.B \-d + +] [ +.B \-g +<\fIgateway\fP> +] [ +.B \-m +<\fIMTU\fP> +] [ +.B \-r +<\fIfilename\fP> +] +.SH DESCRIPTION +.PP +\fBipresend\fP was designed to allow packets to be resent, once captured, +back out onto the network for use in testing. \fIipresend\fP supports a +number of different file formats as input, including saved snoop/tcpdump +binary data. +.SH OPTIONS +.TP +.BR \-d \0 +Set the interface name to be the name supplied. This is useful with the +\fB\-P, \-S, \-T\fP and \fB\-E\fP options, where it is not otherwise possible +to associate a packet with an interface. Normal "text packets" can override +this setting. +.TP +.BR \-g \0 +Specify the hostname of the gateway through which to route packets. This +is required whenever the destination host isn't directly attached to the +same network as the host from which you're sending. +.TP +.BR \-m \0 +Specify the MTU to be used when sending out packets. This option allows you +to set a fake MTU, allowing the simulation of network interfaces with small +MTU's without setting them so. +.TP +.BR \-r \0 +Specify the filename from which to take input. Default is stdin. +.B \-E +The input file is to be text output from etherfind. The text formats which +are currently supported are those which result from the following etherfind +option combinations: +.PP +.nf + etherfind -n + etherfind -n -t +.fi +.LP +.TP +.B \-H +The input file is to be hex digits, representing the binary makeup of the +packet. No length correction is made, if an incorrect length is put in +the IP header. +.TP +.B \-P +The input file specified by \fB\-i\fP is a binary file produced using libpcap +(i.e., tcpdump version 3). Packets are read from this file as being input +(for rule purposes). +.TP +.B \-R +When sending packets out, send them out "raw" (the way they came in). The +only real significance here is that it will expect the link layer (i.e. +ethernet) headers to be prepended to the IP packet being output. +.TP +.B \-S +The input file is to be in "snoop" format (see RFC 1761). Packets are read +from this file and used as input from any interface. This is perhaps the +most useful input type, currently. +.TP +.B \-T +The input file is to be text output from tcpdump. The text formats which +are currently supported are those which result from the following tcpdump +option combinations: +.PP +.nf + tcpdump -n + tcpdump -nq + tcpdump -nqt + tcpdump -nqtt + tcpdump -nqte +.fi +.LP +.TP +.B \-X +The input file is composed of text descriptions of IP packets. +.TP +.SH FILES +.DT +.SH SEE ALSO +snoop(1m), tcpdump(8), etherfind(8c), ipftest(1), ipresend(1), iptest(1), bpf(4), dlpi(7p) +.SH DIAGNOSTICS +.PP +Needs to be run as root. +.SH BUGS +.PP +Not all of the input formats are sufficiently capable of introducing a +wide enough variety of packets for them to be all useful in testing. +If you find any, please send email to me at darrenr@cyber.com.au + diff --git a/usr.sbin/ipf/ipresend/ipresend.c b/usr.sbin/ipf/ipresend/ipresend.c index c7895bcbed9d..7dedfb74d5e7 100644 --- a/usr.sbin/ipf/ipresend/ipresend.c +++ b/usr.sbin/ipf/ipresend/ipresend.c @@ -1,20 +1,16 @@ -/* $NetBSD: ipresend.c,v 1.1.1.2 1997/05/27 22:18:08 thorpej Exp $ */ +/* $NetBSD: ipresend.c,v 1.1.1.3 1997/09/21 16:49:04 veego Exp $ */ /* - * ipsend.c (C) 1995 Darren Reed + * ipresend.c (C) 1995-1997 Darren Reed * * This was written to test what size TCP fragments would get through * various TCP/IP packet filters, as used in IP firewalls. In certain * conditions, enough of the TCP header is missing for unpredictable * results unless the filter is aware that this can happen. * - * The author provides this program as-is, with no gaurantee for its - * suitability for any specific purpose. The author takes no responsibility - * for the misuse/abuse of this program and provides it for the sole purpose - * of testing packet filter policies. This file maybe distributed freely - * providing it is not modified and that this notice remains in tact. - * - * This was written and tested (successfully) on SunOS 4.1.x. + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. */ #if !defined(lint) && defined(LIBC_SCCS) static char sccsid[] = "%W% %G% (C)1995 Darren Reed"; @@ -96,10 +92,10 @@ char **argv; struct in_addr gwip; struct ipread *ipr = NULL; char *name = argv[0], *gateway = NULL, *dev = NULL; - char c, *resend = NULL; - int mtu = 1500; + char *resend = NULL; + int mtu = 1500, c; - while ((c = getopt(argc, argv, "EHPSTXd:g:m:r:")) != -1) + while ((c = getopt(argc, argv, "EHPRSTXd:g:m:r:")) != -1) switch (c) { case 'd' : @@ -118,6 +114,9 @@ char **argv; case 'r' : resend = optarg; break; + case 'R' : + opts |= OPT_RAW; + break; #ifndef NO_IPF case 'E' : ipr = ðerf; diff --git a/usr.sbin/ipf/ipsend/iplang.h b/usr.sbin/ipf/ipsend/iplang.h new file mode 100644 index 000000000000..7c75f37f174a --- /dev/null +++ b/usr.sbin/ipf/ipsend/iplang.h @@ -0,0 +1,53 @@ +/* $NetBSD: iplang.h,v 1.1.1.1 1997/09/21 16:49:16 veego Exp $ */ + +/* + * (C)opyright 1997 by Darren Reed. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. + */ +typedef struct iface { + int if_MTU; + char *if_name; + struct in_addr if_addr; + struct ether_addr if_eaddr; + struct iface *if_next; + int if_fd; +} iface_t; + + +typedef struct send { + struct iface *snd_if; + struct in_addr snd_gw; +} send_t; + + +typedef struct arp { + struct in_addr arp_addr; + struct ether_addr arp_eaddr; + struct arp *arp_next; +} arp_t; + + +typedef struct aniphdr { + union { + ip_t *ahu_ip; + char *ahu_data; + tcphdr_t *ahu_tcp; + udphdr_t *ahu_udp; + icmphdr_t *ahu_icmp; + } ah_un; + int ah_optlen; + int ah_lastopt; + int ah_p; + size_t ah_len; + struct aniphdr *ah_next; + struct aniphdr *ah_prev; +} aniphdr_t; + +#define ah_ip ah_un.ahu_ip +#define ah_data ah_un.ahu_data +#define ah_tcp ah_un.ahu_tcp +#define ah_udp ah_un.ahu_udp +#define ah_icmp ah_un.ahu_icmp diff --git a/usr.sbin/ipf/ipsend/iplang.tst b/usr.sbin/ipf/ipsend/iplang.tst new file mode 100644 index 000000000000..53457165a401 --- /dev/null +++ b/usr.sbin/ipf/ipsend/iplang.tst @@ -0,0 +1,20 @@ +# +interface { ifname le0; mtu 1500; } + +ipv4 { + src 10.1.1.49; dst 10.1.1.50; id 123; opt { rr 7; }; + tcp { + seq 12345; ack 0; sport 9999; dport 23; flags S; + opt { mss 65535; }; data { value "abcdef"; } ; + } +} +send { via 10.1.1.50; } +# +ipv4 { + src 10.1.1.49; dst 10.1.1.50; id 1; opt { lsrr 1.1.1.1; }; + tcp { + seq 12345; ack 0; sport 9999; dport 23; flags S; + opt { wscale 2 ; eol; mss 1; }; data { value "abcdef"; } ; + } +} +send { via 10.1.1.50; } diff --git a/usr.sbin/ipf/ipsend/iplang_l.l b/usr.sbin/ipf/ipsend/iplang_l.l new file mode 100644 index 000000000000..7a1422fe1a23 --- /dev/null +++ b/usr.sbin/ipf/ipsend/iplang_l.l @@ -0,0 +1,246 @@ +/* $NetBSD: iplang_l.l,v 1.1.1.1 1997/09/21 16:49:16 veego Exp $ */ + +%{ +/* + * (C)opyright 1997 by Darren Reed. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. + * + * Id: iplang_l.l,v 2.0.2.8 1997/09/13 07:14:23 darrenr Exp + */ + +#include +#include +#include +#include "y.tab.h" + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + +int lineNum = 0, proto = 0, oldproto = 0, next = -1, laststate = 0; +int *prstack = NULL, numpr = 0, state = 0, token = 0; + +void push_proto __P((void)); +void pop_proto __P((void)); +int next_state __P((int, int)); +int next_item __P((int)); +int save_token __P((void)); +void swallow __P((void)); +int yylex __P((void)); +%} + +%% +[ \t\r] ; +\n { lineNum++; swallow(); } +interface | +iface { return next_state(IL_INTERFACE, -1); } +name | +ifname { return next_state(IL_IFNAME, IL_TOKEN); } +router { return next_state(IL_DEFROUTER, IL_TOKEN); } +mtu { return next_state(IL_MTU, IL_NUMBER); } +eaddr { return next_state(IL_EADDR, IL_TOKEN); } +v4addr { return next_state(IL_V4ADDR, IL_TOKEN); } +ipv4 { return next_state(IL_IPV4, -1); } +v { return next_state(IL_V4V, IL_TOKEN); } +proto { return next_state(IL_V4PROTO, IL_TOKEN); } +hl { return next_state(IL_V4HL, IL_TOKEN); } +id { return next_state(IL_V4ID, IL_TOKEN); } +ttl { return next_state(IL_V4TTL, IL_TOKEN); } +tos { return next_state(IL_V4TOS, IL_TOKEN); } +src { return next_state(IL_V4SRC, IL_TOKEN); } +dst { return next_state(IL_V4DST, IL_TOKEN); } +opt { return next_state(IL_OPT, -1); } +len { return next_state(IL_LEN, IL_TOKEN); } +off { return next_state(IL_OFF, IL_TOKEN); } +sum { return next_state(IL_SUM, IL_TOKEN); } +tcp { return next_state(IL_TCP, -1); } +sport { return next_state(IL_SPORT, IL_TOKEN); } +dport { return next_state(IL_DPORT, IL_TOKEN); } +seq { return next_state(IL_TCPSEQ, IL_TOKEN); } +ack { return next_state(IL_TCPACK, IL_TOKEN); } +flags { return next_state(IL_TCPFL, IL_TOKEN); } +urp { return next_state(IL_TCPURP, IL_TOKEN); } +win { return next_state(IL_TCPWIN, IL_TOKEN); } +udp { return next_state(IL_UDP, -1); } +send { return next_state(IL_SEND, -1); } +via { return next_state(IL_VIA, IL_TOKEN); } +arp { return next_state(IL_ARP, -1); } +data { return next_state(IL_DATA, -1); } +value { return next_state(IL_DVALUE, IL_TOKEN); } +file { return next_state(IL_DFILE, IL_TOKEN); } +nop { return next_state(IL_IPO_NOP, -1); } +eol { return next_state(IL_IPO_EOL, -1); } +rr { return next_state(IL_IPO_RR, -1); } +zsu { return next_state(IL_IPO_ZSU, -1); } +mtup { return next_state(IL_IPO_MTUP, -1); } +mtur { return next_state(IL_IPO_MTUR, -1); } +encode { return next_state(IL_IPO_ENCODE, -1); } +ts { return next_state(IL_IPO_TS, -1); } +tr { return next_state(IL_IPO_TR, -1); } +sec { return next_state(IL_IPO_SEC, -1); } +secclass { return next_state(IL_IPO_SECCLASS, IL_TOKEN); } +lsrr { return next_state(IL_IPO_LSRR, -1); } +esec { return next_state(IL_IPO_ESEC, -1); } +cipso { return next_state(IL_IPO_CIPSO, -1); } +satid { return next_state(IL_IPO_SATID, -1); } +ssrr { return next_state(IL_IPO_SSRR, -1); } +addext { return next_state(IL_IPO_ADDEXT, -1); } +visa { return next_state(IL_IPO_VISA, -1); } +imitd { return next_state(IL_IPO_IMITD, -1); } +eip { return next_state(IL_IPO_EIP, -1); } +finn { return next_state(IL_IPO_FINN, -1); } +mss { return next_state(IL_TCPO_MSS, IL_TOKEN); } +wscale { return next_state(IL_TCPO_MSS, IL_TOKEN); } +reserv-4 { return next_state(IL_IPS_RESERV4, -1); } +topsecret { return next_state(IL_IPS_TOPSECRET, -1); } +secret { return next_state(IL_IPS_SECRET, -1); } +reserv-3 { return next_state(IL_IPS_RESERV3, -1); } +confid { return next_state(IL_IPS_CONFID, -1); } +unclass { return next_state(IL_IPS_UNCLASS, -1); } +reserv-2 { return next_state(IL_IPS_RESERV2, -1); } +reserv-1 { return next_state(IL_IPS_RESERV1, -1); } +\{ { push_proto(); return next_item(IL_LBRACE); } +\} { pop_proto(); return next_item(IL_RBRACE); } +\. { return next_item(IL_DOT); } +; { return next_item(IL_SEMICOLON); } +[0-9]+ { return next_item(IL_NUMBER); } +[0-9a-fA-F] { return next_item(IL_HEXDIGIT); } +: { return next_item(IL_COLON); } +#[^\n]* { return next_item(IL_COMMENT); } +[^ {}\n\t;]* { return next_item(IL_TOKEN); } +\"[^\"]*\" { return next_item(IL_TOKEN); } +%% +void push_proto() +{ + numpr++; + if (!prstack) + prstack = (int *)malloc(sizeof(int)); + else + prstack = (int *)realloc((char *)prstack, numpr * sizeof(int)); + prstack[numpr - 1] = oldproto; +} + + +void pop_proto() +{ + numpr--; + proto = prstack[numpr]; + if (!numpr) { + free(prstack); + prstack = NULL; + return; + } + prstack = (int *)realloc((char *)prstack, numpr * sizeof(int)); +} + + +int save_token() +{ + static char *buf = NULL; + + if (buf && (buf == yylval.str)) + free(buf); + buf = yylval.str = strdup(yytext); + return IL_TOKEN; +} + + +int next_item(nstate) +int nstate; +{ + if (next == IL_TOKEN) { + next = -1; + return save_token(); + } + next = -1; + if (nstate == IL_NUMBER) + yylval.num = atoi(yytext); + token++; + return nstate; +} + + +int next_state(nstate, fornext) +int nstate, fornext; +{ + token++; + + if (next == IL_TOKEN) { + next = -1; + return save_token(); + } + + next = fornext; + + switch (nstate) + { + case IL_IPV4 : + case IL_TCP : + case IL_UDP : + case IL_ICMP : + case IL_DATA : + case IL_INTERFACE : + case IL_ARP : + oldproto = proto; + proto = nstate; + break; + case IL_SUM : + if (proto == IL_IPV4) + nstate = IL_V4SUM; + else if (proto == IL_TCP) + nstate = IL_TCPSUM; + else if (proto == IL_UDP) + nstate = IL_UDPSUM; + break; + case IL_OPT : + if (proto == IL_IPV4) + nstate = IL_V4OPT; + else if (proto == IL_TCP) + nstate = IL_TCPOPT; + break; + case IL_IPO_NOP : + if (proto == IL_TCP) + nstate = IL_TCPO_NOP; + break; + case IL_IPO_EOL : + if (proto == IL_TCP) + nstate = IL_TCPO_EOL; + break; + case IL_IPO_TS : + if (proto == IL_TCP) + nstate = IL_TCPO_TS; + break; + case IL_OFF : + if (proto == IL_IPV4) + nstate = IL_V4OFF; + else if (proto == IL_TCP) + nstate = IL_TCPOFF; + break; + case IL_LEN : + if (proto == IL_IPV4) + nstate = IL_V4LEN; + else if (proto == IL_UDP) + nstate = IL_UDPLEN; + break; + } + return nstate; +} + + +void swallow() +{ + int c = input(); + + if (c == '#') { + while ((c != '\n') && (c != EOF)) + c = input(); + } + unput(c); +} diff --git a/usr.sbin/ipf/ipsend/iplang_y.y b/usr.sbin/ipf/ipsend/iplang_y.y new file mode 100644 index 000000000000..788729714c60 --- /dev/null +++ b/usr.sbin/ipf/ipsend/iplang_y.y @@ -0,0 +1,1808 @@ +/* $NetBSD: iplang_y.y,v 1.1.1.1 1997/09/21 16:49:16 veego Exp $ */ + +%{ +/* + * (C)opyright 1997 by Darren Reed. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. + * + * Id: iplang_y.y,v 2.0.2.9 1997/09/13 07:14:24 darrenr Exp + */ + +#include +#include +#include +#if !defined(__SVR4) && !defined(__svr4__) +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ipf.h" +#include "iplang.h" + +extern struct ether_addr *ether_aton __P((char *)); + +extern int opts; +extern struct ipopt_names ionames[]; +extern int state, state, lineNum, token; +extern int yylineno; +extern char yytext[]; +extern FILE *yyin; +/*#define YYDEBUG 1*/ +int yydebug = 0; + +iface_t *iflist = NULL, **iftail = &iflist; +iface_t *cifp = NULL; +arp_t *arplist = NULL, **arptail = &arplist, *carp = NULL; +struct in_addr defrouter; +send_t sending; +char *sclass = NULL; +u_short c_chksum __P((u_short *, u_int, u_long)); +u_long p_chksum __P((u_short *, u_int)); + +u_long ipbuffer[67584/sizeof(u_long)]; /* 66K */ +aniphdr_t *aniphead = NULL, *canip = NULL, **aniptail = &aniphead; +ip_t *ip = NULL; +udphdr_t *udp = NULL; +tcphdr_t *tcp = NULL; +icmphdr_t *icmp = NULL; + +struct statetoopt { + int sto_st; + int sto_op; +}; + +struct in_addr getipv4addr __P((char *arg)); +u_short getportnum __P((char *, char *)); +struct ether_addr *geteaddr __P((char *, struct ether_addr *)); +void *new_header __P((int)); +void free_aniplist __P((void)); +void inc_anipheaders __P((int)); +void new_data __P((void)); +void set_datalen __P((char **)); +void set_datafile __P((char **)); +void set_data __P((char **)); +void new_packet __P((void)); +void set_ipv4proto __P((char **)); +void set_ipv4src __P((char **)); +void set_ipv4dst __P((char **)); +void set_ipv4off __P((char **)); +void set_ipv4v __P((char **)); +void set_ipv4hl __P((char **)); +void set_ipv4ttl __P((char **)); +void set_ipv4tos __P((char **)); +void set_ipv4id __P((char **)); +void set_ipv4sum __P((char **)); +void set_ipv4len __P((char **)); +void new_tcpheader __P((void)); +void set_tcpsport __P((char **)); +void set_tcpdport __P((char **)); +void set_tcpseq __P((char **)); +void set_tcpack __P((char **)); +void set_tcpoff __P((char **)); +void set_tcpurp __P((char **)); +void set_tcpwin __P((char **)); +void set_tcpsum __P((char **)); +void set_tcpflags __P((char **)); +void set_tcpopt __P((int, char **)); +void end_tcpopt __P((void)); +void new_udpheader __P((void)); +void set_udplen __P((char **)); +void set_udpsum __P((char **)); +void prep_packet __P((void)); +void packet_done __P((void)); +void new_interface __P((void)); +void check_interface __P((void)); +void set_ifname __P((char **)); +void set_ifmtu __P((int)); +void set_ifv4addr __P((char **)); +void set_ifeaddr __P((char **)); +void new_arp __P((void)); +void set_arpeaddr __P((char **)); +void set_arpv4addr __P((char **)); +void reset_send __P((void)); +void set_sendif __P((char **)); +void set_sendvia __P((char **)); +void set_defaultrouter __P((char **)); +void new_icmpheader __P((void)); +void set_icmpcode __P((int)); +void set_icmptype __P((int)); +void set_icmpcodetok __P((char **)); +void set_icmptypetok __P((char **)); +void set_icmpid __P((int)); +void set_icmpseq __P((int)); +void set_icmpotime __P((int)); +void set_icmprtime __P((int)); +void set_icmpttime __P((int)); +void set_icmpmtu __P((int)); +void set_redir __P((int, char **)); +void new_ipv4opt __P((void)); +void add_ipopt __P((int, void *)); +void end_ipopt __P((void)); +void set_secclass __P((char **)); +void free_anipheader __P((void)); +void end_ipv4 __P((void)); +void end_icmp __P((void)); +void end_udp __P((void)); +void end_tcp __P((void)); +void end_data __P((void)); +void yyerror __P((char *)); +void iplang __P((FILE *)); +int yyparse __P((void)); +%} +%union { + char *str; + int num; +} +%token IL_NUMBER +%type number digits +%token IL_TOKEN +%type token +%token IL_HEXDIGIT IL_COLON IL_DOT IL_EOF IL_COMMENT +%token IL_LBRACE IL_RBRACE IL_SEMICOLON +%token IL_INTERFACE IL_IFNAME IL_MTU IL_EADDR +%token IL_IPV4 IL_V4PROTO IL_V4SRC IL_V4DST IL_V4OFF IL_V4V IL_V4HL IL_V4TTL +%token IL_V4TOS IL_V4SUM IL_V4LEN IL_V4OPT IL_V4ID +%token IL_TCP IL_SPORT IL_DPORT IL_TCPFL IL_TCPSEQ IL_TCPACK IL_TCPOFF +%token IL_TCPWIN IL_TCPSUM IL_TCPURP IL_TCPOPT IL_TCPO_NOP IL_TCPO_EOL +%token IL_TCPO_MSS IL_TCPO_WSCALE IL_TCPO_TS +%token IL_UDP IL_UDPLEN IL_UDPSUM +%token IL_ICMP IL_ICMPTYPE IL_ICMPCODE +%token IL_SEND IL_VIA +%token IL_ARP +%token IL_DEFROUTER +%token IL_SUM IL_OFF IL_LEN IL_V4ADDR IL_OPT +%token IL_DATA IL_DLEN IL_DVALUE IL_DFILE +%token IL_IPO_NOP IL_IPO_RR IL_IPO_ZSU IL_IPO_MTUP IL_IPO_MTUR IL_IPO_EOL +%token IL_IPO_TS IL_IPO_TR IL_IPO_SEC IL_IPO_LSRR IL_IPO_ESEC +%token IL_IPO_SATID IL_IPO_SSRR IL_IPO_ADDEXT IL_IPO_VISA IL_IPO_IMITD +%token IL_IPO_EIP IL_IPO_FINN IL_IPO_SECCLASS IL_IPO_CIPSO IL_IPO_ENCODE +%token IL_IPS_RESERV4 IL_IPS_TOPSECRET IL_IPS_SECRET IL_IPS_RESERV3 +%token IL_IPS_CONFID IL_IPS_UNCLASS IL_IPS_RESERV2 IL_IPS_RESERV1 +%token IL_ICMP_ECHOREPLY IL_ICMP_UNREACH IL_ICMP_UNREACH_NET +%token IL_ICMP_UNREACH_HOST IL_ICMP_UNREACH_PROTOCOL IL_ICMP_UNREACH_PORT +%token IL_ICMP_UNREACH_NEEDFRAG IL_ICMP_UNREACH_SRCFAIL +%token IL_ICMP_UNREACH_NET_UNKNOWN IL_ICMP_UNREACH_HOST_UNKNOWN +%token IL_ICMP_UNREACH_ISOLATED IL_ICMP_UNREACH_NET_PROHIB +%token IL_ICMP_UNREACH_HOST_PROHIB IL_ICMP_UNREACH_TOSNET +%token IL_ICMP_UNREACH_TOSHOST IL_ICMP_UNREACH_FILTER_PROHIB +%token IL_ICMP_UNREACH_HOST_PRECEDENCE IL_ICMP_UNREACH_PRECEDENCE_CUTOFF +%token IL_ICMP_SOURCEQUENCH IL_ICMP_REDIRECT IL_ICMP_REDIRECT_NET +%token IL_ICMP_REDIRECT_HOST IL_ICMP_REDIRECT_TOSNET +%token IL_ICMP_REDIRECT_TOSHOST IL_ICMP_ECHO IL_ICMP_ROUTERADVERT +%token IL_ICMP_ROUTERSOLICIT IL_ICMP_TIMXCEED IL_ICMP_TIMXCEED_INTRANS +%token IL_ICMP_TIMXCEED_REASS IL_ICMP_PARAMPROB IL_ICMP_PARAMPROB_OPTABSENT +%token IL_ICMP_TSTAMP IL_ICMP_TSTAMPREPLY IL_ICMP_IREQ IL_ICMP_IREQREPLY +%token IL_ICMP_MASKREQ IL_ICMP_MASKREPLY IL_ICMP_SEQ IL_ICMP_ID +%token IL_ICMP_OTIME IL_ICMP_RTIME IL_ICMP_TTIME + +%% +file: line + | line file + | IL_COMMENT + | IL_COMMENT file + ; + +line: iface + | arp + | send + | defrouter + | ipline + ; + +iface: ifhdr IL_LBRACE ifaceopts IL_RBRACE { check_interface(); } + ; + +ifhdr: IL_INTERFACE { new_interface(); } + ; + +ifaceopts: + ifaceopt + | ifaceopt ifaceopts + ; + +ifaceopt: + IL_IFNAME token { set_ifname(&yylval.str); } + | IL_MTU number { set_ifmtu(yylval.num); } + | IL_V4ADDR token { set_ifv4addr(&yylval.str); } + | IL_EADDR token { set_ifeaddr(&yylval.str); } + ; + +send: sendhdr IL_LBRACE sendbody IL_RBRACE { packet_done(); } + | sendhdr IL_SEMICOLON { packet_done(); } + ; + +sendhdr: + IL_SEND { reset_send(); } + ; + +sendbody: + sendopt + | sendbody sendopt + ; + +sendopt: + IL_IFNAME token { set_sendif(&yylval.str); } + | IL_VIA token { set_sendvia(&yylval.str); } + ; + +arp: arphdr IL_LBRACE arpbody IL_RBRACE + ; + +arphdr: IL_ARP { new_arp(); } + ; + +arpbody: + arpopt + | arpbody arpopt + ; + +arpopt: IL_V4ADDR token { set_arpv4addr(&yylval.str); } + | IL_EADDR token { set_arpeaddr(&yylval.str); } + ; + +defrouter: + IL_DEFROUTER token { set_defaultrouter(&yylval.str); } + ; + +ipline: ipv4 gotbody + ; + +ipv4: IL_IPV4 { new_packet(); } + +gotbody: IL_LBRACE ipv4body IL_RBRACE { end_ipv4(); } + ; + +ipv4body: + ipv4type IL_SEMICOLON + | ipv4type IL_SEMICOLON ipv4body + | tcp tcpline + | udp udpline + | icmp icmpline + | data dataline + ; + +ipv4type: + | IL_V4PROTO IL_TOKEN { set_ipv4proto(&yylval.str); } + | IL_V4SRC IL_TOKEN { set_ipv4src(&yylval.str); } + | IL_V4DST IL_TOKEN { set_ipv4dst(&yylval.str); } + | IL_V4OFF IL_TOKEN { set_ipv4off(&yylval.str); } + | IL_V4V IL_TOKEN { set_ipv4v(&yylval.str); } + | IL_V4HL IL_TOKEN { set_ipv4hl(&yylval.str); } + | IL_V4ID IL_TOKEN { set_ipv4id(&yylval.str); } + | IL_V4TTL IL_TOKEN { set_ipv4ttl(&yylval.str); } + | IL_V4TOS IL_TOKEN { set_ipv4tos(&yylval.str); } + | IL_V4SUM IL_TOKEN { set_ipv4sum(&yylval.str); } + | IL_V4LEN IL_TOKEN { set_ipv4len(&yylval.str); } + | ipv4opt IL_LBRACE ipv4optlist IL_RBRACE { end_ipopt(); } + | ipline + ; + +tcp: IL_TCP { new_tcpheader(); } + ; + +tcpline: + IL_LBRACE tcpheader IL_RBRACE { end_tcp(); } + ; + +tcpheader: + tcpbody IL_SEMICOLON + | tcpbody IL_SEMICOLON tcpheader + ; + +tcpbody: + | IL_SPORT IL_TOKEN { set_tcpsport(&yylval.str); } + | IL_DPORT IL_TOKEN { set_tcpdport(&yylval.str); } + | IL_TCPSEQ IL_TOKEN { set_tcpseq(&yylval.str); } + | IL_TCPACK IL_TOKEN { set_tcpack(&yylval.str); } + | IL_TCPOFF IL_TOKEN { set_tcpoff(&yylval.str); } + | IL_TCPURP IL_TOKEN { set_tcpurp(&yylval.str); } + | IL_TCPWIN IL_TOKEN { set_tcpwin(&yylval.str); } + | IL_TCPSUM IL_TOKEN { set_tcpsum(&yylval.str); } + | IL_TCPFL IL_TOKEN { set_tcpflags(&yylval.str); } + | IL_TCPOPT IL_LBRACE tcpopts IL_RBRACE { end_tcpopt(); } + | data dataline + ; + +tcpopts: + | tcpopt tcpopts + ; + +tcpopt: IL_TCPO_NOP IL_SEMICOLON { set_tcpopt(IL_TCPO_NOP, NULL); } + | IL_TCPO_EOL IL_SEMICOLON { set_tcpopt(IL_TCPO_EOL, NULL); } + | IL_TCPO_MSS optoken { set_tcpopt(IL_TCPO_MSS,&yylval.str);} + | IL_TCPO_WSCALE optoken { set_tcpopt(IL_TCPO_MSS,&yylval.str);} + | IL_TCPO_TS optoken { set_tcpopt(IL_TCPO_TS, &yylval.str);} + ; + +udp: IL_UDP { new_udpheader(); } + ; + +udpline: IL_LBRACE udpheader IL_RBRACE { end_udp(); } + ; + + +udpheader: + udpbody IL_SEMICOLON + | udpbody IL_SEMICOLON udpheader + ; + +udpbody: + | IL_SPORT IL_TOKEN { set_tcpsport(&yylval.str); } + | IL_DPORT IL_TOKEN { set_tcpdport(&yylval.str); } + | IL_UDPLEN IL_TOKEN { set_udplen(&yylval.str); } + | IL_UDPSUM IL_TOKEN { set_udpsum(&yylval.str); } + | data dataline + ; + +icmp: IL_ICMP { new_icmpheader(); } + ; + +icmpline: + IL_LBRACE icmpbody IL_RBRACE { end_icmp(); } + ; + +icmpbody: + icmptype icmpcode + | icmptype + | data dataline + ; + +icmpcode: + IL_ICMPCODE token { set_icmpcodetok(&yylval.str); } + ; + + +icmptype: + IL_ICMP_ECHOREPLY { set_icmptype(ICMP_ECHOREPLY); } + | IL_ICMP_ECHOREPLY IL_LBRACE icmpechoopts IL_RBRACE + | unreach + | IL_ICMP_SOURCEQUENCH { set_icmptype(ICMP_SOURCEQUENCH); } + | redirect + | IL_ICMP_ROUTERADVERT { set_icmptype(ICMP_ROUTERADVERT); } + | IL_ICMP_ROUTERSOLICIT { set_icmptype(ICMP_ROUTERSOLICIT); } + | IL_ICMP_ECHO { set_icmptype(ICMP_ECHO); } + | IL_ICMP_ECHO IL_LBRACE icmpechoopts IL_RBRACE + | IL_ICMP_TIMXCEED { set_icmptype(ICMP_TIMXCEED); } + | IL_ICMP_TIMXCEED IL_LBRACE exceed IL_RBRACE + | IL_ICMP_TSTAMP { set_icmptype(ICMP_TSTAMP); } + | IL_ICMP_TSTAMPREPLY { set_icmptype(ICMP_TSTAMPREPLY); } + | IL_ICMP_TSTAMPREPLY IL_LBRACE icmptsopts IL_RBRACE + | IL_ICMP_IREQ { set_icmptype(ICMP_IREQ); } + | IL_ICMP_IREQREPLY { set_icmptype(ICMP_IREQREPLY); } + | IL_ICMP_IREQREPLY IL_LBRACE data dataline IL_RBRACE + | IL_ICMP_MASKREQ { set_icmptype(ICMP_MASKREQ); } + | IL_ICMP_MASKREPLY { set_icmptype(ICMP_MASKREPLY); } + | IL_ICMP_MASKREPLY IL_LBRACE token IL_RBRACE + | IL_ICMP_PARAMPROB { set_icmptype(ICMP_PARAMPROB); } + | IL_ICMP_PARAMPROB IL_LBRACE paramprob IL_RBRACE + | token { set_icmptypetok(&yylval.str); } + ; + +icmpechoopts: + | icmpechoopts icmpecho + ; + +icmpecho: + IL_ICMP_SEQ number { set_icmpseq(yylval.num); } + | IL_ICMP_ID number { set_icmpid(yylval.num); } + ; + +icmptsopts: + | icmptsopts icmpts + ; + +icmpts: IL_ICMP_OTIME number { set_icmpotime(yylval.num); } + | IL_ICMP_RTIME number { set_icmprtime(yylval.num); } + | IL_ICMP_TTIME number { set_icmpttime(yylval.num); } + ; + +unreach: + IL_ICMP_UNREACH + | IL_ICMP_UNREACH IL_LBRACE unreachopts IL_RBRACE + ; + +unreachopts: + IL_ICMP_UNREACH_NET line + | IL_ICMP_UNREACH_HOST line + | IL_ICMP_UNREACH_PROTOCOL line + | IL_ICMP_UNREACH_PORT line + | IL_ICMP_UNREACH_NEEDFRAG number { set_icmpmtu(yylval.num); } + | IL_ICMP_UNREACH_SRCFAIL line + | IL_ICMP_UNREACH_NET_UNKNOWN line + | IL_ICMP_UNREACH_HOST_UNKNOWN line + | IL_ICMP_UNREACH_ISOLATED line + | IL_ICMP_UNREACH_NET_PROHIB line + | IL_ICMP_UNREACH_HOST_PROHIB line + | IL_ICMP_UNREACH_TOSNET line + | IL_ICMP_UNREACH_TOSHOST line + | IL_ICMP_UNREACH_FILTER_PROHIB line + | IL_ICMP_UNREACH_HOST_PRECEDENCE line + | IL_ICMP_UNREACH_PRECEDENCE_CUTOFF line + ; + +redirect: + IL_ICMP_REDIRECT + | IL_ICMP_REDIRECT IL_LBRACE redirectopts IL_RBRACE + ; + +redirectopts: + | IL_ICMP_REDIRECT_NET token { set_redir(0, &yylval.str); } + | IL_ICMP_REDIRECT_HOST token { set_redir(1, &yylval.str); } + | IL_ICMP_REDIRECT_TOSNET token { set_redir(2, &yylval.str); } + | IL_ICMP_REDIRECT_TOSHOST token { set_redir(3, &yylval.str); } + ; + +exceed: + IL_ICMP_TIMXCEED_INTRANS line + | IL_ICMP_TIMXCEED_REASS line + ; + +paramprob: + IL_ICMP_PARAMPROB_OPTABSENT + | IL_ICMP_PARAMPROB_OPTABSENT paraprobarg + +paraprobarg: + IL_LBRACE number IL_RBRACE { set_icmppprob(yylval.num); } + ; + +ipv4opt: IL_V4OPT { new_ipv4opt(); } + ; + +ipv4optlist: + | ipv4opts ipv4optlist + ; + +ipv4opts: + IL_IPO_NOP IL_SEMICOLON { add_ipopt(IL_IPO_NOP, NULL); } + | IL_IPO_RR optnumber { add_ipopt(IL_IPO_RR, &yylval.num); } + | IL_IPO_ZSU IL_SEMICOLON { add_ipopt(IL_IPO_ZSU, NULL); } + | IL_IPO_MTUP IL_SEMICOLON { add_ipopt(IL_IPO_MTUP, NULL); } + | IL_IPO_MTUR IL_SEMICOLON { add_ipopt(IL_IPO_MTUR, NULL); } + | IL_IPO_ENCODE IL_SEMICOLON { add_ipopt(IL_IPO_ENCODE, NULL); } + | IL_IPO_TS IL_SEMICOLON { add_ipopt(IL_IPO_TS, NULL); } + | IL_IPO_TR IL_SEMICOLON { add_ipopt(IL_IPO_TR, NULL); } + | IL_IPO_SEC IL_SEMICOLON { add_ipopt(IL_IPO_SEC, NULL); } + | IL_IPO_SECCLASS secclass { add_ipopt(IL_IPO_SECCLASS, sclass); } + | IL_IPO_LSRR token { add_ipopt(IL_IPO_LSRR,&yylval.str); } + | IL_IPO_ESEC IL_SEMICOLON { add_ipopt(IL_IPO_ESEC, NULL); } + | IL_IPO_CIPSO IL_SEMICOLON { add_ipopt(IL_IPO_CIPSO, NULL); } + | IL_IPO_SATID optnumber { add_ipopt(IL_IPO_SATID,&yylval.num);} + | IL_IPO_SSRR token { add_ipopt(IL_IPO_SSRR,&yylval.str); } + | IL_IPO_ADDEXT IL_SEMICOLON { add_ipopt(IL_IPO_ADDEXT, NULL); } + | IL_IPO_VISA IL_SEMICOLON { add_ipopt(IL_IPO_VISA, NULL); } + | IL_IPO_IMITD IL_SEMICOLON { add_ipopt(IL_IPO_IMITD, NULL); } + | IL_IPO_EIP IL_SEMICOLON { add_ipopt(IL_IPO_EIP, NULL); } + | IL_IPO_FINN IL_SEMICOLON { add_ipopt(IL_IPO_FINN, NULL); } + ; + +secclass: + IL_IPS_RESERV4 { set_secclass(&yylval.str); } + | IL_IPS_TOPSECRET { set_secclass(&yylval.str); } + | IL_IPS_SECRET { set_secclass(&yylval.str); } + | IL_IPS_RESERV3 { set_secclass(&yylval.str); } + | IL_IPS_CONFID { set_secclass(&yylval.str); } + | IL_IPS_UNCLASS { set_secclass(&yylval.str); } + | IL_IPS_RESERV2 { set_secclass(&yylval.str); } + | IL_IPS_RESERV1 { set_secclass(&yylval.str); } + ; + +data: IL_DATA { new_data(); } + ; + +dataline: + IL_LBRACE databody IL_RBRACE { end_data(); } + ; + +databody: dataopts IL_SEMICOLON + | dataopts IL_SEMICOLON databody + ; + +dataopts: + IL_DLEN IL_TOKEN { set_datalen(&yylval.str); } + | IL_DVALUE IL_TOKEN { set_data(&yylval.str); } + | IL_DFILE IL_TOKEN { set_datafile(&yylval.str); } + ; + +token: IL_TOKEN IL_SEMICOLON + ; + +optoken: IL_SEMICOLON + | token + ; + +number: digits IL_SEMICOLON + ; + +optnumber: IL_SEMICOLON + | number + ; + +digits: IL_NUMBER + | digits IL_NUMBER + ; +%% + +struct statetoopt toipopts[] = { + { IL_IPO_NOP, IPOPT_NOP }, + { IL_IPO_RR, IPOPT_RR }, + { IL_IPO_ZSU, IPOPT_ZSU }, + { IL_IPO_MTUP, IPOPT_MTUP }, + { IL_IPO_MTUR, IPOPT_MTUR }, + { IL_IPO_ENCODE, IPOPT_ENCODE }, + { IL_IPO_TS, IPOPT_TS }, + { IL_IPO_TR, IPOPT_TR }, + { IL_IPO_SEC, IPOPT_SECURITY }, + { IL_IPO_SECCLASS, IPOPT_SECURITY }, + { IL_IPO_LSRR, IPOPT_LSRR }, + { IL_IPO_ESEC, IPOPT_E_SEC }, + { IL_IPO_CIPSO, IPOPT_CIPSO }, + { IL_IPO_SATID, IPOPT_SATID }, + { IL_IPO_SSRR, IPOPT_SSRR }, + { IL_IPO_ADDEXT, IPOPT_ADDEXT }, + { IL_IPO_VISA, IPOPT_VISA }, + { IL_IPO_IMITD, IPOPT_IMITD }, + { IL_IPO_EIP, IPOPT_EIP }, + { IL_IPO_FINN, IPOPT_FINN }, + { 0, 0 } +}; + +struct statetoopt tosecopts[] = { + { IL_IPS_RESERV4, IPSO_CLASS_RES4 }, + { IL_IPS_TOPSECRET, IPSO_CLASS_TOPS }, + { IL_IPS_SECRET, IPSO_CLASS_SECR }, + { IL_IPS_RESERV3, IPSO_CLASS_RES3 }, + { IL_IPS_CONFID, IPSO_CLASS_CONF }, + { IL_IPS_UNCLASS, IPSO_CLASS_UNCL }, + { IL_IPS_RESERV2, IPSO_CLASS_RES2 }, + { IL_IPS_RESERV1, IPSO_CLASS_RES1 }, + { 0, 0 } +}; + + +struct in_addr getipv4addr(arg) +char *arg; +{ + struct hostent *hp; + struct in_addr in; + + in.s_addr = 0xffffffff; + + if ((hp = gethostbyname(arg))) + bcopy(hp->h_addr, &in.s_addr, sizeof(struct in_addr)); + else + in.s_addr = inet_addr(arg); + return in; +} + + +u_short getportnum(pr, name) +char *pr, *name; +{ + struct servent *sp; + + if (!(sp = getservbyname(name, pr))) + return atoi(name); + return sp->s_port; +} + + +struct ether_addr *geteaddr(arg, buf) +char *arg; +struct ether_addr *buf; +{ + struct ether_addr *e; + + e = ether_aton(arg); + if (!e) + fprintf(stderr, "Invalid ethernet address: %s\n", arg); + else +#ifdef __FreeBSD__ + bcopy(e->octet, buf->octet, sizeof(e->octet)); +#else + bcopy(e->ether_addr_octet, buf->ether_addr_octet, + sizeof(e->ether_addr_octet)); +#endif + return e; +} + + +void *new_header(type) +int type; +{ + aniphdr_t *aip, *oip = canip; + int sz = 0; + + aip = (aniphdr_t *)calloc(1, sizeof(*aip)); + *aniptail = aip; + aniptail = &aip->ah_next; + aip->ah_p = type; + aip->ah_prev = oip; + canip = aip; + + if (type == IPPROTO_UDP) + sz = sizeof(udphdr_t); + else if (type == IPPROTO_TCP) + sz = sizeof(tcphdr_t); + else if (type == IPPROTO_ICMP) + sz = sizeof(icmphdr_t); + else if (type == IPPROTO_IP) + sz = sizeof(ip_t); + + if (oip) + canip->ah_data = oip->ah_data + oip->ah_len; + else + canip->ah_data = (char *)ipbuffer; + + /* + * Increase the size fields in all wrapping headers. + */ + for (aip = aniphead; aip; aip = aip->ah_next) { + aip->ah_len += sz; + if (aip->ah_p == IPPROTO_IP) + aip->ah_ip->ip_len += sz; + else if (aip->ah_p == IPPROTO_UDP) + aip->ah_udp->uh_ulen += sz; + } + return (void *)canip->ah_data; +} + + +void free_aniplist() +{ + aniphdr_t *aip, **aipp = &aniphead; + + while ((aip = *aipp)) { + *aipp = aip->ah_next; + free(aip); + } + aniptail = &aniphead; +} + + +void inc_anipheaders(inc) +int inc; +{ + aniphdr_t *aip; + + for (aip = aniphead; aip; aip = aip->ah_next) { + aip->ah_len += inc; + if (aip->ah_p == IPPROTO_IP) + aip->ah_ip->ip_len += inc; + else if (aip->ah_p == IPPROTO_UDP) + aip->ah_udp->uh_ulen += inc; + } +} + + +void new_data() +{ + (void) new_header(-1); + canip->ah_len = 0; +} + + +void set_datalen(arg) +char **arg; +{ + int len; + + len = strtol(*arg, NULL, 0); + inc_anipheaders(len); + free(*arg); + *arg = NULL; +} + + +void set_data(arg) +char **arg; +{ + u_char *s = *arg, *t = canip->ah_data, c; + int len = 0, todo = 0, quote = 0, val = 0; + + while ((c = *s++)) { + if (todo) { + if (isdigit(c)) { + todo--; + if (c > '7') { + fprintf(stderr, "octal with %c!\n", c); + break; + } + val <<= 3; + val |= (c - '0'); + } + if (!isdigit(c) || !todo) { + *t++ = (u_char)(val & 0xff); + todo = 0; + } + } + if (quote) { + if (isdigit(c)) { + todo = 2; + if (c > '7') { + fprintf(stderr, "octal with %c!\n", c); + break; + } + val = (c - '0'); + } else { + switch (c) + { + case '\"' : + *t++ = '\"'; + break; + case '\\' : + *t++ = '\\'; + break; + case 'n' : + *t++ = '\n'; + break; + case 'r' : + *t++ = '\r'; + break; + case 't' : + *t++ = '\t'; + break; + } + quote = 0; + } + continue; + } + + if (c == '\\') + quote = 1; + else + *t++ = c; + } + if (quote) + *t++ = '\\'; + len = t - (u_char *)canip->ah_data; + inc_anipheaders(len - canip->ah_len); + canip->ah_len = len; +} + + +void set_datafile(arg) +char **arg; +{ + struct stat sb; + u_char *t = canip->ah_data; + char *file = *arg; + int fd, len; + + if ((fd = open(file, O_RDONLY)) == -1) { + perror("open"); + exit(-1); + } + + if (fstat(fd, &sb) == -1) { + perror("fstat"); + exit(-1); + } + + if ((sb.st_size + aniphead->ah_len ) > 65535) { + fprintf(stderr, "data file %s too big to include.\n", file); + close(fd); + return; + } + if ((len = read(fd, canip->ah_data, sb.st_size)) == -1) { + perror("read"); + close(fd); + return; + } + inc_anipheaders(len); + canip->ah_len += len; + close(fd); +} + + +void new_packet() +{ + static u_short id = 0; + + if (!aniphead) + bzero((char *)ipbuffer, sizeof(ipbuffer)); + + ip = (ip_t *)new_header(IPPROTO_IP); + ip->ip_v = IPVERSION; + ip->ip_hl = sizeof(ip_t) >> 2; + ip->ip_len = sizeof(ip_t); + ip->ip_ttl = 63; + ip->ip_id = htons(id++); +} + + +void set_ipv4proto(arg) +char **arg; +{ + struct protoent *pr; + + if ((pr = getprotobyname(*arg))) + ip->ip_p = pr->p_proto; + else + if (!(ip->ip_p = atoi(*arg))) + fprintf(stderr, "unknown protocol %s\n", *arg); + free(*arg); + *arg = NULL; +} + + +void set_ipv4src(arg) +char **arg; +{ + ip->ip_src = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +void set_ipv4dst(arg) +char **arg; +{ + ip->ip_dst = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +void set_ipv4off(arg) +char **arg; +{ + ip->ip_off = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_ipv4v(arg) +char **arg; +{ + ip->ip_v = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_ipv4hl(arg) +char **arg; +{ + int offset, newhl, inc; + + newhl = strtol(*arg, NULL, 0); + inc = (newhl - ip->ip_hl) << 2; + ip->ip_len += inc; + ip->ip_hl = newhl; + canip->ah_len += inc; + free(*arg); + *arg = NULL; +} + + +void set_ipv4ttl(arg) +char **arg; +{ + ip->ip_ttl = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_ipv4tos(arg) +char **arg; +{ + ip->ip_tos = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_ipv4id(arg) +char **arg; +{ + ip->ip_id = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_ipv4sum(arg) +char **arg; +{ + ip->ip_sum = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_ipv4len(arg) +char **arg; +{ + int len; + + len = strtol(*arg, NULL, 0); + inc_anipheaders(len - ip->ip_len); + ip->ip_len = len; + free(*arg); + *arg = NULL; +} + + +void new_tcpheader() +{ + int offset, inc; + + if ((ip->ip_p) && (ip->ip_p != IPPROTO_TCP)) { + fprintf(stderr, "protocol %d specified with TCP!\n", ip->ip_p); + return; + } + ip->ip_p = IPPROTO_TCP; + + tcp = (tcphdr_t *)new_header(IPPROTO_TCP); + tcp->th_win = 4096; + tcp->th_off = sizeof(*tcp) >> 2; +} + + +void set_tcpsport(arg) +char **arg; +{ + u_short *port; + char *pr; + + if (ip->ip_p == IPPROTO_UDP) { + port = &udp->uh_sport; + pr = "udp"; + } else { + port = &tcp->th_sport; + pr = "udp"; + } + + *port = getportnum(pr, *arg); + free(*arg); + *arg = NULL; +} + + +void set_tcpdport(arg) +char **arg; +{ + u_short *port; + char *pr; + + if (ip->ip_p == IPPROTO_UDP) { + port = &udp->uh_dport; + pr = "udp"; + } else { + port = &tcp->th_dport; + pr = "udp"; + } + + *port = getportnum(pr, *arg); + free(*arg); + *arg = NULL; +} + + +void set_tcpseq(arg) +char **arg; +{ + tcp->th_seq = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_tcpack(arg) +char **arg; +{ + tcp->th_ack = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_tcpoff(arg) +char **arg; +{ + int off; + + off = strtol(*arg, NULL, 0); + inc_anipheaders((off - tcp->th_off) << 2); + tcp->th_off = off; + free(*arg); + *arg = NULL; +} + + +void set_tcpurp(arg) +char **arg; +{ + tcp->th_urp = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_tcpwin(arg) +char **arg; +{ + tcp->th_win = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_tcpsum(arg) +char **arg; +{ + tcp->th_sum = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_tcpflags(arg) +char **arg; +{ + static char flags[] = "ASURPF"; + static int flagv[] = { TH_ACK, TH_SYN, TH_URG, TH_RST, TH_PUSH, + TH_FIN } ; + char *s, *t; + int nf = 0; + + for (s = *arg; *s; s++) + if (!(t = strchr(flags, *s))) { + if (s - *arg) { + fprintf(stderr, "unknown TCP flag %c\n", *s); + break; + } + tcp->th_flags = strtol(*arg, NULL, 0); + break; + } else + tcp->th_flags |= flagv[t - flags]; + free(*arg); + *arg = NULL; +} + + +void set_tcpopt(state, arg) +int state; +char **arg; +{ + u_char *s; + int val, len, val2, pad, optval; + + if (arg && *arg) + val = atoi(*arg); + else + val = 0; + + s = (u_char *)tcp + sizeof(*tcp) + canip->ah_optlen; + switch (state) + { + case IL_TCPO_EOL : + optval = 0; + len = 1; + break; + case IL_TCPO_NOP : + optval = 1; + len = 1; + break; + case IL_TCPO_MSS : + optval = 2; + len = 4; + break; + case IL_TCPO_WSCALE : + optval = 3; + len = 3; + break; + case IL_TCPO_TS : + optval = 8; + len = 10; + break; + default : + optval = 0; + len = 0; + break; + } + + if (len > 1) { + /* + * prepend padding - if required. + */ + if (len & 3) + for (pad = 4 - (len & 3); pad; pad--) { + *s++ = 1; + canip->ah_optlen++; + } + /* + * build tcp option + */ + *s++ = (u_char)optval; + *s++ = (u_char)len; + if (len > 2) { + if (len == 3) { /* 1 byte - char */ + *s++ = (u_char)val; + } else if (len == 4) { /* 2 bytes - short */ + *s++ = (u_char)((val >> 8) & 0xff); + *s++ = (u_char)(val & 0xff); + } else if (len >= 6) { /* 4 bytes - long */ + val2 = htonl(val); + bcopy((char *)&val2, s, 4); + } + s += (len - 2); + } + } else + *s++ = (u_char)optval; + + canip->ah_lastopt = optval; + canip->ah_optlen += len; + + if (arg && *arg) { + free(*arg); + *arg = NULL; + } +} + + +void end_tcpopt() +{ + int pad; + char *s = (char *)tcp; + + s += sizeof(*tcp) + canip->ah_optlen; + /* + * pad out so that we have a multiple of 4 bytes in size fo the + * options. make sure last byte is EOL. + */ + if (canip->ah_optlen & 3) { + if (canip->ah_lastopt != 1) { + for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) { + *s++ = 1; + canip->ah_optlen++; + } + canip->ah_optlen++; + } else { + s -= 1; + + for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) { + *s++ = 1; + canip->ah_optlen++; + } + } + *s++ = 0; + } + tcp->th_off = (sizeof(*tcp) + canip->ah_optlen) >> 2; + inc_anipheaders(canip->ah_optlen); +} + + +void new_udpheader() +{ + if ((ip->ip_p) && (ip->ip_p != IPPROTO_UDP)) { + fprintf(stderr, "protocol %d specified with UDP!\n", ip->ip_p); + return; + } + ip->ip_p = IPPROTO_UDP; + + udp = (udphdr_t *)new_header(IPPROTO_UDP); + udp->uh_ulen = sizeof(*udp); +} + + +void set_udplen(arg) +char **arg; +{ + int len; + + len = strtol(*arg, NULL, 0); + inc_anipheaders(len - udp->uh_ulen); + udp->uh_ulen = len; + free(*arg); + *arg = NULL; +} + + +void set_udpsum(arg) +char **arg; +{ + udp->uh_sum = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void prep_packet() +{ + iface_t *ifp; + struct in_addr gwip; + + ifp = sending.snd_if; + if (!ifp) { + fprintf(stderr, "no interface defined for sending!\n"); + return; + } + if (ifp->if_fd == -1) + ifp->if_fd = initdevice(ifp->if_name, 0, 5); + gwip = sending.snd_gw; + if (!gwip.s_addr) + gwip = aniphead->ah_ip->ip_dst; + (void) send_ip(ifp->if_fd, ifp->if_MTU, (ip_t *)ipbuffer, gwip, 2); +} + + +void packet_done() +{ + char outline[80]; + int i, j, k; + u_char *s = (u_char *)ipbuffer, *t = (u_char *)outline; + + if (opts & OPT_VERBOSE) { + for (i = ip->ip_len, j = 0; i; i--, j++, s++) { + if (j && !(j & 0xf)) { + *t++ = '\n'; + *t = '\0'; + fputs(outline, stdout); + fflush(stdout); + t = (u_char *)outline; + *t = '\0'; + } + sprintf(t, "%02x", *s & 0xff); + t += 2; + if (!((j + 1) & 0xf)) { + s -= 15; + sprintf(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(t, " "); + t += 7; + s -= j & 0xf; + for (k = j & 0xf; k; k--, s++) + *t++ = (isprint(*s) ? *s : '.'); + *t++ = '\n'; + *t = '\0'; + } + fputs(outline, stdout); + fflush(stdout); + } + + prep_packet(); + free_aniplist(); +} + + +void new_interface() +{ + cifp = (iface_t *)calloc(1, sizeof(iface_t)); + *iftail = cifp; + iftail = &cifp->if_next; + cifp->if_fd = -1; +} + + +void check_interface() +{ + if (!cifp->if_name || !*cifp->if_name) + fprintf(stderr, "No interface name given!\n"); + if (!cifp->if_MTU || !*cifp->if_name) + fprintf(stderr, "Interface %s has an MTU of 0!\n", + cifp->if_name); +} + + +void set_ifname(arg) +char **arg; +{ + cifp->if_name = *arg; + *arg = NULL; +} + + +void set_ifmtu(arg) +int arg; +{ + cifp->if_MTU = arg; +} + + +void set_ifv4addr(arg) +char **arg; +{ + cifp->if_addr = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +void set_ifeaddr(arg) +char **arg; +{ + (void) geteaddr(*arg, &cifp->if_eaddr); + free(*arg); + *arg = NULL; +} + + +void new_arp() +{ + carp = (arp_t *)calloc(1, sizeof(arp_t)); + *arptail = carp; + arptail = &carp->arp_next; +} + + +void set_arpeaddr(arg) +char **arg; +{ + (void) geteaddr(*arg, &carp->arp_eaddr); + free(*arg); + *arg = NULL; +} + + +void set_arpv4addr(arg) +char **arg; +{ + carp->arp_addr = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +void reset_send() +{ + sending.snd_if = iflist; + sending.snd_gw = defrouter; +} + + +void set_sendif(arg) +char **arg; +{ + iface_t *ifp; + + for (ifp = iflist; ifp; ifp = ifp->if_next) + if (ifp->if_name && !strcmp(ifp->if_name, *arg)) + break; + sending.snd_if = ifp; + if (!ifp) + fprintf(stderr, "couldn't find interface %s\n", *arg); + free(*arg); + *arg = NULL; +} + + +void set_sendvia(arg) +char **arg; +{ + sending.snd_gw = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +void set_defaultrouter(arg) +char **arg; +{ + defrouter = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +void new_icmpheader() +{ + if ((ip->ip_p) && (ip->ip_p != IPPROTO_ICMP)) { + fprintf(stderr, "protocol %d specified with ICMP!\n", + ip->ip_p); + return; + } + ip->ip_p = IPPROTO_ICMP; + icmp = (icmphdr_t *)new_header(IPPROTO_ICMP); +} + + +void set_icmpcode(code) +int code; +{ + icmp->icmp_code = code; +} + + +void set_icmptype(type) +int type; +{ + icmp->icmp_type = type; +} + + +static char *icmpcodes[] = { + "net-unr", "host-unr", "proto-unr", "port-unr", "needfrag", "srcfail", + "net-unk", "host-unk", "isolate", "net-prohib", "host-prohib", + "net-tos", "host-tos", NULL }; + +void set_icmpcodetok(code) +char **code; +{ + char *s; + int i; + + for (i = 0; (s = icmpcodes[i]); i++) + if (!strcmp(s, *code)) { + icmp->icmp_code = i; + break; + } + if (!s) + fprintf(stderr, "unknown ICMP code %s\n", *code); + free(*code); + *code = NULL; +} + + +static char *icmptypes[] = { + "echorep", (char *)NULL, (char *)NULL, "unreach", "squench", + "redir", (char *)NULL, (char *)NULL, "echo", (char *)NULL, + (char *)NULL, "timex", "paramprob", "timest", "timestrep", + "inforeq", "inforep", "maskreq", "maskrep", "END" +}; + +void set_icmptypetok(type) +char **type; +{ + char *s; + int i, done = 0; + + for (i = 0; !(s = icmptypes[i]) || strcmp(s, "END"); i++) + if (s && !strcmp(s, *type)) { + icmp->icmp_type = i; + done = 1; + break; + } + if (!done) + fprintf(stderr, "unknown ICMP type %s\n", *type); + free(*type); + *type = NULL; +} + + +void set_icmpid(arg) +int arg; +{ + icmp->icmp_id = arg; +} + + +void set_icmpseq(arg) +int arg; +{ + icmp->icmp_seq = arg; +} + + +void set_icmpotime(arg) +int arg; +{ + icmp->icmp_otime = arg; +} + + +void set_icmprtime(arg) +int arg; +{ + icmp->icmp_rtime = arg; +} + + +void set_icmpttime(arg) +int arg; +{ + icmp->icmp_ttime = arg; +} + + +void set_icmpmtu(arg) +int arg; +{ +#if BSD >= 199306 + icmp->icmp_nextmtu = arg; +#endif +} + + +void set_redir(redir, arg) +int redir; +char **arg; +{ + icmp->icmp_code = redir; + icmp->icmp_gwaddr = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +void set_icmppprob(num) +int num; +{ + icmp->icmp_pptr = num; +} + + +void new_ipv4opt() +{ + new_header(-2); +} + + +void add_ipopt(state, ptr) +int state; +void *ptr; +{ + struct ipopt_names *io; + struct statetoopt *sto; + char *op, numbuf[16], *arg, **param = ptr; + int inc, optlen, hlen, *inptr; + + if (state == IL_IPO_RR || state == IL_IPO_SATID) { + if (param) + sprintf(numbuf, "%d", *(int *)param); + else + strcpy(numbuf, "0"); + arg = numbuf; + } else + arg = param ? *param : NULL; + + if (canip->ah_next) { + fprintf(stderr, "cannot specify options after data body\n"); + return; + } + for (sto = toipopts; sto->sto_st; sto++) + if (sto->sto_st == state) + break; + if (!sto || !sto->sto_st) { + fprintf(stderr, "No mapping for state %d to IP option\n", + state); + return; + } + + hlen = sizeof(ip_t) + canip->ah_optlen; + for (io = ionames; io->on_name; io++) + if (io->on_value == sto->sto_op) + break; + canip->ah_lastopt = io->on_value; + + if (io->on_name) { + inc = addipopt((char *)ip + hlen, io, hlen - sizeof(ip_t),arg); + if (inc > 0) { + while (inc & 3) { + ((char *)ip)[sizeof(*ip) + inc] = IPOPT_NOP; + canip->ah_lastopt = IPOPT_NOP; + inc++; + } + hlen += inc; + } + } + + canip->ah_optlen = hlen - sizeof(ip_t); + + if (state != IL_IPO_RR && state != IL_IPO_SATID) + if (param && *param) { + free(*param); + *param = NULL; + } + sclass = NULL; +} + + +void end_ipopt() +{ + int pad; + char *s, *buf = (char *)ip; + + /* + * pad out so that we have a multiple of 4 bytes in size fo the + * options. make sure last byte is EOL. + */ + if (canip->ah_lastopt == IPOPT_NOP) { + buf[sizeof(*ip) + canip->ah_optlen - 1] = IPOPT_EOL; + } else if (canip->ah_lastopt != IPOPT_EOL) { + s = buf + sizeof(*ip) + canip->ah_optlen; + + for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) { + *s++ = IPOPT_NOP; + *s = IPOPT_EOL; + canip->ah_optlen++; + } + canip->ah_optlen++; + } else { + s = buf + sizeof(*ip) + canip->ah_optlen - 1; + + for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) { + *s++ = IPOPT_NOP; + *s = IPOPT_EOL; + canip->ah_optlen++; + } + } + ip->ip_hl = (sizeof(*ip) + canip->ah_optlen) >> 2; + inc_anipheaders(canip->ah_optlen); + free_anipheader(); +} + + +void set_secclass(arg) +char **arg; +{ + sclass = *arg; + *arg = NULL; +} + + +void free_anipheader() +{ + aniphdr_t *aip; + + aip = canip; + if ((canip = aip->ah_prev)) { + canip->ah_next = NULL; + aniptail = &canip->ah_next; + } + free(aip); +} + + +void end_ipv4() +{ + aniphdr_t *aip; + + ip->ip_sum = 0; + ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); + free_anipheader(); + for (aip = aniphead, ip = NULL; aip; aip = aip->ah_next) + if (aip->ah_p == IPPROTO_IP) + ip = aip->ah_ip; +} + + +void end_icmp() +{ + aniphdr_t *aip; + + icmp->icmp_cksum = 0; + icmp->icmp_cksum = chksum((u_short *)icmp, canip->ah_len); + free_anipheader(); + for (aip = aniphead, icmp = NULL; aip; aip = aip->ah_next) + if (aip->ah_p == IPPROTO_ICMP) + icmp = aip->ah_icmp; +} + + +void end_udp() +{ + u_long sum; + aniphdr_t *aip; + ip_t iptmp; + + bzero((char *)&iptmp, sizeof(iptmp)); + iptmp.ip_p = ip->ip_p; + iptmp.ip_src = ip->ip_src; + iptmp.ip_dst = ip->ip_dst; + iptmp.ip_len = ip->ip_len - (ip->ip_hl << 2); + sum = p_chksum((u_short *)&iptmp, (u_int)sizeof(iptmp)); + udp->uh_sum = c_chksum((u_short *)udp, (u_int)iptmp.ip_len, sum); + free_anipheader(); + for (aip = aniphead, udp = NULL; aip; aip = aip->ah_next) + if (aip->ah_p == IPPROTO_UDP) + udp = aip->ah_udp; +} + + +void end_tcp() +{ + u_long sum; + aniphdr_t *aip; + ip_t iptmp; + + bzero((char *)&iptmp, sizeof(iptmp)); + iptmp.ip_p = ip->ip_p; + iptmp.ip_src = ip->ip_src; + iptmp.ip_dst = ip->ip_dst; + iptmp.ip_len = ip->ip_len - (ip->ip_hl << 2); + sum = p_chksum((u_short *)&iptmp, (u_int)sizeof(iptmp)); + tcp->th_sum = 0; + tcp->th_sum = c_chksum((u_short *)tcp, (u_int)iptmp.ip_len, sum); + free_anipheader(); + for (aip = aniphead, tcp = NULL; aip; aip = aip->ah_next) + if (aip->ah_p == IPPROTO_TCP) + tcp = aip->ah_tcp; +} + + +void end_data() +{ + free_anipheader(); +} + + +void yyerror(msg) +char *msg; +{ + fprintf(stderr, "%s error at \"%s\", line %d\n", msg, yytext, + lineNum + 1); + exit(1); +} + + +void iplang(fp) +FILE *fp; +{ + yyin = fp; + + while (!feof(fp)) + yyparse(); +} + + +u_short c_chksum(buf, len, init) +u_short *buf; +u_int len; +u_long init; +{ + u_long sum = init; + int nwords = len >> 1; + + for(; nwords > 0; nwords--) + sum += *buf++; + sum = (sum>>16) + (sum & 0xffff); + sum += (sum >>16); + return (~sum); +} + + +u_long p_chksum(buf,len) +u_short *buf; +u_int len; +{ + u_long sum = 0; + int nwords = len >> 1; + + for(; nwords > 0; nwords--) + sum += *buf++; + return sum; +} diff --git a/usr.sbin/ipf/ipsend/ipsend.1 b/usr.sbin/ipf/ipsend/ipsend.1 new file mode 100644 index 000000000000..7494de8ccf18 --- /dev/null +++ b/usr.sbin/ipf/ipsend/ipsend.1 @@ -0,0 +1,102 @@ +.TH IPSEND 1 +.SH NAME +ipsend \- sends IP packets +.SH SYNOPSIS +.B ipsend +[ +.B \-ITU +] [ +.B \-d + +] [ +.B \-f +<\fIoffset\fP> +] [ +.B \-g +<\fIgateway\fP> +] [ +.B \-m +<\fIMTU\fP> +] [ +.B \-o +<\fIoption\fP> +] [ +.B \-P + +] [ +.B \-s +<\fIsource\fP> +] [ +.B \-t +<\fIdest. port\fP> +] [ +.B \-w +<\fIwindow\fP> +] [TCP-flags] +.SH DESCRIPTION +.PP +\fBipsend\fP can be compiled in two ways. The first is used to send one-off +packets to a destination host, using command line options to specify various +attributes present in the headers. The \fIdestination\fP must be given as +the last command line option, except for when TCP flags are specified as +a combination of A, S, F, U, P and R, last. +.PP +The other way it may be compiled, with DOSOCKET defined, is to allow an +attempt at making a TCP connection using a with ipsend resending the SYN +packet as per the command line options. +.SH OPTIONS +.TP +.BR \-d \0 +Set the interface name to be the name supplied. +.TP +.BR \-f \0 +The \fI-f\fP allows the IP offset field in the IP header to be set to an +arbitrary value, which can be specified in decimal or hexidecimal. +.TP +.BR \-g \0 +Specify the hostname of the gateway through which to route packets. This +is required whenever the destination host isn't directly attached to the +same network as the host from which you're sending. +.TP +.BR \-m \0 +Specify the MTU to be used when sending out packets. This option allows you +to set a fake MTU, allowing the simulation of network interfaces with small +MTU's without setting them so. +.TP +.BR \-o \0