-
Notifications
You must be signed in to change notification settings - Fork 507
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update client and server to allow forwarding IPv6 packets within the tunnel #65
base: master
Are you sure you want to change the base?
Changes from all commits
bc061f0
e75ca72
78b5b7d
70c6e98
8e206ae
1e196bf
16e1b73
ab2bbd9
8ee7290
883ef8b
461c4c3
00c8429
c9efbc0
65c88a4
a2d65f6
9d86d0a
061fac4
3eb959c
846082f
ab7e5b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use int instead (also in other changes) |
||
|
||
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; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is an internal function, can you move it so it doesn't need to be declared here? |
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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. | ||
* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undo |
||
* | ||
*/ | ||
|
||
#include <time.h> | ||
|
@@ -557,3 +559,17 @@ fd_set_close_on_exec(int fd) | |
} | ||
#endif | ||
|
||
bool | ||
isV6AddrSet(struct in6_addr *ip6) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. follow naming convention. also, can this replaced by using the comparison function vs a constant? |
||
{ | ||
int i; | ||
|
||
for (i = 0; i < sizeof(ip6->s6_addr); i++) { | ||
if (ip6->s6_addr[i] != 0) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) { | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undo |
||
switch(choice) { | ||
case '4': | ||
nameserv_family = AF_INET; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. move these into the minimal scope |
||
char *display_ip6_buffer = NULL; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i am not sold on calling the string version of an address |
||
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]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use lowercase names, why len 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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. duplicate identical assignment |
||
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]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use memcpy based on a header struct |
||
} | ||
inet_ntop(AF_INET6, &v6Addr, v6AddrP, INET6_ADDRSTRLEN); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. redundant? |
||
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]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wrong indent |
||
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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. u lost its |
||
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."); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undo |
||
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)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we just refuse strings with netmask set instead? |
||
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,19 +2739,36 @@ 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 */ | ||
return 1; | ||
} | ||
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undo |
||
free((void*) other_ip); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IPv6 address string leak |
||
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"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does it really? shouldn't some flag be changed? |
||
} | ||
|
||
free((void*) other_ip); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IPv6 address string leak |
||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
flag changes should be reflected in manpages also