summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRenato Westphal <renato@cvs.openbsd.org>2016-05-23 16:08:19 +0000
committerRenato Westphal <renato@cvs.openbsd.org>2016-05-23 16:08:19 +0000
commit91ec63a6cc84ab519bdb3d5333da436b8b9a2647 (patch)
tree165323bcc28becfcbc217e6e1d05e9ec27de1cc9
parent960a41bce4d794d6d183c192d4ee2fd1f6021296 (diff)
Several improvements in the parsing of UDP/Hello packets.
* Fix check of the packet's size and the "PDU Length" field; * Add check for the "Message Length" field; * Check for invalid labelspace earlier. * Use if_lookup() on disc_recv_iface() to reduce one level of identation; Additionally, add the following safeguards: * Check for unicast link hellos; * Check for multicast targeted hellos; * Validate packet's source address; * Validate received transport-address. Put the ancillary function bad_ip_addr() into a new file, util.c, which will be used later for several other things.
-rw-r--r--usr.sbin/ldpd/Makefile4
-rw-r--r--usr.sbin/ldpd/hello.c44
-rw-r--r--usr.sbin/ldpd/ldpd.h5
-rw-r--r--usr.sbin/ldpd/packet.c53
-rw-r--r--usr.sbin/ldpd/parse.y4
-rw-r--r--usr.sbin/ldpd/util.c38
6 files changed, 106 insertions, 42 deletions
diff --git a/usr.sbin/ldpd/Makefile b/usr.sbin/ldpd/Makefile
index 32f6019f005..2ea6107cfc0 100644
--- a/usr.sbin/ldpd/Makefile
+++ b/usr.sbin/ldpd/Makefile
@@ -1,10 +1,10 @@
-# $OpenBSD: Makefile,v 1.7 2015/07/21 04:56:44 renato Exp $
+# $OpenBSD: Makefile,v 1.8 2016/05/23 16:08:18 renato Exp $
PROG= ldpd
SRCS= accept.c adjacency.c address.c control.c hello.c init.c interface.c \
keepalive.c kroute.c labelmapping.c lde.c lde_lib.c ldpd.c ldpe.c \
log.c neighbor.c notification.c packet.c parse.y printconf.c pfkey.c \
- l2vpn.c
+ l2vpn.c util.c
MAN= ldpd.8 ldpd.conf.5
diff --git a/usr.sbin/ldpd/hello.c b/usr.sbin/ldpd/hello.c
index ed2369fe3b0..ff1676e2517 100644
--- a/usr.sbin/ldpd/hello.c
+++ b/usr.sbin/ldpd/hello.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hello.c,v 1.32 2016/05/23 16:04:04 renato Exp $ */
+/* $OpenBSD: hello.c,v 1.33 2016/05/23 16:08:18 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -128,6 +128,20 @@ recv_hello(struct iface *iface, struct in_addr src, char *buf, u_int16_t len)
__func__, inet_ntoa(lsr_id), holdtime);
return;
}
+ buf += r;
+ len -= r;
+
+ /* safety checks */
+ if (multicast && (flags & TARGETED_HELLO)) {
+ log_debug("%s: neighbor %s: multicast targeted hello", __func__,
+ inet_ntoa(lsr_id));
+ return;
+ }
+ if (!multicast && !((flags & TARGETED_HELLO))) {
+ log_debug("%s: neighbor %s: unicast link hello", __func__,
+ inet_ntoa(lsr_id));
+ return;
+ }
bzero(&source, sizeof(source));
if (flags & TARGETED_HELLO) {
@@ -154,19 +168,11 @@ recv_hello(struct iface *iface, struct in_addr src, char *buf, u_int16_t len)
source.type = HELLO_TARGETED;
source.target = tnbr;
} else {
- if (ldp.lspace_id != 0) {
- log_debug("%s: invalid label space ID %u, interface %s",
- __func__, ldp.lspace_id, iface->name);
- return;
- }
source.type = HELLO_LINK;
source.link.iface = iface;
source.link.src_addr.s_addr = src.s_addr;
}
- buf += r;
- len -= r;
-
r = tlv_decode_opt_hello_prms(buf, len, &transport_addr,
&conf_number);
if (r == -1) {
@@ -174,16 +180,22 @@ recv_hello(struct iface *iface, struct in_addr src, char *buf, u_int16_t len)
__func__, inet_ntoa(lsr_id));
return;
}
- if (transport_addr.s_addr == INADDR_ANY)
- transport_addr.s_addr = src.s_addr;
-
if (r != len) {
log_debug("%s: neighbor %s: unexpected data in message",
__func__, inet_ntoa(lsr_id));
return;
}
- nbr = nbr_find_ldpid(ldp.lsr_id);
+ /* implicit transport address */
+ if (transport_addr.s_addr == INADDR_ANY)
+ transport_addr.s_addr = src.s_addr;
+ if (bad_ip_addr(transport_addr)) {
+ log_debug("%s: neighbor %s: invalid transport address %s",
+ __func__, inet_ntoa(lsr_id), inet_ntoa(transport_addr));
+ return;
+ }
+
+ nbr = nbr_find_ldpid(lsr_id.s_addr);
if (!nbr) {
/* create new adjacency and new neighbor */
nbr = nbr_new(lsr_id, transport_addr);
@@ -216,7 +228,6 @@ recv_hello(struct iface *iface, struct in_addr src, char *buf, u_int16_t len)
adj->holdtime = min(tnbr->hello_holdtime, holdtime);
}
-
if (adj->holdtime != INFINITE_HOLDTIME)
adj_start_itimer(adj);
else
@@ -264,11 +275,10 @@ tlv_decode_hello_prms(char *buf, u_int16_t len, u_int16_t *holdtime,
return (-1);
bcopy(buf, &tlv, sizeof(tlv));
- if (ntohs(tlv.length) != sizeof(tlv) - TLV_HDR_LEN)
- return (-1);
-
if (tlv.type != htons(TLV_TYPE_COMMONHELLO))
return (-1);
+ if (ntohs(tlv.length) != sizeof(tlv) - TLV_HDR_LEN)
+ return (-1);
*holdtime = ntohs(tlv.holdtime);
*flags = ntohs(tlv.flags);
diff --git a/usr.sbin/ldpd/ldpd.h b/usr.sbin/ldpd/ldpd.h
index 0cf11845c2e..c40a1a072c9 100644
--- a/usr.sbin/ldpd/ldpd.h
+++ b/usr.sbin/ldpd/ldpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpd.h,v 1.57 2016/05/23 14:59:50 renato Exp $ */
+/* $OpenBSD: ldpd.h,v 1.58 2016/05/23 16:08:18 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -464,6 +464,9 @@ const char *if_state_name(int);
const char *if_type_name(enum iface_type);
const char *notification_name(u_int32_t);
+/* util.c */
+int bad_ip_addr(struct in_addr);
+
/* ldpd.c */
void main_imsg_compose_ldpe(int, pid_t, void *, u_int16_t);
void main_imsg_compose_lde(int, pid_t, void *, u_int16_t);
diff --git a/usr.sbin/ldpd/packet.c b/usr.sbin/ldpd/packet.c
index 6ea5aafd4d8..b855b22ea98 100644
--- a/usr.sbin/ldpd/packet.c
+++ b/usr.sbin/ldpd/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.48 2016/05/23 16:06:08 renato Exp $ */
+/* $OpenBSD: packet.c,v 1.49 2016/05/23 16:08:18 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -42,7 +42,7 @@
extern struct ldpd_conf *leconf;
extern struct ldpd_sysdep sysdep;
-struct iface *disc_find_iface(unsigned int, struct in_addr);
+struct iface *disc_find_iface(unsigned int, struct in_addr, int);
ssize_t session_get_pdu(struct ibuf_read *, char **);
static int msgcnt = 0;
@@ -142,6 +142,14 @@ disc_recv_packet(int fd, short event, void *bula)
strerror(errno));
return;
}
+
+ multicast = (msg.msg_flags & MSG_MCAST) ? 1 : 0;
+ if (bad_ip_addr(src.sin_addr)) {
+ log_debug("%s: invalid source address: %s", __func__,
+ inet_ntoa(src.sin_addr));
+ return;
+ }
+
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level == IPPROTO_IP &&
@@ -203,27 +211,34 @@ disc_recv_packet(int fd, short event, void *bula)
}
struct iface *
-disc_find_iface(unsigned int ifindex, struct in_addr src)
+disc_find_iface(unsigned int ifindex, struct in_addr src,
+ int multicast)
{
struct iface *iface;
struct if_addr *if_addr;
- LIST_FOREACH(iface, &leconf->iface_list, entry)
- LIST_FOREACH(if_addr, &iface->addr_list, entry)
- switch (iface->type) {
- case IF_TYPE_POINTOPOINT:
- if (ifindex == iface->ifindex &&
- if_addr->dstbrd.s_addr == src.s_addr)
- return (iface);
- break;
- default:
- if (ifindex == iface->ifindex &&
- (if_addr->addr.s_addr &
- if_addr->mask.s_addr) ==
- (src.s_addr & if_addr->mask.s_addr))
- return (iface);
- break;
- }
+ iface = if_lookup(leconf, ifindex);
+ if (iface == NULL)
+ return (NULL);
+
+ if (!multicast)
+ return (iface);
+
+ LIST_FOREACH(if_addr, &iface->addr_list, entry) {
+ switch (iface->type) {
+ case IF_TYPE_POINTOPOINT:
+ if (ifindex == iface->ifindex &&
+ if_addr->dstbrd.s_addr == src.s_addr)
+ return (iface);
+ break;
+ default:
+ if (ifindex == iface->ifindex &&
+ (if_addr->addr.s_addr & if_addr->mask.s_addr) ==
+ (src.s_addr & if_addr->mask.s_addr))
+ return (iface);
+ break;
+ }
+ }
return (NULL);
}
diff --git a/usr.sbin/ldpd/parse.y b/usr.sbin/ldpd/parse.y
index 1ff60fe3707..5b301b0a369 100644
--- a/usr.sbin/ldpd/parse.y
+++ b/usr.sbin/ldpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.36 2016/05/23 15:43:11 renato Exp $ */
+/* $OpenBSD: parse.y,v 1.37 2016/05/23 16:08:18 renato Exp $ */
/*
* Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
@@ -106,8 +106,6 @@ struct config_defaults tnbrdefs;
struct config_defaults pwdefs;
struct config_defaults *defs;
-int bad_ip_addr(struct in_addr);
-
struct iface *conf_get_if(struct kif *);
struct tnbr *conf_get_tnbr(struct in_addr);
struct nbr_params *conf_get_nbrp(struct in_addr);
diff --git a/usr.sbin/ldpd/util.c b/usr.sbin/ldpd/util.c
new file mode 100644
index 00000000000..9cc5c461107
--- /dev/null
+++ b/usr.sbin/ldpd/util.c
@@ -0,0 +1,38 @@
+/* $OpenBSD: util.c,v 1.1 2016/05/23 16:08:18 renato Exp $ */
+
+/*
+ * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
+ * Copyright (c) 2012 Alexander Bluhm <bluhm@openbsd.org>
+ * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include "ldpd.h"
+#include "log.h"
+
+int
+bad_ip_addr(struct in_addr addr)
+{
+ uint32_t a = ntohl(addr.s_addr);
+
+ if (((a >> IN_CLASSA_NSHIFT) == 0) ||
+ ((a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) ||
+ IN_MULTICAST(a) || IN_BADCLASS(a))
+ return (1);
+
+ return (0);
+}