]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Fixes a nasty bug in OSPF.
authorOndrej Zajicek <santiago@crfreenet.org>
Mon, 28 Mar 2011 23:41:46 +0000 (01:41 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Mon, 28 Mar 2011 23:41:46 +0000 (01:41 +0200)
Sending malformed network prefixes in LSAs causes OSPF to crash
just after the LSA is propagated to the other routers.

nest/rt-table.c
proto/ospf/ospf.h
proto/ospf/packet.c
proto/ospf/rt.c

index 73b05d08ef5dec2ea89c1f4954c136ede63a9153..3013b0f723fde20f63baa81d4c6842b21e22a788 100644 (file)
@@ -374,7 +374,7 @@ rte_validate(rte *e)
 
   if ((n->n.pxlen > BITS_PER_IP_ADDRESS) || !ip_is_prefix(n->n.prefix,n->n.pxlen))
     {
-      log(L_BUG "Ignoring bogus prefix %I/%d received via %s",
+      log(L_WARN "Ignoring bogus prefix %I/%d received via %s",
          n->n.prefix, n->n.pxlen, e->sender->name);
       return 0;
     }
index 74a8e316c91e62f62ac5b3807861a9e972db47bd..664bc48fc3964be68027ce14b7bc33a181b42a61 100644 (file)
@@ -587,6 +587,10 @@ lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest)
   if (pxl > 96)
     _I3(*addr) = *buf++;
 
+  /* Clean up remaining bits */
+  if (pxl < 128)
+    addr->addr[pxl / 32] &= u32_mkmask(pxl % 32);
+
   return buf;
 }
 
index ae9f862a83144776b027c7b6164c1852f8fe3809..3cda384507767662ca469b50f58ab5abf4317bd4 100644 (file)
@@ -269,9 +269,10 @@ ospf_rx_hook(sock *sk, int size)
   struct proto_ospf *po = ifa->oa->po;
   // struct proto *p = &po->proto;
 
-  int src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen);
-  int dst_local = ipa_equal(sk->laddr, ifa->addr->ip);
-  int dst_mcast = ipa_equal(sk->laddr, AllSPFRouters) || ipa_equal(sk->laddr, AllDRouters);
+  int src_local, dst_local UNUSED, dst_mcast; 
+  src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen);
+  dst_local = ipa_equal(sk->laddr, ifa->addr->ip);
+  dst_mcast = ipa_equal(sk->laddr, AllSPFRouters) || ipa_equal(sk->laddr, AllDRouters);
 
 #ifdef OSPFv2
   /* First, we eliminate packets with strange address combinations.
index 2f9fe49368ac4bf829f1024a0243ebb99e474dbc..9e3f9d7aaf28033f00a3706b692167d6ddc7ef24 100644 (file)
@@ -245,6 +245,13 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_
     .nhs = en->nhs
   };
 
+  if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
+  {
+    log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
+       oa->po->proto.name, en->lsa.type, en->lsa.id, en->lsa.rt);
+    return;
+  }
+
   if (en == oa->rt)
   {
     /* 
@@ -336,7 +343,8 @@ ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct to
 {
   // struct proto *p = &oa->po->proto;
   struct proto_ospf *po = oa->po;
-  int i;
+  ip_addr prefix UNUSED;
+  int pxlen UNUSED, i;
 
   struct ospf_lsa_rt *rt = en->lsa_body;
   struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1);
@@ -357,9 +365,9 @@ ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct to
           * the same result by handing them here because add_network()
           * will keep the best (not the first) found route.
           */
-         add_network(oa, ipa_from_u32(rtl->id),
-                     ipa_mklen(ipa_from_u32(rtl->data)),
-                     act->dist + rtl->metric, act, i);
+         prefix = ipa_from_u32(rtl->id & rtl->data);
+         pxlen = ipa_mklen(ipa_from_u32(rtl->data));
+         add_network(oa, prefix, pxlen, act->dist + rtl->metric, act, i);
          break;
 #endif
 
