Diff for /embedaddon/quagga/ospfd/ospf_packet.c between versions 1.1 and 1.1.1.4

version 1.1, 2012/02/21 17:26:12 version 1.1.1.4, 2013/07/21 23:54:40
Line 50 Line 50
 #include "ospfd/ospf_dump.h"  #include "ospfd/ospf_dump.h"
   
 /* Packet Type String. */  /* Packet Type String. */
const char *ospf_packet_type_str[] =const struct message ospf_packet_type_str[] =
 {  {
  "unknown",  { OSPF_MSG_HELLO,   "Hello"                     },
  "Hello",  { OSPF_MSG_DB_DESC, "Database Description"      },
  "Database Description",  { OSPF_MSG_LS_REQ,  "Link State Request"        },
  "Link State Request",  { OSPF_MSG_LS_UPD,  "Link State Update"         },
  "Link State Update",  { OSPF_MSG_LS_ACK,  "Link State Acknowledgment" },
  "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 */  /* OSPF authentication checking function */
 static int  static int
 ospf_auth_type (struct ospf_interface *oi)  ospf_auth_type (struct ospf_interface *oi)
Line 201  ospf_packet_add (struct ospf_interface *oi, struct osp Line 235  ospf_packet_add (struct ospf_interface *oi, struct osp
                "destination %s) called with NULL obuf, ignoring "                 "destination %s) called with NULL obuf, ignoring "
                "(please report this bug)!\n",                 "(please report this bug)!\n",
                IF_NAME(oi), oi->state, LOOKUP (ospf_ism_state_msg, oi->state),                 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));                 inet_ntoa (op->dst));
       return;        return;
     }      }
Line 222  ospf_packet_add_top (struct ospf_interface *oi, struct Line 256  ospf_packet_add_top (struct ospf_interface *oi, struct
                "destination %s) called with NULL obuf, ignoring "                 "destination %s) called with NULL obuf, ignoring "
                "(please report this bug)!\n",                 "(please report this bug)!\n",
                IF_NAME(oi), oi->state, LOOKUP (ospf_ism_state_msg, oi->state),                 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));                 inet_ntoa (op->dst));
       return;        return;
     }      }
Line 266  ospf_packet_dup (struct ospf_packet *op) Line 300  ospf_packet_dup (struct ospf_packet *op)
 }  }
   
 /* XXX inline */  /* XXX inline */
