mirror of
https://github.com/yarrick/iodine.git
synced 2024-11-28 20:45:12 +00:00
Ping responses use the same query and are immediate + set window params
This commit is contained in:
parent
ceaac64814
commit
f4f358f5e2
113
src/server.c
113
src/server.c
@ -112,7 +112,7 @@ send_raw(int fd, uint8_t *buf, size_t buflen, int user, int cmd, struct sockaddr
|
|||||||
len += RAW_HDR_LEN;
|
len += RAW_HDR_LEN;
|
||||||
packet[RAW_HDR_CMD] = cmd | (user & 0x0F);
|
packet[RAW_HDR_CMD] = cmd | (user & 0x0F);
|
||||||
|
|
||||||
DEBUG(3, "TX-raw: client %s (user %d), cmd %d, %d bytes\n",
|
DEBUG(3, "TX-raw: client %s (user %d), cmd %d, %d bytes",
|
||||||
format_addr(from, fromlen), user, cmd, len);
|
format_addr(from, fromlen), user, cmd, len);
|
||||||
|
|
||||||
sendto(fd, packet, len, 0, (struct sockaddr *) from, fromlen);
|
sendto(fd, packet, len, 0, (struct sockaddr *) from, fromlen);
|
||||||
@ -149,10 +149,10 @@ qmem_init(int userid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qmem_append(int dns_fd, int userid, struct query *q)
|
qmem_is_cached(int dns_fd, int userid, struct query *q)
|
||||||
/* Appends incoming query to the buffer. If the query is already in the buffer,
|
/* Check if an answer for a particular query is cached in qmem
|
||||||
* ie a duplicate, an illegal answer is sent.
|
* If so, sends an "invalid" answer
|
||||||
* Return: 0 = answer sent, don't process; 1 = not a duplicate (all OK) */
|
* Returns 1 if new query, 0 if cached (and then answered) */
|
||||||
{
|
{
|
||||||
struct query_buffer *buf;
|
struct query_buffer *buf;
|
||||||
struct query *pq;
|
struct query *pq;
|
||||||
@ -166,21 +166,29 @@ qmem_append(int dns_fd, int userid, struct query *q)
|
|||||||
if (pq->type != q->type)
|
if (pq->type != q->type)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// FIXME: check for case changes?
|
if (strcasecmp(pq->name, q->name))
|
||||||
if (memcmp(pq->name, q->name, sizeof(q->name)))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
QMEM_DEBUG(1, userid, "OUT for '%s' == duplicate, sending illegal reply", q->name);
|
QMEM_DEBUG(2, userid, "OUT for '%s' == duplicate, sending illegal reply", q->name);
|
||||||
|
|
||||||
// TODO cache answers/respond using cache? (merge with dnscache)
|
// TODO cache answers/respond using cache? (merge with dnscache)
|
||||||
write_dns(dns_fd, q, "x", 1, 'T');
|
write_dns(dns_fd, q, "x", 1, 'T');
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qmem_append(int userid, struct query *q)
|
||||||
|
/* Appends incoming query to the buffer. */
|
||||||
|
{
|
||||||
|
struct query_buffer *buf;
|
||||||
|
buf = &users[userid].qmem;
|
||||||
|
|
||||||
if (buf->num_pending >= QMEM_LEN) {
|
if (buf->num_pending >= QMEM_LEN) {
|
||||||
/* this means we have QMEM_LEN *pending* queries; don't overwrite */
|
/* this means we have QMEM_LEN *pending* queries; don't overwrite */
|
||||||
QMEM_DEBUG(2, userid, "full of pending queries. Not appending query with id %d.", q->id);
|
QMEM_DEBUG(2, userid, "full of pending queries. Not appending query with id %d.", q->id);
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf->length < QMEM_LEN) {
|
if (buf->length < QMEM_LEN) {
|
||||||
@ -241,15 +249,15 @@ qmem_max_wait(struct dnsfd *dns_fds, int *touser, struct query **sendq)
|
|||||||
* - the query has timed out
|
* - the query has timed out
|
||||||
* - the user has data to send, pending ACKs or ping and spare pending queries
|
* - the user has data to send, pending ACKs or ping and spare pending queries
|
||||||
* - the user has excess pending queries (>downstream window size)
|
* - the user has excess pending queries (>downstream window size)
|
||||||
* Returns largest safe time to wait before next timeout
|
* Returns largest safe time to wait before next timeout */
|
||||||
* TODO respond to excess pending queries */
|
|
||||||
{
|
{
|
||||||
struct timeval now, timeout, soonest, tmp;
|
struct timeval now, timeout, soonest, tmp, age;
|
||||||
soonest.tv_sec = 10;
|
soonest.tv_sec = 10;
|
||||||
soonest.tv_usec = 0;
|
soonest.tv_usec = 0;
|
||||||
int userid, qnum, nextuser = -1;
|
int userid, qnum, nextuser = -1, immediate;
|
||||||
struct query *q = NULL, *nextq = NULL;
|
struct query *q = NULL, *nextq = NULL;
|
||||||
size_t sending, total, sent;
|
size_t sending, total, sent;
|
||||||
|
time_t age_ms;
|
||||||
struct tun_user *u;
|
struct tun_user *u;
|
||||||
|
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
@ -273,7 +281,7 @@ qmem_max_wait(struct dnsfd *dns_fds, int *touser, struct query **sendq)
|
|||||||
sending = total;
|
sending = total;
|
||||||
sent = 0;
|
sent = 0;
|
||||||
|
|
||||||
if (!u->lazy && u->qmem.num_pending > 0) {
|
if ((!u->lazy) && u->qmem.num_pending > 0) {
|
||||||
QMEM_DEBUG(2, userid, "User switched to immediate mode, answering all pending queries...");
|
QMEM_DEBUG(2, userid, "User switched to immediate mode, answering all pending queries...");
|
||||||
sending = u->qmem.num_pending;
|
sending = u->qmem.num_pending;
|
||||||
}
|
}
|
||||||
@ -283,29 +291,28 @@ qmem_max_wait(struct dnsfd *dns_fds, int *touser, struct query **sendq)
|
|||||||
|
|
||||||
/* queries will always be in time order */
|
/* queries will always be in time order */
|
||||||
timeradd(&q->time_recv, &u->dns_timeout, &timeout);
|
timeradd(&q->time_recv, &u->dns_timeout, &timeout);
|
||||||
if (sending > 0 || !timercmp(&now, &timeout, <) ||
|
if (sending > 0 || !timercmp(&now, &timeout, <) || u->next_upstream_ack >= 0) {
|
||||||
u->next_upstream_ack >= 0 || u->send_ping_next) {
|
|
||||||
/* respond to a query with ping/data if:
|
/* respond to a query with ping/data if:
|
||||||
* - query has timed out (ping, or data if available)
|
* - query has timed out (ping, or data if available)
|
||||||
* - user has pending data (always data)
|
* - user has pending data (always data)
|
||||||
* - user has pending ACK (either)
|
* - user has pending ACK (either)
|
||||||
* - user has pending ping (always ping, with data if available) */
|
* - user has pending ping (always ping, with data if available) */
|
||||||
|
timersub(&q->time_recv, &now, &age);
|
||||||
|
age_ms = timeval_to_ms(&age);
|
||||||
|
|
||||||
|
/* only consider "immediate" when age is negligible */
|
||||||
|
immediate = age_ms <= 10;
|
||||||
|
|
||||||
if (debug >= 3) {
|
if (debug >= 3) {
|
||||||
struct timeval age;
|
QMEM_DEBUG(3, userid, "Auto response to cached query: ID %d, %ld ms old (%s), timeout %ld ms",
|
||||||
timersub(&q->time_recv, &now, &age);
|
q->id, age_ms, immediate ? "immediate" : "lazy", timeval_to_ms(&u->dns_timeout));
|
||||||
QMEM_DEBUG(3, userid, "Auto response to cached query: ID %d, %ld ms old, timeout %ld ms",
|
|
||||||
q->id, timeval_to_ms(&age), timeval_to_ms(&u->dns_timeout));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sent++;
|
sent++;
|
||||||
QMEM_DEBUG(4, userid, "ANSWER q id %d, ping %d, ACK %d; sent %lu of %lu + sending another %lu",
|
QMEM_DEBUG(4, userid, "ANSWER q id %d, ACK %d; sent %lu of %lu + sending another %lu",
|
||||||
q->id, u->send_ping_next, u->next_upstream_ack, sent, total, sending);
|
q->id, u->next_upstream_ack, sent, total, sending);
|
||||||
|
|
||||||
send_data_or_ping(dns_fds, userid, q, u->send_ping_next, 1, 0);
|
send_data_or_ping(dns_fds, userid, q, 0, immediate);
|
||||||
|
|
||||||
if (u->send_ping_next)
|
|
||||||
u->send_ping_next = 0;
|
|
||||||
|
|
||||||
if (sending > 0)
|
if (sending > 0)
|
||||||
sending--;
|
sending--;
|
||||||
@ -332,7 +339,8 @@ qmem_max_wait(struct dnsfd *dns_fds, int *touser, struct query **sendq)
|
|||||||
if (nextuser < 0)
|
if (nextuser < 0)
|
||||||
nextuser = 0;
|
nextuser = 0;
|
||||||
/* sanity check: soonest_ms should always be default value here (ie. 10000) */
|
/* sanity check: soonest_ms should always be default value here (ie. 10000) */
|
||||||
QMEM_DEBUG(5, nextuser, "Don't need to send anything to any users, waiting %lu ms", soonest_ms);
|
if (soonest_ms != 10000)
|
||||||
|
QMEM_DEBUG(1, nextuser, "Don't need to send anything to any users, waiting %lu ms", soonest_ms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,10 +502,9 @@ send_version_response(int fd, version_ack_t ack, uint32_t payload, int userid, s
|
|||||||
|
|
||||||
void
|
void
|
||||||
send_data_or_ping(struct dnsfd *dns_fds, int userid, struct query *q,
|
send_data_or_ping(struct dnsfd *dns_fds, int userid, struct query *q,
|
||||||
int ping, int respond_now, int immediate)
|
int ping, int immediate)
|
||||||
/* 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.
|
||||||
respond_now: 1=must answer query now, 0=leave in qmem if no data available
|
|
||||||
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 */
|
||||||
{
|
{
|
||||||
uint8_t pkt[MAX_FRAGSIZE + DOWNSTREAM_PING_HDR];
|
uint8_t pkt[MAX_FRAGSIZE + DOWNSTREAM_PING_HDR];
|
||||||
@ -514,10 +521,6 @@ send_data_or_ping(struct dnsfd *dns_fds, int userid, struct query *q,
|
|||||||
|
|
||||||
/* 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) {
|
||||||
if (users[userid].lazy && !respond_now) {
|
|
||||||
/* No data and lazy mode: leave this query to wait in qmem */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* No data, may as well send data/ping header (with extra info) */
|
/* No data, may as well send data/ping header (with extra info) */
|
||||||
ping = 1;
|
ping = 1;
|
||||||
datalen = 0;
|
datalen = 0;
|
||||||
@ -708,7 +711,7 @@ tunnel_dns(int tun_fd, int dns_fd, struct dnsfd *dns_fds, int bind_fd)
|
|||||||
if ((read = read_dns(dns_fd, dns_fds, tun_fd, &q)) <= 0)
|
if ((read = read_dns(dns_fd, dns_fds, tun_fd, &q)) <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
DEBUG(3, "RX: client %s ID %5d, type %d, name %s\n",
|
DEBUG(3, "RX: client %s ID %5d, type %d, name %s",
|
||||||
format_addr(&q.from, q.fromlen), q.id, q.type, q.name);
|
format_addr(&q.from, q.fromlen), q.id, q.type, q.name);
|
||||||
|
|
||||||
domain_len = strlen(q.name) - strlen(topdomain);
|
domain_len = strlen(q.name) - strlen(topdomain);
|
||||||
@ -1189,7 +1192,7 @@ write_dns(int fd, struct query *q, char *data, size_t datalen, char downenc)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(3, "TX: client %s ID %5d, %lu bytes data, type %d, name '%10s'\n",
|
DEBUG(3, "TX: client %s ID %5d, %lu bytes data, type %d, name '%10s'",
|
||||||
format_addr(&q->from, q->fromlen), q->id, datalen, q->type, q->name);
|
format_addr(&q->from, q->fromlen), q->id, datalen, q->type, q->name);
|
||||||
|
|
||||||
sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen);
|
sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen);
|
||||||
@ -1216,7 +1219,7 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query
|
|||||||
|
|
||||||
memcpy(in, q->name, MIN(domain_len, sizeof(in)));
|
memcpy(in, q->name, MIN(domain_len, sizeof(in)));
|
||||||
|
|
||||||
DEBUG(3, "NULL request length %d/%lu, command '%c'\n", domain_len, sizeof(in), in[0]);
|
DEBUG(3, "NULL request length %d/%lu, command '%c'", domain_len, sizeof(in), in[0]);
|
||||||
|
|
||||||
if(in[0] == 'V' || in[0] == 'v') { /* Version request */
|
if(in[0] == 'V' || in[0] == 'v') { /* Version request */
|
||||||
uint32_t version = !PROTOCOL_VERSION;
|
uint32_t version = !PROTOCOL_VERSION;
|
||||||
@ -1259,7 +1262,6 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query
|
|||||||
window_buffer_clear(u->outgoing);
|
window_buffer_clear(u->outgoing);
|
||||||
window_buffer_clear(u->incoming);
|
window_buffer_clear(u->incoming);
|
||||||
u->next_upstream_ack = -1;
|
u->next_upstream_ack = -1;
|
||||||
u->send_ping_next = 0;
|
|
||||||
#ifdef QMEM_LEN
|
#ifdef QMEM_LEN
|
||||||
qmem_init(userid);
|
qmem_init(userid);
|
||||||
#endif
|
#endif
|
||||||
@ -1635,13 +1637,6 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ping packet, store userid */
|
|
||||||
userid = unpacked[0];
|
|
||||||
if (check_authenticated_user_and_ip(userid, q) != 0) {
|
|
||||||
write_dns(dns_fd, q, "BADIP", 5, 'T');
|
|
||||||
return; /* illegal id */
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DNSCACHE_LEN
|
#ifdef DNSCACHE_LEN
|
||||||
/* Check if cached */
|
/* Check if cached */
|
||||||
if (answer_from_dnscache(dns_fd, userid, q))
|
if (answer_from_dnscache(dns_fd, userid, q))
|
||||||
@ -1649,10 +1644,17 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query
|
|||||||
#endif // XXX hmm these look very similar...
|
#endif // XXX hmm these look very similar...
|
||||||
#ifdef QMEM_LEN
|
#ifdef QMEM_LEN
|
||||||
/* Check if cached */
|
/* Check if cached */
|
||||||
if (!qmem_append(dns_fd, userid, q))
|
if (!qmem_is_cached(dns_fd, userid, q))
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Ping packet, store userid */
|
||||||
|
userid = unpacked[0];
|
||||||
|
if (check_authenticated_user_and_ip(userid, q) != 0) {
|
||||||
|
write_dns(dns_fd, q, "BADIP", 5, 'T');
|
||||||
|
return; /* illegal id */
|
||||||
|
}
|
||||||
|
|
||||||
dn_ack = ((unpacked[8] >> 2) & 1) ? unpacked[1] : -1;
|
dn_ack = ((unpacked[8] >> 2) & 1) ? unpacked[1] : -1;
|
||||||
up_winsize = unpacked[2];
|
up_winsize = unpacked[2];
|
||||||
dn_winsize = unpacked[3];
|
dn_winsize = unpacked[3];
|
||||||
@ -1664,6 +1666,16 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query
|
|||||||
|
|
||||||
respond = unpacked[8] & 1;
|
respond = unpacked[8] & 1;
|
||||||
|
|
||||||
|
if (respond) {
|
||||||
|
/* ping handshake - set windowsizes etc, respond NOW using this query
|
||||||
|
* NOTE: not added to qmem */
|
||||||
|
users[userid].outgoing->windowsize = dn_winsize;
|
||||||
|
users[userid].incoming->windowsize = up_winsize;
|
||||||
|
send_data_or_ping(dns_fds, userid, q, 1, 1);
|
||||||
|
} else {
|
||||||
|
qmem_append(userid, q);
|
||||||
|
}
|
||||||
|
|
||||||
if ((unpacked[8] >> 3) & 1) {
|
if ((unpacked[8] >> 3) & 1) {
|
||||||
/* update user's query timeout if timeout flag set */
|
/* update user's query timeout if timeout flag set */
|
||||||
users[userid].dns_timeout = timeout;
|
users[userid].dns_timeout = timeout;
|
||||||
@ -1678,10 +1690,7 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query
|
|||||||
|
|
||||||
user_process_incoming_data(tun_fd, dns_fds, userid, dn_ack);
|
user_process_incoming_data(tun_fd, dns_fds, userid, dn_ack);
|
||||||
|
|
||||||
/* Leave query in qmem, response is done in qmem_max_wait.
|
/* if respond flag not set, query waits in qmem and is used later */
|
||||||
* Set the ping flag if it needs to respond */
|
|
||||||
users[userid].send_ping_next = respond;
|
|
||||||
|
|
||||||
} else if (isxdigit(in[0])) { /* Upstream data packet */
|
} else if (isxdigit(in[0])) { /* Upstream data packet */
|
||||||
int code = 0;
|
int code = 0;
|
||||||
static fragment f;
|
static fragment f;
|
||||||
@ -1722,7 +1731,7 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query
|
|||||||
#endif
|
#endif
|
||||||
#ifdef QMEM_LEN
|
#ifdef QMEM_LEN
|
||||||
/* Check if cached */
|
/* Check if cached */
|
||||||
if (!qmem_append(dns_fd, userid, q))
|
if (!qmem_is_cached(dns_fd, userid, q))
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
/* Decode upstream data header - see docs/proto_XXXXXXXX.txt */
|
/* Decode upstream data header - see docs/proto_XXXXXXXX.txt */
|
||||||
@ -1753,8 +1762,8 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query
|
|||||||
|
|
||||||
user_process_incoming_data(tun_fd, dns_fds, userid, f.ack_other);
|
user_process_incoming_data(tun_fd, dns_fds, userid, f.ack_other);
|
||||||
|
|
||||||
/* Nothing to do. ACK (and response to this query) is sent
|
/* Nothing to do. ACK for this fragment is sent later in qmem_max_wait,
|
||||||
* later in qmem_max_wait. */
|
* using an old query. This is left in qmem until needed/times out */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +124,6 @@ void handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct q
|
|||||||
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(struct dnsfd *, int, struct query *, int, int, int);
|
void send_data_or_ping(struct dnsfd *, int, struct query *, int, int);
|
||||||
|
|
||||||
#endif /* __SERVER_H__ */
|
#endif /* __SERVER_H__ */
|
||||||
|
@ -81,7 +81,7 @@ init_users(in_addr_t my_ip, int netbits)
|
|||||||
if (debug >= 2) {
|
if (debug >= 2) {
|
||||||
struct in_addr IP;
|
struct in_addr IP;
|
||||||
IP.s_addr = ip;
|
IP.s_addr = ip;
|
||||||
DEBUG(2, "User %d: IP %s\n", i, inet_ntoa(IP));
|
DEBUG(2, "User %d: IP %s", i, inet_ntoa(IP));
|
||||||
}
|
}
|
||||||
users[i].tun_ip = ip;
|
users[i].tun_ip = ip;
|
||||||
net.s_addr = ip;
|
net.s_addr = ip;
|
||||||
|
@ -40,7 +40,6 @@ struct tun_user {
|
|||||||
struct frag_buffer *incoming;
|
struct frag_buffer *incoming;
|
||||||
struct frag_buffer *outgoing;
|
struct frag_buffer *outgoing;
|
||||||
int next_upstream_ack;
|
int next_upstream_ack;
|
||||||
int send_ping_next;
|
|
||||||
struct encoder *encoder;
|
struct encoder *encoder;
|
||||||
char downenc;
|
char downenc;
|
||||||
int downenc_bits;
|
int downenc_bits;
|
||||||
|
Loading…
Reference in New Issue
Block a user