1
0
mirror of https://code.semirocket.science/wrapsix synced 2024-09-19 23:11:04 +03:00

Integrated wrapper into WrapSix

Fixed bug in resolver so now even normal applications accept its answers
Improved configuration - now accepts arguments from command line
Cleaned the code a little bit
Added simple build script
Written more documentation into README
Chosen the licence - GNU AGPLv3
This commit is contained in:
xHire 2009-01-14 23:05:12 +01:00
parent e7d8a4c1dd
commit c894b7186c
9 changed files with 205 additions and 58 deletions

15
LICENCE Normal file
View File

@ -0,0 +1,15 @@
WrapSix
Copyright (C) 2008-2009 Michal Zima <xhire@tuxportal.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

36
README
View File

@ -1,21 +1,47 @@
##### #####
## WrapSix readme ## WrapSix readme
#### ####
# Author: Michal Zima, 2008 # Author: Michal Zima, 2008-2009
# E-mail: xhire@tuxportal.cz # E-mail: xhire@tuxportal.cz
##### #####
== About == == About ==
WrapSix is a revolutionary piece of software that make possible to reach IPv4-only servers from IPv6-only networks. It stands as a wrapper of faked IPv6 addresses to real IPv4 addresses. WrapSix is a revolutionary piece of software that makes possible to reach IPv4-only servers from IPv6-only networks. It stands as a wrapper of faked IPv6 addresses to real IPv4 addresses.
== Requirements == == Requirements ==
WrapSix is very simple to use. You only need: * GNU/Linux system with IPv6 support (best with 2.6.12 or newer; tested with 2.6.11 (OK) and 2.6.17 (OK))
* GNU/Linux system * C compiler and such things (just to build binaries of course)
* Ruby (I've tested version 1.8.6) * libpcap (tested with version 0.8.3)
* Ruby (tested with version 1.8.6)
== Building ==
If you satisfied all requirements, let's run build script: './build.sh'.
== Configuration == == Configuration ==
Look at configuration file conf/wrapsix.conf.
In section of the DNS resolver you have to set its IPv6 address (already assigned to the network interface of the server) and IPv4 address of already existing DNS resolver.
In section of the wrapper you have to set some *unused* IPv6 prefix (/96) and *unused* IPv4 address that is not set anywhere. WrapSix manage them itself. If autodetection of network device fails, set it as well, e.g. to 'eth0'.
The IPv6 prefix can be globaly routable - it is up to you to set the firewall appropriately.
If you don't need debug mode, it is recommended to disable it.
All configuration options can be passed on as command line arguments - run './wrapsix.rb --help' for more details. Command line arguments have higher priority and override those in configuration file.
== Instalation ==
WrapSix is not stable yet - it is just experimental version. So it is not supposed to be installed in system (=> there is no installation script), but you can install it by hand if you want. The best location would be in /opt/wrapsix/ I think...
== Running == == Running ==
Run WrapSix with wrapsix.rb. E.g. './wrapsix.rb'. Notice: you need root privileges.
It is recommended to run WrapSix on its own dedicated machine.
== Clients ==
On client station set some routable IPv6 address (generally from similar prefix as WrapSix has, but not the same!) and DNS server to the address that you set in WrapSix. First test the DNS resolving (with dig, ping (as it does resolving too) or whatsoever) and then try pinging such destination that doesn't have native IPv6 connectivity (e.g. 'ping6 wrapsix.tuxportal.cz' (yes, this site doesn't have IPv6 connectivity yet).
Note: you have to have IPv6 connectivity (native or even a tunnel is acceptable)!
== Getting help == == Getting help ==
You can visit official WrapSix IRC channel #wrapsix on server irc.tuxportal.cz. Thank you for feedback. You can visit official WrapSix IRC channel #wrapsix on server irc.tuxportal.cz. Thank you for feedback.

4
build.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
cd wrapper
make clean && make

View File

@ -1,11 +1,13 @@
### Configuration of Resolver ### Configuration of Resolver
resolver: 1 resolver: true
#resolver_ip: '::1' resolver_ip: 'fc00:1::1'
resolver_ip: '2001:470:9985:1:200:e2ff:fe7f:414' secondary_resolver: 10.0.0.1 # if not set => /etc/resolv.conf
secondary_resolver: 10.0.0.139 # if not set => /etc/resolv.conf
### Configuration of Wrapper ### Configuration of Wrapper
wrapper: 0 wrapper: true
wrapper_device: # if not set => automatic detection
wrapper_ipv6_prefix: 'fc00:2::'
wrapper_ipv4_address: 10.0.0.111
### Others ### Others
debug: 1 debug: false

