Hi,

this allows to have

  allow from any AS 64512 - 65534 ...
  allow from any AS > 100

etc in bgpd.conf.

Ignore the example file for now, i will commit that seperatly anyway.

One obvious improvment would be to be able to use this in bgpctl to restrict
the output of "show rib" a bit more. However, that is for another commit i
think, the bgpctl bit in this diff is just to make it compile and work.

ok?

/Benno

diff --git etc/examples/bgpd.conf etc/examples/bgpd.conf
index 8ffa8a8..02a31f9 100644
--- etc/examples/bgpd.conf
+++ etc/examples/bgpd.conf
@@ -119,3 +119,14 @@ deny from any prefix fc00::/7 prefixlen >= 7               
# unique local unicast
 deny from any prefix fe80::/10 prefixlen >= 10         # link local unicast
 deny from any prefix fec0::/10 prefixlen >= 10         # old site local unicast
 deny from any prefix ff00::/8 prefixlen >= 8           # multicast
+
+# filter bogon AS numbers
+# http://www.iana.org/assignments/as-numbers/as-numbers.xhtml
+deny from any AS 23456                         # AS_TRANS
+deny from any AS 64496 - 64511                 # Reserved for use in docs and 
code RFC5398
+deny from any AS 64512 - 65534                 # Reserved for Private Use 
RFC6996
+deny from any AS 65535                         # Reserved RFC7300
+deny from any AS 65536 - 65551                 # Reserved for use in docs and 
code RFC5398 
+deny from any AS 65552 - 131071                        # Reserved
+deny from any AS 4200000000 - 4294967294       # Reserved for Private Use 
RFC6996
+deny from any AS 4294967295                    # Reserved RFC7300
diff --git usr.sbin/bgpctl/bgpctl.c usr.sbin/bgpctl/bgpctl.c
index 62569bf..afdcf2c 100644
--- usr.sbin/bgpctl/bgpctl.c
+++ usr.sbin/bgpctl/bgpctl.c
@@ -1788,7 +1788,7 @@ show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, 
void *arg)
                /* filter by AS */
                if (req->as.type != AS_NONE &&
                   !aspath_match(mre->aspath, mre->aspath_len,
-                  req->as.type, req->as.as))
+                  &req->as, req->as.as))
                        continue;
 
                if (req->flags & F_CTL_DETAIL) {
@@ -1853,7 +1853,7 @@ network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, 
void *arg)
                /* filter by AS */
                if (req->as.type != AS_NONE &&
                   !aspath_match(mre->aspath, mre->aspath_len,
-                  req->as.type, req->as.as))
+                  &req->as, req->as.as))
                        continue;
 
                bzero(&net, sizeof(net));
diff --git usr.sbin/bgpd/bgpd.conf.5 usr.sbin/bgpd/bgpd.conf.5
index 84a01ed..0017124 100644
--- usr.sbin/bgpd/bgpd.conf.5
+++ usr.sbin/bgpd/bgpd.conf.5
@@ -1027,7 +1027,10 @@ If a parameter is specified, the rule only applies to 
packets with
 matching attributes.
 .Pp
 .Bl -tag -width Ds -compact
-.It Ar as-type as-number
+.It Xo
+.Ar as-type Op Ar operator
+.Ar as-number
+.Xc
 This rule applies only to
 .Em UPDATES
 where the
@@ -1038,13 +1041,7 @@ The
 is matched against a part of the
 .Em AS path
 specified by the
-.Ar as-type .
-.Ar as-number
-may be set to
-.Ic neighbor-as ,
-which is expanded to the current neighbor remote AS number.
-.Ar as-type
-is one of the following operators:
+.Ar as-type :
 .Pp
 .Bl -tag -width transmit-as -compact
 .It Ic AS
@@ -1057,6 +1054,33 @@ is one of the following operators:
 (all but the rightmost AS number)
 .El
 .Pp
+.Ar as-number
+is an AS number as explained above under
+.Sx GLOBAL CONFIGURATION .
+It may be set to
+.Ic neighbor-as ,
+which is expanded to the current neighbor remote AS number.
+.Pp
+The
+.Ar operator
+can be unspecified (this case is identical to the equality operator), or one 
of the numerical operators
+.Bd -literal -offset indent
+=      (equal)
+!=     (unequal)
+<      (less than)
+<=     (less than or equal)
+>      (greater than)
+>=     (greater than or equal)
+-      (range including boundaries)
+><     (except range)
+.Ed
+.Pp
+>< and -
+are binary operators (they take two arguments), with these,
+.Ar as-number
+cannot be set to
+.Ic neighbor-as .
+.Pp
 Multiple
 .Ar as-number
 entries for a given type or
