Merge branch 'feature/socks5_rework'
This commit is contained in:
commit
febfed9d1d
11 changed files with 584 additions and 339 deletions
|
@ -19,6 +19,7 @@ int on_tcp_co(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
in_len = sizeof(addr);
|
in_len = sizeof(addr);
|
||||||
conn_sock1 = accept(fdinfo->fd, (struct sockaddr*)&addr, &in_len);
|
conn_sock1 = accept(fdinfo->fd, (struct sockaddr*)&addr, &in_len);
|
||||||
|
|
||||||
|
if (conn_sock1 == -1 && errno == EAGAIN) return 1;
|
||||||
if (conn_sock1 == -1) goto co_error;
|
if (conn_sock1 == -1) goto co_error;
|
||||||
conn_sock2 = dup(conn_sock1);
|
conn_sock2 = dup(conn_sock1);
|
||||||
if (conn_sock2 == -1) goto co_error;
|
if (conn_sock2 == -1) goto co_error;
|
||||||
|
@ -36,7 +37,7 @@ int on_tcp_co(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
sprintf(to_fdinfo.url, "tcp:write:127.0.0.1:%s", port);
|
sprintf(to_fdinfo.url, "tcp:write:127.0.0.1:%s", port);
|
||||||
evt_core_add_fd (ctx, &to_fdinfo);
|
evt_core_add_fd (ctx, &to_fdinfo);
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
co_error:
|
co_error:
|
||||||
perror("Failed to handle new connection");
|
perror("Failed to handle new connection");
|
||||||
|
|
|
@ -47,6 +47,7 @@ int rr_on_tcp_co(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
in_len = sizeof(addr);
|
in_len = sizeof(addr);
|
||||||
conn_sock1 = accept(fdinfo->fd, (struct sockaddr*)&addr, &in_len);
|
conn_sock1 = accept(fdinfo->fd, (struct sockaddr*)&addr, &in_len);
|
||||||
|
|
||||||
|
if (conn_sock1 == -1 && errno == EAGAIN) return 1;
|
||||||
if (conn_sock1 == -1) goto co_error;
|
if (conn_sock1 == -1) goto co_error;
|
||||||
conn_sock2 = dup(conn_sock1);
|
conn_sock2 = dup(conn_sock1);
|
||||||
if (conn_sock2 == -1) goto co_error;
|
if (conn_sock2 == -1) goto co_error;
|
||||||
|
@ -64,7 +65,7 @@ int rr_on_tcp_co(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
sprintf(to_fdinfo.url, "tcp:write:127.0.0.1:%s", port);
|
sprintf(to_fdinfo.url, "tcp:write:127.0.0.1:%s", port);
|
||||||
evt_core_add_fd (ctx, &to_fdinfo);
|
evt_core_add_fd (ctx, &to_fdinfo);
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
co_error:
|
co_error:
|
||||||
perror("Failed to handle new connection");
|
perror("Failed to handle new connection");
|
||||||
|
|
|
@ -5,47 +5,7 @@ void load_onion_services(struct donar_client_ctx* ctx, char* onion_file, int por
|
||||||
tor_os_read (&(ctx->tos));
|
tor_os_read (&(ctx->tos));
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_tcp_client(struct donar_client_ctx* ctx, int i) {
|
void init_socks5_client(struct donar_client_ctx* app_ctx, int pos) {
|
||||||
struct evt_core_cat cat = {0};
|
|
||||||
struct evt_core_fdinfo fdinfo = {0};
|
|
||||||
char url_buf[255];
|
|
||||||
int err;
|
|
||||||
|
|
||||||
ctx->ports[i] = 7500 + i;
|
|
||||||
cat.name = "configure-socks5";
|
|
||||||
fdinfo.cat = &cat;
|
|
||||||
fdinfo.url = url_buf;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
fdinfo.fd = create_tcp_client("127.0.0.1", "9050");
|
|
||||||
if (fdinfo.fd < 0) goto failed_socks5;
|
|
||||||
ctx->client_sock[i].fd = fdinfo.fd;
|
|
||||||
ctx->client_sock[i].state = SOCKS5_STATE_NEW;
|
|
||||||
sprintf(url_buf, "socks5:dist:%d", i);
|
|
||||||
evt_core_add_fd (&(ctx->evts), &fdinfo);
|
|
||||||
//@FIXME: We suppose that we will be able to do the whole write at once which is wrong
|
|
||||||
err = socks5_handshake_syn(fdinfo.fd);
|
|
||||||
if (err) goto failed_socks5;
|
|
||||||
|
|
||||||
break;
|
|
||||||
failed_socks5:
|
|
||||||
fprintf(stderr, "Failed connection for socket %d/%d. Sleeping 2 seconds...\n",i+1, CLIENT_PORT_SIZE);
|
|
||||||
close(fdinfo.fd);
|
|
||||||
sleep(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int configure_tcp_clients(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
|
||||||
int err, pos;
|
|
||||||
struct donar_client_ctx* app_ctx = (struct donar_client_ctx*) fdinfo->cat->app_ctx;
|
|
||||||
|
|
||||||
pos = -1;
|
|
||||||
for (int i = 0; i < CLIENT_PORT_SIZE; i++) {
|
|
||||||
if (app_ctx->client_sock[i].fd == fdinfo->fd) {
|
|
||||||
pos = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char target_host[255];
|
char target_host[255];
|
||||||
if (strlen(app_ctx->tos.keys[pos].pub) > 254) {
|
if (strlen(app_ctx->tos.keys[pos].pub) > 254) {
|
||||||
fprintf(stderr, "Domain name is too long\n");
|
fprintf(stderr, "Domain name is too long\n");
|
||||||
|
@ -53,91 +13,70 @@ int configure_tcp_clients(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdin
|
||||||
}
|
}
|
||||||
sprintf(target_host, "%s.onion", app_ctx->tos.keys[pos].pub);
|
sprintf(target_host, "%s.onion", app_ctx->tos.keys[pos].pub);
|
||||||
|
|
||||||
switch (app_ctx->client_sock[pos].state) {
|
|
||||||
case SOCKS5_STATE_NEW:
|
app_ctx->ports[pos] = 7500 + pos;
|
||||||
//@FIXME: We suppose that we will be able to do the whole read at once which is wrong
|
socks5_create_dns_client (&app_ctx->evts, "127.0.0.1", "9050", target_host, app_ctx->ports[pos]);
|
||||||
err = socks5_handshake_ack (fdinfo->fd);
|
|
||||||
if (err < 0) goto on_socks5_err;
|
|
||||||
//@FIXME: We suppose that we will be able to do the whole write at once which is wrong too
|
|
||||||
err = socks5_connect_dns(fdinfo->fd, target_host, app_ctx->ports[pos]);
|
|
||||||
if (err < 0) goto on_socks5_err;
|
|
||||||
app_ctx->client_sock[pos].state = SOCKS5_STATE_ACK;
|
|
||||||
printf("Socket %d/%d %s:%d is connecting...\n", pos+1, CLIENT_PORT_SIZE, target_host, app_ctx->ports[pos]);
|
|
||||||
break;
|
|
||||||
case SOCKS5_STATE_ACK:
|
|
||||||
//@FIXME: We suppose that we will be able to do the whole read at once which is wrong too
|
|
||||||
err = socks5_reply (fdinfo->fd);
|
|
||||||
if (err == -SOCKS5_REP_GENERAL_FAILURE || err == -SOCKS5_REP_TTLEXP || err == -SOCKS5_REP_HOSTUNREACH) {
|
|
||||||
fprintf(stderr, "%s is not ready, received %s\n", fdinfo->url, socks5_rep(-err));
|
|
||||||
goto on_socks5_err;
|
|
||||||
} else if (err < 0) {
|
|
||||||
fprintf(stderr, "An other error occured on %s\n", fdinfo->url);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
app_ctx->client_sock[pos].state = SOCKS5_STATE_RDY;
|
|
||||||
int sock1, sock2;
|
|
||||||
sock1 = dup(fdinfo->fd);
|
|
||||||
sock2 = dup(fdinfo->fd);
|
|
||||||
if (sock1 < 0 || sock2 < 0) {
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
void* fdcat = evt_core_rm_fd (ctx, fdinfo->fd);
|
|
||||||
if (fdcat == NULL) {
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct evt_core_fdinfo fdinfo = {0};
|
int on_socks5_success(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
struct evt_core_cat cat = {0};
|
struct evt_core_fdinfo fdinfo_n = {0};
|
||||||
|
struct evt_core_cat cat_n = {0};
|
||||||
char url[1024];
|
char url[1024];
|
||||||
fdinfo.cat = &cat;
|
struct socks5_ctx* s5ctx = fdinfo->other;
|
||||||
fdinfo.url = url;
|
fdinfo_n.cat = &cat_n;
|
||||||
|
fdinfo_n.url = url;
|
||||||
|
|
||||||
fdinfo.cat->name = "tcp-write";
|
fdinfo_n.fd = dup(fdinfo->fd);
|
||||||
fdinfo.fd = sock1;
|
fdinfo_n.cat->name = "tcp-write";
|
||||||
sprintf(fdinfo.url, "tcp:write:127.0.0.1:%d", app_ctx->ports[pos]);
|
sprintf(fdinfo_n.url, "tcp:write:127.0.0.1:%d", s5ctx->port);
|
||||||
evt_core_add_fd (ctx, &fdinfo);
|
evt_core_add_fd (ctx, &fdinfo_n);
|
||||||
|
|
||||||
fdinfo.cat->name = "tcp-read";
|
fdinfo_n.fd = dup(fdinfo->fd);
|
||||||
fdinfo.fd = sock2;
|
fdinfo_n.cat->name = "tcp-read";
|
||||||
sprintf(fdinfo.url, "tcp:read:127.0.0.1:%d", app_ctx->ports[pos]);
|
sprintf(fdinfo_n.url, "tcp:read:127.0.0.1:%d", s5ctx->port);
|
||||||
evt_core_add_fd (ctx, &fdinfo);
|
evt_core_add_fd (ctx, &fdinfo_n);
|
||||||
|
|
||||||
printf("Socket %d/%d %s:%d has been added to the pool!\n", pos+1, CLIENT_PORT_SIZE, target_host, app_ctx->ports[pos]);
|
evt_core_rm_fd (ctx, fdinfo->fd);
|
||||||
break;
|
return 1;
|
||||||
case SOCKS5_STATE_RDY:
|
|
||||||
goto on_socks5_err;
|
failed:
|
||||||
break;
|
fprintf(stderr, "Memory allocation failed\n");
|
||||||
case SOCKS5_STATE_ERR:
|
exit(EXIT_FAILURE);
|
||||||
goto on_socks5_err;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
int on_socks5_failed(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
on_socks5_err:
|
struct donar_client_ctx* app_ctx = fdinfo->cat->app_ctx;
|
||||||
//perror("An error occured while connecting to an Onion Service");
|
struct socks5_ctx* s5ctx = fdinfo->other;
|
||||||
app_ctx->client_sock[pos].state = SOCKS5_STATE_ERR;
|
int pos = 7500 - s5ctx->port;
|
||||||
|
|
||||||
evt_core_rm_fd (ctx, fdinfo->fd);
|
evt_core_rm_fd (ctx, fdinfo->fd);
|
||||||
sleep(2);
|
init_socks5_client (app_ctx, pos);
|
||||||
init_tcp_client (app_ctx, pos);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void init_socks5_sinks(struct donar_client_ctx* app_ctx) {
|
||||||
|
struct evt_core_cat template = { 0 };
|
||||||
|
|
||||||
|
template.cb = on_socks5_success;
|
||||||
|
template.name = "socks5-success";
|
||||||
|
template.flags = EPOLLET;
|
||||||
|
evt_core_add_cat(&app_ctx->evts, &template);
|
||||||
|
|
||||||
|
template.cb = on_socks5_failed;
|
||||||
|
template.app_ctx = app_ctx;
|
||||||
|
template.name = "socks5-failed";
|
||||||
|
template.flags = EPOLLET;
|
||||||
|
evt_core_add_cat(&app_ctx->evts, &template);
|
||||||
|
}
|
||||||
|
|
||||||
void donar_client(struct donar_client_ctx* ctx, char* algoname,
|
void donar_client(struct donar_client_ctx* ctx, char* algoname,
|
||||||
char* onion_file, GPtrArray* exposed_ports, GPtrArray* remote_ports) {
|
char* onion_file, GPtrArray* exposed_ports, GPtrArray* remote_ports) {
|
||||||
struct algo_skel algo = {0};
|
struct algo_skel algo = {0};
|
||||||
|
|
||||||
evt_core_init (&(ctx->evts));
|
evt_core_init (&(ctx->evts));
|
||||||
init_algo(&ctx->evts, &algo, algoname);
|
init_algo(&ctx->evts, &algo, algoname);
|
||||||
struct evt_core_cat init_socks5 = {
|
socks5_init (&ctx->evts);
|
||||||
.app_ctx = ctx,
|
init_socks5_sinks(ctx);
|
||||||
.free_app_ctx = NULL,
|
|
||||||
.cb = configure_tcp_clients,
|
|
||||||
.err_cb = NULL,
|
|
||||||
.name = "configure-socks5",
|
|
||||||
.flags = EPOLLIN | EPOLLET,
|
|
||||||
.socklist = NULL
|
|
||||||
};
|
|
||||||
evt_core_add_cat (&(ctx->evts), &init_socks5);
|
|
||||||
evt_core_add_cat (&(ctx->evts), &(algo.on_tcp_co));
|
evt_core_add_cat (&(ctx->evts), &(algo.on_tcp_co));
|
||||||
evt_core_add_cat (&(ctx->evts), &(algo.on_udp_read));
|
evt_core_add_cat (&(ctx->evts), &(algo.on_udp_read));
|
||||||
evt_core_add_cat (&(ctx->evts), &(algo.on_tcp_read));
|
evt_core_add_cat (&(ctx->evts), &(algo.on_tcp_read));
|
||||||
|
@ -149,7 +88,7 @@ void donar_client(struct donar_client_ctx* ctx, char* algoname,
|
||||||
printf("--- Onion services loaded\n");
|
printf("--- Onion services loaded\n");
|
||||||
|
|
||||||
for (int i = 0; i < CLIENT_PORT_SIZE; i++) {
|
for (int i = 0; i < CLIENT_PORT_SIZE; i++) {
|
||||||
init_tcp_client(ctx, i);
|
init_socks5_client(ctx, i);
|
||||||
}
|
}
|
||||||
printf("--- TCP Clients Connected\n");
|
printf("--- TCP Clients Connected\n");
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,39 @@ void evt_core_add_cat(struct evt_core_ctx* ctx, struct evt_core_cat* cat) {
|
||||||
g_hash_table_insert (ctx->catlist, dyn->name, dyn);
|
g_hash_table_insert (ctx->catlist, dyn->name, dyn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void evt_core_add_fd(struct evt_core_ctx* ctx, struct evt_core_fdinfo* user_data) {
|
void evt_core_mv_fd(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo, struct evt_core_cat* to_cat) {
|
||||||
|
printf("Moving fd=%d from cat=%s to cat=%s\n",fdinfo->fd, fdinfo->cat->name, to_cat->name);
|
||||||
|
|
||||||
|
// 1. Update old category
|
||||||
|
for (int i = 0; i < fdinfo->cat->socklist->len; i++) {
|
||||||
|
if (g_array_index(fdinfo->cat->socklist, struct evt_core_fdinfo*, i) == fdinfo) {
|
||||||
|
g_array_remove_index(fdinfo->cat->socklist, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Set new cat for fdinfo
|
||||||
|
fdinfo->cat = to_cat;
|
||||||
|
|
||||||
|
// 3. Update new category
|
||||||
|
g_array_append_val (fdinfo->cat->socklist, fdinfo);
|
||||||
|
|
||||||
|
// 4. Update epoll flags
|
||||||
|
update_fd_epoll (ctx->epollfd, fdinfo->fd, fdinfo->cat->flags);
|
||||||
|
|
||||||
|
// 5. Handle cases where data arrived before registering the file descriptor
|
||||||
|
fdinfo->cat->cb(ctx, fdinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void evt_core_mv_fd2(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo, char* to_cat) {
|
||||||
|
struct evt_core_cat* cat = evt_core_get_from_cat (ctx, to_cat);
|
||||||
|
if (cat == NULL) {
|
||||||
|
fprintf(stderr, "Category %s does not exist\n", to_cat);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
evt_core_mv_fd (ctx, fdinfo, cat);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct evt_core_fdinfo* evt_core_add_fd(struct evt_core_ctx* ctx, struct evt_core_fdinfo* user_data) {
|
||||||
// 1. Fetch fd category
|
// 1. Fetch fd category
|
||||||
struct evt_core_cat* cat = g_hash_table_lookup(ctx->catlist, user_data->cat->name);
|
struct evt_core_cat* cat = g_hash_table_lookup(ctx->catlist, user_data->cat->name);
|
||||||
if (cat == NULL) {
|
if (cat == NULL) {
|
||||||
|
@ -99,6 +131,11 @@ void evt_core_add_fd(struct evt_core_ctx* ctx, struct evt_core_fdinfo* user_data
|
||||||
// 5. Add file descriptor to epoll
|
// 5. Add file descriptor to epoll
|
||||||
add_fd_to_epoll(ctx->epollfd, user_data->fd, cat->flags);
|
add_fd_to_epoll(ctx->epollfd, user_data->fd, cat->flags);
|
||||||
printf("Added fd=%d with url=%s in cat=%s\n", fdinfo->fd, fdinfo->url, fdinfo->cat->name);
|
printf("Added fd=%d with url=%s in cat=%s\n", fdinfo->fd, fdinfo->url, fdinfo->cat->name);
|
||||||
|
|
||||||
|
// 6. Ensure that events arrived before epoll registering are handled
|
||||||
|
fdinfo->cat->cb(ctx, fdinfo);
|
||||||
|
|
||||||
|
return fdinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct evt_core_cat* evt_core_rm_fd(struct evt_core_ctx* ctx, int fd) {
|
struct evt_core_cat* evt_core_rm_fd(struct evt_core_ctx* ctx, int fd) {
|
||||||
|
@ -108,14 +145,11 @@ struct evt_core_cat* evt_core_rm_fd(struct evt_core_ctx* ctx, int fd) {
|
||||||
struct evt_core_fdinfo* fdinfo = g_hash_table_lookup (ctx->socklist, &fd);
|
struct evt_core_fdinfo* fdinfo = g_hash_table_lookup (ctx->socklist, &fd);
|
||||||
if (fdinfo == NULL) return NULL;
|
if (fdinfo == NULL) return NULL;
|
||||||
cat = fdinfo->cat;
|
cat = fdinfo->cat;
|
||||||
|
printf("Closing fd=%d from cat=%s\n",fdinfo->fd, fdinfo->cat->name);
|
||||||
|
|
||||||
// 2. Update category
|
// 2. Update category
|
||||||
for (int i = 0; i < cat->socklist->len; i++) {
|
for (int i = 0; i < cat->socklist->len; i++) {
|
||||||
if (g_array_index(cat->socklist, struct evt_core_fdinfo*, i) == fdinfo) {
|
if (g_array_index(cat->socklist, struct evt_core_fdinfo*, i) == fdinfo) {
|
||||||
if (fdinfo->fd != fd) {
|
|
||||||
fprintf(stderr, "Logic error in updating file descriptor list\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
g_array_remove_index(cat->socklist, i);
|
g_array_remove_index(cat->socklist, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,9 @@ struct evt_core_fdinfo {
|
||||||
|
|
||||||
void evt_core_init(struct evt_core_ctx* ctx);
|
void evt_core_init(struct evt_core_ctx* ctx);
|
||||||
void evt_core_add_cat(struct evt_core_ctx* ctx, struct evt_core_cat* cat);
|
void evt_core_add_cat(struct evt_core_ctx* ctx, struct evt_core_cat* cat);
|
||||||
void evt_core_add_fd(struct evt_core_ctx* ctx, struct evt_core_fdinfo* user_data);
|
void evt_core_mv_fd(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo, struct evt_core_cat* to_cat);
|
||||||
|
void evt_core_mv_fd2(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo, char* to_cat);
|
||||||
|
struct evt_core_fdinfo* evt_core_add_fd(struct evt_core_ctx* ctx, struct evt_core_fdinfo* user_data);
|
||||||
struct evt_core_cat* evt_core_rm_fd(struct evt_core_ctx* ctx, int fd);
|
struct evt_core_cat* evt_core_rm_fd(struct evt_core_ctx* ctx, int fd);
|
||||||
void evt_core_free(struct evt_core_ctx* ctx);
|
void evt_core_free(struct evt_core_ctx* ctx);
|
||||||
void evt_core_loop(struct evt_core_ctx* ctx);
|
void evt_core_loop(struct evt_core_ctx* ctx);
|
||||||
|
|
260
src/meas_lat.c
260
src/meas_lat.c
|
@ -8,6 +8,11 @@
|
||||||
#include "net_tools.h"
|
#include "net_tools.h"
|
||||||
#include "socks5.h"
|
#include "socks5.h"
|
||||||
|
|
||||||
|
struct measlat_ctx {
|
||||||
|
int count, size, interval;
|
||||||
|
char *host, *port, *transport;
|
||||||
|
};
|
||||||
|
|
||||||
struct measure_conf {
|
struct measure_conf {
|
||||||
uint64_t max_measure;
|
uint64_t max_measure;
|
||||||
uint64_t payload_size;
|
uint64_t payload_size;
|
||||||
|
@ -79,12 +84,19 @@ int on_udp(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void free_timer_conf(void* v) {
|
||||||
|
struct measure_conf* mc = v;
|
||||||
|
free(mc->payload);
|
||||||
|
free(mc);
|
||||||
|
}
|
||||||
|
|
||||||
int on_timer(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
int on_timer(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
ssize_t s;
|
ssize_t s;
|
||||||
uint64_t ticks;
|
uint64_t ticks;
|
||||||
struct measure_conf* mc = fdinfo->other;
|
struct measure_conf* mc = fdinfo->other;
|
||||||
|
|
||||||
s = read(fdinfo->fd, &ticks, sizeof(uint64_t));
|
s = read(fdinfo->fd, &ticks, sizeof(uint64_t));
|
||||||
|
if (s == -1 && errno == EAGAIN) return 0;
|
||||||
if (s != sizeof(uint64_t)) {
|
if (s != sizeof(uint64_t)) {
|
||||||
perror("Read error");
|
perror("Read error");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
@ -113,112 +125,9 @@ int on_timer(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
perror("Send error");
|
perror("Send error");
|
||||||
//exit(EXIT_FAILURE);
|
//exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_timer_conf(void* v) {
|
|
||||||
struct measure_conf* mc = v;
|
|
||||||
free(mc->payload);
|
|
||||||
free(mc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_categories(struct evt_core_ctx* evts) {
|
|
||||||
struct evt_core_cat tcp_read = {
|
|
||||||
.app_ctx = NULL,
|
|
||||||
.free_app_ctx = NULL,
|
|
||||||
.cb = on_udp,
|
|
||||||
.err_cb = on_udp_err,
|
|
||||||
.name = "tcp-read",
|
|
||||||
.flags = EPOLLIN | EPOLLET,
|
|
||||||
.socklist = NULL
|
|
||||||
};
|
|
||||||
struct evt_core_cat udp_read = {
|
|
||||||
.app_ctx = NULL,
|
|
||||||
.free_app_ctx = NULL,
|
|
||||||
.cb = on_udp,
|
|
||||||
.err_cb = on_udp_err,
|
|
||||||
.name = "udp-read",
|
|
||||||
.flags = EPOLLIN | EPOLLET,
|
|
||||||
.socklist = NULL
|
|
||||||
};
|
|
||||||
struct evt_core_cat timer = {
|
|
||||||
.app_ctx = NULL,
|
|
||||||
.free_app_ctx = NULL,
|
|
||||||
.cb = on_timer,
|
|
||||||
.err_cb = NULL,
|
|
||||||
.name = "timer",
|
|
||||||
.flags = EPOLLIN | EPOLLET,
|
|
||||||
.socklist = NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
evt_core_init(evts);
|
|
||||||
evt_core_add_cat (evts, &udp_read);
|
|
||||||
evt_core_add_cat (evts, &tcp_read);
|
|
||||||
evt_core_add_cat(evts, &timer);
|
|
||||||
printf("--- Categories registered\n");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int register_tor_socket(struct evt_core_ctx* evts, char* host, char* port, int count, int size) {
|
|
||||||
int socks5_sock = -1, err = 0;
|
|
||||||
for (int i = 120; i > 0; i--) {
|
|
||||||
sleep(2);
|
|
||||||
printf("Remaining try %d/120 to connect to %s:%s\n", i, host, port);
|
|
||||||
if (socks5_sock >= 0) {
|
|
||||||
close(socks5_sock);
|
|
||||||
socks5_sock = -1;
|
|
||||||
}
|
|
||||||
socks5_sock = create_tcp_client ("127.0.0.1", "9050");
|
|
||||||
err = socks5_handshake_syn (socks5_sock);
|
|
||||||
if (err < 0) continue;
|
|
||||||
err = socks5_handshake_ack (socks5_sock);
|
|
||||||
if (err < 0) continue;
|
|
||||||
err = socks5_connect_dns (socks5_sock, host, atoi(port));
|
|
||||||
if (err < 0) continue;
|
|
||||||
err = socks5_reply (socks5_sock);
|
|
||||||
if (err < 0) {
|
|
||||||
fprintf(stderr, "Socks5 error %s\n", socks5_rep(-err));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
if (socks5_sock < 0 || err < 0) {
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
char url[1024];
|
|
||||||
struct evt_core_cat cat = {0};
|
|
||||||
struct evt_core_fdinfo fdinfo = {0};
|
|
||||||
fdinfo.cat = &cat;
|
|
||||||
fdinfo.url = url;
|
|
||||||
|
|
||||||
fdinfo.fd = socks5_sock;
|
|
||||||
fdinfo.cat->name = "tcp-read";
|
|
||||||
fdinfo.other = create_measure_conf (count, size);
|
|
||||||
fdinfo.free_other = free_mesure_conf;
|
|
||||||
sprintf(fdinfo.url, "tcp:read:%s:%s", host, port);
|
|
||||||
evt_core_add_fd (evts, &fdinfo);
|
|
||||||
printf("--- Tor socket registered\n");
|
|
||||||
return fdinfo.fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
int register_udp_socket(struct evt_core_ctx* evts, char* host, char* port, int count, int size) {
|
|
||||||
int udp_sock = create_udp_client (host, port);
|
|
||||||
char url[1024];
|
|
||||||
struct evt_core_cat cat = {0};
|
|
||||||
struct evt_core_fdinfo fdinfo = {0};
|
|
||||||
fdinfo.cat = &cat;
|
|
||||||
fdinfo.url = url;
|
|
||||||
|
|
||||||
fdinfo.fd = udp_sock;
|
|
||||||
fdinfo.cat->name = "udp-read";
|
|
||||||
fdinfo.other = create_measure_conf (count, size);
|
|
||||||
fdinfo.free_other = free_mesure_conf;
|
|
||||||
sprintf(fdinfo.url, "udp:read:%s:%s", host, port);
|
|
||||||
evt_core_add_fd (evts, &fdinfo);
|
|
||||||
printf("--- UDP socket registered\n");
|
|
||||||
return fdinfo.fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_timer(struct evt_core_ctx* evts, int udp, int interval, int count, int size) {
|
void register_timer(struct evt_core_ctx* evts, int udp, int interval, int count, int size) {
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
|
@ -256,34 +165,144 @@ void register_timer(struct evt_core_ctx* evts, int udp, int interval, int count,
|
||||||
printf("--- Timer registered\n");
|
printf("--- Timer registered\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int on_socks5_success_measlat(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
|
char url[1024];
|
||||||
|
struct evt_core_cat cat = {0};
|
||||||
|
struct evt_core_fdinfo fdinfo_n = {0};
|
||||||
|
struct socks5_ctx* s5ctx = fdinfo->other;
|
||||||
|
fdinfo_n.cat = &cat;
|
||||||
|
fdinfo_n.url = url;
|
||||||
|
|
||||||
|
struct evt_core_cat* ucat = evt_core_get_from_cat (ctx, "tcp-read");
|
||||||
|
if (ucat == NULL) {
|
||||||
|
fprintf(stderr, "Category udp-read not found\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
struct measlat_ctx* mctx = ucat->app_ctx;
|
||||||
|
|
||||||
|
fdinfo_n.fd = dup(fdinfo->fd);
|
||||||
|
fdinfo_n.cat->name = "tcp-read";
|
||||||
|
fdinfo_n.other = create_measure_conf (mctx->count, mctx->size);
|
||||||
|
fdinfo_n.free_other = free_mesure_conf;
|
||||||
|
sprintf(fdinfo_n.url, "tcp:read:%s:%d", s5ctx->addr, s5ctx->port);
|
||||||
|
|
||||||
|
evt_core_add_fd (ctx, &fdinfo_n);
|
||||||
|
printf("--- Tor socket registered\n");
|
||||||
|
|
||||||
|
register_timer(ctx, fdinfo->fd, mctx->interval, mctx->count, mctx->size);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spawn_tor_socket(struct evt_core_ctx* evts) {
|
||||||
|
struct evt_core_cat* ucat = evt_core_get_from_cat (evts, "tcp-read");
|
||||||
|
if (ucat == NULL) {
|
||||||
|
fprintf(stderr, "Category udp-read not found\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
struct measlat_ctx* mctx = ucat->app_ctx;
|
||||||
|
|
||||||
|
socks5_create_dns_client (evts, "127.0.0.1", "9050", mctx->host, atoi(mctx->port));
|
||||||
|
}
|
||||||
|
|
||||||
|
int on_socks5_failed_measlat(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
|
evt_core_rm_fd (ctx, fdinfo->fd);
|
||||||
|
sleep(1);
|
||||||
|
spawn_tor_socket(ctx);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_categories(struct evt_core_ctx* evts, struct measlat_ctx* mctx) {
|
||||||
|
struct evt_core_cat template = {0};
|
||||||
|
template.app_ctx = mctx;
|
||||||
|
evt_core_init(evts);
|
||||||
|
|
||||||
|
template.cb = on_timer;
|
||||||
|
template.name = "timer";
|
||||||
|
template.flags = EPOLLIN | EPOLLET;
|
||||||
|
evt_core_add_cat(evts, &template);
|
||||||
|
|
||||||
|
template.cb = on_udp; // intended but not elegant
|
||||||
|
template.err_cb = on_udp_err; // intended but not elegant
|
||||||
|
template.name = "tcp-read";
|
||||||
|
template.flags = EPOLLIN | EPOLLET;
|
||||||
|
evt_core_add_cat(evts, &template);
|
||||||
|
|
||||||
|
template.cb = on_udp;
|
||||||
|
template.err_cb = on_udp_err;
|
||||||
|
template.name = "udp-read";
|
||||||
|
template.flags = EPOLLIN | EPOLLET;
|
||||||
|
evt_core_add_cat(evts, &template);
|
||||||
|
|
||||||
|
template.cb = on_socks5_success_measlat;
|
||||||
|
template.err_cb = on_socks5_failed_measlat;
|
||||||
|
template.name = "socks5-success";
|
||||||
|
template.flags = EPOLLET;
|
||||||
|
|
||||||
|
template.cb = on_socks5_failed_measlat;
|
||||||
|
template.err_cb = on_socks5_failed_measlat;
|
||||||
|
template.name = "socks5-failed";
|
||||||
|
template.flags = EPOLLET;
|
||||||
|
|
||||||
|
socks5_init(evts);
|
||||||
|
printf("--- Categories registered\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void spawn_udp_socket(struct evt_core_ctx* evts) {
|
||||||
|
struct evt_core_cat* ucat = evt_core_get_from_cat (evts, "udp-read");
|
||||||
|
if (ucat == NULL) {
|
||||||
|
fprintf(stderr, "Category udp-read not found\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
struct measlat_ctx* mctx = ucat->app_ctx;
|
||||||
|
|
||||||
|
int udp_sock = create_udp_client (mctx->host, mctx->port);
|
||||||
|
char url[1024];
|
||||||
|
struct evt_core_cat cat = {0};
|
||||||
|
struct evt_core_fdinfo fdinfo = {0};
|
||||||
|
fdinfo.cat = &cat;
|
||||||
|
fdinfo.url = url;
|
||||||
|
|
||||||
|
fdinfo.fd = udp_sock;
|
||||||
|
fdinfo.cat->name = "udp-read";
|
||||||
|
fdinfo.other = create_measure_conf (mctx->count, mctx->size);
|
||||||
|
fdinfo.free_other = free_mesure_conf;
|
||||||
|
sprintf(fdinfo.url, "udp:read:%s:%s", mctx->host, mctx->port);
|
||||||
|
evt_core_add_fd (evts, &fdinfo);
|
||||||
|
printf("--- UDP socket registered\n");
|
||||||
|
|
||||||
|
register_timer(evts, fdinfo.fd, mctx->interval, mctx->count, mctx->size);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
setvbuf(stdout, NULL, _IONBF, 0);
|
setvbuf(stdout, NULL, _IONBF, 0);
|
||||||
printf("~ measlat ~\n");
|
printf("~ measlat ~\n");
|
||||||
|
|
||||||
int opt, udp_fd, count = 0, size = 0, interval = 0;
|
int opt;
|
||||||
char *host = NULL, *port = NULL, *transport = NULL;
|
struct measlat_ctx mctx = {0};
|
||||||
struct evt_core_ctx evts = {0};
|
struct evt_core_ctx evts = {0};
|
||||||
|
|
||||||
// 1. Parse parameters
|
// 1. Parse parameters
|
||||||
while ((opt = getopt(argc, argv, "h:p:c:s:i:t:")) != -1) {
|
while ((opt = getopt(argc, argv, "h:p:c:s:i:t:")) != -1) {
|
||||||
switch(opt) {
|
switch(opt) {
|
||||||
case 'h': // host
|
case 'h': // host
|
||||||
host = optarg;
|
mctx.host = optarg;
|
||||||
break;
|
break;
|
||||||
case 'p': // port
|
case 'p': // port
|
||||||
port = optarg;
|
mctx.port = optarg;
|
||||||
break;
|
break;
|
||||||
case 't': // transport
|
case 't': // transport
|
||||||
transport = optarg;
|
mctx.transport = optarg;
|
||||||
break;
|
break;
|
||||||
case 'c': // count
|
case 'c': // count
|
||||||
count = atoi(optarg);
|
mctx.count = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 's': // size - payload in bytes
|
case 's': // size - payload in bytes
|
||||||
size = atoi(optarg);
|
mctx.size = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'i': // interval - every ms
|
case 'i': // interval - every ms
|
||||||
interval = atoi(optarg);
|
mctx.interval = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto usage;
|
goto usage;
|
||||||
|
@ -292,17 +311,16 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
// 2. Check and fix parameters
|
// 2. Check and fix parameters
|
||||||
size_t header_size = sizeof(struct packet_header);
|
size_t header_size = sizeof(struct packet_header);
|
||||||
if (interval <= 0) interval = 1000;
|
if (mctx.interval <= 0) mctx.interval = 1000;
|
||||||
if (count <= 0) count = 1;
|
if (mctx.count <= 0) mctx.count = 1;
|
||||||
if (size < header_size) size = header_size;
|
if (mctx.size < header_size) mctx.size = header_size;
|
||||||
if (transport == NULL) transport = "udp";
|
if (mctx.transport == NULL) mctx.transport = "udp";
|
||||||
if (host == NULL || port == NULL) goto usage;
|
if (mctx.host == NULL || mctx.port == NULL) goto usage;
|
||||||
|
|
||||||
// 3. Bind events
|
// 3. Bind events
|
||||||
register_categories(&evts);
|
register_categories(&evts, &mctx);
|
||||||
if (strcmp(transport, "udp") == 0) udp_fd = register_udp_socket(&evts, host, port, count, size);
|
if (strcmp(mctx.transport, "udp") == 0) spawn_udp_socket(&evts);
|
||||||
else if (strcmp(transport, "tor") == 0) udp_fd = register_tor_socket(&evts, host, port, count, size);
|
else if (strcmp(mctx.transport, "tor") == 0) spawn_tor_socket(&evts);
|
||||||
register_timer(&evts, udp_fd, interval, count, size);
|
|
||||||
|
|
||||||
// 4. Run main loop
|
// 4. Run main loop
|
||||||
evt_core_loop(&evts);
|
evt_core_loop(&evts);
|
||||||
|
|
|
@ -165,3 +165,13 @@ void add_fd_to_epoll(int epollfd, int fd, uint32_t flags) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update_fd_epoll(int epollfd, int fd, uint32_t flags) {
|
||||||
|
struct epoll_event current_event = {0};
|
||||||
|
current_event.events = flags;
|
||||||
|
current_event.data.fd = fd;
|
||||||
|
if (epoll_ctl (epollfd, EPOLL_CTL_MOD, fd, ¤t_event) == -1) {
|
||||||
|
perror("Failed to update a file descriptor to epoll with epoll_ctl");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,5 +14,6 @@ int create_tcp_server(char* host, char* service);
|
||||||
int create_udp_server(char* host, char* service);
|
int create_udp_server(char* host, char* service);
|
||||||
int make_socket_non_blocking(int fd);
|
int make_socket_non_blocking(int fd);
|
||||||
void add_fd_to_epoll(int epollfd, int fd, uint32_t flags);
|
void add_fd_to_epoll(int epollfd, int fd, uint32_t flags);
|
||||||
|
void update_fd_epoll(int epollfd, int fd, uint32_t flags);
|
||||||
int read_entity(int fd, void* entity, int size);
|
int read_entity(int fd, void* entity, int size);
|
||||||
void fill_buffer(size_t* written, char* dest, void *src, size_t n);
|
void fill_buffer(size_t* written, char* dest, void *src, size_t n);
|
||||||
|
|
388
src/socks5.c
388
src/socks5.c
|
@ -1,107 +1,317 @@
|
||||||
#include "socks5.h"
|
#include "socks5.h"
|
||||||
|
|
||||||
int socks5_handshake_syn(int sock) {
|
void socks5_free_ctx(void* elem) {
|
||||||
//@TODO: Refactor the client handshake management
|
struct socks5_ctx* ctx = elem;
|
||||||
struct client_handshake ch = {
|
free(ctx);
|
||||||
.ver = 0x05,
|
|
||||||
.nmethods = 0x01,
|
|
||||||
.methods = {0x00}
|
|
||||||
};
|
|
||||||
|
|
||||||
int size = sizeof(uint8_t) * (2 + ch.nmethods);
|
|
||||||
if (size != write(sock, &ch, size)) {
|
|
||||||
perror("write failed on tcp socket in socks5");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int socks5_handshake_ack(int sock) {
|
void socks5_create_dns_client(struct evt_core_ctx* ctx, char* proxy_host, char* proxy_port, char* addr, uint16_t port) {
|
||||||
//@TODO: Refactor the client handshake management
|
struct evt_core_fdinfo fdinfo;
|
||||||
struct client_handshake ch = {
|
struct evt_core_cat cat;
|
||||||
.ver = 0x05,
|
struct socks5_ctx* s5ctx;
|
||||||
.nmethods = 0x01,
|
struct evt_core_fdinfo* reg_fdinfo;
|
||||||
.methods = {0x00}
|
char url[1024];
|
||||||
};
|
|
||||||
struct server_handshake sh = {0};
|
|
||||||
int err = read_entity(sock, &sh, sizeof(struct server_handshake));
|
|
||||||
if (err == -1) {
|
|
||||||
perror("sock5 handshake failed read");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (ch.ver != sh.ver || sh.method != ch.methods[0]) {
|
|
||||||
fprintf(stderr, "Protocol error: client asks for ver=%d, method=%d and server answers with ver=%d, method=%d\n",
|
|
||||||
ch.ver, ch.methods[0], sh.ver, sh.method);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf("[server_handshake] ver=%d, method=%d\n", sh.ver, sh.method);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int socks5_reply(int sock) {
|
// 0. Compute domain length and enforce an upper bound on its size
|
||||||
int res;
|
|
||||||
struct server_reply sr = {0};
|
|
||||||
res = read_entity(sock, &sr, sizeof(uint8_t) * 4);
|
|
||||||
if (res == -1) goto read_error;
|
|
||||||
|
|
||||||
switch(sr.atyp) {
|
|
||||||
case ATYP_IPV4:
|
|
||||||
if (read_entity(sock, sr.bind_addr.ipv4, sizeof(uint8_t) * 4) == -1)
|
|
||||||
goto read_error;
|
|
||||||
break;
|
|
||||||
case ATYP_DOMAINNAME:
|
|
||||||
if (read_entity(sock, &sr.bind_addr.dns.len, sizeof(uint8_t) * 4) == -1)
|
|
||||||
goto read_error;
|
|
||||||
if (read_entity(sock, sr.bind_addr.dns.str, sizeof(char) * sr.bind_addr.dns.len) == -1)
|
|
||||||
goto read_error;
|
|
||||||
break;
|
|
||||||
case ATYP_IPV6:
|
|
||||||
if (read_entity(sock, sr.bind_addr.ipv6, sizeof(uint8_t) * 16) == -1)
|
|
||||||
goto read_error;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Unsupported ATYP in server reply\n");
|
|
||||||
return -128;
|
|
||||||
}
|
|
||||||
res = read_entity(sock, &sr.port, sizeof(uint16_t));
|
|
||||||
if (res == -1) {
|
|
||||||
perror("read_entity");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sr.rep < 0 || sr.rep > 0x08) {
|
|
||||||
fprintf(stderr, "Invalid reply field\n");
|
|
||||||
return -128;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("[server_reply] ver=%d, rep=%s, atyp=%d, port=%d\n", sr.ver, rep_msg[sr.rep], sr.atyp, sr.port);
|
|
||||||
return -sr.rep;
|
|
||||||
|
|
||||||
read_error:
|
|
||||||
fprintf(stderr, "Unable to read ATYP\n");
|
|
||||||
return -128;
|
|
||||||
}
|
|
||||||
|
|
||||||
int socks5_connect_dns(int sock, char* addr, uint16_t port) {
|
|
||||||
char buffer[262];
|
|
||||||
size_t domainLength = strlen(addr);
|
size_t domainLength = strlen(addr);
|
||||||
if (domainLength > 255) {
|
if (domainLength > 255) {
|
||||||
fprintf(stderr, "domain is too long\n");
|
fprintf(stderr, "domain is too long\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
struct client_request cr = { 0x05, CMD_CONNECT, 0x00, ATYP_DOMAINNAME, (uint8_t)domainLength, addr, htons(port) };
|
|
||||||
size_t written = 0;
|
|
||||||
fill_buffer(&written, buffer, &cr, 5*sizeof(uint8_t));
|
|
||||||
fill_buffer(&written, buffer, cr.dst_addr, cr.dst_addr_len*sizeof(char));
|
|
||||||
fill_buffer(&written, buffer, &cr.port, sizeof(uint16_t));
|
|
||||||
|
|
||||||
if (written != write(sock, buffer, written)) {
|
// 1. Open connection
|
||||||
fprintf(stderr, "partial/failed write\n");
|
int sock = create_tcp_client (proxy_host, proxy_port);
|
||||||
return -1;
|
if (sock < 0) {
|
||||||
|
fprintf(stderr, "Unable to connect to proxy %s:%s\n", proxy_host, proxy_port);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. Create fdinfo
|
||||||
|
fdinfo.cat = &cat;
|
||||||
|
fdinfo.cat->name = "socks5-send-handshake";
|
||||||
|
fdinfo.fd = sock;
|
||||||
|
fdinfo.other = malloc(sizeof(struct socks5_ctx));
|
||||||
|
if (fdinfo.other == NULL) {
|
||||||
|
perror("malloc failed");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
memset(fdinfo.other, 0, sizeof(struct socks5_ctx));
|
||||||
|
fdinfo.free_other = socks5_free_ctx;
|
||||||
|
sprintf(url, "socks5:send-hs:%s:%d", addr, port);
|
||||||
|
fdinfo.url = strdup(url);
|
||||||
|
|
||||||
|
// 3. Fill socks5_ctx structures
|
||||||
|
s5ctx = fdinfo.other;
|
||||||
|
s5ctx->port = port;
|
||||||
|
s5ctx->addr = strdup(addr);
|
||||||
|
|
||||||
|
// 3.1 Client handshake to send
|
||||||
|
s5ctx->ch.ver = VER_SOCKS5;
|
||||||
|
s5ctx->ch.nmethods = 0x01;
|
||||||
|
s5ctx->ch.methods[0] = METHOD_NOAUTH;
|
||||||
|
s5ctx->ch_size = sizeof(uint8_t) * (2 + s5ctx->ch.nmethods);
|
||||||
|
|
||||||
|
// 3.2 Client request to send
|
||||||
|
s5ctx->cr.ver = VER_SOCKS5;
|
||||||
|
s5ctx->cr.cmd = CMD_CONNECT;
|
||||||
|
s5ctx->cr.rsv = 0x00;
|
||||||
|
s5ctx->cr.atyp = ATYP_DOMAINNAME;
|
||||||
|
s5ctx->cr.dst_addr_len = domainLength;
|
||||||
|
s5ctx->cr.dst_addr = addr;
|
||||||
|
s5ctx->cr.port = htons(port);
|
||||||
|
|
||||||
|
// 3.3 Generate client request buffer
|
||||||
|
s5ctx->cr_size = 0;
|
||||||
|
fill_buffer(&s5ctx->cr_size, s5ctx->cr_buffer, &s5ctx->cr, 5*sizeof(uint8_t));
|
||||||
|
fill_buffer(&s5ctx->cr_size, s5ctx->cr_buffer, s5ctx->cr.dst_addr, s5ctx->cr.dst_addr_len*sizeof(char));
|
||||||
|
fill_buffer(&s5ctx->cr_size, s5ctx->cr_buffer, &s5ctx->cr.port, sizeof(uint16_t));
|
||||||
|
|
||||||
|
reg_fdinfo = evt_core_add_fd (ctx, &fdinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
int on_socks5_send_handshake(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
|
struct socks5_ctx* s5ctx = fdinfo->other;
|
||||||
|
|
||||||
|
size_t written = write(fdinfo->fd, (char*)&s5ctx->ch + s5ctx->ch_cursor, s5ctx->ch_size - s5ctx->ch_cursor);
|
||||||
|
if (written == -1 && errno == EAGAIN) return 1;
|
||||||
|
if (written < 0) {
|
||||||
|
perror("write failed on tcp socket in socks5");
|
||||||
|
evt_core_mv_fd2(ctx, fdinfo, "socks5-failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
s5ctx->ch_cursor += written;
|
||||||
|
if (s5ctx->ch_cursor < s5ctx->ch_size) return 0;
|
||||||
|
|
||||||
|
evt_core_mv_fd2(ctx, fdinfo, "socks5-recv-handshake");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int on_socks5_recv_handshake(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
|
struct socks5_ctx* s5ctx = fdinfo->other;
|
||||||
|
int readn = 0;
|
||||||
|
|
||||||
|
readn = read(fdinfo->fd, (char*)&s5ctx->sh + s5ctx->sh_cursor, sizeof(s5ctx->sh) - s5ctx->sh_cursor);
|
||||||
|
if (readn == -1 && errno == EAGAIN) return 1;
|
||||||
|
if (readn < 0) {
|
||||||
|
perror("sock5 handshake failed read");
|
||||||
|
evt_core_mv_fd2(ctx, fdinfo, "socks5-failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
s5ctx->sh_cursor += readn;
|
||||||
|
if (s5ctx->sh_cursor < sizeof(s5ctx->sh)) return 0;
|
||||||
|
|
||||||
|
if (s5ctx->ch.ver != s5ctx->sh.ver || s5ctx->sh.method != s5ctx->ch.methods[0]) {
|
||||||
|
fprintf(stderr, "Protocol error: client asks for ver=%d, method=%d and server answers with ver=%d, method=%d\n",
|
||||||
|
s5ctx->ch.ver, s5ctx->ch.methods[0], s5ctx->sh.ver, s5ctx->sh.method);
|
||||||
|
evt_core_mv_fd2(ctx, fdinfo, "socks5-failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("[socks5_server_handshake] fd=%d, ver=%d, method=%d\n", fdinfo->fd, s5ctx->sh.ver, s5ctx->sh.method);
|
||||||
|
evt_core_mv_fd2(ctx, fdinfo, "socks5-send-client-req");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int on_socks5_send_client_req(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
|
struct socks5_ctx* s5ctx = fdinfo->other;
|
||||||
|
int written = 0;
|
||||||
|
|
||||||
|
written = write(fdinfo->fd, (char*)s5ctx->cr_buffer + s5ctx->cr_cursor, s5ctx->cr_size - s5ctx->cr_cursor);
|
||||||
|
if (written == -1 && errno == EAGAIN) return 1;
|
||||||
|
if (written < 0) {
|
||||||
|
fprintf(stderr, "socks5 send client request failed\n");
|
||||||
|
evt_core_mv_fd2 (ctx, fdinfo, "socks5-failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
s5ctx->cr_cursor += written;
|
||||||
|
if (s5ctx->cr_cursor < s5ctx->cr_size) return 0;
|
||||||
|
|
||||||
|
evt_core_mv_fd2 (ctx, fdinfo, "socks5-recv-server-reply");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int socks5_server_reply_atyp_ipv4(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
|
struct socks5_ctx* s5ctx = fdinfo->other;
|
||||||
|
size_t fixed_headers_size = (char*)&s5ctx->sr.bind_addr.ipv4 - (char*)&s5ctx->sr;
|
||||||
|
size_t host_size = sizeof(s5ctx->sr.bind_addr.ipv4);
|
||||||
|
uint64_t relative_cursor = (s5ctx->sr_cursor - fixed_headers_size);
|
||||||
|
int nread = 0;
|
||||||
|
|
||||||
|
nread = read(fdinfo->fd,
|
||||||
|
(char*)s5ctx->sr.bind_addr.ipv4 + relative_cursor,
|
||||||
|
host_size - relative_cursor);
|
||||||
|
|
||||||
|
if (nread == -1 && errno == EAGAIN) return 1;
|
||||||
|
if (nread < 0) {
|
||||||
|
perror("write failed on tcp socket in socks5");
|
||||||
|
evt_core_mv_fd2(ctx, fdinfo, "socks5-failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
s5ctx->sr_cursor += nread;
|
||||||
|
if (s5ctx->sr_cursor < fixed_headers_size + host_size) return 0;
|
||||||
|
|
||||||
|
s5ctx->sr_host_read = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int socks5_server_reply_atyp_ipv6(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
|
struct socks5_ctx* s5ctx = fdinfo->other;
|
||||||
|
size_t fixed_headers_size = (char*)&s5ctx->sr.bind_addr.ipv6 - (char*)&s5ctx->sr;
|
||||||
|
size_t host_size = sizeof(s5ctx->sr.bind_addr.ipv6);
|
||||||
|
uint64_t relative_cursor = (s5ctx->sr_cursor - fixed_headers_size);
|
||||||
|
int nread = 0;
|
||||||
|
|
||||||
|
nread = read(fdinfo->fd,
|
||||||
|
(char*)s5ctx->sr.bind_addr.ipv6 + relative_cursor,
|
||||||
|
host_size - relative_cursor);
|
||||||
|
|
||||||
|
if (nread == -1 && errno == EAGAIN) return 1;
|
||||||
|
if (nread < 0) {
|
||||||
|
perror("write failed on tcp socket in socks5");
|
||||||
|
evt_core_mv_fd2(ctx, fdinfo, "socks5-failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
s5ctx->sr_cursor += nread;
|
||||||
|
if (s5ctx->sr_cursor < fixed_headers_size + host_size) return 0;
|
||||||
|
|
||||||
|
s5ctx->sr_host_read = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int socks5_server_reply_atyp_dn(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
|
struct socks5_ctx* s5ctx = fdinfo->other;
|
||||||
|
size_t fixed_headers_size = (char*)&s5ctx->sr.bind_addr.ipv6 - (char*)&s5ctx->sr;
|
||||||
|
size_t dn_size_size = sizeof(s5ctx->sr.bind_addr.dns.len);
|
||||||
|
uint64_t relative_cursor = 0;
|
||||||
|
int nread = 0;
|
||||||
|
|
||||||
|
if (s5ctx->sr_cursor < fixed_headers_size + dn_size_size) {
|
||||||
|
relative_cursor = (s5ctx->sr_cursor - fixed_headers_size);
|
||||||
|
nread = read(fdinfo->fd, (char*)&s5ctx->sr.bind_addr.dns.len + relative_cursor, dn_size_size - relative_cursor);
|
||||||
|
if (nread == -1 && errno == EAGAIN) return 1;
|
||||||
|
if (nread < 0) {
|
||||||
|
perror("write failed on tcp socket in socks5");
|
||||||
|
evt_core_mv_fd2(ctx, fdinfo, "socks5-failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
s5ctx->sr_cursor += nread;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
relative_cursor = s5ctx->sr_cursor - fixed_headers_size - sizeof(s5ctx->sr.bind_addr.dns.len);
|
||||||
|
nread = read(fdinfo->fd, (char*)&s5ctx->sr.bind_addr.dns.str + relative_cursor, s5ctx->sr.bind_addr.dns.len - relative_cursor);
|
||||||
|
if (nread == -1 && errno == EAGAIN) return 1;
|
||||||
|
if (nread < 0) {
|
||||||
|
perror("write failed on tcp socket in socks5");
|
||||||
|
evt_core_mv_fd2(ctx, fdinfo, "socks5-failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
s5ctx->sr_cursor += nread;
|
||||||
|
if (s5ctx->sr_cursor < fixed_headers_size + dn_size_size + s5ctx->sr.bind_addr.dns.len) return 0;
|
||||||
|
|
||||||
|
s5ctx->sr_host_read = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t socks5_server_reply_size(struct server_reply* sr) {
|
||||||
|
size_t fixed_headers_size = (char*)&sr->bind_addr - (char*)sr;
|
||||||
|
size_t fixed_tail_size = (char*)(sr + 1) - (char*)&sr->port;
|
||||||
|
size_t host_size = 0;
|
||||||
|
|
||||||
|
if (sr->atyp == ATYP_IPV4) {
|
||||||
|
host_size = sizeof(sr->bind_addr.ipv4);
|
||||||
|
} else if (sr->atyp == ATYP_IPV6) {
|
||||||
|
host_size = sizeof(sr->bind_addr.ipv6);
|
||||||
|
} else if (sr->atyp == ATYP_DOMAINNAME) {
|
||||||
|
host_size = sizeof(sr->bind_addr.dns.len) + sr->bind_addr.dns.len;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Unsupported ATYP for SOCK5\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fixed_headers_size + host_size + fixed_tail_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int on_socks5_recv_server_reply(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
|
struct socks5_ctx* s5ctx = fdinfo->other;
|
||||||
|
int readn = 0;
|
||||||
|
size_t fixed_headers_size = (char*)&s5ctx->sr.bind_addr - (char*)&s5ctx->sr;
|
||||||
|
|
||||||
|
// Read headers
|
||||||
|
if (s5ctx->sr_cursor < fixed_headers_size) {
|
||||||
|
readn = read(fdinfo->fd, (char*)&s5ctx->sr + s5ctx->sr_cursor, fixed_headers_size - s5ctx->sr_cursor);
|
||||||
|
if (readn == -1 && errno == EAGAIN) return 1;
|
||||||
|
if (readn < 0) goto move_to_failed;
|
||||||
|
s5ctx->sr_cursor += readn;
|
||||||
|
return 0; // Needed as we might have not read enough bytes and free us from writing a loop
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read host
|
||||||
|
if (!s5ctx->sr_host_read) {
|
||||||
|
if (s5ctx->sr.atyp == ATYP_IPV4) return socks5_server_reply_atyp_ipv4(ctx, fdinfo);
|
||||||
|
else if (s5ctx->sr.atyp == ATYP_IPV6) return socks5_server_reply_atyp_ipv6(ctx, fdinfo);
|
||||||
|
else if (s5ctx->sr.atyp == ATYP_DOMAINNAME) return socks5_server_reply_atyp_dn(ctx, fdinfo);
|
||||||
|
else goto move_to_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read port
|
||||||
|
size_t final_size = socks5_server_reply_size(&s5ctx->sr);
|
||||||
|
if (s5ctx->sr_cursor < final_size) {
|
||||||
|
size_t relative_cursor = s5ctx->sr_cursor - (final_size - sizeof(s5ctx->sr.port));
|
||||||
|
readn = read(fdinfo->fd, (char*)&s5ctx->sr.port + relative_cursor, sizeof(s5ctx->sr.port) - relative_cursor);
|
||||||
|
if (readn == -1 && errno == EAGAIN) return 1;
|
||||||
|
if (readn < 0) goto move_to_failed;
|
||||||
|
s5ctx->sr_cursor += readn;
|
||||||
|
return 0; // Needed as we might have not read enough bytes and free us from writing a loop
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do some checks
|
||||||
|
if (s5ctx->sr.rep > 0x08) goto move_to_failed;
|
||||||
|
printf("[socks5_server_reply] fd=%d, ver=%d, rep=%s, atyp=%d, port=%d\n", fdinfo->fd, s5ctx->sr.ver, rep_msg[s5ctx->sr.rep], s5ctx->sr.atyp, s5ctx->sr.port);
|
||||||
|
|
||||||
|
if (s5ctx->sr.rep != SOCKS5_REP_SUCCESS) goto move_to_failed;
|
||||||
|
|
||||||
|
evt_core_mv_fd2 (ctx, fdinfo, "socks5-success");
|
||||||
|
return 1;
|
||||||
|
move_to_failed:
|
||||||
|
evt_core_mv_fd2 (ctx, fdinfo, "socks5-failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int on_socks5_err(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
|
evt_core_mv_fd2 (ctx, fdinfo, "socks5-failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void socks5_init(struct evt_core_ctx* ctx) {
|
||||||
|
struct evt_core_cat template = {0};
|
||||||
|
|
||||||
|
template.cb = on_socks5_send_handshake;
|
||||||
|
template.err_cb = on_socks5_err;
|
||||||
|
template.name = "socks5-send-handshake";
|
||||||
|
template.flags = EPOLLOUT | EPOLLET;
|
||||||
|
evt_core_add_cat (ctx, &template);
|
||||||
|
|
||||||
|
template.cb = on_socks5_recv_handshake;
|
||||||
|
template.err_cb = on_socks5_err;
|
||||||
|
template.name = "socks5-recv-handshake";
|
||||||
|
template.flags = EPOLLIN | EPOLLET;
|
||||||
|
evt_core_add_cat (ctx, &template);
|
||||||
|
|
||||||
|
template.cb = on_socks5_send_client_req;
|
||||||
|
template.err_cb = on_socks5_err;
|
||||||
|
template.name = "socks5-send-client-req";
|
||||||
|
template.flags = EPOLLOUT | EPOLLET;
|
||||||
|
evt_core_add_cat(ctx, &template);
|
||||||
|
|
||||||
|
template.cb = on_socks5_recv_server_reply;
|
||||||
|
template.err_cb = on_socks5_err;
|
||||||
|
template.name = "socks5-recv-server-reply";
|
||||||
|
template.flags = EPOLLIN | EPOLLET;
|
||||||
|
evt_core_add_cat(ctx, &template);
|
||||||
|
}
|
||||||
|
|
||||||
char* socks5_rep (enum socks5_rep rep) {
|
char* socks5_rep (enum socks5_rep rep) {
|
||||||
return rep_msg[rep];
|
return rep_msg[rep];
|
||||||
}
|
}
|
||||||
|
|
38
src/socks5.h
38
src/socks5.h
|
@ -7,6 +7,7 @@
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "net_tools.h"
|
#include "net_tools.h"
|
||||||
|
#include "evt_core.h"
|
||||||
|
|
||||||
enum socks5_state {
|
enum socks5_state {
|
||||||
SOCKS5_STATE_NEW,
|
SOCKS5_STATE_NEW,
|
||||||
|
@ -27,10 +28,21 @@ enum atyp {
|
||||||
ATYP_IPV6 = 0x04
|
ATYP_IPV6 = 0x04
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ver {
|
||||||
|
VER_SOCKS5 = 0x05
|
||||||
|
};
|
||||||
|
|
||||||
|
enum methods {
|
||||||
|
METHOD_NOAUTH = 0x00,
|
||||||
|
METHOD_GSSAPI = 0x01,
|
||||||
|
METHOD_USERPASS = 0x02,
|
||||||
|
METHOD_NOACCEPT = 0xff
|
||||||
|
};
|
||||||
|
|
||||||
union socks5_addr {
|
union socks5_addr {
|
||||||
struct {
|
struct {
|
||||||
uint8_t len;
|
uint8_t len;
|
||||||
char* str;
|
char str[256];
|
||||||
} dns;
|
} dns;
|
||||||
uint8_t ipv4[4];
|
uint8_t ipv4[4];
|
||||||
uint8_t ipv6[16];
|
uint8_t ipv6[16];
|
||||||
|
@ -95,8 +107,24 @@ struct server_reply {
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
};
|
};
|
||||||
|
|
||||||
int socks5_handshake_syn(int sock);
|
struct socks5_ctx {
|
||||||
int socks5_handshake_ack(int sock);
|
uint16_t port;
|
||||||
int socks5_connect_dns(int sock, char* addr, uint16_t port);
|
char* addr;
|
||||||
int socks5_reply(int sock);
|
|
||||||
|
struct client_handshake ch;
|
||||||
|
struct server_handshake sh;
|
||||||
|
struct client_request cr;
|
||||||
|
struct server_reply sr;
|
||||||
|
uint64_t ch_cursor;
|
||||||
|
uint64_t sh_cursor;
|
||||||
|
uint64_t cr_cursor;
|
||||||
|
uint64_t sr_cursor;
|
||||||
|
char cr_buffer[262];
|
||||||
|
size_t ch_size;
|
||||||
|
size_t cr_size;
|
||||||
|
uint8_t sr_host_read;
|
||||||
|
};
|
||||||
|
|
||||||
|
void socks5_init(struct evt_core_ctx* ctx);
|
||||||
|
void socks5_create_dns_client(struct evt_core_ctx* ctx, char* proxy_host, char* proxy_port, char* addr, uint16_t port);
|
||||||
char* socks5_rep (enum socks5_rep rep);
|
char* socks5_rep (enum socks5_rep rep);
|
||||||
|
|
|
@ -37,6 +37,7 @@ int te_on_tcp_co(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
in_len = sizeof(addr);
|
in_len = sizeof(addr);
|
||||||
conn_sock1 = accept(fdinfo->fd, (struct sockaddr*)&addr, &in_len);
|
conn_sock1 = accept(fdinfo->fd, (struct sockaddr*)&addr, &in_len);
|
||||||
|
|
||||||
|
if (conn_sock1 == -1 && errno == EAGAIN) return 1;
|
||||||
if (conn_sock1 == -1) goto co_error;
|
if (conn_sock1 == -1) goto co_error;
|
||||||
|
|
||||||
url_get_port(port, fdinfo->url);
|
url_get_port(port, fdinfo->url);
|
||||||
|
@ -46,7 +47,7 @@ int te_on_tcp_co(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) {
|
||||||
sprintf(to_fdinfo.url, "tcp:all:127.0.0.1:%s", port);
|
sprintf(to_fdinfo.url, "tcp:all:127.0.0.1:%s", port);
|
||||||
evt_core_add_fd (ctx, &to_fdinfo);
|
evt_core_add_fd (ctx, &to_fdinfo);
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
co_error:
|
co_error:
|
||||||
perror("Failed to handle new connection");
|
perror("Failed to handle new connection");
|
||||||
|
|
Loading…
Reference in a new issue