diff options
author | Renato Westphal <renato@cvs.openbsd.org> | 2016-05-23 16:08:19 +0000 |
---|---|---|
committer | Renato Westphal <renato@cvs.openbsd.org> | 2016-05-23 16:08:19 +0000 |
commit | 91ec63a6cc84ab519bdb3d5333da436b8b9a2647 (patch) | |
tree | 165323bcc28becfcbc217e6e1d05e9ec27de1cc9 | |
parent | 960a41bce4d794d6d183c192d4ee2fd1f6021296 (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/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/ldpd/hello.c | 44 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpd.h | 5 | ||||
-rw-r--r-- | usr.sbin/ldpd/packet.c | 53 | ||||
-rw-r--r-- | usr.sbin/ldpd/parse.y | 4 | ||||
-rw-r--r-- | usr.sbin/ldpd/util.c | 38 |
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); +} |