diff --git usr.sbin/bgpd/bgpd.h usr.sbin/bgpd/bgpd.h
index 86dfee9..9c635a8 100644
--- usr.sbin/bgpd/bgpd.h
+++ usr.sbin/bgpd/bgpd.h
@@ -625,6 +625,9 @@ struct filter_as {
        u_int32_t       as;
        u_int16_t       flags;
        enum as_spec    type;
+       u_int8_t        op;
+       u_int32_t       as_min;
+       u_int32_t       as_max;
 };
 
 struct filter_aslen {
@@ -660,7 +663,6 @@ struct filter_extcommunity {
        }               data;
 };
 
-
 struct ctl_show_rib_request {
        char                    rib[PEER_DESCR_LEN];
        struct ctl_neighbor     neighbor;
@@ -1051,7 +1053,8 @@ const char        *log_ext_subtype(u_int8_t);
 int             aspath_snprint(char *, size_t, void *, u_int16_t);
 int             aspath_asprint(char **, void *, u_int16_t);
 size_t          aspath_strlen(void *, u_int16_t);
-int             aspath_match(void *, u_int16_t, enum as_spec, u_int32_t);
+int             aspath_match(void *, u_int16_t, struct filter_as *, u_int32_t);
+int             as_compare(u_int8_t, u_int32_t, u_int32_t, u_int32_t, 
u_int32_t);
 u_int32_t       aspath_extract(const void *, int);
 int             prefix_compare(const struct bgpd_addr *,
                    const struct bgpd_addr *, int);
diff --git usr.sbin/bgpd/parse.y usr.sbin/bgpd/parse.y
index 1c1355f..59cac5d 100644
--- usr.sbin/bgpd/parse.y
+++ usr.sbin/bgpd/parse.y
@@ -196,7 +196,7 @@ typedef struct {
 %token NE LE GE XRANGE LONGER
 %token <v.string>              STRING
 %token <v.number>              NUMBER
-%type  <v.number>              asnumber as4number optnumber
+%type  <v.number>              asnumber as4number as4number_any optnumber
 %type  <v.number>              espah family restart origincode nettype
 %type  <v.number>              yesno inout restricted
 %type  <v.string>              string filter_rib
@@ -280,6 +280,38 @@ as4number  : STRING                        {
                }
                ;
 
+as4number_any  : STRING                        {
+                       const char      *errstr;
+                       char            *dot;
+                       u_int32_t        uvalh = 0, uval;
+
+                       if ((dot = strchr($1,'.')) != NULL) {
+                               *dot++ = '\0';
+                               uvalh = strtonum($1, 0, USHRT_MAX, &errstr);
+                               if (errstr) {
+                                       yyerror("number %s is %s", $1, errstr);
+                                       free($1);
+                                       YYERROR;
+                               }
+                               uval = strtonum(dot, 0, USHRT_MAX, &errstr);
+                               if (errstr) {
+                                       yyerror("number %s is %s", dot, errstr);
+                                       free($1);
+                                       YYERROR;
+                               }
+                               free($1);
+                       } else {
+                               yyerror("AS %s is bad", $1);
+                               free($1);
+                               YYERROR;
+                       }
+                       $$ = uval | (uvalh << 16);
+               }
+               | asnumber {
+                       $$ = $1;
+               }
+               ;
+
 string         : string STRING                 {
                        if (asprintf(&$$, "%s %s", $1, $2) == -1)
                                fatal("string: asprintf");
@@ -1616,11 +1648,12 @@ filter_as_l     : filter_as
                }
                ;
 
-filter_as      : as4number             {
+filter_as      : as4number_any         {
                        if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
                            NULL)
                                fatal(NULL);
                        $$->a.as = $1;
+                       $$->a.op = OP_EQ;
                }
                | NEIGHBORAS            {
                        if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
@@ -1628,6 +1661,25 @@ filter_as        : as4number             {
                                fatal(NULL);
                        $$->a.flags = AS_FLAG_NEIGHBORAS;
                }
+               | unaryop as4number_any {
+                       if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
+                           NULL)
+                               fatal(NULL);
+                       $$->a.op = $1;
+                       $$->a.as = $2;
+               }
+               | as4number_any binaryop as4number_any {
+                       if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
+                           NULL)
+                               fatal(NULL);
+                       if ($1 >= $3) {
+                               yyerror("start AS is bigger than end");
+                               YYERROR;
+                       }
+                       $$->a.op = $2;
+                       $$->a.as_min = $1;
+                       $$->a.as_max = $3;
+               }
                ;
 
 filter_match_h : /* empty */                   {
diff --git usr.sbin/bgpd/rde.c usr.sbin/bgpd/rde.c
index 3c6e0d1..5d849b4 100644
--- usr.sbin/bgpd/rde.c
+++ usr.sbin/bgpd/rde.c
@@ -2252,7 +2252,7 @@ rde_dump_filter(struct prefix *p, struct 
ctl_show_rib_request *req)
                        return;
                if (req->type == IMSG_CTL_SHOW_RIB_AS &&
                    !aspath_match(p->aspath->aspath->data,
-                   p->aspath->aspath->len, req->as.type, req->as.as))
+                   p->aspath->aspath->len, &req->as, req->as.as))
                        return;
                if (req->type == IMSG_CTL_SHOW_RIB_COMMUNITY &&
                    !community_match(p->aspath, req->community.as,
diff --git usr.sbin/bgpd/rde_filter.c usr.sbin/bgpd/rde_filter.c
index 047f0db..a33369d 100644
--- usr.sbin/bgpd/rde_filter.c
+++ usr.sbin/bgpd/rde_filter.c
@@ -230,7 +230,7 @@ rde_filter_match(struct filter_rule *f, struct rde_aspath 
*asp,
                else
                        pas = f->match.as.as;
                if (aspath_match(asp->aspath->data, asp->aspath->len,
-                   f->match.as.type, pas) == 0)
+                   &f->match.as, pas) == 0)
                        return (0);
        }
 
