diff -ur libpcap-orig/gencode.c libpcap-portrange/gencode.c --- libpcap-orig/gencode.c Wed Apr 23 22:17:41 2003 +++ libpcap-portrange/gencode.c Wed Apr 23 22:18:46 2003 @@ -185,11 +185,14 @@ #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); #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); @@ -3212,6 +3215,120 @@ } #endif /* INET6 */ +/* gen_portrange code */ +struct block * +gen_portrangeatom (off, v1, v2) + int off; + bpf_int32 v1, v2; /* suppose that v1 <= v2 */ +{ + struct slist *s1; + struct slist *s2; + + struct block *b1; + struct block *b1bis; + struct block *b2; + + 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, ip_proto, dir) + int port1, port2; + int ip_proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + tmp = gen_cmp(off_nl + 9, BPF_B, (bpf_int32)ip_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; + + /* ether 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; +} + static int lookup_proto(name, proto) register const char *name; @@ -3780,6 +3897,7 @@ #endif /*INET6*/ struct block *b, *tmp; int port, real_proto; + int port1, port2; switch (q.addr) { @@ -3987,6 +4105,46 @@ } #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 range port '%s'", name); + + if (proto == Q_UDP) { + if (real_proto == IPPROTO_TCP) + bpf_error("range port '%s' is tcp", name); + else if (real_proto == IPPROTO_SCTP) + bpf_error("range port '%s' is sctp", name); + else + real_proto = IPPROTO_UDP; + } + + if (proto == Q_TCP) { + if (real_proto == IPPROTO_UDP) + bpf_error("range port '%s' is udp", name); + else if (real_proto == IPPROTO_SCTP) + bpf_error("range port '%s' is sctp", name); + else + real_proto = IPPROTO_TCP; + } + + if (proto == Q_SCTP) { + if (real_proto == IPPROTO_UDP) + bpf_error("range port '%s' is udp", name); + else if (real_proto == IPPROTO_TCP) + bpf_error("range port '%s' is tcp", name); + else + real_proto = IPPROTO_SCTP; + } + + /* XXX INET6 TODO */ + if (port1 < port2) + return gen_portrange (port1, port2, real_proto, dir); + + return gen_portrange (port2, port1, real_proto, dir); + case Q_GATEWAY: #ifndef INET6 eaddr = pcap_ether_hostton(name); @@ -4132,6 +4290,20 @@ return b; } #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 'port'"); + + return (gen_portrange ((int)v, (int)v, proto, dir)); case Q_GATEWAY: bpf_error("'gateway' requires a name"); diff -ur libpcap-orig/gencode.h libpcap-portrange/gencode.h --- libpcap-orig/gencode.h Wed Apr 23 22:17:41 2003 +++ libpcap-portrange/gencode.h Wed Apr 23 22:18:52 2003 @@ -63,6 +63,7 @@ #define Q_GATEWAY 4 #define Q_PROTO 5 #define Q_PROTOCHAIN 6 +#define Q_PORTRANGE 7 /* Protocol qualifiers. */ diff -ur libpcap-orig/grammar.y libpcap-portrange/grammar.y --- libpcap-orig/grammar.y Wed Apr 23 22:17:41 2003 +++ libpcap-portrange/grammar.y Wed Apr 23 22:20:03 2003 @@ -115,7 +115,7 @@ %type atmfieldvalue atmvalue atmlistvalue %token DST SRC HOST GATEWAY -%token NET MASK PORT LESS GREATER PROTO PROTOCHAIN CBYTE +%token NET MASK 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 @@ -272,6 +272,7 @@ aqual: HOST { $$ = Q_HOST; } | NET { $$ = Q_NET; } | PORT { $$ = Q_PORT; } + | PORTRANGE { $$ = Q_PORTRANGE; } ; /* non-directional address type qualifiers */ ndaqual: GATEWAY { $$ = Q_GATEWAY; } diff -ur libpcap-orig/nametoaddr.c libpcap-portrange/nametoaddr.c --- libpcap-orig/nametoaddr.c Wed Apr 23 22:17:41 2003 +++ libpcap-portrange/nametoaddr.c Wed Apr 23 22:18:57 2003 @@ -209,6 +209,52 @@ } int +pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto) +{ + u_int p1, p2; + char *off, *cpy; + int save_proto; + + if (sscanf((char *)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) { struct protoent *p; diff -ur libpcap-orig/pcap-namedb.h libpcap-portrange/pcap-namedb.h --- libpcap-orig/pcap-namedb.h Wed Apr 23 22:17:41 2003 +++ libpcap-portrange/pcap-namedb.h Wed Apr 23 22:19:01 2003 @@ -65,6 +65,7 @@ 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 *); /* diff -ur libpcap-orig/scanner.l libpcap-portrange/scanner.l --- libpcap-orig/scanner.l Wed Apr 23 22:17:42 2003 +++ libpcap-portrange/scanner.l Wed Apr 23 22:19:04 2003 @@ -234,6 +234,7 @@ net return NET; mask return MASK; port return PORT; +portrange return PORTRANGE; proto return PROTO; protochain { #ifdef NO_PROTOCHAIN