diff options
Diffstat (limited to 'ospf6d/ospf6_message.c')
| -rw-r--r-- | ospf6d/ospf6_message.c | 221 |
1 files changed, 197 insertions, 24 deletions
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 352cb137ed..c1004a7080 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -27,6 +27,7 @@ #include "thread.h" #include "linklist.h" #include "lib_errors.h" +#include "checksum.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" @@ -48,19 +49,34 @@ #include "ospf6d.h" #include "ospf6_gr.h" #include <netinet/ip6.h> +#include "lib/libospf.h" +#include "lib/keychain.h" +#include "ospf6_auth_trailer.h" DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_MESSAGE, "OSPF6 message"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PACKET, "OSPF6 packet"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_FIFO, "OSPF6 FIFO queue"); unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0}; -static const struct message ospf6_message_type_str[] = { - {OSPF6_MESSAGE_TYPE_HELLO, "Hello"}, - {OSPF6_MESSAGE_TYPE_DBDESC, "DbDesc"}, - {OSPF6_MESSAGE_TYPE_LSREQ, "LSReq"}, - {OSPF6_MESSAGE_TYPE_LSUPDATE, "LSUpdate"}, - {OSPF6_MESSAGE_TYPE_LSACK, "LSAck"}, - {0}}; + +const char *ospf6_message_type(int type) +{ + switch (type) { + case OSPF6_MESSAGE_TYPE_HELLO: + return "Hello"; + case OSPF6_MESSAGE_TYPE_DBDESC: + return "DbDesc"; + case OSPF6_MESSAGE_TYPE_LSREQ: + return "LSReq"; + case OSPF6_MESSAGE_TYPE_LSUPDATE: + return "LSUpdate"; + case OSPF6_MESSAGE_TYPE_LSACK: + return "LSAck"; + case OSPF6_MESSAGE_TYPE_UNKNOWN: + default: + return "unknown"; + } +} /* Minimum (besides the standard OSPF packet header) lengths for OSPF packets of particular types, offset is the "type" field. */ @@ -101,7 +117,7 @@ static void ospf6_header_print(struct ospf6_header *oh) void ospf6_hello_print(struct ospf6_header *oh, int action) { struct ospf6_hello *hello; - char options[16]; + char options[32]; char *p; ospf6_header_print(oh); @@ -136,7 +152,7 @@ void ospf6_hello_print(struct ospf6_header *oh, int action) void ospf6_dbdesc_print(struct ospf6_header *oh, int action) { struct ospf6_dbdesc *dbdesc; - char options[16]; + char options[32]; char *p; ospf6_header_print(oh); @@ -439,6 +455,20 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, return; } + if (((OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT) == + OSPF6_OPT_AT) && + (oi->at_data.flags == 0)) || + ((OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT) != + OSPF6_OPT_AT) && + (oi->at_data.flags != 0))) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_warn( + "VRF %s: IF %s AT-bit mismatch in hello packet", + oi->interface->vrf->name, oi->interface->name); + oi->at_data.rx_drop++; + return; + } + /* Find neighbor, create if not exist */ on = ospf6_neighbor_lookup(oh->router_id, oi); if (on == NULL) { @@ -1006,6 +1036,20 @@ static void ospf6_dbdesc_recv(struct in6_addr *src, struct in6_addr *dst, dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh + sizeof(struct ospf6_header)); + if (((OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT) == + OSPF6_OPT_AT) && + (oi->at_data.flags == 0)) || + ((OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT) != + OSPF6_OPT_AT) && + (oi->at_data.flags != 0))) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_warn( + "VRF %s: IF %s AT-bit mismatch in dbdesc packet", + oi->interface->vrf->name, oi->interface->name); + oi->at_data.rx_drop++; + return; + } + /* Interface MTU check */ if (!oi->mtu_ignore && ntohs(dbdesc->ifmtu) != oi->ifmtu) { zlog_warn("VRF %s: I/F %s MTU mismatch (my %d rcvd %d)", @@ -1412,14 +1456,15 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, bytesonwire); return MSG_NG; } + /* Now it is safe to access header fields. */ if (bytesonwire != ntohs(oh->length)) { zlog_warn("%s: %s packet length error (%u real, %u declared)", - __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL), - bytesonwire, ntohs(oh->length)); + __func__, ospf6_message_type(oh->type), bytesonwire, + ntohs(oh->length)); return MSG_NG; } + /* version check */ if (oh->version != OSPFV3_VERSION) { zlog_warn("%s: invalid (%u) protocol version", __func__, @@ -1431,8 +1476,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, && bytesonwire < OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type]) { zlog_warn("%s: undersized (%u B) %s packet", __func__, - bytesonwire, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + bytesonwire, ospf6_message_type(oh->type)); return MSG_NG; } /* type-specific deeper validation */ @@ -1446,7 +1490,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, % 4) return MSG_OK; zlog_warn("%s: alignment error in %s packet", __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + ospf6_message_type(oh->type)); return MSG_NG; case OSPF6_MESSAGE_TYPE_DBDESC: /* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes @@ -1467,7 +1511,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, % OSPF6_LSREQ_LSDESC_FIX_SIZE) return MSG_OK; zlog_warn("%s: alignment error in %s packet", __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + ospf6_message_type(oh->type)); return MSG_NG; case OSPF6_MESSAGE_TYPE_LSUPDATE: /* RFC5340 A.3.5, packet header + OSPF6_LS_UPD_MIN_SIZE bytes @@ -1497,7 +1541,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, } if (test != MSG_OK) zlog_warn("%s: anomaly in %s packet", __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + ospf6_message_type(oh->type)); return test; } @@ -1727,6 +1771,9 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) struct iovec iovector[2]; struct ospf6_interface *oi; struct ospf6_header *oh; + enum ospf6_auth_err ret = OSPF6_AUTH_PROCESS_NORMAL; + uint32_t at_len = 0; + uint32_t lls_len = 0; /* initialize */ memset(&src, 0, sizeof(src)); @@ -1772,6 +1819,24 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) return OSPF6_READ_CONTINUE; oh = (struct ospf6_header *)recvbuf; + ret = ospf6_auth_validate_pkt(oi, (uint32_t *)&len, oh, &at_len, + &lls_len); + if (ret == OSPF6_AUTH_VALIDATE_SUCCESS) { + ret = ospf6_auth_check_digest(oh, oi, &src, lls_len); + if (ret == OSPF6_AUTH_VALIDATE_FAILURE) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err( + "RECV[%s]: OSPF packet auth digest miss-match on %s", + oi->interface->name, + ospf6_message_type(oh->type)); + oi->at_data.rx_drop++; + return OSPF6_READ_CONTINUE; + } + } else if (ret == OSPF6_AUTH_VALIDATE_FAILURE) { + oi->at_data.rx_drop++; + return OSPF6_READ_CONTINUE; + } + if (ospf6_rxpacket_examin(oi, oh, len) != MSG_OK) return OSPF6_READ_CONTINUE; @@ -1782,8 +1847,7 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) /* Log */ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR)) { - zlog_debug("%s received on %s", - lookup_msg(ospf6_message_type_str, oh->type, NULL), + zlog_debug("%s received on %s", ospf6_message_type(oh->type), oi->interface->name); zlog_debug(" src: %pI6", &src); zlog_debug(" dst: %pI6", &dst); @@ -1807,6 +1871,10 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) default: assert(0); } + + if ((at_len != 0) && IS_OSPF6_DEBUG_AUTH_RX) + ospf6_auth_hdr_dump_recv(oh, (len + at_len + lls_len), + lls_len); } switch (oh->type) { @@ -1863,6 +1931,27 @@ int ospf6_receive(struct thread *thread) return 0; } +static void ospf6_fill_hdr_checksum(struct ospf6_interface *oi, + struct ospf6_packet *op) +{ + struct ipv6_ph ph = {}; + struct ospf6_header *oh; + void *offset = NULL; + + if (oi->at_data.flags != 0) + return; + + memcpy(&ph.src, oi->linklocal_addr, sizeof(struct in6_addr)); + memcpy(&ph.dst, &op->dst, sizeof(struct in6_addr)); + ph.ulpl = htonl(op->length); + ph.next_hdr = IPPROTO_OSPFIGP; + + /* Suppress static analysis warnings about accessing icmp6 oob */ + oh = (struct ospf6_header *)STREAM_DATA(op->s); + offset = oh; + oh->checksum = in_cksum_with_ph6(&ph, offset, op->length); +} + static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi, struct stream *s) { @@ -1873,6 +1962,7 @@ static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi, oh->version = (uint8_t)OSPFV3_VERSION; oh->type = type; oh->length = 0; + oh->router_id = oi->area->ospf6->router_id; oh->area_id = oi->area->area_id; oh->checksum = 0; @@ -1904,9 +1994,48 @@ static void ospf6_fill_lsupdate_header(struct stream *s, uint32_t lsa_num) lsu->lsa_number = htonl(lsa_num); } +static void ospf6_auth_trailer_copy_keychain_key(struct ospf6_interface *oi) +{ + char *keychain_name = NULL; + struct keychain *keychain = NULL; + struct key *key = NULL; + + keychain_name = oi->at_data.keychain; + keychain = keychain_lookup(keychain_name); + if (keychain) { + key = key_lookup_for_send(keychain); + if (key && key->string && + key->hash_algo != KEYCHAIN_ALGO_NULL) { + /* storing the values so that further + * lookup can be avoided. after + * processing the digest need to reset + * these values + */ + oi->at_data.hash_algo = key->hash_algo; + oi->at_data.auth_key = XSTRDUP( + MTYPE_OSPF6_AUTH_MANUAL_KEY, key->string); + oi->at_data.key_id = key->index; + SET_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN_VALID); + } + } +} + static uint32_t ospf6_packet_max(struct ospf6_interface *oi) { + int at_len = 0; + assert(oi->ifmtu > sizeof(struct ip6_hdr)); + + if (oi->at_data.flags != 0) { + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) + ospf6_auth_trailer_copy_keychain_key(oi); + + at_len += OSPF6_AUTH_HDR_MIN_SIZE; + at_len += keychain_get_hash_len(oi->at_data.hash_algo); + return oi->ifmtu - (sizeof(struct ip6_hdr)) - at_len; + } + return oi->ifmtu - (sizeof(struct ip6_hdr)); } @@ -1915,11 +2044,15 @@ static uint16_t ospf6_make_hello(struct ospf6_interface *oi, struct stream *s) struct listnode *node, *nnode; struct ospf6_neighbor *on; uint16_t length = OSPF6_HELLO_MIN_SIZE; + uint8_t options1 = oi->area->options[1]; + + if (oi->at_data.flags != 0) + options1 |= OSPF6_OPT_AT; stream_putl(s, oi->interface->ifindex); stream_putc(s, oi->priority); stream_putc(s, oi->area->options[0]); - stream_putc(s, oi->area->options[1]); + stream_putc(s, options1); stream_putc(s, oi->area->options[2]); stream_putw(s, oi->hello_interval); stream_putw(s, oi->dead_interval); @@ -1959,6 +2092,7 @@ static int ospf6_write(struct thread *thread) int len; int64_t latency = 0; struct timeval timestamp; + unsigned int at_len = 0; if (ospf6->fd < 0) { zlog_warn("ospf6_write failed to send, fd %d", ospf6->fd); @@ -1983,17 +2117,32 @@ static int ospf6_write(struct thread *thread) oh = (struct ospf6_header *)STREAM_DATA(op->s); + if (oi->at_data.flags != 0) { + at_len = ospf6_auth_len_get(oi); + if (at_len) { + iovector[0].iov_len = + ntohs(oh->length) + at_len; + ospf6_auth_digest_send(oi->linklocal_addr, oi, + oh, at_len, + iovector[0].iov_len); + } else { + iovector[0].iov_len = ntohs(oh->length); + } + } else { + iovector[0].iov_len = ntohs(oh->length); + } + len = ospf6_sendmsg(oi->linklocal_addr, &op->dst, oi->interface->ifindex, iovector, ospf6->fd); - if (len != op->length) + + if (len != (op->length + (int)at_len)) flog_err(EC_LIB_DEVELOPMENT, "Could not send entire message"); if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) { zlog_debug("%s send on %s", - lookup_msg(ospf6_message_type_str, oh->type, - NULL), + ospf6_message_type(oh->type), oi->interface->name); zlog_debug(" src: %pI6", oi->linklocal_addr); zlog_debug(" dst: %pI6", &op->dst); @@ -2052,6 +2201,15 @@ static int ospf6_write(struct thread *thread) assert(0); break; } + + if ((oi->at_data.flags != 0) && + (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) && + (IS_OSPF6_DEBUG_AUTH_TX)) + ospf6_auth_hdr_dump_send(oh, iovector[0].iov_len); + + /* initialize at_len to 0 for next packet */ + at_len = 0; + /* Now delete packet from queue. */ ospf6_packet_delete(oi); @@ -2117,6 +2275,8 @@ int ospf6_hello_send(struct thread *thread) op->dst = allspfrouters6; + ospf6_fill_hdr_checksum(oi, op); + /* Add packet to the top of the interface output queue, so that they * can't get delayed by things like long queues of LS Update packets */ @@ -2135,6 +2295,10 @@ static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s) { uint16_t length = OSPF6_DB_DESC_MIN_SIZE; struct ospf6_lsa *lsa, *lsanext; + uint8_t options1 = on->ospf6_if->area->options[1]; + + if (on->ospf6_if->at_data.flags != 0) + options1 |= OSPF6_OPT_AT; /* if this is initial one, initialize sequence number for DbDesc */ if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT) @@ -2145,7 +2309,7 @@ static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s) /* reserved */ stream_putc(s, 0); /* reserved 1 */ stream_putc(s, on->ospf6_if->area->options[0]); - stream_putc(s, on->ospf6_if->area->options[1]); + stream_putc(s, options1); stream_putc(s, on->ospf6_if->area->options[2]); stream_putw(s, on->ospf6_if->ifmtu); stream_putc(s, 0); /* reserved 2 */ @@ -2212,6 +2376,8 @@ int ospf6_dbdesc_send(struct thread *thread) else op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); + ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2319,6 +2485,7 @@ static uint16_t ospf6_make_lsack_neighbor(struct ospf6_neighbor *on, (*op)->length = length + OSPF6_HEADER_SIZE; (*op)->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, *op); ospf6_packet_add(on->ospf6_if, *op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); /* new packet */ @@ -2388,6 +2555,7 @@ int ospf6_lsreq_send(struct thread *thread) else op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2425,6 +2593,7 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on, op->dst = alldrouters6; } if (oi) { + ospf6_fill_hdr_checksum(oi, op); ospf6_packet_add(oi, op); /* If ospf instance is being deleted, send the packet * immediately @@ -2502,6 +2671,7 @@ static uint16_t ospf6_make_ls_retrans_list(struct ospf6_neighbor *on, else (*op)->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, *op); ospf6_packet_add(on->ospf6_if, *op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2573,6 +2743,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) op->dst = allspfrouters6; else op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); } else @@ -2739,6 +2910,7 @@ int ospf6_lsack_send_neighbor(struct thread *thread) /* Set packet length, dst and queue to FIFO. */ op->length = length; op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2823,6 +2995,7 @@ int ospf6_lsack_send_interface(struct thread *thread) else op->dst = alldrouters6; + ospf6_fill_hdr_checksum(oi, op); ospf6_packet_add(oi, op); OSPF6_MESSAGE_WRITE_ON(oi); |
