diff -urN quagga-0.99.15.orig//ospfd/ospf_dump.c quagga-0.99.15/ospfd/ospf_dump.c
--- quagga-0.99.15.orig//ospfd/ospf_dump.c	2009-07-29 00:35:45.000000000 +0800
+++ quagga-0.99.15/ospfd/ospf_dump.c	2012-03-21 15:48:11.000000000 +0800
@@ -115,6 +115,16 @@
 };
 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 @@
 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 @@
     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 @@
       {
 	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 -urN quagga-0.99.15.orig//ospfd/ospf_dump.h quagga-0.99.15/ospfd/ospf_dump.h
--- quagga-0.99.15.orig//ospfd/ospf_dump.h	2009-05-08 23:46:43.000000000 +0800
+++ quagga-0.99.15/ospfd/ospf_dump.h	2012-03-21 15:48:11.000000000 +0800
@@ -121,8 +121,9 @@
 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 -urN quagga-0.99.15.orig//ospfd/ospf_lsa.h quagga-0.99.15/ospfd/ospf_lsa.h
--- quagga-0.99.15.orig//ospfd/ospf_lsa.h	2009-08-28 19:29:10.000000000 +0800
+++ quagga-0.99.15/ospfd/ospf_lsa.h	2012-03-21 15:48:11.000000000 +0800
@@ -154,6 +154,7 @@
 };
 
 /* OSPF Router-LSAs structure. */
+#define OSPF_ROUTER_LSA_MIN_SIZE                  16U /* w/1 link descriptor */
 struct router_lsa
 {
   struct lsa_header header;
@@ -171,6 +172,7 @@
 };
 
 /* OSPF Network-LSAs structure. */
+#define OSPF_NETWORK_LSA_MIN_SIZE                  8U /* w/1 router-ID */
 struct network_lsa
 {
   struct lsa_header header;
@@ -179,6 +181,7 @@
 };
 
 /* OSPF Summary-LSAs structure. */
+#define OSPF_SUMMARY_LSA_MIN_SIZE                  8U /* w/1 TOS metric block */
 struct summary_lsa
 {
   struct lsa_header header;
@@ -188,6 +191,7 @@
 };
 
 /* 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 -urN quagga-0.99.15.orig//ospfd/ospf_packet.c quagga-0.99.15/ospfd/ospf_packet.c
--- quagga-0.99.15.orig//ospfd/ospf_packet.c	2012-03-21 15:46:48.000000000 +0800
+++ quagga-0.99.15/ospfd/ospf_packet.c	2012-03-21 15:48:11.000000000 +0800
@@ -50,15 +50,49 @@
 #include "ospfd/ospf_dump.h"
 
 /* Packet Type String. */
-const char *ospf_packet_type_str[] =
+const struct message ospf_packet_type_str[] =
 {
-  "unknown",
-  "Hello",
-  "Database Description",
-  "Link State Request",
-  "Link State Update",
-  "Link State Acknowledgment",
+  { 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
@@ -187,7 +221,7 @@
 	       "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;
     }
@@ -256,24 +290,14 @@
 
 
 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);
@@ -299,12 +323,12 @@
   /* 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));
@@ -713,7 +737,7 @@
 	}
 
       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))
@@ -759,7 +783,7 @@
         {
           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;
@@ -2177,45 +2201,91 @@
  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
@@ -2244,26 +2314,311 @@
   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;
+}
 
-  /* Valid OSPFv2 packet types are 1 through 5 inclusive. */
-  if (ospfh->type < 1 || ospfh->type > 5)
+/* 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]
+  )
   {
-    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: 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, 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))
     {
@@ -2280,42 +2635,9 @@
       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;
 }
@@ -2339,10 +2661,10 @@
   /* 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. */
@@ -2377,16 +2699,10 @@
      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);
@@ -2502,7 +2818,7 @@
         }
 
       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 -urN quagga-0.99.15.orig//ospfd/ospf_packet.h quagga-0.99.15/ospfd/ospf_packet.h
--- quagga-0.99.15.orig//ospfd/ospf_packet.h	2009-05-08 23:46:43.000000000 +0800
+++ quagga-0.99.15/ospfd/ospf_packet.h	2012-03-21 15:48:11.000000000 +0800
@@ -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 @@
   u_int32_t dd_seqnum;
 };
 
+struct ospf_ls_update
+{
+  u_int32_t num_lsas;
+};
 
 /* Macros. */
 /* XXX Perhaps obsolete; function in ospf_packet.c */
@@ -164,4 +172,7 @@
 extern int ospf_hello_reply_timer (struct thread *);
 extern void ospf_hello_send_sub (struct ospf_interface *, struct in_addr *);
 
+extern const struct message ospf_packet_type_str[];
+extern const size_t ospf_packet_type_str_max;
+
 #endif /* _ZEBRA_OSPF_PACKET_H */
