diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2010-11-04 09:52:17 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2010-11-04 09:52:17 +0000 |
commit | f43f9ad39dccdded320e0038181cb93f2586f9dd (patch) | |
tree | 1cd9a589d4c5ec3b1d050e521bcd77d03850c8c6 | |
parent | 399e2bd2fdd1d1bfede26dda086423c31e1000bc (diff) |
Rewrite all packet parsers to be more careful about alignment. Until
now ldpd had no chance to run on a strict alignment architecture but
this makes ldpd happy on sparc64. Be careful to do all needed overflow
checks and try to make all parsing functions look similar.
OK michele@
-rw-r--r-- | usr.sbin/ldpd/address.c | 127 | ||||
-rw-r--r-- | usr.sbin/ldpd/hello.c | 120 | ||||
-rw-r--r-- | usr.sbin/ldpd/init.c | 33 | ||||
-rw-r--r-- | usr.sbin/ldpd/keepalive.c | 15 | ||||
-rw-r--r-- | usr.sbin/ldpd/labelmapping.c | 393 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldp.h | 14 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpe.h | 3 | ||||
-rw-r--r-- | usr.sbin/ldpd/notification.c | 38 | ||||
-rw-r--r-- | usr.sbin/ldpd/packet.c | 33 |
9 files changed, 404 insertions, 372 deletions
diff --git a/usr.sbin/ldpd/address.c b/usr.sbin/ldpd/address.c index e0bf23d0e11..0c456e91827 100644 --- a/usr.sbin/ldpd/address.c +++ b/usr.sbin/ldpd/address.c @@ -1,4 +1,4 @@ -/* $OpenBSD: address.c,v 1.5 2010/05/26 13:56:07 nicm Exp $ */ +/* $OpenBSD: address.c,v 1.6 2010/11/04 09:52:16 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -83,61 +83,67 @@ send_address(struct nbr *nbr, struct iface *iface) int recv_address(struct nbr *nbr, char *buf, u_int16_t len) { - struct ldp_msg *addr; - struct address_list_tlv *alt; - struct in_addr *address; - u_int32_t addrs_len; + struct ldp_msg addr; + struct address_list_tlv alt; + enum imsg_type type; - log_debug("recv_address: neighbor ID %s", inet_ntoa(nbr->id)); - - if (nbr->state != NBR_STA_OPER) - return (-1); - - addr = (struct ldp_msg *)buf; - - if ((len - TLV_HDR_LEN) < ntohs(addr->length)) { - session_shutdown(nbr, S_BAD_MSG_LEN, addr->msgid, addr->type); + if (nbr->state != NBR_STA_OPER) { + log_debug("recv_address: neighbor ID %s not operational", + inet_ntoa(nbr->id)); return (-1); } + bcopy(buf, &addr, sizeof(addr)); + log_debug("recv_address: neighbor ID %s%s", inet_ntoa(nbr->id), + ntohs(addr.type) == MSG_TYPE_ADDR ? "" : " address withdraw"); + if (ntohs(addr.type) == MSG_TYPE_ADDR) + type = IMSG_ADDRESS_ADD; + else + type = IMSG_ADDRESS_DEL; + buf += sizeof(struct ldp_msg); len -= sizeof(struct ldp_msg); - alt = (struct address_list_tlv *)buf; - - if (len < sizeof(*alt) || - (len - TLV_HDR_LEN) < ntohs(alt->length)) { - session_shutdown(nbr, S_BAD_TLV_LEN, addr->msgid, addr->type); + if (len < sizeof(alt)) { + session_shutdown(nbr, S_BAD_MSG_LEN, addr.msgid, addr.type); return (-1); } - addrs_len = (ntohs(alt->length) - sizeof(alt->family)); + bcopy(buf, &alt, sizeof(alt)); + + if (ntohs(alt.length) != len - TLV_HDR_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, addr.msgid, addr.type); + return (-1); + } - if (alt->type != TLV_TYPE_ADDRLIST) { - session_shutdown(nbr, S_UNKNOWN_TLV, addr->msgid, addr->type); + if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) { + session_shutdown(nbr, S_UNKNOWN_TLV, addr.msgid, addr.type); return (-1); } /* For now we only support IPv4 */ - if (alt->family != htons(ADDR_IPV4)) { - send_notification_nbr(nbr, S_UNSUP_ADDR, addr->msgid, - addr->type); + if (alt.family != htons(ADDR_IPV4)) { + send_notification_nbr(nbr, S_UNSUP_ADDR, addr.msgid, addr.type); return (-1); } - buf += sizeof(*alt); - len -= sizeof(*alt); - address = (struct in_addr *)buf; + buf += sizeof(alt); + len -= sizeof(alt); - while (addrs_len >= sizeof(address)) { - ldpe_imsg_compose_lde(IMSG_ADDRESS_ADD, nbr->peerid, 0, - address, sizeof(*address)); + while (len >= sizeof(struct in_addr)) { + ldpe_imsg_compose_lde(type, nbr->peerid, 0, + buf, sizeof(struct in_addr)); - address++; - addrs_len -= sizeof(*address); + buf += sizeof(struct in_addr); + len -= sizeof(struct in_addr); } - return (ntohs(addr->length)); + if (len != 0) { + session_shutdown(nbr, S_BAD_TLV_LEN, addr.msgid, addr.type); + return (-1); + } + + return (ntohs(addr.length)); } void @@ -193,56 +199,3 @@ send_address_withdraw(struct nbr *nbr, struct iface *iface) evbuf_enqueue(&nbr->wbuf, buf); } - -int -recv_address_withdraw(struct nbr *nbr, char *buf, u_int16_t len) -{ - struct ldp_msg *aw; - struct address_list_tlv *alt; - struct in_addr *address; - - log_debug("recv_address_withdraw: neighbor ID %s", inet_ntoa(nbr->id)); - - aw = (struct ldp_msg *)buf; - - if ((len - TLV_HDR_LEN) < ntohs(aw->length)) { - session_shutdown(nbr, S_BAD_MSG_LEN, aw->msgid, aw->type); - return (-1); - } - - buf += sizeof(struct ldp_msg); - len -= sizeof(struct ldp_msg); - - alt = (struct address_list_tlv *)buf; - - if (len < sizeof(*alt) || - (len - TLV_HDR_LEN) < ntohs(alt->length)) { - session_shutdown(nbr, S_BAD_TLV_LEN, aw->msgid, aw->type); - return (-1); - } - - if (alt->type != TLV_TYPE_ADDRLIST) { - session_shutdown(nbr, S_UNKNOWN_TLV, aw->msgid, aw->type); - return (-1); - } - - /* For now we just support IPv4 */ - if (alt->family != AF_INET) { - send_notification_nbr(nbr, S_UNSUP_ADDR, aw->msgid, aw->type); - return (-1); - } - - buf += sizeof(*alt); - len -= sizeof(*alt); - address = (struct in_addr *)buf; - - while (len >= sizeof(address)) { - ldpe_imsg_compose_lde(IMSG_ADDRESS_DEL, nbr->peerid, 0, - address, sizeof(*address)); - - address++; - len -= sizeof(*address); - } - - return (ntohs(aw->length)); -} diff --git a/usr.sbin/ldpd/hello.c b/usr.sbin/ldpd/hello.c index d6cb184727e..4a506c1d6d2 100644 --- a/usr.sbin/ldpd/hello.c +++ b/usr.sbin/ldpd/hello.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hello.c,v 1.6 2010/05/26 13:56:07 nicm Exp $ */ +/* $OpenBSD: hello.c,v 1.7 2010/11/04 09:52:16 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -36,11 +36,10 @@ #include "log.h" #include "ldpe.h" -struct hello_prms_tlv *tlv_decode_hello_prms(char *, u_int16_t); -int tlv_decode_opt_hello_prms(char *, u_int16_t, - struct in_addr *, u_int32_t *); -int gen_hello_prms_tlv(struct iface *, struct ibuf *, - u_int16_t); +int tlv_decode_hello_prms(char *, u_int16_t, u_int16_t *, u_int16_t *); +int tlv_decode_opt_hello_prms(char *, u_int16_t, struct in_addr *, + u_int32_t *); +int gen_hello_prms_tlv(struct iface *, struct ibuf *, u_int16_t); int send_hello(struct iface *iface) @@ -82,41 +81,50 @@ send_hello(struct iface *iface) void recv_hello(struct iface *iface, struct in_addr src, char *buf, u_int16_t len) { - struct ldp_msg *hello; - u_int32_t messageid; + struct ldp_msg hello; + struct ldp_hdr ldp; struct nbr *nbr = NULL; - struct hello_prms_tlv *cpt; - struct ldp_hdr *ldp; struct in_addr address; u_int32_t conf_number; + u_int16_t holdtime, flags; + int r; - ldp = (struct ldp_hdr *)buf; - + bcopy(buf, &ldp, sizeof(ldp)); buf += LDP_HDR_SIZE; len -= LDP_HDR_SIZE; - hello = (struct ldp_msg *)buf; - - if ((len - TLV_HDR_LEN) < ntohs(hello->length)) - return; - - messageid = hello->msgid; - + bcopy(buf, &hello, sizeof(hello)); buf += sizeof(struct ldp_msg); len -= sizeof(struct ldp_msg); - cpt = tlv_decode_hello_prms(buf, len); - if (cpt == NULL) + r = tlv_decode_hello_prms(buf, len, &holdtime, &flags); + if (r == -1) { + address.s_addr = ldp.lsr_id; + log_debug("recv_hello: neighbor %s: failed to decode params", + inet_ntoa(address)); return; + } - buf += sizeof(struct hello_prms_tlv); - len -= sizeof(struct hello_prms_tlv); + buf += r; + len -= r; - tlv_decode_opt_hello_prms(buf, len, &address, &conf_number); + r = tlv_decode_opt_hello_prms(buf, len, &address, &conf_number); + if (r == -1) { + address.s_addr = ldp.lsr_id; + log_debug("recv_hello: neighbor %s: failed to decode " + "optional params", inet_ntoa(address)); + return; + } + if (r != len) { + address.s_addr = ldp.lsr_id; + log_debug("recv_hello: neighbor %s: unexpected data in message", + inet_ntoa(address)); + return; + } - nbr = nbr_find_ldpid(iface, ldp->lsr_id, ldp->lspace_id); + nbr = nbr_find_ldpid(iface, ldp.lsr_id, ldp.lspace_id); if (!nbr) { - nbr = nbr_new(ldp->lsr_id, ldp->lspace_id, iface); + nbr = nbr_new(ldp.lsr_id, ldp.lspace_id, iface); /* set neighbor parameters */ if (address.s_addr == INADDR_ANY) @@ -124,22 +132,22 @@ recv_hello(struct iface *iface, struct in_addr src, char *buf, u_int16_t len) else nbr->addr.s_addr = address.s_addr; - nbr->hello_type = cpt->reserved; + nbr->hello_type = flags; - if (cpt->holdtime == 0) { + if (holdtime == 0) { /* XXX: lacks support for targeted hellos */ if (iface->holdtime < LINK_DFLT_HOLDTIME) nbr->holdtime = iface->holdtime; else nbr->holdtime = LINK_DFLT_HOLDTIME; - } else if (cpt->holdtime == INFINITE_HOLDTIME) { + } else if (holdtime == INFINITE_HOLDTIME) { /* No timeout for this neighbor */ nbr->holdtime = iface->holdtime; } else { - if (iface->holdtime < ntohs(cpt->holdtime)) + if (iface->holdtime < holdtime) nbr->holdtime = iface->holdtime; else - nbr->holdtime = ntohs(cpt->holdtime); + nbr->holdtime = holdtime; } } @@ -163,60 +171,64 @@ gen_hello_prms_tlv(struct iface *iface, struct ibuf *buf, u_int16_t size) parms.length = htons(size); /* XXX */ parms.holdtime = htons(iface->holdtime); - parms.reserved = 0; + parms.flags = 0; return (ibuf_add(buf, &parms, sizeof(parms))); } -struct hello_prms_tlv * -tlv_decode_hello_prms(char *buf, u_int16_t len) +int +tlv_decode_hello_prms(char *buf, u_int16_t len, u_int16_t *holdtime, + u_int16_t *flags) { - struct hello_prms_tlv *tlv; + struct hello_prms_tlv tlv; - tlv = (struct hello_prms_tlv *)buf; + if (len < sizeof(tlv)) + return (-1); + bcopy(buf, &tlv, sizeof(tlv)); - if (len < sizeof(*tlv) || ntohs(tlv->length) != - (sizeof(tlv->holdtime) + sizeof(tlv->reserved))) - return (NULL); + if (ntohs(tlv.length) != sizeof(tlv) - TLV_HDR_LEN) + return (-1); - if ((tlv->type & ~UNKNOWN_FLAGS_MASK) != htons(TLV_TYPE_COMMONHELLO)) - return (NULL); + if (tlv.type != htons(TLV_TYPE_COMMONHELLO)) + return (-1); - if ((tlv->type & UNKNOWN_FLAGS_MASK) != 0) - return (NULL); + *holdtime = ntohs(tlv.holdtime); + *flags = ntohs(tlv.flags); - return (tlv); + return (sizeof(tlv)); } int tlv_decode_opt_hello_prms(char *buf, u_int16_t len, struct in_addr *addr, u_int32_t *conf_number) { - struct hello_opt_parms_tlv *tlv; + struct hello_opt_parms_tlv tlv; + int cons = 0; bzero(addr, sizeof(*addr)); *conf_number = 0; - while (len >= sizeof(*tlv)) { - tlv = (struct hello_opt_parms_tlv *)buf; + while (len >= sizeof(tlv)) { + bcopy(buf, &tlv, sizeof(tlv)); - if (tlv->length < sizeof(u_int32_t)) + if (ntohs(tlv.length) < sizeof(u_int32_t)) return (-1); - switch (ntohs(tlv->type)) { + switch (ntohs(tlv.type)) { case TLV_TYPE_IPV4TRANSADDR: - addr->s_addr = tlv->value; + addr->s_addr = tlv.value; break; case TLV_TYPE_CONFIG: - *conf_number = ntohl(tlv->value); + *conf_number = ntohl(tlv.value); break; default: return (-1); } - len -= sizeof(*tlv); - buf += sizeof(*tlv); + len -= sizeof(tlv); + buf += sizeof(tlv); + cons += sizeof(cons); } - return (0); + return (cons); } diff --git a/usr.sbin/ldpd/init.c b/usr.sbin/ldpd/init.c index 31556a670e2..2004bc71bcf 100644 --- a/usr.sbin/ldpd/init.c +++ b/usr.sbin/ldpd/init.c @@ -1,4 +1,4 @@ -/* $OpenBSD: init.c,v 1.5 2010/05/26 13:56:07 nicm Exp $ */ +/* $OpenBSD: init.c,v 1.6 2010/11/04 09:52:16 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -71,37 +71,38 @@ send_init(struct nbr *nbr) int recv_init(struct nbr *nbr, char *buf, u_int16_t len) { - struct ldp_msg *init; - struct sess_prms_tlv *sess_tlv; + struct ldp_msg init; + struct sess_prms_tlv sess; log_debug("recv_init: neighbor ID %s", inet_ntoa(nbr->id)); - init = (struct ldp_msg *)buf; - - if ((len - TLV_HDR_LEN) < ntohs(init->length)) { - session_shutdown(nbr, S_BAD_MSG_LEN, init->msgid, init->type); - return (-1); - } + bcopy(buf, &init, sizeof(init)); buf += sizeof(struct ldp_msg); len -= sizeof(struct ldp_msg); - sess_tlv = (struct sess_prms_tlv *)buf; + if (len < SESS_PRMS_SIZE) { + session_shutdown(nbr, S_BAD_MSG_LEN, init.msgid, init.type); + return (-1); + } + bcopy(buf, &sess, sizeof(sess)); - if (len < SESS_PRMS_SIZE || - ntohs(sess_tlv->length) != (SESS_PRMS_SIZE - TLV_HDR_LEN)) { - session_shutdown(nbr, S_BAD_TLV_LEN, init->msgid, init->type); + if (ntohs(sess.length) != SESS_PRMS_SIZE - TLV_HDR_LEN || + ntohs(sess.length) != len - TLV_HDR_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, init.msgid, init.type); return (-1); } - if (nbr->iface->keepalive < ntohs(sess_tlv->keepalive_time)) + /* ATM and Frame Relay optional attributes not supported */ + + if (nbr->iface->keepalive < ntohs(sess.keepalive_time)) nbr->keepalive = nbr->iface->keepalive; else - nbr->keepalive = ntohs(sess_tlv->keepalive_time); + nbr->keepalive = ntohs(sess.keepalive_time); nbr_fsm(nbr, NBR_EVT_INIT_RCVD); - return (ntohs(init->length)); + return (ntohs(init.length)); } int diff --git a/usr.sbin/ldpd/keepalive.c b/usr.sbin/ldpd/keepalive.c index 2e9152a1b4e..933e3093aaf 100644 --- a/usr.sbin/ldpd/keepalive.c +++ b/usr.sbin/ldpd/keepalive.c @@ -1,4 +1,4 @@ -/* $OpenBSD: keepalive.c,v 1.6 2010/05/26 13:56:07 nicm Exp $ */ +/* $OpenBSD: keepalive.c,v 1.7 2010/11/04 09:52:16 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -63,22 +63,19 @@ send_keepalive(struct nbr *nbr) int recv_keepalive(struct nbr *nbr, char *buf, u_int16_t len) { - struct ldp_msg *ka; + struct ldp_msg ka; - ka = (struct ldp_msg *)buf; + bcopy(buf, &ka, sizeof(ka)); - if ((len - TLV_HDR_LEN) < ntohs(ka->length)) { - session_shutdown(nbr, S_BAD_MSG_LEN, ka->msgid, ka->type); + if (len != LDP_MSG_LEN) { + session_shutdown(nbr, S_BAD_MSG_LEN, ka.msgid, ka.type); return (-1); } - buf += sizeof(struct ldp_msg); - len -= sizeof(struct ldp_msg); - if (nbr->state != NBR_STA_OPER) nbr_fsm(nbr, NBR_EVT_KEEPALIVE_RCVD); else nbr_fsm(nbr, NBR_EVT_PDU_RCVD); - return (ntohs(ka->length)); + return (ntohs(ka.length)); } diff --git a/usr.sbin/ldpd/labelmapping.c b/usr.sbin/ldpd/labelmapping.c index eb60ecd1e97..8b325cbb908 100644 --- a/usr.sbin/ldpd/labelmapping.c +++ b/usr.sbin/ldpd/labelmapping.c @@ -1,4 +1,4 @@ -/* $OpenBSD: labelmapping.c,v 1.16 2010/10/26 12:59:03 claudio Exp $ */ +/* $OpenBSD: labelmapping.c,v 1.17 2010/11/04 09:52:16 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -41,10 +41,10 @@ void gen_label_tlv(struct ibuf *, u_int32_t); void gen_reqid_tlv(struct ibuf *, u_int32_t); void gen_fec_tlv(struct ibuf *, struct in_addr, u_int8_t); -u_int32_t tlv_decode_label(struct label_tlv *); -u_int32_t tlv_decode_reqid(struct reqid_tlv *); -int tlv_decode_fec_elm(char *, u_int16_t, u_int8_t *, u_int32_t *, - u_int8_t *); +int tlv_decode_label(char *, u_int16_t, u_int32_t *); +int tlv_decode_reqid(char *, u_int16_t, u_int32_t *); +int tlv_decode_fec_elm(char *, u_int16_t, u_int8_t *, u_int32_t *, + u_int8_t *); /* Label Mapping Message */ void @@ -91,60 +91,60 @@ send_labelmapping(struct nbr *nbr) int recv_labelmapping(struct nbr *nbr, char *buf, u_int16_t len) { - struct ldp_msg *lm; - struct fec_tlv *ft; - struct label_tlv *lt; - struct map map; - int feclen, tlen; - u_int8_t addr_type; - - if (nbr->state != NBR_STA_OPER) - return (-1); - - lm = (struct ldp_msg *)buf; - - if ((len - TLV_HDR_LEN) < ntohs(lm->length)) { - session_shutdown(nbr, S_BAD_MSG_LEN, lm->msgid, lm->type); + struct ldp_msg lm; + struct fec_tlv ft; + struct map map; + u_int32_t label; + int feclen, lbllen, tlen; + u_int8_t addr_type; + + if (nbr->state != NBR_STA_OPER) { + log_debug("recv_labelmapping: neighbor ID %s not operational", + inet_ntoa(nbr->id)); return (-1); } + bcopy(buf, &lm, sizeof(lm)); + buf += sizeof(struct ldp_msg); len -= sizeof(struct ldp_msg); - ft = (struct fec_tlv *)buf; - - if (len < sizeof(*ft) || - (len - TLV_HDR_LEN) < ntohs(ft->length)) { - session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); + if (len < sizeof(ft)) { + session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, lm.type); return (-1); } - feclen = ntohs(ft->length); - buf += sizeof(struct fec_tlv); - len -= sizeof(struct fec_tlv); + bcopy(buf, &ft, sizeof(ft)); + feclen = ntohs(ft.length); - if (len < feclen + LABEL_TLV_LEN) { - session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); + if (feclen > len - TLV_HDR_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, lm.type); return (-1); } - bzero(&map, sizeof(map)); - map.messageid = lm->msgid; + buf += TLV_HDR_LEN; /* just advance to the end of the fec header */ + len -= TLV_HDR_LEN; - lt = (struct label_tlv *)(buf + feclen); - map.label = tlv_decode_label(lt); - if (map.label == NO_LABEL) { - session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, lm->type); + lbllen = tlv_decode_label(buf + feclen, len - feclen, &label); + if (lbllen == -1) { + session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, lm.type); return (-1); } - /* TODO opt label request msg id */ + if (label == NO_LABEL) { + session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, lm.type); + return (-1); + } + + /* TODO opt label request msg id, hop cnt and path vektor TLV */ + bzero(&map, sizeof(map)); + map.messageid = lm.msgid; + map.label = label; do { if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type, &map.prefix.s_addr, &map.prefixlen)) == -1 || addr_type == FEC_WILDCARD) { - session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, - lm->type); + session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, lm.type); return (-1); } @@ -157,7 +157,7 @@ recv_labelmapping(struct nbr *nbr, char *buf, u_int16_t len) nbr_fsm(nbr, NBR_EVT_PDU_RCVD); - return (ntohs(lm->length)); + return (ntohs(lm.length)); } /* Label Request Message */ @@ -200,46 +200,48 @@ send_labelrequest(struct nbr *nbr) int recv_labelrequest(struct nbr *nbr, char *buf, u_int16_t len) { - struct ldp_msg *lr; - struct fec_tlv *ft; - struct map map; - int feclen, tlen; - u_int8_t addr_type; - - if (nbr->state != NBR_STA_OPER) - return (-1); - - lr = (struct ldp_msg *)buf; + struct ldp_msg lr; + struct fec_tlv ft; + struct map map; + int feclen, tlen; + u_int8_t addr_type; - if ((len - TLV_HDR_LEN) < ntohs(lr->length)) { - session_shutdown(nbr, S_BAD_MSG_LEN, lr->msgid, lr->type); + if (nbr->state != NBR_STA_OPER) { + log_debug("recv_labelrequest: neighbor ID %s not operational", + inet_ntoa(nbr->id)); return (-1); } + bcopy(buf, &lr, sizeof(lr)); + buf += sizeof(struct ldp_msg); len -= sizeof(struct ldp_msg); - ft = (struct fec_tlv *)buf; + if (len < sizeof(ft)) { + session_shutdown(nbr, S_BAD_MSG_LEN, lr.msgid, lr.type); + return (-1); + } + + bcopy(buf, &ft, sizeof(ft)); + feclen = ntohs(ft.length); - if (len < sizeof(*ft) || - (len - TLV_HDR_LEN) < ntohs(ft->length)) { - session_shutdown(nbr, S_BAD_TLV_LEN, lr->msgid, lr->type); + if (feclen > len - TLV_HDR_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, lr.msgid, lr.type); return (-1); } - feclen = ntohs(ft->length); - buf += sizeof(struct fec_tlv); - len -= sizeof(struct fec_tlv); + buf += TLV_HDR_LEN; /* just advance to the end of the fec header */ + len -= TLV_HDR_LEN; - bzero(&map, sizeof(map)); - map.messageid = lr->msgid; + /* TODO opt hop cnt and path vektor TLV */ + bzero(&map, sizeof(map)); + map.messageid = lr.msgid; do { if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type, &map.prefix.s_addr, &map.prefixlen)) == -1 || addr_type == FEC_WILDCARD) { - session_shutdown(nbr, S_BAD_TLV_VAL, lr->msgid, - lr->type); + session_shutdown(nbr, S_BAD_TLV_VAL, lr.msgid, lr.type); return (-1); } @@ -252,7 +254,7 @@ recv_labelrequest(struct nbr *nbr, char *buf, u_int16_t len) nbr_fsm(nbr, NBR_EVT_PDU_RCVD); - return (ntohs(lr->length)); + return (ntohs(lr.length)); } /* Label Withdraw Message */ @@ -303,70 +305,70 @@ send_labelwithdraw(struct nbr *nbr) int recv_labelwithdraw(struct nbr *nbr, char *buf, u_int16_t len) { - struct map map; - struct ldp_msg *lw; - struct fec_tlv *ft; - u_int32_t optlabel = NO_LABEL; - int feclen, tlen, numfec = 0; - u_int8_t addr_type; - - if (nbr->state != NBR_STA_OPER) - return (-1); - - lw = (struct ldp_msg *)buf; + struct map map; + struct ldp_msg lw; + struct fec_tlv ft; + u_int32_t label = NO_LABEL; + int feclen, tlen, numfec = 0; + u_int8_t addr_type; - if ((len - TLV_HDR_LEN) < ntohs(lw->length)) { - session_shutdown(nbr, S_BAD_MSG_LEN, lw->msgid, lw->type); + if (nbr->state != NBR_STA_OPER) { + log_debug("recv_labelwithdraw: neighbor ID %s not operational", + inet_ntoa(nbr->id)); return (-1); } + bcopy(buf, &lw, sizeof(lw)); + buf += sizeof(struct ldp_msg); len -= sizeof(struct ldp_msg); - ft = (struct fec_tlv *)buf; + if (len < sizeof(ft)) { + session_shutdown(nbr, S_BAD_MSG_LEN, lw.msgid, lw.type); + return (-1); + } + + bcopy(buf, &ft, sizeof(ft)); + feclen = ntohs(ft.length); - if (len < sizeof(*ft) || - (len - TLV_HDR_LEN) < ntohs(ft->length)) { - session_shutdown(nbr, S_BAD_TLV_LEN, lw->msgid, lw->type); + if (feclen > len - TLV_HDR_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, lw.msgid, lw.type); return (-1); } - feclen = ntohs(ft->length); - buf += sizeof(struct fec_tlv); - len -= sizeof(struct fec_tlv); + buf += TLV_HDR_LEN; /* just advance to the end of the fec header */ + len -= TLV_HDR_LEN; - /* release may include optional label */ - if (len >= feclen) { - struct label_tlv *lt; - - lt = (struct label_tlv *)(buf + feclen); - optlabel = tlv_decode_label(lt); - if (optlabel == NO_LABEL) { - session_shutdown(nbr, S_BAD_TLV_VAL, lw->msgid, - lw->type); + /* withdraw may include optional label */ + if (len > feclen) { + int r; + + r = tlv_decode_label(buf + feclen, len - feclen, &label); + if (r == -1 || len != feclen + r) { + session_shutdown(nbr, S_BAD_TLV_VAL, lw.msgid, + lw.type); return (-1); } } bzero(&map, sizeof(map)); - map.messageid = lw->msgid; - if (optlabel != NO_LABEL) { - map.label = optlabel; + map.messageid = lw.msgid; + if (label != NO_LABEL) { + map.label = label; map.flags = F_MAP_OPTLABEL; } do { if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type, &map.prefix.s_addr, &map.prefixlen)) == -1) { - session_shutdown(nbr, S_BAD_TLV_VAL, lw->msgid, - lw->type); + session_shutdown(nbr, S_BAD_TLV_VAL, lw.msgid, lw.type); return (-1); } if (addr_type == FEC_WILDCARD) { /* Wildcard FEC must be the only FEC element */ if (numfec != 0) { - session_shutdown(nbr, S_BAD_TLV_VAL, lw->msgid, - lw->type); + session_shutdown(nbr, S_BAD_TLV_VAL, lw.msgid, + lw.type); return (-1); } map.prefix.s_addr = 0; @@ -376,8 +378,8 @@ recv_labelwithdraw(struct nbr *nbr, char *buf, u_int16_t len) } else { /* Wildcard FEC must be the only FEC element */ if (numfec == -1) { - session_shutdown(nbr, S_BAD_TLV_VAL, lw->msgid, - lw->type); + session_shutdown(nbr, S_BAD_TLV_VAL, lw.msgid, + lw.type); return (-1); } numfec++; @@ -393,7 +395,7 @@ recv_labelwithdraw(struct nbr *nbr, char *buf, u_int16_t len) nbr_fsm(nbr, NBR_EVT_PDU_RCVD); - return (ntohs(lw->length)); + return (ntohs(lw.length)); } /* Label Release Message */ @@ -444,70 +446,70 @@ send_labelrelease(struct nbr *nbr) int recv_labelrelease(struct nbr *nbr, char *buf, u_int16_t len) { - struct map map; - struct ldp_msg *lr; - struct fec_tlv *ft; - u_int32_t optlabel = NO_LABEL; - int feclen, tlen, numfec = 0; - u_int8_t addr_type; - - if (nbr->state != NBR_STA_OPER) - return (-1); - - lr = (struct ldp_msg *)buf; + struct map map; + struct ldp_msg lr; + struct fec_tlv ft; + u_int32_t label = NO_LABEL; + int feclen, tlen, numfec = 0; + u_int8_t addr_type; - if ((len - TLV_HDR_LEN) < ntohs(lr->length)) { - session_shutdown(nbr, S_BAD_MSG_LEN, lr->msgid, lr->type); + if (nbr->state != NBR_STA_OPER) { + log_debug("recv_labelrelease: neighbor ID %s not operational", + inet_ntoa(nbr->id)); return (-1); } + bcopy(buf, &lr, sizeof(lr)); + buf += sizeof(struct ldp_msg); len -= sizeof(struct ldp_msg); - ft = (struct fec_tlv *)buf; + if (len < sizeof(ft)) { + session_shutdown(nbr, S_BAD_MSG_LEN, lr.msgid, lr.type); + return (-1); + } + + bcopy(buf, &ft, sizeof(ft)); + feclen = ntohs(ft.length); - if (len < sizeof(*ft) || - (len - TLV_HDR_LEN) < ntohs(ft->length)) { - session_shutdown(nbr, S_BAD_TLV_LEN, lr->msgid, lr->type); + if (feclen > len - TLV_HDR_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, lr.msgid, lr.type); return (-1); } - feclen = ntohs(ft->length); - buf += sizeof(struct fec_tlv); - len -= sizeof(struct fec_tlv); + buf += TLV_HDR_LEN; /* just advance to the end of the fec header */ + len -= TLV_HDR_LEN; /* release may include optional label */ - if (len >= feclen) { - struct label_tlv *lt; - - lt = (struct label_tlv *)(buf + feclen); - optlabel = tlv_decode_label(lt); - if (optlabel == NO_LABEL) { - session_shutdown(nbr, S_BAD_TLV_VAL, lr->msgid, - lr->type); + if (len > feclen) { + int r; + + r = tlv_decode_label(buf + feclen, len - feclen, &label); + if (r == -1 || len != feclen + r) { + session_shutdown(nbr, S_BAD_TLV_VAL, lr.msgid, + lr.type); return (-1); } } bzero(&map, sizeof(map)); - map.messageid = lr->msgid; - if (optlabel != NO_LABEL) { - map.label = optlabel; + map.messageid = lr.msgid; + if (label != NO_LABEL) { + map.label = label; map.flags = F_MAP_OPTLABEL; } do { if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type, &map.prefix.s_addr, &map.prefixlen)) == -1) { - session_shutdown(nbr, S_BAD_TLV_VAL, lr->msgid, - lr->type); + session_shutdown(nbr, S_BAD_TLV_VAL, lr.msgid, lr.type); return (-1); } if (addr_type == FEC_WILDCARD) { /* Wildcard FEC must be the only FEC element */ if (numfec != 0) { - session_shutdown(nbr, S_BAD_TLV_VAL, lr->msgid, - lr->type); + session_shutdown(nbr, S_BAD_TLV_VAL, lr.msgid, + lr.type); return (-1); } map.prefix.s_addr = 0; @@ -517,8 +519,8 @@ recv_labelrelease(struct nbr *nbr, char *buf, u_int16_t len) } else { /* Wildcard FEC must be the only FEC element */ if (numfec == -1) { - session_shutdown(nbr, S_BAD_TLV_VAL, lr->msgid, - lr->type); + session_shutdown(nbr, S_BAD_TLV_VAL, lr.msgid, + lr.type); return (-1); } map.flags &= ~F_MAP_WILDCARD; @@ -533,7 +535,7 @@ recv_labelrelease(struct nbr *nbr, char *buf, u_int16_t len) nbr_fsm(nbr, NBR_EVT_PDU_RCVD); - return (ntohs(lr->length)); + return (ntohs(lr.length)); } /* Label Abort Req Message */ @@ -563,28 +565,76 @@ send_labelabortreq(struct nbr *nbr) int recv_labelabortreq(struct nbr *nbr, char *buf, u_int16_t len) { - struct ldp_msg *la; + struct map map; + struct ldp_msg la; + struct fec_tlv ft; + int feclen, tlen; + u_int8_t addr_type; + + if (nbr->state != NBR_STA_OPER) { + log_debug("recv_labelabortreq: neighbor ID %s not operational", + inet_ntoa(nbr->id)); + return (-1); + } log_debug("recv_labelabortreq: neighbor ID %s", inet_ntoa(nbr->id)); - if (nbr->state != NBR_STA_OPER) + bcopy(buf, &la, sizeof(la)); + + buf += sizeof(struct ldp_msg); + len -= sizeof(struct ldp_msg); + + if (len < sizeof(ft)) { + session_shutdown(nbr, S_BAD_MSG_LEN, la.msgid, la.type); return (-1); + } - la = (struct ldp_msg *)buf; + bcopy(buf, &ft, sizeof(ft)); + feclen = ntohs(ft.length); - if ((len - TLV_HDR_LEN) < ntohs(la->length)) { - session_shutdown(nbr, S_BAD_MSG_LEN, la->msgid, la->type); + if (feclen > len - TLV_HDR_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, la.msgid, la.type); return (-1); } - buf += sizeof(struct ldp_msg); - len -= sizeof(struct ldp_msg); + buf += TLV_HDR_LEN; /* just advance to the end of the fec header */ + len -= TLV_HDR_LEN; + + bzero(&map, sizeof(map)); + map.messageid = la.msgid; - /* XXX XXX XXX */ + /* abort request may include optional request msg id */ + if (len > feclen) { + int r; + + r = tlv_decode_reqid(buf + feclen, len - feclen, + &map.requestid); + if (r == -1 || len != feclen + r) { + session_shutdown(nbr, S_BAD_TLV_VAL, la.msgid, + la.type); + return (-1); + } + map.flags = F_MAP_REQ_ID; + } + + do { + if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type, + &map.prefix.s_addr, &map.prefixlen)) == -1 || + addr_type == FEC_WILDCARD) { + session_shutdown(nbr, S_BAD_TLV_VAL, la.msgid, la.type); + return (-1); + } + + ldpe_imsg_compose_lde(IMSG_LABEL_ABORT, nbr->peerid, 0, &map, + sizeof(map)); + + buf += tlen; + feclen -= tlen; + } while (feclen > 0); nbr_fsm(nbr, NBR_EVT_PDU_RCVD); - return (ntohs(la->length)); + return (ntohs(la.length)); } /* Other TLV related functions */ @@ -600,16 +650,24 @@ gen_label_tlv(struct ibuf *buf, u_int32_t label) ibuf_add(buf, <, sizeof(lt)); } -u_int32_t -tlv_decode_label(struct label_tlv *lt) +int +tlv_decode_label(char *buf, u_int16_t len, u_int32_t *label) { - if (lt->type != htons(TLV_TYPE_GENERICLABEL)) - return (NO_LABEL); + struct label_tlv lt; + + if (len < sizeof(lt)) + return (-1); + bcopy(buf, <, sizeof(lt)); + + if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_LEN) + return (-1); - if (ntohs(lt->length) != sizeof(lt->label)) - return (NO_LABEL); + if (lt.type != htons(TLV_TYPE_GENERICLABEL)) + return (-1); + + *label = ntohl(lt.label); - return (ntohl(lt->label)); + return (sizeof(lt)); } void @@ -624,18 +682,27 @@ gen_reqid_tlv(struct ibuf *buf, u_int32_t reqid) ibuf_add(buf, &rt, sizeof(rt)); } -u_int32_t -tlv_decode_reqid(struct reqid_tlv *rt) +int +tlv_decode_reqid(char *buf, u_int16_t len, u_int32_t *reqid) { - if (rt->type != htons(TLV_TYPE_LABELREQUEST)) - return (NO_LABEL); + struct reqid_tlv rt; + + if (len < sizeof(rt)) + return (-1); + bcopy(buf, &rt, sizeof(rt)); - if (ntohs(rt->length) != sizeof(rt->reqid)) - return (NO_LABEL); + if (ntohs(rt.length) != sizeof(rt) - TLV_HDR_LEN) + return (-1); + + if (rt.type != htons(TLV_TYPE_LABELREQUEST)) + return (-1); - return (ntohl(rt->reqid)); + *reqid = ntohl(rt.reqid); + + return (sizeof(rt)); } + void gen_fec_tlv(struct ibuf *buf, struct in_addr prefix, u_int8_t prefixlen) { diff --git a/usr.sbin/ldpd/ldp.h b/usr.sbin/ldpd/ldp.h index 40ca600f160..83a3a179e01 100644 --- a/usr.sbin/ldpd/ldp.h +++ b/usr.sbin/ldpd/ldp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldp.h,v 1.6 2010/10/26 12:59:03 claudio Exp $ */ +/* $OpenBSD: ldp.h,v 1.7 2010/11/04 09:52:16 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -103,7 +103,7 @@ struct ldp_msg { u_int32_t msgid; /* Mandatory Parameters */ /* Optional Parameters */ -}; +} __packed; #define LDP_MSG_LEN 8 #define TLV_HDR_LEN 4 @@ -119,9 +119,11 @@ struct hello_prms_tlv { u_int16_t type; u_int16_t length; u_int16_t holdtime; - u_int16_t reserved; + u_int16_t flags; }; +#define HELLO_PRMS_SIZE 8 + #define S_SUCCESS 0x00000000 #define S_BAD_LDP_ID 0x80000001 #define S_BAD_PROTO_VER 0x80000002 @@ -159,7 +161,7 @@ struct sess_prms_tlv { u_int16_t max_pdu_len; u_int32_t lsr_id; u_int16_t lspace_id; -}; +} __packed; #define SESS_PRMS_SIZE 18 @@ -169,7 +171,7 @@ struct status_tlv { u_int32_t status_code; u_int32_t msg_id; u_int16_t msg_type; -}; +} __packed; #define STATUS_SIZE 14 #define STATUS_TLV_LEN 10 @@ -180,7 +182,7 @@ struct address_list_tlv { u_int16_t length; u_int16_t family; /* address entries */ -}; +} __packed; #define BASIC_LABEL_MAP_LEN 24 diff --git a/usr.sbin/ldpd/ldpe.h b/usr.sbin/ldpd/ldpe.h index 4691859adf8..ff651b7a9d8 100644 --- a/usr.sbin/ldpd/ldpe.h +++ b/usr.sbin/ldpd/ldpe.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpe.h,v 1.12 2010/10/26 12:22:35 claudio Exp $ */ +/* $OpenBSD: ldpe.h,v 1.13 2010/11/04 09:52:16 claudio Exp $ */ /* * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> @@ -95,7 +95,6 @@ int recv_notification(struct nbr *, char *, u_int16_t); void send_address(struct nbr *, struct iface *); int recv_address(struct nbr *, char *, u_int16_t); void send_address_withdraw(struct nbr *, struct iface *); -int recv_address_withdraw(struct nbr *, char *, u_int16_t); /* labelmapping.c */ #define PREFIX_SIZE(x) (((x) + 7) / 8) diff --git a/usr.sbin/ldpd/notification.c b/usr.sbin/ldpd/notification.c index 52650908a09..0c9b1b06166 100644 --- a/usr.sbin/ldpd/notification.c +++ b/usr.sbin/ldpd/notification.c @@ -1,4 +1,4 @@ -/* $OpenBSD: notification.c,v 1.7 2010/05/26 13:56:08 nicm Exp $ */ +/* $OpenBSD: notification.c,v 1.8 2010/11/04 09:52:16 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -80,44 +80,46 @@ send_notification(u_int32_t status, struct iface *iface, u_int32_t msgid, int recv_notification(struct nbr *nbr, char *buf, u_int16_t len) { - struct ldp_msg *not; - struct status_tlv *st; + struct ldp_msg not; + struct status_tlv st; log_debug("recv_notification: neighbor ID %s", inet_ntoa(nbr->id)); - not = (struct ldp_msg *)buf; - - if ((len - TLV_HDR_LEN) < ntohs(not->length)) { - session_shutdown(nbr, S_BAD_MSG_LEN, not->msgid, not->type); - return (-1); - } + bcopy(buf, ¬, sizeof(not)); buf += sizeof(struct ldp_msg); len -= sizeof(struct ldp_msg); - st = (struct status_tlv *)buf; + if (len < STATUS_SIZE) { + session_shutdown(nbr, S_BAD_MSG_LEN, not.msgid, not.type); + return (-1); + } + bcopy(buf, &st, sizeof(st)); - if (len < STATUS_SIZE || - (STATUS_SIZE - TLV_HDR_LEN) != ntohs(st->length)) { - session_shutdown(nbr, S_BAD_TLV_LEN, not->msgid, not->type); + if (ntohs(st.length) > STATUS_SIZE - TLV_HDR_LEN || + ntohs(st.length) > len - TLV_HDR_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, not.msgid, not.type); return (-1); } - if (st->status_code & htonl(STATUS_FATAL)) + /* TODO optional parameters: ext status, returned PDU and msg */ + + if (st.status_code & htonl(STATUS_FATAL)) log_warnx("recieved notification from neighbor %s: %s", inet_ntoa(nbr->id), - notification_name(ntohl(st->status_code))); + notification_name(ntohl(st.status_code))); else log_debug("recieved non-fatal notification from neighbor " "%s: %s", inet_ntoa(nbr->id), - notification_name(ntohl(st->status_code))); + notification_name(ntohl(st.status_code))); - if (st->status_code & htonl(STATUS_FATAL)) { + if (st.status_code & htonl(STATUS_FATAL)) { nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); return (-1); } + /* XXX in some cases we should inform the RDE about non-fatal ones */ - return (ntohs(not->length)); + return (ntohs(not.length)); } int diff --git a/usr.sbin/ldpd/packet.c b/usr.sbin/ldpd/packet.c index 12613b7c454..932e1daad3e 100644 --- a/usr.sbin/ldpd/packet.c +++ b/usr.sbin/ldpd/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.12 2010/05/26 13:56:08 nicm Exp $ */ +/* $OpenBSD: packet.c,v 1.13 2010/11/04 09:52:16 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -115,8 +115,8 @@ disc_recv_packet(int fd, short event, void *bula) struct msghdr msg; struct iovec iov; struct ldpd_conf *xconf = bula; - struct ldp_hdr *ldp_hdr; - struct ldp_msg *ldp_msg; + struct ldp_hdr ldp_hdr; + struct ldp_msg ldp_msg; struct iface *iface; char *buf; struct cmsghdr *cmsg; @@ -168,33 +168,34 @@ disc_recv_packet(int fd, short event, void *bula) log_debug("disc_recv_packet: bad packet size"); return; } - ldp_hdr = (struct ldp_hdr *)buf; + bcopy(buf, &ldp_hdr, sizeof(ldp_hdr)); - if (ntohs(ldp_hdr->version) != LDP_VERSION) { + if (ntohs(ldp_hdr.version) != LDP_VERSION) { log_debug("dsc_recv_packet: invalid LDP version %d", - ldp_hdr->version); + ldp_hdr.version); return; } - if ((l = ldp_hdr_sanity_check(ldp_hdr, len, iface)) == -1) + if ((l = ldp_hdr_sanity_check(&ldp_hdr, len, iface)) == -1) return; if (l > len) { log_debug("disc_recv_packet: invalid LDP packet length %d", - ntohs(ldp_hdr->length)); + ntohs(ldp_hdr.length)); return; } - ldp_msg = (struct ldp_msg *)(buf + LDP_HDR_SIZE); - if (len < LDP_HDR_SIZE + LDP_MSG_LEN) { log_debug("disc_recv_packet: invalid LDP packet length %d", - ntohs(ldp_hdr->length)); + ntohs(ldp_hdr.length)); return; } + bcopy(buf + LDP_HDR_SIZE, &ldp_msg, sizeof(ldp_msg)); + + /* switch LDP packet type */ - switch (ntohs(ldp_msg->type)) { + switch (ntohs(ldp_msg.type)) { case MSG_TYPE_HELLO: recv_hello(iface, src.sin_addr, buf, len); break; @@ -373,10 +374,8 @@ session_read(int fd, short event, void *arg) msg_size = recv_keepalive(nbr, pdu, pdu_len); break; case MSG_TYPE_ADDR: - msg_size = recv_address(nbr, pdu, pdu_len); - break; case MSG_TYPE_ADDRWITHDRAW: - msg_size = recv_address_withdraw(nbr, pdu, pdu_len); + msg_size = recv_address(nbr, pdu, pdu_len); break; case MSG_TYPE_LABELMAPPING: msg_size = recv_labelmapping(nbr, pdu, pdu_len); @@ -393,8 +392,8 @@ session_read(int fd, short event, void *arg) case MSG_TYPE_LABELABORTREQ: case MSG_TYPE_HELLO: default: - log_debug("session_read: unknown LDP packet type " - "interface %s", iface->name); + log_debug("session_read: unknown LDP packet " + "type interface %s", iface->name); free(buf); return; } |