/** Print a CMETHOD/SMETHOD line saying that we launched 'transport' with 'cfg' under 'proxy'. */ static void print_method_line(const char *transport, const managed_proxy_t *proxy, config_t *cfg) { struct evconnlistener *listener = get_evconnlistener_by_config(cfg); obfs_assert(listener); struct sockaddr_in saddr; memset(&saddr,0,sizeof(struct sockaddr_in)); socklen_t slen = sizeof(saddr); obfs_assert(!(getsockname(evconnlistener_get_fd(listener), (struct sockaddr *)&saddr, &slen) < 0)); if (proxy->is_server) { print_protocol_line("%s %s %s:%hu\n", PROTO_SMETHOD, transport, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); } else { print_protocol_line("%s %s %s %s:%hu\n", PROTO_CMETHOD, transport, "socks5", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); } }
int regress_get_listener_addr(struct evconnlistener *lev, struct sockaddr *sa, ev_socklen_t *socklen) { evutil_socket_t s = evconnlistener_get_fd(lev); if (s <= 0) return -1; return getsockname(s, sa, socklen); }
/* Start the server listening on a random port and start the first client. */ static void start_loop(void) { struct event_base *base; struct evconnlistener *listener; struct sockaddr_storage ss; ev_socklen_t socklen = sizeof(ss); evutil_socket_t fd; base = event_base_new(); if (base == NULL) { puts("Could not open event base!"); exit(1); } listener = evconnlistener_new_bind(base, listener_accept_cb, NULL, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1, (struct sockaddr *)&saddr, sizeof(saddr)); if (listener == NULL) { my_perror("Could not create listener!"); exit(1); } fd = evconnlistener_get_fd(listener); if (fd < 0) { puts("Couldn't get fd from listener"); exit(1); } if (getsockname(fd, (struct sockaddr *)&ss, &socklen) < 0) { my_perror("getsockname()"); exit(1); } memcpy(&saddr, &ss, sizeof(saddr)); if (saddr.sin_family != AF_INET) { puts("AF mismatch from getsockname()."); exit(1); } start_client(base); event_base_dispatch(base); }
int main(int argc, char* argv[]) { daemon(1, 1); glog_init(argv[0]); sockaddr addr; int len = sizeof(sockaddr); evutil_parse_sockaddr_port("127.0.0.1:5000", &addr, &len); event_base* pbase = event_base_new(); char test[32] = "test data"; evconnlistener* plistener = evconnlistener_new_bind(pbase, listener_cb, reinterpret_cast<void*>(test), LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 10, &addr, len); LOG(INFO) << evconnlistener_get_fd(plistener); event_base_dispatch(pbase); evconnlistener_free(plistener); event_base_free(pbase); return 0; }
static void regress_pick_a_port(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evconnlistener *listener1 = NULL, *listener2 = NULL; //struct event *connecting; struct sockaddr_in sin; int count1 = 2, count2 = 1; struct sockaddr_storage ss1, ss2; struct sockaddr_in *sin1, *sin2; ev_socklen_t slen1 = sizeof(ss1), slen2 = sizeof(ss2); unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC; evutil_socket_t fd1 = -1, fd2 = -1, fd3 = -1; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ sin.sin_port = 0; /* "You pick!" */ listener1 = evconnlistener_new_bind(base, acceptcb, &count1, flags, -1, (struct sockaddr *)&sin, sizeof(sin)); tt_assert(listener1); listener2 = evconnlistener_new_bind(base, acceptcb, &count2, flags, -1, (struct sockaddr *)&sin, sizeof(sin)); tt_assert(listener2); tt_int_op(evconnlistener_get_fd(listener1), >=, 0); tt_int_op(evconnlistener_get_fd(listener2), >=, 0); tt_assert(getsockname(evconnlistener_get_fd(listener1), (struct sockaddr*)&ss1, &slen1) == 0); tt_assert(getsockname(evconnlistener_get_fd(listener2), (struct sockaddr*)&ss2, &slen2) == 0); tt_int_op(ss1.ss_family, ==, AF_INET); tt_int_op(ss2.ss_family, ==, AF_INET); sin1 = (struct sockaddr_in*)&ss1; sin2 = (struct sockaddr_in*)&ss2; tt_int_op(ntohl(sin1->sin_addr.s_addr), ==, 0x7f000001); tt_int_op(ntohl(sin2->sin_addr.s_addr), ==, 0x7f000001); tt_int_op(sin1->sin_port, !=, sin2->sin_port); tt_ptr_op(evconnlistener_get_base(listener1), ==, base); tt_ptr_op(evconnlistener_get_base(listener2), ==, base); fd1 = fd2 = fd3 = -1; evutil_socket_connect(&fd1, (struct sockaddr*)&ss1, slen1); evutil_socket_connect(&fd2, (struct sockaddr*)&ss1, slen1); evutil_socket_connect(&fd3, (struct sockaddr*)&ss2, slen2); #ifdef WIN32 Sleep(100); /* XXXX this is a stupid stopgap. */ #endif event_base_dispatch(base); tt_int_op(count1, ==, 0); tt_int_op(count2, ==, 0); end: if (fd1>=0) EVUTIL_CLOSESOCKET(fd1); if (fd2>=0) EVUTIL_CLOSESOCKET(fd2); if (fd3>=0) EVUTIL_CLOSESOCKET(fd3); }
static int test_ratelimiting(void) { struct event_base *base; struct sockaddr_in sin; struct evconnlistener *listener; struct sockaddr_storage ss; ev_socklen_t slen; struct bufferevent **bevs; struct client_state *states; struct bufferevent_rate_limit_group *group = NULL; int i; struct timeval tv; ev_uint64_t total_received; double total_sq_persec, total_persec; double variance; double expected_total_persec = -1.0, expected_avg_persec = -1.0; int ok = 1; struct event_config *base_cfg; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ sin.sin_port = 0; /* unspecified port */ if (0) event_enable_debug_mode(); base_cfg = event_config_new(); #ifdef _WIN32 if (cfg_enable_iocp) { evthread_use_windows_threads(); event_config_set_flag(base_cfg, EVENT_BASE_FLAG_STARTUP_IOCP); } #endif base = event_base_new_with_config(base_cfg); listener = evconnlistener_new_bind(base, echo_listenercb, base, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1, (struct sockaddr *)&sin, sizeof(sin)); slen = sizeof(ss); if (getsockname(evconnlistener_get_fd(listener), (struct sockaddr *)&ss, &slen) < 0) { perror("getsockname"); return 1; } if (cfg_connlimit > 0) { conn_bucket_cfg = ev_token_bucket_cfg_new( cfg_connlimit, cfg_connlimit * 4, cfg_connlimit, cfg_connlimit * 4, &cfg_tick); assert(conn_bucket_cfg); } if (cfg_grouplimit > 0) { group_bucket_cfg = ev_token_bucket_cfg_new( cfg_grouplimit, cfg_grouplimit * 4, cfg_grouplimit, cfg_grouplimit * 4, &cfg_tick); group = ratelim_group = bufferevent_rate_limit_group_new( base, group_bucket_cfg); expected_total_persec = cfg_grouplimit; expected_avg_persec = cfg_grouplimit / cfg_n_connections; if (cfg_connlimit > 0 && expected_avg_persec > cfg_connlimit) expected_avg_persec = cfg_connlimit; if (cfg_min_share >= 0) bufferevent_rate_limit_group_set_min_share( ratelim_group, cfg_min_share); } if (expected_avg_persec < 0 && cfg_connlimit > 0) expected_avg_persec = cfg_connlimit; if (expected_avg_persec > 0) expected_avg_persec /= seconds_per_tick; if (expected_total_persec > 0) expected_total_persec /= seconds_per_tick; bevs = calloc(cfg_n_connections, sizeof(struct bufferevent *)); states = calloc(cfg_n_connections, sizeof(struct client_state)); for (i = 0; i < cfg_n_connections; ++i) { bevs[i] = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE); assert(bevs[i]); bufferevent_setcb(bevs[i], discard_readcb, loud_writecb, write_on_connectedcb, &states[i]); bufferevent_enable(bevs[i], EV_READ|EV_WRITE); bufferevent_socket_connect(bevs[i], (struct sockaddr *)&ss, slen); } tv.tv_sec = cfg_duration - 1; tv.tv_usec = 995000; event_base_loopexit(base, &tv); event_base_dispatch(base); ratelim_group = NULL; /* So no more responders get added */ for (i = 0; i < cfg_n_connections; ++i) { bufferevent_free(bevs[i]); } evconnlistener_free(listener); /* Make sure no new echo_conns get added to the group. */ ratelim_group = NULL; /* This should get _everybody_ freed */ while (n_echo_conns_open) { printf("waiting for %d conns\n", n_echo_conns_open); tv.tv_sec = 0; tv.tv_usec = 300000; event_base_loopexit(base, &tv); event_base_dispatch(base); } if (group) bufferevent_rate_limit_group_free(group); total_received = 0; total_persec = 0.0; total_sq_persec = 0.0; for (i=0; i < cfg_n_connections; ++i) { double persec = states[i].received; persec /= cfg_duration; total_received += states[i].received; total_persec += persec; total_sq_persec += persec*persec; printf("%d: %f per second\n", i+1, persec); } printf(" total: %f per second\n", ((double)total_received)/cfg_duration); if (expected_total_persec > 0) { double diff = expected_total_persec - ((double)total_received/cfg_duration); printf(" [Off by %lf]\n", diff); if (cfg_grouplimit_tolerance > 0 && fabs(diff) > cfg_grouplimit_tolerance) { fprintf(stderr, "Group bandwidth out of bounds\n"); ok = 0; } } printf(" average: %f per second\n", (((double)total_received)/cfg_duration)/cfg_n_connections); if (expected_avg_persec > 0) { double diff = expected_avg_persec - (((double)total_received)/cfg_duration)/cfg_n_connections; printf(" [Off by %lf]\n", diff); if (cfg_connlimit_tolerance > 0 && fabs(diff) > cfg_connlimit_tolerance) { fprintf(stderr, "Connection bandwidth out of bounds\n"); ok = 0; } } variance = total_sq_persec/cfg_n_connections - total_persec*total_persec/(cfg_n_connections*cfg_n_connections); printf(" stddev: %f per second\n", sqrt(variance)); if (cfg_stddev_tolerance > 0 && sqrt(variance) > cfg_stddev_tolerance) { fprintf(stderr, "Connection variance out of bounds\n"); ok = 0; } event_base_free(base); free(bevs); free(states); return ok ? 0 : 1; }
static void test_bufferevent_connect_hostname(void *arg) { struct basic_test_data *data = arg; struct evconnlistener *listener = NULL; struct bufferevent *be1=NULL, *be2=NULL, *be3=NULL, *be4=NULL, *be5=NULL; int be1_outcome=0, be2_outcome=0, be3_outcome=0, be4_outcome=0, be5_outcome=0; struct evdns_base *dns=NULL; struct evdns_server_port *port=NULL; evutil_socket_t server_fd=-1; struct sockaddr_in sin; int listener_port=-1; ev_uint16_t dns_port=0; int n_accept=0, n_dns=0; char buf[128]; be_connect_hostname_base = data->base; /* Bind an address and figure out what port it's on. */ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ sin.sin_port = 0; listener = evconnlistener_new_bind(data->base, nil_accept_cb, &n_accept, LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC, -1, (struct sockaddr *)&sin, sizeof(sin)); listener_port = regress_get_socket_port( evconnlistener_get_fd(listener)); port = regress_get_dnsserver(data->base, &dns_port, NULL, be_getaddrinfo_server_cb, &n_dns); tt_assert(port); tt_int_op(dns_port, >=, 0); /* Start an evdns_base that uses the server as its resolver. */ dns = evdns_base_new(data->base, 0); evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", dns_port); evdns_base_nameserver_ip_add(dns, buf); /* Now, finally, at long last, launch the bufferevents. One should do * a failing lookup IP, one should do a successful lookup by IP, * and one should do a successful lookup by hostname. */ be1 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); be2 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); be3 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); be4 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); be5 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(be1, NULL, NULL, be_connect_hostname_event_cb, &be1_outcome); bufferevent_setcb(be2, NULL, NULL, be_connect_hostname_event_cb, &be2_outcome); bufferevent_setcb(be3, NULL, NULL, be_connect_hostname_event_cb, &be3_outcome); bufferevent_setcb(be4, NULL, NULL, be_connect_hostname_event_cb, &be4_outcome); bufferevent_setcb(be5, NULL, NULL, be_connect_hostname_event_cb, &be5_outcome); /* Launch an async resolve that will fail. */ tt_assert(!bufferevent_socket_connect_hostname(be1, dns, AF_INET, "nosuchplace.example.com", listener_port)); /* Connect to the IP without resolving. */ tt_assert(!bufferevent_socket_connect_hostname(be2, dns, AF_INET, "127.0.0.1", listener_port)); /* Launch an async resolve that will succeed. */ tt_assert(!bufferevent_socket_connect_hostname(be3, dns, AF_INET, "nobodaddy.example.com", listener_port)); /* Use the blocking resolver. This one will fail if your resolver * can't resolve localhost to 127.0.0.1 */ tt_assert(!bufferevent_socket_connect_hostname(be4, NULL, AF_INET, "localhost", listener_port)); /* Use the blocking resolver with a nonexistent hostname. */ tt_assert(!bufferevent_socket_connect_hostname(be5, NULL, AF_INET, "nonesuch.nowhere.example.com", 80)); event_base_dispatch(data->base); tt_int_op(be1_outcome, ==, BEV_EVENT_ERROR); tt_int_op(be2_outcome, ==, BEV_EVENT_CONNECTED); tt_int_op(be3_outcome, ==, BEV_EVENT_CONNECTED); tt_int_op(be4_outcome, ==, BEV_EVENT_CONNECTED); tt_int_op(be5_outcome, ==, BEV_EVENT_ERROR); tt_int_op(n_accept, ==, 3); tt_int_op(n_dns, ==, 2); end: if (listener) evconnlistener_free(listener); if (server_fd>=0) EVUTIL_CLOSESOCKET(server_fd); if (port) evdns_close_server_port(port); if (dns) evdns_base_free(dns, 0); if (be1) bufferevent_free(be1); if (be2) bufferevent_free(be2); if (be3) bufferevent_free(be3); if (be4) bufferevent_free(be4); if (be5) bufferevent_free(be5); }
inline static void setup_relays(void) { if(!*options.relay_ports) { debug("relays: missing ports"); teardown_control(); return; } const char *w = options.relay_ports; for(context.relays_count = 1; *w; ++ w) context.relays_count += *w == ','; debug("relays: setting up tcp channels port"); evconnlistener_set_cb( context.listener.tcp, accept_tcp_channel, NULL); debug("relays: setting up %d relay ports", context.relays_count); context.relays = (struct RelayListener *) malloc( context.relays_count * sizeof(struct RelayListener)); w = options.relay_ports; struct RelayListener *cur = context.relays; uint8_t udp = 0; for(int c = 0; c < context.relays_count; ++ c) { char proto[4]; int32_t bytes; if(sscanf(w, "%[^:]:%hu,%n", proto, &cur->port, &bytes) != 2) { debug("relays: invalid relay ports format"); context.relays_count = c; teardown_control(); return; } if(!strcmp(proto, "tcp")) { debug("relays: setting up tcp relay %d", cur->port); cur->proto = IPPROTO_TCP; struct sockaddr_in relay; memset(&relay, 0, sizeof(relay)); relay.sin_family = AF_INET; if(options.address) { debug("relays: binding to address %s", options.address); inet_pton(AF_INET, options.address, &relay.sin_addr); } else relay.sin_addr.s_addr = INADDR_ANY; relay.sin_port = htons(cur->port); cur->tcp_listener = evconnlistener_new_bind( context.events, accept_tcp_peer, cur, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1, (struct sockaddr *) &relay, sizeof(relay)); if(!cur->tcp_listener) { perror("evconnlistener_new_bind"); context.relays_count = c; teardown_control(); return; } if(options.interface) { evutil_socket_t fd = evconnlistener_get_fd(cur->tcp_listener); debug( "relays: binding fd:%d to interface %s", fd, options.interface); assert(fd != -1); struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, options.interface, sizeof(ifr.ifr_name)); if(setsockopt( fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1) { perror("setsockopt"); context.relays_count = c; teardown_control(); return; } } evconnlistener_set_error_cb(cur->tcp_listener, error_on_tcp_peer_listener); ++ cur; w += bytes; } else if(!strcmp(proto, "udp")) { udp = 1; debug("relays: setting up udp relay %d", cur->port); cur->proto = IPPROTO_UDP; struct sockaddr_in relay; memset(&relay, 0, sizeof(relay)); relay.sin_family = AF_INET; if(options.address) { debug("relays: binding to address %s", options.address); inet_pton(AF_INET, options.address, &relay.sin_addr); } else relay.sin_addr.s_addr = INADDR_ANY; relay.sin_port = htons(cur->port); evutil_socket_t ufd = socket(AF_INET, SOCK_DGRAM, 0); assert(ufd != -1); //evutil_make_socket_nonblocking(ufd); maybe? if(options.interface) { debug( "relays: binding fd:%d to interface %s", ufd, options.interface); struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, options.interface, sizeof(ifr.ifr_name)); if(setsockopt( ufd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1) { perror("setsockopt"); context.relays_count = c; teardown_control(); return; } } if(bind(ufd, (struct sockaddr *) &relay, sizeof(relay)) == -1) { perror("bind"); context.relays_count = c; teardown_control(); return; } cur->udp_listener = event_new( context.events, ufd, EV_READ | EV_PERSIST, read_udp_peer, cur); event_add(cur->udp_listener, NULL); ++ cur; w += bytes; } else { debug("relays: unsupported protocol %s", proto); context.relays_count = c; teardown_control(); return; } } if(udp) { debug("relays: setting up udp channels port"); struct sockaddr_in relay; memset(&relay, 0, sizeof(relay)); relay.sin_family = AF_INET; if(options.address) { debug("relays: binding to address %s", options.address); inet_pton(AF_INET, options.address, &relay.sin_addr); } else relay.sin_addr.s_addr = INADDR_ANY; relay.sin_port = htons(options.control_port); evutil_socket_t ufd = socket(AF_INET, SOCK_DGRAM, 0); //evutil_make_socket_nonblocking(ufd); maybe? if(options.interface) { debug( "relays: binding fd:%d to interface %s", ufd, options.interface); struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, options.interface, sizeof(ifr.ifr_name)); if(setsockopt( ufd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1) { perror("setsockopt"); teardown_control(); return; } } if(bind(ufd, (struct sockaddr *) &relay, sizeof(relay)) == -1) { perror("bind"); teardown_control(); return; } context.listener.udp = event_new( context.events, ufd, EV_READ | EV_PERSIST, read_udp_channel, NULL); event_add(context.listener.udp, NULL); } }
int obfsproxyssh_client_init(obfsproxyssh_t *state) { obfsproxyssh_client_t *client; struct sockaddr_storage addr; evutil_socket_t sock; uint16_t port; int rval, len; client = calloc(1, sizeof(obfsproxyssh_client_t)); if (NULL == client) { fprintf(stdout, "CMETHOD-ERROR %s Out of memory allocating state\n", OBFSPROXYSSH_METHOD); return -1; } client->state = state; memset(&addr, 0, sizeof(addr)); len = sizeof(addr); evutil_parse_sockaddr_port(OBFSPROXYSSH_CLIENT_BIND_ADDR ":8080", (struct sockaddr *) &addr, &len); ((struct sockaddr_in *) &addr)->sin_port = 0; /* Use ephemeral port */ client->listener = evconnlistener_new_bind(state->base, socks_accept_cb, client, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1, (struct sockaddr *) &addr, len); if (NULL == client->listener) { fprintf(stdout, "CMETHOD-ERROR %s Failed to bind SOCKS socket\n", OBFSPROXYSSH_METHOD); goto out_error; } evconnlistener_set_error_cb(client->listener, client_error_cb); sock = evconnlistener_get_fd(client->listener); len = sizeof(addr); rval = getsockname(sock, (struct sockaddr *) &addr, (socklen_t *) &len); if (rval) { fprintf(stdout, "CMETHOD-ERROR %s Failed to get SOCKS socket addr %d\n", OBFSPROXYSSH_METHOD, rval); goto out_free_listener; } port = htons(((struct sockaddr_in *) &addr)->sin_port); rval = libssh2_init(0); if (rval) { fprintf(stdout, "CMETHOD-ERROR %s Failed to initialize libssh2 (%d)\n", OBFSPROXYSSH_METHOD, rval); goto out_free_listener; } rval = ssh_client_profile_init(client); if (rval) { fprintf(stdout, "CMETHOD-ERROR %s Failed to initialize libssh2 algorithms (%d)\n", OBFSPROXYSSH_METHOD, rval); goto out_free_listener; } if (0 == state->unsafe_logging) log_f(state, "SOCKS: Listening on: TCP port %d", port); else log_f(state, "SOCKS: Listening on: %s:%d", OBFSPROXYSSH_CLIENT_BIND_ADDR, port); fprintf(stdout, "CMETHOD %s socks4 %s:%d %s\n", OBFSPROXYSSH_METHOD, OBFSPROXYSSH_CLIENT_BIND_ADDR, port, OBFSPROXYSSH_CLIENT_CMETHOD_ARGS); LIST_INIT(&client->sessions); LIST_INIT(&client->arg_cache); state->ctxt = client; state->shutdown_fn = client_on_shutdown; return 0; out_free_listener: evconnlistener_free(client->listener); out_error: free(client); return -1; }