diff options
| author | 2010-11-04 09:52:16 +0000 | |
|---|---|---|
| committer | 2010-11-04 09:52:16 +0000 | |
| commit | 89f23408dcb312cf299c29cafa7b5d191b7a7cd6 (patch) | |
| tree | 89edad7fbcd3b23e8ca6b17ffd3c5765b3d96e71 /usr.sbin/ldpd/labelmapping.c | |
| parent | Only consider pathes with highest priority when replying to label (diff) | |
| download | wireguard-openbsd-89f23408dcb312cf299c29cafa7b5d191b7a7cd6.tar.xz wireguard-openbsd-89f23408dcb312cf299c29cafa7b5d191b7a7cd6.zip | |
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@
Diffstat (limited to 'usr.sbin/ldpd/labelmapping.c')
| -rw-r--r-- | usr.sbin/ldpd/labelmapping.c | 393 |
1 files changed, 230 insertions, 163 deletions
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) { |
