static int str_decode(struct mbuf *mb, char **str, size_t len) { if (mbuf_get_left(mb) < len) return EBADMSG; return mbuf_strdup(mb, str, len); }
/** * Decode a DNS character string from a memory buffer * * @param mb Memory buffer to decode from * @param str Pointer to allocated character string * * @return 0 if success, otherwise errorcode */ int dns_cstr_decode(struct mbuf *mb, char **str) { uint8_t len; if (!mb || !str || (mbuf_get_left(mb) < 1)) return EINVAL; len = mbuf_read_u8(mb); if (mbuf_get_left(mb) < len) return EBADMSG; return mbuf_strdup(mb, str, len); }
static int cmd_report(const struct cmd *cmd, struct re_printf *pf, struct mbuf *mb, void *data) { struct cmd_arg arg; int err; memset(&arg, 0, sizeof(arg)); mb->pos = 0; err = mbuf_strdup(mb, &arg.prm, mb->end); if (err) return err; arg.key = cmd->key; arg.data = data; err = cmd->h(pf, &arg); mem_deref(arg.prm); return err; }
int pcp_option_decode(struct pcp_option **optp, struct mbuf *mb) { struct pcp_option *opt; size_t start, len; uint16_t port; int err = 0; if (!optp || !mb) return EINVAL; if (mbuf_get_left(mb) < 4) return EBADMSG; opt = mem_zalloc(sizeof(*opt), destructor); if (!opt) return ENOMEM; opt->code = mbuf_read_u8(mb); (void)mbuf_read_u8(mb); len = ntohs(mbuf_read_u16(mb)); if (mbuf_get_left(mb) < len) goto badmsg; start = mb->pos; switch (opt->code) { case PCP_OPTION_THIRD_PARTY: if (len < 16) goto badmsg; err = pcp_ipaddr_decode(mb, &opt->u.third_party); break; case PCP_OPTION_PREFER_FAILURE: /* no payload */ break; case PCP_OPTION_FILTER: if (len < 20) goto badmsg; (void)mbuf_read_u8(mb); opt->u.filter.prefix_length = mbuf_read_u8(mb); port = ntohs(mbuf_read_u16(mb)); err = pcp_ipaddr_decode(mb, &opt->u.filter.remote_peer); sa_set_port(&opt->u.filter.remote_peer, port); break; case PCP_OPTION_DESCRIPTION: err = mbuf_strdup(mb, &opt->u.description, len); break; default: mb->pos += len; (void)re_printf("pcp: ignore option code %d (len=%zu)\n", opt->code, len); break; } if (err) goto error; /* padding */ while (((mb->pos - start) & 0x03) && mbuf_get_left(mb)) ++mb->pos; *optp = opt; return 0; badmsg: err = EBADMSG; error: mem_deref(opt); return err; }
/** * Decode one RTCP message from a buffer * * @param msgp Pointer to allocated RTCP Message * @param mb Buffer to decode from * * @return 0 for success, otherwise errorcode */ int rtcp_decode(struct rtcp_msg **msgp, struct mbuf *mb) { struct rtcp_msg *msg = NULL; size_t start, i, sz, count, rem; int err; if (!msgp) return EINVAL; if (mbuf_get_left(mb) < RTCP_HDR_SIZE) return EBADMSG; msg = mem_zalloc(sizeof(*msg), rtcp_destructor); if (!msg) return ENOMEM; start = mb->pos; /* decode and check header */ err = rtcp_hdr_decode(mb, &msg->hdr); if (err) goto out; if (msg->hdr.version != RTCP_VERSION) goto badmsg; /* check length and remaining */ rem = msg->hdr.length * sizeof(uint32_t); if (mbuf_get_left(mb) < rem) goto badmsg; count = msg->hdr.count; switch (msg->hdr.pt) { case RTCP_SR: if (mbuf_get_left(mb) < (RTCP_SRC_SIZE + RTCP_SR_SIZE)) goto badmsg; msg->r.sr.ssrc = ntohl(mbuf_read_u32(mb)); msg->r.sr.ntp_sec = ntohl(mbuf_read_u32(mb)); msg->r.sr.ntp_frac = ntohl(mbuf_read_u32(mb)); msg->r.sr.rtp_ts = ntohl(mbuf_read_u32(mb)); msg->r.sr.psent = ntohl(mbuf_read_u32(mb)); msg->r.sr.osent = ntohl(mbuf_read_u32(mb)); err = rtcp_rr_alloc(&msg->r.sr.rrv, count); if (err) goto out; for (i=0; i<count && !err; i++) err = rtcp_rr_decode(mb, &msg->r.sr.rrv[i]); break; case RTCP_RR: if (mbuf_get_left(mb) < RTCP_SRC_SIZE) goto badmsg; msg->r.rr.ssrc = ntohl(mbuf_read_u32(mb)); err = rtcp_rr_alloc(&msg->r.rr.rrv, count); if (err) goto out; for (i=0; i<count && !err; i++) err = rtcp_rr_decode(mb, &msg->r.rr.rrv[i]); break; case RTCP_SDES: if (count == 0) break; sz = count * sizeof(*msg->r.sdesv); msg->r.sdesv = mem_zalloc(sz, NULL); if (!msg->r.sdesv) { err = ENOMEM; goto out; } for (i=0; i<msg->hdr.count && !err; i++) err = rtcp_sdes_decode(mb, &msg->r.sdesv[i]); break; case RTCP_BYE: sz = count * sizeof(*msg->r.bye.srcv); msg->r.bye.srcv = mem_alloc(sz, NULL); if (!msg->r.bye.srcv) { err = ENOMEM; goto out; } if (mbuf_get_left(mb) < sz) goto badmsg; for (i=0; i<count; i++) msg->r.bye.srcv[i] = ntohl(mbuf_read_u32(mb)); /* decode reason (optional) */ if (rem > count*sizeof(uint32_t)) { const size_t len = mbuf_read_u8(mb); if (mbuf_get_left(mb) < len) goto badmsg; err = mbuf_strdup(mb, &msg->r.bye.reason, len); } break; case RTCP_APP: if (mbuf_get_left(mb) < RTCP_APP_SIZE) goto badmsg; msg->r.app.src = ntohl(mbuf_read_u32(mb)); (void)mbuf_read_mem(mb, (uint8_t *)msg->r.app.name, sizeof(msg->r.app.name)); if (rem > RTCP_APP_SIZE) { msg->r.app.data_len = rem - RTCP_APP_SIZE; msg->r.app.data = mem_alloc(msg->r.app.data_len, NULL); if (!msg->r.app.data) { err = ENOMEM; goto out; } if (mbuf_get_left(mb) < msg->r.app.data_len) goto badmsg; (void)mbuf_read_mem(mb, msg->r.app.data, msg->r.app.data_len); } break; case RTCP_FIR: if (mbuf_get_left(mb) < RTCP_FIR_SIZE) goto badmsg; msg->r.fir.ssrc = ntohl(mbuf_read_u32(mb)); break; case RTCP_NACK: if (mbuf_get_left(mb) < RTCP_NACK_SIZE) goto badmsg; msg->r.nack.ssrc = ntohl(mbuf_read_u32(mb)); msg->r.nack.fsn = ntohs(mbuf_read_u16(mb)); msg->r.nack.blp = ntohs(mbuf_read_u16(mb)); break; case RTCP_RTPFB: if (mbuf_get_left(mb) < RTCP_FB_SIZE) goto badmsg; msg->r.fb.ssrc_packet = ntohl(mbuf_read_u32(mb)); msg->r.fb.ssrc_media = ntohl(mbuf_read_u32(mb)); msg->r.fb.n = msg->hdr.length - 2; err = rtcp_rtpfb_decode(mb, msg); break; case RTCP_PSFB: if (mbuf_get_left(mb) < RTCP_FB_SIZE) goto badmsg; msg->r.fb.ssrc_packet = ntohl(mbuf_read_u32(mb)); msg->r.fb.ssrc_media = ntohl(mbuf_read_u32(mb)); msg->r.fb.n = msg->hdr.length - 2; err = rtcp_psfb_decode(mb, msg); break; default: /* unknown message type */ mbuf_advance(mb, rem); break; } if (err) goto out; /* slurp padding */ while ((mb->pos - start) & 0x3 && mbuf_get_left(mb)) ++mb->pos; out: if (err) mem_deref(msg); else *msgp = msg; return err; badmsg: mem_deref(msg); return EBADMSG; }