|
|
|
|
@ -4,6 +4,7 @@
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <zlib.h>
|
|
|
|
|
#include <openssl/hmac.h>
|
|
|
|
|
|
|
|
|
|
#include "str.h"
|
|
|
|
|
#include "aux.h"
|
|
|
|
|
@ -11,6 +12,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define STUN_CRC_XOR 0x5354554eUL
|
|
|
|
|
#define STUN_USERNAME 0x0006
|
|
|
|
|
#define STUN_MESSAGE_INTEGRITY 0x0008
|
|
|
|
|
#define STUN_FINGERPRINT 0x8028
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -28,9 +31,10 @@ struct tlv {
|
|
|
|
|
|
|
|
|
|
struct stun_attrs {
|
|
|
|
|
str username;
|
|
|
|
|
char *msg_integrity_attr;
|
|
|
|
|
str msg_integrity;
|
|
|
|
|
char *fingerprint_attr;
|
|
|
|
|
u_int32_t priority;
|
|
|
|
|
char *fingerprint_attr;
|
|
|
|
|
u_int32_t fingerprint;
|
|
|
|
|
int use:1,
|
|
|
|
|
controlled:1,
|
|
|
|
|
@ -77,10 +81,13 @@ static int stun_attributes(struct stun_attrs *out, str *s) {
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
switch (ntohs(tlv->type)) {
|
|
|
|
|
case 0x0006: /* username */
|
|
|
|
|
case STUN_USERNAME:
|
|
|
|
|
out->username = attr;
|
|
|
|
|
break;
|
|
|
|
|
case 0x0008: /* message-integrity */
|
|
|
|
|
case STUN_MESSAGE_INTEGRITY:
|
|
|
|
|
if (attr.len != 20)
|
|
|
|
|
return -1;
|
|
|
|
|
out->msg_integrity_attr = (void *) tlv;
|
|
|
|
|
out->msg_integrity = attr;
|
|
|
|
|
break;
|
|
|
|
|
case STUN_FINGERPRINT:
|
|
|
|
|
@ -172,6 +179,46 @@ static int check_fingerprint(str *msg, struct stun_attrs *attrs) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int check_auth(str *msg, struct stun_attrs *attrs, struct peer *peer) {
|
|
|
|
|
HMAC_CTX ctx;
|
|
|
|
|
u_int16_t lenX;
|
|
|
|
|
unsigned char digest[20];
|
|
|
|
|
int ret;
|
|
|
|
|
str ufrag[2];
|
|
|
|
|
|
|
|
|
|
if (!peer->ice_ufrag[0].s || !peer->ice_ufrag[0].len)
|
|
|
|
|
return -1;
|
|
|
|
|
if (!peer->ice_pwd.s || !peer->ice_pwd.len)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
ufrag[0] = attrs->username;
|
|
|
|
|
str_chr_str(&ufrag[1], &ufrag[0], ':');
|
|
|
|
|
if (!ufrag[1].s)
|
|
|
|
|
return -1;
|
|
|
|
|
ufrag[0].len -= ufrag[1].len;
|
|
|
|
|
str_shift(&ufrag[1], 1);
|
|
|
|
|
|
|
|
|
|
if (!ufrag[0].len || !ufrag[1].len)
|
|
|
|
|
return -1;
|
|
|
|
|
if (str_cmp_str(&ufrag[0], &peer->ice_ufrag[0]))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
HMAC_CTX_init(&ctx);
|
|
|
|
|
HMAC_Init(&ctx, peer->ice_pwd.s, peer->ice_pwd.len, EVP_sha1());
|
|
|
|
|
HMAC_Update(&ctx, (void *) msg->s, OFFSET_OF(struct stun, msg_len));
|
|
|
|
|
lenX = htons((attrs->msg_integrity_attr - msg->s) - 20 + 24);
|
|
|
|
|
HMAC_Update(&ctx, (void *) &lenX, sizeof(lenX));
|
|
|
|
|
HMAC_Update(&ctx, (void *) msg->s + OFFSET_OF(struct stun, cookie),
|
|
|
|
|
ntohs(lenX) + - 24 + 20 - OFFSET_OF(struct stun, cookie));
|
|
|
|
|
HMAC_Final(&ctx, digest, NULL);
|
|
|
|
|
|
|
|
|
|
ret = memcmp(digest, attrs->msg_integrity.s, 20) ? -1 : 0;
|
|
|
|
|
|
|
|
|
|
HMAC_CTX_cleanup(&ctx);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* XXX add error reporting */
|
|
|
|
|
int stun(str *b, struct streamrelay *sr, struct sockaddr_in6 *sin) {
|
|
|
|
|
struct stun *s = (void *) b->s;
|
|
|
|
|
@ -203,10 +250,15 @@ int stun(str *b, struct streamrelay *sr, struct sockaddr_in6 *sin) {
|
|
|
|
|
|
|
|
|
|
if (check_fingerprint(b, &attrs))
|
|
|
|
|
return -1;
|
|
|
|
|
if (check_auth(b, &attrs, sr->up))
|
|
|
|
|
goto unauth;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
bad_req:
|
|
|
|
|
stun_error(sr->fd.fd, sin, s, 400, "Bad request");
|
|
|
|
|
return 0;
|
|
|
|
|
unauth:
|
|
|
|
|
stun_error(sr->fd.fd, sin, s, 401, "Unauthorized");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|