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
####
# Author: Michal Zima, 2008
# Author: Michal Zima, 2008-2009
# E-mail: xhire@tuxportal.cz
#####
== 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 ==
WrapSix is very simple to use. You only need:
* GNU/Linux system
* Ruby (I've tested version 1.8.6)
* GNU/Linux system with IPv6 support (best with 2.6.12 or newer; tested with 2.6.11 (OK) and 2.6.17 (OK))
* C compiler and such things (just to build binaries of course)
* 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 ==
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 ==
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 ==
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
resolver: 1
#resolver_ip: '::1'
resolver_ip: '2001:470:9985:1:200:e2ff:fe7f:414'
secondary_resolver: 10.0.0.139 # if not set => /etc/resolv.conf
resolver: true
resolver_ip: 'fc00:1::1'
secondary_resolver: 10.0.0.1 # if not set => /etc/resolv.conf
### 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
debug: 1
debug: false

View File

@ -4,7 +4,7 @@
#> lib/resolver.rb
#~ WrapSix Resolver
####
# Author: Michal Zima, 2008
# Author: Michal Zima, 2008-2009
# E-mail: xhire@tuxportal.cz
#####
@ -20,7 +20,6 @@ class Resolver
@resolver = UDPSocket.open Socket::AF_INET6
begin
@resolver.bind $config['resolver_ip'], 53
#rescue Errno::EPERM
rescue Errno::EACCES
$stderr.puts "You have to run #{$0} as root!"
exit!
@ -28,7 +27,6 @@ class Resolver
puts "Started DNS resolver on IPv6 address #{$config['resolver_ip']}" if @debug
loop do
puts "---------- start ----------" if @debug
# Receive and parse query
data = @resolver.recvfrom 2048
print "Client: " if @debug
@ -44,16 +42,16 @@ class Resolver
answer.opcode = query.opcode # Type of Query; copy from query
answer.aa = 0 # Is this an authoritative response: 0 = No, 1 = Yes
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
query.each_question do |question, typeclass| # There may be multiple questions per query
begin
name = question.to_s # The domain name looked for in the query.
answer.add_question name, typeclass
puts "Looking for: #{name}" if @debug
#record_type = typeclass.name.split("::").last # For example "A", "MX"
puts "RR: #{typeclass}" if @debug
#puts "RR: #{record_type}" if @debug
# So let's look for it :c) (in secondary resolver)
sr = Resolv::DNS::new :nameserver => $config['secondary_resolver']
@ -75,18 +73,43 @@ class Resolver
print "My answer: " if @debug
p answer if @debug
rescue Resolv::ResolvError
puts "Error: DNS result has no information for #{name}"
# 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
puts "Error: DNS result has no information for #{name}"
end
end
end
# send the response
@resolver.send answer.encode, 0, data[1][3], data[1][1] # msg, flags, client, port
puts "---------- end ----------" if @debug
end
end
def exit
@resolver.close
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

View File

@ -4,15 +4,22 @@
#> lib/wrapper.rb
#~ WrapSix Wrapper
####
# Author: Michal Zima, 2008
# Author: Michal Zima, 2008-2009
# E-mail: xhire@tuxportal.cz
#####
class Wrapper
def initializer
@debug = $config['debug']
end
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
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(" To: %s\n", inet_ntoa(ip->ip_dest));
/* check if this packet is ours */
if (memcmp(&ip4addr_wrapsix, &ip->ip_dest, 4)) {
printf("==> This packet is not ours! <==\n");
return;
}
/* determine protocol */
switch (ip->proto) {
case IPPROTO_TCP:
printf(" Protocol: TCP\n");
/* check if this packet is ours */
if (memcmp(&ip4addr_wrapsix, &ip->ip_dest, 4)) {
printf("==> This packet is not ours! <==\n");
return;
}
process_tcp4(eth, ip, payload, htons(ip->pckt_len) - header_length);
break;
case IPPROTO_UDP:
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);
break;
case IPPROTO_ICMP:
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);
break;
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 */
if (ent == NULL) {
fprintf(stderr, "Error: data not found\n");
printf("Error: data not found\n");
return;
}
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(" IP-from: %s\n", inet_ntoa(ip_hdr->ip_src));
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 */
if (ent == NULL) {
fprintf(stderr, "Error: data not found\n");
printf("Error: data not found\n");
return;
}
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(" IP-from: %s\n", inet_ntoa(ip_hdr->ip_src));
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 */
if (ent == NULL) {
fprintf(stderr, "Error: data not found\n");
printf("Error: data not found\n");
return;
}
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(" IP-from: %s\n", inet_ntoa(ip_hdr->ip_src));
return;

View File

@ -13,9 +13,13 @@ jsw_rbtree_t *stg_conn_tcp;
jsw_rbtree_t *stg_conn_udp;
jsw_rbtree_t *stg_conn_icmp;
/*
* 1: IPv4 address
* 2: IPv6 prefix
* 3: ethernet device
*/
int main(int argc, char **argv)
{
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
pcap_t *handle; /* packet capture handle */
@ -30,10 +34,20 @@ int main(int argc, char **argv)
/* find a capture device */
dev = NULL;
dev = pcap_lookupdev(errbuf);
if (dev == NULL) {
fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
exit(EXIT_FAILURE);
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);
if (dev == NULL) {
fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
exit(EXIT_FAILURE);
}
}
/* print capture info */
@ -72,8 +86,10 @@ int main(int argc, char **argv)
dev_index = get_dev_index(dev);
/* set the WrapSix addresses */
inet_aton("10.0.0.111", &ip4addr_wrapsix);
inet_pton(AF_INET6, "fc00:1::", &ip6addr_wrapsix);
//inet_aton("10.0.0.111", &ip4addr_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 */
if (pcap_compile(handle, &fp, filter_exp, 0, 0) == -1) {

View File

@ -3,63 +3,102 @@
## WrapSix
###
#> wrapsix.rb
#~ Description...
#~ Main part of WrapSix that starts all other components
####
# Author: Michal Zima, 2008
# E-mail: xhire@tuxportal.cz
# Author: Michal Zima, 2008-2009
# E-mail: xhire@tuxportal.cz
# Homepage: http://wrapsix.tuxportal.cz/
#####
$version = '0.1.0'
### Hardcoded configuration => configured by system administrator
$config = {}
$config['config_file'] = 'conf/wrapsix.conf'
#------------------------------------------------------------------------------#
### Include all necessary libraries
require 'yaml'
require 'socket'
require 'optparse'
# WrapSix libs
require 'lib/resolver'
require 'lib/wrapper'
### Parse command line arguments if any
OptionParser.new do |opts|
opts.banner = "Usage: wrapsix.rb [options]"
### Load configuration
configuration = YAML.load_file $config['config_file']
opts.on("--[no-]resolver", "Run the DNS resolver") do |resolver|
$config['resolver'] = resolver
end
## Merge both configs
$config.merge! configuration # FIX: this overwrites those configs from command line!
#p $config
opts.on("--[no-]wrapper", "Run the wrapper") do |wrapper|
$config['wrapper'] = wrapper
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
# todo: replace this with right variables
def exit
$resolver.exit if $config['resolver']
$wrapper.exit if $config['wrapper']
Process.exit
end
# TERM -KILL- QUIT INT
# TERM QUIT INT
trap "INT" do; exit; end
trap "TERM" do; exit; end
trap "QUIT" do; exit; end
services = []
### 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
end
### 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
end
### Start WrapSix
# in best conditions it would *never* stop
services.each do |srvc| srvc.join end