mirror of
https://github.com/yarrick/iodine.git
synced 2024-12-27 07:13:33 +02:00
#36, upstream traffic now sent in raw mode
This commit is contained in:
parent
e2c8ac3985
commit
5d3b502ec6
5 changed files with 183 additions and 80 deletions
15
src/common.h
15
src/common.h
|
@ -21,8 +21,13 @@
|
|||
#define RAW_HDR_LEN 4
|
||||
#define RAW_HDR_IDENT_LEN 3
|
||||
#define RAW_HDR_CMD 3
|
||||
#define RAW_HDR_CMD_LOGIN 0x01
|
||||
#define RAW_HDR_CMD_DATA 0x02
|
||||
#define RAW_HDR_CMD_LOGIN 0x10
|
||||
#define RAW_HDR_CMD_DATA 0x20
|
||||
|
||||
#define RAW_HDR_CMD_MASK 0xF0
|
||||
#define RAW_HDR_USR_MASK 0x0F
|
||||
#define RAW_HDR_GET_CMD(x) ((x)[RAW_HDR_CMD] & RAW_HDR_CMD_MASK)
|
||||
#define RAW_HDR_GET_USR(x) ((x)[RAW_HDR_CMD] & RAW_HDR_USR_MASK)
|
||||
extern const unsigned char raw_header[RAW_HDR_LEN];
|
||||
|
||||
#ifdef WINDOWS32
|
||||
|
@ -85,6 +90,12 @@ struct query {
|
|||
int fromlen;
|
||||
};
|
||||
|
||||
enum connection {
|
||||
CONN_RAW_UDP,
|
||||
CONN_DNS_NULL,
|
||||
CONN_MAX
|
||||
};
|
||||
|
||||
void check_superuser(void (*usage_fn)(void));
|
||||
int open_dns(int, in_addr_t);
|
||||
void close_dns(int);
|
||||
|
|
77
src/iodine.c
77
src/iodine.c
|
@ -60,6 +60,7 @@ WSADATA wsa_data;
|
|||
|
||||
static void send_ping(int fd);
|
||||
static void send_chunk(int fd);
|
||||
static void send_raw_data(int fd);
|
||||
static int build_hostname(char *buf, size_t buflen,
|
||||
const char *data, const size_t datalen,
|
||||
const char *topdomain, struct encoder *encoder);
|
||||
|
@ -94,6 +95,9 @@ static struct encoder *b32;
|
|||
* Defaults to Base32, can be changed after handshake */
|
||||
static struct encoder *dataenc;
|
||||
|
||||
/* My connection mode */
|
||||
static enum connection conn;
|
||||
|
||||
#if !defined(BSD) && !defined(__GLIBC__)
|
||||
static char *__progname;
|
||||
#endif
|
||||
|
@ -120,7 +124,7 @@ send_query(int fd, char *hostname)
|
|||
}
|
||||
|
||||
static void
|
||||
send_raw(int fd, char *buf, int buflen, int cmd)
|
||||
send_raw(int fd, char *buf, int buflen, int user, int cmd)
|
||||
{
|
||||
char packet[4096];
|
||||
int len;
|
||||
|
@ -131,7 +135,7 @@ send_raw(int fd, char *buf, int buflen, int cmd)
|
|||
memcpy(&packet[RAW_HDR_LEN], buf, len);
|
||||
|
||||
len += RAW_HDR_LEN;
|
||||
packet[RAW_HDR_CMD] = cmd;
|
||||
packet[RAW_HDR_CMD] = cmd | (user & 0x0F);
|
||||
|
||||
sendto(fd, packet, len, 0, (struct sockaddr*)&raw_serv, sizeof(raw_serv));
|
||||
}
|
||||
|
@ -263,7 +267,11 @@ tunnel_tun(int tun_fd, int dns_fd)
|
|||
outpkt.seqno++;
|
||||
outpkt.fragment = 0;
|
||||
|
||||
send_chunk(dns_fd);
|
||||
if (conn == CONN_DNS_NULL) {
|
||||
send_chunk(dns_fd);
|
||||
} else {
|
||||
send_raw_data(dns_fd);
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
@ -327,7 +335,7 @@ tunnel(int tun_fd, int dns_fd)
|
|||
|
||||
|
||||
FD_ZERO(&fds);
|
||||
if (!is_sending()) {
|
||||
if ((!is_sending()) || conn == CONN_RAW_UDP) {
|
||||
FD_SET(tun_fd, &fds);
|
||||
}
|
||||
FD_SET(dns_fd, &fds);
|
||||
|
@ -340,7 +348,7 @@ tunnel(int tun_fd, int dns_fd)
|
|||
if (i < 0)
|
||||
err(1, "select");
|
||||
|
||||
if (i == 0) /* timeout */
|
||||
if (i == 0 && conn == CONN_DNS_NULL) /* timeout */
|
||||
send_ping(dns_fd);
|
||||
else {
|
||||
if (FD_ISSET(tun_fd, &fds)) {
|
||||
|
@ -357,6 +365,12 @@ tunnel(int tun_fd, int dns_fd)
|
|||
return rv;
|
||||
}
|
||||
|
||||
static void
|
||||
send_raw_data(int dns_fd)
|
||||
{
|
||||
send_raw(dns_fd, outpkt.data, outpkt.len, userid, RAW_HDR_CMD_DATA);
|
||||
}
|
||||
|
||||
static void
|
||||
send_chunk(int fd)
|
||||
{
|
||||
|
@ -507,11 +521,10 @@ send_ip_request(int fd, int userid)
|
|||
static void
|
||||
send_raw_udp_login(int dns_fd, int userid, int seed)
|
||||
{
|
||||
char buf[17];
|
||||
char buf[16];
|
||||
login_calculate(buf, 16, password, seed + 1);
|
||||
buf[16] = userid;
|
||||
|
||||
send_raw(dns_fd, buf, sizeof(buf), RAW_HDR_CMD_LOGIN);
|
||||
send_raw(dns_fd, buf, sizeof(buf), userid, RAW_HDR_CMD_LOGIN);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -715,7 +728,7 @@ handshake_raw_udp(int dns_fd, int seed)
|
|||
|
||||
if (!remoteaddr) {
|
||||
fprintf(stderr, " failed to get IP.\n");
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, " at %s: ", inet_ntoa(server));
|
||||
fflush(stderr);
|
||||
|
@ -743,16 +756,15 @@ handshake_raw_udp(int dns_fd, int seed)
|
|||
if(r > 0) {
|
||||
/* recv() needed for windows, dont change to read() */
|
||||
len = recv(dns_fd, in, sizeof(in), 0);
|
||||
if (len >= (17 + RAW_HDR_LEN)) {
|
||||
if (len >= (16 + RAW_HDR_LEN)) {
|
||||
char hash[16];
|
||||
login_calculate(hash, 16, password, seed - 1);
|
||||
if (memcmp(in, raw_header, RAW_HDR_IDENT_LEN) == 0
|
||||
&& in[RAW_HDR_CMD] == RAW_HDR_CMD_LOGIN
|
||||
&& memcmp(&in[RAW_HDR_LEN], hash, sizeof(hash)) == 0
|
||||
&& in[16 + RAW_HDR_LEN] == userid) {
|
||||
&& RAW_HDR_GET_CMD(in) == RAW_HDR_CMD_LOGIN
|
||||
&& memcmp(&in[RAW_HDR_LEN], hash, sizeof(hash)) == 0) {
|
||||
|
||||
fprintf(stderr, "OK\n");
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -761,7 +773,7 @@ handshake_raw_udp(int dns_fd, int seed)
|
|||
}
|
||||
|
||||
fprintf(stderr, "failed\n");
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1016,22 +1028,24 @@ handshake(int dns_fd, int autodetect_frag_size, int fragsize)
|
|||
return r;
|
||||
}
|
||||
|
||||
handshake_raw_udp(dns_fd, seed);
|
||||
if (handshake_raw_udp(dns_fd, seed)) {
|
||||
conn = CONN_RAW_UDP;
|
||||
} else {
|
||||
case_preserved = handshake_case_check(dns_fd);
|
||||
|
||||
case_preserved = handshake_case_check(dns_fd);
|
||||
|
||||
if (case_preserved) {
|
||||
handshake_switch_codec(dns_fd);
|
||||
}
|
||||
|
||||
if (autodetect_frag_size) {
|
||||
fragsize = handshake_autoprobe_fragsize(dns_fd);
|
||||
if (!fragsize) {
|
||||
return 1;
|
||||
if (case_preserved) {
|
||||
handshake_switch_codec(dns_fd);
|
||||
}
|
||||
}
|
||||
|
||||
handshake_set_fragsize(dns_fd, fragsize);
|
||||
if (autodetect_frag_size) {
|
||||
fragsize = handshake_autoprobe_fragsize(dns_fd);
|
||||
if (!fragsize) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
handshake_set_fragsize(dns_fd, fragsize);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1178,6 +1192,7 @@ main(int argc, char **argv)
|
|||
|
||||
b32 = get_base32_encoder();
|
||||
dataenc = get_base32_encoder();
|
||||
conn = CONN_DNS_NULL;
|
||||
|
||||
retval = 0;
|
||||
|
||||
|
@ -1312,7 +1327,11 @@ main(int argc, char **argv)
|
|||
goto cleanup2;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Sending queries for %s to %s\n", topdomain, nameserv_addr);
|
||||
if (conn == CONN_DNS_NULL) {
|
||||
fprintf(stderr, "Sending queries for %s to %s\n", topdomain, nameserv_addr);
|
||||
} else {
|
||||
fprintf(stderr, "Sending raw traffic directly to %s\n", inet_ntoa(raw_serv.sin_addr));
|
||||
}
|
||||
|
||||
if (foreground == 0)
|
||||
do_detach();
|
||||
|
|
153
src/iodined.c
153
src/iodined.c
|
@ -85,8 +85,9 @@ static int debug;
|
|||
static char *__progname;
|
||||
#endif
|
||||
|
||||
static int read_dns(int, struct query *);
|
||||
static int read_dns(int, int, struct query *);
|
||||
static void write_dns(int, struct query *, char *, int);
|
||||
static void handle_full_packet(int, int);
|
||||
|
||||
static void
|
||||
sigint(int sig)
|
||||
|
@ -295,15 +296,12 @@ static void
|
|||
handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
|
||||
{
|
||||
struct in_addr tempip;
|
||||
struct ip *hdr;
|
||||
unsigned long outlen;
|
||||
char in[512];
|
||||
char logindata[16];
|
||||
char out[64*1024];
|
||||
char unpacked[64*1024];
|
||||
char *tmp[2];
|
||||
int userid;
|
||||
int touser;
|
||||
int version;
|
||||
int code;
|
||||
int read;
|
||||
|
@ -589,30 +587,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
|
|||
}
|
||||
|
||||
if (lastfrag & 1) { /* packet is complete */
|
||||
int ret;
|
||||
outlen = sizeof(out);
|
||||
ret = uncompress((uint8_t*)out, &outlen,
|
||||
(uint8_t*)users[userid].inpacket.data, users[userid].inpacket.len);
|
||||
|
||||
if (ret == Z_OK) {
|
||||
hdr = (struct ip*) (out + 4);
|
||||
touser = find_user_by_ip(hdr->ip_dst.s_addr);
|
||||
|
||||
if (touser == -1) {
|
||||
/* send the uncompressed packet to tun device */
|
||||
write_tun(tun_fd, out, outlen);
|
||||
} else {
|
||||
/* send the compressed packet to other client
|
||||
* if another packet is queued, throw away this one. TODO build queue */
|
||||
if (users[touser].outpacket.len == 0) {
|
||||
memcpy(users[touser].outpacket.data, users[userid].inpacket.data, users[userid].inpacket.len);
|
||||
users[touser].outpacket.len = users[userid].inpacket.len;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Discarded data, uncompress() result: %d\n", ret);
|
||||
}
|
||||
users[userid].inpacket.len = users[userid].inpacket.offset = 0;
|
||||
handle_full_packet(tun_fd, userid);
|
||||
}
|
||||
/* Update seqno and maybe send immediate response packet */
|
||||
update_downstream_seqno(dns_fd, userid, dn_seq, dn_frag);
|
||||
|
@ -730,7 +705,7 @@ tunnel_dns(int tun_fd, int dns_fd, int bind_fd)
|
|||
int domain_len;
|
||||
int inside_topdomain;
|
||||
|
||||
if ((read = read_dns(dns_fd, &q)) <= 0)
|
||||
if ((read = read_dns(dns_fd, tun_fd, &q)) <= 0)
|
||||
return 0;
|
||||
|
||||
if (debug >= 2) {
|
||||
|
@ -820,15 +795,15 @@ tunnel(int tun_fd, int dns_fd, int bind_fd)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if(FD_ISSET(tun_fd, &fds)) {
|
||||
if (FD_ISSET(tun_fd, &fds)) {
|
||||
tunnel_tun(tun_fd, dns_fd);
|
||||
continue;
|
||||
}
|
||||
if(FD_ISSET(dns_fd, &fds)) {
|
||||
if (FD_ISSET(dns_fd, &fds)) {
|
||||
tunnel_dns(tun_fd, dns_fd, bind_fd);
|
||||
continue;
|
||||
}
|
||||
if(FD_ISSET(bind_fd, &fds)) {
|
||||
if (FD_ISSET(bind_fd, &fds)) {
|
||||
tunnel_bind(bind_fd, dns_fd);
|
||||
continue;
|
||||
}
|
||||
|
@ -839,7 +814,42 @@ tunnel(int tun_fd, int dns_fd, int bind_fd)
|
|||
}
|
||||
|
||||
static void
|
||||
send_raw(int fd, char *buf, int buflen, int cmd, struct query *q)
|
||||
handle_full_packet(int tun_fd, int userid)
|
||||
{
|
||||
unsigned long outlen;
|
||||
char out[64*1024];
|
||||
int touser;
|
||||
int ret;
|
||||
|
||||
outlen = sizeof(out);
|
||||
ret = uncompress((uint8_t*)out, &outlen,
|
||||
(uint8_t*)users[userid].inpacket.data, users[userid].inpacket.len);
|
||||
|
||||
if (ret == Z_OK) {
|
||||
struct ip *hdr;
|
||||
|
||||
hdr = (struct ip*) (out + 4);
|
||||
touser = find_user_by_ip(hdr->ip_dst.s_addr);
|
||||
|
||||
if (touser == -1) {
|
||||
/* send the uncompressed packet to tun device */
|
||||
write_tun(tun_fd, out, outlen);
|
||||
} else {
|
||||
/* send the compressed packet to other client
|
||||
* if another packet is queued, throw away this one. TODO build queue */
|
||||
if (users[touser].outpacket.len == 0) {
|
||||
memcpy(users[touser].outpacket.data, users[userid].inpacket.data, users[userid].inpacket.len);
|
||||
users[touser].outpacket.len = users[userid].inpacket.len;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Discarded data, uncompress() result: %d\n", ret);
|
||||
}
|
||||
users[userid].inpacket.len = users[userid].inpacket.offset = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
send_raw(int fd, char *buf, int buflen, int user, int cmd, struct query *q)
|
||||
{
|
||||
char packet[4096];
|
||||
int len;
|
||||
|
@ -850,51 +860,96 @@ send_raw(int fd, char *buf, int buflen, int cmd, struct query *q)
|
|||
memcpy(&packet[RAW_HDR_LEN], buf, len);
|
||||
|
||||
len += RAW_HDR_LEN;
|
||||
packet[RAW_HDR_CMD] = cmd;
|
||||
packet[RAW_HDR_CMD] = cmd | (user & 0x0F);
|
||||
|
||||
sendto(fd, packet, len, 0, &q->from, q->fromlen);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_raw_login(char *packet, int len, struct query *q, int fd)
|
||||
handle_raw_login(char *packet, int len, struct query *q, int fd, int userid)
|
||||
{
|
||||
int userid;
|
||||
char myhash[16];
|
||||
|
||||
if (len < 17) return;
|
||||
if (len < 16) return;
|
||||
|
||||
userid = packet[16];
|
||||
if (userid < 0 || userid > created_users) return;
|
||||
if (!users[userid].active) return;
|
||||
|
||||
/* User sends hash of seed + 1 */
|
||||
login_calculate(myhash, 16, password, users[userid].seed + 1);
|
||||
if (memcmp(packet, myhash, 16) == 0) {
|
||||
struct sockaddr_in *tempin;
|
||||
|
||||
/* Update query and time info for user */
|
||||
users[userid].last_pkt = time(NULL);
|
||||
memcpy(&(users[userid].q), q, sizeof(struct query));
|
||||
|
||||
/* Store remote IP number */
|
||||
tempin = (struct sockaddr_in *) &(q->from);
|
||||
memcpy(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr));
|
||||
|
||||
/* Correct hash, reply with hash of seed - 1 */
|
||||
user_set_conn_type(userid, CONN_RAW_UDP);
|
||||
users[userid].last_pkt = time(NULL);
|
||||
login_calculate(myhash, 16, password, users[userid].seed - 1);
|
||||
memcpy(packet, myhash, 16);
|
||||
send_raw(fd, packet, 17, RAW_HDR_CMD_LOGIN, q);
|
||||
send_raw(fd, myhash, 16, userid, RAW_HDR_CMD_LOGIN, q);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
raw_decode(char *packet, int len, struct query *q, int fd)
|
||||
static void
|
||||
handle_raw_data(char *packet, int len, struct query *q, int dns_fd, int tun_fd, int userid)
|
||||
{
|
||||
if (check_user_and_ip(userid, q) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update query and time info for user */
|
||||
users[userid].last_pkt = time(NULL);
|
||||
memcpy(&(users[userid].q), q, sizeof(struct query));
|
||||
|
||||
/* copy to packet buffer, update length */
|
||||
users[userid].inpacket.offset = 0;
|
||||
memcpy(users[userid].inpacket.data, packet, len);
|
||||
users[userid].inpacket.len = len;
|
||||
|
||||
if (debug >= 1) {
|
||||
fprintf(stderr, "IN pkt raw, total %d, from user %d\n",
|
||||
users[userid].inpacket.len, userid);
|
||||
}
|
||||
|
||||
handle_full_packet(tun_fd, userid);
|
||||
}
|
||||
|
||||
static int
|
||||
raw_decode(char *packet, int len, struct query *q, int dns_fd, int tun_fd)
|
||||
{
|
||||
int raw_user;
|
||||
|
||||
/* minimum length */
|
||||
if (len < RAW_HDR_LEN) return 0;
|
||||
/* should start with header */
|
||||
if (memcmp(packet, raw_header, RAW_HDR_IDENT_LEN)) return 0;
|
||||
|
||||
if (packet[RAW_HDR_CMD] == RAW_HDR_CMD_LOGIN) {
|
||||
handle_raw_login(&packet[RAW_HDR_LEN], len - RAW_HDR_LEN, q, fd);
|
||||
} else {
|
||||
warnx("Unhandled raw command %02X\n", packet[RAW_HDR_CMD]);
|
||||
raw_user = RAW_HDR_GET_USR(packet);
|
||||
printf("raw %02x\n", packet[RAW_HDR_CMD]);
|
||||
switch (RAW_HDR_GET_CMD(packet)) {
|
||||
case RAW_HDR_CMD_LOGIN:
|
||||
/* Login challenge */
|
||||
handle_raw_login(&packet[RAW_HDR_LEN], len - RAW_HDR_LEN, q, dns_fd, raw_user);
|
||||
break;
|
||||
case RAW_HDR_CMD_DATA:
|
||||
/* Data packet */
|
||||
handle_raw_data(&packet[RAW_HDR_LEN], len - RAW_HDR_LEN, q, dns_fd, tun_fd, raw_user);
|
||||
break;
|
||||
default:
|
||||
warnx("Unhandled raw command %02X from user %d", RAW_HDR_GET_CMD(packet), raw_user);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
read_dns(int fd, struct query *q)
|
||||
read_dns(int fd, int tun_fd, struct query *q) /* FIXME: tun_fd is because of raw_decode() below */
|
||||
{
|
||||
struct sockaddr_in from;
|
||||
socklen_t addrlen;
|
||||
|
@ -929,7 +984,7 @@ read_dns(int fd, struct query *q)
|
|||
q->fromlen = addrlen;
|
||||
|
||||
/* TODO do not handle raw packets here! */
|
||||
if (raw_decode(packet, r, q, fd)) {
|
||||
if (raw_decode(packet, r, q, fd, tun_fd)) {
|
||||
return 0;
|
||||
}
|
||||
if (dns_decode(NULL, 0, q, QR_QUERY, packet, r) < 0) {
|
||||
|
@ -1177,7 +1232,7 @@ main(int argc, char **argv)
|
|||
}
|
||||
|
||||
topdomain = strdup(argv[1]);
|
||||
if(strlen(topdomain) <= 128) {
|
||||
if (strlen(topdomain) <= 128) {
|
||||
if(check_topdomain(topdomain)) {
|
||||
warnx("Topdomain contains invalid characters.");
|
||||
usage();
|
||||
|
|
16
src/user.c
16
src/user.c
|
@ -90,6 +90,7 @@ init_users(in_addr_t my_ip, int netbits)
|
|||
users[i].out_acked_seqno = 0;
|
||||
users[i].out_acked_fragment = 0;
|
||||
users[i].fragsize = 4096;
|
||||
users[i].conn = CONN_DNS_NULL;
|
||||
}
|
||||
|
||||
return created_users;
|
||||
|
@ -161,6 +162,8 @@ find_available_user()
|
|||
if ((!users[i].active || users[i].last_pkt + 60 < time(NULL)) && !users[i].disabled) {
|
||||
users[i].active = 1;
|
||||
users[i].last_pkt = time(NULL);
|
||||
users[i].fragsize = 4096;
|
||||
users[i].conn = CONN_DNS_NULL;
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
|
@ -176,3 +179,16 @@ user_switch_codec(int userid, struct encoder *enc)
|
|||
|
||||
users[userid].encoder = enc;
|
||||
}
|
||||
|
||||
void
|
||||
user_set_conn_type(int userid, enum connection c)
|
||||
{
|
||||
if (userid < 0 || userid >= USERS)
|
||||
return;
|
||||
|
||||
if (c < 0 || c >= CONN_MAX)
|
||||
return;
|
||||
|
||||
users[userid].conn = c;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ struct user {
|
|||
int out_acked_seqno;
|
||||
int out_acked_fragment;
|
||||
int fragsize;
|
||||
enum connection conn;
|
||||
};
|
||||
|
||||
extern struct user users[USERS];
|
||||
|
@ -44,5 +45,6 @@ int find_user_by_ip(uint32_t);
|
|||
int all_users_waiting_to_send();
|
||||
int find_available_user();
|
||||
void user_switch_codec(int userid, struct encoder *enc);
|
||||
void user_set_conn_type(int userid, enum connection c);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue