Browse Source

Fix #826

pull/829/head
Max Lv 8 years ago
parent
commit
306f84b522
1 changed files with 200 additions and 202 deletions
  1. 402
      src/local.c

402
src/local.c

@ -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 (udp_assc) {
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));
char host[257], ip[INET6_ADDRSTRLEN], port[16];
int reply_size = sizeof(struct socks5_response) +
sizeof(sock_addr.sin_addr) + sizeof(sock_addr.sin_port);
buffer_t ss_addr_to_send;
buffer_t *abuf = &ss_addr_to_send;
balloc(abuf, BUF_SIZE);
int s = send(server->fd, resp_buf->array, reply_size, 0);
abuf->array[abuf->len++] = request->atyp;
int atyp = request->atyp;
bfree(resp_buf);
// 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 (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;
}
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';
}
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;
ss_free(hostname);
if (acl || verbose) {
memcpy(host, hostname, ret);
host[ret] = '\0';
}
}
server->stage = 5;
buf->len -= (3 + abuf_len);
if (buf->len > 0) {
memmove(buf->array, buf->array + 3 + abuf_len, buf->len);
ss_free(hostname);
}
}
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);
}
server->stage = 5;
if (acl) {
int host_match = acl_match_host(host);
int ip_match = acl_match_host(ip);
buf->len -= (3 + abuf_len);
if (buf->len > 0) {
memmove(buf->array, buf->array + 3 + abuf_len, buf->len);
}
int bypass = get_acl_mode() == WHITE_LIST;
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 (get_acl_mode() == BLACK_LIST) {
if (ip_match > 0)
bypass = 1; // bypass IPs in black list
if (acl) {
int host_match = acl_match_host(host);
int ip_match = acl_match_host(ip);
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
int bypass = get_acl_mode() == 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 (get_acl_mode() == BLACK_LIST) {
if (ip_match > 0)
bypass = 1; // bypass IPs 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;
}
}
}
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
// Not match ACL
if (remote == NULL) {
remote = create_remote(server->listener, NULL);
if (host_match < 0)
bypass = 0; // proxy hostnames in white list
else if (host_match > 0)
bypass = 1; // bypass hostnames in black list
}
if (remote == NULL) {
bfree(abuf);
LOGE("invalid remote addr");
close_and_free_server(EV_A_ server);
return;
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;
}
}
}
if (!remote->direct) {
if (auth) {
abuf->array[0] |= ONETIMEAUTH_FLAG;
ss_onetimeauth(abuf, server->e_ctx->evp.iv, BUF_SIZE);
}
// Not match ACL
if (remote == NULL) {
remote = create_remote(server->listener, NULL);
}
if (buf->len > 0 && auth) {
ss_gen_hash(buf, &remote->counter, server->e_ctx, BUF_SIZE);
}
if (remote == NULL) {
bfree(abuf);
LOGE("invalid remote addr");
close_and_free_server(EV_A_ server);
return;
}
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 (!remote->direct) {
if (auth) {
abuf->array[0] |= ONETIMEAUTH_FLAG;
ss_onetimeauth(abuf, server->e_ctx->evp.iv, BUF_SIZE);
}
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;
}
if (buf->len > 0 && auth) {
ss_gen_hash(buf, &remote->counter, server->e_ctx, BUF_SIZE);
}
server->remote = remote;
remote->server = server;
brealloc(remote->buf, buf->len + abuf->len, BUF_SIZE);
memcpy(remote->buf->array, abuf->array, abuf->len);
remote->buf->len = buf->len + abuf->len;
bfree(abuf);
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);
}
}
}

Loading…
Cancel
Save