From 73ce1b460d30f625453a70f252910be0d1d56502 Mon Sep 17 00:00:00 2001 From: guy Date: Tue, 19 Apr 2005 04:26:06 +0000 Subject: [PATCH] From Patrick Marie : add support for port ranges in tests - "portrange X-Y" matches all ports in the range [X,Y]. Support added for port ranges with IPv6. Fix some comments. --- CREDITS | 1 + gencode.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++++- gencode.h | 3 +- grammar.y | 5 +- nametoaddr.c | 47 +++++++- pcap-namedb.h | 3 +- scanner.l | 3 +- 7 files changed, 369 insertions(+), 9 deletions(-) diff --git a/CREDITS b/CREDITS index 1cc579b..7c0e9cc 100644 --- a/CREDITS +++ b/CREDITS @@ -68,6 +68,7 @@ Additional people who have contributed patches: Octavian Cerna Olaf Kirch Onno van der Linden + Patrick Marie Paul Mundt Pavel Kankovsky Peter Fales diff --git a/gencode.c b/gencode.c index d4946ed..53ecbcc 100644 --- a/gencode.c +++ b/gencode.c @@ -21,7 +21,7 @@ */ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.4 2005-04-18 22:40:14 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.5 2005-04-19 04:26:06 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -193,14 +193,20 @@ static struct block *gen_gateway(const u_char *, bpf_u_int32 **, int, int); #endif static struct block *gen_ipfrag(void); static struct block *gen_portatom(int, bpf_int32); +static struct block *gen_portrangeatom(int, bpf_int32, bpf_int32); #ifdef INET6 static struct block *gen_portatom6(int, bpf_int32); +static struct block *gen_portrangeatom6(int, bpf_int32, bpf_int32); #endif struct block *gen_portop(int, int, int); static struct block *gen_port(int, int, int); +struct block *gen_portrangeop(int, int, int, int); +static struct block *gen_portrange(int, int, int, int); #ifdef INET6 struct block *gen_portop6(int, int, int); static struct block *gen_port6(int, int, int); +struct block *gen_portrangeop6(int, int, int, int); +static struct block *gen_portrange6(int, int, int, int); #endif static int lookup_proto(const char *, int); static struct block *gen_protochain(int, int, int); @@ -3315,7 +3321,7 @@ gen_portop6(port, proto, dir) { struct block *b0, *b1, *tmp; - /* ip proto 'proto' */ + /* ip6 proto 'proto' */ b0 = gen_cmp(off_nl + 6, BPF_B, (bpf_int32)proto); switch (dir) { @@ -3356,7 +3362,7 @@ gen_port6(port, ip_proto, dir) { struct block *b0, *b1, *tmp; - /* ether proto ip */ + /* link proto ip6 */ b0 = gen_linktype(ETHERTYPE_IPV6); switch (ip_proto) { @@ -3382,6 +3388,242 @@ gen_port6(port, ip_proto, dir) } #endif /* INET6 */ +/* gen_portrange code */ +struct block * +gen_portrangeatom(off, v1, v2) + int off; + bpf_int32 v1, v2; +{ + struct slist *s1, *s2; + struct block *b1, *b2; + + if (v1 > v2) { + /* + * Reverse the order of the ports, so v1 is the lower one. + */ + bpf_int32 vtemp; + + vtemp = v1; + v1 = v2; + v2 = vtemp; + } + s1 = new_stmt(BPF_LDX|BPF_MSH|BPF_B); + s1->s.k = off_nl; + + s1->next = new_stmt(BPF_LD|BPF_IND|BPF_H); + s1->next->s.k = off_nl + off; + + b1 = new_block(JMP(BPF_JGE)); + b1->stmts = s1; + b1->s.k = v1; + + s2 = new_stmt(BPF_LDX|BPF_MSH|BPF_B); + s2->s.k = off_nl; + + s2->next = new_stmt(BPF_LD|BPF_IND|BPF_H); + s2->next->s.k = off_nl + off; + + b2 = new_block(JMP(BPF_JGT)); + gen_not(b2); + b2->stmts = s2; + b2->s.k = v2; + + gen_and(b1, b2); + + return b2; +} + +struct block * +gen_portrangeop(port1, port2, proto, dir) + int port1, port2; + int proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + /* ip proto 'proto' */ + tmp = gen_cmp(off_nl + 9, BPF_B, (bpf_int32)proto); + b0 = gen_ipfrag(); + gen_and(tmp, b0); + + switch (dir) { + case Q_SRC: + b1 = gen_portrangeatom(0, (bpf_int32)port1, (bpf_int32)port2); + break; + + case Q_DST: + b1 = gen_portrangeatom(2, (bpf_int32)port1, (bpf_int32)port2); + break; + + case Q_OR: + case Q_DEFAULT: + tmp = gen_portrangeatom(0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom(2, (bpf_int32)port1, (bpf_int32)port2); + gen_or(tmp, b1); + break; + + case Q_AND: + tmp = gen_portrangeatom(0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom(2, (bpf_int32)port1, (bpf_int32)port2); + gen_and(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + + return b1; +} + +static struct block * +gen_portrange(port1, port2, ip_proto, dir) + int port1, port2; + int ip_proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + /* link proto ip */ + b0 = gen_linktype(ETHERTYPE_IP); + + switch (ip_proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + b1 = gen_portrangeop(port1, port2, ip_proto, dir); + break; + + case PROTO_UNDEF: + tmp = gen_portrangeop(port1, port2, IPPROTO_TCP, dir); + b1 = gen_portrangeop(port1, port2, IPPROTO_UDP, dir); + gen_or(tmp, b1); + tmp = gen_portrangeop(port1, port2, IPPROTO_SCTP, dir); + gen_or(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + return b1; +} + +#ifdef INET6 +struct block * +gen_portrangeatom6(off, v1, v2) + int off; + bpf_int32 v1, v2; +{ + struct slist *s1, *s2; + struct block *b1, *b2; + + if (v1 > v2) { + /* + * Reverse the order of the ports, so v1 is the lower one. + */ + bpf_int32 vtemp; + + vtemp = v1; + v1 = v2; + v2 = vtemp; + } + + s1 = new_stmt(BPF_LD|BPF_ABS|BPF_H); + s1->s.k = off_nl + 40 + off; + + b1 = new_block(JMP(BPF_JGE)); + b1->stmts = s1; + b1->s.k = v1; + + s2 = new_stmt(BPF_LD|BPF_ABS|BPF_H); + s2->s.k = off_nl + 40 + off; + + b2 = new_block(JMP(BPF_JGT)); + gen_not(b2); + b2->stmts = s2; + b2->s.k = v2; + + gen_and(b1, b2); + + return b2; +} + +struct block * +gen_portrangeop6(port1, port2, proto, dir) + int port1, port2; + int proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + /* ip6 proto 'proto' */ + b0 = gen_cmp(off_nl + 6, BPF_B, (bpf_int32)proto); + + switch (dir) { + case Q_SRC: + b1 = gen_portrangeatom6(0, (bpf_int32)port1, (bpf_int32)port2); + break; + + case Q_DST: + b1 = gen_portrangeatom6(2, (bpf_int32)port1, (bpf_int32)port2); + break; + + case Q_OR: + case Q_DEFAULT: + tmp = gen_portrangeatom6(0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom6(2, (bpf_int32)port1, (bpf_int32)port2); + gen_or(tmp, b1); + break; + + case Q_AND: + tmp = gen_portrangeatom6(0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom6(2, (bpf_int32)port1, (bpf_int32)port2); + gen_and(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + + return b1; +} + +static struct block * +gen_portrange6(port1, port2, ip_proto, dir) + int port1, port2; + int ip_proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + /* link proto ip6 */ + b0 = gen_linktype(ETHERTYPE_IPV6); + + switch (ip_proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + b1 = gen_portrangeop6(port1, port2, ip_proto, dir); + break; + + case PROTO_UNDEF: + tmp = gen_portrangeop6(port1, port2, IPPROTO_TCP, dir); + b1 = gen_portrangeop6(port1, port2, IPPROTO_UDP, dir); + gen_or(tmp, b1); + tmp = gen_portrangeop6(port1, port2, IPPROTO_SCTP, dir); + gen_or(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + return b1; +} +#endif /* INET6 */ + static int lookup_proto(name, proto) register const char *name; @@ -3963,6 +4205,7 @@ gen_scode(name, q) #endif /*INET6*/ struct block *b, *tmp; int port, real_proto; + int port1, port2; switch (q.addr) { @@ -4170,6 +4413,50 @@ gen_scode(name, q) } #endif /* INET6 */ + case Q_PORTRANGE: + if (proto != Q_DEFAULT && + proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP) + bpf_error("illegal qualifier of 'portrange'"); + if (pcap_nametoportrange(name, &port1, &port2, &real_proto) == 0) + bpf_error("unknown port in range '%s'", name); + if (proto == Q_UDP) { + if (real_proto == IPPROTO_TCP) + bpf_error("port in range '%s' is tcp", name); + else if (real_proto == IPPROTO_SCTP) + bpf_error("port in range '%s' is sctp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_UDP; + } + if (proto == Q_TCP) { + if (real_proto == IPPROTO_UDP) + bpf_error("port in range '%s' is udp", name); + else if (real_proto == IPPROTO_SCTP) + bpf_error("port in range '%s' is sctp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_TCP; + } + if (proto == Q_SCTP) { + if (real_proto == IPPROTO_UDP) + bpf_error("port in range '%s' is udp", name); + else if (real_proto == IPPROTO_TCP) + bpf_error("port in range '%s' is tcp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_SCTP; + } +#ifndef INET6 + return gen_portrange(port1, port2, real_proto, dir); +#else + { + struct block *b; + b = gen_portrange(port1, port2, real_proto, dir); + gen_or(gen_portrange6(port1, port2, real_proto, dir), b); + return b; + } +#endif /* INET6 */ + case Q_GATEWAY: #ifndef INET6 eaddr = pcap_ether_hostton(name); @@ -4317,6 +4604,29 @@ gen_ncode(s, v, q) } #endif /* INET6 */ + case Q_PORTRANGE: + if (proto == Q_UDP) + proto = IPPROTO_UDP; + else if (proto == Q_TCP) + proto = IPPROTO_TCP; + else if (proto == Q_SCTP) + proto = IPPROTO_SCTP; + else if (proto == Q_DEFAULT) + proto = PROTO_UNDEF; + else + bpf_error("illegal qualifier of 'portrange'"); + +#ifndef INET6 + return gen_portrange((int)v, (int)v, proto, dir); +#else + { + struct block *b; + b = gen_portrange((int)v, (int)v, proto, dir); + gen_or(gen_portrange6((int)v, (int)v, proto, dir), b); + return b; + } +#endif /* INET6 */ + case Q_GATEWAY: bpf_error("'gateway' requires a name"); /* NOTREACHED */ diff --git a/gencode.h b/gencode.h index 6b97e89..eb9ac3d 100644 --- a/gencode.h +++ b/gencode.h @@ -18,7 +18,7 @@ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * @(#) $Header: /tcpdump/master/libpcap/gencode.h,v 1.60 2004-06-16 08:20:30 hannes Exp $ (LBL) + * @(#) $Header: /tcpdump/master/libpcap/gencode.h,v 1.60.2.1 2005-04-19 04:26:07 guy Exp $ (LBL) */ /* @@ -63,6 +63,7 @@ #define Q_GATEWAY 4 #define Q_PROTO 5 #define Q_PROTOCHAIN 6 +#define Q_PORTRANGE 7 /* Protocol qualifiers. */ diff --git a/grammar.y b/grammar.y index 3325b76..d3343fc 100644 --- a/grammar.y +++ b/grammar.y @@ -22,7 +22,7 @@ */ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/grammar.y,v 1.86 2004-12-18 08:49:23 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/grammar.y,v 1.86.2.1 2005-04-19 04:26:08 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -114,7 +114,7 @@ pcap_parse() %type atmfieldvalue atmvalue atmlistvalue %token DST SRC HOST GATEWAY -%token NET NETMASK PORT LESS GREATER PROTO PROTOCHAIN CBYTE +%token NET NETMASK PORT PORTRANGE LESS GREATER PROTO PROTOCHAIN CBYTE %token ARP RARP IP SCTP TCP UDP ICMP IGMP IGRP PIM VRRP %token ATALK AARP DECNET LAT SCA MOPRC MOPDL %token TK_BROADCAST TK_MULTICAST @@ -271,6 +271,7 @@ dqual: SRC { $$ = Q_SRC; } aqual: HOST { $$ = Q_HOST; } | NET { $$ = Q_NET; } | PORT { $$ = Q_PORT; } + | PORTRANGE { $$ = Q_PORTRANGE; } ; /* non-directional address type qualifiers */ ndaqual: GATEWAY { $$ = Q_GATEWAY; } diff --git a/nametoaddr.c b/nametoaddr.c index 8f033b4..dae6dfc 100644 --- a/nametoaddr.c +++ b/nametoaddr.c @@ -24,7 +24,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/nametoaddr.c,v 1.77 2005-03-27 22:26:25 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/nametoaddr.c,v 1.77.2.1 2005-04-19 04:26:08 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -216,6 +216,51 @@ pcap_nametoport(const char *name, int *port, int *proto) return 0; } +/* + * Convert a string in the form PPP-PPP, where correspond to ports, to + * a starting and ending port in a port range. + * Return 0 on failure. + */ +int +pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto) +{ + u_int p1, p2; + char *off, *cpy; + int save_proto; + + if (sscanf(name, "%d-%d", &p1, &p2) != 2) { + if ((cpy = strdup(name)) == NULL) + return 0; + + if ((off = strchr(cpy, '-')) == NULL) { + free(cpy); + return 0; + } + + *off = '\0'; + + if (pcap_nametoport(cpy, port1, proto) == 0) { + free(cpy); + return 0; + } + save_proto = *proto; + + if (pcap_nametoport(off + 1, port2, proto) == 0) { + free(cpy); + return 0; + } + + if (*proto != save_proto) + *proto = PROTO_UNDEF; + } else { + *port1 = p1; + *port2 = p2; + *proto = PROTO_UNDEF; + } + + return 1; +} + int pcap_nametoproto(const char *str) { diff --git a/pcap-namedb.h b/pcap-namedb.h index ba02ee0..eb58ec7 100644 --- a/pcap-namedb.h +++ b/pcap-namedb.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#) $Header: /tcpdump/master/libpcap/pcap-namedb.h,v 1.10 2005-03-17 07:02:32 guy Exp $ (LBL) + * @(#) $Header: /tcpdump/master/libpcap/pcap-namedb.h,v 1.10.2.1 2005-04-19 04:26:08 guy Exp $ (LBL) */ #ifndef lib_pcap_namedb_h @@ -65,6 +65,7 @@ struct addrinfo *pcap_nametoaddrinfo(const char *); bpf_u_int32 pcap_nametonetaddr(const char *); int pcap_nametoport(const char *, int *, int *); +int pcap_nametoportrange(const char *, int *, int *, int *); int pcap_nametoproto(const char *); int pcap_nametoeproto(const char *); int pcap_nametollc(const char *); diff --git a/scanner.l b/scanner.l index f03d04e..89aed6e 100644 --- a/scanner.l +++ b/scanner.l @@ -22,7 +22,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/scanner.l,v 1.99 2004-06-16 08:20:28 hannes Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/scanner.l,v 1.99.2.1 2005-04-19 04:26:08 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -234,6 +234,7 @@ host return HOST; net return NET; mask return NETMASK; port return PORT; +portrange return PORTRANGE; proto return PROTO; protochain { #ifdef NO_PROTOCHAIN