diff --git usr.sbin/bgpd/util.c usr.sbin/bgpd/util.c
index 61af759..ec88f12 100644
--- usr.sbin/bgpd/util.c
+++ usr.sbin/bgpd/util.c
@@ -307,20 +307,23 @@ aspath_strlen(void *data, u_int16_t len)
 
 /* we need to be able to search more than one as */
 int
-aspath_match(void *data, u_int16_t len, enum as_spec type, u_int32_t as)
+aspath_match(void *data, u_int16_t len, struct filter_as *as, u_int32_t match)
 {
        u_int8_t        *seg;
        int              final;
        u_int16_t        seg_size;
        u_int8_t         i, seg_len;
+       u_int32_t        tmp;
 
-       if (type == AS_EMPTY) {
+       if (as->type == AS_EMPTY) {
                if (len == 0)
                        return (1);
                else
                        return (0);
        }
 
+//     log_debug("%s: op %d, type %d, match %u", __func__, as->op, as->type, 
match);
+
        seg = data;
        for (; len > 0; len -= seg_size, seg += seg_size) {
                seg_len = seg[1];
@@ -329,41 +332,67 @@ aspath_match(void *data, u_int16_t len, enum as_spec 
type, u_int32_t as)
                final = (len == seg_size);
 
                /* just check the first (leftmost) AS */
-               if (type == AS_PEER) {
-                       if (as == aspath_extract(seg, 0))
+               if (as->type == AS_PEER) {
+                       tmp = aspath_extract(seg, 0);
+                       if (as_compare(as->op, tmp, match, as->as_min,
+                           as->as_max))
                                return (1);
                        else
                                return (0);
                }
                /* just check the final (rightmost) AS */
-               if (type == AS_SOURCE) {
+               if (as->type == AS_SOURCE) {
                        /* not yet in the final segment */
                        if (!final)
                                continue;
-
-                       if (as == aspath_extract(seg, seg_len - 1))
+                       tmp = aspath_extract(seg, seg_len - 1);
+                       if (as_compare(as->op, tmp, match, as->as_min,
+                           as->as_max))
                                return (1);
                        else
                                return (0);
                }
-
                /* AS_TRANSIT or AS_ALL */
                for (i = 0; i < seg_len; i++) {
-                       if (as == aspath_extract(seg, i)) {
-                               /*
-                                * the source (rightmost) AS is excluded from
-                                * AS_TRANSIT matches.
-                                */
-                               if (final && i == seg_len - 1 &&
-                                   type == AS_TRANSIT)
-                                       return (0);
+                       tmp = aspath_extract(seg, i);
+                       /*
+                        * the source (rightmost) AS is excluded from
+                        * AS_TRANSIT matches.
+                        */
+                       if (final && i == seg_len - 1 &&
+                           as->type == AS_TRANSIT)
+                               return (0);
+                       if (as_compare(as->op, tmp, match, as->as_min,
+                           as->as_max))
                                return (1);
-                       }
                }
        }
        return (0);
 }
 
+int
+as_compare(u_int8_t op, u_int32_t tmp, u_int32_t match, u_int32_t as_min,
+    u_int32_t as_max)
+{
+       if ((op == OP_NONE || op == OP_EQ) && tmp == match)
+               return (1);
+       else if (op == OP_NE && tmp != match)
+               return (1);
+       else if (op == OP_LE && tmp <= match)
+               return (1);
+       else if (op == OP_LT && tmp <  match)
+               return (1);
+       else if (op == OP_GE && tmp >= match)
+               return (1);
+       else if (op == OP_GT && tmp >  match)
+               return (1);
+       else if (op == OP_RANGE && tmp >= as_min && tmp <= as_max)
+               return (1);
+       else if (op == OP_XRANGE && tmp > as_min && tmp < as_max)
+               return (1);
+       return (0);
+}
+
 /*
  * Extract the asnum out of the as segment at the specified position.
  * Direct access is not possible because of non-aligned reads.

Reply via email to