@@ -398,6 +406,8 @@ ospf_rt_spfa(struct ospf_area *oa)
   struct ospf_lsa_rt *rt;
   struct ospf_lsa_net *ln;
   struct top_hash_entry *act, *tmp;
+  ip_addr prefix UNUSED;
+  int pxlen UNUSED;
   u32 i, *rts;
   node *n;
 
@@ -470,8 +480,9 @@ ospf_rt_spfa(struct ospf_area *oa)
       ln = act->lsa_body;
 
 #ifdef OSPFv2
-      add_network(oa, ipa_and(ipa_from_u32(act->lsa.id), ln->netmask),
-                 ipa_mklen(ln->netmask), act->dist, act, -1);
+      prefix = ipa_and(ipa_from_u32(act->lsa.id), ln->netmask);
+      pxlen = ipa_mklen(ln->netmask);
+      add_network(oa, prefix, pxlen, act->dist, act, -1);
 #endif
 
       rts = (u32 *) (ln + 1);
@@ -618,8 +629,8 @@ ospf_rt_sum(struct ospf_area *oa)
     {
 #ifdef OSPFv2
       struct ospf_lsa_sum *ls = en->lsa_body;
-      pxlen = ipa_mklen(ls->netmask);
       ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask);
+      pxlen = ipa_mklen(ls->netmask);
 #else /* OSPFv3 */
       u8 pxopts;
       u16 rest;
@@ -630,6 +641,13 @@ ospf_rt_sum(struct ospf_area *oa)
        continue;
 #endif
 
+      if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
+      {
+       log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
+           p->name, en->lsa.type, en->lsa.id, en->lsa.rt);
+       continue;
+      }
+
       metric = ls->metric & METRIC_MASK;
       options = 0;
       type = ORT_NET;
@@ -695,7 +713,7 @@ ospf_rt_sum(struct ospf_area *oa)
 static void
 ospf_rt_sum_tr(struct ospf_area *oa)
 {
-  // struct proto *p = &oa->po->proto;
+  struct proto *p = &oa->po->proto;
   struct proto_ospf *po = oa->po;
   struct ospf_area *bb = po->backbone;
   ip_addr abrip;
@@ -728,8 +746,8 @@ ospf_rt_sum_tr(struct ospf_area *oa)
       int pxlen;
 #ifdef OSPFv2
       struct ospf_lsa_sum *ls = en->lsa_body;
-      pxlen = ipa_mklen(ls->netmask);
       ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask);
+      pxlen = ipa_mklen(ls->netmask);
 #else /* OSPFv3 */
       u8 pxopts;
       u16 rest;
@@ -740,6 +758,13 @@ ospf_rt_sum_tr(struct ospf_area *oa)
        continue;
 #endif
 
+      if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
+      {
+       log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
+           p->name, en->lsa.type, en->lsa.id, en->lsa.rt);
+       continue;
+      }
+
       metric = ls->metric & METRIC_MASK;
       re = fib_find(&po->rtf, &ip, pxlen);
     }
@@ -1139,9 +1164,9 @@ ospf_ext_spf(struct proto_ospf *po)
       rt_tag = 0;
 #endif
 
-    if (pxlen < 0)
+    if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
     {
-      log(L_WARN "%s: Invalid mask in LSA (Type: %04x, Id: %R, Rt: %R)",
+      log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
          p->name, en->lsa.type, en->lsa.id, en->lsa.rt);
       continue;
     }
@@ -1703,8 +1728,6 @@ again1:
        e->net = ne;
        e->pref = p->preference;
 
-
-
        DBG("Mod rte type %d - %I/%d via %I on iface %s, met %d\n",
            a0.source, nf->fn.prefix, nf->fn.pxlen, a0.gw, a0.iface ? a0.iface->name : "(none)", nf->n.metric1);
        rte_update(p->table, ne, p, p, e);