static void accept_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *a, int slen, void *p) { struct bufferevent *b_out, *b_in; /* Create two linked bufferevent objects: one to connect, one for the * new connection */ b_in = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); if (!ssl_ctx || use_wrapper) b_out = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); else { SSL *ssl = SSL_new(ssl_ctx); b_out = bufferevent_openssl_socket_new(base, -1, ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); } assert(b_in && b_out); if (bufferevent_socket_connect(b_out, (struct sockaddr*)&connect_to_addr, connect_to_addrlen)<0) { perror("bufferevent_socket_connect"); bufferevent_free(b_out); bufferevent_free(b_in); return; } if (ssl_ctx && use_wrapper) { struct bufferevent *b_ssl; SSL *ssl = SSL_new(ssl_ctx); b_ssl = bufferevent_openssl_filter_new(base, b_out, ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); if (!b_ssl) { perror("Bufferevent_openssl_new"); bufferevent_free(b_out); bufferevent_free(b_in); } b_out = b_ssl; } bufferevent_setcb(b_in, readcb, NULL, eventcb, b_out); bufferevent_setcb(b_out, readcb, NULL, eventcb, b_in); bufferevent_enable(b_in, EV_READ|EV_WRITE); bufferevent_enable(b_out, EV_READ|EV_WRITE); }
static void open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out, struct event_base *base, int is_open, int flags, SSL *ssl1, SSL *ssl2, evutil_socket_t *fd_pair, struct bufferevent **underlying_pair) { int state1 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_CONNECTING; int state2 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_ACCEPTING; if (fd_pair) { *bev1_out = bufferevent_openssl_socket_new( base, fd_pair[0], ssl1, state1, flags); *bev2_out = bufferevent_openssl_socket_new( base, fd_pair[1], ssl2, state2, flags); } else { *bev1_out = bufferevent_openssl_filter_new( base, underlying_pair[0], ssl1, state1, flags); *bev2_out = bufferevent_openssl_filter_new( base, underlying_pair[1], ssl2, state2, flags); } bufferevent_setcb(*bev1_out, respond_to_number, done_writing_cb, eventcb, (void*)"client"); bufferevent_setcb(*bev2_out, respond_to_number, done_writing_cb, eventcb, (void*)"server"); }
static int imap_starttls(struct imap_context *ctx, struct imap_request *req, void *priv) { struct bufferevent *bev = ctx->client_bev; struct evbuffer *output = bufferevent_get_output(bev); SSL *ssl_client_ctx = SSL_new(ctx->driver->ssl_ctx); bufferevent_data_cb readcb, writecb; bufferevent_event_cb eventcb; void *orig_ctx; if (ctx->state & IMAP_TLS) { evbuffer_add_printf(output, "%s BAD TLS layer already in place" CRLF, req->tag.bv_val); return IMAP_OK; } /* retrieve the callbacks to apply them again on the filtering bev */ bufferevent_getcb(bev, &readcb, &writecb, &eventcb, &orig_ctx); evbuffer_add_printf(output, "%s OK Begin TLS negotiation now" CRLF, req->tag.bv_val); bev = bufferevent_openssl_filter_new(ctx->driver->base, bev, ssl_client_ctx, BUFFEREVENT_SSL_ACCEPTING, BEV_OPT_CLOSE_ON_FREE); if (!bev) { return IMAP_SHUTDOWN; } bufferevent_setcb(bev, readcb, writecb, eventcb, orig_ctx); bufferevent_enable(bev, EV_READ|EV_WRITE); ctx->client_bev = bev; ctx->state |= IMAP_TLS; return IMAP_OK; }
struct bufferevent* red_connect_relay_ssl(const char *ifname, struct sockaddr_in *addr, SSL * ssl, bufferevent_data_cb readcb, bufferevent_data_cb writecb, bufferevent_event_cb errorcb, void *cbarg, const struct timeval *timeout_write) { struct bufferevent *retval = NULL; struct bufferevent *underlying = NULL; int relay_fd = -1; int error; underlying = red_prepare_relay(ifname, NULL, NULL, NULL, NULL); if (!underlying) goto fail; relay_fd = bufferevent_getfd(underlying); if (timeout_write) bufferevent_set_timeouts(underlying, NULL, timeout_write); error = connect(relay_fd, (struct sockaddr*)addr, sizeof(*addr)); if (error && errno != EINPROGRESS) { log_errno(LOG_NOTICE, "connect"); goto fail; } retval = bufferevent_openssl_filter_new(bufferevent_get_base(underlying), underlying, ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS); if (!retval) { log_errno(LOG_NOTICE, "bufferevent_openssl_filter_new"); goto fail; } if (timeout_write) bufferevent_set_timeouts(retval, NULL, timeout_write); bufferevent_setcb(retval, readcb, writecb, errorcb, cbarg); if (writecb) { error = bufferevent_enable(retval, EV_WRITE); // we wait for connection... if (error) { log_errno(LOG_ERR, "bufferevent_enable"); goto fail; } } return retval; fail: if (retval) { bufferevent_disable(retval, EV_READ|EV_WRITE); bufferevent_free(retval); } if (underlying) { bufferevent_disable(underlying, EV_READ|EV_WRITE); bufferevent_free(underlying); } if (relay_fd != -1) redsocks_close(relay_fd); return NULL; }
// This starts a new TCP/TLS connection to notblocked // It is called both when a new local proxy connection is accepted // and when we need to re-open an existing telex transport (state->local is reused) void make_new_telex_conn(struct telex_state *state) { struct telex_conf *conf = state->conf; HexDump(LOG_TRACE, state->name, "Opening telex id:", state->remote_conn_id, sizeof(state->remote_conn_id)); state->remotetcp = bufferevent_socket_new(state->base, -1, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); if (!state->remotetcp) { LogError(state->name, "Could not create remote bufferevent socket"); StateCleanup(&state); return; } _inc(BEV); // TODO: make nonblocking lookup? bufferevent_socket_connect_hostname(state->remotetcp, NULL, AF_INET, conf->notblocked_host, conf->notblocked_port); // After resolution... /* struct sockaddr_in sin; if (getpeername(bufferevent_getfd(state->remotetcp), (struct sockaddr *)&sin, (socklen_t*)sizeof(sin)) < 0) { perror("getpeername"); LogError("proxy", "getpeername failed"); StateCleanup(&state); return; } char ip_p[INET_ADDRSTRLEN]; LogTrace(state->name, "Connecting to %s:%d", evutil_inet_ntop(AF_INET, server_ip, ip_p, sizeof(ip_p)), state->conf->notblocked_port); //bufferevent_socket_connect(state->remotetcp, ai->ai_addr, (int)ai->ai_addrlen); */ if (ssl_new_telex(state) < 0) { ssl_log_errors(LOG_ERROR, state->name); LogError(state->name, "Could not create new telex SSL connection object"); StateCleanup(&state); return; } _inc(SSL); state->remote = bufferevent_openssl_filter_new(state->base, state->remotetcp, state->ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS); // Not BEV_OPT_CLOSE_ON_FREE! if (!state->remote) { LogError(state->name, "Could not create remote SSL bufferevent filter"); StateCleanup(&state); return; } _inc(BEV); // First, set our read_cb to something that receives the SPTelex init message bufferevent_setcb(state->remote, (bufferevent_data_cb)first_read_cb, NULL, (bufferevent_event_cb)event_cb, state); // Disable until SPTelex init msg bufferevent_disable(state->local, EV_READ|EV_WRITE); bufferevent_setcb(state->local, (bufferevent_data_cb)read_cb, NULL, (bufferevent_event_cb)event_cb, state); // Hmm...we should make a second one of these state->in_local = 0; }