From edf5f111405db44480ddeca947decc115441f02a Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Wed, 27 Feb 2013 17:22:10 -0500 Subject: [PATCH] parse stun attributes --- daemon/str.h | 9 ++++++ daemon/stun.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++-- daemon/stun.h | 2 +- 3 files changed, 95 insertions(+), 3 deletions(-) diff --git a/daemon/str.h b/daemon/str.h index 7cf5613b1..008f50ab1 100644 --- a/daemon/str.h +++ b/daemon/str.h @@ -47,6 +47,8 @@ static inline void str_init(str *out, char *s); static inline str *str_dup(const str *s); /* returns new str object allocated from chunk, including buffer */ static inline str *str_chunk_insert(GStringChunk *c, const str *s); +/* shifts pointer by len chars and decrements len. returns -1 if buffer too short, 0 otherwise */ +static inline int str_shift(str *s, int len); /* asprintf() analogs */ #define str_sprintf(fmt, a...) __str_sprintf(STR_MALLOC_PADDING fmt, a) @@ -74,6 +76,13 @@ static inline str *str_chunk_insert(GStringChunk *c, const str *s) { static inline char *str_end(const str *s) { return s->s + s->len; } +static inline int str_shift(str *s, int len) { + if (s->len < len) + return -1; + s->s += len; + s->len -= len; + return 0; +} static inline char *str_chr(const str *s, int c) { return memchr(s->s, c, s->len); } diff --git a/daemon/stun.c b/daemon/stun.c index 4af0c9e7c..db8c6fa23 100644 --- a/daemon/stun.c +++ b/daemon/stun.c @@ -1,6 +1,10 @@ #include "stun.h" + #include +#include "str.h" +#include "aux.h" + struct stun { u_int16_t msg_type; u_int16_t msg_len; @@ -8,17 +12,96 @@ struct stun { unsigned char transaction[12]; } __attribute__ ((packed)); +struct tlv { + u_int16_t type; + u_int16_t len; + char value[0]; +} __attribute__ ((packed)); + +struct stun_attrs { + str username; + str msg_integrity; + u_int32_t priority; + int use:1, + controlled:1, + controlling:1; +}; + + + +static int stun_attributes(struct stun_attrs *out, str *s) { + struct tlv *tlv; + int len; + str attr; + + ZERO(*out); + + while (1) { + if (!s->len) + return 0; + + tlv = (void *) s->s; + if (str_shift(s, sizeof(*tlv))) + return -1; + + len = ntohs(tlv->len); + attr = *s; + attr.len = len; -int stun(const char *buf, int len) { - const struct stun *s = (const void *) buf; + len = (len + 3) & 0xfffc; + if (str_shift(s, len)) + return -1; + + switch (ntohs(tlv->type)) { + case 0x0006: /* username */ + out->username = attr; + break; + case 0x0008: /* message-integrity */ + out->msg_integrity = attr; + break; + + case 0x0025: /* use-candidate */ + out->use = 1; + break; + case 0x8029: /* ice-controlled */ + out->controlled = 1; + break; + case 0x802a: /* ice-controlling */ + out->controlling = 1; + break; + + case 0x0024: /* priority */ + if (attr.len != 4) + return -1; + out->priority = ntohl(*((u_int32_t *) attr.s)); + break; + } + } + + return 0; +} + +/* XXX add error reporting */ +int stun(char *buf, int len) { + struct stun *s = (void *) buf; int msglen, method, class; + str attr_str; + struct stun_attrs attrs; msglen = ntohs(s->msg_len); + if (msglen + 20 > len || msglen < 0) + return -1; + class = method = ntohl(s->msg_type); class = ((class & 0x10) >> 4) | ((class & 0x100) >> 7); method = (method & 0xf) | ((method & 0xe0) >> 1) | ((method & 0x3e00) >> 2); if (method != 0x1) /* binding */ return -1; + attr_str.s = &buf[20]; + attr_str.len = len; + if (stun_attributes(&attrs, &attr_str)) + return -1; + return 0; } diff --git a/daemon/stun.h b/daemon/stun.h index 3f97ff677..97a6142a0 100644 --- a/daemon/stun.h +++ b/daemon/stun.h @@ -24,7 +24,7 @@ static inline int is_stun(const char *bx, int len) { } -int stun(const char *buf, int len); +int stun(char *buf, int len); #endif