summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_open.c14
-rwxr-xr-xconfigure.ac2
-rw-r--r--ospfd/ospf_dump.c23
-rw-r--r--ospfd/ospf_dump.h3
-rw-r--r--ospfd/ospf_lsa.h4
-rw-r--r--ospfd/ospf_packet.c552
-rw-r--r--ospfd/ospf_packet.h11
7 files changed, 479 insertions, 130 deletions
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 872e12a2..d9db1c99 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -454,12 +454,20 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
static as_t
bgp_capability_as4 (struct peer *peer, struct capability_header *hdr)
{
+ SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
+
+ if (hdr->length != CAPABILITY_CODE_AS4_LEN)
+ {
+ zlog_err ("%s AS4 capability has incorrect data length %d",
+ peer->host, hdr->length);
+ return 0;
+ }
+
as_t as4 = stream_getl (BGP_INPUT(peer));
if (BGP_DEBUG (as4, AS4))
zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u",
peer->host, as4);
- SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
return as4;
}
@@ -724,11 +732,9 @@ peek_for_as4_capability (struct peer *peer, u_char length)
if (hdr.code == CAPABILITY_CODE_AS4)
{
- if (hdr.length != CAPABILITY_CODE_AS4_LEN)
- goto end;
-
if (BGP_DEBUG (as4, AS4))
zlog_info ("[AS4] found AS4 capability, about to parse");
+
as4 = bgp_capability_as4 (peer, &hdr);
goto end;
diff --git a/configure.ac b/configure.ac
index 8d79e7d6..d87e682c 100755
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@
##
AC_PREREQ(2.53)
-AC_INIT(Quagga, 0.99.20ex21b, [http://bugzilla.quagga.net])
+AC_INIT(Quagga, 0.99.20ex22b, [http://bugzilla.quagga.net])
AC_CONFIG_SRCDIR(lib/zebra.h)
AC_CONFIG_MACRO_DIR([m4])
diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c
index e65b2e33..7e11e251 100644
--- a/ospfd/ospf_dump.c
+++ b/ospfd/ospf_dump.c
@@ -115,6 +115,16 @@ const struct message ospf_network_type_msg[] =
};
const int ospf_network_type_msg_max = OSPF_IFTYPE_MAX;
+/* AuType */
+const struct message ospf_auth_type_str[] =
+{
+ { OSPF_AUTH_NULL, "Null" },
+ { OSPF_AUTH_SIMPLE, "Simple" },
+ { OSPF_AUTH_CRYPTOGRAPHIC, "Cryptographic" },
+};
+const size_t ospf_auth_type_str_max = sizeof (ospf_auth_type_str) /
+ sizeof (ospf_auth_type_str[0]);
+
/* Configuration debug option variables. */
unsigned long conf_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
unsigned long conf_debug_ospf_event = 0;
@@ -657,18 +667,19 @@ static void
ospf_header_dump (struct ospf_header *ospfh)
{
char buf[9];
+ u_int16_t auth_type = ntohs (ospfh->auth_type);
zlog_debug ("Header");
zlog_debug (" Version %d", ospfh->version);
zlog_debug (" Type %d (%s)", ospfh->type,
- ospf_packet_type_str[ospfh->type]);
+ LOOKUP (ospf_packet_type_str, ospfh->type));
zlog_debug (" Packet Len %d", ntohs (ospfh->length));
zlog_debug (" Router ID %s", inet_ntoa (ospfh->router_id));
zlog_debug (" Area ID %s", inet_ntoa (ospfh->area_id));
zlog_debug (" Checksum 0x%x", ntohs (ospfh->checksum));
- zlog_debug (" AuType %d", ntohs (ospfh->auth_type));
+ zlog_debug (" AuType %s", LOOKUP (ospf_auth_type_str, auth_type));
- switch (ntohs (ospfh->auth_type))
+ switch (auth_type)
{
case OSPF_AUTH_NULL:
break;
@@ -1457,7 +1468,7 @@ DEFUN (show_debugging_ospf,
if (IS_DEBUG_OSPF_PACKET (i, SEND) && IS_DEBUG_OSPF_PACKET (i, RECV))
{
vty_out (vty, " OSPF packet %s%s debugging is on%s",
- ospf_packet_type_str[i + 1],
+ LOOKUP (ospf_packet_type_str, i + 1),
IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "",
VTY_NEWLINE);
}
@@ -1465,12 +1476,12 @@ DEFUN (show_debugging_ospf,
{
if (IS_DEBUG_OSPF_PACKET (i, SEND))
vty_out (vty, " OSPF packet %s send%s debugging is on%s",
- ospf_packet_type_str[i + 1],
+ LOOKUP (ospf_packet_type_str, i + 1),
IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "",
VTY_NEWLINE);
if (IS_DEBUG_OSPF_PACKET (i, RECV))
vty_out (vty, " OSPF packet %s receive%s debugging is on%s",
- ospf_packet_type_str[i + 1],
+ LOOKUP (ospf_packet_type_str, i + 1),
IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "",
VTY_NEWLINE);
}
diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h
index fb813719..a2d5e8ba 100644
--- a/ospfd/ospf_dump.h
+++ b/ospfd/ospf_dump.h
@@ -121,8 +121,9 @@ extern unsigned long term_debug_ospf_zebra;
extern unsigned long term_debug_ospf_nssa;
/* Message Strings. */
-extern const char *ospf_packet_type_str[];
extern char *ospf_lsa_type_str[];
+extern const struct message ospf_auth_type_str[];
+extern const size_t ospf_auth_type_str_max;
/* Prototypes. */
extern const char *ospf_area_name_string (struct ospf_area *);
diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h
index f364840f..297cd984 100644
--- a/ospfd/ospf_lsa.h
+++ b/ospfd/ospf_lsa.h
@@ -153,6 +153,7 @@ struct router_lsa_link
};
/* OSPF Router-LSAs structure. */
+#define OSPF_ROUTER_LSA_MIN_SIZE 16U /* w/1 link descriptor */
struct router_lsa
{
struct lsa_header header;
@@ -170,6 +171,7 @@ struct router_lsa
};
/* OSPF Network-LSAs structure. */
+#define OSPF_NETWORK_LSA_MIN_SIZE 8U /* w/1 router-ID */
struct network_lsa
{
struct lsa_header header;
@@ -178,6 +180,7 @@ struct network_lsa
};
/* OSPF Summary-LSAs structure. */
+#define OSPF_SUMMARY_LSA_MIN_SIZE 8U /* w/1 TOS metric block */
struct summary_lsa
{
struct lsa_header header;
@@ -187,6 +190,7 @@ struct summary_lsa
};
/* OSPF AS-external-LSAs structure. */
+#define OSPF_AS_EXTERNAL_LSA_MIN_SIZE 16U /* w/1 TOS forwarding block */
struct as_external_lsa
{
struct lsa_header header;
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index d3a60de0..88d516e3 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -50,16 +50,50 @@
#include "ospfd/ospf_dump.h"
/* Packet Type String. */
-const char *ospf_packet_type_str[] =
-{
- "unknown",
- "Hello",
- "Database Description",
- "Link State Request",
- "Link State Update",
- "Link State Acknowledgment",
+const struct message ospf_packet_type_str[] =
+{
+ { OSPF_MSG_HELLO, "Hello" },
+ { OSPF_MSG_DB_DESC, "Database Description" },
+ { OSPF_MSG_LS_REQ, "Link State Request" },
+ { OSPF_MSG_LS_UPD, "Link State Update" },
+ { OSPF_MSG_LS_ACK, "Link State Acknowledgment" },
+};
+const size_t ospf_packet_type_str_max = sizeof (ospf_packet_type_str) /
+ sizeof (ospf_packet_type_str[0]);
+
+/* Minimum (besides OSPF_HEADER_SIZE) lengths for OSPF packets of
+ particular types, offset is the "type" field of a packet. */
+static const u_int16_t ospf_packet_minlen[] =
+{
+ 0,
+ OSPF_HELLO_MIN_SIZE,
+ OSPF_DB_DESC_MIN_SIZE,
+ OSPF_LS_REQ_MIN_SIZE,
+ OSPF_LS_UPD_MIN_SIZE,
+ 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,
};
+/* for ospf_check_auth() */
+static int ospf_check_sum (struct ospf_header *);
+
/* OSPF authentication checking function */
static int
ospf_auth_type (struct ospf_interface *oi)
@@ -201,7 +235,7 @@ ospf_packet_add (struct ospf_interface *oi, struct ospf_packet *op)
"destination %s) called with NULL obuf, ignoring "
"(please report this bug)!\n",
IF_NAME(oi), oi->state, LOOKUP (ospf_ism_state_msg, oi->state),
- ospf_packet_type_str[stream_getc_from(op->s, 1)],
+ LOOKUP (ospf_packet_type_str, stream_getc_from(op->s, 1)),
inet_ntoa (op->dst));
return;
}
@@ -222,7 +256,7 @@ ospf_packet_add_top (struct ospf_interface *oi, struct ospf_packet *op)
"destination %s) called with NULL obuf, ignoring "
"(please report this bug)!\n",
IF_NAME(oi), oi->state, LOOKUP (ospf_ism_state_msg, oi->state),
- ospf_packet_type_str[stream_getc_from(op->s, 1)],
+ LOOKUP (ospf_packet_type_str, stream_getc_from(op->s, 1)),
inet_ntoa (op->dst));
return;
}
@@ -291,24 +325,14 @@ ospf_packet_max (struct ospf_interface *oi)
static int
-ospf_check_md5_digest (struct ospf_interface *oi, struct stream *s,
- u_int16_t length)
+ospf_check_md5_digest (struct ospf_interface *oi, struct ospf_header *ospfh)
{
- unsigned char *ibuf;
MD5_CTX ctx;
unsigned char digest[OSPF_AUTH_MD5_SIZE];
- unsigned char *pdigest;
struct crypt_key *ck;
- struct ospf_header *ospfh;
struct ospf_neighbor *nbr;
+ u_int16_t length = ntohs (ospfh->length);
-
- ibuf = STREAM_PNT (s);
- ospfh = (struct ospf_header *) ibuf;
-
- /* Get pointer to the end of the packet. */
- pdigest = ibuf + length;
-
/* Get secret key. */
ck = ospf_crypt_key_lookup (OSPF_IF_PARAM (oi, auth_crypt),
ospfh->u.crypt.key_id);
@@ -334,12 +358,12 @@ ospf_check_md5_digest (struct ospf_interface *oi, struct stream *s,
/* Generate a digest for the ospf packet - their digest + our digest. */
memset(&ctx, 0, sizeof(ctx));
MD5Init(&ctx);
- MD5Update(&ctx, ibuf, length);
+ MD5Update(&ctx, ospfh, length);
MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE);
MD5Final(digest, &ctx);
/* compare the two */
- if (memcmp (pdigest, digest, OSPF_AUTH_MD5_SIZE))
+ if (memcmp ((caddr_t)ospfh + length, digest, OSPF_AUTH_MD5_SIZE))
{
zlog_warn ("interface %s: ospf_check_md5 checksum mismatch",
IF_NAME (oi));
@@ -754,7 +778,7 @@ ospf_write (struct thread *thread)
}
zlog_debug ("%s sent to [%s] via [%s].",
- ospf_packet_type_str[type], inet_ntoa (op->dst),
+ LOOKUP (ospf_packet_type_str, type), inet_ntoa (op->dst),
IF_NAME (oi));
if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
@@ -800,7 +824,7 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
{
zlog_debug ("ospf_header[%s/%s]: selforiginated, "
"dropping.",
- ospf_packet_type_str[ospfh->type],
+ LOOKUP (ospf_packet_type_str, ospfh->type),
inet_ntoa (iph->ip_src));
}
return;
@@ -2245,45 +2269,91 @@ ospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src)
return 0;
}
+/* Return 1, if the packet is properly authenticated and checksummed,
+ 0 otherwise. In particular, check that AuType header field is valid and
+ matches the locally configured AuType, and that D.5 requirements are met. */
static int
-ospf_check_auth (struct ospf_interface *oi, struct stream *ibuf,
- struct ospf_header *ospfh)
+ospf_check_auth (struct ospf_interface *oi, struct ospf_header *ospfh)
{
- int ret = 0;
struct crypt_key *ck;
+ u_int16_t iface_auth_type;
+ u_int16_t pkt_auth_type = ntohs (ospfh->auth_type);
- switch (ntohs (ospfh->auth_type))
+ switch (pkt_auth_type)
+ {
+ case OSPF_AUTH_NULL: /* RFC2328 D.5.1 */
+ if (OSPF_AUTH_NULL != (iface_auth_type = ospf_auth_type (oi)))
{
- case OSPF_AUTH_NULL:
- ret = 1;
- break;
- case OSPF_AUTH_SIMPLE:
- if (!memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE))
- ret = 1;
- else
- ret = 0;
- break;
- case OSPF_AUTH_CRYPTOGRAPHIC:
- if ((ck = listgetdata (listtail(OSPF_IF_PARAM (oi,auth_crypt)))) == NULL)
- {
- ret = 0;
- break;
- }
-
- /* This is very basic, the digest processing is elsewhere */
- if (ospfh->u.crypt.auth_data_len == OSPF_AUTH_MD5_SIZE &&
- ospfh->u.crypt.key_id == ck->key_id &&
- ntohs (ospfh->length) + OSPF_AUTH_SIMPLE_SIZE <= stream_get_size (ibuf))
- ret = 1;
- else
- ret = 0;
- break;
- default:
- ret = 0;
- break;
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+ zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Null",
+ IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type));
+ return 0;
}
-
- return ret;
+ if (! ospf_check_sum (ospfh))
+ {
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+ zlog_warn ("interface %s: Null auth OK, but checksum error, Router-ID %s",
+ IF_NAME (oi), inet_ntoa (ospfh->router_id));
+ return 0;
+ }
+ return 1;
+ case OSPF_AUTH_SIMPLE: /* RFC2328 D.5.2 */
+ if (OSPF_AUTH_SIMPLE != (iface_auth_type = ospf_auth_type (oi)))
+ {
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+ zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Simple",
+ IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type));
+ return 0;
+ }
+ if (memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE))
+ {
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+ zlog_warn ("interface %s: Simple auth failed", IF_NAME (oi));
+ return 0;
+ }
+ if (! ospf_check_sum (ospfh))
+ {
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+ zlog_warn ("interface %s: Simple auth OK, checksum error, Router-ID %s",
+ IF_NAME (oi), inet_ntoa (ospfh->router_id));
+ return 0;
+ }
+ return 1;
+ case OSPF_AUTH_CRYPTOGRAPHIC: /* RFC2328 D.5.3 */
+ if (OSPF_AUTH_CRYPTOGRAPHIC != (iface_auth_type = ospf_auth_type (oi)))
+ {
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+ zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Cryptographic",
+ IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type));
+ return 0;
+ }
+ if (ospfh->checksum)
+ {
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+ zlog_warn ("interface %s: OSPF header checksum is not 0", IF_NAME (oi));
+ return 0;
+ }
+ /* only MD5 crypto method can pass ospf_packet_examin() */
+ if
+ (
+ NULL == (ck = listgetdata (listtail(OSPF_IF_PARAM (oi,auth_crypt)))) ||
+ ospfh->u.crypt.key_id != ck->key_id ||
+ /* Condition above uses the last key ID on the list, which is
+ different from what ospf_crypt_key_lookup() does. A bug? */
+ ! ospf_check_md5_digest (oi, ospfh)
+ )
+ {
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+ zlog_warn ("interface %s: MD5 auth failed", IF_NAME (oi));
+ return 0;
+ }
+ return 1;
+ default:
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+ zlog_warn ("interface %s: invalid packet auth-type (%02x)",
+ IF_NAME (oi), pkt_auth_type);
+ return 0;
+ }
}
static int
@@ -2312,26 +2382,311 @@ ospf_check_sum (struct ospf_header *ospfh)
return 1;
}
-/* OSPF Header verification. */
-static int
-ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi,
- struct ip *iph, struct ospf_header *ospfh)
+/* 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
+)
{
- /* check version. */
- if (ospfh->version != OSPF_VERSION)
+ unsigned counted_links = 0, thislinklen;
+
+ while (linkbytes)
+ {
+ thislinklen = OSPF_ROUTER_LSA_LINK_SIZE + 4 * link->m[0].tos_count;
+ if (thislinklen > linkbytes)
{
- zlog_warn ("interface %s: ospf_read version number mismatch.",
- IF_NAME (oi));
- return -1;
+ 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++;
+ }
- /* Valid OSPFv2 packet types are 1 through 5 inclusive. */
- if (ospfh->type < 1 || ospfh->type > 5)
+ if (declared_num_lsas && counted_lsas != declared_num_lsas)
{
- zlog_warn ("interface %s: invalid packet type %u", IF_NAME (oi), ospfh->type);
- return -1;
+ 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, bytesauth;
+ unsigned ret;
+ struct ospf_ls_update * lsupd;
+
+ /* Length, 1st approximation. */
+ if (bytesonwire < OSPF_HEADER_SIZE)
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: undersized (%u B) packet", __func__, bytesonwire);
+ return MSG_NG;
+ }
+ /* Now it is safe to access header fields. Performing length check, allow
+ * for possible extra bytes of crypto auth/padding, which are not counted
+ * in the OSPF header "length" field. */
+ if (oh->version != OSPF_VERSION)
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: invalid (%u) protocol version", __func__, oh->version);
+ return MSG_NG;
+ }
+ bytesdeclared = ntohs (oh->length);
+ if (ntohs (oh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
+ bytesauth = 0;
+ else
+ {
+ if (oh->u.crypt.auth_data_len != OSPF_AUTH_MD5_SIZE)
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: unsupported crypto auth length (%u B)",
+ __func__, oh->u.crypt.auth_data_len);
+ return MSG_NG;
+ }
+ bytesauth = OSPF_AUTH_MD5_SIZE;
+ }
+ if (bytesdeclared + bytesauth > bytesonwire)
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: packet length error (%u real, %u+%u declared)",
+ __func__, bytesonwire, bytesdeclared, bytesauth);
+ return MSG_NG;
}
+ /* Length, 2nd approximation. The type-specific constraint is checked
+ against declared length, not amount of bytes on wire. */
+ if
+ (
+ oh->type >= OSPF_MSG_HELLO &&
+ oh->type <= OSPF_MSG_LS_ACK &&
+ bytesdeclared < OSPF_HEADER_SIZE + ospf_packet_minlen[oh->type]
+ )
+ {
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ zlog_debug ("%s: undersized (%u B) %s packet", __func__,
+ bytesdeclared, LOOKUP (ospf_packet_type_str, oh->type));
+ return MSG_NG;
+ }
+ 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 = (bytesdeclared - 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),
+ bytesdeclared - 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 = (bytesdeclared - 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),
+ bytesdeclared - 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),
+ bytesdeclared - 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. */
+static int
+ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi,
+ struct ip *iph, struct ospf_header *ospfh)
+{
/* Check Area ID. */
if (!ospf_check_area_id (oi, ospfh))
{
@@ -2348,42 +2703,9 @@ ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi,
return -1;
}
- /* Check authentication. */
- if (ospf_auth_type (oi) != ntohs (ospfh->auth_type))
- {
- zlog_warn ("interface %s: auth-type mismatch, local %d, rcvd %d",
- IF_NAME (oi), ospf_auth_type (oi), ntohs (ospfh->auth_type));
- return -1;
- }
-
- if (! ospf_check_auth (oi, ibuf, ospfh))
- {
- zlog_warn ("interface %s: ospf_read authentication failed.",
- IF_NAME (oi));
- return -1;
- }
-
- /* if check sum is invalid, packet is discarded. */
- if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
- {
- if (! ospf_check_sum (ospfh))
- {
- zlog_warn ("interface %s: ospf_read packet checksum error %s",
- IF_NAME (oi), inet_ntoa (ospfh->router_id));
- return -1;
- }
- }
- else
- {
- if (ospfh->checksum != 0)
- return -1;
- if (ospf_check_md5_digest (oi, ibuf, ntohs (ospfh->length)) == 0)
- {
- zlog_warn ("interface %s: ospf_read md5 authentication failed.",
- IF_NAME (oi));
- return -1;
- }
- }
+ /* Check authentication. The function handles logging actions, where required. */
+ if (! ospf_check_auth (oi, ospfh))
+ return -1;
return 0;
}
@@ -2407,10 +2729,10 @@ ospf_read (struct thread *thread)
/* prepare for next packet. */
ospf->t_read = thread_add_read (master, ospf_read, ospf, ospf->fd);
- /* read OSPF packet. */
stream_reset(ospf->ibuf);
if (!(ibuf = ospf_recv_packet (ospf->fd, &ifp, ospf->ibuf)))
return -1;
+ /* This raw packet is known to be at least as big as its IP header. */
/* Note that there should not be alignment problems with this assignment
because this is at the beginning of the stream data buffer. */
@@ -2445,16 +2767,10 @@ ospf_read (struct thread *thread)
by ospf_recv_packet() to be correct). */
stream_forward_getp (ibuf, iph->ip_hl * 4);
- /* Make sure the OSPF header is really there. */
- if (stream_get_endp (ibuf) - stream_get_getp (ibuf) < OSPF_HEADER_SIZE)
- {
- zlog_debug ("ospf_read: ignored OSPF packet with undersized (%u bytes) header",
- stream_get_endp (ibuf) - stream_get_getp (ibuf));
+ ospfh = (struct ospf_header *) STREAM_PNT (ibuf);
+ if (MSG_OK != ospf_packet_examin (ospfh, stream_get_endp (ibuf) - stream_get_getp (ibuf)))
return -1;
- }
-
/* Now it is safe to access all fields of OSPF packet header. */
- ospfh = (struct ospf_header *) STREAM_PNT (ibuf);
/* associate packet with ospf interface */
oi = ospf_if_lookup_recv_if (ospf, iph->ip_src, ifp);
@@ -2575,7 +2891,7 @@ ospf_read (struct thread *thread)
}
zlog_debug ("%s received from [%s] via [%s]",
- ospf_packet_type_str[ospfh->type],
+ LOOKUP (ospf_packet_type_str, ospfh->type),
inet_ntoa (ospfh->router_id), IF_NAME (oi));
zlog_debug (" src [%s],", inet_ntoa (iph->ip_src));
zlog_debug (" dst [%s]", inet_ntoa (iph->ip_dst));
diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h
index 9a472081..337686ad 100644
--- a/ospfd/ospf_packet.h
+++ b/ospfd/ospf_packet.h
@@ -46,6 +46,10 @@
#define OSPF_HELLO_REPLY_DELAY 1
+/* Return values of functions involved in packet verification, see ospf6d. */
+#define MSG_OK 0
+#define MSG_NG 1
+
struct ospf_packet
{
struct ospf_packet *next;
@@ -117,6 +121,10 @@ struct ospf_db_desc
u_int32_t dd_seqnum;
};
+struct ospf_ls_update
+{
+ u_int32_t num_lsas;
+};
/* Macros. */
/* XXX Perhaps obsolete; function in ospf_packet.c */
@@ -163,4 +171,7 @@ extern int ospf_ls_ack_timer (struct thread *);
extern int ospf_poll_timer (struct thread *);
extern int ospf_hello_reply_timer (struct thread *);
+extern const struct message ospf_packet_type_str[];
+extern const size_t ospf_packet_type_str_max;
+
#endif /* _ZEBRA_OSPF_PACKET_H */