View File

@ -4,7 +4,7 @@
#> lib/resolver.rb #> lib/resolver.rb
#~ WrapSix Resolver #~ WrapSix Resolver
#### ####
# Author: Michal Zima, 2008 # Author: Michal Zima, 2008-2009
# E-mail: xhire@tuxportal.cz # E-mail: xhire@tuxportal.cz
##### #####
@ -20,7 +20,6 @@ class Resolver
@resolver = UDPSocket.open Socket::AF_INET6 @resolver = UDPSocket.open Socket::AF_INET6
begin begin
@resolver.bind $config['resolver_ip'], 53 @resolver.bind $config['resolver_ip'], 53
#rescue Errno::EPERM
rescue Errno::EACCES rescue Errno::EACCES
$stderr.puts "You have to run #{$0} as root!" $stderr.puts "You have to run #{$0} as root!"
exit! exit!
@ -28,7 +27,6 @@ class Resolver
puts "Started DNS resolver on IPv6 address #{$config['resolver_ip']}" if @debug puts "Started DNS resolver on IPv6 address #{$config['resolver_ip']}" if @debug
loop do loop do
puts "---------- start ----------" if @debug
# Receive and parse query # Receive and parse query
data = @resolver.recvfrom 2048 data = @resolver.recvfrom 2048
print "Client: " if @debug print "Client: " if @debug
@ -44,16 +42,16 @@ class Resolver
answer.opcode = query.opcode # Type of Query; copy from query answer.opcode = query.opcode # Type of Query; copy from query
answer.aa = 0 # Is this an authoritative response: 0 = No, 1 = Yes answer.aa = 0 # Is this an authoritative response: 0 = No, 1 = Yes
answer.rd = query.rd # Is Recursion Desired, copied from query answer.rd = query.rd # Is Recursion Desired, copied from query
answer.ra = 0 # Does name server support recursion: 0 = No, 1 = Yes answer.ra = 1 # Does name server support recursion: 0 = No, 1 = Yes
answer.rcode = 0 # Response code: 0 = No errors answer.rcode = 0 # Response code: 0 = No errors
query.each_question do |question, typeclass| # There may be multiple questions per query query.each_question do |question, typeclass| # There may be multiple questions per query
begin begin
name = question.to_s # The domain name looked for in the query. name = question.to_s # The domain name looked for in the query.
answer.add_question name, typeclass
puts "Looking for: #{name}" if @debug puts "Looking for: #{name}" if @debug
#record_type = typeclass.name.split("::").last # For example "A", "MX" #record_type = typeclass.name.split("::").last # For example "A", "MX"
puts "RR: #{typeclass}" if @debug puts "RR: #{typeclass}" if @debug
#puts "RR: #{record_type}" if @debug
# So let's look for it :c) (in secondary resolver) # So let's look for it :c) (in secondary resolver)
sr = Resolv::DNS::new :nameserver => $config['secondary_resolver'] sr = Resolv::DNS::new :nameserver => $config['secondary_resolver']
@ -74,19 +72,44 @@ class Resolver
print "My answer: " if @debug print "My answer: " if @debug
p answer if @debug p answer if @debug
rescue Resolv::ResolvError
# creating 'faked' AAAA entry
begin
if typeclass == Resolv::DNS::Resource::IN::AAAA
sr = Resolv::DNS::new :nameserver => $config['secondary_resolver']
sr_data = sr.getresource name, Resolv::DNS::Resource::IN::A
print "Raw answer: " if @debug
p sr_data if @debug
# completing the answer
aaaa_answer = Resolv::DNS::Resource::IN::AAAA.new(ipaddr_4to6(sr_data.address))
print "IPv4 address: " if @debug
p sr_data.address if @debug
p ipaddr_4to6(sr_data.address) if @debug
ttl = 86400 # I think ttl doesn't matter ;c)
answer.add_answer name + ".", ttl, aaaa_answer
print "My answer: " if @debug
p answer if @debug
end
rescue Resolv::ResolvError rescue Resolv::ResolvError
puts "Error: DNS result has no information for #{name}" puts "Error: DNS result has no information for #{name}"
end end
end end
end
# send the response # send the response
@resolver.send answer.encode, 0, data[1][3], data[1][1] # msg, flags, client, port @resolver.send answer.encode, 0, data[1][3], data[1][1] # msg, flags, client, port
puts "---------- end ----------" if @debug
end end
end end
def exit def exit
@resolver.close @resolver.close
end end
private
def ipaddr_4to6 ip4addr
ip4parsed = ip4addr.to_s.match(Resolv::IPv4::Regex)
return $config['wrapper_ipv6_prefix'] + ("%02x%02x:%02x%02x" % [ ip4parsed[1], ip4parsed[2], ip4parsed[3], ip4parsed[4] ])
end
end end

