mirror of
https://github.com/yarrick/iodine.git
synced 2025-04-03 13:23:35 +03:00
Merge ab7e5b8656
into 1df7d235f5
This commit is contained in:
commit
98c71c3593
13 changed files with 508 additions and 29 deletions
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2006-2020 iodine authors
|
||||
Copyright (c) 2006-2021 iodine authors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
|
|
10
README.md
10
README.md
|
@ -123,7 +123,7 @@ end of the tunnel. In this case, `ping 192.168.99.1` from the iodine client, and
|
|||
### MISC. INFO
|
||||
|
||||
#### IPv6
|
||||
The data inside the tunnel is IPv4 only.
|
||||
The data inside the tunnel may be IPv4 or IPv6.
|
||||
|
||||
The server listens to both IPv4 and IPv6 for incoming requests by default.
|
||||
Use options `-4` or `-6` to only listen on one protocol. Raw mode will be
|
||||
|
@ -141,6 +141,14 @@ to your DNS setup. Extending the example above would look like this:
|
|||
t1ns IN A 10.15.213.99
|
||||
t1ns IN AAAA 2001:db8::1001:99
|
||||
|
||||
On the server, specify -S followed by an IPv6 address that will be the server end
|
||||
of the IPv6 pool to allocate to clients. The server only supports a /64 subnet
|
||||
mask, which is assumed and can be omitted. The first 64 bits are the network from
|
||||
which IPv6 addresses are allocated from.
|
||||
|
||||
The client will automatically check for IPv6 capability on the server and
|
||||
assign the allocated address to its tunnel interface. No flags are needed.
|
||||
|
||||
#### Routing
|
||||
It is possible to route all traffic through the DNS tunnel. To do this, first
|
||||
add a host route to the nameserver used by iodine over the wired/wireless
|
||||
|
|
|
@ -9,7 +9,7 @@ ARCH = `uname -m`
|
|||
HEAD_COMMIT = `git rev-parse --short HEAD`
|
||||
|
||||
LIBPATH = -L.
|
||||
LDFLAGS += -lz `sh osflags $(TARGETOS) link` $(LIBPATH)
|
||||
LDFLAGS += -lz `sh osflags $(TARGETOS) link` $(LIBPATH) -lm
|
||||
CFLAGS += -std=c99 -c -g -Wall -D$(OS) -pedantic `sh osflags $(TARGETOS) cflags` -DGITREVISION=\"$(HEAD_COMMIT)\"
|
||||
CFLAGS += -Wstrict-prototypes -Wtype-limits -Wmissing-declarations -Wmissing-prototypes
|
||||
|
||||
|
|
72
src/client.c
72
src/client.c
|
@ -28,6 +28,8 @@
|
|||
#include <fcntl.h>
|
||||
#include <zlib.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
#ifdef WINDOWS32
|
||||
#include "windows.h"
|
||||
|
@ -101,6 +103,7 @@ static time_t lastdownstreamtime;
|
|||
static long send_query_sendcnt = -1;
|
||||
static long send_query_recvcnt = 0;
|
||||
static int hostname_maxlen = 0xFF;
|
||||
static bool use_v6 = false;
|
||||
|
||||
void
|
||||
client_init()
|
||||
|
@ -2414,8 +2417,77 @@ client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsiz
|
|||
handshake_set_fragsize(dns_fd, fragsize);
|
||||
if (!running)
|
||||
return -1;
|
||||
|
||||
handshake_check_v6(dns_fd);
|
||||
if (!running)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void send_v6_probe(int dns_fd)
|
||||
{
|
||||
char data[4096];
|
||||
|
||||
data[0] = userid;
|
||||
|
||||
send_packet(dns_fd, 'g', data, sizeof(data));
|
||||
}
|
||||
|
||||
int
|
||||
handshake_check_v6(int dns_fd)
|
||||
{
|
||||
char in[4096];
|
||||
char server6[INET6_ADDRSTRLEN];
|
||||
char client6[INET6_ADDRSTRLEN];
|
||||
int i;
|
||||
int read;
|
||||
int netmask6 = 0;
|
||||
int length_recieved;
|
||||
|
||||
fprintf(stderr, "Autoprobing server IPV6 tunnel support\n");
|
||||
|
||||
for (i = 0; running && i < 5; i++) {
|
||||
|
||||
send_v6_probe(dns_fd);
|
||||
|
||||
read = handshake_waitdns(dns_fd, in, sizeof(in), 'g', 'G', i+1);
|
||||
|
||||
if (read > 0) {
|
||||
|
||||
/*
|
||||
* including a terminating dash to allow for future IPv6 options, e.g.
|
||||
* netmask. Currently assumes /64. MTU is taken from the IPv4 handshake.
|
||||
* A future IPv6-only implementation would need to pass mtu
|
||||
* in the IPV6 handshake.
|
||||
*/
|
||||
|
||||
if (sscanf(in, "%512[^-]-%512[^-]-%d", server6, client6, &netmask6) == 3) {
|
||||
|
||||
fprintf(stderr, "Server tunnel IPv6 is %s\n", server6);
|
||||
fprintf(stderr, "Local tunnel IPv6 is %s\n", client6);
|
||||
|
||||
length_recieved = strlen(client6);
|
||||
if (length_recieved > 2) {
|
||||
if (tun_setip6(client6, server6, netmask6) == 0) {
|
||||
|
||||
use_v6 = true;
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
errx(4, "Failed to set IPv6 tunnel address");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Received bad IPv6 tunnel handshake\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "Retrying IPv6 tunnel handshake...\n");
|
||||
}
|
||||
if (!running)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -37,5 +37,5 @@ void client_set_hostname_maxlen(int i);
|
|||
int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size,
|
||||
int fragsize);
|
||||
int client_tunnel(int tun_fd, int dns_fd);
|
||||
|
||||
int handshake_check_v6(int tun_fd);
|
||||
#endif
|
||||
|
|
16
src/common.c
16
src/common.c
|
@ -13,6 +13,8 @@
|
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
|
@ -557,3 +559,17 @@ fd_set_close_on_exec(int fd)
|
|||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
isV6AddrSet(struct in6_addr *ip6)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(ip6->s6_addr); i++) {
|
||||
if (ip6->s6_addr[i] != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
extern const unsigned char raw_header[RAW_HDR_LEN];
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#ifdef WINDOWS32
|
||||
#include "windows.h"
|
||||
#else
|
||||
|
@ -129,6 +130,7 @@ void read_password(char*, size_t);
|
|||
int check_topdomain(char *, int, char **);
|
||||
|
||||
int query_datalen(const char *qname, const char *topdomain);
|
||||
bool isV6AddrSet(struct in6_addr *);
|
||||
|
||||
#if defined(WINDOWS32) || defined(ANDROID)
|
||||
#ifndef ANDROID
|
||||
|
|
|
@ -193,6 +193,7 @@ int main(int argc, char **argv)
|
|||
#endif
|
||||
|
||||
while ((choice = getopt(argc, argv, "46vfhru:t:d:R:P:m:M:F:T:O:L:I:")) != -1) {
|
||||
|
||||
switch(choice) {
|
||||
case '4':
|
||||
nameserv_family = AF_INET;
|
||||
|
|
110
src/iodined.c
110
src/iodined.c
|
@ -88,10 +88,16 @@ static int created_users;
|
|||
static int check_ip;
|
||||
static int my_mtu;
|
||||
static in_addr_t my_ip;
|
||||
|
||||
char display_ip6[INET6_ADDRSTRLEN];
|
||||
char *display_ip6_buffer = NULL;
|
||||
char *ip6_netmask_buffer = NULL;
|
||||
|
||||
static struct in6_addr my_ip6;
|
||||
static int netmask;
|
||||
static int ip6_netmask = 64;
|
||||
|
||||
static in_addr_t ns_ip;
|
||||
|
||||
static int bind_port;
|
||||
static int debug;
|
||||
|
||||
|
@ -649,17 +655,32 @@ static int tunnel_tun(int tun_fd, struct dnsfd *dns_fds)
|
|||
char in[64*1024];
|
||||
int userid;
|
||||
int read;
|
||||
|
||||
int ip_version;
|
||||
int c;
|
||||
struct in6_addr v6Addr;
|
||||
char v6AddrP[16];
|
||||
if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0)
|
||||
return 0;
|
||||
|
||||
/* find target ip in packet, in is padded with 4 bytes TUN header */
|
||||
header = (struct ip*) (in + 4);
|
||||
userid = find_user_by_ip(header->ip_dst.s_addr);
|
||||
ip_version = get_ipversion(in[4]);
|
||||
|
||||
if (ip_version == 4) { /* IPv4 */
|
||||
header = (struct ip*) (in + 4);
|
||||
userid = find_user_by_ip(header->ip_dst.s_addr);
|
||||
} else { /* IPv6 */
|
||||
for (c = 0; c < 16; c++) {
|
||||
v6Addr.s6_addr[c] = in[c + 28];
|
||||
}
|
||||
inet_ntop(AF_INET6, &v6Addr, v6AddrP, INET6_ADDRSTRLEN);
|
||||
userid = find_user_by_ip6(&v6Addr);
|
||||
}
|
||||
if (userid < 0)
|
||||
return 0;
|
||||
|
||||
outlen = sizeof(out);
|
||||
|
||||
compress2((uint8_t*)out, &outlen, (uint8_t*)in, read, 9);
|
||||
|
||||
if (users[userid].conn == CONN_DNS_NULL) {
|
||||
|
@ -1289,6 +1310,32 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query
|
|||
!users[userid].lazy)
|
||||
send_chunk_or_dataless(dns_fd, userid, &users[userid].q);
|
||||
|
||||
/* IPv6 tunnel address probe */
|
||||
} else if (in[0] == 'G' || in[0] == 'g') {
|
||||
char client_ip6[INET6_ADDRSTRLEN];
|
||||
char display_my_ip6[INET6_ADDRSTRLEN];
|
||||
|
||||
read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), domain_len - 1, &base32_ops);
|
||||
if (read < 1) {
|
||||
write_dns(dns_fd, q, "BADLEN", 6, 'T');
|
||||
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 */
|
||||
}
|
||||
|
||||
inet_ntop(AF_INET6, &users[userid].tun_ip6, client_ip6, INET6_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &my_ip6, display_my_ip6, INET6_ADDRSTRLEN);
|
||||
read = snprintf(out, sizeof(out), "%s-%s-%d-",
|
||||
display_my_ip6, client_ip6, ip6_netmask);
|
||||
|
||||
write_dns(dns_fd, q, out, read, users[userid].downenc);
|
||||
return;
|
||||
|
||||
} else if ((in[0] >= '0' && in[0] <= '9')
|
||||
|| (in[0] >= 'a' && in[0] <= 'f')
|
||||
|| (in[0] >= 'A' && in[0] <= 'F')) {
|
||||
|
@ -2277,7 +2324,7 @@ static void print_usage(FILE *stream)
|
|||
"Usage: %s [-46cDfsv] [-u user] [-t chrootdir] [-d device] [-m mtu]\n"
|
||||
" [-z context] [-l ipv4 listen address] [-L ipv6 listen address]\n"
|
||||
" [-p port] [-n auto|external_ip] [-b dnsport] [-P password]\n"
|
||||
" [-F pidfile] [-i max idle time] tunnel_ip[/netmask] topdomain\n",
|
||||
" [-F pidfile] [-S ipv6 tunnel address] [-i max idle time] tunnel_ip[/netmask] topdomain\n",
|
||||
__progname);
|
||||
}
|
||||
|
||||
|
@ -2319,6 +2366,7 @@ static void help(FILE *stream)
|
|||
" -b port to forward normal DNS queries to (on localhost)\n"
|
||||
" -P password used for authentication (max 32 chars will be used)\n"
|
||||
" -F pidfile to write pid to a file\n"
|
||||
" -S IPv6 server address within the tunnel. Netmask fixed at /64\n"
|
||||
" -i maximum idle time before shutting down\n\n"
|
||||
"tunnel_ip is the IP number of the local tunnel interface.\n"
|
||||
" /netmask sets the size of the tunnel network.\n"
|
||||
|
@ -2418,7 +2466,6 @@ main(int argc, char **argv)
|
|||
debug = 0;
|
||||
netmask = 27;
|
||||
pidfile = NULL;
|
||||
|
||||
retval = 0;
|
||||
|
||||
#ifdef WINDOWS32
|
||||
|
@ -2436,7 +2483,8 @@ main(int argc, char **argv)
|
|||
srand(time(NULL));
|
||||
fw_query_init();
|
||||
|
||||
while ((choice = getopt(argc, argv, "46vcsfhDu:t:d:m:l:L:p:n:b:P:z:F:i:")) != -1) {
|
||||
while ((choice = getopt(argc, argv, "46vcsfhDuS:t:d:m:l:L:p:n:b:P:z:F:i:")) != -1) {
|
||||
|
||||
switch(choice) {
|
||||
case '4':
|
||||
addrfamily = AF_INET;
|
||||
|
@ -2507,6 +2555,9 @@ main(int argc, char **argv)
|
|||
/* XXX: find better way of cleaning up ps(1) */
|
||||
memset(optarg, 0, strlen(optarg));
|
||||
break;
|
||||
case 'S':
|
||||
display_ip6_buffer = optarg;
|
||||
break;
|
||||
case 'z':
|
||||
context = optarg;
|
||||
break;
|
||||
|
@ -2534,10 +2585,32 @@ main(int argc, char **argv)
|
|||
my_ip = inet_addr(argv[0]);
|
||||
|
||||
if (my_ip == INADDR_NONE) {
|
||||
warnx("Bad IP address to use inside tunnel.");
|
||||
warnx("Bad IP address to use inside tunnel.");
|
||||
usage();
|
||||
}
|
||||
|
||||
|
||||
if (display_ip6_buffer != NULL) {
|
||||
|
||||
ip6_netmask_buffer = strchr(display_ip6_buffer, '/');
|
||||
|
||||
if (ip6_netmask_buffer != NULL) {
|
||||
if (atoi(ip6_netmask_buffer+1) != ip6_netmask) {
|
||||
warnx("IPv6 address must be a 64-bit mask.");
|
||||
usage();
|
||||
}
|
||||
/* remove masklen */
|
||||
memcpy(display_ip6, display_ip6_buffer, strlen(display_ip6_buffer) - strlen(ip6_netmask_buffer));
|
||||
display_ip6[strlen(display_ip6)+1] = '\0';
|
||||
}
|
||||
|
||||
/* IPV6 address sanity check */
|
||||
if (inet_pton(AF_INET6, display_ip6, &my_ip6) != 1) {
|
||||
warnx("Bad IPv6 address to use inside tunnel.");
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
topdomain = strdup(argv[1]);
|
||||
if (check_topdomain(topdomain, 1, &errormsg)) {
|
||||
warnx("Invalid topdomain: %s", errormsg);
|
||||
|
@ -2666,7 +2739,7 @@ main(int argc, char **argv)
|
|||
dns_fds.v4fd = -1;
|
||||
dns_fds.v6fd = -1;
|
||||
|
||||
created_users = init_users(my_ip, netmask);
|
||||
created_users = init_users(my_ip, netmask, my_ip6, ip6_netmask);
|
||||
|
||||
if ((tun_fd = open_tun(device)) == -1) {
|
||||
/* nothing to clean up, just return */
|
||||
|
@ -2674,11 +2747,28 @@ main(int argc, char **argv)
|
|||
}
|
||||
if (!skipipconfig) {
|
||||
const char *other_ip = users_get_first_ip();
|
||||
const char *display_other_ip6 = users_get_first_ip6();
|
||||
|
||||
|
||||
if (tun_setip(argv[0], other_ip, netmask) != 0 || tun_setmtu(mtu) != 0) {
|
||||
retval = 1;
|
||||
retval = 1;
|
||||
free((void*) other_ip);
|
||||
goto cleanup;
|
||||
goto cleanup;
|
||||
|
||||
}
|
||||
|
||||
if (display_ip6_buffer != NULL) {
|
||||
if (tun_setip6(display_ip6, display_other_ip6, ip6_netmask) != 0 ) {
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if ((mtu < 1280) && (sizeof(display_ip6)) != 0) {
|
||||
warnx("Interface mtu of %d below the 1280 threshold needed for IPv6 tunneling.\n", mtu);
|
||||
warnx("Proceeding without IPv6 tunneling\n");
|
||||
}
|
||||
|
||||
free((void*) other_ip);
|
||||
}
|
||||
|
||||
|
|
202
src/tun.c
202
src/tun.c
|
@ -35,6 +35,11 @@
|
|||
#include <netinet/ip.h>
|
||||
#endif
|
||||
|
||||
#if defined FREEBSD || defined NETBSD
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if_tun.h>
|
||||
#endif
|
||||
|
||||
#ifndef IFCONFIGPATH
|
||||
#define IFCONFIGPATH "PATH=/sbin:/bin "
|
||||
#endif
|
||||
|
@ -82,6 +87,7 @@ static char if_name[250];
|
|||
#include <net/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
|
||||
|
||||
int
|
||||
open_tun(const char *tun_device)
|
||||
{
|
||||
|
@ -452,7 +458,15 @@ open_tun(const char *tun_device)
|
|||
snprintf(tun_name, sizeof(tun_name), "/dev/tun%d", i);
|
||||
|
||||
if ((tun_fd = open(tun_name, O_RDWR)) >= 0) {
|
||||
fprintf(stderr, "Opened %s\n", tun_name);
|
||||
#if defined FREEBSD || defined NETBSD
|
||||
/* FreeBSD requires a packet header for
|
||||
* IPv6 traffic
|
||||
*/
|
||||
if (ioctl(tun_fd, TUNSIFHEAD, &(int){1}) != 0) {
|
||||
fprintf(stderr, "Not able to enable TUNSIFHEAD\n");
|
||||
break;
|
||||
}
|
||||
#endif /* LINUX */
|
||||
snprintf(if_name, sizeof(if_name), "tun%d", i);
|
||||
fd_set_close_on_exec(tun_fd);
|
||||
return tun_fd;
|
||||
|
@ -530,9 +544,12 @@ read_tun(int tun_fd, char *buf, size_t len)
|
|||
static int
|
||||
tun_uses_header(void)
|
||||
{
|
||||
#if defined (FREEBSD) || defined (NETBSD)
|
||||
/* FreeBSD/NetBSD has no header */
|
||||
return 0;
|
||||
#if defined FREEBSD || defined NETBSD || defined OPENBSD
|
||||
/* To enable IPv6 in FreeBSD tunnels, tunnel
|
||||
* headers now enabled for that platform
|
||||
*/
|
||||
return 1;
|
||||
|
||||
#elif defined (DARWIN)
|
||||
/* Darwin tun has no header, Darwin utun does */
|
||||
return !strncmp(if_name, "utun", 4);
|
||||
|
@ -544,24 +561,83 @@ tun_uses_header(void)
|
|||
int
|
||||
write_tun(int tun_fd, char *data, size_t len)
|
||||
{
|
||||
|
||||
int ip_version = 0;
|
||||
|
||||
if (!tun_uses_header()) {
|
||||
data += 4;
|
||||
len -= 4;
|
||||
} else {
|
||||
|
||||
ip_version = get_ipversion(data[4]);
|
||||
|
||||
if (ip_version < 0) {
|
||||
return 1; /* Cannot read IP version number from packet */
|
||||
}
|
||||
|
||||
#ifdef LINUX
|
||||
|
||||
if (ip_version == 4) {
|
||||
// Linux prefixes with 32 bits ethertype
|
||||
// 0x0800 for IPv4, 0x86DD for IPv6
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
data[2] = 0x08;
|
||||
data[3] = 0x00;
|
||||
#else /* OPENBSD and DARWIN(utun) */
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
data[2] = 0x08;
|
||||
data[3] = 0x00;
|
||||
} else { /* IPV6 */
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
data[2] = 0x86;
|
||||
data[3] = 0xDD;
|
||||
}
|
||||
#elif defined (FREEBSD) || defined (OPENBSD)
|
||||
|
||||
// BSDs prefix with 32 bits address family
|
||||
// AF_INET for IPv4, AF_INET6 for IPv6
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
data[2] = 0x00;
|
||||
data[3] = 0x02;
|
||||
if (ip_version == 4) {
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
data[2] = 0x00;
|
||||
data[3] = 0x02;
|
||||
} else { /* IPV6 */
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
data[2] = 0x00;
|
||||
data[3] = 0x1C;
|
||||
|
||||
}
|
||||
|
||||
#elif defined NETBSD
|
||||
|
||||
// BSDs prefix with 32 bits address family
|
||||
// AF_INET for IPv4, AF_INET6 for IPv6
|
||||
if (ip_version == 4) {
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
data[2] = 0x00;
|
||||
data[3] = 0x02;
|
||||
} else { /* IPV6 */
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
data[2] = 0x00;
|
||||
data[3] = 0x18;
|
||||
|
||||
}
|
||||
#else /* DARWIN(utun) and all others */
|
||||
|
||||
// BSDs prefix with 32 bits address family
|
||||
// AF_INET for IPv4, AF_INET6 for IPv6
|
||||
if (ip_version == 4) {
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
data[2] = 0x00;
|
||||
data[3] = 0x02;
|
||||
} else { /* IPV6 */
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
data[2] = 0x00;
|
||||
data[3] = 0x1E;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -630,6 +706,7 @@ tun_setip(const char *ip, const char *other_ip, int netbits)
|
|||
# else
|
||||
display_ip = ip;
|
||||
# endif
|
||||
|
||||
snprintf(cmdline, sizeof(cmdline),
|
||||
IFCONFIGPATH "ifconfig %s %s %s netmask %s",
|
||||
if_name,
|
||||
|
@ -687,6 +764,90 @@ tun_setip(const char *ip, const char *other_ip, int netbits)
|
|||
if_name, ip, inet_ntoa(net));
|
||||
return system(cmdline);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
tun_setip6(char *display_ip6, const char *display_other_ip6, int netbits6)
|
||||
{
|
||||
int v6_r;
|
||||
struct in6_addr ip6;
|
||||
char v6_cmdline[512];
|
||||
if (inet_pton(AF_INET6, display_ip6, &ip6) < 1){
|
||||
warnx("Error in IPv6 address");
|
||||
}
|
||||
|
||||
#ifdef WINDOWS32
|
||||
/*
|
||||
DWORD status;
|
||||
DWORD ipdata[3];
|
||||
struct in_addr addr;
|
||||
DWORD len;
|
||||
*/
|
||||
#endif
|
||||
|
||||
if (netbits6 > 0) {
|
||||
|
||||
fprintf(stderr, "Setting IPv6 of %s to %s\n", if_name, display_ip6);
|
||||
|
||||
#if defined LINUX
|
||||
snprintf(v6_cmdline, sizeof(v6_cmdline),
|
||||
IFCONFIGPATH "ifconfig %s inet6 add %s/%d",
|
||||
if_name,
|
||||
display_ip6, netbits6);
|
||||
#else
|
||||
snprintf(v6_cmdline, sizeof(v6_cmdline),
|
||||
IFCONFIGPATH "ifconfig %s inet6 %s/%d",
|
||||
if_name,
|
||||
display_ip6, netbits6);
|
||||
#endif
|
||||
|
||||
v6_r = system(v6_cmdline);
|
||||
|
||||
if (v6_r != 0) {
|
||||
return v6_r;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WINDOWS32 /* WINDOWS32 */
|
||||
|
||||
/* Set device as connected */
|
||||
fprintf(stderr, "Enabling interface '%s'\n", if_name);
|
||||
status = 1;
|
||||
r = DeviceIoControl(dev_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status,
|
||||
sizeof(status), &status, sizeof(status), &len, NULL);
|
||||
if (!r) {
|
||||
fprintf(stderr, "Failed to enable interface\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inet_aton(ip, &addr)) {
|
||||
ipdata[0] = (DWORD) addr.s_addr; /* local ip addr */
|
||||
ipdata[1] = net.s_addr & ipdata[0]; /* network addr */
|
||||
ipdata[2] = (DWORD) net.s_addr; /* netmask */
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Tell ip/networkaddr/netmask to device for arp use */
|
||||
r = DeviceIoControl(dev_handle, TAP_IOCTL_CONFIG_TUN, &ipdata,
|
||||
sizeof(ipdata), &ipdata, sizeof(ipdata), &len, NULL);
|
||||
if (!r) {
|
||||
fprintf(stderr, "Failed to set interface in TUN mode\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* use netsh to set ip address */
|
||||
fprintf(stderr, "Setting IP of interface '%s' to %s (can take a few seconds)...\n", if_name, ip);
|
||||
snprintf(cmdline, sizeof(cmdline), "netsh interface ip set address \"%s\" static %s %s",
|
||||
if_name, ip, inet_ntoa(net));
|
||||
return system(cmdline);
|
||||
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -714,3 +875,18 @@ tun_setmtu(const unsigned mtu)
|
|||
#endif
|
||||
}
|
||||
|
||||
int get_ipversion(char first_byte)
|
||||
{
|
||||
|
||||
int v;
|
||||
|
||||
v = first_byte & 0xf0;
|
||||
|
||||
if (v == 64) {
|
||||
return 4;
|
||||
} else if (v == 96) {
|
||||
return 6;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ void close_tun(int);
|
|||
int write_tun(int, char *, size_t);
|
||||
ssize_t read_tun(int, char *, size_t);
|
||||
int tun_setip(const char *, const char *, int);
|
||||
int tun_setip6(char *, const char *, int);
|
||||
int tun_setmtu(const unsigned);
|
||||
int get_ipversion(char);
|
||||
|
||||
#endif /* _TUN_H_ */
|
||||
|
|
110
src/user.c
110
src/user.c
|
@ -23,6 +23,7 @@
|
|||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef WINDOWS32
|
||||
#include <winsock2.h>
|
||||
|
@ -37,10 +38,12 @@
|
|||
struct tun_user *users;
|
||||
unsigned usercount;
|
||||
|
||||
int init_users(in_addr_t my_ip, int netbits)
|
||||
int init_users(in_addr_t my_ip, int netbits, struct in6_addr my_ip6, int netbits6)
|
||||
{
|
||||
int i;
|
||||
int i6;
|
||||
int skip = 0;
|
||||
int skip6 = 0;
|
||||
char newip[16];
|
||||
|
||||
int maxusers;
|
||||
|
@ -48,7 +51,13 @@ int init_users(in_addr_t my_ip, int netbits)
|
|||
in_addr_t netmask = 0;
|
||||
struct in_addr net;
|
||||
struct in_addr ipstart;
|
||||
struct in6_addr ip6start;
|
||||
unsigned ip6_netmask[16];
|
||||
|
||||
bool ip6_enabled;
|
||||
|
||||
ip6_enabled = isV6AddrSet(&my_ip6);
|
||||
|
||||
for (i = 0; i < netbits; i++) {
|
||||
netmask = (netmask << 1) | 1;
|
||||
}
|
||||
|
@ -56,22 +65,77 @@ int init_users(in_addr_t my_ip, int netbits)
|
|||
net.s_addr = htonl(netmask);
|
||||
ipstart.s_addr = my_ip & net.s_addr;
|
||||
|
||||
/* Covert IPv6 netbits to IPv6 netmask and work
|
||||
* out the network address from my IP address. Start
|
||||
* assigning IPv6 address from the network address + 1
|
||||
*/
|
||||
if (ip6_enabled == true) {
|
||||
for (i6 = 0; i6 < netbits6 / 8; i6++) {
|
||||
ip6_netmask[i6] |= 0xFF;
|
||||
}
|
||||
|
||||
ip6_netmask[netbits6 / 8] = pow(2, (netbits6 % 8 )) - 1;
|
||||
ip6_netmask[netbits6 / 8] <<= (8-(netbits6 % 8));
|
||||
|
||||
for (i6 = 0; i6 < 16; i6++) {
|
||||
ip6start.s6_addr[i6] = my_ip6.s6_addr[i6] & ip6_netmask[i6];
|
||||
}
|
||||
}
|
||||
maxusers = (1 << (32-netbits)) - 3; /* 3: Net addr, broadcast addr, iodined addr */
|
||||
usercount = MIN(maxusers, USERS);
|
||||
|
||||
users = calloc(usercount, sizeof(struct tun_user));
|
||||
/*
|
||||
* IPv6 note: Current behavior is to populate the users structure
|
||||
* with the IPv4 addresses that are expected to be used.
|
||||
* In the future with IPv6-only tunnel transport, we should not be
|
||||
* populating a /64 (or whatever mask) in the users structure
|
||||
* and should shift to an on-demand scheme. For now
|
||||
* we expect dual-stack and pre-allocate IPv6 addresses into the
|
||||
* users struct as we do with IPv4.
|
||||
*/
|
||||
for (i = 0; i < usercount; i++) {
|
||||
in_addr_t ip;
|
||||
users[i].id = i;
|
||||
|
||||
snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1);
|
||||
|
||||
ip = ipstart.s_addr + inet_addr(newip);
|
||||
if (ip == my_ip && skip == 0) {
|
||||
/* This IP was taken by iodined */
|
||||
skip++;
|
||||
snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1);
|
||||
ip = ipstart.s_addr + inet_addr(newip);
|
||||
|
||||
}
|
||||
users[i].tun_ip = ip;
|
||||
|
||||
if (ip6_enabled == true) {
|
||||
struct in6_addr temp_ip6;
|
||||
/*
|
||||
* start assigning host addresses from the network address + 1
|
||||
* unless that is my_ip, in which case, use the following address.
|
||||
*/
|
||||
memcpy(temp_ip6.s6_addr, ip6start.s6_addr, sizeof(ip6start.s6_addr));
|
||||
temp_ip6.s6_addr[15] = ip6start.s6_addr[15] + skip + 1 + i;
|
||||
|
||||
if (v6AddressesEqual(&temp_ip6, &my_ip6) == true &&
|
||||
skip6 == 0) {
|
||||
/* This IPv6 was taken by iodined */
|
||||
skip6++;
|
||||
|
||||
/*
|
||||
* We expect to start assigning addresses at the network address + 1 and
|
||||
* to not worry about assigning more than 254 host addresses. If we did, we have to
|
||||
* iterate through lower order bytes of ip6. This plus a few other corner cases
|
||||
* is why we enourage/force/assume the user to specify a /64 V6 address
|
||||
*/
|
||||
|
||||
temp_ip6.s6_addr[15] = ip6start.s6_addr[15] + skip + 1 + i;
|
||||
|
||||
}
|
||||
memcpy(users[i].tun_ip6.s6_addr, temp_ip6.s6_addr, sizeof(temp_ip6.s6_addr));
|
||||
}
|
||||
net.s_addr = ip;
|
||||
users[i].disabled = 0;
|
||||
users[i].authenticated = 0;
|
||||
|
@ -91,6 +155,50 @@ const char *users_get_first_ip(void)
|
|||
return strdup(inet_ntoa(ip));
|
||||
}
|
||||
|
||||
const char *users_get_first_ip6(void)
|
||||
{
|
||||
struct in6_addr ip6;
|
||||
char display_ip6[INET6_ADDRSTRLEN];
|
||||
|
||||
memcpy(&ip6, &users[0].tun_ip6, sizeof(struct in6_addr));
|
||||
|
||||
inet_ntop(AF_INET6, &ip6, display_ip6, INET6_ADDRSTRLEN);
|
||||
return strdup(display_ip6);
|
||||
}
|
||||
|
||||
|
||||
int find_user_by_ip6(struct in6_addr *v6Addr)
|
||||
{
|
||||
int i;
|
||||
char v6AddrOut[32];
|
||||
|
||||
inet_ntop(AF_INET6, v6Addr, v6AddrOut, INET6_ADDRSTRLEN);
|
||||
|
||||
for (i = 0; i < usercount; i++) {
|
||||
if (users[i].active &&
|
||||
users[i].authenticated &&
|
||||
!users[i].disabled &&
|
||||
users[i].last_pkt + 60 > time(NULL) &&
|
||||
v6AddressesEqual(v6Addr, &users[i].tun_ip6) == true) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool v6AddressesEqual(struct in6_addr *v6Struct1, struct in6_addr *v6Struct2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (v6Struct1->s6_addr[i] != v6Struct2->s6_addr[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int find_user_by_ip(uint32_t ip)
|
||||
{
|
||||
int ret;
|
||||
|
|
|
@ -45,6 +45,7 @@ struct tun_user {
|
|||
int seed;
|
||||
in_addr_t tun_ip;
|
||||
struct sockaddr_storage host;
|
||||
struct in6_addr tun_ip6;
|
||||
socklen_t hostlen;
|
||||
struct query q;
|
||||
struct query q_sendrealsoon;
|
||||
|
@ -80,12 +81,15 @@ struct tun_user {
|
|||
|
||||
extern struct tun_user *users;
|
||||
|
||||
int init_users(in_addr_t, int);
|
||||
int init_users(in_addr_t, int, struct in6_addr, int);
|
||||
const char* users_get_first_ip(void);
|
||||
const char* users_get_first_ip6(void);
|
||||
int find_user_by_ip(uint32_t);
|
||||
int find_user_by_ip6(struct in6_addr *v6Addr);
|
||||
int all_users_waiting_to_send(void);
|
||||
int find_available_user(void);
|
||||
void user_switch_codec(int userid, const struct encoder *enc);
|
||||
void user_set_conn_type(int userid, enum connection c);
|
||||
bool v6AddressesEqual(struct in6_addr *, struct in6_addr *);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue