mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-24 17:33:46 +00:00
Refine incomplete header handling
This commit is contained in:
+13
-13
@@ -78,7 +78,7 @@
|
||||
#define BUF_SIZE 2048
|
||||
#endif
|
||||
|
||||
int verbose = 0;
|
||||
int verbose = 0;
|
||||
int keep_resolving = 1;
|
||||
|
||||
#ifdef ANDROID
|
||||
@@ -267,7 +267,8 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
int not_protect = 0;
|
||||
if (remote->addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in *s = (struct sockaddr_in *)&remote->addr;
|
||||
if (s->sin_addr.s_addr == inet_addr("127.0.0.1")) not_protect = 1;
|
||||
if (s->sin_addr.s_addr == inet_addr("127.0.0.1"))
|
||||
not_protect = 1;
|
||||
}
|
||||
if (!not_protect) {
|
||||
if (protect_socket(remote->fd) == -1) {
|
||||
@@ -294,7 +295,8 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
if (verbose) LOGI("connected immediately");
|
||||
if (verbose)
|
||||
LOGI("connected immediately");
|
||||
remote_send_cb(EV_A_ & remote->send_ctx->io, 0);
|
||||
} else {
|
||||
// wait on remote connected event
|
||||
@@ -302,7 +304,6 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
ev_io_start(EV_A_ & remote->send_ctx->io);
|
||||
ev_timer_start(EV_A_ & remote->send_ctx->watcher);
|
||||
}
|
||||
|
||||
} else {
|
||||
#ifdef TCP_FASTOPEN
|
||||
#ifdef __APPLE__
|
||||
@@ -986,7 +987,8 @@ void accept_cb(EV_P_ ev_io *w, int revents)
|
||||
ev_io_start(EV_A_ & server->recv_ctx->io);
|
||||
}
|
||||
|
||||
void resolve_int_cb(int dummy) {
|
||||
void resolve_int_cb(int dummy)
|
||||
{
|
||||
keep_resolving = 0;
|
||||
}
|
||||
|
||||
@@ -1015,11 +1017,11 @@ int main(int argc, char **argv)
|
||||
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{ "fast-open", no_argument , 0, 0 },
|
||||
{ "acl" , required_argument, 0, 0 },
|
||||
{ "mtu" , required_argument, 0, 0 },
|
||||
{ "mptcp" , no_argument , 0, 0 },
|
||||
{ "help" , no_argument , 0, 0 },
|
||||
{ "fast-open", no_argument, 0, 0 },
|
||||
{ "acl", required_argument, 0, 0 },
|
||||
{ "mtu", required_argument, 0, 0 },
|
||||
{ "mptcp", no_argument, 0, 0 },
|
||||
{ "help", no_argument, 0, 0 },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -1228,7 +1230,7 @@ int main(int argc, char **argv)
|
||||
// ignore SIGPIPE
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGABRT, SIG_IGN);
|
||||
signal(SIGINT, resolve_int_cb);
|
||||
signal(SIGINT, resolve_int_cb);
|
||||
signal(SIGTERM, resolve_int_cb);
|
||||
#endif
|
||||
|
||||
@@ -1319,7 +1321,6 @@ int main(int argc, char **argv)
|
||||
ss_free(listen_ctx.remote_addr);
|
||||
}
|
||||
|
||||
|
||||
if (mode != TCP_ONLY) {
|
||||
free_udprelay();
|
||||
}
|
||||
@@ -1416,7 +1417,6 @@ int start_ss_local_server(profile_t profile)
|
||||
listen_ctx.mptcp = mptcp;
|
||||
|
||||
if (mode != UDP_ONLY) {
|
||||
|
||||
// Setup socket
|
||||
int listenfd;
|
||||
listenfd = create_and_bind(local_addr, local_port_str);
|
||||
|
||||
+10
-8
@@ -81,7 +81,7 @@ static void close_and_free_remote(EV_P_ remote_t *remote);
|
||||
static void free_server(server_t *server);
|
||||
static void close_and_free_server(EV_P_ server_t *server);
|
||||
|
||||
int verbose = 0;
|
||||
int verbose = 0;
|
||||
int keep_resolving = 1;
|
||||
|
||||
static int mode = TCP_ONLY;
|
||||
@@ -669,7 +669,8 @@ static void accept_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
if (verbose) LOGI("connected immediately");
|
||||
if (verbose)
|
||||
LOGI("connected immediately");
|
||||
remote_send_cb(EV_A_ & remote->send_ctx->io, 0);
|
||||
} else {
|
||||
// listen to remote connected event
|
||||
@@ -680,7 +681,8 @@ static void accept_cb(EV_P_ ev_io *w, int revents)
|
||||
ev_io_start(EV_A_ & server->recv_ctx->io);
|
||||
}
|
||||
|
||||
void signal_cb(int dummy) {
|
||||
void signal_cb(int dummy)
|
||||
{
|
||||
keep_resolving = 0;
|
||||
exit(-1);
|
||||
}
|
||||
@@ -708,10 +710,10 @@ int main(int argc, char **argv)
|
||||
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{ "mtu", required_argument, 0, 0 },
|
||||
{ "mptcp", no_argument , 0, 0 },
|
||||
{ "help", no_argument , 0, 0 },
|
||||
{ 0, 0 , 0, 0 }
|
||||
{ "mtu", required_argument, 0, 0 },
|
||||
{ "mptcp", no_argument, 0, 0 },
|
||||
{ "help", no_argument, 0, 0 },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
opterr = 0;
|
||||
@@ -880,7 +882,7 @@ int main(int argc, char **argv)
|
||||
// ignore SIGPIPE
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGABRT, SIG_IGN);
|
||||
signal(SIGINT, signal_cb);
|
||||
signal(SIGINT, signal_cb);
|
||||
signal(SIGTERM, signal_cb);
|
||||
|
||||
// Setup keys
|
||||
|
||||
+94
-15
@@ -106,6 +106,7 @@ static void server_resolve_cb(struct sockaddr *addr, void *data);
|
||||
static void query_free_cb(void *data);
|
||||
|
||||
static size_t parse_header_len(const char atyp, const char *data, size_t offset);
|
||||
static int is_header_complete(const buffer_t *buf);
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
@@ -235,6 +236,42 @@ static size_t parse_header_len(const char atyp, const char *data, size_t offset)
|
||||
return len;
|
||||
}
|
||||
|
||||
static int is_header_complete(const buffer_t *buf)
|
||||
{
|
||||
size_t header_len = 0;
|
||||
size_t buf_len = buf->len;
|
||||
|
||||
char atyp = buf->array[header_len];
|
||||
|
||||
// 1 byte for atyp
|
||||
header_len++;
|
||||
|
||||
if ((atyp & ADDRTYPE_MASK) == 1) {
|
||||
// IP V4
|
||||
header_len += sizeof(struct in_addr);
|
||||
} else if ((atyp & ADDRTYPE_MASK) == 3) {
|
||||
// Domain name
|
||||
// domain len + len of domain
|
||||
if (buf_len < header_len + 1)
|
||||
return 0;
|
||||
uint8_t name_len = *(uint8_t *)(buf->array + header_len);
|
||||
header_len += name_len + 1;
|
||||
} else if ((atyp & ADDRTYPE_MASK) == 4) {
|
||||
// IP V6
|
||||
header_len += sizeof(struct in6_addr);
|
||||
}
|
||||
|
||||
// len of port
|
||||
header_len += 2;
|
||||
|
||||
// size of ONETIMEAUTH_BYTES
|
||||
if (auth || (atyp & ONETIMEAUTH_FLAG)) {
|
||||
header_len += ONETIMEAUTH_BYTES;
|
||||
}
|
||||
|
||||
return buf_len >= header_len;
|
||||
}
|
||||
|
||||
static char *get_peer_name(int fd)
|
||||
{
|
||||
static char peer_name[INET6_ADDRSTRLEN] = { 0 };
|
||||
@@ -513,7 +550,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
|
||||
ev_timer_again(EV_A_ & server->recv_ctx->watcher);
|
||||
|
||||
if (server->stage != 0) {
|
||||
if (server->stage > 2) {
|
||||
remote = server->remote;
|
||||
buf = remote->buf;
|
||||
len = 0;
|
||||
@@ -544,16 +581,16 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
|
||||
tx += r;
|
||||
|
||||
// handle incomplete header
|
||||
// handle incomplete header part 1
|
||||
if (server->stage == 0) {
|
||||
buf->len += r;
|
||||
if (buf->len <= enc_get_iv_len()) {
|
||||
if (buf->len <= enc_get_iv_len() + 1) {
|
||||
// wait for more
|
||||
if (verbose) {
|
||||
#ifdef __MINGW32__
|
||||
LOGI("incomplete header: %u", r);
|
||||
LOGI("incomplete IV: %u", r);
|
||||
#else
|
||||
LOGI("incomplete header: %zu", r);
|
||||
LOGI("incomplete IV: %zu", r);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
@@ -572,6 +609,42 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
return;
|
||||
}
|
||||
|
||||
// handle incomplete header part 2
|
||||
if (server->stage == 0) {
|
||||
if (is_header_complete(server->buf)) {
|
||||
bfree(server->header_buf);
|
||||
ss_free(server->header_buf);
|
||||
server->stage = 2;
|
||||
} else {
|
||||
server->stage = 1;
|
||||
}
|
||||
}
|
||||
if (server->stage == 1) {
|
||||
size_t header_len = server->header_buf->len;
|
||||
brealloc(server->header_buf, server->buf->len + header_len, BUF_SIZE);
|
||||
memcpy(server->header_buf->array + header_len,
|
||||
server->buf->array, server->buf->len);
|
||||
server->header_buf->len = server->buf->len + header_len;
|
||||
|
||||
if (is_header_complete(server->header_buf)) {
|
||||
brealloc(server->buf, server->header_buf->len, BUF_SIZE);
|
||||
memcpy(server->buf->array, server->header_buf->array, server->header_buf->len);
|
||||
server->buf->len = server->header_buf->len;
|
||||
bfree(server->header_buf);
|
||||
ss_free(server->header_buf);
|
||||
server->stage = 2;
|
||||
} else {
|
||||
#ifdef __MINGW32__
|
||||
LOGI("incomplete header: %u", server->header_buf->len);
|
||||
#else
|
||||
LOGI("incomplete header: %zu", server->header_buf->len);
|
||||
#endif
|
||||
server->buf->len = 0;
|
||||
server->buf->idx = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// handshake and transmit data
|
||||
if (server->stage == 5) {
|
||||
if (server->auth && !ss_check_hash(remote->buf, server->chunk, server->d_ctx, BUF_SIZE)) {
|
||||
@@ -600,7 +673,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
ev_io_start(EV_A_ & remote->send_ctx->io);
|
||||
}
|
||||
return;
|
||||
} else if (server->stage == 0) {
|
||||
} else if (server->stage == 2) {
|
||||
/*
|
||||
* Shadowsocks TCP Relay Header:
|
||||
*
|
||||
@@ -793,7 +866,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
|
||||
if (!need_query) {
|
||||
int connected = 0;
|
||||
int connected = 0;
|
||||
remote_t *remote = connect_to_remote(&info, server, &connected);
|
||||
|
||||
if (remote == NULL) {
|
||||
@@ -830,7 +903,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
|
||||
server->stage = 4;
|
||||
server->query = resolv_query(host, server_resolve_cb,
|
||||
query_free_cb, query, port);
|
||||
query_free_cb, query, port);
|
||||
|
||||
ev_io_stop(EV_A_ & server_recv_ctx->io);
|
||||
}
|
||||
@@ -947,7 +1020,7 @@ static void server_resolve_cb(struct sockaddr *addr, void *data)
|
||||
info.ai_addrlen = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
|
||||
int connected = 0;
|
||||
int connected = 0;
|
||||
remote_t *remote = connect_to_remote(&info, server, &connected);
|
||||
|
||||
if (remote == NULL) {
|
||||
@@ -1206,6 +1279,7 @@ static server_t *new_server(int fd, listen_ctx_t *listener)
|
||||
server->recv_ctx = ss_malloc(sizeof(server_ctx_t));
|
||||
server->send_ctx = ss_malloc(sizeof(server_ctx_t));
|
||||
server->buf = ss_malloc(sizeof(buffer_t));
|
||||
server->header_buf = ss_malloc(sizeof(buffer_t));
|
||||
server->fd = fd;
|
||||
server->recv_ctx->server = server;
|
||||
server->recv_ctx->connected = 0;
|
||||
@@ -1232,6 +1306,7 @@ static server_t *new_server(int fd, listen_ctx_t *listener)
|
||||
min(MAX_CONNECT_TIMEOUT, listener->timeout), listener->timeout);
|
||||
|
||||
balloc(server->buf, BUF_SIZE);
|
||||
balloc(server->header_buf, BUF_SIZE);
|
||||
|
||||
server->chunk = (chunk_t *)malloc(sizeof(chunk_t));
|
||||
memset(server->chunk, 0, sizeof(chunk_t));
|
||||
@@ -1269,6 +1344,10 @@ static void free_server(server_t *server)
|
||||
bfree(server->buf);
|
||||
ss_free(server->buf);
|
||||
}
|
||||
if (server->header_buf != NULL) {
|
||||
bfree(server->header_buf);
|
||||
ss_free(server->header_buf);
|
||||
}
|
||||
|
||||
ss_free(server->recv_ctx);
|
||||
ss_free(server->send_ctx);
|
||||
@@ -1363,12 +1442,12 @@ int main(int argc, char **argv)
|
||||
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{ "fast-open" , no_argument , 0, 0 },
|
||||
{ "acl" , required_argument, 0, 0 },
|
||||
{ "fast-open", no_argument, 0, 0 },
|
||||
{ "acl", required_argument, 0, 0 },
|
||||
{ "manager-address", required_argument, 0, 0 },
|
||||
{ "mtu" , required_argument, 0, 0 },
|
||||
{ "mptcp" , no_argument , 0, 0 },
|
||||
{ "help" , no_argument , 0, 0 },
|
||||
{ "mtu", required_argument, 0, 0 },
|
||||
{ "mptcp", no_argument, 0, 0 },
|
||||
{ "help", no_argument, 0, 0 },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -1659,7 +1738,7 @@ int main(int argc, char **argv)
|
||||
// Setup UDP
|
||||
if (mode != TCP_ONLY) {
|
||||
init_udprelay(server_host[index], server_port, mtu, m,
|
||||
auth, atoi(timeout), iface);
|
||||
auth, atoi(timeout), iface);
|
||||
}
|
||||
|
||||
LOGI("listening at %s:%s", host ? host : "*", server_port);
|
||||
|
||||
@@ -53,6 +53,7 @@ typedef struct server {
|
||||
int fd;
|
||||
int stage;
|
||||
buffer_t *buf;
|
||||
buffer_t *header_buf;
|
||||
|
||||
int auth;
|
||||
struct chunk *chunk;
|
||||
|
||||
+12
-9
@@ -90,7 +90,7 @@ int vpn = 0;
|
||||
char *prefix;
|
||||
#endif
|
||||
|
||||
int verbose = 0;
|
||||
int verbose = 0;
|
||||
int keep_resolving = 1;
|
||||
|
||||
static int mode = TCP_ONLY;
|
||||
@@ -636,7 +636,8 @@ static void accept_cb(EV_P_ ev_io *w, int revents)
|
||||
int not_protect = 0;
|
||||
if (remote_addr->sa_family == AF_INET) {
|
||||
struct sockaddr_in *s = (struct sockaddr_in *)remote_addr;
|
||||
if (s->sin_addr.s_addr == inet_addr("127.0.0.1")) not_protect = 1;
|
||||
if (s->sin_addr.s_addr == inet_addr("127.0.0.1"))
|
||||
not_protect = 1;
|
||||
}
|
||||
if (!not_protect) {
|
||||
if (protect_socket(remotefd) == -1) {
|
||||
@@ -685,7 +686,8 @@ static void accept_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
if (verbose) LOGI("connected immediately");
|
||||
if (verbose)
|
||||
LOGI("connected immediately");
|
||||
remote_send_cb(EV_A_ & remote->send_ctx->io, 0);
|
||||
} else {
|
||||
// listen to remote connected event
|
||||
@@ -694,7 +696,8 @@ static void accept_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
}
|
||||
|
||||
void signal_cb(int dummy) {
|
||||
void signal_cb(int dummy)
|
||||
{
|
||||
keep_resolving = 0;
|
||||
exit(-1);
|
||||
}
|
||||
@@ -726,10 +729,10 @@ int main(int argc, char **argv)
|
||||
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{ "mtu", required_argument, 0, 0 },
|
||||
{ "mptcp",no_argument, 0, 0 },
|
||||
{ "help", no_argument, 0, 0 },
|
||||
{ 0, 0, 0, 0 }
|
||||
{ "mtu", required_argument, 0, 0 },
|
||||
{ "mptcp", no_argument, 0, 0 },
|
||||
{ "help", no_argument, 0, 0 },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
opterr = 0;
|
||||
@@ -935,7 +938,7 @@ int main(int argc, char **argv)
|
||||
// ignore SIGPIPE
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGABRT, SIG_IGN);
|
||||
signal(SIGINT, signal_cb);
|
||||
signal(SIGINT, signal_cb);
|
||||
signal(SIGTERM, signal_cb);
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user