static int verify_callback(int ok, X509_STORE_CTX *store) { SSL *ssl; struct stream_fd *sfd; struct packet_stream *ps; struct call_media *media; ssl = X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx()); sfd = SSL_get_app_data(ssl); if (sfd->dtls.ssl != ssl) return 0; ps = sfd->stream; if (!ps) return 0; if (PS_ISSET(ps, FINGERPRINT_VERIFIED)) return 1; media = ps->media; if (!media) return 0; if (ps->dtls_cert) X509_free(ps->dtls_cert); ps->dtls_cert = X509_dup(X509_STORE_CTX_get_current_cert(store)); if (!media->fingerprint.hash_func) return 1; /* delay verification */ if (dtls_verify_cert(ps)) return 0; return 1; }
static void ng_stats_stream(bencode_item_t *list, const struct packet_stream *ps, struct call_stats *totals) { bencode_item_t *dict = NULL, *flags; struct stats *s; if (!list) goto stats; dict = bencode_list_add_dictionary(list); if (ps->sfd) bencode_dictionary_add_integer(dict, "local port", ps->sfd->fd.localport); ng_stats_endpoint(bencode_dictionary_add_dictionary(dict, "endpoint"), &ps->endpoint); ng_stats_endpoint(bencode_dictionary_add_dictionary(dict, "advertised endpoint"), &ps->advertised_endpoint); if (ps->crypto.params.crypto_suite) bencode_dictionary_add_string(dict, "crypto suite", ps->crypto.params.crypto_suite->name); bencode_dictionary_add_integer(dict, "last packet", ps->last_packet); flags = bencode_dictionary_add_list(dict, "flags"); BF_PS("RTP", RTP); BF_PS("RTCP", RTCP); BF_PS("fallback RTCP", FALLBACK_RTCP); BF_PS("filled", FILLED); BF_PS("confirmed", CONFIRMED); BF_PS("kernelized", KERNELIZED); BF_PS("no kernel support", NO_KERNEL_SUPPORT); BF_PS("DTLS fingerprint verified", FINGERPRINT_VERIFIED); BF_PS("strict source address", STRICT_SOURCE); BF_PS("media handover", MEDIA_HANDOVER); stats: if (totals->last_packet < ps->last_packet) totals->last_packet = ps->last_packet; /* XXX distinguish between input and output */ s = &totals->totals[0]; if (!PS_ISSET(ps, RTP)) s = &totals->totals[1]; ng_stats(bencode_dictionary_add_dictionary(dict, "stats"), &ps->stats, s); }
/* called with call locked in W or R with ps->in_lock held */ int dtls(struct packet_stream *ps, const str *s, struct sockaddr_in6 *fsin) { struct dtls_connection *d; int ret; unsigned char buf[0x10000], ctrl[256]; struct msghdr mh; struct iovec iov; struct sockaddr_in6 sin; if (!ps || !ps->sfd) return 0; if (!MEDIA_ISSET(ps->media, DTLS)) return 0; d = &ps->sfd->dtls; if (s) __DBG("dtls packet input: len %u %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", s->len, (unsigned char) s->s[0], (unsigned char) s->s[1], (unsigned char) s->s[2], (unsigned char) s->s[3], (unsigned char) s->s[4], (unsigned char) s->s[5], (unsigned char) s->s[6], (unsigned char) s->s[7], (unsigned char) s->s[8], (unsigned char) s->s[9], (unsigned char) s->s[10], (unsigned char) s->s[11], (unsigned char) s->s[12], (unsigned char) s->s[13], (unsigned char) s->s[14], (unsigned char) s->s[15]); if (d->connected) return 0; if (!d->init || !d->ssl) return -1; if (s) { BIO_write(d->r_bio, s->s, s->len); /* we understand this as preference of DTLS over SDES */ MEDIA_CLEAR(ps->media, SDES); } ret = try_connect(d); if (ret == -1) { ilog(LOG_ERROR, "DTLS error on local port %hu", ps->sfd->fd.localport); /* fatal error */ dtls_connection_cleanup(d); return 0; } else if (ret == 1) { /* connected! */ if (dtls_setup_crypto(ps, d)) /* XXX ?? */ ; if (PS_ISSET(ps, RTP) && PS_ISSET(ps, RTCP) && ps->rtcp_sibling && MEDIA_ISSET(ps->media, RTCP_MUX)) { if (dtls_setup_crypto(ps->rtcp_sibling, d)) /* XXX ?? */ ; } } ret = BIO_ctrl_pending(d->w_bio); if (ret <= 0) return 0; if (ret > sizeof(buf)) { ilog(LOG_ERROR, "BIO buffer overflow"); (void) BIO_reset(d->w_bio); return 0; } ret = BIO_read(d->w_bio, buf, ret); if (ret <= 0) return 0; __DBG("dtls packet output: len %u %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", ret, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); if (!fsin) { ZERO(sin); sin.sin6_family = AF_INET6; sin.sin6_addr = ps->endpoint.ip46; sin.sin6_port = htons(ps->endpoint.port); fsin = &sin; } ZERO(mh); mh.msg_control = ctrl; mh.msg_controllen = sizeof(ctrl); mh.msg_name = fsin; mh.msg_namelen = sizeof(*fsin); mh.msg_iov = &iov; mh.msg_iovlen = 1; ZERO(iov); iov.iov_base = buf; iov.iov_len = ret; stream_msg_mh_src(ps, &mh); sendmsg(ps->sfd->fd.fd, &mh, 0); return 0; }