]> The Tcpdump Group git mirrors - libpcap/commitdiff
From Patrick Marie <[email protected]>: add support for port ranges
authorguy <guy>
Tue, 19 Apr 2005 04:26:06 +0000 (04:26 +0000)
committerguy <guy>
Tue, 19 Apr 2005 04:26:06 +0000 (04:26 +0000)
in tests - "portrange X-Y" matches all ports in the range [X,Y].

Support added for port ranges with IPv6.

Fix some comments.

CREDITS
gencode.c
gencode.h
grammar.y
nametoaddr.c
pcap-namedb.h
scanner.l

diff --git a/CREDITS b/CREDITS
index 1cc579b814d6bf6cf0edf85daf097b359722d8cc..7c0e9cc08f41a8a186f1f4435095a5c52d08dfea 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -68,6 +68,7 @@ Additional people who have contributed patches:
        Octavian Cerna                  <[email protected]>
        Olaf Kirch                      <[email protected]>
        Onno van der Linden             <[email protected]>
+       Patrick Marie                   <[email protected]>
        Paul Mundt                      <[email protected]>
        Pavel Kankovsky                 <[email protected]>
        Peter Fales                     <[email protected]>
index d4946edfac27743b09a6687f87a32c92e3b73e10..53ecbcc9c926dffce784d01ad68e636070344b2d 100644 (file)
--- 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 */
index 6b97e8921260278065ee873cb5695295c21cb914..eb9ac3da480768bf4920c815b99551ffcfcb701b 100644 (file)
--- 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. */
 
index 3325b764ad338709244009f374cb618374db7f86..d3343fc5ee536f91916719bd21a8f02dd2b666c3 100644 (file)
--- 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  <blk>   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; }
index 8f033b4449f0fbd3e381e319cd6afdde0eeba721..dae6dfcd6203673c37179b3d5bfd5d0d79344b46 100644 (file)
@@ -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)
 {
index ba02ee0fb126f46b06325a7b42fbe8a100b13570..eb58ec7bb3993d8b308c2edebecd4b6b63bad4e4 100644 (file)
@@ -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 *);
index f03d04e78a797f19436c13c17f914f21cbe91766..89aed6e2a61c5c676cb492e97890dffe104b619a 100644 (file)
--- 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