version 1.1, 2012/02/21 17:26:12
|
version 1.1.1.5, 2016/11/02 10:09:12
|
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 int | static unsigned int |
ospf_packet_authspace (struct ospf_interface *oi) |
ospf_packet_authspace (struct ospf_interface *oi) |
{ |
{ |
int auth = 0; |
int auth = 0; |
Line 289 ospf_packet_max (struct ospf_interface *oi)
|
Line 323 ospf_packet_max (struct ospf_interface *oi)
|
return max; |
return max; |
} |
} |
|
|
| |
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 359 static int
|
Line 383 static int
|
ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op) |
ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op) |
{ |
{ |
struct ospf_header *ospfh; |
struct ospf_header *ospfh; |
unsigned char digest[OSPF_AUTH_MD5_SIZE]; | unsigned char digest[OSPF_AUTH_MD5_SIZE] = {0}; |
MD5_CTX ctx; |
MD5_CTX ctx; |
void *ibuf; |
void *ibuf; |
u_int32_t t; |
u_int32_t t; |
Line 386 ospf_make_md5_digest (struct ospf_interface *oi, struc
|
Line 410 ospf_make_md5_digest (struct ospf_interface *oi, struc
|
|
|
/* Get MD5 Authentication key from auth_key list. */ |
/* Get MD5 Authentication key from auth_key list. */ |
if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt))) |
if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt))) |
auth_key = (const u_int8_t *) ""; | auth_key = (const u_int8_t *) digest; |
else |
else |
{ |
{ |
ck = listgetdata (listtail(OSPF_IF_PARAM (oi, auth_crypt))); |
ck = listgetdata (listtail(OSPF_IF_PARAM (oi, auth_crypt))); |
Line 414 ospf_make_md5_digest (struct ospf_interface *oi, struc
|
Line 438 ospf_make_md5_digest (struct ospf_interface *oi, struc
|
return OSPF_AUTH_MD5_SIZE; |
return OSPF_AUTH_MD5_SIZE; |
} |
} |
|
|
| |
static int |
static int |
ospf_ls_req_timer (struct thread *thread) |
ospf_ls_req_timer (struct thread *thread) |
{ |
{ |
Line 620 ospf_write (struct thread *thread)
|
Line 644 ospf_write (struct thread *thread)
|
struct listnode *node; |
struct listnode *node; |
#ifdef WANT_OSPF_WRITE_FRAGMENT |
#ifdef WANT_OSPF_WRITE_FRAGMENT |
static u_int16_t ipid = 0; |
static u_int16_t ipid = 0; |
#endif /* WANT_OSPF_WRITE_FRAGMENT */ |
|
u_int16_t maxdatasize; |
u_int16_t maxdatasize; |
|
#endif /* WANT_OSPF_WRITE_FRAGMENT */ |
#define OSPF_WRITE_IPHL_SHIFT 2 |
#define OSPF_WRITE_IPHL_SHIFT 2 |
|
|
ospf->t_write = NULL; |
ospf->t_write = NULL; |
Line 635 ospf_write (struct thread *thread)
|
Line 659 ospf_write (struct thread *thread)
|
/* seed ipid static with low order bits of time */ |
/* seed ipid static with low order bits of time */ |
if (ipid == 0) |
if (ipid == 0) |
ipid = (time(NULL) & 0xffff); |
ipid = (time(NULL) & 0xffff); |
#endif /* WANT_OSPF_WRITE_FRAGMENT */ |
|
|
|
/* convenience - max OSPF data per packet, |
/* convenience - max OSPF data per packet, |
* and reliability - not more data, than our |
* and reliability - not more data, than our |
Line 643 ospf_write (struct thread *thread)
|
Line 666 ospf_write (struct thread *thread)
|
*/ |
*/ |
maxdatasize = MIN (oi->ifp->mtu, ospf->maxsndbuflen) - |
maxdatasize = MIN (oi->ifp->mtu, ospf->maxsndbuflen) - |
sizeof (struct ip); |
sizeof (struct ip); |
|
#endif /* WANT_OSPF_WRITE_FRAGMENT */ |
|
|
/* Get one packet from queue. */ |
/* Get one packet from queue. */ |
op = ospf_fifo_head (oi->obuf); |
op = ospf_fifo_head (oi->obuf); |
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 765 ospf_write (struct thread *thread)
|
Line 789 ospf_write (struct thread *thread)
|
/* Now delete packet from queue. */ |
/* Now delete packet from queue. */ |
ospf_packet_delete (oi); |
ospf_packet_delete (oi); |
|
|
|
/* Move this interface to the tail of write_q to |
|
serve everyone in a round robin fashion */ |
|
listnode_move_to_tail (ospf->oi_write_q, node); |
if (ospf_fifo_head (oi->obuf) == NULL) |
if (ospf_fifo_head (oi->obuf) == NULL) |
{ |
{ |
oi->on_write_q = 0; |
oi->on_write_q = 0; |
Line 801 ospf_hello (struct ip *iph, struct ospf_header *ospfh,
|
Line 828 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 867 ospf_hello (struct ip *iph, struct ospf_header *ospfh,
|
Line 894 ospf_hello (struct ip *iph, struct ospf_header *ospfh,
|
} |
} |
#endif /* REJECT_IF_TBIT_ON */ |
#endif /* REJECT_IF_TBIT_ON */ |
|
|
#ifdef HAVE_OPAQUE_LSA |
|
if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE) |
if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE) |
&& CHECK_FLAG (hello->options, OSPF_OPTION_O)) |
&& CHECK_FLAG (hello->options, OSPF_OPTION_O)) |
{ |
{ |
Line 883 ospf_hello (struct ip *iph, struct ospf_header *ospfh,
|
Line 909 ospf_hello (struct ip *iph, struct ospf_header *ospfh,
|
UNSET_FLAG (hello->options, OSPF_OPTION_O); /* Ignore O-bit. */ |
UNSET_FLAG (hello->options, OSPF_OPTION_O); /* Ignore O-bit. */ |
#endif /* STRICT_OBIT_USAGE_CHECK */ |
#endif /* STRICT_OBIT_USAGE_CHECK */ |
} |
} |
#endif /* HAVE_OPAQUE_LSA */ |
|
|
|
/* new for NSSA is to ensure that NP is on and E is off */ |
/* new for NSSA is to ensure that NP is on and E is off */ |
|
|
Line 1035 ospf_db_desc_proc (struct stream *s, struct ospf_inter
|
Line 1060 ospf_db_desc_proc (struct stream *s, struct ospf_inter
|
return; |
return; |
} |
} |
|
|
#ifdef HAVE_OPAQUE_LSA |
|
if (IS_OPAQUE_LSA (lsah->type) |
if (IS_OPAQUE_LSA (lsah->type) |
&& ! CHECK_FLAG (nbr->options, OSPF_OPTION_O)) |
&& ! CHECK_FLAG (nbr->options, OSPF_OPTION_O)) |
{ |
{ |
Line 1043 ospf_db_desc_proc (struct stream *s, struct ospf_inter
|
Line 1067 ospf_db_desc_proc (struct stream *s, struct ospf_inter
|
OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); |
OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); |
return; |
return; |
} |
} |
#endif /* HAVE_OPAQUE_LSA */ |
|
|
|
switch (lsah->type) |
switch (lsah->type) |
{ |
{ |
case OSPF_AS_EXTERNAL_LSA: |
case OSPF_AS_EXTERNAL_LSA: |
#ifdef HAVE_OPAQUE_LSA |
|
case OSPF_OPAQUE_AS_LSA: |
case OSPF_OPAQUE_AS_LSA: |
#endif /* HAVE_OPAQUE_LSA */ |
|
/* Check for stub area. Reject if AS-External from stub but |
/* Check for stub area. Reject if AS-External from stub but |
allow if from NSSA. */ |
allow if from NSSA. */ |
if (oi->area->external_routing == OSPF_AREA_STUB) |
if (oi->area->external_routing == OSPF_AREA_STUB) |
Line 1221 ospf_db_desc (struct ip *iph, struct ospf_header *ospf
|
Line 1242 ospf_db_desc (struct ip *iph, struct ospf_header *ospf
|
} |
} |
#endif /* REJECT_IF_TBIT_ON */ |
#endif /* REJECT_IF_TBIT_ON */ |
|
|
#ifdef HAVE_OPAQUE_LSA |
|
if (CHECK_FLAG (dd->options, OSPF_OPTION_O) |
if (CHECK_FLAG (dd->options, OSPF_OPTION_O) |
&& !CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) |
&& !CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) |
{ |
{ |
Line 1231 ospf_db_desc (struct ip *iph, struct ospf_header *ospf
|
Line 1251 ospf_db_desc (struct ip *iph, struct ospf_header *ospf
|
*/ |
*/ |
UNSET_FLAG (dd->options, OSPF_OPTION_O); |
UNSET_FLAG (dd->options, OSPF_OPTION_O); |
} |
} |
#endif /* HAVE_OPAQUE_LSA */ |
|
|
|
/* Add event to thread. */ |
/* Add event to thread. */ |
OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); |
OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); |
Line 1296 ospf_db_desc (struct ip *iph, struct ospf_header *ospf
|
Line 1315 ospf_db_desc (struct ip *iph, struct ospf_header *ospf
|
/* This is where the real Options are saved */ |
/* This is where the real Options are saved */ |
nbr->options = dd->options; |
nbr->options = dd->options; |
|
|
#ifdef HAVE_OPAQUE_LSA |
|
if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) |
if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) |
{ |
{ |
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
Line 1314 ospf_db_desc (struct ip *iph, struct ospf_header *ospf
|
Line 1332 ospf_db_desc (struct ip *iph, struct ospf_header *ospf
|
/* This situation is undesirable, but not a real error. */ |
/* This situation is undesirable, but not a real error. */ |
} |
} |
} |
} |
#endif /* HAVE_OPAQUE_LSA */ |
|
|
|
OSPF_NSM_EVENT_EXECUTE (nbr, NSM_NegotiationDone); |
OSPF_NSM_EVENT_EXECUTE (nbr, NSM_NegotiationDone); |
|
|
Line 1566 ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struc
|
Line 1583 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 1587 ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struc
|
Line 1609 ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struc
|
if (ntohs (lsah->ls_age) > OSPF_LSA_MAXAGE) |
if (ntohs (lsah->ls_age) > OSPF_LSA_MAXAGE) |
lsah->ls_age = htons (OSPF_LSA_MAXAGE); |
lsah->ls_age = htons (OSPF_LSA_MAXAGE); |
|
|
#ifdef HAVE_OPAQUE_LSA |
|
if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) |
if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) |
{ |
{ |
#ifdef STRICT_OBIT_USAGE_CHECK |
#ifdef STRICT_OBIT_USAGE_CHECK |
Line 1619 ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struc
|
Line 1640 ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struc
|
zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id)); |
zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id)); |
continue; |
continue; |
} |
} |
#endif /* HAVE_OPAQUE_LSA */ |
|
|
|
/* Create OSPF LSA instance. */ |
/* Create OSPF LSA instance. */ |
lsa = ospf_lsa_new (); |
lsa = ospf_lsa_new (); |
Line 1629 ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struc
|
Line 1649 ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struc
|
switch (lsah->type) |
switch (lsah->type) |
{ |
{ |
case OSPF_AS_EXTERNAL_LSA: |
case OSPF_AS_EXTERNAL_LSA: |
#ifdef HAVE_OPAQUE_LSA |
|
case OSPF_OPAQUE_AS_LSA: |
case OSPF_OPAQUE_AS_LSA: |
lsa->area = NULL; |
lsa->area = NULL; |
break; |
break; |
case OSPF_OPAQUE_LINK_LSA: |
case OSPF_OPAQUE_LINK_LSA: |
lsa->oi = oi; /* Remember incoming interface for flooding control. */ |
lsa->oi = oi; /* Remember incoming interface for flooding control. */ |
/* Fallthrough */ |
/* Fallthrough */ |
#endif /* HAVE_OPAQUE_LSA */ |
|
default: |
default: |
lsa->area = oi->area; |
lsa->area = oi->area; |
break; |
break; |
Line 1647 ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struc
|
Line 1665 ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struc
|
|
|
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug("LSA[Type%d:%s]: %p new LSA created with Link State Update", |
zlog_debug("LSA[Type%d:%s]: %p new LSA created with Link State Update", |
lsa->data->type, inet_ntoa (lsa->data->id), lsa); | lsa->data->type, inet_ntoa (lsa->data->id), (void *)lsa); |
listnode_add (lsas, lsa); |
listnode_add (lsas, lsa); |
} |
} |
|
|
Line 1669 ospf_upd_list_clean (struct list *lsas)
|
Line 1687 ospf_upd_list_clean (struct list *lsas)
|
|
|
/* OSPF Link State Update message read -- RFC2328 Section 13. */ |
/* OSPF Link State Update message read -- RFC2328 Section 13. */ |
static void |
static void |
ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, | ospf_ls_upd (struct ospf *ospf, struct ip *iph, struct ospf_header *ospfh, |
struct stream *s, struct ospf_interface *oi, u_int16_t size) |
struct stream *s, struct ospf_interface *oi, u_int16_t size) |
{ |
{ |
struct ospf_neighbor *nbr; |
struct ospf_neighbor *nbr; |
Line 1711 ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
|
Line 1729 ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
|
*/ |
*/ |
lsas = ospf_ls_upd_list_lsa (nbr, s, oi, size); |
lsas = ospf_ls_upd_list_lsa (nbr, s, oi, size); |
|
|
#ifdef HAVE_OPAQUE_LSA |
|
/* |
|
* If self-originated Opaque-LSAs that have flooded before restart |
|
* are contained in the received LSUpd message, corresponding LSReq |
|
* messages to be sent may have to be modified. |
|
* To eliminate possible race conditions such that flushing and normal |
|
* updating for the same LSA would take place alternately, this trick |
|
* must be done before entering to the loop below. |
|
*/ |
|
/* XXX: Why is this Opaque specific? Either our core code is deficient |
|
* and this should be fixed generally, or Opaque is inventing strawman |
|
* problems */ |
|
ospf_opaque_adjust_lsreq (nbr, lsas); |
|
#endif /* HAVE_OPAQUE_LSA */ |
|
|
|
#define DISCARD_LSA(L,N) {\ |
#define DISCARD_LSA(L,N) {\ |
if (IS_DEBUG_OSPF_EVENT) \ |
if (IS_DEBUG_OSPF_EVENT) \ |
zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p Type-%d", N, lsa, (int) lsa->data->type); \ | zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p" \ |
| " Type-%d", N, (void *)lsa, (int) lsa->data->type); \ |
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 1764 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 1788 ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
|
Line 1796 ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
|
DISCARD_LSA (lsa,2); |
DISCARD_LSA (lsa,2); |
} |
} |
|
|
|
/* VU229804: Router-LSA Adv-ID must be equal to LS-ID */ |
|
if (lsa->data->type == OSPF_ROUTER_LSA) |
|
if (!IPV4_ADDR_SAME(&lsa->data->id, &lsa->data->adv_router)) |
|
{ |
|
char buf1[INET_ADDRSTRLEN]; |
|
char buf2[INET_ADDRSTRLEN]; |
|
char buf3[INET_ADDRSTRLEN]; |
|
|
|
zlog_err("Incoming Router-LSA from %s with " |
|
"Adv-ID[%s] != LS-ID[%s]", |
|
inet_ntop (AF_INET, &ospfh->router_id, |
|
buf1, INET_ADDRSTRLEN), |
|
inet_ntop (AF_INET, &lsa->data->id, |
|
buf2, INET_ADDRSTRLEN), |
|
inet_ntop (AF_INET, &lsa->data->adv_router, |
|
buf3, INET_ADDRSTRLEN)); |
|
zlog_err("OSPF domain compromised by attack or corruption. " |
|
"Verify correct operation of -ALL- OSPF routers."); |
|
DISCARD_LSA (lsa, 0); |
|
} |
|
|
/* Find the LSA in the current database. */ |
/* Find the LSA in the current database. */ |
|
|
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_check_nbr_status(oi->ospf)) |
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); |
} |
} |
|
|
#ifdef HAVE_OPAQUE_LSA |
|
if (IS_OPAQUE_LSA (lsa->data->type) |
if (IS_OPAQUE_LSA (lsa->data->type) |
&& IPV4_ADDR_SAME (&lsa->data->adv_router, &oi->ospf->router_id)) |
&& IPV4_ADDR_SAME (&lsa->data->adv_router, &oi->ospf->router_id)) |
{ |
{ |
Line 1858 ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
|
Line 1888 ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
|
continue; |
continue; |
} |
} |
} |
} |
#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 1886 ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
|
Line 1915 ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
|
ospf_lsa_flush_area(lsa,out_if->area); |
ospf_lsa_flush_area(lsa,out_if->area); |
if(IS_DEBUG_OSPF_EVENT) |
if(IS_DEBUG_OSPF_EVENT) |
zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point 9: lsa %p Type-%d", |
zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point 9: lsa %p Type-%d", |
lsa, (int) lsa->data->type); | (void *)lsa, (int) lsa->data->type); |
ospf_lsa_discard (lsa); |
ospf_lsa_discard (lsa); |
Flag = 1; |
Flag = 1; |
} |
} |
Line 1900 ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
|
Line 1929 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 1997 ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
|
Line 2028 ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); |
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); |
|
|
if (tv_cmp (tv_sub (now, current->tv_orig), |
if (tv_cmp (tv_sub (now, current->tv_orig), |
int2tv (OSPF_MIN_LS_ARRIVAL)) >= 0) | msec2tv (ospf->min_ls_arrival)) >= 0) |
/* Trap NSSA type later.*/ |
/* Trap NSSA type later.*/ |
ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT); |
ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT); |
DISCARD_LSA (lsa, 8); |
DISCARD_LSA (lsa, 8); |
Line 2060 ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh
|
Line 2091 ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh
|
|
|
lsr = ospf_ls_retransmit_lookup (nbr, lsa); |
lsr = ospf_ls_retransmit_lookup (nbr, lsa); |
|
|
if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum) | if (lsr != NULL && ospf_lsa_more_recent (lsr, lsa) == 0) |
{ | ospf_ls_retransmit_delete (nbr, lsr); |
#ifdef HAVE_OPAQUE_LSA | |
if (IS_OPAQUE_LSA (lsr->data->type)) | |
ospf_opaque_ls_ack_received (nbr, lsr); | |
#endif /* HAVE_OPAQUE_LSA */ | |
|
|
ospf_ls_retransmit_delete (nbr, lsr); |
|
} |
|
|
|
lsa->data = NULL; |
lsa->data = NULL; |
ospf_lsa_discard (lsa); |
ospf_lsa_discard (lsa); |
} |
} |
|
|
return; |
return; |
} |
} |
| |
static struct stream * |
static struct stream * |
ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf) |
ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf) |
{ |
{ |
int ret; |
int ret; |
struct ip *iph; |
struct ip *iph; |
u_int16_t ip_len; |
u_int16_t ip_len; |
unsigned int ifindex = 0; | ifindex_t ifindex = 0; |
struct iovec iov; |
struct iovec iov; |
/* Header and data both require alignment. */ |
/* Header and data both require alignment. */ |
char buff [CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())]; |
char buff [CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())]; |
Line 2116 ospf_recv_packet (int fd, struct interface **ifp, stru
|
Line 2140 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 2232 ospf_associate_packet_vl (struct ospf *ospf, struct in
|
return NULL; |
return NULL; |
} |
} |
|
|
static inline int | static 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 2265 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 2378 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 */ |
|
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. */ |
|
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 2697 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 2723 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 2761 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 2885 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)); |
Line 2598 ospf_read (struct thread *thread)
|
Line 2912 ospf_read (struct thread *thread)
|
ospf_ls_req (iph, ospfh, ibuf, oi, length); |
ospf_ls_req (iph, ospfh, ibuf, oi, length); |
break; |
break; |
case OSPF_MSG_LS_UPD: |
case OSPF_MSG_LS_UPD: |
ospf_ls_upd (iph, ospfh, ibuf, oi, length); | ospf_ls_upd (ospf, iph, ospfh, ibuf, oi, length); |
break; |
break; |
case OSPF_MSG_LS_ACK: |
case OSPF_MSG_LS_ACK: |
ospf_ls_ack (iph, ospfh, ibuf, oi, length); |
ospf_ls_ack (iph, ospfh, ibuf, oi, length); |
Line 2786 ospf_make_db_desc (struct ospf_interface *oi, struct o
|
Line 3100 ospf_make_db_desc (struct ospf_interface *oi, struct o
|
|
|
/* Set Options. */ |
/* Set Options. */ |
options = OPTIONS (oi); |
options = OPTIONS (oi); |
#ifdef HAVE_OPAQUE_LSA |
|
if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) |
if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) |
{ | SET_FLAG (options, OSPF_OPTION_O); |
if (IS_SET_DD_I (nbr->dd_flags) | |
|| CHECK_FLAG (nbr->options, OSPF_OPTION_O)) | |
/* | |
* Set O-bit in the outgoing DD packet for capablity negotiation, | |
* if one of following case is applicable. | |
* | |
* 1) WaitTimer expiration event triggered the neighbor state to | |
* change to Exstart, but no (valid) DD packet has received | |
* from the neighbor yet. | |
* | |
* 2) At least one DD packet with O-bit on has received from the | |
* neighbor. | |
*/ | |
SET_FLAG (options, OSPF_OPTION_O); | |
} | |
#endif /* HAVE_OPAQUE_LSA */ | |
stream_putc (s, options); |
stream_putc (s, options); |
|
|
/* DD flags */ |
/* DD flags */ |
Line 2829 ospf_make_db_desc (struct ospf_interface *oi, struct o
|
Line 3126 ospf_make_db_desc (struct ospf_interface *oi, struct o
|
for (rn = route_top (table); rn; rn = route_next (rn)) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
if ((lsa = rn->info) != NULL) |
if ((lsa = rn->info) != NULL) |
{ |
{ |
#ifdef HAVE_OPAQUE_LSA |
|
if (IS_OPAQUE_LSA (lsa->data->type) |
if (IS_OPAQUE_LSA (lsa->data->type) |
&& (! CHECK_FLAG (options, OSPF_OPTION_O))) |
&& (! CHECK_FLAG (options, OSPF_OPTION_O))) |
{ |
{ |
Line 2838 ospf_make_db_desc (struct ospf_interface *oi, struct o
|
Line 3134 ospf_make_db_desc (struct ospf_interface *oi, struct o
|
ospf_lsdb_delete (lsdb, lsa); |
ospf_lsdb_delete (lsdb, lsa); |
continue; |
continue; |
} |
} |
#endif /* HAVE_OPAQUE_LSA */ |
|
|
|
if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)) |
if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)) |
{ |
{ |
Line 2974 ospf_make_ls_upd (struct ospf_interface *oi, struct li
|
Line 3269 ospf_make_ls_upd (struct ospf_interface *oi, struct li
|
u_int16_t ls_age; |
u_int16_t ls_age; |
|
|
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("ospf_make_ls_upd: List Iteration"); | zlog_debug ("ospf_make_ls_upd: List Iteration %d", count); |
|
|
lsa = listgetdata (node); |
lsa = listgetdata (node); |
|
|
Line 3380 ospf_ls_upd_queue_send (struct ospf_interface *oi, str
|
Line 3675 ospf_ls_upd_queue_send (struct ospf_interface *oi, str
|
u_int16_t length = OSPF_HEADER_SIZE; |
u_int16_t length = OSPF_HEADER_SIZE; |
|
|
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("listcount = %d, dst %s", listcount (update), inet_ntoa(addr)); | zlog_debug ("listcount = %d, [%s]dst %s", listcount (update), IF_NAME(oi), |
| inet_ntoa(addr)); |
|
|
op = ospf_ls_upd_packet_new (update, oi); |
op = ospf_ls_upd_packet_new (update, oi); |
|
|
Line 3502 ospf_ls_upd_send (struct ospf_neighbor *nbr, struct li
|
Line 3798 ospf_ls_upd_send (struct ospf_neighbor *nbr, struct li
|
|
|
if (rn->info == NULL) |
if (rn->info == NULL) |
rn->info = list_new (); |
rn->info = list_new (); |
|
else |
|
route_unlock_node (rn); |
|
|
for (ALL_LIST_ELEMENTS_RO (update, node, lsa)) |
for (ALL_LIST_ELEMENTS_RO (update, node, lsa)) |
listnode_add (rn->info, ospf_lsa_lock (lsa)); /* oi->ls_upd_queue */ |
listnode_add (rn->info, ospf_lsa_lock (lsa)); /* oi->ls_upd_queue */ |