version 1.1.1.1, 2012/02/21 17:26:12
|
version 1.1.1.2, 2012/05/29 11:53:41
|
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 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 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 */ |
|
#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 2699 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 2725 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 2763 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 2887 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)); |