From 4bc68edce5f5fb9e5216a190d5213605ca86e1ec Mon Sep 17 00:00:00 2001 From: xHire Date: Wed, 31 Dec 2008 13:41:21 +0100 Subject: [PATCH] Improved creating of a socket for the resolver Written new mechanism of wrapper from scratch in C * It listens to all ICMPv6 packets (for now) and translates them to ICMPv4 ones * It can compute the checksum of the packet as well --- README | 2 +- lib/resolver.rb | 11 ++-- wrapper/Makefile | 24 +++++++ wrapper/checksum.c | 30 +++++++++ wrapper/connections.c | 23 +++++++ wrapper/process.c | 140 +++++++++++++++++++++++++++++++++++++++++ wrapper/translate_ip.c | 18 ++++++ wrapper/translate_ip.h | 15 +++++ wrapper/wrapper.c | 73 +++++++++++++++++++++ wrapper/wrapper.h | 93 +++++++++++++++++++++++++++ wrapsix.rb | 4 +- 11 files changed, 426 insertions(+), 7 deletions(-) create mode 100644 wrapper/Makefile create mode 100644 wrapper/checksum.c create mode 100644 wrapper/connections.c create mode 100644 wrapper/process.c create mode 100644 wrapper/translate_ip.c create mode 100644 wrapper/translate_ip.h create mode 100644 wrapper/wrapper.c create mode 100644 wrapper/wrapper.h diff --git a/README b/README index 7f3f744..a517269 100644 --- a/README +++ b/README @@ -11,7 +11,7 @@ WrapSix is a revolutionary piece of software that make possible to reach IPv4-on == Requirements == WrapSix is very simple to use. You only need: * GNU/Linux system -* Ruby (I've tested version 1.8.7) +* Ruby (I've tested version 1.8.6) == Configuration == diff --git a/lib/resolver.rb b/lib/resolver.rb index 8459fd5..e7d0bf0 100644 --- a/lib/resolver.rb +++ b/lib/resolver.rb @@ -18,11 +18,14 @@ class Resolver def start @resolver = UDPSocket.open Socket::AF_INET6 - if @resolver.bind $config['resolver_ip'], 53 - puts "Started DNS resolver on IPv6 address #{$config['resolver_ip']}" if @debug - else - puts "DNS resolver not started!" if @debug + begin + @resolver.bind $config['resolver_ip'], 53 + #rescue Errno::EPERM + rescue Errno::EACCES + $stderr.puts "You have to run #{$0} as root!" + exit! end + puts "Started DNS resolver on IPv6 address #{$config['resolver_ip']}" if @debug loop do puts "---------- start ----------" if @debug diff --git a/wrapper/Makefile b/wrapper/Makefile new file mode 100644 index 0000000..da2d495 --- /dev/null +++ b/wrapper/Makefile @@ -0,0 +1,24 @@ +CC = gcc +CFLAGS = -Wall -O0 +LDFLAGS = -L/usr/lib -lpcap + +all: wrapper.o process.o translate_ip.o connections.o checksum.o + $(CC) $(CFLAGS) $(LDFLAGS) *.o -o wrapper + +wrapper.o: wrapper.c wrapper.h + $(CC) $(CFLAGS) -c wrapper.c -o wrapper.o + +process.o: process.c wrapper.h translate_ip.h + $(CC) $(CFLAGS) -c process.c -o process.o + +translate_ip.o: translate_ip.c translate_ip.h wrapper.h + $(CC) $(CFLAGS) -c translate_ip.c -o translate_ip.o + +connections.o: connections.c wrapper.h + $(CC) $(CFLAGS) -c connections.c -o connections.o + +checksum.o: checksum.c + $(CC) $(CFLAGS) -c checksum.c -o checksum.o + +clean: + rm -f wrapper *.o diff --git a/wrapper/checksum.c b/wrapper/checksum.c new file mode 100644 index 0000000..174f82c --- /dev/null +++ b/wrapper/checksum.c @@ -0,0 +1,30 @@ +unsigned short checksum(const void *_buf, int len) +{ + const unsigned short *buf = _buf; + unsigned sum = 0; + + while (len >= 2) { + sum += *buf ++; + + if (sum & 0x80000000) { + sum = (sum & 0xffff) + (sum >> 16); + } + + len -= 2; + } + + if (len) { + unsigned char temp[2]; + + temp[0] = *(unsigned char *) buf; + temp[1] = 0; + + sum += *(unsigned short *) temp; + } + + while (sum >> 16) { + sum = (sum & 0xffff) + (sum >> 16); + } + + return ~sum; +} diff --git a/wrapper/connections.c b/wrapper/connections.c new file mode 100644 index 0000000..f40fe8b --- /dev/null +++ b/wrapper/connections.c @@ -0,0 +1,23 @@ +#include + +#include "wrapper.h" + +void send_there(struct in_addr ip4_addr, unsigned char ttl, unsigned int type, unsigned char *payload, unsigned int paylen) { + int sock; + struct sockaddr_in sock_addr; + + if ((sock = socket(AF_INET, SOCK_RAW, type)) == -1) { + fprintf(stderr, "Couldn't open RAW socket.\n"); + exit(EXIT_FAILURE); + } + + setsockopt(sock, IPPROTO_IP, IP_TTL, (const char *) &ttl, sizeof(ttl)); + + sock_addr.sin_family = AF_INET; + sock_addr.sin_port = 0; + sock_addr.sin_addr = ip4_addr; + + sendto(sock, (char *) payload, paylen, 0, (struct sockaddr *) &sock_addr, sizeof(struct sockaddr)); + + close(sock); +} diff --git a/wrapper/process.c b/wrapper/process.c new file mode 100644 index 0000000..bdd95df --- /dev/null +++ b/wrapper/process.c @@ -0,0 +1,140 @@ +#include "wrapper.h" +#include "translate_ip.h" + +void process_packet6(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) +{ + static int count = 1; /* packet counter */ + + /* declare pointers to packet headers */ + const struct s_ethernet *ethernet; /* The ethernet header [1] */ + const struct s_ip6 *ip; /* The IP header */ + const unsigned char *payload; /* Packet payload */ + + printf("\nPacket number %d:\n", count); + count++; + + /* define ethernet header */ + ethernet = (struct s_ethernet*) (packet); + + /* define/compute ip header offset */ + ip = (struct s_ip6*) (packet + SIZE_ETHERNET); + + payload = packet + SIZE_ETHERNET + SIZE_IP6; + + /* print source and destination IP addresses */ + char ip6addr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &ip->ip_src, ip6addr, sizeof(ip6addr)); + printf(" From: %s\n", ip6addr); + /* keep the following line as the last one inet_ntop! */ + inet_ntop(AF_INET6, &ip->ip_dest, ip6addr, sizeof(ip6addr)); + printf(" To: %s\n", ip6addr); + + /* check if this packet is ours - hardcoded for now */ + char wsaddr[INET6_ADDRSTRLEN] = "fc00:1::4d4b:4c03"; + if (strcmp(wsaddr, ip6addr) != 0) { + printf("==> This packet is not ours! <==\n"); + return; + } + + /* determine protocol */ + switch (ip->next_header) { + case IPPROTO_TCP: + printf(" Protocol: TCP\n"); + //process_tcp(); + break; + case IPPROTO_UDP: + printf(" Protocol: UDP\n"); + break; + case IPPROTO_ICMPV6: + printf(" Protocol: ICMPv6\n"); + process_icmp6((struct s_ip6 *) ip, payload); + break; + default: + printf(" Protocol: unknown\n"); + break; + } + return; +} + +void process_icmp6(struct s_ip6 *ip, const unsigned char *payload) +{ + struct s_icmp *icmp; + struct in_addr ip4_addr; + + unsigned char *icmp_data; + unsigned char *icmp_packet; + + int packet_size; + + /* extract the ICMP header */ + icmp = (struct s_icmp *) (payload); + icmp_data = (unsigned char *) (payload + sizeof(icmp)); + + /* decide what type of ICMP we have */ + switch (icmp->type) { + /* NDP */ + case ICMP6_NDP_NS: + printf(" ICMP: [NDP] Neighbor Solicitation\n"); + break; + case ICMP6_NDP_NA: + printf(" ICMP: [NDP] Neighbor Advertisement\n"); + break; + case ICMP6_NDP_RS: + printf(" ICMP: [NDP] Router Solicitation\n"); + break; + case ICMP6_NDP_RA: + printf(" ICMP: [NDP] Router Advertisement\n"); + break; + case ICMP6_NDP_RM: + printf(" ICMP: [NDP] Redirect Message\n"); + break; + /* ping */ + case ICMP6_ECHO_REQUEST: + printf(" ICMP: Echo Request\n"); + + packet_size = htons(ip->len); + icmp_packet = (unsigned char *) malloc(packet_size); + + if (icmp_packet == NULL) { + fprintf(stderr, "Fatal error! Lack of free memory!\n"); + exit(EXIT_FAILURE); + } + + struct s_icmp_ping *icmp_ping = (struct s_icmp_ping *) icmp_data; + + icmp->type = ICMP4_ECHO_REQUEST; + icmp->code = 0; + icmp->checksum = 0; + + printf("[id;seq]:[0x%x;0x%x]\n", htons(icmp_ping->id), htons(icmp_ping->seq)); + + memcpy(icmp_packet, icmp, sizeof(struct s_icmp)); + memcpy(icmp_packet + sizeof(struct s_icmp), icmp_data, packet_size - sizeof(struct s_icmp)); + + // compute the checksum :c) + icmp->checksum = checksum(icmp_packet, packet_size); + + // copy this structure again - because of the checksum + memcpy(icmp_packet, icmp, sizeof(struct s_icmp)); + + break; + case ICMP6_ECHO_REPLY: + printf(" ICMP: Echo Reply\n"); + break; + default: + printf(" ICMP: unknown: %d/0x%x\n", icmp->type, icmp->type); + break; + } + + /* where to send this ICMP */ + ip4_addr = ipaddr_6to4((struct in6_addr) ip->ip_dest); + printf(" Send to: %s\n", inet_ntoa(ip4_addr)); + + /* send */ + send_there(ip4_addr, ip->hop_limit, IPPROTO_ICMP, icmp_packet, packet_size); + + free(icmp_packet); + icmp_packet = NULL; + + return; +} diff --git a/wrapper/translate_ip.c b/wrapper/translate_ip.c new file mode 100644 index 0000000..5fcfef5 --- /dev/null +++ b/wrapper/translate_ip.c @@ -0,0 +1,18 @@ +#include "wrapper.h" +#include "translate_ip.h" + +struct in_addr ipaddr_6to4(struct in6_addr ip6_addr) +{ + struct ip6addr_ip4part *addr; + struct in_addr ip4_addr; + char ip4_str[15]; + + /* "parse" the IPv6 addres */ + addr = (struct ip6addr_ip4part *)(&ip6_addr); + + /* build IPv4 address */ + sprintf(ip4_str, "%d.%d.%d.%d", addr->a, addr->b, addr->c, addr->d); + inet_aton(ip4_str, &ip4_addr); + + return ip4_addr; +} diff --git a/wrapper/translate_ip.h b/wrapper/translate_ip.h new file mode 100644 index 0000000..53cd9b5 --- /dev/null +++ b/wrapper/translate_ip.h @@ -0,0 +1,15 @@ +#ifndef TRANSLATE_IP_H +#define TRANSLATE_IP_H + +struct ip6addr_ip4part { + long double prefix; + unsigned char a; + unsigned char b; + unsigned char c; + unsigned char d; +}; + +struct in_addr ipaddr_6to4(struct in6_addr ip6_addr); +//in6_addr ipaddr_4to6(in_addr ip_addr); + +#endif diff --git a/wrapper/wrapper.c b/wrapper/wrapper.c new file mode 100644 index 0000000..1161621 --- /dev/null +++ b/wrapper/wrapper.c @@ -0,0 +1,73 @@ +#include "wrapper.h" + +int main(int argc, char **argv) +{ + + char *dev = NULL; /* capture device name */ + char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */ + pcap_t *handle; /* packet capture handle */ + + //char filter_exp[] = "ip6"; /* filter expression */ + char filter_exp[] = "icmp6"; /* filter expression */ + struct bpf_program fp; /* compiled filter program (expression) */ + bpf_u_int32 mask; /* subnet mask */ + bpf_u_int32 net; /* ip */ + int num_packets = 0; /* number of packets to capture */ + + /* find a capture device */ + dev = pcap_lookupdev(errbuf); + if (dev == NULL) { + fprintf(stderr, "Couldn't find default device: %s\n", errbuf); + exit(EXIT_FAILURE); + } + + /* get network number and mask associated with capture device */ + if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) { + fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf); + net = 0; + mask = 0; + } + + /* print capture info */ + printf("Device: %s\n", dev); + printf("Number of packets: %d\n", num_packets); + printf("Filter expression: %s\n", filter_exp); + + /* open capture device */ + handle = pcap_open_live(dev, SNAP_LEN, 1, 1, errbuf); + if (handle == NULL) { + fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf); + exit(EXIT_FAILURE); + } + + /* make sure we're capturing on an Ethernet device */ + if (pcap_datalink(handle) != DLT_EN10MB) { + fprintf(stderr, "%s is not an Ethernet\n", dev); + exit(EXIT_FAILURE); + } + + /* compile the filter expression */ + if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) { + fprintf(stderr, "Couldn't parse filter %s: %s\n", + filter_exp, pcap_geterr(handle)); + exit(EXIT_FAILURE); + } + + /* apply the compiled filter */ + if (pcap_setfilter(handle, &fp) == -1) { + fprintf(stderr, "Couldn't install filter %s: %s\n", + filter_exp, pcap_geterr(handle)); + exit(EXIT_FAILURE); + } + + /* now we can set our callback function */ + pcap_loop(handle, num_packets, process_packet6, NULL); + + /* cleanup */ + pcap_freecode(&fp); + pcap_close(handle); + + printf("\nCapture complete.\n"); + + return 0; +} diff --git a/wrapper/wrapper.h b/wrapper/wrapper.h new file mode 100644 index 0000000..7bea80a --- /dev/null +++ b/wrapper/wrapper.h @@ -0,0 +1,93 @@ +#ifndef WRAPPER_H +#define WRAPPER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Default snap length (maximum bytes per packet to capture) */ +#define SNAP_LEN BUFSIZ + +/* Ethernet headers are always exactly 14 bytes */ +#define SIZE_ETHERNET 14 + +/* Ethernet addresses are 6 bytes */ +#define ETHER_ADDR_LEN 6 + +/* IPv6 headers are always exactly 40 bytes */ +#define SIZE_IP6 40 + +/* Ethernet header */ +struct s_ethernet { + u_char ether_dhost[ETHER_ADDR_LEN]; /* destination host address */ + u_char ether_shost[ETHER_ADDR_LEN]; /* source host address */ + u_short ether_type; /* IP/ARP/RARP/... */ +}; + +/* IPv4 header */ + +/* IPv6 header */ +struct s_ip6 { + unsigned char ver; /* 8 b; version */ + unsigned char traffic_class; /* 8 b; traffic class */ + unsigned short flow_label; /* 16 b; flow label (qos) */ + unsigned short len; /* 16 b; payload length */ + unsigned char next_header; /* 8 b; next header */ + unsigned char hop_limit; /* 8 b; hop limit (replaces ttl) */ + struct in6_addr ip_src; /* 128 b; source address */ + struct in6_addr ip_dest; /* 128 b; destination address */ +}; + +/* TCP structure - only needed fields! */ +struct s_tcp { + unsigned short port_src; /* 16 b; source port */ + unsigned short port_dest; /* 16 b; destination port */ + long double data1; /* 96 b; first data segment */ + unsigned short checksum; /* 16 b */ + unsigned short data2; /* 16 b; the rest (urgent pointer here) */ +}; + +/* UDP structure */ + +/* ICMP header structure */ +struct s_icmp { + unsigned char type; /* 8 b; ICMP type */ + unsigned char code; /* 8 b; further specification of ICMP type */ + unsigned short checksum; /* 16 b */ +}; + +/* ICMP - ping structure */ +struct s_icmp_ping { + unsigned short id; /* 16 b; ID value for ECHO REPLY */ + unsigned short seq; /* 16 b; sequence value for ECHO REPLY */ +}; + +/* ICMP types */ +#define ICMP4_ECHO_REQUEST 0x8 +#define ICMP4_ECHO_REPLY 0x0 + +/* ICMPv6 types */ +#define ICMP6_ECHO_REQUEST 0x80 +#define ICMP6_ECHO_REPLY 0x81 +#define ICMP6_NDP_RS 0x85 +#define ICMP6_NDP_RA 0x86 +#define ICMP6_NDP_NS 0x87 +#define ICMP6_NDP_NA 0x88 +#define ICMP6_NDP_RM 0x89 + +/* Prototypes */ +void process_packet6(u_char *args, const struct pcap_pkthdr *header, const u_char *packet); +void process_icmp6(struct s_ip6 *ip, const unsigned char *payload); + +void send_there(struct in_addr ip4_addr, unsigned char ttl, unsigned int type, unsigned char *payload, unsigned int paylen); + +unsigned short checksum(const void *_buf, int len); + +#endif diff --git a/wrapsix.rb b/wrapsix.rb index 758e6d2..8984326 100755 --- a/wrapsix.rb +++ b/wrapsix.rb @@ -48,13 +48,13 @@ trap "QUIT" do; exit; end services = [] ### Start DNS resolver function -if $config['resolver'] +if $config['resolver'] == 1 $resolver = Resolver.new services << Thread.start do; $resolver.start; end end ### Start IPv6-to-IPv4 wrapper -if $config['wrapper'] +if $config['wrapper'] == 1 $wrapper = Wrapper.new services << Thread.start do; $wrapper.start; end end