summaryrefslogtreecommitdiff
path: root/ospfd/ospf_packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'ospfd/ospf_packet.c')
-rw-r--r--ospfd/ospf_packet.c260
1 files changed, 259 insertions, 1 deletions
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 15ec3733..68c25790 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -73,6 +73,24 @@ static const u_int16_t ospf_packet_minlen[] =
OSPF_LS_ACK_MIN_SIZE,
};
+/* Minimum (besides OSPF_LSA_HEADER_SIZE) lengths for LSAs of particular
+ types, offset is the "LSA type" field. */
+static const u_int16_t ospf_lsa_minlen[] =
+{
+ 0,
+ OSPF_ROUTER_LSA_MIN_SIZE,
+ OSPF_NETWORK_LSA_MIN_SIZE,
+ OSPF_SUMMARY_LSA_MIN_SIZE,
+ OSPF_SUMMARY_LSA_MIN_SIZE,
+ OSPF_AS_EXTERNAL_LSA_MIN_SIZE,
+ 0,
+ OSPF_AS_EXTERNAL_LSA_MIN_SIZE,
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
/* OSPF authentication checking function */
static int
ospf_auth_type (struct ospf_interface *oi)
@@ -2315,11 +2333,199 @@ ospf_check_sum (struct ospf_header *ospfh)
return 1;
}
+/* Verify, that given link/TOS records are properly sized/aligned and match
+ Router-LSA "# links" and "# TOS" fields as specified in RFC2328 A.4.2. */
+static unsigned
+ospf_router_lsa_links_examin
+(
+ struct router_lsa_link * link,
+ u_int16_t linkbytes,
+ const u_int16_t num_links
+)
+{
+ unsigned counted_links = 0, thislinklen;
+
+ while (linkbytes)
+ {
+ thislinklen = OSPF_ROUTER_LSA_LINK_SIZE + 4 * link->m[0].tos_count;
+ if (thislinklen > linkbytes)
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: length error in link block #%u", __func__, counted_links);
+ return MSG_NG;
+ }
+ link = (struct router_lsa_link *)((caddr_t) link + thislinklen);
+ linkbytes -= thislinklen;
+ counted_links++;
+ }
+ if (counted_links != num_links)
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: %u link blocks declared, %u present",
+ __func__, num_links, counted_links);
+ return MSG_NG;
+ }
+ return MSG_OK;
+}
+
+/* Verify, that the given LSA is properly sized/aligned (including type-specific
+ minimum length constraint). */
+static unsigned
+ospf_lsa_examin (struct lsa_header * lsah, const u_int16_t lsalen, const u_char headeronly)
+{
+ unsigned ret;
+ struct router_lsa * rlsa;
+ if
+ (
+ lsah->type < OSPF_MAX_LSA &&
+ ospf_lsa_minlen[lsah->type] &&
+ lsalen < OSPF_LSA_HEADER_SIZE + ospf_lsa_minlen[lsah->type]
+ )
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: undersized (%u B) %s",
+ __func__, lsalen, LOOKUP (ospf_lsa_type_msg, lsah->type));
+ return MSG_NG;
+ }
+ switch (lsah->type)
+ {
+ case OSPF_ROUTER_LSA:
+ /* RFC2328 A.4.2, LSA header + 4 bytes followed by N>=1 (12+)-byte link blocks */
+ if (headeronly)
+ {
+ ret = (lsalen - OSPF_LSA_HEADER_SIZE - OSPF_ROUTER_LSA_MIN_SIZE) % 4 ? MSG_NG : MSG_OK;
+ break;
+ }
+ rlsa = (struct router_lsa *) lsah;
+ ret = ospf_router_lsa_links_examin
+ (
+ (struct router_lsa_link *) rlsa->link,
+ lsalen - OSPF_LSA_HEADER_SIZE - 4, /* skip: basic header, "flags", 0, "# links" */
+ ntohs (rlsa->links) /* 16 bits */
+ );
+ break;
+ case OSPF_AS_EXTERNAL_LSA:
+ /* RFC2328 A.4.5, LSA header + 4 bytes followed by N>=1 12-bytes long blocks */
+ case OSPF_AS_NSSA_LSA:
+ /* RFC3101 C, idem */
+ ret = (lsalen - OSPF_LSA_HEADER_SIZE - OSPF_AS_EXTERNAL_LSA_MIN_SIZE) % 12 ? MSG_NG : MSG_OK;
+ break;
+ /* Following LSA types are considered OK length-wise as soon as their minimum
+ * length constraint is met and length of the whole LSA is a multiple of 4
+ * (basic LSA header size is already a multiple of 4). */
+ case OSPF_NETWORK_LSA:
+ /* RFC2328 A.4.3, LSA header + 4 bytes followed by N>=1 router-IDs */
+ case OSPF_SUMMARY_LSA:
+ case OSPF_ASBR_SUMMARY_LSA:
+ /* RFC2328 A.4.4, LSA header + 4 bytes followed by N>=1 4-bytes TOS blocks */
+#ifdef HAVE_OPAQUE_LSA
+ case OSPF_OPAQUE_LINK_LSA:
+ case OSPF_OPAQUE_AREA_LSA:
+ case OSPF_OPAQUE_AS_LSA:
+ /* RFC5250 A.2, "some number of octets (of application-specific
+ * data) padded to 32-bit alignment." This is considered equivalent
+ * to 4-byte alignment of all other LSA types, see OSPF-ALIGNMENT.txt
+ * file for the detailed analysis of this passage. */
+#endif
+ ret = lsalen % 4 ? MSG_NG : MSG_OK;
+ break;
+ default:
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: unsupported LSA type 0x%02x", __func__, lsah->type);
+ return MSG_NG;
+ }
+ if (ret != MSG_OK && IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: alignment error in %s",
+ __func__, LOOKUP (ospf_lsa_type_msg, lsah->type));
+ return ret;
+}
+
+/* Verify if the provided input buffer is a valid sequence of LSAs. This
+ includes verification of LSA blocks length/alignment and dispatching
+ of deeper-level checks. */
+static unsigned
+ospf_lsaseq_examin
+(
+ struct lsa_header *lsah, /* start of buffered data */
+ size_t length,
+ const u_char headeronly,
+ /* When declared_num_lsas is not 0, compare it to the real number of LSAs
+ and treat the difference as an error. */
+ const u_int32_t declared_num_lsas
+)
+{
+ u_int32_t counted_lsas = 0;
+
+ while (length)
+ {
+ u_int16_t lsalen;
+ if (length < OSPF_LSA_HEADER_SIZE)
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: undersized (%zu B) trailing (#%u) LSA header",
+ __func__, length, counted_lsas);
+ return MSG_NG;
+ }
+ /* save on ntohs() calls here and in the LSA validator */
+ lsalen = ntohs (lsah->length);
+ if (lsalen < OSPF_LSA_HEADER_SIZE)
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: malformed LSA header #%u, declared length is %u B",
+ __func__, counted_lsas, lsalen);
+ return MSG_NG;
+ }
+ if (headeronly)
+ {
+ /* less checks here and in ospf_lsa_examin() */
+ if (MSG_OK != ospf_lsa_examin (lsah, lsalen, 1))
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: malformed header-only LSA #%u", __func__, counted_lsas);
+ return MSG_NG;
+ }
+ lsah = (struct lsa_header *) ((caddr_t) lsah + OSPF_LSA_HEADER_SIZE);
+ length -= OSPF_LSA_HEADER_SIZE;
+ }
+ else
+ {
+ /* make sure the input buffer is deep enough before further checks */
+ if (lsalen > length)
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: anomaly in LSA #%u: declared length is %u B, buffered length is %zu B",
+ __func__, counted_lsas, lsalen, length);
+ return MSG_NG;
+ }
+ if (MSG_OK != ospf_lsa_examin (lsah, lsalen, 0))
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: malformed LSA #%u", __func__, counted_lsas);
+ return MSG_NG;
+ }
+ lsah = (struct lsa_header *) ((caddr_t) lsah + lsalen);
+ length -= lsalen;
+ }
+ counted_lsas++;
+ }
+
+ if (declared_num_lsas && counted_lsas != declared_num_lsas)
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: #LSAs declared (%u) does not match actual (%u)",
+ __func__, declared_num_lsas, counted_lsas);
+ return MSG_NG;
+ }
+ return MSG_OK;
+}
+
/* Verify a complete OSPF packet for proper sizing/alignment. */
static unsigned
ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire)
{
u_int16_t bytesdeclared;
+ unsigned ret;
+ struct ospf_ls_update * lsupd;
/* Length, 1st approximation. */
if (bytesonwire < OSPF_HEADER_SIZE)
@@ -2353,7 +2559,59 @@ ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire)
bytesdeclared, LOOKUP (ospf_packet_type_str, oh->type));
return MSG_NG;
}
- return MSG_OK;
+ switch (oh->type)
+ {
+ case OSPF_MSG_HELLO:
+ /* RFC2328 A.3.2, packet header + OSPF_HELLO_MIN_SIZE bytes followed
+ by N>=0 router-IDs. */
+ ret = (bytesonwire - OSPF_HEADER_SIZE - OSPF_HELLO_MIN_SIZE) % 4 ? MSG_NG : MSG_OK;
+ break;
+ case OSPF_MSG_DB_DESC:
+ /* RFC2328 A.3.3, packet header + OSPF_DB_DESC_MIN_SIZE bytes followed
+ by N>=0 header-only LSAs. */
+ ret = ospf_lsaseq_examin
+ (
+ (struct lsa_header *) ((caddr_t) oh + OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE),
+ bytesonwire - OSPF_HEADER_SIZE - OSPF_DB_DESC_MIN_SIZE,
+ 1, /* header-only LSAs */
+ 0
+ );
+ break;
+ case OSPF_MSG_LS_REQ:
+ /* RFC2328 A.3.4, packet header followed by N>=0 12-bytes request blocks. */
+ ret = (bytesonwire - OSPF_HEADER_SIZE - OSPF_LS_REQ_MIN_SIZE) %
+ OSPF_LSA_KEY_SIZE ? MSG_NG : MSG_OK;
+ break;
+ case OSPF_MSG_LS_UPD:
+ /* RFC2328 A.3.5, packet header + OSPF_LS_UPD_MIN_SIZE bytes followed
+ by N>=0 full LSAs (with N declared beforehand). */
+ lsupd = (struct ospf_ls_update *) ((caddr_t) oh + OSPF_HEADER_SIZE);
+ ret = ospf_lsaseq_examin
+ (
+ (struct lsa_header *) ((caddr_t) lsupd + OSPF_LS_UPD_MIN_SIZE),
+ bytesonwire - OSPF_HEADER_SIZE - OSPF_LS_UPD_MIN_SIZE,
+ 0, /* full LSAs */
+ ntohl (lsupd->num_lsas) /* 32 bits */
+ );
+ break;
+ case OSPF_MSG_LS_ACK:
+ /* RFC2328 A.3.6, packet header followed by N>=0 header-only LSAs. */
+ ret = ospf_lsaseq_examin
+ (
+ (struct lsa_header *) ((caddr_t) oh + OSPF_HEADER_SIZE + OSPF_LS_ACK_MIN_SIZE),
+ bytesonwire - OSPF_HEADER_SIZE - OSPF_LS_ACK_MIN_SIZE,
+ 1, /* header-only LSAs */
+ 0
+ );
+ break;
+ default:
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: invalid packet type 0x%02x", __func__, oh->type);
+ return MSG_NG;
+ }
+ if (ret != MSG_OK && IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: malformed %s packet", __func__, LOOKUP (ospf_packet_type_str, oh->type));
+ return ret;
}
/* OSPF Header verification. */