]> git.puffer.fish Git - mirror/frr.git/commitdiff
Correct a few fuzz failures in BGP
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 01:03:43 +0000 (18:03 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 01:03:43 +0000 (18:03 -0700)
bgpd/bgp_attr.c
bgpd/bgp_packet.c
bgpd/bgp_packet.h

index 8e1a37ab63addfd3e8349067f6c26c2a57a422b8..8ff8a5cff5bf2c4220043244d281144966e55fca 100644 (file)
@@ -1148,14 +1148,9 @@ bgp_attr_nexthop (struct bgp_attr_parser_args *args)
                                  args->total);
     }
 
-  /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
-     attribute must result in a NOTIFICATION message (this is implemented below).
-     At the same time, semantically incorrect NEXT_HOP is more likely to be just
-     logged locally (this is implemented somewhere else). The UPDATE message
-     gets ignored in any of these cases. */
   nexthop_n = stream_get_ipv4 (peer->ibuf);
   nexthop_h = ntohl (nexthop_n);
-  if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
+  if (!bgp_valid_host_address(nexthop_h))
     {
       char buf[INET_ADDRSTRLEN];
       inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN);
@@ -1864,9 +1859,10 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
       if (attr_endp > endp)
        {
          zlog_warn ("%s: BGP type %d length %d is too large, attribute total length is %d.  attr_endp is %p.  endp is %p", peer->host, type, length, size, attr_endp, endp);
-         bgp_notify_send (peer, 
-                          BGP_NOTIFY_UPDATE_ERR, 
-                          BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+          bgp_notify_send_with_data (peer,
+                                     BGP_NOTIFY_UPDATE_ERR,
+                                     BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                     startp, attr_endp - startp);
          return BGP_ATTR_PARSE_ERROR;
        }
        
index 16284bd5bfe195e3d04c883088bc9d915989dd1f..1d7d2d5f9bb9902791629d14edff2f33793db3e6 100644 (file)
@@ -1343,6 +1343,34 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id)
   return 0;
 }
 
+/*
+ * per draft-ietf-idr-error-handling-13
+ *
+ * An IP host address SHOULD be considered invalid if it appears in the
+ * "IANA IPv4 Special-Purpose Address Registry" [IANA-IPV4] and either
+ * the "destination" or the "forwardable" boolean in that registry is
+ * given as "false".
+ */
+int
+bgp_valid_host_address (unsigned long addr)
+{
+  if (IPV4_NET0(addr) ||      // 0.0.0.0/8
+      IPV4_NET127(addr) ||    // 127.0.0.0/8
+      IPV4_LINKLOCAL(addr) || // 169.254.0.0/16
+      addr == 0xC00000AA ||   // 192.0.0.170/32
+      addr == 0xC00000AB ||   // 192.0.0.171/32
+      (addr & 0xffffff00) == 0xC0000200 ||  // 192.0.2.0/24
+      (addr & 0xffffff00) == 0xC6336400 ||  // 198.51.100.0/24
+      (addr & 0xffffff00) == 0xCB007100 ||  // 203.0.113.0/24
+      IPV4_CLASS_DE(addr))
+    {
+      return 0;
+    }
+
+  return 1;
+}
+
+
 static int
 bgp_open_receive (struct peer *peer, bgp_size_t size)
 {
@@ -1358,11 +1386,15 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
   int mp_capability;
   u_int8_t notify_data_remote_as[2];
   u_int8_t notify_data_remote_id[4];
+  u_int16_t *holdtime_ptr;
+  unsigned long local_addr;
+  unsigned long remote_addr;
 
   /* Parse open packet. */
   version = stream_getc (peer->ibuf);
   memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2);
   remote_as  = stream_getw (peer->ibuf);
+  holdtime_ptr = stream_pnt (peer->ibuf);
   holdtime = stream_getw (peer->ibuf);
   memcpy (notify_data_remote_id, stream_pnt (peer->ibuf), 4);
   remote_id.s_addr = stream_get_ipv4 (peer->ibuf);
@@ -1438,10 +1470,11 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
        }
     }
 
+  local_addr = ntohl (peer->local_id.s_addr);
+  remote_addr = ntohl (remote_id.s_addr);
+
   /* remote router-id check. */
-  if (remote_id.s_addr == 0
-      || IPV4_CLASS_DE (ntohl (remote_id.s_addr))
-      || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr))
+  if (local_addr == remote_addr || !bgp_valid_host_address(remote_addr))
     {
       if (bgp_debug_neighbor_events(peer))
        zlog_debug ("%s bad OPEN, wrong router identifier %s",
@@ -1493,9 +1526,10 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
 
   if (holdtime < 3 && holdtime != 0)
     {
-      bgp_notify_send (peer,
-                      BGP_NOTIFY_OPEN_ERR, 
-                      BGP_NOTIFY_OPEN_UNACEP_HOLDTIME);
+      bgp_notify_send_with_data (peer,
+                                BGP_NOTIFY_OPEN_ERR,
+                                BGP_NOTIFY_OPEN_UNACEP_HOLDTIME,
+                                 holdtime_ptr, 2);
       return -1;
     }
     
index 18b0024a7c06ebdc24552a02ccc248ce58df1027..bb3903cf7809062b736c30e3f34b66d398f18aea 100644 (file)
@@ -66,4 +66,5 @@ extern void bgp_check_update_delay (struct bgp *);
 extern int bgp_peer_wd_fifo_exists (struct peer *);
 extern int bgp_peer_adv_fifo_exists (struct peer *, int);
 extern void bgp_peer_schedule_updates(struct peer *peer);
+extern int bgp_valid_host_address (unsigned long addr);
 #endif /* _QUAGGA_BGP_PACKET_H */