mirror of
https://github.com/yarrick/iodine.git
synced 2024-11-25 11:05:15 +00:00
Implemented TCP forward function (can be used with SSH proxycommand)
This commit is contained in:
parent
d46766bcc9
commit
a5a936f4e4
247
src/client.c
247
src/client.c
@ -29,6 +29,7 @@
|
|||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
#ifdef WINDOWS32
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
@ -201,7 +202,7 @@ update_server_timeout(int handshake)
|
|||||||
|
|
||||||
if (handshake) {
|
if (handshake) {
|
||||||
/* Send ping handshake to set server timeout */
|
/* Send ping handshake to set server timeout */
|
||||||
return send_ping(1, -1, 1);
|
return send_ping(1, -1, 1, 0);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -447,7 +448,7 @@ send_packet(char cmd, const uint8_t *data, const size_t datalen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
send_ping(int ping_response, int ack, int set_timeout)
|
send_ping(int ping_response, int ack, int set_timeout, int disconnect)
|
||||||
{
|
{
|
||||||
this.num_pings++;
|
this.num_pings++;
|
||||||
if (this.conn == CONN_DNS_NULL) {
|
if (this.conn == CONN_DNS_NULL) {
|
||||||
@ -468,14 +469,16 @@ send_ping(int ping_response, int ack, int set_timeout)
|
|||||||
*(uint16_t *) (data + 7) = htons(this.downstream_timeout_ms);
|
*(uint16_t *) (data + 7) = htons(this.downstream_timeout_ms);
|
||||||
|
|
||||||
/* update server frag/lazy timeout, ack flag, respond with ping flag */
|
/* update server frag/lazy timeout, ack flag, respond with ping flag */
|
||||||
data[9] = ((set_timeout & 1) << 4) | ((set_timeout & 1) << 3) | ((ack < 0 ? 0 : 1) << 2) | (ping_response & 1);
|
data[9] = ((disconnect & 1) << 5) | ((set_timeout & 1) << 4) |
|
||||||
|
((set_timeout & 1) << 3) | ((ack < 0 ? 0 : 1) << 2) | (ping_response & 1);
|
||||||
data[10] = (this.rand_seed >> 8) & 0xff;
|
data[10] = (this.rand_seed >> 8) & 0xff;
|
||||||
data[11] = (this.rand_seed >> 0) & 0xff;
|
data[11] = (this.rand_seed >> 0) & 0xff;
|
||||||
this.rand_seed += 1;
|
this.rand_seed += 1;
|
||||||
|
|
||||||
DEBUG(3, " SEND PING: respond %d, ack %d, %s(server %ld ms, downfrag %ld ms), flags %02X",
|
DEBUG(3, " SEND PING: %srespond %d, ack %d, %s(server %ld ms, downfrag %ld ms), flags %02X, wup %u, wdn %u",
|
||||||
ping_response, ack, set_timeout ? "SET " : "", this.server_timeout_ms,
|
disconnect ? "DISCONNECT! " : "", ping_response, ack, set_timeout ? "SET " : "",
|
||||||
this.downstream_timeout_ms, data[8]);
|
this.server_timeout_ms, this.downstream_timeout_ms,
|
||||||
|
data[8], this.outbuf->windowsize, this.inbuf->windowsize);
|
||||||
|
|
||||||
id = send_packet('p', data, sizeof(data));
|
id = send_packet('p', data, sizeof(data));
|
||||||
|
|
||||||
@ -505,7 +508,7 @@ send_next_frag()
|
|||||||
if (this.outbuf->numitems > 0) {
|
if (this.outbuf->numitems > 0) {
|
||||||
/* There is stuff to send but we're out of sync, so send a ping
|
/* There is stuff to send but we're out of sync, so send a ping
|
||||||
* to get things back in order and keep the packets flowing */
|
* to get things back in order and keep the packets flowing */
|
||||||
send_ping(1, this.next_downstream_ack, 1);
|
send_ping(1, this.next_downstream_ack, 1, 0);
|
||||||
this.next_downstream_ack = -1;
|
this.next_downstream_ack = -1;
|
||||||
window_tick(this.outbuf);
|
window_tick(this.outbuf);
|
||||||
}
|
}
|
||||||
@ -889,11 +892,11 @@ handshake_waitdns(char *buf, size_t buflen, char cmd, int timeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
parse_data(uint8_t *data, size_t len, fragment *f, int *immediate)
|
parse_data(uint8_t *data, size_t len, fragment *f, int *immediate, int *ping)
|
||||||
{
|
{
|
||||||
size_t headerlen = DOWNSTREAM_HDR;
|
size_t headerlen = DOWNSTREAM_HDR;
|
||||||
int ping;
|
|
||||||
memset(f, 0, sizeof(fragment));
|
memset(f, 0, sizeof(fragment));
|
||||||
|
int error;
|
||||||
|
|
||||||
f->seqID = data[0];
|
f->seqID = data[0];
|
||||||
|
|
||||||
@ -902,12 +905,13 @@ parse_data(uint8_t *data, size_t len, fragment *f, int *immediate)
|
|||||||
f->start = (data[2] >> 1) & 1;
|
f->start = (data[2] >> 1) & 1;
|
||||||
f->compressed = (data[2] >> 2) & 1;
|
f->compressed = (data[2] >> 2) & 1;
|
||||||
f->ack_other = (data[2] >> 3) & 1 ? data[1] : -1;
|
f->ack_other = (data[2] >> 3) & 1 ? data[1] : -1;
|
||||||
ping = (data[2] >> 4) & 1;
|
if (ping) *ping = (data[2] >> 4) & 1;
|
||||||
|
error = (data[2] >> 6) & 1;
|
||||||
|
|
||||||
if (immediate)
|
if (immediate)
|
||||||
*immediate = (data[2] >> 5) & 1;
|
*immediate = (data[2] >> 5) & 1;
|
||||||
|
|
||||||
if (ping) { /* Handle ping stuff */
|
if (ping && *ping) { /* Handle ping stuff */
|
||||||
static unsigned dn_start_seq, up_start_seq, dn_wsize, up_wsize;
|
static unsigned dn_start_seq, up_start_seq, dn_wsize, up_wsize;
|
||||||
|
|
||||||
headerlen = DOWNSTREAM_PING_HDR;
|
headerlen = DOWNSTREAM_PING_HDR;
|
||||||
@ -924,7 +928,52 @@ parse_data(uint8_t *data, size_t len, fragment *f, int *immediate)
|
|||||||
f->len = len - headerlen;
|
f->len = len - headerlen;
|
||||||
if (f->len > 0)
|
if (f->len > 0)
|
||||||
memcpy(f->data, data + headerlen, MIN(f->len, sizeof(f->data)));
|
memcpy(f->data, data + headerlen, MIN(f->len, sizeof(f->data)));
|
||||||
return ping; /* return ping flag (if corresponding query was a ping) */
|
return error; /* return ping flag (if corresponding query was a ping) */
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
tunnel_stdin()
|
||||||
|
{
|
||||||
|
size_t datalen;
|
||||||
|
uint8_t out[64*1024];
|
||||||
|
uint8_t in[64*1024];
|
||||||
|
uint8_t *data;
|
||||||
|
ssize_t readlen;
|
||||||
|
|
||||||
|
readlen = read(STDIN_FILENO, in, sizeof(in));
|
||||||
|
DEBUG(4, " IN: %" L "d bytes on stdin, to be compressed: %d", readlen, this.compression_up);
|
||||||
|
if (readlen == 0) {
|
||||||
|
DEBUG(2, "EOF on stdin!");
|
||||||
|
return -1;
|
||||||
|
} else if (readlen < 0) {
|
||||||
|
warnx("Error %d reading from stdin: %s", errno, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.conn != CONN_DNS_NULL || this.compression_up) {
|
||||||
|
datalen = sizeof(out);
|
||||||
|
compress2(out, &datalen, in, readlen, 9);
|
||||||
|
data = out;
|
||||||
|
} else {
|
||||||
|
datalen = readlen;
|
||||||
|
data = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.conn == CONN_DNS_NULL) {
|
||||||
|
/* Check if outgoing buffer can hold data */
|
||||||
|
if (window_buffer_available(this.outbuf) < (datalen / MAX_FRAGSIZE) + 1) {
|
||||||
|
DEBUG(1, " Outgoing buffer full (%" L "u/%" L "u), not adding data!",
|
||||||
|
this.outbuf->numitems, this.outbuf->length);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
window_add_outgoing_data(this.outbuf, data, datalen, this.compression_up);
|
||||||
|
/* Don't send anything here to respect min. send interval */
|
||||||
|
} else {
|
||||||
|
send_raw_data(data, datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
return datalen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -974,7 +1023,7 @@ tunnel_dns()
|
|||||||
size_t datalen, buflen;
|
size_t datalen, buflen;
|
||||||
uint8_t buf[64*1024], cbuf[64*1024], *data;
|
uint8_t buf[64*1024], cbuf[64*1024], *data;
|
||||||
fragment f;
|
fragment f;
|
||||||
int read, compressed, res, immediate;
|
int read, compressed, ping, immediate, error;
|
||||||
|
|
||||||
memset(&q, 0, sizeof(q));
|
memset(&q, 0, sizeof(q));
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@ -1060,27 +1109,35 @@ tunnel_dns()
|
|||||||
|
|
||||||
this.num_recv++;
|
this.num_recv++;
|
||||||
|
|
||||||
/* Decode the downstream data header and fragment-ify ready for processing */
|
|
||||||
res = parse_data(cbuf, read, &f, &immediate);
|
|
||||||
|
|
||||||
/* Mark query as received */
|
/* Mark query as received */
|
||||||
got_response(q.id, immediate, 0);
|
got_response(q.id, immediate, 0);
|
||||||
|
|
||||||
if ((this.debug >= 3 && res) || (this.debug >= 2 && !res))
|
/* Decode the downstream data header and fragment-ify ready for processing */
|
||||||
|
error = parse_data(cbuf, read, &f, &immediate, &ping);
|
||||||
|
|
||||||
|
if ((this.debug >= 3 && ping) || (this.debug >= 2 && !ping))
|
||||||
fprintf(stderr, " RX %s; frag ID %3u, ACK %3d, compression %d, datalen %" L "u, s%d e%d\n",
|
fprintf(stderr, " RX %s; frag ID %3u, ACK %3d, compression %d, datalen %" L "u, s%d e%d\n",
|
||||||
res ? "PING" : "DATA", f.seqID, f.ack_other, f.compressed, f.len, f.start, f.end);
|
ping ? "PING" : "DATA", f.seqID, f.ack_other, f.compressed, f.len, f.start, f.end);
|
||||||
|
|
||||||
|
|
||||||
window_ack(this.outbuf, f.ack_other);
|
window_ack(this.outbuf, f.ack_other);
|
||||||
window_tick(this.outbuf);
|
window_tick(this.outbuf);
|
||||||
|
|
||||||
|
/* respond to TCP forwarding errors by shutting down */
|
||||||
|
if (error && this.use_remote_forward) {
|
||||||
|
f.data[f.len] = 0;
|
||||||
|
warnx("server: TCP forwarding error: %s", f.data);
|
||||||
|
this.running = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* In lazy mode, we shouldn't get immediate replies to our most-recent
|
/* In lazy mode, we shouldn't get immediate replies to our most-recent
|
||||||
query, only during heavy data transfer. Since this means the server
|
query, only during heavy data transfer. Since this means the server
|
||||||
doesn't have any packets to send, send one relatively fast (but not
|
doesn't have any packets to send, send one relatively fast (but not
|
||||||
too fast, to avoid runaway ping-pong loops..) */
|
too fast, to avoid runaway ping-pong loops..) */
|
||||||
/* Don't send anything too soon; no data waiting from server */
|
/* Don't send anything too soon; no data waiting from server */
|
||||||
if (f.len == 0) {
|
if (f.len == 0) {
|
||||||
if (!res)
|
if (!ping)
|
||||||
DEBUG(1, "[WARNING] Received downstream data fragment with 0 length and NOT a ping!");
|
DEBUG(1, "[WARNING] Received downstream data fragment with 0 length and NOT a ping!");
|
||||||
if (!this.lazymode)
|
if (!this.lazymode)
|
||||||
this.send_ping_soon = 100;
|
this.send_ping_soon = 100;
|
||||||
@ -1107,8 +1164,8 @@ tunnel_dns()
|
|||||||
if (datalen > 0) {
|
if (datalen > 0) {
|
||||||
if (compressed) {
|
if (compressed) {
|
||||||
buflen = sizeof(buf);
|
buflen = sizeof(buf);
|
||||||
if ((res = uncompress(buf, &buflen, cbuf, datalen)) != Z_OK) {
|
if ((ping = uncompress(buf, &buflen, cbuf, datalen)) != Z_OK) {
|
||||||
DEBUG(1, "Uncompress failed (%d) for data len %" L "u: reassembled data corrupted or incomplete!", res, datalen);
|
DEBUG(1, "Uncompress failed (%d) for data len %" L "u: reassembled data corrupted or incomplete!", ping, datalen);
|
||||||
datalen = 0;
|
datalen = 0;
|
||||||
} else {
|
} else {
|
||||||
datalen = buflen;
|
datalen = buflen;
|
||||||
@ -1118,8 +1175,12 @@ tunnel_dns()
|
|||||||
data = cbuf;
|
data = cbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (datalen)
|
if (datalen) {
|
||||||
write_tun(this.tun_fd, data, datalen);
|
if (this.use_remote_forward)
|
||||||
|
write(STDOUT_FILENO, data, datalen);
|
||||||
|
else
|
||||||
|
write_tun(this.tun_fd, data, datalen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move window along after doing all data processing */
|
/* Move window along after doing all data processing */
|
||||||
@ -1135,7 +1196,7 @@ client_tunnel()
|
|||||||
fd_set fds;
|
fd_set fds;
|
||||||
int rv;
|
int rv;
|
||||||
int i, use_min_send;
|
int i, use_min_send;
|
||||||
int sending, total;
|
int sending, total, maxfd;
|
||||||
time_t last_stats;
|
time_t last_stats;
|
||||||
size_t sent_since_report, recv_since_report;
|
size_t sent_since_report, recv_since_report;
|
||||||
|
|
||||||
@ -1191,7 +1252,7 @@ client_tunnel()
|
|||||||
send_next_frag();
|
send_next_frag();
|
||||||
} else {
|
} else {
|
||||||
/* Send ping if we didn't send anything yet */
|
/* Send ping if we didn't send anything yet */
|
||||||
send_ping(0, this.next_downstream_ack, (this.num_pings > 20 && this.num_pings % 50 == 0));
|
send_ping(0, this.next_downstream_ack, (this.num_pings > 20 && this.num_pings % 50 == 0), 0);
|
||||||
this.next_downstream_ack = -1;
|
this.next_downstream_ack = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1260,12 +1321,20 @@ client_tunnel()
|
|||||||
}
|
}
|
||||||
|
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
if (this.conn != CONN_DNS_NULL || window_buffer_available(this.outbuf) > 16) {
|
maxfd = 0;
|
||||||
|
if (this.conn != CONN_DNS_NULL || window_buffer_available(this.outbuf) > 1) {
|
||||||
/* Fill up outgoing buffer with available data if it has enough space
|
/* Fill up outgoing buffer with available data if it has enough space
|
||||||
* The windowing protocol manages data retransmits, timeouts etc. */
|
* The windowing protocol manages data retransmits, timeouts etc. */
|
||||||
FD_SET(this.tun_fd, &fds);
|
if (this.use_remote_forward) {
|
||||||
|
FD_SET(STDIN_FILENO, &fds);
|
||||||
|
maxfd = MAX(STDIN_FILENO, maxfd);
|
||||||
|
} else {
|
||||||
|
FD_SET(this.tun_fd, &fds);
|
||||||
|
maxfd = MAX(this.tun_fd, maxfd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FD_SET(this.dns_fd, &fds);
|
FD_SET(this.dns_fd, &fds);
|
||||||
|
maxfd = MAX(this.dns_fd, maxfd);
|
||||||
|
|
||||||
DEBUG(4, "Waiting %ld ms before sending more... (min_send %d)", timeval_to_ms(&tv), use_min_send);
|
DEBUG(4, "Waiting %ld ms before sending more... (min_send %d)", timeval_to_ms(&tv), use_min_send);
|
||||||
|
|
||||||
@ -1273,7 +1342,7 @@ client_tunnel()
|
|||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
i = select(MAX(this.tun_fd, this.dns_fd) + 1, &fds, NULL, NULL, &tv);
|
i = select(maxfd + 1, &fds, NULL, NULL, &tv);
|
||||||
|
|
||||||
if (use_min_send && i > 0) {
|
if (use_min_send && i > 0) {
|
||||||
/* enforce min_send_interval if we get interrupted by new tun data */
|
/* enforce min_send_interval if we get interrupted by new tun data */
|
||||||
@ -1299,7 +1368,7 @@ client_tunnel()
|
|||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
/* timed out - no new packets recv'd */
|
/* timed out - no new packets recv'd */
|
||||||
} else {
|
} else {
|
||||||
if (FD_ISSET(this.tun_fd, &fds)) {
|
if (!this.use_remote_forward && FD_ISSET(this.tun_fd, &fds)) {
|
||||||
if (tunnel_tun() <= 0)
|
if (tunnel_tun() <= 0)
|
||||||
continue;
|
continue;
|
||||||
/* Returns -1 on error OR when quickly
|
/* Returns -1 on error OR when quickly
|
||||||
@ -1307,11 +1376,22 @@ client_tunnel()
|
|||||||
we need to _not_ do tunnel_dns() then.
|
we need to _not_ do tunnel_dns() then.
|
||||||
If chunk sent, sets this.send_ping_soon=0. */
|
If chunk sent, sets this.send_ping_soon=0. */
|
||||||
}
|
}
|
||||||
|
if (this.use_remote_forward && FD_ISSET(STDIN_FILENO, &fds)) {
|
||||||
|
if (tunnel_stdin() <= 0) {
|
||||||
|
fprintf(stderr, "server: closing remote TCP forward connection\n");
|
||||||
|
/* send ping to disconnect, don't care if it comes back */
|
||||||
|
send_ping(0, 0, 0, 1);
|
||||||
|
this.running = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (FD_ISSET(this.dns_fd, &fds)) {
|
if (FD_ISSET(this.dns_fd, &fds)) {
|
||||||
tunnel_dns();
|
tunnel_dns();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.running == 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
@ -1369,6 +1449,7 @@ send_version(uint32_t version)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
send_login(char *login, int len)
|
send_login(char *login, int len)
|
||||||
|
/* Send DNS login packet. See doc/proto_xxxxxxxx.txt for details */
|
||||||
{
|
{
|
||||||
uint8_t flags = 0, data[100];
|
uint8_t flags = 0, data[100];
|
||||||
int length = 17, addrlen = 0;
|
int length = 17, addrlen = 0;
|
||||||
@ -1379,7 +1460,9 @@ send_login(char *login, int len)
|
|||||||
|
|
||||||
memcpy(data + 1, login, 16);
|
memcpy(data + 1, login, 16);
|
||||||
|
|
||||||
if (this.remote_forward_addr.ss_family != AF_UNSPEC) {
|
/* if remote forward address is specified and not currently connecting */
|
||||||
|
if (this.remote_forward_connected != 2 &&
|
||||||
|
this.remote_forward_addr.ss_family != AF_UNSPEC) {
|
||||||
struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &this.remote_forward_addr;
|
struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &this.remote_forward_addr;
|
||||||
struct sockaddr_in *s = (struct sockaddr_in *) &this.remote_forward_addr;
|
struct sockaddr_in *s = (struct sockaddr_in *) &this.remote_forward_addr;
|
||||||
|
|
||||||
@ -1405,6 +1488,10 @@ send_login(char *login, int len)
|
|||||||
}
|
}
|
||||||
DEBUG(2, "Sending TCP forward login request: port %hu, length %d, addrlen %d",
|
DEBUG(2, "Sending TCP forward login request: port %hu, length %d, addrlen %d",
|
||||||
port, length, addrlen);
|
port, length, addrlen);
|
||||||
|
} else if (this.remote_forward_connected == 2) {
|
||||||
|
/* remote TCP forward connection in progress */
|
||||||
|
DEBUG(2, "Sending TCP forward login/poll request to check connection status.");
|
||||||
|
flags |= (1 << 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
data[0] = flags;
|
data[0] = flags;
|
||||||
@ -1538,7 +1625,7 @@ static int
|
|||||||
handshake_login(int seed)
|
handshake_login(int seed)
|
||||||
{
|
{
|
||||||
char in[4096], login[16], server[65], client[65], flag;
|
char in[4096], login[16], server[65], client[65], flag;
|
||||||
int mtu, read;
|
int mtu, netmask, read, numwaiting = 0;
|
||||||
|
|
||||||
login_calculate(login, 16, this.password, seed);
|
login_calculate(login, 16, this.password, seed);
|
||||||
|
|
||||||
@ -1550,31 +1637,84 @@ handshake_login(int seed)
|
|||||||
in[MIN(read, sizeof(in))] = 0; /* Null terminate */
|
in[MIN(read, sizeof(in))] = 0; /* Null terminate */
|
||||||
|
|
||||||
if (read > 0) {
|
if (read > 0) {
|
||||||
int netmask;
|
|
||||||
if (strncmp("LNAK", in, 4) == 0) {
|
if (strncmp("LNAK", in, 4) == 0) {
|
||||||
fprintf(stderr, "Bad password\n");
|
fprintf(stderr, "Bad password\n");
|
||||||
return 1;
|
return 1;
|
||||||
} else if (sscanf(in, "%c-%64[^-]-%64[^-]-%d-%d",
|
/* not reached */
|
||||||
&flag, server, client, &mtu, &netmask) == 4) {
|
|
||||||
|
|
||||||
server[64] = 0;
|
|
||||||
client[64] = 0;
|
|
||||||
if (tun_setip(client, server, netmask) == 0 &&
|
|
||||||
tun_setmtu(mtu) == 0) {
|
|
||||||
|
|
||||||
fprintf(stderr, "Server tunnel IP is %s\n", server);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
errx(4, "Failed to set IP and MTU");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Received bad handshake: %.*s\n", read, in);
|
|
||||||
}
|
}
|
||||||
|
flag = toupper(in[0]);
|
||||||
|
|
||||||
|
switch (flag) {
|
||||||
|
case 'I':
|
||||||
|
if (sscanf(in, "%c-%64[^-]-%64[^-]-%d-%d",
|
||||||
|
&flag, server, client, &mtu, &netmask) == 5) {
|
||||||
|
|
||||||
|
server[64] = 0;
|
||||||
|
client[64] = 0;
|
||||||
|
if (tun_setip(client, server, netmask) == 0 &&
|
||||||
|
tun_setmtu(mtu) == 0) {
|
||||||
|
|
||||||
|
fprintf(stderr, "Server tunnel IP is %s\n", server);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
errx(4, "Failed to set IP and MTU");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
goto bad_handshake;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
if (!this.use_remote_forward) {
|
||||||
|
goto bad_handshake;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.remote_forward_connected = 1;
|
||||||
|
fprintf(stderr, " done.");
|
||||||
|
return 0;
|
||||||
|
case 'W':
|
||||||
|
if (!this.use_remote_forward || this.remote_forward_connected == 1) {
|
||||||
|
goto bad_handshake;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.remote_forward_connected = 2;
|
||||||
|
|
||||||
|
if (numwaiting == 0)
|
||||||
|
fprintf(stderr, "server: Opening Remote TCP forward.\n");
|
||||||
|
else
|
||||||
|
fprintf(stderr, "%.*s", numwaiting, "...............");
|
||||||
|
|
||||||
|
numwaiting ++;
|
||||||
|
|
||||||
|
/* wait a while before re-polling server, max 5 tries (14 seconds) */
|
||||||
|
if (numwaiting > 1)
|
||||||
|
sleep(numwaiting);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
case 'E':
|
||||||
|
if (!this.use_remote_forward)
|
||||||
|
goto bad_handshake;
|
||||||
|
|
||||||
|
char errormsg[100];
|
||||||
|
strncpy(errormsg, in + 1, MIN(read, sizeof(errormsg)));
|
||||||
|
errormsg[99] = 0;
|
||||||
|
fprintf(stderr, "server: Remote TCP forward connection failed: %s\n", errormsg);
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
/* undefined flag */
|
||||||
|
bad_handshake:
|
||||||
|
fprintf(stderr, "Received bad handshake: %.*s\n", read, in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Retrying login...\n");
|
fprintf(stderr, "Retrying login...\n");
|
||||||
}
|
}
|
||||||
warnx("couldn't login to server");
|
if (numwaiting != 0)
|
||||||
|
warnx("Remote TCP forward connection timed out after 5 tries.");
|
||||||
|
else
|
||||||
|
warnx("couldn't login to server");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2424,7 +2564,7 @@ handshake_set_timeout()
|
|||||||
for (int i = 0; this.running && i < 5; i++) {
|
for (int i = 0; this.running && i < 5; i++) {
|
||||||
|
|
||||||
id = this.autodetect_server_timeout ?
|
id = this.autodetect_server_timeout ?
|
||||||
update_server_timeout(1) : send_ping(1, -1, 1);
|
update_server_timeout(1) : send_ping(1, -1, 1, 0);
|
||||||
|
|
||||||
read = handshake_waitdns(in, sizeof(in), 'P', i + 1);
|
read = handshake_waitdns(in, sizeof(in), 'P', i + 1);
|
||||||
got_response(id, 1, 0);
|
got_response(id, 1, 0);
|
||||||
@ -2464,13 +2604,11 @@ client_handshake()
|
|||||||
|
|
||||||
fprintf(stderr, "Using DNS type %s queries\n", client_get_qtype());
|
fprintf(stderr, "Using DNS type %s queries\n", client_get_qtype());
|
||||||
|
|
||||||
r = handshake_version(&seed);
|
if ((r = handshake_version(&seed))) {
|
||||||
if (r) {
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = handshake_login(seed);
|
if ((r = handshake_login(seed))) {
|
||||||
if (r) {
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2479,6 +2617,9 @@ client_handshake()
|
|||||||
this.max_timeout_ms = 10000;
|
this.max_timeout_ms = 10000;
|
||||||
this.compression_down = 1;
|
this.compression_down = 1;
|
||||||
this.compression_up = 1;
|
this.compression_up = 1;
|
||||||
|
if (this.use_remote_forward)
|
||||||
|
fprintf(stderr, "Warning: Remote TCP forwards over Raw (UDP) mode may be unreliable.\n"
|
||||||
|
" If forwarded connections are unstable, try using '-r' to force DNS tunnelling mode.\n");
|
||||||
} else {
|
} else {
|
||||||
if (this.raw_mode == 0) {
|
if (this.raw_mode == 0) {
|
||||||
fprintf(stderr, "Skipping raw mode\n");
|
fprintf(stderr, "Skipping raw mode\n");
|
||||||
|
@ -47,6 +47,7 @@ struct client_instance {
|
|||||||
/* Remote TCP forwarding stuff (for -R) */
|
/* Remote TCP forwarding stuff (for -R) */
|
||||||
struct sockaddr_storage remote_forward_addr;
|
struct sockaddr_storage remote_forward_addr;
|
||||||
int use_remote_forward; /* 0 if no forwarding used */
|
int use_remote_forward; /* 0 if no forwarding used */
|
||||||
|
int remote_forward_connected;
|
||||||
|
|
||||||
int tun_fd;
|
int tun_fd;
|
||||||
int dns_fd;
|
int dns_fd;
|
||||||
@ -160,9 +161,9 @@ void client_set_hostname_maxlen(size_t i);
|
|||||||
int client_handshake();
|
int client_handshake();
|
||||||
int client_tunnel();
|
int client_tunnel();
|
||||||
|
|
||||||
int parse_data(uint8_t *data, size_t len, fragment *f, int *immediate);
|
int parse_data(uint8_t *data, size_t len, fragment *f, int *immediate, int*);
|
||||||
int handshake_waitdns(char *buf, size_t buflen, char cmd, int timeout);
|
int handshake_waitdns(char *buf, size_t buflen, char cmd, int timeout);
|
||||||
void handshake_switch_options(int lazy, int compression, char denc);
|
void handshake_switch_options(int lazy, int compression, char denc);
|
||||||
int send_ping(int ping_response, int ack, int timeout);
|
int send_ping(int ping_response, int ack, int timeout, int);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
15
src/common.c
15
src/common.c
@ -228,9 +228,15 @@ open_dns_from_host(char *host, int port, int addr_family, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
close_dns(int fd)
|
close_socket(int fd)
|
||||||
{
|
{
|
||||||
|
if (fd <= 0)
|
||||||
|
return;
|
||||||
|
#ifdef WINDOWS32
|
||||||
|
closesocket(fd);
|
||||||
|
#else
|
||||||
close(fd);
|
close(fd);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -411,7 +417,7 @@ socket_set_blocking(int fd, int blocking)
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fcntl(fd, F_SETFL, blocking ? (flags | O_NONBLOCK) : (flags & (~O_NONBLOCK))) == -1)
|
if (fcntl(fd, F_SETFL, !blocking ? (flags | O_NONBLOCK) : (flags & (~O_NONBLOCK))) == -1)
|
||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -442,11 +448,14 @@ open_tcp_nonblocking(struct sockaddr_storage *addr, char **errormsg)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (errormsg)
|
||||||
|
*errormsg = strerror(errno);
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
check_tcp_status(int fd, char **error)
|
check_tcp_error(int fd, char **error)
|
||||||
/* checks connected status of given socket.
|
/* checks connected status of given socket.
|
||||||
* returns error code. 0 if connected or EINPROGRESS if connecting */
|
* returns error code. 0 if connected or EINPROGRESS if connecting */
|
||||||
{
|
{
|
||||||
|
@ -159,10 +159,10 @@ int get_addr(char *, int, int, int, struct sockaddr_storage *);
|
|||||||
int open_dns(struct sockaddr_storage *, size_t);
|
int open_dns(struct sockaddr_storage *, size_t);
|
||||||
int open_dns_opt(struct sockaddr_storage *sockaddr, size_t sockaddr_len, int v6only);
|
int open_dns_opt(struct sockaddr_storage *sockaddr, size_t sockaddr_len, int v6only);
|
||||||
int open_dns_from_host(char *host, int port, int addr_family, int flags);
|
int open_dns_from_host(char *host, int port, int addr_family, int flags);
|
||||||
void close_dns(int);
|
void close_socket(int);
|
||||||
|
|
||||||
int open_tcp_nonblocking(struct sockaddr_storage *addr, char **error);
|
int open_tcp_nonblocking(struct sockaddr_storage *addr, char **error);
|
||||||
int check_tcp_status(int fd, char **error);
|
int check_tcp_error(int fd, char **error);
|
||||||
|
|
||||||
void do_chroot(char *);
|
void do_chroot(char *);
|
||||||
void do_setcon(char *);
|
void do_setcon(char *);
|
||||||
|
54
src/iodine.c
54
src/iodine.c
@ -304,23 +304,23 @@ version()
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parse_tcp_forward_option()
|
parse_tcp_forward_option(char *optstr)
|
||||||
{
|
{
|
||||||
char *remote_port_str, *remote_host_str;
|
char *remote_port_str, *remote_host_str;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (strrchr(optarg, ':')) {
|
if (strrchr(optstr, ':')) {
|
||||||
remote_port_str = strrchr(optarg, ':') + 1;
|
remote_port_str = strrchr(optstr, ':') + 1;
|
||||||
if (optarg[0] == '[') {
|
if (optstr[0] == '[') {
|
||||||
/* IPv6 address enclosed in square brackets */
|
/* IPv6 address enclosed in square brackets */
|
||||||
remote_host_str = optarg + 1;
|
remote_host_str = optstr + 1;
|
||||||
/* replace closing bracket with null terminator */
|
/* replace closing bracket with null terminator */
|
||||||
*strchr(remote_host_str, ']') = 0;
|
*strchr(remote_host_str, ']') = 0;
|
||||||
this.remote_forward_addr.ss_family = AF_INET6;
|
this.remote_forward_addr.ss_family = AF_INET6;
|
||||||
retval = inet_pton(AF_INET6, remote_host_str,
|
retval = inet_pton(AF_INET6, remote_host_str,
|
||||||
&((struct sockaddr_in6 *) &this.remote_forward_addr)->sin6_addr);
|
&((struct sockaddr_in6 *) &this.remote_forward_addr)->sin6_addr);
|
||||||
} else {
|
} else {
|
||||||
remote_host_str = optarg;
|
remote_host_str = optstr;
|
||||||
/* replace separator with null terminator */
|
/* replace separator with null terminator */
|
||||||
*strchr(remote_host_str, ':') = 0;
|
*strchr(remote_host_str, ':') = 0;
|
||||||
this.remote_forward_addr.ss_family = AF_INET;
|
this.remote_forward_addr.ss_family = AF_INET;
|
||||||
@ -328,14 +328,15 @@ parse_tcp_forward_option()
|
|||||||
&((struct sockaddr_in *) &this.remote_forward_addr)->sin_addr);
|
&((struct sockaddr_in *) &this.remote_forward_addr)->sin_addr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* no address specified (use server localhost IPv4), optarg is port */
|
/* no address specified (use server localhost IPv4), optstr is port */
|
||||||
remote_port_str = optarg;
|
remote_port_str = optstr;
|
||||||
this.remote_forward_addr.ss_family = AF_INET;
|
this.remote_forward_addr.ss_family = AF_INET;
|
||||||
((struct sockaddr_in *) &this.remote_forward_addr)->sin_addr.s_addr = INADDR_LOOPBACK;
|
((struct sockaddr_in *) &this.remote_forward_addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
retval = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retval <= 0) {
|
if (!retval) {
|
||||||
errx(12, "Invalid remote forward address (-R)! Must be [host:]port,\n"
|
warnx("Invalid remote forward address (-R)! Must be [host:]port,\n"
|
||||||
"where IPv6 addresses are enclosed in literal square brackets [].");
|
"where IPv6 addresses are enclosed in literal square brackets [].");
|
||||||
usage();
|
usage();
|
||||||
/* not reached */
|
/* not reached */
|
||||||
@ -351,10 +352,10 @@ parse_tcp_forward_option()
|
|||||||
|
|
||||||
if (this.remote_forward_addr.ss_family == AF_INET) {
|
if (this.remote_forward_addr.ss_family == AF_INET) {
|
||||||
/* set port as sockaddr_in (IPv4) */
|
/* set port as sockaddr_in (IPv4) */
|
||||||
((struct sockaddr_in *) &this.remote_forward_addr)->sin_port = port;
|
((struct sockaddr_in *) &this.remote_forward_addr)->sin_port = htons(port);
|
||||||
} else {
|
} else {
|
||||||
/* set port in IPv6 sockaddr */
|
/* set port in IPv6 sockaddr */
|
||||||
((struct sockaddr_in6 *) &this.remote_forward_addr)->sin6_port = port;
|
((struct sockaddr_in6 *) &this.remote_forward_addr)->sin6_port = htons(port);
|
||||||
}
|
}
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
@ -510,7 +511,7 @@ main(int argc, char **argv)
|
|||||||
/* Argument format: [host:]port */
|
/* Argument format: [host:]port */
|
||||||
if (!optarg) break;
|
if (!optarg) break;
|
||||||
this.use_remote_forward = 1;
|
this.use_remote_forward = 1;
|
||||||
remote_forward_port = parse_tcp_forward_option();
|
remote_forward_port = parse_tcp_forward_option(optarg);
|
||||||
break;
|
break;
|
||||||
case OPT_NODROP:
|
case OPT_NODROP:
|
||||||
// TODO implement TCP-over-tun optimisations
|
// TODO implement TCP-over-tun optimisations
|
||||||
@ -711,13 +712,16 @@ main(int argc, char **argv)
|
|||||||
read_password(this.password, sizeof(this.password));
|
read_password(this.password, sizeof(this.password));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((this.tun_fd = open_tun(device)) == -1) {
|
if (!this.use_remote_forward) {
|
||||||
retval = 1;
|
if ((this.tun_fd = open_tun(device)) == -1) {
|
||||||
goto cleanup1;
|
retval = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((this.dns_fd = open_dns_from_host(NULL, 0, nameservaddr.ss_family, AI_PASSIVE)) < 0) {
|
if ((this.dns_fd = open_dns_from_host(NULL, 0, nameservaddr.ss_family, AI_PASSIVE)) < 0) {
|
||||||
retval = 1;
|
retval = 1;
|
||||||
goto cleanup2;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
#ifdef OPENBSD
|
#ifdef OPENBSD
|
||||||
if (rtable > 0)
|
if (rtable > 0)
|
||||||
@ -739,7 +743,7 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
if (client_handshake()) {
|
if (client_handshake()) {
|
||||||
retval = 1;
|
retval = 1;
|
||||||
goto cleanup2;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.conn == CONN_RAW_UDP) {
|
if (this.conn == CONN_RAW_UDP) {
|
||||||
@ -774,10 +778,14 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
client_tunnel();
|
client_tunnel();
|
||||||
|
|
||||||
cleanup2:
|
cleanup:
|
||||||
close_dns(this.dns_fd);
|
if (this.use_remote_forward)
|
||||||
close_tun(this.tun_fd);
|
close(STDOUT_FILENO);
|
||||||
cleanup1:
|
close_socket(this.dns_fd);
|
||||||
|
close_socket(this.tun_fd);
|
||||||
|
#ifdef WINDOWS32
|
||||||
|
WSACleanup();
|
||||||
|
#endif
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -636,13 +636,15 @@ main(int argc, char **argv)
|
|||||||
server_tunnel();
|
server_tunnel();
|
||||||
|
|
||||||
syslog(LOG_INFO, "stopping");
|
syslog(LOG_INFO, "stopping");
|
||||||
close_dns(server.bind_fd);
|
close_socket(server.bind_fd);
|
||||||
cleanup:
|
cleanup:
|
||||||
if (server.dns_fds.v6fd >= 0)
|
close_socket(server.dns_fds.v6fd);
|
||||||
close_dns(server.dns_fds.v6fd);
|
close_socket(server.dns_fds.v4fd);
|
||||||
if (server.dns_fds.v4fd >= 0)
|
close_socket(server.tun_fd);
|
||||||
close_dns(server.dns_fds.v4fd);
|
#ifdef WINDOWS32
|
||||||
close_tun(server.tun_fd);
|
WSACleanup();
|
||||||
|
#endif
|
||||||
|
/* TODO close user TCP forward sockets */
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
248
src/server.c
248
src/server.c
@ -318,7 +318,7 @@ qmem_max_wait(int *touser, struct query **sendq)
|
|||||||
QMEM_DEBUG(4, userid, "ANSWER q id %d, ACK %d; sent %" L "u of %" L "u + sending another %" L "u",
|
QMEM_DEBUG(4, userid, "ANSWER q id %d, ACK %d; sent %" L "u of %" L "u + sending another %" L "u",
|
||||||
q->id, u->next_upstream_ack, sent, total, sending);
|
q->id, u->next_upstream_ack, sent, total, sending);
|
||||||
|
|
||||||
send_data_or_ping(userid, q, 0, immediate);
|
send_data_or_ping(userid, q, 0, immediate, NULL);
|
||||||
|
|
||||||
if (sending > 0)
|
if (sending > 0)
|
||||||
sending--;
|
sending--;
|
||||||
@ -428,14 +428,15 @@ send_version_response(int fd, version_ack_t ack, uint32_t payload, int userid, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
send_data_or_ping(int userid, struct query *q, int ping, int immediate)
|
send_data_or_ping(int userid, struct query *q, int ping, int immediate, char *tcperror)
|
||||||
/* Sends current fragment to user, or a ping if no data available.
|
/* Sends current fragment to user, or a ping if no data available.
|
||||||
ping: 1=force send ping (even if data available), 0=only send if no data.
|
ping: 1=force send ping (even if data available), 0=only send if no data.
|
||||||
immediate: 1=not from qmem (ie. fresh query), 0=query is from qmem */
|
immediate: 1=not from qmem (ie. fresh query), 0=query is from qmem
|
||||||
|
disconnect: whether to tell user that TCP socket is closed (NULL if OK or pointer to error message) */
|
||||||
{
|
{
|
||||||
uint8_t pkt[MAX_FRAGSIZE + DOWNSTREAM_PING_HDR];
|
uint8_t pkt[MAX_FRAGSIZE + DOWNSTREAM_PING_HDR];
|
||||||
size_t datalen, headerlen;
|
size_t datalen, headerlen;
|
||||||
fragment *f;
|
fragment *f = NULL;
|
||||||
struct frag_buffer *out, *in;
|
struct frag_buffer *out, *in;
|
||||||
|
|
||||||
in = users[userid].incoming;
|
in = users[userid].incoming;
|
||||||
@ -443,7 +444,21 @@ send_data_or_ping(int userid, struct query *q, int ping, int immediate)
|
|||||||
|
|
||||||
window_tick(out);
|
window_tick(out);
|
||||||
|
|
||||||
f = window_get_next_sending_fragment(out, &users[userid].next_upstream_ack);
|
if (!tcperror) {
|
||||||
|
f = window_get_next_sending_fragment(out, &users[userid].next_upstream_ack);
|
||||||
|
} else {
|
||||||
|
/* construct fake fragment containing error message. */
|
||||||
|
fragment fr;
|
||||||
|
f = &fr;
|
||||||
|
memset(f, 0, sizeof(fragment));
|
||||||
|
f->ack_other = -1;
|
||||||
|
f->len = strlen(tcperror);
|
||||||
|
memcpy(f->data, tcperror, f->len);
|
||||||
|
f->data[f->len] = 0;
|
||||||
|
f->start = 1;
|
||||||
|
f->end = 1;
|
||||||
|
DEBUG(2, "Sending ping with TCP forward disconnect; error: %s", f->data);
|
||||||
|
}
|
||||||
|
|
||||||
/* Build downstream data/ping header (see doc/proto_xxxxxxxx.txt) for details */
|
/* Build downstream data/ping header (see doc/proto_xxxxxxxx.txt) for details */
|
||||||
if (!f) {
|
if (!f) {
|
||||||
@ -464,6 +479,8 @@ send_data_or_ping(int userid, struct query *q, int ping, int immediate)
|
|||||||
|
|
||||||
/* If this is being responded to immediately (ie. not from qmem) */
|
/* If this is being responded to immediately (ie. not from qmem) */
|
||||||
pkt[2] |= (immediate & 1) << 5;
|
pkt[2] |= (immediate & 1) << 5;
|
||||||
|
if (tcperror)
|
||||||
|
pkt[2] |= (1 << 6);
|
||||||
|
|
||||||
if (ping) {
|
if (ping) {
|
||||||
/* set ping flag and build extra header */
|
/* set ping flag and build extra header */
|
||||||
@ -556,6 +573,23 @@ user_send_data(int userid, uint8_t *indata, size_t len, int compressed)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
user_send_tcp_disconnect(int userid, struct query *q, char *errormsg)
|
||||||
|
/* tell user that TCP socket has been disconnected */
|
||||||
|
{
|
||||||
|
users[userid].remote_forward_connected = -1;
|
||||||
|
close_socket(users[userid].remote_tcp_fd);
|
||||||
|
if (q == NULL)
|
||||||
|
q = qmem_get_next_response(userid);
|
||||||
|
if (q != NULL) {
|
||||||
|
send_data_or_ping(userid, q, 1, 0, errormsg);
|
||||||
|
users[userid].active = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
users[userid].active = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
tunnel_bind()
|
tunnel_bind()
|
||||||
{
|
{
|
||||||
@ -597,6 +631,37 @@ tunnel_bind()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
tunnel_tcp(int userid)
|
||||||
|
{
|
||||||
|
ssize_t len;
|
||||||
|
uint8_t buf[64*1024];
|
||||||
|
char *errormsg = NULL;
|
||||||
|
|
||||||
|
if (users[userid].remote_forward_connected != 1) {
|
||||||
|
DEBUG(2, "tunnel_tcp: user %d TCP socket not connected!", userid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = read(users[userid].remote_tcp_fd, buf, sizeof(buf));
|
||||||
|
|
||||||
|
DEBUG(5, "read %ld bytes on TCP", len);
|
||||||
|
if (len == 0) {
|
||||||
|
DEBUG(1, "EOF on TCP forward for user %d; closing connection.", userid);
|
||||||
|
errormsg = "Connection closed by remote host.";
|
||||||
|
user_send_tcp_disconnect(userid, NULL, errormsg);
|
||||||
|
return -1;
|
||||||
|
} else if (len < 0) {
|
||||||
|
errormsg = strerror(errno);
|
||||||
|
DEBUG(1, "Error %d on TCP forward for user %d: %s", errno, userid, errormsg);
|
||||||
|
user_send_tcp_disconnect(userid, NULL, errormsg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
user_send_data(userid, buf, (size_t) len, 0);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
tunnel_tun()
|
tunnel_tun()
|
||||||
{
|
{
|
||||||
@ -696,7 +761,7 @@ int
|
|||||||
server_tunnel()
|
server_tunnel()
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
fd_set fds;
|
fd_set read_fds, write_fds;
|
||||||
int i;
|
int i;
|
||||||
int userid;
|
int userid;
|
||||||
struct query *answer_now = NULL;
|
struct query *answer_now = NULL;
|
||||||
@ -710,31 +775,38 @@ server_tunnel()
|
|||||||
/* max wait time based on pending queries */
|
/* max wait time based on pending queries */
|
||||||
tv = qmem_max_wait(&userid, &answer_now);
|
tv = qmem_max_wait(&userid, &answer_now);
|
||||||
|
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&read_fds);
|
||||||
|
FD_ZERO(&write_fds);
|
||||||
maxfd = 0;
|
maxfd = 0;
|
||||||
|
|
||||||
if (server.dns_fds.v4fd >= 0) {
|
if (server.dns_fds.v4fd >= 0) {
|
||||||
FD_SET(server.dns_fds.v4fd, &fds);
|
FD_SET(server.dns_fds.v4fd, &read_fds);
|
||||||
maxfd = MAX(server.dns_fds.v4fd, maxfd);
|
maxfd = MAX(server.dns_fds.v4fd, maxfd);
|
||||||
}
|
}
|
||||||
if (server.dns_fds.v6fd >= 0) {
|
if (server.dns_fds.v6fd >= 0) {
|
||||||
FD_SET(server.dns_fds.v6fd, &fds);
|
FD_SET(server.dns_fds.v6fd, &read_fds);
|
||||||
maxfd = MAX(server.dns_fds.v6fd, maxfd);
|
maxfd = MAX(server.dns_fds.v6fd, maxfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server.bind_fd) {
|
if (server.bind_fd) {
|
||||||
/* wait for replies from real DNS */
|
/* wait for replies from real DNS */
|
||||||
FD_SET(server.bind_fd, &fds);
|
FD_SET(server.bind_fd, &read_fds);
|
||||||
maxfd = MAX(server.bind_fd, maxfd);
|
maxfd = MAX(server.bind_fd, maxfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't read from tun if all users have filled outpacket queues */
|
/* Don't read from tun if all users have filled outpacket queues */
|
||||||
if(!all_users_waiting_to_send()) {
|
if(!all_users_waiting_to_send()) {
|
||||||
FD_SET(server.tun_fd, &fds);
|
FD_SET(server.tun_fd, &read_fds);
|
||||||
maxfd = MAX(server.tun_fd, maxfd);
|
maxfd = MAX(server.tun_fd, maxfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
i = select(maxfd + 1, &fds, NULL, NULL, &tv);
|
/* add connected user TCP forward FDs to read set */
|
||||||
|
maxfd = MAX(set_user_tcp_fds(&read_fds, 1), maxfd);
|
||||||
|
|
||||||
|
/* add connectING user TCP FDs to write set */
|
||||||
|
maxfd = MAX(set_user_tcp_fds(&write_fds, 2), maxfd);
|
||||||
|
|
||||||
|
i = select(maxfd + 1, &read_fds, &write_fds, NULL, &tv);
|
||||||
|
|
||||||
if(i < 0) {
|
if(i < 0) {
|
||||||
if (server.running)
|
if (server.running)
|
||||||
@ -757,16 +829,29 @@ server_tunnel()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (FD_ISSET(server.tun_fd, &fds)) {
|
if (FD_ISSET(server.tun_fd, &read_fds)) {
|
||||||
tunnel_tun();
|
tunnel_tun();
|
||||||
}
|
}
|
||||||
if (FD_ISSET(server.dns_fds.v4fd, &fds)) {
|
|
||||||
|
for (userid = 0; userid < created_users; userid++) {
|
||||||
|
if (FD_ISSET(users[userid].remote_tcp_fd, &read_fds) && users[userid].remoteforward_addr_len > 0) {
|
||||||
|
DEBUG(4, "tunnel_tcp called for user %d", userid);
|
||||||
|
tunnel_tcp(userid);
|
||||||
|
} else if (users[userid].remote_forward_connected == 2 &&
|
||||||
|
FD_ISSET(users[userid].remote_tcp_fd, &write_fds)) {
|
||||||
|
DEBUG(2, "User %d TCP socket now writable (connection established)", userid);
|
||||||
|
users[userid].remote_forward_connected = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET(server.dns_fds.v4fd, &read_fds)) {
|
||||||
tunnel_dns(server.dns_fds.v4fd);
|
tunnel_dns(server.dns_fds.v4fd);
|
||||||
}
|
}
|
||||||
if (FD_ISSET(server.dns_fds.v6fd, &fds)) {
|
if (FD_ISSET(server.dns_fds.v6fd, &read_fds)) {
|
||||||
tunnel_dns(server.dns_fds.v6fd);
|
tunnel_dns(server.dns_fds.v6fd);
|
||||||
}
|
}
|
||||||
if (FD_ISSET(server.bind_fd, &fds)) {
|
|
||||||
|
if (FD_ISSET(server.bind_fd, &read_fds)) {
|
||||||
tunnel_bind();
|
tunnel_bind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -781,7 +866,7 @@ handle_full_packet(int userid, uint8_t *data, size_t len, int compressed)
|
|||||||
size_t rawlen;
|
size_t rawlen;
|
||||||
uint8_t out[64*1024], *rawdata;
|
uint8_t out[64*1024], *rawdata;
|
||||||
struct ip *hdr;
|
struct ip *hdr;
|
||||||
int touser;
|
int touser = -1;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Check if data needs to be uncompressed */
|
/* Check if data needs to be uncompressed */
|
||||||
@ -796,20 +881,28 @@ handle_full_packet(int userid, uint8_t *data, size_t len, int compressed)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ret == Z_OK) {
|
if (ret == Z_OK) {
|
||||||
hdr = (struct ip*) (out + 4);
|
if (users[userid].remoteforward_addr_len == 0) {
|
||||||
touser = find_user_by_ip(hdr->ip_dst.s_addr);
|
hdr = (struct ip*) (out + 4);
|
||||||
DEBUG(2, "FULL PKT: %" L "u bytes from user %d (touser %d)", len, userid, touser);
|
touser = find_user_by_ip(hdr->ip_dst.s_addr);
|
||||||
if (touser == -1) {
|
DEBUG(2, "FULL PKT: %" L "u bytes from user %d (touser %d)", len, userid, touser);
|
||||||
/* send the uncompressed packet to tun device */
|
if (touser == -1) {
|
||||||
write_tun(server.tun_fd, rawdata, rawlen);
|
/* send the uncompressed packet to tun device */
|
||||||
} else {
|
write_tun(server.tun_fd, rawdata, rawlen);
|
||||||
/* don't re-compress if possible */
|
|
||||||
if (users[touser].down_compression && compressed) {
|
|
||||||
user_send_data(touser, data, len, 1);
|
|
||||||
} else {
|
} else {
|
||||||
user_send_data(touser, rawdata, rawlen, 0);
|
/* don't re-compress if possible */
|
||||||
|
if (users[touser].down_compression && compressed) {
|
||||||
|
user_send_data(touser, data, len, 1);
|
||||||
|
} else {
|
||||||
|
user_send_data(touser, rawdata, rawlen, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Write full pkt to user's remote forward TCP stream */
|
||||||
|
if ((ret = write(users[userid].remote_tcp_fd, rawdata, rawlen)) != rawlen) {
|
||||||
|
DEBUG(2, "Write error %d on TCP socket for user %d: %s", errno, userid, strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG(2, "Discarded upstream data from user %d, uncompress() result: %d", userid, ret);
|
DEBUG(2, "Discarded upstream data from user %d, uncompress() result: %d", userid, ret);
|
||||||
}
|
}
|
||||||
@ -1170,6 +1263,7 @@ handle_dns_version(int dns_fd, struct query *q, uint8_t *domain, int domain_len)
|
|||||||
u->hostlen = q->fromlen;
|
u->hostlen = q->fromlen;
|
||||||
u->remote_forward_connected = 0;
|
u->remote_forward_connected = 0;
|
||||||
u->remoteforward_addr_len = 0;
|
u->remoteforward_addr_len = 0;
|
||||||
|
u->remote_tcp_fd = 0;
|
||||||
u->remoteforward_addr.ss_family = AF_UNSPEC;
|
u->remoteforward_addr.ss_family = AF_UNSPEC;
|
||||||
u->fragsize = 100; /* very safe */
|
u->fragsize = 100; /* very safe */
|
||||||
u->conn = CONN_DNS_NULL;
|
u->conn = CONN_DNS_NULL;
|
||||||
@ -1250,7 +1344,7 @@ handle_dns_login(int dns_fd, struct query *q, uint8_t *domain, int domain_len, i
|
|||||||
{
|
{
|
||||||
uint8_t unpacked[512], flags;
|
uint8_t unpacked[512], flags;
|
||||||
char logindata[16], *tmp[2], out[512], *reason = NULL;
|
char logindata[16], *tmp[2], out[512], *reason = NULL;
|
||||||
char *errormsg = NULL;
|
char *errormsg = NULL, fromaddr[100];
|
||||||
struct in_addr tempip;
|
struct in_addr tempip;
|
||||||
char remote_tcp, remote_isnt_localhost, use_ipv6, poll_status; //, drop_packets;
|
char remote_tcp, remote_isnt_localhost, use_ipv6, poll_status; //, drop_packets;
|
||||||
int length = 17, read, addrlen, login_ok = 1;
|
int length = 17, read, addrlen, login_ok = 1;
|
||||||
@ -1279,8 +1373,10 @@ handle_dns_login(int dns_fd, struct query *q, uint8_t *domain, int domain_len, i
|
|||||||
|
|
||||||
CHECK_LEN(read, length);
|
CHECK_LEN(read, length);
|
||||||
|
|
||||||
|
strncpy(fromaddr, format_addr(&q->from, q->fromlen), 100);
|
||||||
|
|
||||||
DEBUG(2, "Received login request for user %d from %s",
|
DEBUG(2, "Received login request for user %d from %s",
|
||||||
userid, format_addr(&q->from, q->fromlen));
|
userid, fromaddr);
|
||||||
|
|
||||||
DEBUG(6, "Login: length=%d, flags=0x%02x, seed=0x%08x, hash=0x%016llx%016llx",
|
DEBUG(6, "Login: length=%d, flags=0x%02x, seed=0x%08x, hash=0x%016llx%016llx",
|
||||||
length, flags, u->seed, *(unsigned long long *) (unpacked + 1),
|
length, flags, u->seed, *(unsigned long long *) (unpacked + 1),
|
||||||
@ -1289,7 +1385,7 @@ handle_dns_login(int dns_fd, struct query *q, uint8_t *domain, int domain_len, i
|
|||||||
if (check_user_and_ip(userid, q, server.check_ip) != 0) {
|
if (check_user_and_ip(userid, q, server.check_ip) != 0) {
|
||||||
write_dns(dns_fd, q, "BADIP", 5, 'T');
|
write_dns(dns_fd, q, "BADIP", 5, 'T');
|
||||||
syslog(LOG_WARNING, "rejected login request from user #%d from %s; expected source %s",
|
syslog(LOG_WARNING, "rejected login request from user #%d from %s; expected source %s",
|
||||||
userid, format_addr(&q->from, q->fromlen), format_addr(&u->host, u->hostlen));
|
userid, fromaddr, format_addr(&u->host, u->hostlen));
|
||||||
DEBUG(1, "Rejected login request from user %d: BADIP", userid);
|
DEBUG(1, "Rejected login request from user %d: BADIP", userid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1314,12 +1410,12 @@ handle_dns_login(int dns_fd, struct query *q, uint8_t *domain, int domain_len, i
|
|||||||
if (addrlen > 0) {
|
if (addrlen > 0) {
|
||||||
if (use_ipv6) {
|
if (use_ipv6) {
|
||||||
addr6->sin6_family = AF_INET6;
|
addr6->sin6_family = AF_INET6;
|
||||||
addr6->sin6_port = port;
|
addr6->sin6_port = htons(port);
|
||||||
u->remoteforward_addr_len = sizeof(*addr6);
|
u->remoteforward_addr_len = sizeof(*addr6);
|
||||||
memcpy(&addr6->sin6_addr, unpacked + 19, MIN(sizeof(*addr6), addrlen));
|
memcpy(&addr6->sin6_addr, unpacked + 19, MIN(sizeof(*addr6), addrlen));
|
||||||
} else {
|
} else {
|
||||||
addr->sin_family = AF_INET;
|
addr->sin_family = AF_INET;
|
||||||
addr->sin_port = port;
|
addr->sin_port = htons(port);
|
||||||
u->remoteforward_addr_len = sizeof(*addr);
|
u->remoteforward_addr_len = sizeof(*addr);
|
||||||
memcpy(&addr->sin_addr, unpacked + 19, MIN(sizeof(*addr), addrlen));
|
memcpy(&addr->sin_addr, unpacked + 19, MIN(sizeof(*addr), addrlen));
|
||||||
}
|
}
|
||||||
@ -1329,8 +1425,8 @@ handle_dns_login(int dns_fd, struct query *q, uint8_t *domain, int domain_len, i
|
|||||||
port, login_ok ? "allowed" : "rejected");
|
port, login_ok ? "allowed" : "rejected");
|
||||||
} else {
|
} else {
|
||||||
addr->sin_family = AF_INET;
|
addr->sin_family = AF_INET;
|
||||||
addr->sin_port = port;
|
addr->sin_port = htons(port);
|
||||||
addr->sin_addr.s_addr = INADDR_LOOPBACK;
|
addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
DEBUG(1, "User %d requested TCP connection to localhost:%hu, %s.", userid,
|
DEBUG(1, "User %d requested TCP connection to localhost:%hu, %s.", userid,
|
||||||
port, login_ok ? "allowed" : "rejected");
|
port, login_ok ? "allowed" : "rejected");
|
||||||
}
|
}
|
||||||
@ -1347,12 +1443,11 @@ handle_dns_login(int dns_fd, struct query *q, uint8_t *domain, int domain_len, i
|
|||||||
write_dns(dns_fd, q, "LNAK", 4, 'T');
|
write_dns(dns_fd, q, "LNAK", 4, 'T');
|
||||||
if (--u->authenticated >= 0)
|
if (--u->authenticated >= 0)
|
||||||
u->authenticated = -1;
|
u->authenticated = -1;
|
||||||
char *src_ip = format_addr(&q->from, q->fromlen);
|
|
||||||
int tries = abs(u->authenticated);
|
int tries = abs(u->authenticated);
|
||||||
DEBUG(1, "rejected login from user %d (%s), tries: %d, reason: %s",
|
DEBUG(1, "rejected login from user %d (%s), tries: %d, reason: %s",
|
||||||
userid, src_ip, tries, reason);
|
userid, fromaddr, tries, reason);
|
||||||
syslog(LOG_WARNING, "rejected login request from user #%d from %s, %s; incorrect attempts: %d",
|
syslog(LOG_WARNING, "rejected login request from user #%d from %s, %s; incorrect attempts: %d",
|
||||||
userid, src_ip, reason, tries);
|
userid, fromaddr, reason, tries);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1360,13 +1455,13 @@ handle_dns_login(int dns_fd, struct query *q, uint8_t *domain, int domain_len, i
|
|||||||
u->authenticated++;
|
u->authenticated++;
|
||||||
if (u->authenticated > 1 && !poll_status)
|
if (u->authenticated > 1 && !poll_status)
|
||||||
syslog(LOG_WARNING, "duplicate login request from user #%d from %s",
|
syslog(LOG_WARNING, "duplicate login request from user #%d from %s",
|
||||||
userid, format_addr(&u->host, u->hostlen));
|
userid, fromaddr);
|
||||||
|
|
||||||
if (remote_tcp) {
|
if (remote_tcp) {
|
||||||
int tcp_fd;
|
int tcp_fd;
|
||||||
|
|
||||||
DEBUG(1, "User %d connected from %s, starting TCP connection to %s.", userid,
|
DEBUG(1, "User %d connected from %s, starting TCP connection to %s.", userid,
|
||||||
format_addr(&q->from, q->fromlen), format_addr(&u->remoteforward_addr, sizeof(struct sockaddr_storage)));
|
fromaddr, format_addr(&u->remoteforward_addr, sizeof(struct sockaddr_storage)));
|
||||||
syslog(LOG_NOTICE, "accepted password from user #%d, connecting TCP forward", userid);
|
syslog(LOG_NOTICE, "accepted password from user #%d, connecting TCP forward", userid);
|
||||||
|
|
||||||
/* Open socket and connect to TCP forward host:port */
|
/* Open socket and connect to TCP forward host:port */
|
||||||
@ -1377,28 +1472,38 @@ handle_dns_login(int dns_fd, struct query *q, uint8_t *domain, int domain_len, i
|
|||||||
goto tcp_forward_error;
|
goto tcp_forward_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* connection in progress */
|
||||||
out[0] = 'W';
|
out[0] = 'W';
|
||||||
read = 1;
|
read = 1;
|
||||||
write_dns(dns_fd, q, out, read + 1, u->downenc);
|
write_dns(dns_fd, q, out, read + 1, u->downenc);
|
||||||
u->tcp_fd = tcp_fd;
|
u->remote_tcp_fd = tcp_fd;
|
||||||
|
u->remote_forward_connected = 2; /* connecting */
|
||||||
return;
|
return;
|
||||||
} else if (poll_status) {
|
} else if (poll_status) {
|
||||||
|
/* Check TCP forward connection status and update user data */
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if ((retval = check_tcp_status(u->tcp_fd, &errormsg)) == -1) {
|
/* Check for connection errors */
|
||||||
goto tcp_forward_error;
|
if ((retval = check_tcp_error(u->remote_tcp_fd, &errormsg)) != 0) {
|
||||||
|
/* if unacceptable error, tell user */
|
||||||
|
if (retval != EINPROGRESS)
|
||||||
|
goto tcp_forward_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (retval == EINPROGRESS)
|
||||||
|
u->remote_forward_connected = 2;
|
||||||
|
|
||||||
read = 1;
|
read = 1;
|
||||||
out[1] = 0;
|
out[1] = 0;
|
||||||
|
|
||||||
if (retval == 0) {
|
/* check user TCP forward status flag, which is updated in server_tunnel
|
||||||
|
* when the file descriptor becomes writable (ie, connection established */
|
||||||
|
if (u->remote_forward_connected == 1) {
|
||||||
out[0] = 'C';
|
out[0] = 'C';
|
||||||
u->remote_forward_connected = 1;
|
DEBUG(2, "User %d TCP forward connection established: %s", userid, errormsg);
|
||||||
} else if (retval == EINPROGRESS) {
|
} else if (u->remote_forward_connected == 2) {
|
||||||
out[0] = 'W';
|
out[0] = 'W';
|
||||||
} else {
|
DEBUG(3, "User %d TCP connection in progress: %s", userid, errormsg);
|
||||||
goto tcp_forward_error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write_dns(dns_fd, q, out, read + 1, u->downenc);
|
write_dns(dns_fd, q, out, read + 1, u->downenc);
|
||||||
@ -1412,11 +1517,11 @@ handle_dns_login(int dns_fd, struct query *q, uint8_t *domain, int domain_len, i
|
|||||||
tempip.s_addr = u->tun_ip;
|
tempip.s_addr = u->tun_ip;
|
||||||
tmp[1] = strdup(inet_ntoa(tempip));
|
tmp[1] = strdup(inet_ntoa(tempip));
|
||||||
|
|
||||||
read = snprintf(out, sizeof(out) - 1, "-%s-%s-%d-%d",
|
read = snprintf(out + 1, sizeof(out) - 1, "-%s-%s-%d-%d",
|
||||||
tmp[0], tmp[1], server.mtu, server.netmask);
|
tmp[0], tmp[1], server.mtu, server.netmask);
|
||||||
|
|
||||||
DEBUG(1, "User %d connected from %s, tun_ip %s.", userid,
|
DEBUG(1, "User %d connected from %s, tun_ip %s.", userid,
|
||||||
format_addr(&q->from, q->fromlen), tmp[1]);
|
fromaddr, tmp[1]);
|
||||||
syslog(LOG_NOTICE, "accepted password from user #%d, given IP %s", userid, tmp[1]);
|
syslog(LOG_NOTICE, "accepted password from user #%d, given IP %s", userid, tmp[1]);
|
||||||
|
|
||||||
free(tmp[1]);
|
free(tmp[1]);
|
||||||
@ -1618,7 +1723,7 @@ handle_dns_ping(int dns_fd, struct query *q, int userid,
|
|||||||
uint8_t *unpacked, size_t read)
|
uint8_t *unpacked, size_t read)
|
||||||
{
|
{
|
||||||
int dn_seq, up_seq, dn_winsize, up_winsize, dn_ack;
|
int dn_seq, up_seq, dn_winsize, up_winsize, dn_ack;
|
||||||
int respond, set_qtimeout, set_wtimeout;
|
int respond, set_qtimeout, set_wtimeout, tcp_disconnect;
|
||||||
unsigned qtimeout_ms, wtimeout_ms;
|
unsigned qtimeout_ms, wtimeout_ms;
|
||||||
|
|
||||||
CHECK_LEN(read, UPSTREAM_PING);
|
CHECK_LEN(read, UPSTREAM_PING);
|
||||||
@ -1628,23 +1733,36 @@ handle_dns_ping(int dns_fd, struct query *q, int userid,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* Unpack flags/options from ping header */
|
/* Unpack flags/options from ping header */
|
||||||
dn_ack = ((unpacked[10] >> 2) & 1) ? unpacked[1] : -1;
|
dn_ack = ((unpacked[9] >> 2) & 1) ? unpacked[0] : -1;
|
||||||
up_winsize = unpacked[2];
|
up_winsize = unpacked[1];
|
||||||
dn_winsize = unpacked[3];
|
dn_winsize = unpacked[2];
|
||||||
up_seq = unpacked[4];
|
up_seq = unpacked[3];
|
||||||
dn_seq = unpacked[5];
|
dn_seq = unpacked[4];
|
||||||
|
|
||||||
/* Query timeout and window frag timeout */
|
/* Query timeout and window frag timeout */
|
||||||
qtimeout_ms = ntohs(*(uint16_t *) (unpacked + 6));
|
qtimeout_ms = ntohs(*(uint16_t *) (unpacked + 5));
|
||||||
wtimeout_ms = ntohs(*(uint16_t *) (unpacked + 8));
|
wtimeout_ms = ntohs(*(uint16_t *) (unpacked + 7));
|
||||||
respond = unpacked[10] & 1;
|
respond = unpacked[9] & 1;
|
||||||
set_qtimeout = (unpacked[10] >> 3) & 1;
|
set_qtimeout = (unpacked[9] >> 3) & 1;
|
||||||
set_wtimeout = (unpacked[10] >> 4) & 1;
|
set_wtimeout = (unpacked[9] >> 4) & 1;
|
||||||
|
tcp_disconnect = (unpacked[9] >> 5) & 1;
|
||||||
|
|
||||||
DEBUG(3, "PING pkt user %d, down %d/%d, up %d/%d, ACK %d, %sqtime %u ms, %swtime %u ms, respond %d (flags %02X)",
|
DEBUG(3, "PING pkt user %d, down %d/%d, up %d/%d, ACK %d, %sqtime %u ms, "
|
||||||
|
"%swtime %u ms, respond %d, tcp_close %d (flags %02X)",
|
||||||
userid, dn_seq, dn_winsize, up_seq, up_winsize, dn_ack,
|
userid, dn_seq, dn_winsize, up_seq, up_winsize, dn_ack,
|
||||||
set_qtimeout ? "SET " : "", qtimeout_ms, set_wtimeout ? "SET " : "",
|
set_qtimeout ? "SET " : "", qtimeout_ms, set_wtimeout ? "SET " : "",
|
||||||
wtimeout_ms, respond, unpacked[10]);
|
wtimeout_ms, respond, tcp_disconnect, unpacked[9]);
|
||||||
|
|
||||||
|
if (tcp_disconnect) {
|
||||||
|
/* close user's TCP forward connection and mark user as inactive */
|
||||||
|
if (users[userid].remoteforward_addr_len == 0) {
|
||||||
|
DEBUG(1, "User %d attempted TCP disconnect but didn't request TCP forwarding!", userid);
|
||||||
|
} else {
|
||||||
|
DEBUG(1, "User %d closed remote TCP forward", userid);
|
||||||
|
close_socket(users[userid].remote_tcp_fd);
|
||||||
|
users[userid].active = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (set_qtimeout) {
|
if (set_qtimeout) {
|
||||||
/* update user's query timeout if timeout flag set */
|
/* update user's query timeout if timeout flag set */
|
||||||
@ -1671,7 +1789,7 @@ handle_dns_ping(int dns_fd, struct query *q, int userid,
|
|||||||
users[userid].outgoing->windowsize, dn_winsize, users[userid].incoming->windowsize, up_winsize);
|
users[userid].outgoing->windowsize, dn_winsize, users[userid].incoming->windowsize, up_winsize);
|
||||||
users[userid].outgoing->windowsize = dn_winsize;
|
users[userid].outgoing->windowsize = dn_winsize;
|
||||||
users[userid].incoming->windowsize = up_winsize;
|
users[userid].incoming->windowsize = up_winsize;
|
||||||
send_data_or_ping(userid, q, 1, 1);
|
send_data_or_ping(userid, q, 1, 1, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1682,7 +1800,7 @@ handle_dns_ping(int dns_fd, struct query *q, int userid,
|
|||||||
void
|
void
|
||||||
handle_dns_data(int dns_fd, struct query *q, uint8_t *domain, int domain_len, int userid)
|
handle_dns_data(int dns_fd, struct query *q, uint8_t *domain, int domain_len, int userid)
|
||||||
{
|
{
|
||||||
uint8_t unpacked[512];
|
uint8_t unpacked[20];
|
||||||
static fragment f;
|
static fragment f;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
|
@ -158,6 +158,6 @@ void handle_null_request(int dns_fd, struct query *q, int domain_len);
|
|||||||
void handle_ns_request(int dns_fd, struct query *q);
|
void handle_ns_request(int dns_fd, struct query *q);
|
||||||
void handle_a_request(int dns_fd, struct query *q, int fakeip);
|
void handle_a_request(int dns_fd, struct query *q, int fakeip);
|
||||||
|
|
||||||
void send_data_or_ping(int, struct query *, int, int);
|
void send_data_or_ping(int, struct query *, int, int, char*);
|
||||||
|
|
||||||
#endif /* __SERVER_H__ */
|
#endif /* __SERVER_H__ */
|
||||||
|
@ -457,13 +457,6 @@ open_tun(const char *tun_device)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
|
||||||
close_tun(int tun_fd)
|
|
||||||
{
|
|
||||||
if (tun_fd >= 0)
|
|
||||||
close(tun_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
#ifdef WINDOWS32
|
||||||
int
|
int
|
||||||
write_tun(int tun_fd, uint8_t *data, size_t len)
|
write_tun(int tun_fd, uint8_t *data, size_t len)
|
||||||
|
16
src/user.c
16
src/user.c
@ -236,3 +236,19 @@ check_authenticated_user_and_ip(int userid, struct query *q, int check_ip)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
set_user_tcp_fds(fd_set *fds, int conn_status)
|
||||||
|
/* Add TCP forward FDs to fd_set for users with given connection status; returns largest FD added */
|
||||||
|
{
|
||||||
|
int max_fd = 0;
|
||||||
|
for (int userid = 0; userid < created_users; userid ++) {
|
||||||
|
if (user_active(userid) && users[userid].remoteforward_addr_len > 0
|
||||||
|
&& users[userid].remote_forward_connected == conn_status) {
|
||||||
|
FD_SET(users[userid].remote_tcp_fd, fds);
|
||||||
|
max_fd = MAX(max_fd, users[userid].remote_tcp_fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,8 @@ struct tun_user {
|
|||||||
socklen_t hostlen;
|
socklen_t hostlen;
|
||||||
struct sockaddr_storage remoteforward_addr;
|
struct sockaddr_storage remoteforward_addr;
|
||||||
socklen_t remoteforward_addr_len; /* 0 if no remote forwarding enabled */
|
socklen_t remoteforward_addr_len; /* 0 if no remote forwarding enabled */
|
||||||
int tcp_fd;
|
int remote_tcp_fd;
|
||||||
int remote_forward_connected;
|
int remote_forward_connected; /* 0 if not connected, -1 if error or 1 if OK */
|
||||||
struct frag_buffer *incoming;
|
struct frag_buffer *incoming;
|
||||||
struct frag_buffer *outgoing;
|
struct frag_buffer *outgoing;
|
||||||
int next_upstream_ack;
|
int next_upstream_ack;
|
||||||
@ -67,5 +67,6 @@ int find_user_by_ip(uint32_t);
|
|||||||
int find_available_user();
|
int find_available_user();
|
||||||
void user_switch_codec(int userid, struct encoder *enc);
|
void user_switch_codec(int userid, struct encoder *enc);
|
||||||
void user_set_conn_type(int userid, enum connection c);
|
void user_set_conn_type(int userid, enum connection c);
|
||||||
|
int set_user_tcp_fds(fd_set *fds, int);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user