|
|
|
@ -8,6 +8,7 @@ |
|
|
|
|
|
|
|
#include "str.h" |
|
|
|
#include "aux.h" |
|
|
|
#include "log.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -156,6 +157,7 @@ static int stun_attributes(struct stun_attrs *out, str *s, u_int16_t *unknowns) |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
mylog(LOG_INFO, "Unknown STUN attribute: 0x%04x", type); |
|
|
|
if ((type & 0x8000)) |
|
|
|
break; |
|
|
|
unknowns[uc] = tlv->type; |
|
|
|
@ -398,31 +400,42 @@ static inline int u_int16_t_arr_len(u_int16_t *arr) { |
|
|
|
return i; |
|
|
|
} |
|
|
|
|
|
|
|
/* XXX add error reporting */ |
|
|
|
|
|
|
|
#define SLF " on port %hu from %s" |
|
|
|
#define SLP sr->fd.localport, addr |
|
|
|
int stun(str *b, struct streamrelay *sr, struct sockaddr_in6 *sin) { |
|
|
|
struct header *req = (void *) b->s; |
|
|
|
int msglen, method, class; |
|
|
|
str attr_str; |
|
|
|
struct stun_attrs attrs; |
|
|
|
u_int16_t unknowns[UNKNOWNS_COUNT]; |
|
|
|
const char *err; |
|
|
|
char addr[64]; |
|
|
|
|
|
|
|
smart_ntop_port(addr, sin, sizeof(addr)); |
|
|
|
|
|
|
|
msglen = ntohs(req->msg_len); |
|
|
|
err = "message-length mismatch"; |
|
|
|
if (msglen + 20 > b->len || msglen < 0) |
|
|
|
return -1; |
|
|
|
goto ignore; |
|
|
|
|
|
|
|
class = method = ntohs(req->msg_type); |
|
|
|
class = ((class & 0x10) >> 4) | ((class & 0x100) >> 7); |
|
|
|
method = (method & 0xf) | ((method & 0xe0) >> 1) | ((method & 0x3e00) >> 2); |
|
|
|
err = "unknown STUN method"; |
|
|
|
if (method != STUN_METHOD_BINDING) |
|
|
|
return -1; |
|
|
|
goto ignore; |
|
|
|
if (class == STUN_CLASS_INDICATION) |
|
|
|
return 0; |
|
|
|
|
|
|
|
attr_str.s = &b->s[20]; |
|
|
|
attr_str.len = b->len - 20; |
|
|
|
if (stun_attributes(&attrs, &attr_str, unknowns)) { |
|
|
|
err = "failed to parse attributes"; |
|
|
|
if (unknowns[0] == 0xffff) |
|
|
|
return -1; |
|
|
|
goto ignore; |
|
|
|
mylog(LOG_WARNING, "STUN packet contained unknown " |
|
|
|
"\"comprehension required\" attribute(s)" SLF, SLP); |
|
|
|
stun_error_attrs(sr->fd.fd, sin, req, 420, "Unknown attribute", |
|
|
|
STUN_UNKNOWN_ATTRIBUTES, unknowns, |
|
|
|
u_int16_t_arr_len(unknowns) * 2); |
|
|
|
@ -432,23 +445,36 @@ int stun(str *b, struct streamrelay *sr, struct sockaddr_in6 *sin) { |
|
|
|
if (class != STUN_CLASS_REQUEST) |
|
|
|
return -1; |
|
|
|
|
|
|
|
/* request */ |
|
|
|
if (!attrs.username.s || !attrs.msg_integrity.s || !attrs.fingerprint_attr) |
|
|
|
err = "FINGERPRINT attribute missing"; |
|
|
|
if (!attrs.fingerprint_attr) |
|
|
|
goto ignore; |
|
|
|
err = "USERNAME attribute missing"; |
|
|
|
if (!attrs.username.s) |
|
|
|
goto bad_req; |
|
|
|
err = "MESSAGE_INTEGRITY attribute missing"; |
|
|
|
if (!attrs.msg_integrity.s) |
|
|
|
goto bad_req; |
|
|
|
|
|
|
|
err = "FINGERPRINT mismatch"; |
|
|
|
if (check_fingerprint(b, &attrs)) |
|
|
|
return -1; |
|
|
|
goto ignore; |
|
|
|
if (check_auth(b, &attrs, sr->up)) |
|
|
|
goto unauth; |
|
|
|
|
|
|
|
mylog(LOG_NOTICE, "Successful STUN binding request" SLF, SLP); |
|
|
|
stun_binding_success(sr->fd.fd, req, &attrs, sin, sr->up); |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
bad_req: |
|
|
|
mylog(LOG_INFO, "Received invalid STUN packet" SLF ": %s", SLP, err); |
|
|
|
stun_error(sr->fd.fd, sin, req, 400, "Bad request"); |
|
|
|
return 0; |
|
|
|
unauth: |
|
|
|
mylog(LOG_INFO, "STUN authentication mismatch" SLF, SLP); |
|
|
|
stun_error(sr->fd.fd, sin, req, 401, "Unauthorized"); |
|
|
|
return 0; |
|
|
|
ignore: |
|
|
|
mylog(LOG_INFO, "Not handling potential STUN packet" SLF ": %s", SLP, err); |
|
|
|
return -1; |
|
|
|
} |