From 1758e586cee950866fa52cffd3ec41c04a82ccaa Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 28 Feb 2013 12:51:21 -0500 Subject: [PATCH] generate stun errors --- daemon/call.c | 23 ++++++++++-------- daemon/stun.c | 65 +++++++++++++++++++++++++++++++++++++++++++++------ daemon/stun.h | 15 ++++++++---- 3 files changed, 81 insertions(+), 22 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index ed9701b4a..6ba988989 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -209,7 +209,7 @@ void kernelize(struct callstream *c) { /* called with r->up (== cs) locked */ -static int stream_packet(struct streamrelay *r, char *b, int l, struct sockaddr_in6 *fsin) { +static int stream_packet(struct streamrelay *r, str *s, struct sockaddr_in6 *fsin) { struct streamrelay *p, *p2; struct peer *pe, *pe2; struct callstream *cs; @@ -235,8 +235,8 @@ static int stream_packet(struct streamrelay *r, char *b, int l, struct sockaddr_ m = c->callmaster; smart_ntop_port(addr, fsin, sizeof(addr)); - if (r->stun && is_stun(b, l)) { - if (!stun(b, l)) + if (r->stun && is_stun(s)) { + if (!stun(s, r, fsin)) return 0; } @@ -262,8 +262,8 @@ static int stream_packet(struct streamrelay *r, char *b, int l, struct sockaddr_ pe->confirmed = 1; peerinfo: - if (!pe->codec && l >= 2) { - cc = b[1]; + if (!pe->codec && s->len >= 2) { + cc = s->s[1]; cc &= 0x7f; if (cc < G_N_ELEMENTS(rtp_codecs)) pe->codec = rtp_codecs[cc] ? : "unknown"; @@ -344,8 +344,8 @@ ipv4_src: } ZERO(iov); - iov.iov_base = b; - iov.iov_len = l; + iov.iov_base = s->s; + iov.iov_len = s->len; mh.msg_iov = &iov; mh.msg_iovlen = 1; @@ -363,11 +363,11 @@ ipv4_src: drop: ret = 0; r->stats.packets++; - r->stats.bytes += l; + r->stats.bytes += s->len; r->last = poller_now; mutex_lock(&m->statspslock); m->statsps.packets++; - m->statsps.bytes += l; + m->statsps.bytes += s->len; mutex_unlock(&m->statspslock); out: @@ -392,6 +392,7 @@ static void stream_readable(int fd, void *p, uintptr_t u) { void *sinp; int update = 0; struct call *ca; + str s; mutex_lock(&cs->lock); r = &cs->peers[u >> 1].rtps[u & 1]; @@ -427,7 +428,9 @@ static void stream_readable(int fd, void *p, uintptr_t u) { in4_to_6(&sin6.sin6_addr, sin->sin_addr.s_addr); } - ret = stream_packet(r, buf, ret, sinp); + s.s = buf; + s.len = ret; + ret = stream_packet(r, &s, sinp); if (ret == -1) { mylog(LOG_WARNING, "Write error on RTP socket"); mutex_unlock(&cs->lock); diff --git a/daemon/stun.c b/daemon/stun.c index db8c6fa23..1f6b05ba1 100644 --- a/daemon/stun.c +++ b/daemon/stun.c @@ -1,6 +1,8 @@ #include "stun.h" #include +#include +#include #include "str.h" #include "aux.h" @@ -15,7 +17,6 @@ struct stun { struct tlv { u_int16_t type; u_int16_t len; - char value[0]; } __attribute__ ((packed)); struct stun_attrs { @@ -27,6 +28,12 @@ struct stun_attrs { controlling:1; }; +struct stun_error { + struct stun stun; + struct tlv error_code; + u_int32_t codes; +}; + static int stun_attributes(struct stun_attrs *out, str *s) { @@ -81,27 +88,71 @@ static int stun_attributes(struct stun_attrs *out, str *s) { return 0; } +static inline void stun_error_len(int fd, struct sockaddr_in6 *sin, struct stun *req, + int code, char *reason, int len) +{ + struct stun_error err; + struct msghdr mh; + struct iovec iov[2]; + + err.stun.msg_type = htons(0x0111); /* binding error response */ + err.stun.cookie = htonl(STUN_COOKIE); + memcpy(&err.stun.transaction, &req->transaction, sizeof(err.stun.transaction)); + err.error_code.type = htons(0x0009); /* error-code */ + err.error_code.len = htons(len + sizeof(err.codes)); + err.codes = htonl(((code / 100) << 8) | (code % 100)); + + ZERO(mh); + ZERO(iov); + + iov[0].iov_base = &err; + iov[0].iov_len = sizeof(err); + iov[1].iov_base = reason; + iov[1].iov_len = (len + 3) & 0xfffc; + + err.stun.msg_len = htons(iov[1].iov_len + sizeof(err.codes) + sizeof(err.error_code)); + + mh.msg_name = sin; + mh.msg_namelen = sizeof(*sin); + mh.msg_iov = iov; + mh.msg_iovlen = 2; + + sendmsg(fd, &mh, 0); +} + +#define stun_error(fd, sin, str, code, reason) \ + stun_error_len(fd, sin, str, code, reason "\0\0\0", strlen(reason)) + /* XXX add error reporting */ -int stun(char *buf, int len) { - struct stun *s = (void *) buf; +int stun(str *b, struct streamrelay *sr, struct sockaddr_in6 *sin) { + struct stun *s = (void *) b->s; int msglen, method, class; str attr_str; struct stun_attrs attrs; msglen = ntohs(s->msg_len); - if (msglen + 20 > len || msglen < 0) + if (msglen + 20 > b->len || msglen < 0) return -1; - class = method = ntohl(s->msg_type); + class = method = ntohs(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; + attr_str.s = &b->s[20]; + attr_str.len = b->len - 20; if (stun_attributes(&attrs, &attr_str)) return -1; + if (class == 0x0) { /* request */ + if (!attrs.username.s || !attrs.msg_integrity.s) + goto bad_req; + } + + return 0; + +bad_req: + stun_error(sr->fd.fd, sin, s, 400, "Bad request"); return 0; } diff --git a/daemon/stun.h b/daemon/stun.h index 97a6142a0..eb70449af 100644 --- a/daemon/stun.h +++ b/daemon/stun.h @@ -4,27 +4,32 @@ #include #include +#include "call.h" +#include "str.h" -static inline int is_stun(const char *bx, int len) { - const unsigned char *b = (const void *) bx; +#define STUN_COOKIE 0x2112A442 + + +static inline int is_stun(str *s) { + const unsigned char *b = (const void *) s->s; const u_int32_t *u; - if (len < 20) + if (s->len < 20) return 0; if ((b[0] & 0xb0) != 0x00) return 0; if ((b[3] & 0x3) != 0x0) return 0; u = (const void *) &b[4]; - if (*u != htonl(0x2112A442)) + if (*u != htonl(STUN_COOKIE)) return 0; return 1; } -int stun(char *buf, int len); +int stun(str *, struct streamrelay *, struct sockaddr_in6 *); #endif