/* call must be locked */ void dtls_shutdown(struct packet_stream *ps) { struct dtls_connection *d; struct sockaddr_in6 sin; if (!ps || !ps->sfd) return; __DBG("dtls_shutdown"); d = &ps->sfd->dtls; if (!d->init) return; if (d->connected && d->ssl) { ZERO(sin); sin.sin6_family = AF_INET6; sin.sin6_addr = ps->endpoint.ip46; sin.sin6_port = htons(ps->endpoint.port); SSL_shutdown(d->ssl); dtls(ps, NULL, &sin); } dtls_connection_cleanup(d); if (ps->dtls_cert) { X509_free(ps->dtls_cert); ps->dtls_cert = NULL; } crypto_reset(&ps->crypto); crypto_reset(&ps->sfd->crypto); }
void vpn_thread(void *arg) { struct Ctunnel *ct; struct Network *n; int ret = 0; time_t t, tl; unsigned char *data = NULL; unsigned char *rwind = NULL; struct timeval tv; fd_set rfd; #ifdef HAVE_OPENSSL do_encrypt = openssl_do_encrypt; do_decrypt = openssl_do_decrypt; crypto_init = openssl_crypto_init; crypto_deinit = openssl_crypto_deinit; crypto_reset = openssl_crypto_reset; #else do_encrypt = gcrypt_do_encrypt; do_decrypt = gcrypt_do_decrypt; crypto_init = gcrypt_crypto_init; crypto_deinit = gcrypt_crypto_deinit; crypto_reset = gcrypt_crypto_reset; #endif struct xfer_stats rx_st, tx_st; t = tl = time(NULL); ct = (struct Ctunnel *) arg; if (ct->opt.comp == 1) ct->comp = z_compress_init(ct->opt); /* Data size, plus int for channel */ data = malloc(ct->opt.packet_size); rwind = data; xfer_stats_init(&tx_st, (int) t); xfer_stats_init(&rx_st, (int) t); if (ct->opt.stats == 1) xfer_stats_print(stdout, &tx_st, &rx_st); while (1) { FD_ZERO(&rfd); FD_SET(ct->net_srv->sockfd, &rfd); FD_SET(ct->tunfd, &rfd); //FD_SET(ct->p[0], &rfd); tv.tv_sec = 10; tv.tv_usec = 0; if (ct->opt.proto == UDP) { crypto_reset(ct->ectx, ct->opt, 1); crypto_reset(ct->dctx, ct->opt, 0); } ret = select(ct->net_srv->sockfd + ct->tunfd, &rfd, NULL, NULL, &tv); // for ppp //ret = select(ct->net_srv->sockfd + ct->tunfd, &rfd, // NULL, NULL, NULL); t = time(NULL); if (ct->opt.stats == 1) xfer_stats_print(stdout, &tx_st, &rx_st); /* Not functioning if (ret == 0 || (t > tl+10)) { if (ct->opt.role != SERVER) { ping(ct, ct->net_srv); } tl = t; } Need to redial server if connection timeout, make sure to re-resolv address before connect */ if (ret > 0) { n = ct->net_srv; if (FD_ISSET(ct->tunfd, &rfd)) { *data++ = PACKET_DATA; ret = read(ct->tunfd, data, ct->opt.packet_size); data = rwind; if (ret > 0 && n) { if ((ret = net_write(ct, n, data, ret + sizeof(int), 1)) < 0) ctunnel_log(stderr, LOG_CRIT, "net_write:%d %s", __LINE__, strerror(errno)); xfer_stats_update(&tx_st, ct->net_srv->rate.tx.total, t); } else { ctunnel_log(stderr, LOG_CRIT, "tunfd read:%d %s", __LINE__, strerror(errno)); } } if (FD_ISSET(ct->net_srv->sockfd, &rfd)) { ret = net_read(ct, n, data, ct->opt.packet_size, 1); if (ret > 0) { xfer_stats_update(&rx_st, ct->net_srv->rate.rx.total, t); if (*data == PACKET_DATA) { if ((connected(n) < 0) && (ct->opt.role == SERVER)) { data = rwind; *data++ = PACKET_REUP; data = rwind; net_write(ct, n, data, sizeof(int) * 2, 1); } else { data++; write(ct->tunfd, data, ret - sizeof(int)); data = rwind; } } if (*data == PACKET_CONRQ) { ctunnel_log(stdout, LOG_INFO, "Connect request from %s", inet_ntoa((struct in_addr) ct->net_srv->addr.sin_addr)); vpn_handshake(ct); } /* Not functioning if (*data == PACKET_PING) { ct->seen = time(NULL); if (ct->opt.role == SERVER) ping(ct, ct->net_srv); } */ if ((*data == PACKET_REUP) && ct->opt.role != SERVER) { vpn_handshake(ct); } } else { ctunnel_log(stderr, LOG_CRIT, "net_read:74 %s", strerror(errno)); break; } } } } FD_CLR(ct->net_srv->sockfd, &rfd); FD_CLR(ct->tunfd, &rfd); pthread_mutex_lock(&mutex); threads[ct->id] = 2; pthread_mutex_unlock(&mutex); net_close(ct->net_srv); free(data); fprintf(stdout, "VPN Disconnect\n"); crypto_deinit(ct->ectx); crypto_deinit(ct->dctx); pthread_exit(0); }