View File

@ -4,15 +4,22 @@
#> lib/wrapper.rb #> lib/wrapper.rb
#~ WrapSix Wrapper #~ WrapSix Wrapper
#### ####
# Author: Michal Zima, 2008 # Author: Michal Zima, 2008-2009
# E-mail: xhire@tuxportal.cz # E-mail: xhire@tuxportal.cz
##### #####
class Wrapper class Wrapper
def initializer def initializer
@debug = $config['debug']
end end
def start def start
params = "#{$config['wrapper_ipv4_address']} #{$config['wrapper_ipv6_prefix']}"
params += " #{$config['wrapper_device']}" if $config['wrapper_device']
unless @debug
params += " > /dev/null"
end
system "wrapper/wrapper #{params}"
end end
def exit def exit

View File

@ -52,24 +52,39 @@ void process_packet4(const struct s_ethernet *eth, const unsigned char *packet)
printf(" From: %s\n", inet_ntoa(ip->ip_src)); printf(" From: %s\n", inet_ntoa(ip->ip_src));
printf(" To: %s\n", inet_ntoa(ip->ip_dest)); printf(" To: %s\n", inet_ntoa(ip->ip_dest));
/* determine protocol */
switch (ip->proto) {
case IPPROTO_TCP:
printf(" Protocol: TCP\n");
/* check if this packet is ours */ /* check if this packet is ours */
if (memcmp(&ip4addr_wrapsix, &ip->ip_dest, 4)) { if (memcmp(&ip4addr_wrapsix, &ip->ip_dest, 4)) {
printf("==> This packet is not ours! <==\n"); printf("==> This packet is not ours! <==\n");
return; return;
} }
/* determine protocol */
switch (ip->proto) {
case IPPROTO_TCP:
printf(" Protocol: TCP\n");
process_tcp4(eth, ip, payload, htons(ip->pckt_len) - header_length); process_tcp4(eth, ip, payload, htons(ip->pckt_len) - header_length);
break; break;
case IPPROTO_UDP: case IPPROTO_UDP:
printf(" Protocol: UDP\n"); printf(" Protocol: UDP\n");
/* check if this packet is ours */
if (memcmp(dev_ip, &ip->ip_dest, 4)) {
printf("==> This packet is not ours! <==\n");
return;
}
process_udp4(eth, ip, payload, htons(ip->pckt_len) - header_length); process_udp4(eth, ip, payload, htons(ip->pckt_len) - header_length);
break; break;
case IPPROTO_ICMP: case IPPROTO_ICMP:
printf(" Protocol: ICMP\n"); printf(" Protocol: ICMP\n");
/* check if this packet is ours */
if (memcmp(dev_ip, &ip->ip_dest, 4)) {
printf("==> This packet is not ours! <==\n");
return;
}
process_icmp4(eth, ip, payload, htons(ip->pckt_len) - header_length); process_icmp4(eth, ip, payload, htons(ip->pckt_len) - header_length);
break; break;
default: default:
@ -117,11 +132,11 @@ void process_tcp4(const struct s_ethernet *eth_hdr, struct s_ip4 *ip_hdr, const
/* check if this packet is from wrapped connection */ /* check if this packet is from wrapped connection */
if (ent == NULL) { if (ent == NULL) {
fprintf(stderr, "Error: data not found\n"); printf("Error: data not found\n");
return; return;
} }
else if (memcmp(&ent->addr_to, &ip_hdr->ip_src, sizeof(struct in_addr))) { else if (memcmp(&ent->addr_to, &ip_hdr->ip_src, sizeof(struct in_addr))) {
fprintf(stderr, "Error: data not appropriate\n"); printf("Error: data not appropriate\n");
printf(" Ent-to: %s\n", inet_ntoa(ent->addr_to)); printf(" Ent-to: %s\n", inet_ntoa(ent->addr_to));
printf(" IP-from: %s\n", inet_ntoa(ip_hdr->ip_src)); printf(" IP-from: %s\n", inet_ntoa(ip_hdr->ip_src));
return; return;
@ -280,11 +295,11 @@ void process_udp4(const struct s_ethernet *eth_hdr, struct s_ip4 *ip_hdr, const
/* check if this packet is from wrapped connection */ /* check if this packet is from wrapped connection */
if (ent == NULL) { if (ent == NULL) {
fprintf(stderr, "Error: data not found\n"); printf("Error: data not found\n");
return; return;
} }
else if (memcmp(&ent->addr_to, &ip_hdr->ip_src, sizeof(struct in_addr))) { else if (memcmp(&ent->addr_to, &ip_hdr->ip_src, sizeof(struct in_addr))) {
fprintf(stderr, "Error: data not appropriate\n"); printf("Error: data not appropriate\n");
printf(" Ent-to: %s\n", inet_ntoa(ent->addr_to)); printf(" Ent-to: %s\n", inet_ntoa(ent->addr_to));
printf(" IP-from: %s\n", inet_ntoa(ip_hdr->ip_src)); printf(" IP-from: %s\n", inet_ntoa(ip_hdr->ip_src));
return; return;
@ -387,11 +402,11 @@ void process_icmp4(const struct s_ethernet *eth_hdr, struct s_ip4 *ip_hdr, const
/* check if this packet is from wrapped connection */ /* check if this packet is from wrapped connection */
if (ent == NULL) { if (ent == NULL) {
fprintf(stderr, "Error: data not found\n"); printf("Error: data not found\n");
return; return;
} }
else if (memcmp(&ent->addr_to, &ip_hdr->ip_src, sizeof(struct in_addr))) { else if (memcmp(&ent->addr_to, &ip_hdr->ip_src, sizeof(struct in_addr))) {
fprintf(stderr, "Error: data not appropriate\n"); printf("Error: data not appropriate\n");
printf(" Ent-to: %s\n", inet_ntoa(ent->addr_to)); printf(" Ent-to: %s\n", inet_ntoa(ent->addr_to));
printf(" IP-from: %s\n", inet_ntoa(ip_hdr->ip_src)); printf(" IP-from: %s\n", inet_ntoa(ip_hdr->ip_src));
return; return;

View File

@ -13,9 +13,13 @@ jsw_rbtree_t *stg_conn_tcp;
jsw_rbtree_t *stg_conn_udp; jsw_rbtree_t *stg_conn_udp;
jsw_rbtree_t *stg_conn_icmp; jsw_rbtree_t *stg_conn_icmp;
/*
* 1: IPv4 address
* 2: IPv6 prefix
* 3: ethernet device
*/
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */ char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
pcap_t *handle; /* packet capture handle */ pcap_t *handle; /* packet capture handle */
@ -30,11 +34,21 @@ int main(int argc, char **argv)
/* find a capture device */ /* find a capture device */
dev = NULL; dev = NULL;
printf("Args: %d\n", argc);
if (argc == 4) {
if ((dev = malloc(strlen(argv[3]))) == NULL) {
fprintf(stderr, "Fatal Error! Lack of free memory!\n");
exit(EXIT_FAILURE);
}
memcpy(dev, argv[3], sizeof(dev));
}
else {
dev = pcap_lookupdev(errbuf); dev = pcap_lookupdev(errbuf);
if (dev == NULL) { if (dev == NULL) {
fprintf(stderr, "Couldn't find default device: %s\n", errbuf); fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
}
/* print capture info */ /* print capture info */
printf("Device: %s\n", dev); printf("Device: %s\n", dev);
@ -72,8 +86,10 @@ int main(int argc, char **argv)
dev_index = get_dev_index(dev); dev_index = get_dev_index(dev);
/* set the WrapSix addresses */ /* set the WrapSix addresses */
inet_aton("10.0.0.111", &ip4addr_wrapsix); //inet_aton("10.0.0.111", &ip4addr_wrapsix);
inet_pton(AF_INET6, "fc00:1::", &ip6addr_wrapsix); //inet_pton(AF_INET6, "fc00:1::", &ip6addr_wrapsix);
inet_aton(argv[1], &ip4addr_wrapsix);
inet_pton(AF_INET6, argv[2], &ip6addr_wrapsix);
/* compile the filter expression */ /* compile the filter expression */
if (pcap_compile(handle, &fp, filter_exp, 0, 0) == -1) { if (pcap_compile(handle, &fp, filter_exp, 0, 0) == -1) {

View File

@ -3,63 +3,102 @@
## WrapSix ## WrapSix
### ###
#> wrapsix.rb #> wrapsix.rb
#~ Description... #~ Main part of WrapSix that starts all other components
#### ####
# Author: Michal Zima, 2008 # Author: Michal Zima, 2008-2009
# E-mail: xhire@tuxportal.cz # E-mail: xhire@tuxportal.cz
# Homepage: http://wrapsix.tuxportal.cz/
##### #####
$version = '0.1.0'
### Hardcoded configuration => configured by system administrator
$config = {} $config = {}
$config['config_file'] = 'conf/wrapsix.conf' $config['config_file'] = 'conf/wrapsix.conf'
#------------------------------------------------------------------------------#
### Include all necessary libraries ### Include all necessary libraries
require 'yaml' require 'yaml'
require 'socket' require 'socket'
require 'optparse'
# WrapSix libs # WrapSix libs
require 'lib/resolver' require 'lib/resolver'
require 'lib/wrapper' require 'lib/wrapper'
### Parse command line arguments if any ### Parse command line arguments if any
OptionParser.new do |opts|
opts.banner = "Usage: wrapsix.rb [options]"
### Load configuration opts.on("--[no-]resolver", "Run the DNS resolver") do |resolver|
configuration = YAML.load_file $config['config_file'] $config['resolver'] = resolver
end
## Merge both configs opts.on("--[no-]wrapper", "Run the wrapper") do |wrapper|
$config.merge! configuration # FIX: this overwrites those configs from command line! $config['wrapper'] = wrapper
#p $config end
### Start logging facility (system wide one) opts.on("--resolver-ip=IPv6_address", "Set the IPv6 address for the DNS resolver") do |rip|
$config['resolver_ip'] = rip
end
opts.on("--dns-resolver=IP_address", "Set the address of DNS resolver to be used") do |sr|
$config['secondary_resolver'] = sr
end
opts.on("--device=dev", "Set the network interface to override automatic detection") do |nic|
$config['wrapper_device'] = nic
end
opts.on("--ipv6=prefix", "Set the IPv6 preffix (max. /96), e.g. fc00::") do |prefix|
$config['wrapper_ipv6_prefix'] = prefix
end
opts.on("--ipv4=address", "Set the IPv4 address") do |addr|
$config['wrapper_ipv4_address'] = addr
end
opts.on("-d", "--[no-]debug", "Run in the debug mode") do |d|
$config['debug'] = d
end
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
end
# Another typical switch to print the version.
opts.on_tail("-v", "--version", "Show version") do
puts "WrapSix #{$version}"
puts "Copyright (c) 2008-2009 Michal Zima"
exit
end
end.parse!
### Load configuration from file and merge it with the original one
$config = YAML.load_file($config['config_file']).merge $config
### Handle some signals ### Handle some signals
# todo: replace this with right variables
def exit def exit
$resolver.exit if $config['resolver'] $resolver.exit if $config['resolver']
$wrapper.exit if $config['wrapper'] $wrapper.exit if $config['wrapper']
Process.exit Process.exit
end end
# TERM -KILL- QUIT INT # TERM QUIT INT
trap "INT" do; exit; end trap "INT" do; exit; end
trap "TERM" do; exit; end trap "TERM" do; exit; end
trap "QUIT" do; exit; end trap "QUIT" do; exit; end
services = [] services = []
### Start DNS resolver function ### Start DNS resolver function
if $config['resolver'] == 1 $resolver = Resolver.new
$resolver = Resolver.new if $config['resolver'] == true
services << Thread.start do; $resolver.start; end services << Thread.start do; $resolver.start; end
end end
### Start IPv6-to-IPv4 wrapper ### Start IPv6-to-IPv4 wrapper
if $config['wrapper'] == 1 $wrapper = Wrapper.new
$wrapper = Wrapper.new if $config['wrapper'] == true
services << Thread.start do; $wrapper.start; end services << Thread.start do; $wrapper.start; end
end end
### Start WrapSix ### Start WrapSix
# in best conditions it would *never* stop # in best conditions it would *never* stop
services.each do |srvc| srvc.join end services.each do |srvc| srvc.join end