]> git.ipfire.org Git - thirdparty/bird.git/blobdiff - proto/bgp/attrs.c
BGP: Add option to enforce first AS in AS_PATH
[thirdparty/bird.git] / proto / bgp / attrs.c
index b892136387f4752425dc7811107f06c74e3ad0e5..39297dd7bf2e877da80582956893294b2c5d9a57 100644 (file)
@@ -404,6 +404,15 @@ bgp_format_origin(eattr *a, byte *buf, uint size UNUSED)
 }
 
 
+static inline int
+bgp_as_path_first_as_equal(const byte *data, uint len, u32 asn)
+{
+  return (len >= 6) &&
+    ((data[0] == AS_PATH_SEQUENCE) || (data[0] == AS_PATH_CONFED_SEQUENCE)) &&
+    (data[1] > 0) &&
+    (get_u32(data+2) == asn);
+}
+
 static int
 bgp_encode_as_path(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
 {
@@ -426,17 +435,13 @@ bgp_decode_as_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte
 {
   struct bgp_proto *p = s->proto;
   int as_length = s->as4_session ? 4 : 2;
+  int as_sets = p->cf->allow_as_sets;
   int as_confed = p->cf->confederation && p->is_interior;
   char err[128];
 
-  if (!as_path_valid(data, len, as_length, as_confed, err, sizeof(err)))
+  if (!as_path_valid(data, len, as_length, as_sets, as_confed, err, sizeof(err)))
     WITHDRAW("Malformed AS_PATH attribute - %s", err);
 
-  /* In some circumstances check for initial AS_CONFED_SEQUENCE; RFC 5065 5.0 */
-  if (p->is_interior && !p->is_internal &&
-      ((len < 2) || (data[0] != AS_PATH_CONFED_SEQUENCE)))
-    WITHDRAW("Malformed AS_PATH attribute - %s", "missing initial AS_CONFED_SEQUENCE");
-
   if (!s->as4_session)
   {
     /* Prepare 32-bit AS_PATH (from 16-bit one) in a temporary buffer */
@@ -445,6 +450,16 @@ bgp_decode_as_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte
     len = as_path_16to32(data, src, len);
   }
 
+  /* In some circumstances check for initial AS_CONFED_SEQUENCE; RFC 5065 5.0 */
+  if (p->is_interior && !p->is_internal &&
+      ((len < 2) || (data[0] != AS_PATH_CONFED_SEQUENCE)))
+    WITHDRAW("Malformed AS_PATH attribute - %s", "missing initial AS_CONFED_SEQUENCE");
+
+  /* Reject routes with first AS in AS_PATH not matching neighbor AS; RFC 4271 6.3 */
+  if (!p->is_internal && p->cf->enforce_first_as &&
+      !bgp_as_path_first_as_equal(data, len, p->remote_as))
+    WITHDRAW("Malformed AS_PATH attribute - %s", "First AS differs from neigbor AS");
+
   bgp_set_attr_data(to, s->pool, BA_AS_PATH, flags, data, len);
 }
 
@@ -717,13 +732,23 @@ bgp_decode_mp_unreach_nlri(struct bgp_parse_state *s, uint code UNUSED, uint fla
 static void
 bgp_export_ext_community(struct bgp_export_state *s, eattr *a)
 {
-  struct adata *ad = ec_set_del_nontrans(s->pool, a->u.ptr);
+  if (!s->proto->is_interior)
+  {
+    struct adata *ad = ec_set_del_nontrans(s->pool, a->u.ptr);
 
-  if (ad->length == 0)
-    UNSET(a);
+    if (ad->length == 0)
+      UNSET(a);
+
+    ec_set_sort_x(ad);
+    a->u.ptr = ad;
+  }
+  else
+  {
+    if (a->u.ptr->length == 0)
+      UNSET(a);
 
-  ec_set_sort_x(ad);
-  a->u.ptr = ad;
+    a->u.ptr = ec_set_sort(s->pool, a->u.ptr);
+  }
 }
 
 static void
@@ -753,6 +778,9 @@ bgp_decode_as4_aggregator(struct bgp_parse_state *s, uint code UNUSED, uint flag
 static void
 bgp_decode_as4_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
 {
+  struct bgp_proto *p = s->proto;
+  int sets = p->cf->allow_as_sets;
+
   char err[128];
 
   if (s->as4_session)
@@ -761,7 +789,7 @@ bgp_decode_as4_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byt
   if (len < 6)
     DISCARD(BAD_LENGTH, "AS4_PATH", len);
 
-  if (!as_path_valid(data, len, 4, 1, err, sizeof(err)))
+  if (!as_path_valid(data, len, 4, sets, 1, err, sizeof(err)))
     DISCARD("Malformed AS4_PATH attribute - %s", err);
 
   struct adata *a = lp_alloc_adata(s->pool, len);