]> git.proxmox.com Git - mirror_frr.git/blobdiff - babeld/message.c
Merge pull request #12890 from pguibert6WIND/attr_cleaning_misc
[mirror_frr.git] / babeld / message.c
index 0ddfda8d7b551de599f97e1bfd3daee161b7d706..b5c2a589848f97eab66d45686d6d50fc668f9062 100644 (file)
@@ -1,23 +1,6 @@
+// SPDX-License-Identifier: MIT
 /*
 Copyright (c) 2007, 2008 by Juliusz Chroboczek
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
 */
 
 #include <zebra.h>
@@ -127,9 +110,8 @@ network_prefix(int ae, int plen, unsigned int omitted,
     return ret;
 }
 
-static void
-parse_update_subtlv(const unsigned char *a, int alen,
-                    unsigned char *channels)
+static bool parse_update_subtlv(const unsigned char *a, int alen,
+                               unsigned char *channels)
 {
     int type, len, i = 0;
 
@@ -142,37 +124,51 @@ parse_update_subtlv(const unsigned char *a, int alen,
 
         if(i + 1 >= alen) {
             flog_err(EC_BABEL_PACKET, "Received truncated attributes.");
-            return;
-        }
+           return false;
+       }
         len = a[i + 1];
         if(i + len + 2 > alen) {
             flog_err(EC_BABEL_PACKET, "Received truncated attributes.");
-            return;
-        }
+           return false;
+       }
 
-        if(type == SUBTLV_PADN) {
-            /* Nothing. */
-        } else if(type == SUBTLV_DIVERSITY) {
-            if(len > DIVERSITY_HOPS) {
-                flog_err(EC_BABEL_PACKET,
-                         "Received overlong channel information (%d > %d).n",
-                          len, DIVERSITY_HOPS);
-                len = DIVERSITY_HOPS;
-            }
-            if(memchr(a + i + 2, 0, len) != NULL) {
-                /* 0 is reserved. */
-                flog_err(EC_BABEL_PACKET, "Channel information contains 0!");
-                return;
-            }
-            memset(channels, 0, DIVERSITY_HOPS);
-            memcpy(channels, a + i + 2, len);
-        } else {
-            debugf(BABEL_DEBUG_COMMON,
-                   "Received unknown route attribute %d.", type);
-        }
+       if (type & SUBTLV_MANDATORY) {
+               /*
+                * RFC 8966 - 4.4
+                * If the mandatory bit is set, then the whole enclosing
+                * TLV MUST be silently ignored (except for updating the
+                * parser state by a Router-Id, Next Hop, or Update TLV,
+                * as described in the next section).
+                */
+               debugf(BABEL_DEBUG_COMMON,
+                      "Received Mandatory bit set but this FRR version is not prepared to handle it at this point");
+               return true;
+       } else if (type == SUBTLV_PADN) {
+               /* Nothing. */
+       } else if (type == SUBTLV_DIVERSITY) {
+               if (len > DIVERSITY_HOPS) {
+                       flog_err(
+                               EC_BABEL_PACKET,
+                               "Received overlong channel information (%d > %d).n",
+                               len, DIVERSITY_HOPS);
+                       len = DIVERSITY_HOPS;
+               }
+               if (memchr(a + i + 2, 0, len) != NULL) {
+                       /* 0 is reserved. */
+                       flog_err(EC_BABEL_PACKET,
+                                "Channel information contains 0!");
+                       return false;
+               }
+               memset(channels, 0, DIVERSITY_HOPS);
+               memcpy(channels, a + i + 2, len);
+       } else {
+               debugf(BABEL_DEBUG_COMMON,
+                      "Received unknown route attribute %d.", type);
+       }
 
-        i += len + 2;
+       i += len + 2;
     }
+    return false;
 }
 
 static int
@@ -200,22 +196,34 @@ parse_hello_subtlv(const unsigned char *a, int alen,
             return -1;
         }
 
-        if(type == SUBTLV_PADN) {
-            /* Nothing to do. */
-        } else if(type == SUBTLV_TIMESTAMP) {
-            if(len >= 4) {
-                DO_NTOHL(*hello_send_us, a + i + 2);
-                ret = 1;
-            } else {
-                flog_err(EC_BABEL_PACKET,
-                         "Received incorrect RTT sub-TLV on Hello message.");
-            }
-        } else {
-            debugf(BABEL_DEBUG_COMMON,
-                   "Received unknown Hello sub-TLV type %d.", type);
-        }
+       if (type & SUBTLV_MANDATORY) {
+               /*
+                * RFC 8966 4.4
+                * If the mandatory bit is set, then the whole enclosing
+                * TLV MUST be silently ignored (except for updating the
+                * parser state by a Router-Id, Next Hop, or Update TLV, as
+                * described in the next section).
+                */
+               debugf(BABEL_DEBUG_COMMON,
+                      "Received subtlv with Mandatory bit, this version of FRR is not prepared to handle this currently");
+               return -2;
+       } else if (type == SUBTLV_PADN) {
+               /* Nothing to do. */
+       } else if (type == SUBTLV_TIMESTAMP) {
+               if (len >= 4) {
+                       DO_NTOHL(*hello_send_us, a + i + 2);
+                       ret = 1;
+               } else {
+                       flog_err(
+                               EC_BABEL_PACKET,
+                               "Received incorrect RTT sub-TLV on Hello message.");
+               }
+       } else {
+               debugf(BABEL_DEBUG_COMMON,
+                      "Received unknown Hello sub-TLV type %d.", type);
+       }
 
