mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-23 08:03:54 +00:00
Fix #826
This commit is contained in:
+219
-221
@@ -439,248 +439,246 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
close_and_free_remote(EV_A_ remote);
|
||||
close_and_free_server(EV_A_ server);
|
||||
return;
|
||||
} else {
|
||||
char host[257], ip[INET6_ADDRSTRLEN], port[16];
|
||||
}
|
||||
|
||||
buffer_t ss_addr_to_send;
|
||||
buffer_t *abuf = &ss_addr_to_send;
|
||||
balloc(abuf, BUF_SIZE);
|
||||
// Fake reply
|
||||
if (server->stage == 1) {
|
||||
struct socks5_response response;
|
||||
response.ver = SVERSION;
|
||||
response.rep = 0;
|
||||
response.rsv = 0;
|
||||
response.atyp = 1;
|
||||
|
||||
abuf->array[abuf->len++] = request->atyp;
|
||||
int atyp = request->atyp;
|
||||
buffer_t resp_to_send;
|
||||
buffer_t *resp_buf = &resp_to_send;
|
||||
balloc(resp_buf, BUF_SIZE);
|
||||
|
||||
// get remote addr and port
|
||||
if (atyp == 1) {
|
||||
// IP V4
|
||||
size_t in_addr_len = sizeof(struct in_addr);
|
||||
memcpy(abuf->array + abuf->len, buf->array + 4, in_addr_len + 2);
|
||||
abuf->len += in_addr_len + 2;
|
||||
memcpy(resp_buf->array, &response, sizeof(struct socks5_response));
|
||||
memcpy(resp_buf->array + sizeof(struct socks5_response),
|
||||
&sock_addr.sin_addr, sizeof(sock_addr.sin_addr));
|
||||
memcpy(resp_buf->array + sizeof(struct socks5_response) +
|
||||
sizeof(sock_addr.sin_addr),
|
||||
&sock_addr.sin_port, sizeof(sock_addr.sin_port));
|
||||
|
||||
if (acl || verbose) {
|
||||
uint16_t p = ntohs(*(uint16_t *)(buf->array + 4 + in_addr_len));
|
||||
dns_ntop(AF_INET, (const void *)(buf->array + 4),
|
||||
ip, INET_ADDRSTRLEN);
|
||||
sprintf(port, "%d", p);
|
||||
}
|
||||
} else if (atyp == 3) {
|
||||
// Domain name
|
||||
uint8_t name_len = *(uint8_t *)(buf->array + 4);
|
||||
abuf->array[abuf->len++] = name_len;
|
||||
memcpy(abuf->array + abuf->len, buf->array + 4 + 1, name_len + 2);
|
||||
abuf->len += name_len + 2;
|
||||
int reply_size = sizeof(struct socks5_response) +
|
||||
sizeof(sock_addr.sin_addr) + sizeof(sock_addr.sin_port);
|
||||
|
||||
if (acl || verbose) {
|
||||
uint16_t p =
|
||||
ntohs(*(uint16_t *)(buf->array + 4 + 1 + name_len));
|
||||
memcpy(host, buf->array + 4 + 1, name_len);
|
||||
host[name_len] = '\0';
|
||||
sprintf(port, "%d", p);
|
||||
}
|
||||
} else if (atyp == 4) {
|
||||
// IP V6
|
||||
size_t in6_addr_len = sizeof(struct in6_addr);
|
||||
memcpy(abuf->array + abuf->len, buf->array + 4, in6_addr_len + 2);
|
||||
abuf->len += in6_addr_len + 2;
|
||||
int s = send(server->fd, resp_buf->array, reply_size, 0);
|
||||
|
||||
if (acl || verbose) {
|
||||
uint16_t p = ntohs(*(uint16_t *)(buf->array + 4 + in6_addr_len));
|
||||
dns_ntop(AF_INET6, (const void *)(buf->array + 4),
|
||||
ip, INET6_ADDRSTRLEN);
|
||||
sprintf(port, "%d", p);
|
||||
}
|
||||
} else {
|
||||
bfree(abuf);
|
||||
LOGE("unsupported addrtype: %d", request->atyp);
|
||||
bfree(resp_buf);
|
||||
|
||||
if (s < reply_size) {
|
||||
LOGE("failed to send fake reply");
|
||||
close_and_free_remote(EV_A_ remote);
|
||||
close_and_free_server(EV_A_ server);
|
||||
return;
|
||||
}
|
||||
|
||||
if (server->stage == 1) {
|
||||
// Fake reply
|
||||
struct socks5_response response;
|
||||
response.ver = SVERSION;
|
||||
response.rep = 0;
|
||||
response.rsv = 0;
|
||||
response.atyp = 1;
|
||||
|
||||
buffer_t resp_to_send;
|
||||
buffer_t *resp_buf = &resp_to_send;
|
||||
balloc(resp_buf, BUF_SIZE);
|
||||
|
||||
memcpy(resp_buf->array, &response, sizeof(struct socks5_response));
|
||||
memcpy(resp_buf->array + sizeof(struct socks5_response),
|
||||
&sock_addr.sin_addr, sizeof(sock_addr.sin_addr));
|
||||
memcpy(resp_buf->array + sizeof(struct socks5_response) +
|
||||
sizeof(sock_addr.sin_addr),
|
||||
&sock_addr.sin_port, sizeof(sock_addr.sin_port));
|
||||
|
||||
int reply_size = sizeof(struct socks5_response) +
|
||||
sizeof(sock_addr.sin_addr) + sizeof(sock_addr.sin_port);
|
||||
|
||||
int s = send(server->fd, resp_buf->array, reply_size, 0);
|
||||
|
||||
bfree(resp_buf);
|
||||
|
||||
if (s < reply_size) {
|
||||
LOGE("failed to send fake reply");
|
||||
bfree(abuf);
|
||||
close_and_free_remote(EV_A_ remote);
|
||||
close_and_free_server(EV_A_ server);
|
||||
return;
|
||||
}
|
||||
if (udp_assc) {
|
||||
bfree(abuf);
|
||||
close_and_free_remote(EV_A_ remote);
|
||||
close_and_free_server(EV_A_ server);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
size_t abuf_len = abuf->len;
|
||||
int sni_detected = 0;
|
||||
|
||||
if (atyp == 1 || atyp == 4) {
|
||||
char *hostname;
|
||||
uint16_t p = ntohs(*(uint16_t *)(abuf->array + abuf->len - 2));
|
||||
int ret = 0;
|
||||
if (p == http_protocol->default_port)
|
||||
ret = http_protocol->parse_packet(buf->array + 3 + abuf->len,
|
||||
buf->len - 3 - abuf->len, &hostname);
|
||||
else if (p == tls_protocol->default_port)
|
||||
ret = tls_protocol->parse_packet(buf->array + 3 + abuf->len,
|
||||
buf->len - 3 - abuf->len, &hostname);
|
||||
if (ret == -1) {
|
||||
server->stage = 2;
|
||||
bfree(abuf);
|
||||
return;
|
||||
} else if (ret > 0) {
|
||||
sni_detected = 1;
|
||||
|
||||
// Reconstruct address buffer
|
||||
abuf->len = 0;
|
||||
abuf->array[abuf->len++] = 3;
|
||||
abuf->array[abuf->len++] = ret;
|
||||
memcpy(abuf->array + abuf->len, hostname, ret);
|
||||
abuf->len += ret;
|
||||
p = htons(p);
|
||||
memcpy(abuf->array + abuf->len, &p, 2);
|
||||
abuf->len += 2;
|
||||
|
||||
if (acl || verbose) {
|
||||
memcpy(host, hostname, ret);
|
||||
host[ret] = '\0';
|
||||
}
|
||||
|
||||
ss_free(hostname);
|
||||
}
|
||||
}
|
||||
|
||||
server->stage = 5;
|
||||
|
||||
buf->len -= (3 + abuf_len);
|
||||
if (buf->len > 0) {
|
||||
memmove(buf->array, buf->array + 3 + abuf_len, buf->len);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
if (sni_detected || atyp == 3)
|
||||
LOGI("connect to %s:%s", host, port);
|
||||
else if (atyp == 1)
|
||||
LOGI("connect to %s:%s", ip, port);
|
||||
else if (atyp == 4)
|
||||
LOGI("connect to [%s]:%s", ip, port);
|
||||
}
|
||||
|
||||
if (acl) {
|
||||
int host_match = acl_match_host(host);
|
||||
int ip_match = acl_match_host(ip);
|
||||
|
||||
int bypass = get_acl_mode() == WHITE_LIST;
|
||||
|
||||
if (get_acl_mode() == BLACK_LIST) {
|
||||
if (ip_match > 0)
|
||||
bypass = 1; // bypass IPs in black list
|
||||
|
||||
if (host_match > 0)
|
||||
bypass = 1; // bypass hostnames in black list
|
||||
else if (host_match < 0)
|
||||
bypass = 0; // proxy hostnames in white list
|
||||
} else if (get_acl_mode() == WHITE_LIST) {
|
||||
if (ip_match < 0)
|
||||
bypass = 0; // proxy IPs in white list
|
||||
|
||||
if (host_match < 0)
|
||||
bypass = 0; // proxy hostnames in white list
|
||||
else if (host_match > 0)
|
||||
bypass = 1; // bypass hostnames in black list
|
||||
}
|
||||
|
||||
if (bypass) {
|
||||
if (verbose) {
|
||||
if (sni_detected || atyp == 3)
|
||||
LOGI("bypass %s:%s", host, port);
|
||||
else if (atyp == 1)
|
||||
LOGI("bypass %s:%s", ip, port);
|
||||
else if (atyp == 4)
|
||||
LOGI("bypass [%s]:%s", ip, port);
|
||||
}
|
||||
struct sockaddr_storage storage;
|
||||
int err;
|
||||
memset(&storage, 0, sizeof(struct sockaddr_storage));
|
||||
if (atyp == 1 || atyp == 4) {
|
||||
err = get_sockaddr(ip, port, &storage, 0);
|
||||
} else {
|
||||
err = get_sockaddr(host, port, &storage, 1);
|
||||
}
|
||||
if (err != -1) {
|
||||
remote = create_remote(server->listener, (struct sockaddr *)&storage);
|
||||
remote->direct = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not match ACL
|
||||
if (remote == NULL) {
|
||||
remote = create_remote(server->listener, NULL);
|
||||
}
|
||||
|
||||
if (remote == NULL) {
|
||||
bfree(abuf);
|
||||
LOGE("invalid remote addr");
|
||||
if (udp_assc) {
|
||||
close_and_free_remote(EV_A_ remote);
|
||||
close_and_free_server(EV_A_ server);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!remote->direct) {
|
||||
if (auth) {
|
||||
abuf->array[0] |= ONETIMEAUTH_FLAG;
|
||||
ss_onetimeauth(abuf, server->e_ctx->evp.iv, BUF_SIZE);
|
||||
char host[257], ip[INET6_ADDRSTRLEN], port[16];
|
||||
|
||||
buffer_t ss_addr_to_send;
|
||||
buffer_t *abuf = &ss_addr_to_send;
|
||||
balloc(abuf, BUF_SIZE);
|
||||
|
||||
abuf->array[abuf->len++] = request->atyp;
|
||||
int atyp = request->atyp;
|
||||
|
||||
// get remote addr and port
|
||||
if (atyp == 1) {
|
||||
// IP V4
|
||||
size_t in_addr_len = sizeof(struct in_addr);
|
||||
memcpy(abuf->array + abuf->len, buf->array + 4, in_addr_len + 2);
|
||||
abuf->len += in_addr_len + 2;
|
||||
|
||||
if (acl || verbose) {
|
||||
uint16_t p = ntohs(*(uint16_t *)(buf->array + 4 + in_addr_len));
|
||||
dns_ntop(AF_INET, (const void *)(buf->array + 4),
|
||||
ip, INET_ADDRSTRLEN);
|
||||
sprintf(port, "%d", p);
|
||||
}
|
||||
} else if (atyp == 3) {
|
||||
// Domain name
|
||||
uint8_t name_len = *(uint8_t *)(buf->array + 4);
|
||||
abuf->array[abuf->len++] = name_len;
|
||||
memcpy(abuf->array + abuf->len, buf->array + 4 + 1, name_len + 2);
|
||||
abuf->len += name_len + 2;
|
||||
|
||||
if (acl || verbose) {
|
||||
uint16_t p =
|
||||
ntohs(*(uint16_t *)(buf->array + 4 + 1 + name_len));
|
||||
memcpy(host, buf->array + 4 + 1, name_len);
|
||||
host[name_len] = '\0';
|
||||
sprintf(port, "%d", p);
|
||||
}
|
||||
} else if (atyp == 4) {
|
||||
// IP V6
|
||||
size_t in6_addr_len = sizeof(struct in6_addr);
|
||||
memcpy(abuf->array + abuf->len, buf->array + 4, in6_addr_len + 2);
|
||||
abuf->len += in6_addr_len + 2;
|
||||
|
||||
if (acl || verbose) {
|
||||
uint16_t p = ntohs(*(uint16_t *)(buf->array + 4 + in6_addr_len));
|
||||
dns_ntop(AF_INET6, (const void *)(buf->array + 4),
|
||||
ip, INET6_ADDRSTRLEN);
|
||||
sprintf(port, "%d", p);
|
||||
}
|
||||
} else {
|
||||
bfree(abuf);
|
||||
LOGE("unsupported addrtype: %d", request->atyp);
|
||||
close_and_free_remote(EV_A_ remote);
|
||||
close_and_free_server(EV_A_ server);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t abuf_len = abuf->len;
|
||||
int sni_detected = 0;
|
||||
|
||||
if (atyp == 1 || atyp == 4) {
|
||||
char *hostname;
|
||||
uint16_t p = ntohs(*(uint16_t *)(abuf->array + abuf->len - 2));
|
||||
int ret = 0;
|
||||
if (p == http_protocol->default_port)
|
||||
ret = http_protocol->parse_packet(buf->array + 3 + abuf->len,
|
||||
buf->len - 3 - abuf->len, &hostname);
|
||||
else if (p == tls_protocol->default_port)
|
||||
ret = tls_protocol->parse_packet(buf->array + 3 + abuf->len,
|
||||
buf->len - 3 - abuf->len, &hostname);
|
||||
if (ret == -1) {
|
||||
server->stage = 2;
|
||||
bfree(abuf);
|
||||
return;
|
||||
} else if (ret > 0) {
|
||||
sni_detected = 1;
|
||||
|
||||
// Reconstruct address buffer
|
||||
abuf->len = 0;
|
||||
abuf->array[abuf->len++] = 3;
|
||||
abuf->array[abuf->len++] = ret;
|
||||
memcpy(abuf->array + abuf->len, hostname, ret);
|
||||
abuf->len += ret;
|
||||
p = htons(p);
|
||||
memcpy(abuf->array + abuf->len, &p, 2);
|
||||
abuf->len += 2;
|
||||
|
||||
if (acl || verbose) {
|
||||
memcpy(host, hostname, ret);
|
||||
host[ret] = '\0';
|
||||
}
|
||||
|
||||
if (buf->len > 0 && auth) {
|
||||
ss_gen_hash(buf, &remote->counter, server->e_ctx, BUF_SIZE);
|
||||
}
|
||||
ss_free(hostname);
|
||||
}
|
||||
}
|
||||
|
||||
brealloc(remote->buf, buf->len + abuf->len, BUF_SIZE);
|
||||
memcpy(remote->buf->array, abuf->array, abuf->len);
|
||||
remote->buf->len = buf->len + abuf->len;
|
||||
server->stage = 5;
|
||||
|
||||
if (buf->len > 0) {
|
||||
memcpy(remote->buf->array + abuf->len, buf->array, buf->len);
|
||||
}
|
||||
} else {
|
||||
if (buf->len > 0) {
|
||||
memcpy(remote->buf->array, buf->array, buf->len);
|
||||
remote->buf->len = buf->len;
|
||||
}
|
||||
buf->len -= (3 + abuf_len);
|
||||
if (buf->len > 0) {
|
||||
memmove(buf->array, buf->array + 3 + abuf_len, buf->len);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
if (sni_detected || atyp == 3)
|
||||
LOGI("connect to %s:%s", host, port);
|
||||
else if (atyp == 1)
|
||||
LOGI("connect to %s:%s", ip, port);
|
||||
else if (atyp == 4)
|
||||
LOGI("connect to [%s]:%s", ip, port);
|
||||
}
|
||||
|
||||
if (acl) {
|
||||
int host_match = acl_match_host(host);
|
||||
int ip_match = acl_match_host(ip);
|
||||
|
||||
int bypass = get_acl_mode() == WHITE_LIST;
|
||||
|
||||
if (get_acl_mode() == BLACK_LIST) {
|
||||
if (ip_match > 0)
|
||||
bypass = 1; // bypass IPs in black list
|
||||
|
||||
if (host_match > 0)
|
||||
bypass = 1; // bypass hostnames in black list
|
||||
else if (host_match < 0)
|
||||
bypass = 0; // proxy hostnames in white list
|
||||
} else if (get_acl_mode() == WHITE_LIST) {
|
||||
if (ip_match < 0)
|
||||
bypass = 0; // proxy IPs in white list
|
||||
|
||||
if (host_match < 0)
|
||||
bypass = 0; // proxy hostnames in white list
|
||||
else if (host_match > 0)
|
||||
bypass = 1; // bypass hostnames in black list
|
||||
}
|
||||
|
||||
server->remote = remote;
|
||||
remote->server = server;
|
||||
|
||||
bfree(abuf);
|
||||
if (bypass) {
|
||||
if (verbose) {
|
||||
if (sni_detected || atyp == 3)
|
||||
LOGI("bypass %s:%s", host, port);
|
||||
else if (atyp == 1)
|
||||
LOGI("bypass %s:%s", ip, port);
|
||||
else if (atyp == 4)
|
||||
LOGI("bypass [%s]:%s", ip, port);
|
||||
}
|
||||
struct sockaddr_storage storage;
|
||||
int err;
|
||||
memset(&storage, 0, sizeof(struct sockaddr_storage));
|
||||
if (atyp == 1 || atyp == 4) {
|
||||
err = get_sockaddr(ip, port, &storage, 0);
|
||||
} else {
|
||||
err = get_sockaddr(host, port, &storage, 1);
|
||||
}
|
||||
if (err != -1) {
|
||||
remote = create_remote(server->listener, (struct sockaddr *)&storage);
|
||||
remote->direct = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not match ACL
|
||||
if (remote == NULL) {
|
||||
remote = create_remote(server->listener, NULL);
|
||||
}
|
||||
|
||||
if (remote == NULL) {
|
||||
bfree(abuf);
|
||||
LOGE("invalid remote addr");
|
||||
close_and_free_server(EV_A_ server);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!remote->direct) {
|
||||
if (auth) {
|
||||
abuf->array[0] |= ONETIMEAUTH_FLAG;
|
||||
ss_onetimeauth(abuf, server->e_ctx->evp.iv, BUF_SIZE);
|
||||
}
|
||||
|
||||
if (buf->len > 0 && auth) {
|
||||
ss_gen_hash(buf, &remote->counter, server->e_ctx, BUF_SIZE);
|
||||
}
|
||||
|
||||
brealloc(remote->buf, buf->len + abuf->len, BUF_SIZE);
|
||||
memcpy(remote->buf->array, abuf->array, abuf->len);
|
||||
remote->buf->len = buf->len + abuf->len;
|
||||
|
||||
if (buf->len > 0) {
|
||||
memcpy(remote->buf->array + abuf->len, buf->array, buf->len);
|
||||
}
|
||||
} else {
|
||||
if (buf->len > 0) {
|
||||
memcpy(remote->buf->array, buf->array, buf->len);
|
||||
remote->buf->len = buf->len;
|
||||
}
|
||||
}
|
||||
|
||||
server->remote = remote;
|
||||
remote->server = server;
|
||||
|
||||
bfree(abuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user