Alter the way extended communities are matched when part of the value
authorclaudio <claudio@openbsd.org>
Mon, 30 Jan 2023 16:51:34 +0000 (16:51 +0000)
committerclaudio <claudio@openbsd.org>
Mon, 30 Jan 2023 16:51:34 +0000 (16:51 +0000)
is auto-expanded or masked off.
Try to match against both 2- and 4-byte AS encoding and on insertion
check if expansion is actually possible and deny communities where both
community values are > USHRT_MAX.
OK tb@

usr.sbin/bgpd/parse.y
usr.sbin/bgpd/rde_community.c

index de3ee73..74ce8fd 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: parse.y,v 1.440 2023/01/24 14:13:11 claudio Exp $ */
+/*     $OpenBSD: parse.y,v 1.441 2023/01/30 16:51:34 claudio Exp $ */
 
 /*
  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -4083,11 +4083,11 @@ parseextvalue(int type, char *s, uint32_t *v, uint32_t *flag)
        } else if (strcmp(s, "neighbor-as") == 0) {
                *flag = COMMUNITY_NEIGHBOR_AS;
                *v = 0;
-               return EXT_COMMUNITY_TRANS_FOUR_AS;
+               return EXT_COMMUNITY_TRANS_TWO_AS;
        } else if (strcmp(s, "local-as") == 0) {
                *flag = COMMUNITY_LOCAL_AS;
                *v = 0;
-               return EXT_COMMUNITY_TRANS_FOUR_AS;
+               return EXT_COMMUNITY_TRANS_TWO_AS;
        } else if ((p = strchr(s, '.')) == NULL) {
                /* AS_PLAIN number (4 or 2 byte) */
                strtonum(s, 0, USHRT_MAX, &errstr);
index 8c47048..746076d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde_community.c,v 1.10 2022/12/28 21:30:16 jmc Exp $ */
+/*     $OpenBSD: rde_community.c,v 1.11 2023/01/30 16:51:34 claudio Exp $ */
 
 /*
  * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
@@ -112,6 +112,7 @@ fc2c(struct community *fc, struct rde_peer *peer, struct community *c,
                c->data3 = type << 8 | subtype;
                switch (type & EXT_COMMUNITY_VALUE) {
                case EXT_COMMUNITY_TRANS_TWO_AS:
+               case EXT_COMMUNITY_TRANS_FOUR_AS:
                        if ((fc->flags >> 8 & 0xff) == COMMUNITY_ANY)
                                break;
 
@@ -121,11 +122,9 @@ fc2c(struct community *fc, struct rde_peer *peer, struct community *c,
                        if (apply_flag(fc->data2, fc->flags >> 16, peer,
                            &c->data2, m ? &m->data2 : NULL))
                                return -1;
-                       /* check that values fit */
-                       if (c->data1 > USHRT_MAX)
-                               return -1;
+                       if (m)
+                               m->data3 &= ~(EXT_COMMUNITY_TRANS_FOUR_AS << 8);
                        return 0;
-               case EXT_COMMUNITY_TRANS_FOUR_AS:
                case EXT_COMMUNITY_TRANS_IPV4:
                        if ((fc->flags >> 8 & 0xff) == COMMUNITY_ANY)
                                break;
@@ -268,7 +267,6 @@ struct rde_peer *peer)
                    sizeof(*fc), fast_match) != NULL);
        } else {
                /* slow path */
-
                if (fc2c(fc, peer, &test, &mask) == -1)
                        return 0;
 
@@ -335,6 +333,24 @@ struct rde_peer *peer)
        } else {
                if (fc2c(fc, peer, &set, NULL) == -1)
                        return 0;
+               if ((uint8_t)set.flags == COMMUNITY_TYPE_EXT) {
+                       int type = (int)set.data3 >> 8;
+                       switch (type & EXT_COMMUNITY_VALUE) {
+                       case EXT_COMMUNITY_TRANS_TWO_AS:
+                       case EXT_COMMUNITY_TRANS_FOUR_AS:
+                               /* check that values fit */
+                               if (set.data1 > USHRT_MAX &&
+                                   set.data2 > USHRT_MAX)
+                                       return 0;
+                               if (set.data1 > USHRT_MAX)
+                                       set.data3 = (set.data3 & 0xff) |
+                                           EXT_COMMUNITY_TRANS_FOUR_AS << 8;
+                               else
+                                       set.data3 = (set.data3 & 0xff) |
+                                           EXT_COMMUNITY_TRANS_TWO_AS << 8;
+                               break;
+                       }
+               }
                insert_community(comm, &set);
        }
        return 1;