static int module_close(void) { restund_stun_unregister_handler(&stun); restund_debug("auth: module closed\n"); return 0; }
static int module_init(void) { restund_db_set_auth_handler(auth_handler); restund_debug("restauth: module loaded\n"); return 0; }
static int module_close(void) { restund_db_set_auth_handler(NULL); restund_debug("restauth: module closed\n"); return 0; }
static int module_close(void) { mysql_close(&my.mysql); restund_debug("mysql: module closed\n"); return 0; }
static int module_close(void) { stg.us = mem_deref(stg.us); stg.httpd = mem_deref(stg.httpd); restund_debug("status: module closed\n"); return 0; }
static void destructor(void *arg) { struct chan *chan = arg; restund_debug("turn: allocation %p channel 0x%x %J destroyed\n", chan->al, chan->numb, &chan->peer); hash_unlink(&chan->he_numb); hash_unlink(&chan->he_peer); }
/* shared secret authentication as described in * http://tools.ietf.org/html/draft-uberti-rtcweb-turn-rest-00 */ static bool sharedsecret_auth_check_timestamp(const struct stun_attr *user, const time_t now) { long ts = 0; sscanf(user->v.username, "%ld:%*s", &ts); if (now > ts) { restund_debug("auth: shared secret nonce expired, ts was %ld now is %ld\n", ts, now); return false; } return true; }
static void chan_refresh(struct chan *chan) { if (!chan) return; chan->expires = time(NULL) + CHAN_LIFETIME; restund_debug("turn: allocation %p channel 0x%x %J refreshed\n", chan->al, chan->numb, &chan->peer); }
static bool nonce_validate(char *nonce, time_t now, const struct sa *src) { uint8_t nkey[MD5_SIZE], ckey[MD5_SIZE]; uint64_t nv[3]; struct pl pl; int64_t age; unsigned i; pl.p = nonce; pl.l = str_len(nonce); if (pl.l < NONCE_MIN_SIZE || pl.l > NONCE_MAX_SIZE) { restund_info("auth: bad nonce length (%zu)\n", pl.l); return false; } for (i=0; i<sizeof(nkey); i++) { nkey[i] = ch_hex(*pl.p++) << 4; nkey[i] += ch_hex(*pl.p++); pl.l -= 2; } nv[0] = pl_x64(&pl); nv[1] = auth.secret; nv[2] = sa_hash(src, SA_ADDR); md5((uint8_t *)nv, sizeof(nv), ckey); if (memcmp(nkey, ckey, MD5_SIZE)) { restund_debug("auth: invalid nonce (%j)\n", src); return false; } age = now - nv[0]; if (age < 0 || age > auth.nonce_expiry) { restund_debug("auth: nonce expired, age: %lli secs\n", age); return false; } return true; }
static int module_close(void) { hash_flush(turnd.ht_alloc); turnd.ht_alloc = mem_deref(turnd.ht_alloc); restund_cmd_unsubscribe(&cmd_turnstats); restund_cmd_unsubscribe(&cmd_turn); restund_stun_unregister_handler(&stun); restund_debug("turn: module closed\n"); return 0; }
static int myconnect(void) { mysql_init(&my.mysql); if (!mysql_real_connect(&my.mysql, my.host, my.user, my.pass, my.db, 0, NULL, 0)) return(ECONNREFUSED); restund_debug("mysql: connected (server %s at %s)\n", mysql_get_server_info(&my.mysql), mysql_get_host_info(&my.mysql)); return 0; }
static int module_init(void) { auth.nonce_expiry = NONCE_EXPIRY; auth.rand_time = rand_u32(); auth.rand_addr = rand_u32(); conf_get_u32(restund_conf(), "auth_nonce_expiry", &auth.nonce_expiry); restund_stun_register_handler(&stun); restund_debug("auth: module loaded (nonce_expiry=%us)\n", auth.nonce_expiry); return 0; }
struct chan *chan_peer_find(const struct chanlist *cl, const struct sa *peer) { struct chan *chan; if (!cl || !peer) return NULL; chan = list_ledata(hash_lookup(cl->ht_peer, sa_hash(peer, SA_ALL), hash_peer_cmp_handler, (void *)peer)); if (!chan) return NULL; if (chan->expires < time(NULL)) { restund_debug("turn: allocation %p channel 0x%x %J expired\n", chan->al, chan->numb, &chan->peer); mem_deref(chan); return NULL; } return chan; }
struct chan *chan_numb_find(const struct chanlist *cl, uint16_t numb) { struct chan *chan; if (!cl) return NULL; chan = list_ledata(hash_lookup(cl->ht_numb, numb, hash_numb_cmp_handler, &numb)); if (!chan) return NULL; if (chan->expires < time(NULL)) { restund_debug("turn: allocation %p channel 0x%x %J expired\n", chan->al, chan->numb, &chan->peer); mem_deref(chan); return NULL; } return chan; }
static int listen_handler(const struct pl *addrport, void *arg) { uint32_t sockbuf_size = *(uint32_t *)arg; struct udp_lstnr *ul = NULL; int err = ENOMEM; ul = mem_zalloc(sizeof(*ul), destructor); if (!ul) { restund_warning("udp listen error: %s\n", strerror(err)); goto out; } list_append(&lstnrl, &ul->le, ul); err = sa_decode(&ul->bnd_addr, addrport->p, addrport->l); if (err || sa_is_any(&ul->bnd_addr) || !sa_port(&ul->bnd_addr)) { restund_warning("bad udp_listen directive: '%r'\n", addrport); err = EINVAL; goto out; } err = udp_listen(&ul->us, &ul->bnd_addr, udp_recv, ul); if (err) { restund_warning("udp listen %J: %s\n", &ul->bnd_addr, strerror(err)); goto out; } if (sockbuf_size > 0) (void)udp_sockbuf_set(ul->us, sockbuf_size); restund_debug("udp listen: %J\n", &ul->bnd_addr); out: if (err) mem_deref(ul); return err; }
static int auth_handler(const char *user, uint8_t *ha1) { uint8_t key[MD5_SIZE], digest[SHA_DIGEST_LENGTH]; const char *username; time_t expires, now; char pass[28]; size_t len; int err; err = decode_user(&expires, &username, user); if (err) return err; now = time(NULL); if (expires < now) { restund_debug("restauth: user '%s' expired %lli seconds ago\n", user, now - expires); return ETIMEDOUT; } /* avoid recursive loops */ restund_db_set_auth_handler(NULL); err = restund_get_ha1(username, key); restund_db_set_auth_handler(auth_handler); if (err) return err; hmac_sha1(key, sizeof(key), (uint8_t *)user, strlen(user), digest, sizeof(digest)); len = sizeof(pass); err = base64_encode(digest, sizeof(digest), pass, &len); if (err) return err; return md5_printf(ha1, "%s:%s:%b", user, restund_realm(), pass, len); }
static int module_init(void) { uint32_t x, bsize = ALLOC_DEFAULT_BSIZE; struct pl opt; int err = 0; restund_stun_register_handler(&stun); restund_cmd_subscribe(&cmd_turn); restund_cmd_subscribe(&cmd_turnstats); /* turn_external_addr */ if (!conf_get(restund_conf(), "turn_relay_addr", &opt)) err = sa_set(&turnd.rel_addr, &opt, 0); else sa_init(&turnd.rel_addr, AF_UNSPEC); if (err) { restund_error("turn: bad turn_relay_addr: '%r'\n", &opt); goto out; } /* turn_external_addr6 */ if (!conf_get(restund_conf(), "turn_relay_addr6", &opt)) err = sa_set(&turnd.rel_addr6, &opt, 0); else sa_init(&turnd.rel_addr6, AF_UNSPEC); if (err) { restund_error("turn: bad turn_relay_addr6: '%r'\n", &opt); goto out; } if (!sa_isset(&turnd.rel_addr, SA_ADDR) && !sa_isset(&turnd.rel_addr6, SA_ADDR)) { restund_error("turn: no relay address configured\n"); err = EINVAL; goto out; } /* turn_max_lifetime, turn_max_allocations, udp_sockbuf_size */ turnd.lifetime_max = TURN_DEFAULT_LIFETIME; conf_get_u32(restund_conf(), "turn_max_lifetime", &turnd.lifetime_max); conf_get_u32(restund_conf(), "turn_max_allocations", &bsize); conf_get_u32(restund_conf(), "udp_sockbuf_size", &turnd.udp_sockbuf_size); for (x=2; (uint32_t)1<<x<bsize; x++); bsize = 1<<x; err = hash_alloc(&turnd.ht_alloc, bsize); if (err) { restund_error("turnd hash alloc error: %m\n", err); goto out; } restund_debug("turn: lifetime=%u ext=%j ext6=%j bsz=%u\n", turnd.lifetime_max, &turnd.rel_addr, &turnd.rel_addr6, bsize); out: return err; }
static bool request_handler(struct restund_msgctx *ctx, int proto, void *sock, const struct sa *src, const struct sa *dst, const struct stun_msg *msg) { const uint16_t met = stun_msg_method(msg); struct allocation *al; int err = 0; switch (met) { case STUN_METHOD_ALLOCATE: case STUN_METHOD_REFRESH: case STUN_METHOD_CREATEPERM: case STUN_METHOD_CHANBIND: break; default: return false; } if (ctx->ua.typec > 0) { err = stun_ereply(proto, sock, src, 0, msg, 420, "Unknown Attribute", ctx->key, ctx->keylen, ctx->fp, 2, STUN_ATTR_UNKNOWN_ATTR, &ctx->ua, STUN_ATTR_SOFTWARE, restund_software); goto out; } al = allocation_find(proto, src, dst); if (!al && met != STUN_METHOD_ALLOCATE) { restund_debug("turn: allocation does not exist\n"); err = stun_ereply(proto, sock, src, 0, msg, 437, "Allocation Mismatch", ctx->key, ctx->keylen, ctx->fp, 1, STUN_ATTR_SOFTWARE, restund_software); goto out; } if (al && al->username && ctx->key) { struct stun_attr *usr = stun_msg_attr(msg, STUN_ATTR_USERNAME); if (!usr || strcmp(usr->v.username, al->username)) { restund_debug("turn: wrong credetials\n"); err = stun_ereply(proto, sock, src, 0, msg, 441, "Wrong Credentials", ctx->key, ctx->keylen, ctx->fp, 1, STUN_ATTR_SOFTWARE,restund_software); goto out; } } switch (met) { case STUN_METHOD_ALLOCATE: allocate_request(&turnd, al, ctx, proto, sock, src, dst, msg); break; case STUN_METHOD_REFRESH: refresh_request(&turnd, al, ctx, proto, sock, src, msg); break; case STUN_METHOD_CREATEPERM: createperm_request(al, ctx, proto, sock, src, msg); break; case STUN_METHOD_CHANBIND: chanbind_request(al, ctx, proto, sock, src, msg); break; } out: if (err) { restund_warning("turn reply error: %m\n", err); } return true; }