1
0
mirror of https://github.com/yarrick/iodine.git synced 2024-11-25 14:36:05 +03:00

Prepare server code for IPv6 listening socket

Add a struct with multiple dns file descriptors (for IPv4 and IPv6)
and pass this to required areas. Choose which descriptor to use when
sending by looking at the destination address family.
This commit is contained in:
Erik Ekman 2015-06-28 12:54:35 +02:00
parent 3069665646
commit 07c2fd4068

View File

@ -95,12 +95,31 @@ static int debug;
static char *__progname; static char *__progname;
#endif #endif
static int read_dns(int, int, struct query *); /* Struct with IPv4 and IPv6 file descriptors.
static void write_dns(int, struct query *, char *, int, char); * Need to be passed on down to tunneling code since we can get a
static void handle_full_packet(int, int, int); * packet on one fd meant for a user on the other.
*/
struct dnsfd {
int v4fd;
int v6fd;
};
static int read_dns(int fd, struct dnsfd *dns_fds, int tun_fd, struct query *q);
static void write_dns(int fd, struct query *q, char *data, int datalen, char downenc);
static void handle_full_packet(int tun_fd, struct dnsfd *dns_fds, int userid);
static int
get_dns_fd(struct dnsfd *fds, struct sockaddr_storage *addr)
{
if (addr->ss_family == AF_INET6) {
return fds->v6fd;
}
return fds->v4fd;
}
/* Ask ipify.org webservice to get external ip */ /* Ask ipify.org webservice to get external ip */
static int get_external_ip(struct in_addr *ip) static int
get_external_ip(struct in_addr *ip)
{ {
int sock; int sock;
struct addrinfo *addr; struct addrinfo *addr;
@ -624,7 +643,7 @@ send_chunk_or_dataless(int dns_fd, int userid, struct query *q)
} }
static int static int
tunnel_tun(int tun_fd, int dns_fd) tunnel_tun(int tun_fd, struct dnsfd *dns_fds)
{ {
unsigned long outlen; unsigned long outlen;
struct ip *header; struct ip *header;
@ -659,13 +678,17 @@ tunnel_tun(int tun_fd, int dns_fd)
start_new_outpacket(userid, out, outlen); start_new_outpacket(userid, out, outlen);
/* Start sending immediately if query is waiting */ /* Start sending immediately if query is waiting */
if (users[userid].q_sendrealsoon.id != 0) if (users[userid].q_sendrealsoon.id != 0) {
int dns_fd = get_dns_fd(dns_fds, &users[userid].q_sendrealsoon.from);
send_chunk_or_dataless(dns_fd, userid, &users[userid].q_sendrealsoon); send_chunk_or_dataless(dns_fd, userid, &users[userid].q_sendrealsoon);
else if (users[userid].q.id != 0) } else if (users[userid].q.id != 0) {
int dns_fd = get_dns_fd(dns_fds, &users[userid].q.from);
send_chunk_or_dataless(dns_fd, userid, &users[userid].q); send_chunk_or_dataless(dns_fd, userid, &users[userid].q);
}
return outlen; return outlen;
} else { /* CONN_RAW_UDP */ } else { /* CONN_RAW_UDP */
int dns_fd = get_dns_fd(dns_fds, &users[userid].q.from);
send_raw(dns_fd, out, outlen, userid, RAW_HDR_CMD_DATA, &users[userid].q); send_raw(dns_fd, out, outlen, userid, RAW_HDR_CMD_DATA, &users[userid].q);
return outlen; return outlen;
} }
@ -742,7 +765,7 @@ process_downstream_ack(int userid, int down_seq, int down_frag)
} }
static void static void
handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query *q, int domain_len)
{ {
struct in_addr tempip; struct in_addr tempip;
char in[512]; char in[512];
@ -1420,7 +1443,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
} }
if (upstream_ok && lastfrag) { /* packet is complete */ if (upstream_ok && lastfrag) { /* packet is complete */
handle_full_packet(tun_fd, dns_fd, userid); handle_full_packet(tun_fd, dns_fds, userid);
} }
/* If there is a query that must be returned real soon, do it. /* If there is a query that must be returned real soon, do it.
@ -1594,13 +1617,14 @@ forward_query(int bind_fd, struct query *q)
} }
static int static int
tunnel_bind(int bind_fd, int dns_fd) tunnel_bind(int bind_fd, struct dnsfd *dns_fds)
{ {
char packet[64*1024]; char packet[64*1024];
struct sockaddr_storage from; struct sockaddr_storage from;
socklen_t fromlen; socklen_t fromlen;
struct fw_query *query; struct fw_query *query;
unsigned short id; unsigned short id;
int dns_fd;
int r; int r;
fromlen = sizeof(struct sockaddr); fromlen = sizeof(struct sockaddr);
@ -1630,6 +1654,7 @@ tunnel_bind(int bind_fd, int dns_fd)
format_addr(&query->addr, query->addrlen), (id & 0xffff), r); format_addr(&query->addr, query->addrlen), (id & 0xffff), r);
} }
dns_fd = get_dns_fd(dns_fds, &query->addr);
if (sendto(dns_fd, packet, r, 0, (const struct sockaddr *) &(query->addr), if (sendto(dns_fd, packet, r, 0, (const struct sockaddr *) &(query->addr),
query->addrlen) <= 0) { query->addrlen) <= 0) {
warn("forward reply error"); warn("forward reply error");
@ -1639,14 +1664,14 @@ tunnel_bind(int bind_fd, int dns_fd)
} }
static int static int
tunnel_dns(int tun_fd, int dns_fd, int bind_fd) tunnel_dns(int tun_fd, int dns_fd, struct dnsfd *dns_fds, int bind_fd)
{ {
struct query q; struct query q;
int read; int read;
int domain_len; int domain_len;
int inside_topdomain = 0; int inside_topdomain = 0;
if ((read = read_dns(dns_fd, tun_fd, &q)) <= 0) if ((read = read_dns(dns_fd, dns_fds, tun_fd, &q)) <= 0)
return 0; return 0;
if (debug >= 2) { if (debug >= 2) {
@ -1694,7 +1719,7 @@ tunnel_dns(int tun_fd, int dns_fd, int bind_fd)
case T_SRV: case T_SRV:
case T_TXT: case T_TXT:
/* encoding is "transparent" here */ /* encoding is "transparent" here */
handle_null_request(tun_fd, dns_fd, &q, domain_len); handle_null_request(tun_fd, dns_fd, dns_fds, &q, domain_len);
break; break;
case T_NS: case T_NS:
handle_ns_request(dns_fd, &q); handle_ns_request(dns_fd, &q);
@ -1712,7 +1737,7 @@ tunnel_dns(int tun_fd, int dns_fd, int bind_fd)
} }
static int static int
tunnel(int tun_fd, int dns_fd, int bind_fd, int max_idle_time) tunnel(int tun_fd, struct dnsfd *dns_fds, int bind_fd, int max_idle_time)
{ {
struct timeval tv; struct timeval tv;
fd_set fds; fd_set fds;
@ -1745,8 +1770,8 @@ tunnel(int tun_fd, int dns_fd, int bind_fd, int max_idle_time)
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(dns_fd, &fds); FD_SET(dns_fds->v4fd, &fds);
maxfd = dns_fd; maxfd = dns_fds->v4fd;
if (bind_fd) { if (bind_fd) {
/* wait for replies from real DNS */ /* wait for replies from real DNS */
@ -1783,15 +1808,15 @@ tunnel(int tun_fd, int dns_fd, int bind_fd, int max_idle_time)
} }
} }
} }
} else { } else {
if (FD_ISSET(tun_fd, &fds)) { if (FD_ISSET(tun_fd, &fds)) {
tunnel_tun(tun_fd, dns_fd); tunnel_tun(tun_fd, dns_fds);
} }
if (FD_ISSET(dns_fd, &fds)) { if (FD_ISSET(dns_fds->v4fd, &fds)) {
tunnel_dns(tun_fd, dns_fd, bind_fd); tunnel_dns(tun_fd, dns_fds->v4fd, dns_fds, bind_fd);
} }
if (FD_ISSET(bind_fd, &fds)) { if (FD_ISSET(bind_fd, &fds)) {
tunnel_bind(bind_fd, dns_fd); tunnel_bind(bind_fd, dns_fds);
} }
} }
@ -1801,15 +1826,17 @@ tunnel(int tun_fd, int dns_fd, int bind_fd, int max_idle_time)
users[userid].last_pkt + 60 > time(NULL) && users[userid].last_pkt + 60 > time(NULL) &&
users[userid].q_sendrealsoon.id != 0 && users[userid].q_sendrealsoon.id != 0 &&
users[userid].conn == CONN_DNS_NULL && users[userid].conn == CONN_DNS_NULL &&
!users[userid].q_sendrealsoon_new) !users[userid].q_sendrealsoon_new) {
int dns_fd = get_dns_fd(dns_fds, &users[userid].q_sendrealsoon.from);
send_chunk_or_dataless(dns_fd, userid, &users[userid].q_sendrealsoon); send_chunk_or_dataless(dns_fd, userid, &users[userid].q_sendrealsoon);
}
} }
return 0; return 0;
} }
static void static void
handle_full_packet(int tun_fd, int dns_fd, int userid) handle_full_packet(int tun_fd, struct dnsfd *dns_fds, int userid)
{ {
unsigned long outlen; unsigned long outlen;
char out[64*1024]; char out[64*1024];
@ -1838,10 +1865,13 @@ handle_full_packet(int tun_fd, int dns_fd, int userid)
users[userid].inpacket.len); users[userid].inpacket.len);
/* Start sending immediately if query is waiting */ /* Start sending immediately if query is waiting */
if (users[touser].q_sendrealsoon.id != 0) if (users[touser].q_sendrealsoon.id != 0) {
int dns_fd = get_dns_fd(dns_fds, &users[touser].q_sendrealsoon.from);
send_chunk_or_dataless(dns_fd, touser, &users[touser].q_sendrealsoon); send_chunk_or_dataless(dns_fd, touser, &users[touser].q_sendrealsoon);
else if (users[touser].q.id != 0) } else if (users[touser].q.id != 0) {
int dns_fd = get_dns_fd(dns_fds, &users[touser].q.from);
send_chunk_or_dataless(dns_fd, touser, &users[touser].q); send_chunk_or_dataless(dns_fd, touser, &users[touser].q);
}
#ifdef OUTPACKETQ_LEN #ifdef OUTPACKETQ_LEN
} else { } else {
save_to_outpacketq(touser, save_to_outpacketq(touser,
@ -1850,6 +1880,7 @@ handle_full_packet(int tun_fd, int dns_fd, int userid)
#endif #endif
} }
} else{ /* CONN_RAW_UDP */ } else{ /* CONN_RAW_UDP */
int dns_fd = get_dns_fd(dns_fds, &users[touser].q.from);
send_raw(dns_fd, users[userid].inpacket.data, send_raw(dns_fd, users[userid].inpacket.data,
users[userid].inpacket.len, touser, users[userid].inpacket.len, touser,
RAW_HDR_CMD_DATA, &users[touser].q); RAW_HDR_CMD_DATA, &users[touser].q);
@ -1905,7 +1936,7 @@ handle_raw_login(char *packet, int len, struct query *q, int fd, int userid)
} }
static void static void
handle_raw_data(char *packet, int len, struct query *q, int dns_fd, int tun_fd, int userid) handle_raw_data(char *packet, int len, struct query *q, struct dnsfd *dns_fds, int tun_fd, int userid)
{ {
if (check_authenticated_user_and_ip(userid, q) != 0) { if (check_authenticated_user_and_ip(userid, q) != 0) {
return; return;
@ -1926,7 +1957,7 @@ handle_raw_data(char *packet, int len, struct query *q, int dns_fd, int tun_fd,
users[userid].inpacket.len, userid); users[userid].inpacket.len, userid);
} }
handle_full_packet(tun_fd, dns_fd, userid); handle_full_packet(tun_fd, dns_fds, userid);
} }
static void static void
@ -1950,7 +1981,7 @@ handle_raw_ping(struct query *q, int dns_fd, int userid)
} }
static int static int
raw_decode(char *packet, int len, struct query *q, int dns_fd, int tun_fd) raw_decode(char *packet, int len, struct query *q, int dns_fd, struct dnsfd *dns_fds, int tun_fd)
{ {
int raw_user; int raw_user;
@ -1967,7 +1998,7 @@ raw_decode(char *packet, int len, struct query *q, int dns_fd, int tun_fd)
break; break;
case RAW_HDR_CMD_DATA: case RAW_HDR_CMD_DATA:
/* Data packet */ /* Data packet */
handle_raw_data(&packet[RAW_HDR_LEN], len - RAW_HDR_LEN, q, dns_fd, tun_fd, raw_user); handle_raw_data(&packet[RAW_HDR_LEN], len - RAW_HDR_LEN, q, dns_fds, tun_fd, raw_user);
break; break;
case RAW_HDR_CMD_PING: case RAW_HDR_CMD_PING:
/* Keepalive packet */ /* Keepalive packet */
@ -1981,7 +2012,8 @@ raw_decode(char *packet, int len, struct query *q, int dns_fd, int tun_fd)
} }
static int static int
read_dns(int fd, int tun_fd, struct query *q) /* FIXME: tun_fd is because of raw_decode() below */ read_dns(int fd, struct dnsfd *dns_fds, int tun_fd, struct query *q)
/* FIXME: dns_fds and tun_fd are because of raw_decode() below */
{ {
struct sockaddr_in from; struct sockaddr_in from;
socklen_t addrlen; socklen_t addrlen;
@ -2016,7 +2048,7 @@ read_dns(int fd, int tun_fd, struct query *q) /* FIXME: tun_fd is because of raw
q->fromlen = addrlen; q->fromlen = addrlen;
/* TODO do not handle raw packets here! */ /* TODO do not handle raw packets here! */
if (raw_decode(packet, r, q, fd, tun_fd)) { if (raw_decode(packet, r, q, fd, dns_fds, tun_fd)) {
return 0; return 0;
} }
if (dns_decode(NULL, 0, q, QR_QUERY, packet, r) < 0) { if (dns_decode(NULL, 0, q, QR_QUERY, packet, r) < 0) {
@ -2262,7 +2294,7 @@ int
main(int argc, char **argv) main(int argc, char **argv)
{ {
extern char *__progname; extern char *__progname;
char *listen_ip; char *listen_ip4;
char *errormsg; char *errormsg;
#ifndef WINDOWS32 #ifndef WINDOWS32
struct passwd *pw; struct passwd *pw;
@ -2273,7 +2305,7 @@ main(int argc, char **argv)
char *context; char *context;
char *device; char *device;
char *pidfile; char *pidfile;
int dnsd_fd; struct dnsfd dns_fds;
int tun_fd; int tun_fd;
/* settings for forwarding normal DNS to /* settings for forwarding normal DNS to
@ -2289,8 +2321,8 @@ main(int argc, char **argv)
int ns_get_externalip; int ns_get_externalip;
int retval; int retval;
int max_idle_time = 0; int max_idle_time = 0;
struct sockaddr_storage dnsaddr; struct sockaddr_storage dns4addr;
int dnsaddr_len; int dns4addr_len;
#ifdef HAVE_SYSTEMD #ifdef HAVE_SYSTEMD
int nb_fds; int nb_fds;
#endif #endif
@ -2308,7 +2340,7 @@ main(int argc, char **argv)
bind_fd = 0; bind_fd = 0;
mtu = 1130; /* Very many relays give fragsize 1150 or slightly mtu = 1130; /* Very many relays give fragsize 1150 or slightly
higher for NULL; tun/zlib adds ~17 bytes. */ higher for NULL; tun/zlib adds ~17 bytes. */
listen_ip = NULL; listen_ip4 = NULL;
port = 53; port = 53;
ns_ip = INADDR_ANY; ns_ip = INADDR_ANY;
ns_get_externalip = 0; ns_get_externalip = 0;
@ -2374,7 +2406,7 @@ main(int argc, char **argv)
mtu = atoi(optarg); mtu = atoi(optarg);
break; break;
case 'l': case 'l':
listen_ip = optarg; listen_ip4 = optarg;
break; break;
case 'p': case 'p':
port = atoi(optarg); port = atoi(optarg);
@ -2471,14 +2503,14 @@ main(int argc, char **argv)
foreground = 1; foreground = 1;
} }
dnsaddr_len = get_addr(listen_ip, port, AF_INET, AI_PASSIVE | AI_NUMERICHOST, &dnsaddr); dns4addr_len = get_addr(listen_ip4, port, AF_INET, AI_PASSIVE | AI_NUMERICHOST, &dns4addr);
if (dnsaddr_len < 0) { if (dns4addr_len < 0) {
warnx("Bad IP address to listen on."); warnx("Bad IP address to listen on.");
usage(); usage();
} }
if(bind_enable) { if(bind_enable) {
in_addr_t dns_ip = ((struct sockaddr_in *) &dnsaddr)->sin_addr.s_addr; in_addr_t dns_ip = ((struct sockaddr_in *) &dns4addr)->sin_addr.s_addr;
if (bind_port < 1 || bind_port > 65535) { if (bind_port < 1 || bind_port > 65535) {
warnx("Bad DNS server port number given."); warnx("Bad DNS server port number given.");
usage(); usage();
@ -2526,30 +2558,36 @@ main(int argc, char **argv)
if ((tun_fd = open_tun(device)) == -1) { if ((tun_fd = open_tun(device)) == -1) {
retval = 1; retval = 1;
goto cleanup0; goto cleanup_none;
} }
if (!skipipconfig) { if (!skipipconfig) {
const char *other_ip = users_get_first_ip(); const char *other_ip = users_get_first_ip();
if (tun_setip(argv[0], other_ip, netmask) != 0 || tun_setmtu(mtu) != 0) { if (tun_setip(argv[0], other_ip, netmask) != 0 || tun_setmtu(mtu) != 0) {
retval = 1; retval = 1;
free((void*) other_ip); free((void*) other_ip);
goto cleanup1; goto cleanup_tun;
} }
free((void*) other_ip); free((void*) other_ip);
} }
/* Mark both file descriptors as unused */
dns_fds.v4fd = -1;
dns_fds.v6fd = -1;
#ifdef HAVE_SYSTEMD #ifdef HAVE_SYSTEMD
nb_fds = sd_listen_fds(0); nb_fds = sd_listen_fds(0);
if (nb_fds > 1) { if (nb_fds > 1) {
retval = 1; retval = 1;
warnx("Too many file descriptors received!\n"); warnx("Too many file descriptors received!\n");
goto cleanup1; goto cleanup_tun;
} else if (nb_fds == 1) { } else if (nb_fds == 1) {
dnsd_fd = SD_LISTEN_FDS_START; /* XXX: assume we get IPv4 socket */
dns_fds.v4fd = SD_LISTEN_FDS_START;
} else { } else {
#endif #endif
if ((dnsd_fd = open_dns(&dnsaddr, dnsaddr_len)) < 0) { if ((dns_fds.v4fd = open_dns(&dns4addr, dns4addr_len)) < 0) {
retval = 1; retval = 1;
goto cleanup2; goto cleanup_tun;
} }
#ifdef HAVE_SYSTEMD #ifdef HAVE_SYSTEMD
} }
@ -2557,7 +2595,7 @@ main(int argc, char **argv)
if (bind_enable) { if (bind_enable) {
if ((bind_fd = open_dns_from_host(NULL, 0, AF_INET, 0)) < 0) { if ((bind_fd = open_dns_from_host(NULL, 0, AF_INET, 0)) < 0) {
retval = 1; retval = 1;
goto cleanup3; goto cleanup_dns4;
} }
} }
@ -2602,16 +2640,16 @@ main(int argc, char **argv)
syslog(LOG_INFO, "started, listening on port %d", port); syslog(LOG_INFO, "started, listening on port %d", port);
tunnel(tun_fd, dnsd_fd, bind_fd, max_idle_time); tunnel(tun_fd, &dns_fds, bind_fd, max_idle_time);
syslog(LOG_INFO, "stopping"); syslog(LOG_INFO, "stopping");
cleanup3:
close_dns(bind_fd); close_dns(bind_fd);
cleanup2: cleanup_dns4:
close_dns(dnsd_fd); if (dns_fds.v4fd >= 0)
cleanup1: close_dns(dns_fds.v4fd);
cleanup_tun:
close_tun(tun_fd); close_tun(tun_fd);
cleanup0: cleanup_none:
return retval; return retval;
} }