mirror of
https://github.com/yarrick/iodine.git
synced 2024-11-22 16:19:20 +02:00
further IPv6 changes
This commit is contained in:
parent
3eb959c8fe
commit
846082f13e
|
@ -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
|
||||
|
||||
|
|
75
src/client.c
75
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()
|
||||
|
@ -1374,7 +1377,7 @@ handshake_version(int dns_fd, int *seed)
|
|||
}
|
||||
|
||||
static int
|
||||
handshake_login(int dns_fd, int seed, int forward_v6)
|
||||
handshake_login(int dns_fd, int seed)
|
||||
{
|
||||
char in[4096];
|
||||
char login[16];
|
||||
|
@ -1405,7 +1408,7 @@ handshake_login(int dns_fd, int seed, int forward_v6)
|
|||
|
||||
server[64] = 0;
|
||||
client[64] = 0;
|
||||
if (tun_setip(client, server, netmask, forward_v6) == 0 &&
|
||||
if (tun_setip(client, server, netmask) == 0 &&
|
||||
tun_setmtu(mtu) == 0) {
|
||||
|
||||
fprintf(stderr, "Server tunnel IP is %s\n", server);
|
||||
|
@ -2326,7 +2329,7 @@ handshake_set_fragsize(int dns_fd, int fragsize)
|
|||
}
|
||||
|
||||
int
|
||||
client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize, int forward_v6)
|
||||
client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize)
|
||||
{
|
||||
int seed;
|
||||
int upcodec;
|
||||
|
@ -2349,7 +2352,7 @@ client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsiz
|
|||
return r;
|
||||
}
|
||||
|
||||
r = handshake_login(dns_fd, seed, forward_v6);
|
||||
r = handshake_login(dns_fd, seed);
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
|
@ -2414,8 +2417,72 @@ 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[1024];
|
||||
char client6[1024];
|
||||
int i;
|
||||
int read;
|
||||
int netmask6 = 0;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ void client_set_lazymode(int lazy_mode);
|
|||
void client_set_hostname_maxlen(int i);
|
||||
|
||||
int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size,
|
||||
int fragsize, int forward_v6);
|
||||
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
|
||||
|
|
13
src/iodine.c
13
src/iodine.c
|
@ -72,7 +72,7 @@ static void help(FILE *stream, bool verbose)
|
|||
{
|
||||
fprintf(stream,
|
||||
"iodine IP over DNS tunneling client\n\n"
|
||||
"Usage: %s [-46fhrvS] [-u user] [-t chrootdir] [-d device] [-P password]\n"
|
||||
"Usage: %s [-46fhrv] [-u user] [-t chrootdir] [-d device] [-P password]\n"
|
||||
" [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec]\n"
|
||||
" [-z context] [-F pidfile] [nameserver] topdomain\n", __progname);
|
||||
|
||||
|
@ -100,7 +100,6 @@ static void help(FILE *stream, bool verbose)
|
|||
" -t dir to chroot to directory dir\n"
|
||||
" -d device to set tunnel device name\n"
|
||||
" -z context, to apply specified SELinux context after initialization\n"
|
||||
" -S enable forwarding of IPv6 packets within the tunnel\n"
|
||||
" -F pidfile to write pid to a file\n\n"
|
||||
"nameserver is the IP number/hostname of the relaying nameserver. If absent,\n"
|
||||
" /etc/resolv.conf is used\n"
|
||||
|
@ -153,7 +152,6 @@ int main(int argc, char **argv)
|
|||
struct sockaddr_storage nameservaddr;
|
||||
int nameservaddr_len;
|
||||
int nameserv_family;
|
||||
int forward_v6;
|
||||
|
||||
nameserv_host = NULL;
|
||||
topdomain = NULL;
|
||||
|
@ -178,7 +176,6 @@ int main(int argc, char **argv)
|
|||
selecttimeout = 4;
|
||||
hostname_maxlen = 0xFF;
|
||||
nameserv_family = AF_UNSPEC;
|
||||
forward_v6 = 0;
|
||||
|
||||
#ifdef WINDOWS32
|
||||
WSAStartup(req_version, &wsa_data);
|
||||
|
@ -195,7 +192,8 @@ int main(int argc, char **argv)
|
|||
__progname++;
|
||||
#endif
|
||||
|
||||
while ((choice = getopt(argc, argv, "t:d:R:P:m:M:z:F:T:O:L:I:46vfhruS")) != -1) {
|
||||
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;
|
||||
|
@ -220,9 +218,6 @@ int main(int argc, char **argv)
|
|||
case 'u':
|
||||
username = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
forward_v6 = 1;
|
||||
break;
|
||||
case 't':
|
||||
newroot = optarg;
|
||||
break;
|
||||
|
@ -372,7 +367,7 @@ int main(int argc, char **argv)
|
|||
fprintf(stderr, "Sending DNS queries for %s to %s\n",
|
||||
topdomain, format_addr(&nameservaddr, nameservaddr_len));
|
||||
|
||||
if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size, forward_v6)) {
|
||||
if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) {
|
||||
retval = 1;
|
||||
goto cleanup2;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
char *ip6_netmask_buffer;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -658,9 +664,9 @@ static int tunnel_tun(int tun_fd, struct dnsfd *dns_fds)
|
|||
|
||||
/* find target ip in packet, in is padded with 4 bytes TUN header */
|
||||
header = (struct ip*) (in + 4);
|
||||
ip_version = in[4] & 0xf0;
|
||||
ip_version = get_ipversion(in[4]);
|
||||
|
||||
if (ip_version == 64) { /* IPv4 */
|
||||
if (ip_version == 4) { /* IPv4 */
|
||||
header = (struct ip*) (in + 4);
|
||||
userid = find_user_by_ip(header->ip_dst.s_addr);
|
||||
} else { /* IPv6 */
|
||||
|
@ -674,6 +680,7 @@ static int tunnel_tun(int tun_fd, struct dnsfd *dns_fds)
|
|||
return 0;
|
||||
|
||||
outlen = sizeof(out);
|
||||
|
||||
compress2((uint8_t*)out, &outlen, (uint8_t*)in, read, 9);
|
||||
|
||||
if (users[userid].conn == CONN_DNS_NULL) {
|
||||
|
@ -1303,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')) {
|
||||
|
@ -2288,10 +2321,10 @@ write_dns(int fd, struct query *q, const char *data, int datalen, char downenc)
|
|||
static void print_usage(FILE *stream)
|
||||
{
|
||||
fprintf(stream,
|
||||
"Usage: %s [-46cDfsvS] [-u user] [-t chrootdir] [-d device] [-m mtu]\n"
|
||||
"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);
|
||||
}
|
||||
|
||||
|
@ -2333,7 +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 enable forwarding of IPv6 packets within the tunnel\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"
|
||||
|
@ -2405,7 +2438,6 @@ main(int argc, char **argv)
|
|||
int dns4addr_len;
|
||||
struct sockaddr_storage dns6addr;
|
||||
int dns6addr_len;
|
||||
int forward_v6;
|
||||
#ifdef HAVE_SYSTEMD
|
||||
int nb_fds;
|
||||
#endif
|
||||
|
@ -2434,7 +2466,6 @@ main(int argc, char **argv)
|
|||
debug = 0;
|
||||
netmask = 27;
|
||||
pidfile = NULL;
|
||||
forward_v6 = 0;
|
||||
retval = 0;
|
||||
|
||||
#ifdef WINDOWS32
|
||||
|
@ -2452,7 +2483,8 @@ main(int argc, char **argv)
|
|||
srand(time(NULL));
|
||||
fw_query_init();
|
||||
|
||||
while ((choice = getopt(argc, argv, "t:d:m:l:L:p:n:b:P:z:F:i:46vcsSfhDu")) != -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;
|
||||
|
@ -2524,7 +2556,7 @@ main(int argc, char **argv)
|
|||
memset(optarg, 0, strlen(optarg));
|
||||
break;
|
||||
case 'S':
|
||||
forward_v6 = 1;
|
||||
display_ip6_buffer = optarg;
|
||||
break;
|
||||
case 'z':
|
||||
context = optarg;
|
||||
|
@ -2553,10 +2585,28 @@ 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();
|
||||
}
|
||||
|
||||
|
||||
ip6_netmask_buffer = strchr(display_ip6_buffer, '/');
|
||||
if (ip6_netmask_buffer) {
|
||||
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);
|
||||
|
@ -2685,7 +2735,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 */
|
||||
|
@ -2693,13 +2743,23 @@ main(int argc, char **argv)
|
|||
}
|
||||
if (!skipipconfig) {
|
||||
const char *other_ip = users_get_first_ip();
|
||||
if (tun_setip(argv[0], other_ip, netmask, forward_v6) != 0 || tun_setmtu(mtu) != 0) {
|
||||
const char *display_other_ip6 = users_get_first_ip6();
|
||||
|
||||
|
||||
if (tun_setip(argv[0], other_ip, netmask) != 0 || tun_setmtu(mtu) != 0) {
|
||||
retval = 1;
|
||||
free((void*) other_ip);
|
||||
goto cleanup;
|
||||
|
||||
}
|
||||
if ((mtu < 1280) && (forward_v6)) {
|
||||
|
||||
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");
|
||||
}
|
||||
|
|
201
src/tun.c
201
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,41 +561,82 @@ 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 {
|
||||
int i = data[4] & 0xf0;
|
||||
|
||||
ip_version = get_ipversion(data[4]);
|
||||
|
||||
if (ip_version < 0) {
|
||||
return 1; /* Cannot read IP version number from packet */
|
||||
}
|
||||
|
||||
#ifdef LINUX
|
||||
|
||||
if (i == 64) {
|
||||
// Look at the fifth bype
|
||||
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 { /* 96 for IPV6 */
|
||||
} else { /* IPV6 */
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
data[2] = 0x86;
|
||||
data[3] = 0xDD;
|
||||
}
|
||||
#else /* OPENBSD and DARWIN(utun) */
|
||||
#elif defined (FREEBSD) || defined (OPENBSD)
|
||||
|
||||
// BSDs prefix with 32 bits address family
|
||||
// AF_INET for IPv4, AF_INET6 for IPv6
|
||||
if (i == 64) {
|
||||
if (ip_version == 4) {
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
data[2] = 0x00;
|
||||
data[3] = 0x02;
|
||||
} else { /* 96 for IPV6 */
|
||||
} 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
|
||||
}
|
||||
|
@ -610,14 +668,12 @@ read_tun(int tun_fd, char *buf, size_t len)
|
|||
#endif
|
||||
|
||||
int
|
||||
tun_setip(const char *ip, const char *other_ip, int netbits, int forward_v6)
|
||||
tun_setip(const char *ip, const char *other_ip, int netbits)
|
||||
{
|
||||
char cmdline[512];
|
||||
char v6_cmdline[512];
|
||||
int netmask;
|
||||
struct in_addr net;
|
||||
int i;
|
||||
int v6_r;
|
||||
#ifndef LINUX
|
||||
int r;
|
||||
#endif
|
||||
|
@ -650,20 +706,7 @@ tun_setip(const char *ip, const char *other_ip, int netbits, int forward_v6)
|
|||
# else
|
||||
display_ip = ip;
|
||||
# endif
|
||||
if (forward_v6) {
|
||||
fprintf(stderr, "Setting IPv6 of %s to ::%s\n", if_name, ip);
|
||||
|
||||
snprintf(v6_cmdline, sizeof(cmdline),
|
||||
IFCONFIGPATH "ifconfig %s inet6 add ::%s/64",
|
||||
if_name,
|
||||
display_ip);
|
||||
|
||||
v6_r = system(v6_cmdline);
|
||||
|
||||
if (v6_r != 0) {
|
||||
return v6_r;
|
||||
}
|
||||
}
|
||||
snprintf(cmdline, sizeof(cmdline),
|
||||
IFCONFIGPATH "ifconfig %s %s %s netmask %s",
|
||||
if_name,
|
||||
|
@ -722,14 +765,89 @@ tun_setip(const char *ip, const char *other_ip, int netbits, int forward_v6)
|
|||
return system(cmdline);
|
||||
#endif
|
||||
|
||||
if (forward_v6) {
|
||||
snprintf(cmdline, sizeof(cmdline),
|
||||
IFCONFIGPATH "ifconfig %s inet6 add ::%s/64",
|
||||
if_name,
|
||||
ip);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Setting IP of %s to %s\n", if_name, ip);
|
||||
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
|
||||
|
@ -757,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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,9 @@ int open_tun(const char *);
|
|||
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);
|
||||
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_ */
|
||||
|
|
95
src/user.c
95
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,24 +38,25 @@
|
|||
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];
|
||||
char ip6Tmp[16];
|
||||
char ip6Tmp2[18];
|
||||
|
||||
int maxusers;
|
||||
|
||||
in_addr_t netmask = 0;
|
||||
struct in_addr net;
|
||||
struct in_addr ipstart;
|
||||
struct in6_addr ip6start;
|
||||
unsigned ip6_netmask[16];
|
||||
|
||||
/* For IPv6, we take the IPv4 address and simply prepend ::
|
||||
* and use a 64-bit mask. Reduces the need to parse
|
||||
* netmasks.
|
||||
*/
|
||||
bool ip6_enabled;
|
||||
|
||||
ip6_enabled = isV6AddrSet(&my_ip6);
|
||||
|
||||
for (i = 0; i < netbits; i++) {
|
||||
netmask = (netmask << 1) | 1;
|
||||
|
@ -63,17 +65,39 @@ 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;
|
||||
|
||||
memset(ip6Tmp,0,strlen(ip6Tmp));
|
||||
memset(ip6Tmp2,0,strlen(ip6Tmp2));
|
||||
|
||||
snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1);
|
||||
|
||||
ip = ipstart.s_addr + inet_addr(newip);
|
||||
|
@ -83,14 +107,35 @@ int init_users(in_addr_t my_ip, int netbits)
|
|||
snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1);
|
||||
ip = ipstart.s_addr + inet_addr(newip);
|
||||
|
||||
|
||||
}
|
||||
users[i].tun_ip = ip;
|
||||
|
||||
inet_ntop(AF_INET, &ip, ip6Tmp, INET_ADDRSTRLEN);
|
||||
snprintf(ip6Tmp2, sizeof(ip6Tmp2), "::%s", ip6Tmp);
|
||||
inet_pton(AF_INET6, ip6Tmp2, &users[i].tun_ip6);
|
||||
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;
|
||||
|
@ -110,6 +155,18 @@ 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;
|
||||
|
@ -122,23 +179,23 @@ int find_user_by_ip6(struct in6_addr *v6Addr)
|
|||
users[i].authenticated &&
|
||||
!users[i].disabled &&
|
||||
users[i].last_pkt + 60 > time(NULL) &&
|
||||
(areV6AddressesEqual(v6Addr, &users[i].tun_ip6) == 0) ) {
|
||||
v6AddressesEqual(v6Addr, &users[i].tun_ip6) == true) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int areV6AddressesEqual(struct in6_addr *v6Struct1, struct in6_addr *v6Struct2)
|
||||
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 -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -81,14 +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);
|
||||
int areV6AddressesEqual(struct in6_addr *, struct in6_addr *);
|
||||
bool v6AddressesEqual(struct in6_addr *, struct in6_addr *);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue