summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrenato <renato@openbsd.org>2017-03-04 00:18:43 +0000
committerrenato <renato@openbsd.org>2017-03-04 00:18:43 +0000
commit9982546c3760090aa44feb891e6df807e4dfa66c (patch)
tree1242802e34d948f09ddbe39a9ff40a0440b79991
parentImplement RFC 5919 (LDP End-of-LIB). (diff)
downloadwireguard-openbsd-9982546c3760090aa44feb891e6df807e4dfa66c.tar.xz
wireguard-openbsd-9982546c3760090aa44feb891e6df807e4dfa66c.zip
Fix parsing of optional tlvs in address messages.
We were aborting the session upon receipt of MAC Address Withdrawal messages. Now make the parser aware that optional TLVs are possible in address messages.
-rw-r--r--usr.sbin/ldpd/address.c75
1 files changed, 60 insertions, 15 deletions
diff --git a/usr.sbin/ldpd/address.c b/usr.sbin/ldpd/address.c
index 238765af5ed..6d23e15ff2e 100644
--- a/usr.sbin/ldpd/address.c
+++ b/usr.sbin/ldpd/address.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: address.c,v 1.33 2017/03/03 23:53:50 renato Exp $ */
+/* $OpenBSD: address.c,v 1.34 2017/03/04 00:18:43 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -144,11 +144,24 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
{
struct ldp_msg msg;
uint16_t msg_type;
- struct address_list_tlv alt;
enum imsg_type type;
+ struct address_list_tlv alt;
+ uint16_t alt_len;
+ uint16_t alt_family;
struct lde_addr lde_addr;
memcpy(&msg, buf, sizeof(msg));
+ msg_type = ntohs(msg.type);
+ switch (msg_type) {
+ case MSG_TYPE_ADDR:
+ type = IMSG_ADDRESS_ADD;
+ break;
+ case MSG_TYPE_ADDRWITHDRAW:
+ type = IMSG_ADDRESS_DEL;
+ break;
+ default:
+ fatalx("recv_address: unexpected msg type");
+ }
buf += LDP_MSG_SIZE;
len -= LDP_MSG_SIZE;
@@ -157,9 +170,10 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
return (-1);
}
-
memcpy(&alt, buf, sizeof(alt));
- if (ntohs(alt.length) != len - TLV_HDR_SIZE) {
+ alt_len = ntohs(alt.length);
+ alt_family = ntohs(alt.family);
+ if (alt_len > len - TLV_HDR_SIZE) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
return (-1);
}
@@ -167,7 +181,7 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
return (-1);
}
- switch (ntohs(alt.family)) {
+ switch (alt_family) {
case AF_IPV4:
if (!nbr->v4_enabled)
/* just ignore the message */
@@ -182,19 +196,15 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
send_notification(nbr->tcp, S_UNSUP_ADDR, msg.id, msg.type);
return (-1);
}
+ alt_len -= sizeof(alt.family);
buf += sizeof(alt);
len -= sizeof(alt);
- msg_type = ntohs(msg.type);
- if (msg_type == MSG_TYPE_ADDR)
- type = IMSG_ADDRESS_ADD;
- else
- type = IMSG_ADDRESS_DEL;
-
- while (len > 0) {
- switch (ntohs(alt.family)) {
+ /* Process all received addresses */
+ while (alt_len > 0) {
+ switch (alt_family) {
case AF_IPV4:
- if (len < sizeof(struct in_addr)) {
+ if (alt_len < sizeof(struct in_addr)) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
msg.type);
return (-1);
@@ -206,9 +216,10 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
buf += sizeof(struct in_addr);
len -= sizeof(struct in_addr);
+ alt_len -= sizeof(struct in_addr);
break;
case AF_IPV6:
- if (len < sizeof(struct in6_addr)) {
+ if (alt_len < sizeof(struct in6_addr)) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
msg.type);
return (-1);
@@ -220,6 +231,7 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
buf += sizeof(struct in6_addr);
len -= sizeof(struct in6_addr);
+ alt_len -= sizeof(struct in6_addr);
break;
default:
fatalx("recv_address: unknown af");
@@ -231,6 +243,39 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
sizeof(lde_addr));
}
+ /* Optional Parameters */
+ while (len > 0) {
+ struct tlv tlv;
+ uint16_t tlv_type;
+ uint16_t tlv_len;
+
+ if (len < sizeof(tlv)) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+ return (-1);
+ }
+
+ memcpy(&tlv, buf, TLV_HDR_SIZE);
+ tlv_type = ntohs(tlv.type);
+ tlv_len = ntohs(tlv.length);
+ if (tlv_len + TLV_HDR_SIZE > len) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+ return (-1);
+ }
+ buf += TLV_HDR_SIZE;
+ len -= TLV_HDR_SIZE;
+
+ switch (tlv_type) {
+ default:
+ if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
+ send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
+ msg.id, msg.type, tlv_type, tlv_len, buf);
+ /* ignore unknown tlv */
+ break;
+ }
+ buf += tlv_len;
+ len -= tlv_len;
+ }
+
return (0);
}