with feedback from florian, sthen and claudio:

- i removed operators < <= > >=
- i kept != and = for symmetry.
- i thought about just using ! , but then it would be different from the
  prefix operators. Willing to change it if you want that.
- i left the forth argument to aspath_match(), as its easier to undestand
  than other things i could think of
- i removed a debug comment
- the usecase for this is mostly whats shown in the example. I think i can
  also simplyfy some filters setting policy with != in my configs.
- as phessler said, the example filters any AS that should not be seen in
  the wild at the moment. You want those filtered because its bad practice
  not to. Also, if you use private AS inside your network, the example
  config will remind you to make sure not to leak them. I'm reasonably
  convinced that these will not change in the near future.

ok?

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..126a037 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,29 @@ 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)
+-      (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..0144b01 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
@@ -211,7 +211,7 @@ typedef struct {
 %type  <v.filter_set>          filter_set_opt
 %type  <v.filter_set_head>     filter_set filter_set_l
 %type  <v.filter_prefix>       filter_prefix filter_prefix_l filter_prefix_h
-%type  <v.u8>                  unaryop binaryop filter_as_type
+%type  <v.u8>                  unaryop equalityop binaryop filter_as_type
 %type  <v.encspec>             encspec
 %%
 
@@ -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;
                }
+               | equalityop 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 */                   {
@@ -2105,6 +2157,10 @@ unaryop          : '='           { $$ = OP_EQ; }
                | '>'           { $$ = OP_GT; }
                ;
 
+equalityop     : '='           { $$ = OP_EQ; }
+               | NE            { $$ = OP_NE; }
+               ;
+
 binaryop       : '-'           { $$ = OP_RANGE; }
                | XRANGE        { $$ = OP_XRANGE; }
                ;
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..9667627 100644
--- usr.sbin/bgpd/util.c
+++ usr.sbin/bgpd/util.c
@@ -307,14 +307,15 @@ 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
@@ -329,41 +330,59 @@ 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_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