diff options
author | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2017-06-09 14:33:06 +0200 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2017-06-09 14:33:06 +0200 |
commit | 145ebfa1df9ad252af61cce01cc0f09db45f7c9d (patch) | |
tree | 0149873196db4dbae05d1a6f0ca84f78920eb7dc /proto/babel | |
parent | b3c6273efaa15976cc1290f00d5abde4991e184e (diff) |
Babel: Parse sub-TLVs and skip TLVs with mandatory sub-TLV
RFC6126bis formally introduces sub-TLVs to the Babel protocol, including
mandatory sub-TLVs. This adds support for parsing sub-TLVs to the Babel
protocol and skips TLVs that contain mandatory sub-TLVs, as per the spec.
For details, see section 4.4 of
https://tools.ietf.org/html/draft-ietf-babel-rfc6126bis-02
Thanks to Toke Høiland-Jørgensen <toke@toke.dk> for the patch.
Diffstat (limited to 'proto/babel')
-rw-r--r-- | proto/babel/babel.h | 5 | ||||
-rw-r--r-- | proto/babel/packets.c | 78 |
2 files changed, 79 insertions, 4 deletions
diff --git a/proto/babel/babel.h b/proto/babel/babel.h index 26f52455..fccb60c9 100644 --- a/proto/babel/babel.h +++ b/proto/babel/babel.h @@ -78,6 +78,11 @@ enum babel_tlv_type { BABEL_TLV_MAX }; +enum babel_subtlv_type { + BABEL_SUBTLV_PAD1 = 0, + BABEL_SUBTLV_PADN = 1 +}; + enum babel_iface_type { /* In practice, UNDEF and WIRED give equivalent behaviour */ BABEL_IFACE_TYPE_UNDEF = 0, diff --git a/proto/babel/packets.c b/proto/babel/packets.c index 72ac4f29..3564c703 100644 --- a/proto/babel/packets.c +++ b/proto/babel/packets.c @@ -120,6 +120,7 @@ struct babel_parse_state { u8 router_id_seen; /* router_id field is valid */ u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */ u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */ + u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */ }; enum parse_result { @@ -379,14 +380,33 @@ babel_read_ihu(struct babel_tlv *hdr, union babel_msg *m, if (msg->ae >= BABEL_AE_MAX) return PARSE_IGNORE; - // We handle link-local IPs. In every other case, the addr field will be 0 but - // validation will succeed. The handler takes care of these cases. - if (msg->ae == BABEL_AE_IP6_LL) + /* + * We only actually read link-local IPs. In every other case, the addr field + * will be 0 but validation will succeed. The handler takes care of these + * cases. We handle them here anyway because we need the length for parsing + * subtlvs. + */ + switch (msg->ae) { + case BABEL_AE_IP4: + if (TLV_OPT_LENGTH(tlv) < 4) + return PARSE_ERROR; + state->current_tlv_endpos += 4; + break; + + case BABEL_AE_IP6: + if (TLV_OPT_LENGTH(tlv) < 16) + return PARSE_ERROR; + state->current_tlv_endpos += 16; + break; + + case BABEL_AE_IP6_LL: if (TLV_OPT_LENGTH(tlv) < 8) return PARSE_ERROR; msg->addr = ipa_from_ip6(get_ip6_ll(&tlv->addr)); + state->current_tlv_endpos += 8; + break; } return PARSE_SUCCESS; @@ -463,6 +483,7 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED, return PARSE_ERROR; state->next_hop_ip4 = ipa_from_ip4(get_ip4(&tlv->addr)); + state->current_tlv_endpos += sizeof(ip4_addr); return PARSE_IGNORE; case BABEL_AE_IP6: @@ -470,6 +491,7 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED, return PARSE_ERROR; state->next_hop_ip6 = ipa_from_ip6(get_ip6(&tlv->addr)); + state->current_tlv_endpos += sizeof(ip6_addr); return PARSE_IGNORE; case BABEL_AE_IP6_LL: @@ -477,6 +499,7 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED, return PARSE_ERROR; state->next_hop_ip6 = ipa_from_ip6(get_ip6_ll(&tlv->addr)); + state->current_tlv_endpos += 8; return PARSE_IGNORE; default: @@ -639,6 +662,7 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m, msg->router_id = state->router_id; msg->sender = state->saddr; + state->current_tlv_endpos += len; return PARSE_SUCCESS; } @@ -765,6 +789,7 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, return PARSE_ERROR; read_ip4_px(&msg->net, tlv->addr, tlv->plen); + state->current_tlv_endpos += BYTES(tlv->plen); return PARSE_SUCCESS; case BABEL_AE_IP6: @@ -775,6 +800,7 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, return PARSE_ERROR; read_ip6_px(&msg->net, tlv->addr, tlv->plen); + state->current_tlv_endpos += BYTES(tlv->plen); return PARSE_SUCCESS; case BABEL_AE_IP6_LL: @@ -851,6 +877,7 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m, return PARSE_ERROR; read_ip4_px(&msg->net, tlv->addr, tlv->plen); + state->current_tlv_endpos += BYTES(tlv->plen); return PARSE_SUCCESS; case BABEL_AE_IP6: @@ -861,6 +888,7 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m, return PARSE_ERROR; read_ip6_px(&msg->net, tlv->addr, tlv->plen); + state->current_tlv_endpos += BYTES(tlv->plen); return PARSE_SUCCESS; case BABEL_AE_IP6_LL: @@ -908,6 +936,42 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m, } static inline int +babel_read_subtlvs(struct babel_tlv *hdr, + union babel_msg *msg UNUSED, + struct babel_parse_state *state) +{ + struct babel_tlv *tlv; + + for (tlv = (void *) hdr + state->current_tlv_endpos; + tlv < hdr + TLV_LENGTH(hdr); + tlv = NEXT_TLV(tlv)) + { + /* + * The subtlv type space is non-contiguous (due to the mandatory bit), so + * use a switch for dispatch instead of the mapping array we use for TLVs + */ + switch (tlv->type) + { + case BABEL_SUBTLV_PAD1: + case BABEL_SUBTLV_PADN: + /* FIXME: Framing errors in PADN are silently ignored, see babel_process_packet() */ + break; + + default: + /* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */ + if (tlv->type > 128) + { + DBG("Babel: Mandatory subtlv %d found; skipping TLV\n", tlv->type); + return PARSE_IGNORE; + } + break; + } + } + + return PARSE_SUCCESS; +} + +static inline int babel_read_tlv(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state) @@ -920,8 +984,14 @@ babel_read_tlv(struct babel_tlv *hdr, if (TLV_LENGTH(hdr) < tlv_data[hdr->type].min_length) return PARSE_ERROR; + state->current_tlv_endpos = tlv_data[hdr->type].min_length; memset(msg, 0, sizeof(*msg)); - return tlv_data[hdr->type].read_tlv(hdr, msg, state); + + int res = tlv_data[hdr->type].read_tlv(hdr, msg, state); + if (res != PARSE_SUCCESS) + return res; + + return babel_read_subtlvs(hdr, msg, state); } static uint |