static inline unsigned intstatic unsigned int
 ospf_packet_authspace (struct ospf_interface *oi)  ospf_packet_authspace (struct ospf_interface *oi)
 {  {
   int auth = 0;    int auth = 0;
Line 291  ospf_packet_max (struct ospf_interface *oi) Line 325  ospf_packet_max (struct ospf_interface *oi)
   
   
 static int  static int
ospf_check_md5_digest (struct ospf_interface *oi, struct stream *s,ospf_check_md5_digest (struct ospf_interface *oi, struct ospf_header *ospfh)
                       u_int16_t length) 
 {  {
   unsigned char *ibuf;  
   MD5_CTX ctx;    MD5_CTX ctx;
   unsigned char digest[OSPF_AUTH_MD5_SIZE];    unsigned char digest[OSPF_AUTH_MD5_SIZE];
   unsigned char *pdigest;  
   struct crypt_key *ck;    struct crypt_key *ck;
   struct ospf_header *ospfh;  
   struct ospf_neighbor *nbr;    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. */    /* Get secret key. */
   ck = ospf_crypt_key_lookup (OSPF_IF_PARAM (oi, auth_crypt),    ck = ospf_crypt_key_lookup (OSPF_IF_PARAM (oi, auth_crypt),
                               ospfh->u.crypt.key_id);                                ospfh->u.crypt.key_id);
Line 334  ospf_check_md5_digest (struct ospf_interface *oi, stru Line 358  ospf_check_md5_digest (struct ospf_interface *oi, stru
   /* Generate a digest for the ospf packet - their digest + our digest. */    /* Generate a digest for the ospf packet - their digest + our digest. */
   memset(&ctx, 0, sizeof(ctx));    memset(&ctx, 0, sizeof(ctx));
   MD5Init(&ctx);    MD5Init(&ctx);
  MD5Update(&ctx, ibuf, length);  MD5Update(&ctx, ospfh, length);
   MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE);    MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE);
   MD5Final(digest, &ctx);    MD5Final(digest, &ctx);
   
   /* compare the two */    /* 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",        zlog_warn ("interface %s: ospf_check_md5 checksum mismatch",
                  IF_NAME (oi));                   IF_NAME (oi));
Line 755  ospf_write (struct thread *thread) Line 779  ospf_write (struct thread *thread)
         }          }
   
       zlog_debug ("%s sent to [%s] via [%s].",        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_NAME (oi));
   
       if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))        if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
Line 801  ospf_hello (struct ip *iph, struct ospf_header *ospfh, Line 825  ospf_hello (struct ip *iph, struct ospf_header *ospfh,
         {          {
           zlog_debug ("ospf_header[%s/%s]: selforiginated, "            zlog_debug ("ospf_header[%s/%s]: selforiginated, "
                      "dropping.",                       "dropping.",
                     ospf_packet_type_str[ospfh->type],                     LOOKUP (ospf_packet_type_str, ospfh->type),
                      inet_ntoa (iph->ip_src));                       inet_ntoa (iph->ip_src));
         }          }
       return;        return;
Line 1566  ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struc Line 1590  ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struc
   
       /* Validate the LSA's LS checksum. */        /* Validate the LSA's LS checksum. */
       sum = lsah->checksum;        sum = lsah->checksum;
      if (sum != ospf_lsa_checksum (lsah))      if (! ospf_lsa_checksum_valid (lsah))
         {          {
          zlog_warn ("Link State Update: LSA checksum error %x, %x.",          /* (bug #685) more details in a one-line message make it possible
                     sum, lsah->checksum);           * to identify problem source on the one hand and to have a better
            * chance to compress repeated messages in syslog on the other */
           zlog_warn ("Link State Update: LSA checksum error %x/%x, ID=%s from: nbr %s, router ID %s, adv router %s",
                      sum, lsah->checksum, inet_ntoa (lsah->id),
                      inet_ntoa (nbr->src), inet_ntoa (nbr->router_id),
                      inet_ntoa (lsah->adv_router));
           continue;            continue;
         }          }
   
Line 1732  ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh Line 1761  ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
         ospf_lsa_discard (L); \          ospf_lsa_discard (L); \
         continue; }          continue; }
   
  /* Process each LSA received in the one packet. */  /* Process each LSA received in the one packet.
    *
    * Numbers in parentheses, e.g. (1), (2), etc., and the corresponding
    * text below are from the steps in RFC 2328, Section 13.
    */
   for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa))    for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa))
     {      {
       struct ospf_lsa *ls_ret, *current;        struct ospf_lsa *ls_ret, *current;
Line 1756  ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh Line 1789  ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
   
       listnode_delete (lsas, lsa); /* We don't need it in list anymore */        listnode_delete (lsas, lsa); /* We don't need it in list anymore */
   
      /* Validate Checksum - Done above by ospf_ls_upd_list_lsa() */      /* (1) Validate Checksum - Done above by ospf_ls_upd_list_lsa() */
   
      /* LSA Type  - Done above by ospf_ls_upd_list_lsa() */      /* (2) LSA Type  - Done above by ospf_ls_upd_list_lsa() */
         
      /* Do not take in AS External LSAs if we are a stub or NSSA. */      /* (3) Do not take in AS External LSAs if we are a stub or NSSA. */
   
       /* Do not take in AS NSSA if this neighbor and we are not NSSA */        /* Do not take in AS NSSA if this neighbor and we are not NSSA */
   
Line 1792  ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh Line 1825  ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
   
       current = ospf_lsa_lookup_by_header (oi->area, lsa->data);        current = ospf_lsa_lookup_by_header (oi->area, lsa->data);
   
      /* If the LSA's LS age is equal to MaxAge, and there is currently      /* (4) If the LSA's LS age is equal to MaxAge, and there is currently
          no instance of the LSA in the router's link state database,           no instance of the LSA in the router's link state database,
          and none of router's neighbors are in states Exchange or Loading,           and none of router's neighbors are in states Exchange or Loading,
         then take the following actions. */         then take the following actions: */
   
       if (IS_LSA_MAXAGE (lsa) && !current &&        if (IS_LSA_MAXAGE (lsa) && !current &&
           (ospf_nbr_count (oi, NSM_Exchange) +            (ospf_nbr_count (oi, NSM_Exchange) +
            ospf_nbr_count (oi, NSM_Loading)) == 0)             ospf_nbr_count (oi, NSM_Loading)) == 0)
         {          {
          /* Response Link State Acknowledgment. */          /* (4a) Response Link State Acknowledgment. */
           ospf_ls_ack_send (nbr, lsa);            ospf_ls_ack_send (nbr, lsa);
   
          /* Discard LSA. */                    /* (4b) Discard LSA. */
          zlog_info ("Link State Update[%s]: LS age is equal to MaxAge.",          if (IS_DEBUG_OSPF (lsa, LSA))
                     dump_lsa_key(lsa));            {
                zlog_debug ("Link State Update[%s]: LS age is equal to MaxAge.",
                            dump_lsa_key(lsa));
             }
           DISCARD_LSA (lsa, 3);            DISCARD_LSA (lsa, 3);
         }          }
   
Line 1861  ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh Line 1897  ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
 #endif /* HAVE_OPAQUE_LSA */  #endif /* HAVE_OPAQUE_LSA */
   
       /* It might be happen that received LSA is self-originated network LSA, but        /* It might be happen that received LSA is self-originated network LSA, but
       * router ID is cahnged. So, we should check if LSA is a network-LSA whose       * router ID is changed. So, we should check if LSA is a network-LSA whose
        * Link State ID is one of the router's own IP interface addresses but whose         * Link State ID is one of the router's own IP interface addresses but whose
        * Advertising Router is not equal to the router's own Router ID         * Advertising Router is not equal to the router's own Router ID
        * According to RFC 2328 12.4.2 and 13.4 this LSA should be flushed.         * According to RFC 2328 12.4.2 and 13.4 this LSA should be flushed.
Line 1900  ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh Line 1936  ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
       /* (5) Find the instance of this LSA that is currently contained        /* (5) Find the instance of this LSA that is currently contained
          in the router's link state database.  If there is no           in the router's link state database.  If there is no
          database copy, or the received LSA is more recent than           database copy, or the received LSA is more recent than
         the database copy the following steps must be performed. */         the database copy the following steps must be performed.
          (The sub steps from RFC 2328 section 13 step (5) will be performed in
          ospf_flood() ) */
   
       if (current == NULL ||        if (current == NULL ||
           (ret = ospf_lsa_more_recent (current, lsa)) < 0)            (ret = ospf_lsa_more_recent (current, lsa)) < 0)
Line 2116  ospf_recv_packet (int fd, struct interface **ifp, stru Line 2154  ospf_recv_packet (int fd, struct interface **ifp, stru
       
   ip_len = iph->ip_len;    ip_len = iph->ip_len;
       
#if !defined(GNU_LINUX) && (OpenBSD < 200311)#if !defined(GNU_LINUX) && (OpenBSD < 200311) && (__FreeBSD_version < 1000000)
   /*    /*
    * Kernel network code touches incoming IP header parameters,     * Kernel network code touches incoming IP header parameters,
    * before protocol specific processing.     * before protocol specific processing.
Line 2208  ospf_associate_packet_vl (struct ospf *ospf, struct in Line 2246  ospf_associate_packet_vl (struct ospf *ospf, struct in
   return NULL;    return NULL;
 }  }
   
static inline intstatic int
 ospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh)  ospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh)
 {  {
   /* Check match the Area ID of the receiving interface. */    /* Check match the Area ID of the receiving interface. */
Line 2241  ospf_check_network_mask (struct ospf_interface *oi, st Line 2279  ospf_check_network_mask (struct ospf_interface *oi, st
  return 0;   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  static int
ospf_check_auth (struct ospf_interface *oi, struct stream *ibuf,ospf_check_auth (struct ospf_interface *oi, struct ospf_header *ospfh)
                 struct ospf_header *ospfh) 
 {  {
   int ret = 0;  
   struct crypt_key *ck;    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:      if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
      ret = 1;        zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Null",
      break;                   IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type));
    case OSPF_AUTH_SIMPLE:      return 0;
      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 (! ospf_check_sum (ospfh))
  return ret;    {
       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  static int
Line 2308  ospf_check_sum (struct ospf_header *ospfh) Line 2392  ospf_check_sum (struct ospf_header *ospfh)
   return 1;    return 1;
 }  }
   
/* OSPF Header verification. *//* Verify, that given link/TOS records are properly sized/aligned and match
static int   Router-LSA "# links" and "# TOS" fields as specified in RFC2328 A.4.2. */
ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi,static unsigned
                    struct ip *iph, struct ospf_header *ospfh)ospf_router_lsa_links_examin
 (
   struct router_lsa_link * link,
   u_int16_t linkbytes,
   const u_int16_t num_links
 )
 {  {
  /* check version. */  unsigned counted_links = 0, thislinklen;
  if (ospfh->version != OSPF_VERSION)
   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 (IS_DEBUG_OSPF_PACKET (0, RECV))
                 IF_NAME (oi));        zlog_debug ("%s: length error in link block #%u", __func__, counted_links);
      return -1;      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. *//* Verify, that the given LSA is properly sized/aligned (including type-specific
  if (ospfh->type < 1 || ospfh->type > 5)   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);    if (IS_DEBUG_OSPF_PACKET (0, RECV))
    return -1;      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. */    /* Check Area ID. */
   if (!ospf_check_area_id (oi, ospfh))    if (!ospf_check_area_id (oi, ospfh))
     {      {
Line 2344  ospf_verify_header (struct stream *ibuf, struct ospf_i Line 2713  ospf_verify_header (struct stream *ibuf, struct ospf_i
       return -1;        return -1;
     }      }
   
  /* Check authentication. */  /* Check authentication. The function handles logging actions, where required. */
  if (ospf_auth_type (oi) != ntohs (ospfh->auth_type))  if (! ospf_check_auth (oi, ospfh))
    {    return -1;
      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;  
         }  
     }  
   
   return 0;    return 0;
 }  }
   
Line 2403  ospf_read (struct thread *thread) Line 2739  ospf_read (struct thread *thread)
   /* prepare for next packet. */    /* prepare for next packet. */
   ospf->t_read = thread_add_read (master, ospf_read, ospf, ospf->fd);    ospf->t_read = thread_add_read (master, ospf_read, ospf, ospf->fd);
   
   /* read OSPF packet. */  
   stream_reset(ospf->ibuf);    stream_reset(ospf->ibuf);
   if (!(ibuf = ospf_recv_packet (ospf->fd, &ifp, ospf->ibuf)))    if (!(ibuf = ospf_recv_packet (ospf->fd, &ifp, ospf->ibuf)))
     return -1;      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    /* Note that there should not be alignment problems with this assignment
      because this is at the beginning of the stream data buffer. */       because this is at the beginning of the stream data buffer. */
Line 2441  ospf_read (struct thread *thread) Line 2777  ospf_read (struct thread *thread)
      by ospf_recv_packet() to be correct). */       by ospf_recv_packet() to be correct). */
   stream_forward_getp (ibuf, iph->ip_hl * 4);    stream_forward_getp (ibuf, iph->ip_hl * 4);
   
  /* Make sure the OSPF header is really there. */  ospfh = (struct ospf_header *) STREAM_PNT (ibuf);
  if (stream_get_endp (ibuf) - stream_get_getp (ibuf) < OSPF_HEADER_SIZE)  if (MSG_OK != ospf_packet_examin (ospfh, stream_get_endp (ibuf) - stream_get_getp (ibuf)))
  { 
    zlog_debug ("ospf_read: ignored OSPF packet with undersized (%u bytes) header", 
                stream_get_endp (ibuf) - stream_get_getp (ibuf)); 
     return -1;      return -1;
   }  
   
   /* Now it is safe to access all fields of OSPF packet header. */    /* Now it is safe to access all fields of OSPF packet header. */
   ospfh = (struct ospf_header *) STREAM_PNT (ibuf);  
   
   /* associate packet with ospf interface */    /* associate packet with ospf interface */
   oi = ospf_if_lookup_recv_if (ospf, iph->ip_src, ifp);    oi = ospf_if_lookup_recv_if (ospf, iph->ip_src, ifp);
Line 2571  ospf_read (struct thread *thread) Line 2901  ospf_read (struct thread *thread)
         }          }
   
       zlog_debug ("%s received from [%s] via [%s]",        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));                   inet_ntoa (ospfh->router_id), IF_NAME (oi));
       zlog_debug (" src [%s],", inet_ntoa (iph->ip_src));        zlog_debug (" src [%s],", inet_ntoa (iph->ip_src));
       zlog_debug (" dst [%s]", inet_ntoa (iph->ip_dst));        zlog_debug (" dst [%s]", inet_ntoa (iph->ip_dst));

Removed from v.1.1  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>