summaryrefslogtreecommitdiff
path: root/ospf6d/ospf6_message.c
diff options
context:
space:
mode:
Diffstat (limited to 'ospf6d/ospf6_message.c')
-rw-r--r--ospf6d/ospf6_message.c695
1 files changed, 517 insertions, 178 deletions
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index 51933b76..01d61263 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -39,12 +39,55 @@
#include "ospf6_neighbor.h"
#include "ospf6_interface.h"
+/* for structures and macros ospf6_lsa_examin() needs */
+#include "ospf6_abr.h"
+#include "ospf6_asbr.h"
+#include "ospf6_intra.h"
+
#include "ospf6_flood.h"
#include "ospf6d.h"
+#include <netinet/ip6.h>
+
unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0};
-const char *ospf6_message_type_str[] =
- { "Unknown", "Hello", "DbDesc", "LSReq", "LSUpdate", "LSAck" };
+static const struct message ospf6_message_type_str [] =
+{
+ { OSPF6_MESSAGE_TYPE_HELLO, "Hello" },
+ { OSPF6_MESSAGE_TYPE_DBDESC, "DbDesc" },
+ { OSPF6_MESSAGE_TYPE_LSREQ, "LSReq" },
+ { OSPF6_MESSAGE_TYPE_LSUPDATE, "LSUpdate" },
+ { OSPF6_MESSAGE_TYPE_LSACK, "LSAck" },
+};
+static const size_t ospf6_message_type_str_max =
+ sizeof (ospf6_message_type_str) / sizeof (ospf6_message_type_str[0]);
+
+/* Minimum (besides the standard OSPF packet header) lengths for OSPF
+ packets of particular types, offset is the "type" field. */
+const u_int16_t ospf6_packet_minlen[OSPF6_MESSAGE_TYPE_ALL] =
+{
+ 0,
+ OSPF6_HELLO_MIN_SIZE,
+ OSPF6_DB_DESC_MIN_SIZE,
+ OSPF6_LS_REQ_MIN_SIZE,
+ OSPF6_LS_UPD_MIN_SIZE,
+ OSPF6_LS_ACK_MIN_SIZE
+};
+
+/* Minimum (besides the standard LSA header) lengths for LSAs of particular
+ types, offset is the "LSA function code" portion of "LSA type" field. */
+const u_int16_t ospf6_lsa_minlen[OSPF6_LSTYPE_SIZE] =
+{
+ 0,
+ /* 0x2001 */ OSPF6_ROUTER_LSA_MIN_SIZE,
+ /* 0x2002 */ OSPF6_NETWORK_LSA_MIN_SIZE,
+ /* 0x2003 */ OSPF6_INTER_PREFIX_LSA_MIN_SIZE,
+ /* 0x2004 */ OSPF6_INTER_ROUTER_LSA_FIX_SIZE,
+ /* 0x4005 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE,
+ /* 0x2006 */ 0,
+ /* 0x2007 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE,
+ /* 0x0008 */ OSPF6_LINK_LSA_MIN_SIZE,
+ /* 0x2009 */ OSPF6_INTRA_PREFIX_LSA_MIN_SIZE
+};
/* print functions */
@@ -93,8 +136,7 @@ ospf6_hello_print (struct ospf6_header *oh)
zlog_debug (" Neighbor: %s", neighbor);
}
- if (p != OSPF6_MESSAGE_END (oh))
- zlog_debug ("Trailing garbage exists");
+ assert (p == OSPF6_MESSAGE_END (oh));
}
void
@@ -126,8 +168,7 @@ ospf6_dbdesc_print (struct ospf6_header *oh)
p += sizeof (struct ospf6_lsa_header))
ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p);
- if (p != OSPF6_MESSAGE_END (oh))
- zlog_debug ("Trailing garbage exists");
+ assert (p == OSPF6_MESSAGE_END (oh));
}
void
@@ -150,8 +191,7 @@ ospf6_lsreq_print (struct ospf6_header *oh)
ospf6_lstype_name (e->type), id, adv_router);
}
- if (p != OSPF6_MESSAGE_END (oh))
- zlog_debug ("Trailing garbage exists");
+ assert (p == OSPF6_MESSAGE_END (oh));
}
void
@@ -176,35 +216,9 @@ ospf6_lsupdate_print (struct ospf6_header *oh)
p += OSPF6_LSA_SIZE (p))
{
ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p);
- if (OSPF6_LSA_SIZE (p) < sizeof (struct ospf6_lsa_header))
- {
- zlog_debug (" Malformed LSA length, quit printing");
- break;
- }
}
- if (p != OSPF6_MESSAGE_END (oh))
- {
- char buf[32];
-
- int num = 0;
- memset (buf, 0, sizeof (buf));
-
- zlog_debug (" Trailing garbage exists");
- while (p < OSPF6_MESSAGE_END (oh))
- {
- snprintf (buf, sizeof (buf), "%s %2x", buf, *p++);
- num++;
- if (num == 8)
- {
- zlog_debug (" %s", buf);
- memset (buf, 0, sizeof (buf));
- num = 0;
- }
- }
- if (num)
- zlog_debug (" %s", buf);
- }
+ assert (p == OSPF6_MESSAGE_END (oh));
}
void
@@ -220,56 +234,7 @@ ospf6_lsack_print (struct ospf6_header *oh)
p += sizeof (struct ospf6_lsa_header))
ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p);
- if (p != OSPF6_MESSAGE_END (oh))
- zlog_debug ("Trailing garbage exists");
-}
-
-/* Receive function */
-#define MSG_OK 0
-#define MSG_NG 1
-static int
-ospf6_header_examin (struct in6_addr *src, struct in6_addr *dst,
- struct ospf6_interface *oi, struct ospf6_header *oh)
-{
- u_char type;
- type = OSPF6_MESSAGE_TYPE_CANONICAL (oh->type);
-
- /* version check */
- if (oh->version != OSPFV3_VERSION)
- {
- if (IS_OSPF6_DEBUG_MESSAGE (type, RECV))
- zlog_debug ("Message with unknown version");
- return MSG_NG;
- }
-
- /* Area-ID check */
- if (oh->area_id != oi->area->area_id)
- {
- if (oh->area_id == BACKBONE_AREA_ID)
- {
- if (IS_OSPF6_DEBUG_MESSAGE (type, RECV))
- zlog_debug ("Message may be via Virtual Link: not supported");
- return MSG_NG;
- }
-
- if (IS_OSPF6_DEBUG_MESSAGE (type, RECV))
- zlog_debug ("Area-ID mismatch");
- return MSG_NG;
- }
-
- /* Instance-ID check */
- if (oh->instance_id != oi->instance_id)
- {
- if (IS_OSPF6_DEBUG_MESSAGE (type, RECV))
- zlog_debug ("Instance-ID mismatch");
- return MSG_NG;
- }
-
- /* Router-ID check */
- if (oh->router_id == oi->area->ospf6->router_id)
- zlog_warn ("Detect duplicate Router-ID");
-
- return MSG_OK;
+ assert (p == OSPF6_MESSAGE_END (oh));
}
static void
@@ -283,9 +248,6 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst,
int neighborchange = 0;
int backupseen = 0;
- if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK)
- return;
-
hello = (struct ospf6_hello *)
((caddr_t) oh + sizeof (struct ospf6_header));
@@ -339,11 +301,7 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst,
twoway++;
}
- if (p != OSPF6_MESSAGE_END (oh))
- {
- if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
- zlog_debug ("Trailing garbage ignored");
- }
+ assert (p == OSPF6_MESSAGE_END (oh));
/* RouterPriority check */
if (on->priority != hello->priority)
@@ -576,11 +534,7 @@ ospf6_dbdesc_recv_master (struct ospf6_header *oh,
}
}
- if (p != OSPF6_MESSAGE_END (oh))
- {
- if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
- zlog_debug ("Trailing garbage ignored");
- }
+ assert (p == OSPF6_MESSAGE_END (oh));
/* Increment sequence number */
on->dbdesc_seqnum ++;
@@ -788,11 +742,7 @@ ospf6_dbdesc_recv_slave (struct ospf6_header *oh,
ospf6_lsa_delete (his);
}
- if (p != OSPF6_MESSAGE_END (oh))
- {
- if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
- zlog_debug ("Trailing garbage ignored");
- }
+ assert (p == OSPF6_MESSAGE_END (oh));
/* Set sequence number to Master's */
on->dbdesc_seqnum = ntohl (dbdesc->seqnum);
@@ -817,9 +767,6 @@ ospf6_dbdesc_recv (struct in6_addr *src, struct in6_addr *dst,
struct ospf6_neighbor *on;
struct ospf6_dbdesc *dbdesc;
- if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK)
- return;
-
on = ospf6_neighbor_lookup (oh->router_id, oi);
if (on == NULL)
{
@@ -869,9 +816,6 @@ ospf6_lsreq_recv (struct in6_addr *src, struct in6_addr *dst,
struct ospf6_lsdb *lsdb = NULL;
struct ospf6_lsa *lsa;
- if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK)
- return;
-
on = ospf6_neighbor_lookup (oh->router_id, oi);
if (on == NULL)
{
@@ -934,11 +878,7 @@ ospf6_lsreq_recv (struct in6_addr *src, struct in6_addr *dst,
ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->lsupdate_list);
}
- if (p != OSPF6_MESSAGE_END (oh))
- {
- if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
- zlog_debug ("Trailing garbage ignored");
- }
+ assert (p == OSPF6_MESSAGE_END (oh));
/* schedule send lsupdate */
THREAD_OFF (on->thread_send_lsupdate);
@@ -946,18 +886,441 @@ ospf6_lsreq_recv (struct in6_addr *src, struct in6_addr *dst,
thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0);
}
+/* Verify, that the specified memory area contains exactly N valid IPv6
+ prefixes as specified by RFC5340, A.4.1. */
+static unsigned
+ospf6_prefixes_examin
+(
+ struct ospf6_prefix *current, /* start of buffer */
+ unsigned length,
+ const u_int32_t req_num_pfxs /* always compared with the actual number of prefixes */
+)
+{
+ u_char requested_pfx_bytes;
+ u_int32_t real_num_pfxs = 0;
+
+ while (length)
+ {
+ if (length < OSPF6_PREFIX_MIN_SIZE)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: undersized IPv6 prefix header", __func__);
+ return MSG_NG;
+ }
+ /* safe to look deeper */
+ if (current->prefix_length > IPV6_MAX_BITLEN)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: invalid PrefixLength (%u bits)", __func__, current->prefix_length);
+ return MSG_NG;
+ }
+ /* covers both fixed- and variable-sized fields */
+ requested_pfx_bytes = OSPF6_PREFIX_MIN_SIZE + OSPF6_PREFIX_SPACE (current->prefix_length);
+ if (requested_pfx_bytes > length)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: undersized IPv6 prefix", __func__);
+ return MSG_NG;
+ }
+ /* next prefix */
+ length -= requested_pfx_bytes;
+ current = (struct ospf6_prefix *) ((caddr_t) current + requested_pfx_bytes);
+ real_num_pfxs++;
+ }
+ if (real_num_pfxs != req_num_pfxs)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: IPv6 prefix number mismatch (%u required, %u real)",
+ __func__, req_num_pfxs, real_num_pfxs);
+ return MSG_NG;
+ }
+ return MSG_OK;
+}
+
+/* Verify an LSA to have a valid length and dispatch further (where
+ appropriate) to check if the contents, including nested IPv6 prefixes,
+ is properly sized/aligned within the LSA. Note that this function gets
+ LSA type in network byte order, uses in host byte order and passes to
+ ospf6_lstype_name() in network byte order again. */
+static unsigned
+ospf6_lsa_examin (struct ospf6_lsa_header *lsah, const u_int16_t lsalen, const u_char headeronly)
+{
+ struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
+ struct ospf6_as_external_lsa *as_external_lsa;
+ struct ospf6_link_lsa *link_lsa;
+ unsigned exp_length;
+ u_int8_t ltindex;
+ u_int16_t lsatype;
+
+ /* In case an additional minimum length constraint is defined for current
+ LSA type, make sure that this constraint is met. */
+ lsatype = ntohs (lsah->type);
+ ltindex = lsatype & OSPF6_LSTYPE_FCODE_MASK;
+ if
+ (
+ ltindex < OSPF6_LSTYPE_SIZE &&
+ ospf6_lsa_minlen[ltindex] &&
+ lsalen < ospf6_lsa_minlen[ltindex] + OSPF6_LSA_HEADER_SIZE
+ )
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: undersized (%u B) LSA", __func__, lsalen);
+ return MSG_NG;
+ }
+ switch (lsatype)
+ {
+ case OSPF6_LSTYPE_ROUTER:
+ /* RFC5340 A.4.3, LSA header + OSPF6_ROUTER_LSA_MIN_SIZE bytes followed
+ by N>=0 interface descriptions. */
+ if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_ROUTER_LSA_MIN_SIZE) % OSPF6_ROUTER_LSDESC_FIX_SIZE)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: interface description alignment error", __func__);
+ return MSG_NG;
+ }
+ break;
+ case OSPF6_LSTYPE_NETWORK:
+ /* RFC5340 A.4.4, LSA header + OSPF6_NETWORK_LSA_MIN_SIZE bytes
+ followed by N>=0 attached router descriptions. */
+ if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_NETWORK_LSA_MIN_SIZE) % OSPF6_NETWORK_LSDESC_FIX_SIZE)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: router description alignment error", __func__);
+ return MSG_NG;
+ }
+ break;
+ case OSPF6_LSTYPE_INTER_PREFIX:
+ /* RFC5340 A.4.5, LSA header + OSPF6_INTER_PREFIX_LSA_MIN_SIZE bytes
+ followed by 3-4 fields of a single IPv6 prefix. */
+ if (headeronly)
+ break;
+ return ospf6_prefixes_examin
+ (
+ (struct ospf6_prefix *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_PREFIX_LSA_MIN_SIZE),
+ lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_INTER_PREFIX_LSA_MIN_SIZE,
+ 1
+ );
+ case OSPF6_LSTYPE_INTER_ROUTER:
+ /* RFC5340 A.4.6, fixed-size LSA. */
+ if (lsalen > OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_ROUTER_LSA_FIX_SIZE)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: oversized (%u B) LSA", __func__, lsalen);
+ return MSG_NG;
+ }
+ break;
+ case OSPF6_LSTYPE_AS_EXTERNAL: /* RFC5340 A.4.7, same as A.4.8. */
+ case OSPF6_LSTYPE_TYPE_7:
+ /* RFC5340 A.4.8, LSA header + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE bytes
+ followed by 3-4 fields of IPv6 prefix and 3 conditional LSA fields:
+ 16 bytes of forwarding address, 4 bytes of external route tag,
+ 4 bytes of referenced link state ID. */
+ if (headeronly)
+ break;
+ as_external_lsa = (struct ospf6_as_external_lsa *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE);
+ exp_length = OSPF6_LSA_HEADER_SIZE + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE;
+ /* To find out if the last optional field (Referenced Link State ID) is
+ assumed in this LSA, we need to access fixed fields of the IPv6
+ prefix before ospf6_prefix_examin() confirms its sizing. */
+ if (exp_length + OSPF6_PREFIX_MIN_SIZE > lsalen)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: undersized (%u B) LSA header", __func__, lsalen);
+ return MSG_NG;
+ }
+ /* forwarding address */
+ if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F))
+ exp_length += 16;
+ /* external route tag */
+ if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T))
+ exp_length += 4;
+ /* referenced link state ID */
+ if (as_external_lsa->prefix.u._prefix_referenced_lstype)
+ exp_length += 4;
+ /* All the fixed-size fields (mandatory and optional) must fit. I.e.,
+ this check does not include any IPv6 prefix fields. */
+ if (exp_length > lsalen)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: undersized (%u B) LSA header", __func__, lsalen);
+ return MSG_NG;
+ }
+ /* The last call completely covers the remainder (IPv6 prefix). */
+ return ospf6_prefixes_examin
+ (
+ (struct ospf6_prefix *) ((caddr_t) as_external_lsa + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE),
+ lsalen - exp_length,
+ 1
+ );
+ case OSPF6_LSTYPE_LINK:
+ /* RFC5340 A.4.9, LSA header + OSPF6_LINK_LSA_MIN_SIZE bytes followed
+ by N>=0 IPv6 prefix blocks (with N declared beforehand). */
+ if (headeronly)
+ break;
+ link_lsa = (struct ospf6_link_lsa *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE);
+ return ospf6_prefixes_examin
+ (
+ (struct ospf6_prefix *) ((caddr_t) link_lsa + OSPF6_LINK_LSA_MIN_SIZE),
+ lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_LINK_LSA_MIN_SIZE,
+ ntohl (link_lsa->prefix_num) /* 32 bits */
+ );
+ case OSPF6_LSTYPE_INTRA_PREFIX:
+ /* RFC5340 A.4.10, LSA header + OSPF6_INTRA_PREFIX_LSA_MIN_SIZE bytes
+ followed by N>=0 IPv6 prefixes (with N declared beforehand). */
+ if (headeronly)
+ break;
+ intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE);
+ return ospf6_prefixes_examin
+ (
+ (struct ospf6_prefix *) ((caddr_t) intra_prefix_lsa + OSPF6_INTRA_PREFIX_LSA_MIN_SIZE),
+ lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_INTRA_PREFIX_LSA_MIN_SIZE,
+ ntohs (intra_prefix_lsa->prefix_num) /* 16 bits */
+ );
+ }
+ /* No additional validation is possible for unknown LSA types, which are
+ themselves valid in OPSFv3, hence the default decision is to accept. */
+ return MSG_OK;
+}
+
+/* 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
+ospf6_lsaseq_examin
+(
+ struct ospf6_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 < OSPF6_LSA_HEADER_SIZE)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, 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 = OSPF6_LSA_SIZE (lsah);
+ if (lsalen < OSPF6_LSA_HEADER_SIZE)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, 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 ospf6_lsa_examin() */
+ if (MSG_OK != ospf6_lsa_examin (lsah, lsalen, 1))
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: anomaly in header-only %s LSA #%u", __func__,
+ ospf6_lstype_name (lsah->type), counted_lsas);
+ return MSG_NG;
+ }
+ lsah = (struct ospf6_lsa_header *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE);
+ length -= OSPF6_LSA_HEADER_SIZE;
+ }
+ else
+ {
+ /* make sure the input buffer is deep enough before further checks */
+ if (lsalen > length)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: anomaly in %s LSA #%u: declared length is %u B, buffered length is %zu B",
+ __func__, ospf6_lstype_name (lsah->type), counted_lsas, lsalen, length);
+ return MSG_NG;
+ }
+ if (MSG_OK != ospf6_lsa_examin (lsah, lsalen, 0))
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: anomaly in %s LSA #%u", __func__,
+ ospf6_lstype_name (lsah->type), counted_lsas);
+ return MSG_NG;
+ }
+ lsah = (struct ospf6_lsa_header *) ((caddr_t) lsah + lsalen);
+ length -= lsalen;
+ }
+ counted_lsas++;
+ }
+
+ if (declared_num_lsas && counted_lsas != declared_num_lsas)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, 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
+ospf6_packet_examin (struct ospf6_header *oh, const unsigned bytesonwire)
+{
+ struct ospf6_lsupdate *lsupd;
+ unsigned test;
+
+ /* length, 1st approximation */
+ if (bytesonwire < OSPF6_HEADER_SIZE)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: undersized (%u B) packet", __func__, bytesonwire);
+ return MSG_NG;
+ }
+ /* Now it is safe to access header fields. */
+ if (bytesonwire != ntohs (oh->length))
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: packet length error (%u real, %u declared)",
+ __func__, bytesonwire, ntohs (oh->length));
+ return MSG_NG;
+ }
+ /* version check */
+ if (oh->version != OSPFV3_VERSION)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: invalid (%u) protocol version", __func__, oh->version);
+ return MSG_NG;
+ }
+ /* length, 2nd approximation */
+ if
+ (
+ oh->type < OSPF6_MESSAGE_TYPE_ALL &&
+ ospf6_packet_minlen[oh->type] &&
+ bytesonwire < OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type]
+ )
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: undersized (%u B) %s packet", __func__,
+ bytesonwire, LOOKUP (ospf6_message_type_str, oh->type));
+ return MSG_NG;
+ }
+ /* type-specific deeper validation */
+ switch (oh->type)
+ {
+ case OSPF6_MESSAGE_TYPE_HELLO:
+ /* RFC5340 A.3.2, packet header + OSPF6_HELLO_MIN_SIZE bytes followed
+ by N>=0 router-IDs. */
+ if (0 == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_HELLO_MIN_SIZE) % 4)
+ return MSG_OK;
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: alignment error in %s packet",
+ __func__, LOOKUP (ospf6_message_type_str, oh->type));
+ return MSG_NG;
+ case OSPF6_MESSAGE_TYPE_DBDESC:
+ /* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes followed
+ by N>=0 header-only LSAs. */
+ test = ospf6_lsaseq_examin
+ (
+ (struct ospf6_lsa_header *) ((caddr_t) oh + OSPF6_HEADER_SIZE + OSPF6_DB_DESC_MIN_SIZE),
+ bytesonwire - OSPF6_HEADER_SIZE - OSPF6_DB_DESC_MIN_SIZE,
+ 1,
+ 0
+ );
+ break;
+ case OSPF6_MESSAGE_TYPE_LSREQ:
+ /* RFC5340 A.3.4, packet header + N>=0 LS description blocks. */
+ if (0 == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_REQ_MIN_SIZE) % OSPF6_LSREQ_LSDESC_FIX_SIZE)
+ return MSG_OK;
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: alignment error in %s packet",
+ __func__, LOOKUP (ospf6_message_type_str, oh->type));
+ return MSG_NG;
+ case OSPF6_MESSAGE_TYPE_LSUPDATE:
+ /* RFC5340 A.3.5, packet header + OSPF6_LS_UPD_MIN_SIZE bytes followed
+ by N>=0 full LSAs (with N declared beforehand). */
+ lsupd = (struct ospf6_lsupdate *) ((caddr_t) oh + OSPF6_HEADER_SIZE);
+ test = ospf6_lsaseq_examin
+ (
+ (struct ospf6_lsa_header *) ((caddr_t) lsupd + OSPF6_LS_UPD_MIN_SIZE),
+ bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_UPD_MIN_SIZE,
+ 0,
+ ntohl (lsupd->lsa_number) /* 32 bits */
+ );
+ break;
+ case OSPF6_MESSAGE_TYPE_LSACK:
+ /* RFC5340 A.3.6, packet header + N>=0 header-only LSAs. */
+ test = ospf6_lsaseq_examin
+ (
+ (struct ospf6_lsa_header *) ((caddr_t) oh + OSPF6_HEADER_SIZE + OSPF6_LS_ACK_MIN_SIZE),
+ bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_ACK_MIN_SIZE,
+ 1,
+ 0
+ );
+ break;
+ default:
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: invalid (%u) message type", __func__, oh->type);
+ return MSG_NG;
+ }
+ if (test != MSG_OK && IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: anomaly in %s packet", __func__, LOOKUP (ospf6_message_type_str, oh->type));
+ return test;
+}
+
+/* Verify particular fields of otherwise correct received OSPF packet to
+ meet the requirements of RFC. */
+static int
+ospf6_rxpacket_examin (struct ospf6_interface *oi, struct ospf6_header *oh, const unsigned bytesonwire)
+{
+ char buf[2][INET_ADDRSTRLEN];
+
+ if (MSG_OK != ospf6_packet_examin (oh, bytesonwire))
+ return MSG_NG;
+
+ /* Area-ID check */
+ if (oh->area_id != oi->area->area_id)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+ {
+ if (oh->area_id == BACKBONE_AREA_ID)
+ zlog_debug ("%s: Message may be via Virtual Link: not supported", __func__);
+ else
+ zlog_debug
+ (
+ "%s: Area-ID mismatch (my %s, rcvd %s)", __func__,
+ inet_ntop (AF_INET, &oi->area->area_id, buf[0], INET_ADDRSTRLEN),
+ inet_ntop (AF_INET, &oh->area_id, buf[1], INET_ADDRSTRLEN)
+ );
+ }
+ return MSG_NG;
+ }
+
+ /* Instance-ID check */
+ if (oh->instance_id != oi->instance_id)
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+ zlog_debug ("%s: Instance-ID mismatch (my %u, rcvd %u)", __func__, oi->instance_id, oh->instance_id);
+ return MSG_NG;
+ }
+
+ /* Router-ID check */
+ if (oh->router_id == oi->area->ospf6->router_id)
+ {
+ zlog_warn ("%s: Duplicate Router-ID (%s)", __func__, inet_ntop (AF_INET, &oh->router_id, buf[0], INET_ADDRSTRLEN));
+ return MSG_NG;
+ }
+ return MSG_OK;
+}
+
static void
ospf6_lsupdate_recv (struct in6_addr *src, struct in6_addr *dst,
struct ospf6_interface *oi, struct ospf6_header *oh)
{
struct ospf6_neighbor *on;
struct ospf6_lsupdate *lsupdate;
- unsigned long num;
char *p;
- if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK)
- return;
-
on = ospf6_neighbor_lookup (oh->router_id, oi);
if (on == NULL)
{
@@ -978,37 +1341,16 @@ ospf6_lsupdate_recv (struct in6_addr *src, struct in6_addr *dst,
lsupdate = (struct ospf6_lsupdate *)
((caddr_t) oh + sizeof (struct ospf6_header));
- num = ntohl (lsupdate->lsa_number);
-
/* Process LSAs */
for (p = (char *) ((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate));
p < OSPF6_MESSAGE_END (oh) &&
p + OSPF6_LSA_SIZE (p) <= OSPF6_MESSAGE_END (oh);
p += OSPF6_LSA_SIZE (p))
{
- if (num == 0)
- break;
- if (OSPF6_LSA_SIZE (p) < sizeof (struct ospf6_lsa_header))
- {
- if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
- zlog_debug ("Malformed LSA length, quit processing");
- break;
- }
-
ospf6_receive_lsa (on, (struct ospf6_lsa_header *) p);
- num--;
}
- if (num != 0)
- {
- if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
- zlog_debug ("Malformed LSA number or LSA length");
- }
- if (p != OSPF6_MESSAGE_END (oh))
- {
- if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
- zlog_debug ("Trailing garbage ignored");
- }
+ assert (p == OSPF6_MESSAGE_END (oh));
/* RFC2328 Section 10.9: When the neighbor responds to these requests
with the proper Link State Update packet(s), the Link state request
@@ -1035,8 +1377,6 @@ ospf6_lsack_recv (struct in6_addr *src, struct in6_addr *dst,
struct ospf6_lsdb *lsdb = NULL;
assert (oh->type == OSPF6_MESSAGE_TYPE_LSACK);
- if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK)
- return;
on = ospf6_neighbor_lookup (oh->router_id, oi);
if (on == NULL)
@@ -1126,11 +1466,7 @@ ospf6_lsack_recv (struct in6_addr *src, struct in6_addr *dst,
ospf6_lsa_delete (his);
}
- if (p != OSPF6_MESSAGE_END (oh))
- {
- if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
- zlog_debug ("Trailing garbage ignored");
- }
+ assert (p == OSPF6_MESSAGE_END (oh));
}
static u_char *recvbuf = NULL;
@@ -1219,11 +1555,6 @@ ospf6_receive (struct thread *thread)
zlog_err ("Excess message read");
return 0;
}
- else if (len < sizeof (struct ospf6_header))
- {
- zlog_err ("Deficient message read");
- return 0;
- }
oi = ospf6_interface_lookup_by_ifindex (ifindex);
if (oi == NULL || oi->area == NULL)
@@ -1231,8 +1562,22 @@ ospf6_receive (struct thread *thread)
zlog_debug ("Message received on disabled interface");
return 0;
}
+ if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE))
+ {
+ if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug ("%s: Ignore message on passive interface %s",
+ __func__, oi->interface->name);
+ return 0;
+ }
oh = (struct ospf6_header *) recvbuf;
+ if (ospf6_rxpacket_examin (oi, oh, len) != MSG_OK)
+ return 0;
+
+ /* Being here means, that no sizing/alignment issues were detected in
+ the input packet. This renders the additional checks performed below
+ and also in the type-specific dispatching functions a dead code,
+ which can be dismissed in a cleanup-focused review round later. */
/* Log */
if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
@@ -1240,11 +1585,9 @@ ospf6_receive (struct thread *thread)
inet_ntop (AF_INET6, &src, srcname, sizeof (srcname));
inet_ntop (AF_INET6, &dst, dstname, sizeof (dstname));
zlog_debug ("%s received on %s",
- OSPF6_MESSAGE_TYPE_NAME (oh->type), oi->interface->name);
+ LOOKUP (ospf6_message_type_str, oh->type), oi->interface->name);
zlog_debug (" src: %s", srcname);
zlog_debug (" dst: %s", dstname);
- if (len != ntohs (oh->length))
- zlog_debug ("Message length does not match actually received: %d", len);
switch (oh->type)
{
@@ -1264,19 +1607,10 @@ ospf6_receive (struct thread *thread)
ospf6_lsack_print (oh);
break;
default:
- zlog_debug ("Unknown message");
- break;
+ assert (0);
}
}
- if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE))
- {
- if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
- zlog_debug ("Ignore message on passive interface %s",
- oi->interface->name);
- return 0;
- }
-
switch (oh->type)
{
case OSPF6_MESSAGE_TYPE_HELLO:
@@ -1300,9 +1634,7 @@ ospf6_receive (struct thread *thread)
break;
default:
- if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
- zlog_debug ("Unknown message");
- break;
+ assert (0);
}
return 0;
@@ -1341,7 +1673,7 @@ ospf6_send (struct in6_addr *src, struct in6_addr *dst,
else
memset (srcname, 0, sizeof (srcname));
zlog_debug ("%s send on %s",
- OSPF6_MESSAGE_TYPE_NAME (oh->type), oi->interface->name);
+ LOOKUP (ospf6_message_type_str, oh->type), oi->interface->name);
zlog_debug (" src: %s", srcname);
zlog_debug (" dst: %s", dstname);
@@ -1375,6 +1707,13 @@ ospf6_send (struct in6_addr *src, struct in6_addr *dst,
zlog_err ("Could not send entire message");
}
+static uint32_t
+ospf6_packet_max(struct ospf6_interface *oi)
+{
+ assert (oi->ifmtu > sizeof (struct ip6_hdr));
+ return oi->ifmtu - (sizeof (struct ip6_hdr));
+}
+
int
ospf6_hello_send (struct thread *thread)
{
@@ -1421,7 +1760,7 @@ ospf6_hello_send (struct thread *thread)
if (on->state < OSPF6_NEIGHBOR_INIT)
continue;
- if (p - sendbuf + sizeof (u_int32_t) > oi->ifmtu)
+ if (p - sendbuf + sizeof (u_int32_t) > ospf6_packet_max(oi))
{
if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_HELLO, SEND))
zlog_debug ("sending Hello message: exceeds I/F MTU");
@@ -1497,7 +1836,7 @@ ospf6_dbdesc_send (struct thread *thread)
/* MTU check */
if (p - sendbuf + sizeof (struct ospf6_lsa_header) >
- on->ospf6_if->ifmtu)
+ ospf6_packet_max(on->ospf6_if))
{
ospf6_lsa_unlock (lsa);
break;
@@ -1531,7 +1870,7 @@ ospf6_dbdesc_send_newone (struct thread *thread)
for (lsa = ospf6_lsdb_head (on->summary_list); lsa;
lsa = ospf6_lsdb_next (lsa))
{
- if (size + sizeof (struct ospf6_lsa_header) > on->ospf6_if->ifmtu)
+ if (size + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if))
{
ospf6_lsa_unlock (lsa);
break;
@@ -1598,7 +1937,7 @@ ospf6_lsreq_send (struct thread *thread)
lsa = ospf6_lsdb_next (lsa))
{
/* MTU check */
- if (p - sendbuf + sizeof (struct ospf6_lsreq_entry) > on->ospf6_if->ifmtu)
+ if (p - sendbuf + sizeof (struct ospf6_lsreq_entry) > ospf6_packet_max(on->ospf6_if))
{
ospf6_lsa_unlock (lsa);
break;
@@ -1667,7 +2006,7 @@ ospf6_lsupdate_send_neighbor (struct thread *thread)
{
/* MTU check */
if ( (p - sendbuf + (unsigned int)OSPF6_LSA_SIZE (lsa->header))
- > on->ospf6_if->ifmtu)
+ > ospf6_packet_max(on->ospf6_if))
{
ospf6_lsa_unlock (lsa);
break;
@@ -1687,7 +2026,7 @@ ospf6_lsupdate_send_neighbor (struct thread *thread)
{
/* MTU check */
if ( (p - sendbuf + (unsigned int)OSPF6_LSA_SIZE (lsa->header))
- > on->ospf6_if->ifmtu)
+ > ospf6_packet_max(on->ospf6_if))
{
ospf6_lsa_unlock (lsa);
break;
@@ -1760,7 +2099,7 @@ ospf6_lsupdate_send_interface (struct thread *thread)
{
/* MTU check */
if ( (p - sendbuf + ((unsigned int)OSPF6_LSA_SIZE (lsa->header)))
- > oi->ifmtu)
+ > ospf6_packet_max(oi))
{
ospf6_lsa_unlock (lsa);
break;
@@ -1827,7 +2166,7 @@ ospf6_lsack_send_neighbor (struct thread *thread)
lsa = ospf6_lsdb_next (lsa))
{
/* MTU check */
- if (p - sendbuf + sizeof (struct ospf6_lsa_header) > on->ospf6_if->ifmtu)
+ if (p - sendbuf + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if))
{
/* if we run out of packet size/space here,
better to try again soon. */
@@ -1887,7 +2226,7 @@ ospf6_lsack_send_interface (struct thread *thread)
lsa = ospf6_lsdb_next (lsa))
{
/* MTU check */
- if (p - sendbuf + sizeof (struct ospf6_lsa_header) > oi->ifmtu)
+ if (p - sendbuf + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(oi))
{
/* if we run out of packet size/space here,
better to try again soon. */