diff options
author | Denis Ovsienko <infrastation@yandex.ru> | 2012-02-26 17:59:43 +0400 |
---|---|---|
committer | David Lamparter <equinox@diac24.net> | 2012-03-12 11:05:38 +0100 |
commit | bd5651f0ec7aa94627a2a6868dd458f016750a35 (patch) | |
tree | 9f5dcd01bd90d1ea78cd841f00fea4bbdc3a6dee | |
parent | ef1b78cbcd8ade0c5444f3ff9dd00a40e760ec92 (diff) |
ospfd: bring ospf_check_auth() into focus
The old ospf_check_auth() function did two different jobs depending on
AuType. For Null and Simple cases it actually authenticated the packet,
but for Cryptographic case it only checked declared packet size (not
taking the actual number of bytes on wire into account). The calling
function, ospf_verify_header(), had its own set of MD5/checksum checks
dispatched depending on AuType.
This commit makes the packet size check work against the real number of
bytes and moves it to ospf_packet_examine(). All MD5/checksum
verification is now performed in ospf_check_auth() function.
* ospf_packet.c
* ospf_packet_examin(): check length with MD5 bytes in mind
* ospf_verify_header(): remove all AuType-specific code
* ospf_check_auth(): completely rewrite
-rw-r--r-- | ospfd/ospf_packet.c | 170 |
1 files changed, 100 insertions, 70 deletions
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 3d827296..4842c4e2 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -91,6 +91,9 @@ static const u_int16_t ospf_lsa_minlen[] = 0, }; +/* for ospf_check_auth() */ +static int ospf_check_sum (struct ospf_header *); + /* OSPF authentication checking function */ static int ospf_auth_type (struct ospf_interface *oi) @@ -2267,44 +2270,91 @@ ospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src) return 0; } +/* Return 1, if the packet is properly authenticated and checksummed, + 0 otherwise. In particular, check that AuType header field is valid and + matches the locally configured AuType, and that D.5 requirements are met. */ static int ospf_check_auth (struct ospf_interface *oi, struct ospf_header *ospfh) { - int ret = 0; struct crypt_key *ck; + u_int16_t iface_auth_type; + u_int16_t pkt_auth_type = ntohs (ospfh->auth_type); - switch (ntohs (ospfh->auth_type)) + switch (pkt_auth_type) + { + case OSPF_AUTH_NULL: /* RFC2328 D.5.1 */ + if (OSPF_AUTH_NULL != (iface_auth_type = ospf_auth_type (oi))) { - case OSPF_AUTH_NULL: - ret = 1; - break; - case OSPF_AUTH_SIMPLE: - if (!memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE)) - ret = 1; - else - ret = 0; - break; - case OSPF_AUTH_CRYPTOGRAPHIC: - if ((ck = listgetdata (listtail(OSPF_IF_PARAM (oi,auth_crypt)))) == NULL) - { - ret = 0; - break; - } - - /* This is very basic, the digest processing is elsewhere */ - if (ospfh->u.crypt.auth_data_len == OSPF_AUTH_MD5_SIZE && - ospfh->u.crypt.key_id == ck->key_id && - ntohs (ospfh->length) + OSPF_AUTH_MD5_SIZE <= OSPF_MAX_PACKET_SIZE) - ret = 1; - else - ret = 0; - break; - default: - ret = 0; - break; + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) + zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Null", + IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type)); + return 0; } - - return ret; + if (! ospf_check_sum (ospfh)) + { + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) + zlog_warn ("interface %s: Null auth OK, but checksum error, Router-ID %s", + IF_NAME (oi), inet_ntoa (ospfh->router_id)); + return 0; + } + return 1; + case OSPF_AUTH_SIMPLE: /* RFC2328 D.5.2 */ + if (OSPF_AUTH_SIMPLE != (iface_auth_type = ospf_auth_type (oi))) + { + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) + zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Simple", + IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type)); + return 0; + } + if (memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE)) + { + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) + zlog_warn ("interface %s: Simple auth failed", IF_NAME (oi)); + return 0; + } + if (! ospf_check_sum (ospfh)) + { + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) + zlog_warn ("interface %s: Simple auth OK, checksum error, Router-ID %s", + IF_NAME (oi), inet_ntoa (ospfh->router_id)); + return 0; + } + return 1; + case OSPF_AUTH_CRYPTOGRAPHIC: /* RFC2328 D.5.3 */ + if (OSPF_AUTH_CRYPTOGRAPHIC != (iface_auth_type = ospf_auth_type (oi))) + { + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) + zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Cryptographic", + IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type)); + return 0; + } + if (ospfh->checksum) + { + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) + zlog_warn ("interface %s: OSPF header checksum is not 0", IF_NAME (oi)); + return 0; + } + /* only MD5 crypto method can pass ospf_packet_examin() */ + if + ( + NULL == (ck = listgetdata (listtail(OSPF_IF_PARAM (oi,auth_crypt)))) || + ospfh->u.crypt.key_id != ck->key_id || + /* Condition above uses the last key ID on the list, which is + different from what ospf_crypt_key_lookup() does. A bug? */ + ! ospf_check_md5_digest (oi, ospfh) + ) + { + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) + zlog_warn ("interface %s: MD5 auth failed", IF_NAME (oi)); + return 0; + } + return 1; + default: + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) + zlog_warn ("interface %s: invalid packet auth-type (%02x)", + IF_NAME (oi), pkt_auth_type); + return 0; + } } static int @@ -2523,7 +2573,7 @@ ospf_lsaseq_examin static unsigned ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) { - u_int16_t bytesdeclared; + u_int16_t bytesdeclared, bytesauth; unsigned ret; struct ospf_ls_update * lsupd; @@ -2538,11 +2588,24 @@ ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) * for possible extra bytes of crypto auth/padding, which are not counted * in the OSPF header "length" field. */ bytesdeclared = ntohs (oh->length); - if (bytesdeclared > bytesonwire) + 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 declared)", - __func__, bytesonwire, bytesdeclared); + 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 @@ -2650,42 +2713,9 @@ ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi, return -1; } - /* Check authentication. */ - if (ospf_auth_type (oi) != ntohs (ospfh->auth_type)) - { - zlog_warn ("interface %s: auth-type mismatch, local %d, rcvd %d", - IF_NAME (oi), ospf_auth_type (oi), ntohs (ospfh->auth_type)); - return -1; - } - + /* Check authentication. The function handles logging actions, where required. */ if (! ospf_check_auth (oi, 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, ospfh) == 0) - { - zlog_warn ("interface %s: ospf_read md5 authentication failed.", - IF_NAME (oi)); - return -1; - } - } + return -1; return 0; } |