-        i += len + 2;
+       i += len + 2;
     }
     return ret;
 }
@@ -398,27 +406,69 @@ parse_packet(const unsigned char *from, struct interface *ifp,
                    format_address(from), ifp->name);
             /* Nothing right now */
         } else if(type == MESSAGE_HELLO) {
-            unsigned short seqno, interval;
-            int changed;
-            unsigned int timestamp = 0;
-            DO_NTOHS(seqno, message + 4);
-            DO_NTOHS(interval, message + 6);
-            debugf(BABEL_DEBUG_COMMON,"Received hello %d (%d) from %s on %s.",
-                   seqno, interval,
-                   format_address(from), ifp->name);
-            changed = update_neighbour(neigh, seqno, interval);
-            update_neighbour_metric(neigh, changed);
-            if(interval > 0)
-                /* Multiply by 3/2 to allow hellos to expire. */
-                schedule_neighbours_check(interval * 15, 0);
-            /* Sub-TLV handling. */
-            if(len > 8) {
-                if(parse_hello_subtlv(message + 8, len - 6, &timestamp) > 0) {
-                    neigh->hello_send_us = timestamp;
-                    neigh->hello_rtt_receive_time = babel_now;
-                    have_hello_rtt = 1;
-                }
-            }
+               unsigned short seqno, interval, flags;
+               int changed;
+               unsigned int timestamp = 0;
+
+#define BABEL_UNICAST_HELLO 0x8000
+               DO_NTOHS(flags, message + 2);
+
+               /*
+                * RFC 8966 4.6.5
+                * All other bits MUST be sent as a 0 and silently
+                * ignored on reception
+                */
+               if (CHECK_FLAG(flags, ~BABEL_UNICAST_HELLO)) {
+                       debugf(BABEL_DEBUG_COMMON,
+                              "Received Hello from %s on %s that does not have all 0's in the unused section of flags, ignoring",
+                              format_address(from), ifp->name);
+                       goto done;
+               }
+
+               /*
+                * RFC 8966 Appendix F
+                * TL;DR -> Please ignore Unicast hellos until FRR's
+                * BABEL is brought up to date
+                */
+               if (CHECK_FLAG(flags, BABEL_UNICAST_HELLO)) {
+                       debugf(BABEL_DEBUG_COMMON,
+                              "Received Unicast Hello from %s on %s that FRR is not prepared to understand yet",
+                              format_address(from), ifp->name);
+                       goto done;
+               }
+
+               DO_NTOHS(seqno, message + 4);
+               DO_NTOHS(interval, message + 6);
+               debugf(BABEL_DEBUG_COMMON,
+                      "Received hello %d (%d) from %s on %s.", seqno, interval,
+                      format_address(from), ifp->name);
+
+               /*
+                * RFC 8966 Appendix F
+                * TL;DR -> Please ignore any Hello packets with the interval
+                * field set to 0
+                */
+               if (interval == 0) {
+                       debugf(BABEL_DEBUG_COMMON,
+                              "Received hello from %s on %s should be ignored as that this version of FRR does not know how to properly handle interval == 0",
+                              format_address(from), ifp->name);
+                       goto done;
+               }
+
+               changed = update_neighbour(neigh, seqno, interval);
+               update_neighbour_metric(neigh, changed);
+               if (interval > 0)
+                       /* Multiply by 3/2 to allow hellos to expire. */
+                       schedule_neighbours_check(interval * 15, 0);
+               /* Sub-TLV handling. */
+               if (len > 8) {
+                       if (parse_hello_subtlv(message + 8, len - 6,
+                                              &timestamp) > 0) {
+                               neigh->hello_send_us = timestamp;
+                               neigh->hello_rtt_receive_time = babel_now;
+                               have_hello_rtt = 1;
+                       }
+               }
         } else if(type == MESSAGE_IHU) {
             unsigned short txcost, interval;
             unsigned char address[16];
@@ -476,7 +526,9 @@ parse_packet(const unsigned char *from, struct interface *ifp,
             unsigned char channels[DIVERSITY_HOPS];
             unsigned short interval, seqno, metric;
             int rc, parsed_len;
-            DO_NTOHS(interval, message + 6);
+           bool ignore_update = false;
+
+           DO_NTOHS(interval, message + 6);
             DO_NTOHS(seqno, message + 8);
             DO_NTOHS(metric, message + 10);
             if(message[5] == 0 ||
@@ -562,14 +614,16 @@ parse_packet(const unsigned char *from, struct interface *ifp,
                 }
 
                 if(parsed_len < len)
-                    parse_update_subtlv(message + 2 + parsed_len,
-                                        len - parsed_len, channels);
-            }
-
-            update_route(router_id, prefix, plen, seqno, metric, interval,
-                         neigh, nh,
-                         channels, channels_len(channels));
-        } else if(type == MESSAGE_REQUEST) {
+                       ignore_update =
+                               parse_update_subtlv(message + 2 + parsed_len,
+                                                   len - parsed_len, channels);
+           }
+
+           if (!ignore_update)
+                   update_route(router_id, prefix, plen, seqno, metric,
+                                interval, neigh, nh, channels,
+                                channels_len(channels));
+       } else if(type == MESSAGE_REQUEST) {
             unsigned char prefix[16], plen;
             int rc;
             rc = network_prefix(message[2], message[3], 0,