support unknown-attributes error response

git.mgm/mediaproxy-ng/2.2
Richard Fuchs 13 years ago
parent 2ea1fe3a47
commit 27a9e92872

@ -16,12 +16,15 @@
#define STUN_USERNAME 0x0006
#define STUN_MESSAGE_INTEGRITY 0x0008
#define STUN_ERROR_CODE 0x0009
#define STUN_UNKNOWN_ATTRIBUTES 0x000a
#define STUN_XOR_MAPPED_ADDRESS 0x0020
#define STUN_FINGERPRINT 0x8028
#define STUN_BINDING_SUCCESS_RESPONSE 0x0101
#define STUN_BINDING_ERROR_RESPONSE 0x0111
#define UNKNOWNS_COUNT 16
struct stun_attrs {
@ -48,6 +51,10 @@ struct tlv {
u_int16_t len;
} __attribute__ ((packed));
struct generic {
struct tlv tlv;
} __attribute__ ((packed));
struct error_code {
struct tlv tlv;
u_int32_t codes;
@ -72,16 +79,18 @@ struct xor_mapped_address {
static int stun_attributes(struct stun_attrs *out, str *s) {
static int stun_attributes(struct stun_attrs *out, str *s, u_int16_t *unknowns) {
struct tlv *tlv;
int len;
int len, type, uc;
str attr;
ZERO(*out);
uc = 0;
unknowns[0] = 0xffff;
while (1) {
if (!s->len)
return 0;
break;
tlv = (void *) s->s;
if (str_shift(s, sizeof(*tlv)))
@ -95,10 +104,11 @@ static int stun_attributes(struct stun_attrs *out, str *s) {
if (str_shift(s, len))
return -1;
if (out->msg_integrity.s && ntohs(tlv->type) != STUN_FINGERPRINT)
type = ntohs(tlv->type);
if (out->msg_integrity.s && type != STUN_FINGERPRINT)
return -1;
switch (ntohs(tlv->type)) {
switch (type) {
case STUN_USERNAME:
out->username = attr;
break;
@ -130,11 +140,20 @@ static int stun_attributes(struct stun_attrs *out, str *s) {
return -1;
out->priority = ntohl(*((u_int32_t *) attr.s));
break;
default:
if ((type & 0x8000))
break;
unknowns[uc] = tlv->type;
unknowns[++uc] = 0xffff;
if (uc >= UNKNOWNS_COUNT - 1)
return -1;
break;
}
}
out:
return 0;
return uc ? -1 : 0;
}
static void output_init(struct msghdr *mh, struct iovec *iov, struct sockaddr_in6 *sin,
@ -241,18 +260,22 @@ static void integrity(struct msghdr *mh, struct msg_integrity *mi, str *pwd) {
}
static void stun_error_len(int fd, struct sockaddr_in6 *sin, struct header *req,
int code, char *reason, int len)
int code, char *reason, int len, u_int16_t add_attr, void *attr_cont,
int attr_len)
{
struct header hdr;
struct error_code ec;
struct fingerprint fp;
struct generic aa;
struct msghdr mh;
struct iovec iov[4]; /* hdr, ec, reason, fp */
struct iovec iov[6]; /* hdr, ec, reason, aa, attr_cont, fp */
output_init(&mh, iov, sin, &hdr, STUN_BINDING_ERROR_RESPONSE, req->transaction);
ec.codes = htonl(((code / 100) << 8) | (code % 100));
output_add_data(&mh, &ec, STUN_ERROR_CODE, reason, len);
if (attr_cont)
output_add_data(&mh, &aa, add_attr, attr_cont, attr_len);
fingerprint(&mh, &fp);
@ -261,7 +284,11 @@ static void stun_error_len(int fd, struct sockaddr_in6 *sin, struct header *req,
}
#define stun_error(fd, sin, str, code, reason) \
stun_error_len(fd, sin, str, code, reason "\0\0\0", strlen(reason))
stun_error_len(fd, sin, str, code, reason "\0\0\0", strlen(reason), \
0, NULL, 0)
#define stun_error_attrs(fd, sin, str, code, reason, type, content, len) \
stun_error_len(fd, sin, str, code, reason "\0\0\0", strlen(reason), \
type, content, len)
@ -350,18 +377,26 @@ static int stun_binding_success(int fd, struct header *req, struct stun_attrs *a
return 0;
}
static inline int u_int16_t_arr_len(u_int16_t *arr) {
int i;
for (i = 0; arr[i] != 0xffff; i++)
;
return i;
}
/* XXX add error reporting */
int stun(str *b, struct streamrelay *sr, struct sockaddr_in6 *sin) {
struct header *s = (void *) b->s;
struct header *req = (void *) b->s;
int msglen, method, class;
str attr_str;
struct stun_attrs attrs;
u_int16_t unknowns[UNKNOWNS_COUNT];
msglen = ntohs(s->msg_len);
msglen = ntohs(req->msg_len);
if (msglen + 20 > b->len || msglen < 0)
return -1;
class = method = ntohs(s->msg_type);
class = method = ntohs(req->msg_type);
class = ((class & 0x10) >> 4) | ((class & 0x100) >> 7);
method = (method & 0xf) | ((method & 0xe0) >> 1) | ((method & 0x3e00) >> 2);
if (method != 0x1) /* binding */
@ -369,8 +404,14 @@ int stun(str *b, struct streamrelay *sr, struct sockaddr_in6 *sin) {
attr_str.s = &b->s[20];
attr_str.len = b->len - 20;
if (stun_attributes(&attrs, &attr_str))
return -1;
if (stun_attributes(&attrs, &attr_str, unknowns)) {
if (unknowns[0] == 0xffff)
return -1;
stun_error_attrs(sr->fd.fd, sin, req, 420, "Unknown attribute",
STUN_UNKNOWN_ATTRIBUTES, unknowns,
u_int16_t_arr_len(unknowns) * 2);
return 0;
}
if (class != 0x0)
return -1; /* XXX ? */
@ -384,14 +425,14 @@ int stun(str *b, struct streamrelay *sr, struct sockaddr_in6 *sin) {
if (check_auth(b, &attrs, sr->up))
goto unauth;
stun_binding_success(sr->fd.fd, s, &attrs, sin, sr->up);
stun_binding_success(sr->fd.fd, req, &attrs, sin, sr->up);
return 0;
bad_req:
stun_error(sr->fd.fd, sin, s, 400, "Bad request");
stun_error(sr->fd.fd, sin, req, 400, "Bad request");
return 0;
unauth:
stun_error(sr->fd.fd, sin, s, 401, "Unauthorized");
stun_error(sr->fd.fd, sin, req, 401, "Unauthorized");
return 0;
}

Loading…
Cancel
Save