diff --git a/wrapper/Makefile b/wrapper/Makefile index 4fb8d1d..304b28e 100644 --- a/wrapper/Makefile +++ b/wrapper/Makefile @@ -1,15 +1,16 @@ CC = gcc -CFLAGS = -Wall -O0 +CFLAGS = -Wall -O0 -g LDFLAGS = -L/usr/lib -lpcap +INCLUDE = -Ilib -all: wrapper.o process.o translate_ip.o connections.o checksum.o if.o - $(CC) $(CFLAGS) $(LDFLAGS) *.o -o wrapper +all: wrapper.o process.o translate_ip.o connections.o checksum.o if.o storage.o lib/jsw_rbtree.o + $(CC) $(CFLAGS) $(LDFLAGS) *.o lib/*.o -o wrapper wrapper.o: wrapper.c wrapper.h - $(CC) $(CFLAGS) -c wrapper.c -o wrapper.o + $(CC) $(CFLAGS) $(INCLUDE) -c wrapper.c -o wrapper.o process.o: process.c wrapper.h translate_ip.h - $(CC) $(CFLAGS) -c process.c -o process.o + $(CC) $(CFLAGS) $(INCLUDE) -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 @@ -18,10 +19,17 @@ 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 + $(CC) $(CFLAGS) -c checksum.c -o checksum.o if.o: if.c wrapper.h $(CC) $(CFLAGS) -c if.c -o if.o +storage.o: storage.c storage.h + $(CC) $(CFLAGS) $(INCLUDE) -c storage.c -o storage.o + +# libraries +lib/jsw_rbtree.o: lib/jsw_rbtree.c lib/jsw_rbtree.h + $(CC) $(CFLAGS) -c lib/jsw_rbtree.c -o lib/jsw_rbtree.o + clean: - rm -f wrapper *.o + rm -f wrapper *.o lib/*.o diff --git a/wrapper/checksum.c b/wrapper/checksum.c index 174f82c..d8d4ca9 100644 --- a/wrapper/checksum.c +++ b/wrapper/checksum.c @@ -1,7 +1,9 @@ +#include "wrapper.h" + unsigned short checksum(const void *_buf, int len) { const unsigned short *buf = _buf; - unsigned sum = 0; + unsigned int sum = 0; while (len >= 2) { sum += *buf ++; @@ -28,3 +30,35 @@ unsigned short checksum(const void *_buf, int len) return ~sum; } + +unsigned short checksum_ipv6(struct in6_addr ip_src, struct in6_addr ip_dest, unsigned short paylen, unsigned char proto, unsigned char *data) +{ + unsigned char *buf_ip6_pseudo; + struct s_ip6_pseudo *ip6_pseudo; + unsigned short sum; + unsigned int length = (unsigned int) paylen; + + buf_ip6_pseudo = (unsigned char *) malloc(sizeof(struct s_ip6_pseudo) + length); + + if (buf_ip6_pseudo == NULL) { + fprintf(stderr, "Fatal error! Lack of free memory!\n"); + exit(EXIT_FAILURE); + } + + ip6_pseudo = (struct s_ip6_pseudo *) buf_ip6_pseudo; + + ip6_pseudo->ip_src = ip_src; + ip6_pseudo->ip_dest = ip_dest; + ip6_pseudo->len = htonl(length); + ip6_pseudo->zeros = 0x0; + ip6_pseudo->next_header = proto; + + memcpy(buf_ip6_pseudo + sizeof(struct s_ip6_pseudo), data, length); + + sum = checksum(buf_ip6_pseudo, sizeof(struct s_ip6_pseudo) + length); + + free(buf_ip6_pseudo); + buf_ip6_pseudo = NULL; + + return sum; +} diff --git a/wrapper/connections.c b/wrapper/connections.c index 78e98dc..ffd598e 100644 --- a/wrapper/connections.c +++ b/wrapper/connections.c @@ -5,26 +5,41 @@ #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; + int sock; + + /* prepare data for the socket */ + sock_addr.sin_family = AF_INET; + sock_addr.sin_port = 0; + sock_addr.sin_addr = ip4_addr; + + /* initialize the socket */ if ((sock = socket(AF_INET, SOCK_RAW, type)) == -1) { fprintf(stderr, "Couldn't open RAW socket.\n"); + perror("socket()"); exit(EXIT_FAILURE); } - setsockopt(sock, IPPROTO_IP, IP_TTL, (const char *) &ttl, sizeof(ttl)); + /* applies settings of the socket */ + if (setsockopt(sock, IPPROTO_IP, IP_TTL, (const char *) &ttl, sizeof(ttl)) == -1) { + fprintf(stderr, "Couldn't apply settings of the socket.\n"); + perror("setsockopt()"); + exit(EXIT_FAILURE); + } - 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)); + /* send the packet */ + if (sendto(sock, (char *) payload, paylen, 0, (struct sockaddr *) &sock_addr, sizeof(struct sockaddr)) != paylen) { + fprintf(stderr, " Error: Couldn't send an IPv4 packet.\n"); + perror("sendto()"); + exit(EXIT_FAILURE); + } + /* close the socket */ close(sock); } -void send_ndp(struct ip6_hdr *ip, unsigned char *packet, int packet_size) +void send_ipv6(unsigned char *packet, int packet_size) { struct sockaddr_ll socket_address; /* target address */ struct ifreq ifr; /* interface */ @@ -34,7 +49,7 @@ void send_ndp(struct ip6_hdr *ip, unsigned char *packet, int packet_size) /* prepare data for RAW socket */ socket_address.sll_family = PF_PACKET; /* RAW communication */ socket_address.sll_protocol = htons(ETH_P_IP); /* protocol above the ethernet layer */ - socket_address.sll_ifindex = get_dev_index(dev); /* set index of the network device */ + socket_address.sll_ifindex = dev_index; /* set index of the network device */ socket_address.sll_pkttype = PACKET_OTHERHOST; /* target host is another host */ /* initialize with zeros */ @@ -59,7 +74,7 @@ void send_ndp(struct ip6_hdr *ip, unsigned char *packet, int packet_size) /* send the NDP packet */ if (sendto(sock, packet, packet_size, 0, (struct sockaddr *) &socket_address, sizeof(struct sockaddr_ll)) != packet_size) { - fprintf(stderr, " Error: Couldn't send NDP packet.\n"); + fprintf(stderr, " Error: Couldn't send an IPv6 packet.\n"); perror("sendto()"); exit(EXIT_FAILURE); } diff --git a/wrapper/if.c b/wrapper/if.c index 83a7e3b..31b992f 100644 --- a/wrapper/if.c +++ b/wrapper/if.c @@ -31,6 +31,34 @@ int get_mac_addr(const char *dev, struct s_mac_addr *addr) return ret; } +/* + * Return the IP address + */ +int get_ip_addr(const char *dev, struct in_addr *addr) +{ + struct ifreq ifr; + int s, ret; + + if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + return -1; + } + + memset(&ifr, 0x00, sizeof(ifr)); + strcpy(ifr.ifr_name, dev); + + if (ioctl(s, SIOCGIFADDR, &ifr) == 0) { + memcpy(addr, &ifr.ifr_addr.sa_data[2], sizeof(struct in_addr)); + ret = 0; + } + else { + ret = -1; + } + + close(s); + + return ret; +} + /* * Return device index */ diff --git a/wrapper/lib/jsw_rbtree.c b/wrapper/lib/jsw_rbtree.c new file mode 100644 index 0000000..f8840cf --- /dev/null +++ b/wrapper/lib/jsw_rbtree.c @@ -0,0 +1,582 @@ +/* + Red Black balanced tree library + + > Created (Julienne Walker): August 23, 2003 + > Modified (Julienne Walker): March 14, 2008 +*/ +#include "jsw_rbtree.h" + +#ifdef __cplusplus +#include + +using std::malloc; +using std::free; +using std::size_t; +#else +#include +#endif + +#ifndef HEIGHT_LIMIT +#define HEIGHT_LIMIT 64 /* Tallest allowable tree */ +#endif + +typedef struct jsw_rbnode { + int red; /* Color (1=red, 0=black) */ + void *data; /* User-defined content */ + struct jsw_rbnode *link[2]; /* Left (0) and right (1) links */ +} jsw_rbnode_t; + +struct jsw_rbtree { + jsw_rbnode_t *root; /* Top of the tree */ + cmp_f cmp; /* Compare two items */ + dup_f dup; /* Clone an item (user-defined) */ + rel_f rel; /* Destroy an item (user-defined) */ + size_t size; /* Number of items (user-defined) */ +}; + +struct jsw_rbtrav { + jsw_rbtree_t *tree; /* Paired tree */ + jsw_rbnode_t *it; /* Current node */ + jsw_rbnode_t *path[HEIGHT_LIMIT]; /* Traversal path */ + size_t top; /* Top of stack */ +}; + +/** + + Checks the color of a red black node + + The node to check + 1 for a red node, 0 for a black node + For jsw_rbtree.c internal use only +*/ +static int is_red ( jsw_rbnode_t *root ) +{ + return root != NULL && root->red == 1; +} + +/** + + Performs a single red black rotation in the specified direction + This function assumes that all nodes are valid for a rotation + + The original root to rotate around + The direction to rotate (0 = left, 1 = right) + The new root ater rotation + For jsw_rbtree.c internal use only +*/ +static jsw_rbnode_t *jsw_single ( jsw_rbnode_t *root, int dir ) +{ + jsw_rbnode_t *save = root->link[!dir]; + + root->link[!dir] = save->link[dir]; + save->link[dir] = root; + + root->red = 1; + save->red = 0; + + return save; +} + +/** + + Performs a double red black rotation in the specified direction + This function assumes that all nodes are valid for a rotation + + The original root to rotate around + The direction to rotate (0 = left, 1 = right) + The new root after rotation + For jsw_rbtree.c internal use only +*/ +static jsw_rbnode_t *jsw_double ( jsw_rbnode_t *root, int dir ) +{ + root->link[!dir] = jsw_single ( root->link[!dir], !dir ); + + return jsw_single ( root, dir ); +} + +/** + + Creates an initializes a new red black node with a copy of + the data. This function does not insert the new node into a tree + + The red black tree this node is being created for + The data value that will be stored in this node + A pointer to the new node + + For jsw_rbtree.c internal use only. The data for this node must + be freed using the same tree's rel function. The returned pointer + must be freed using C's free function + +*/ +static jsw_rbnode_t *new_node ( jsw_rbtree_t *tree, void *data ) +{ + jsw_rbnode_t *rn = (jsw_rbnode_t *)malloc ( sizeof *rn ); + + if ( rn == NULL ) + return NULL; + + rn->red = 1; + rn->data = tree->dup ( data ); + rn->link[0] = rn->link[1] = NULL; + + return rn; +} + +/** + + Creates and initializes an empty red black tree with + user-defined comparison, data copy, and data release operations + + User-defined data comparison function + User-defined data copy function + User-defined data release function + A pointer to the new tree + + The returned pointer must be released with jsw_rbdelete + +*/ +jsw_rbtree_t *jsw_rbnew ( cmp_f cmp, dup_f dup, rel_f rel ) +{ + jsw_rbtree_t *rt = (jsw_rbtree_t *)malloc ( sizeof *rt ); + + if ( rt == NULL ) + return NULL; + + rt->root = NULL; + rt->cmp = cmp; + rt->dup = dup; + rt->rel = rel; + rt->size = 0; + + return rt; +} + +/** + + Releases a valid red black tree + + The tree to release + + The tree must have been created using jsw_rbnew + +*/ +void jsw_rbdelete ( jsw_rbtree_t *tree ) +{ + jsw_rbnode_t *it = tree->root; + jsw_rbnode_t *save; + + /* + Rotate away the left links so that + we can treat this like the destruction + of a linked list + */ + while ( it != NULL ) { + if ( it->link[0] == NULL ) { + /* No left links, just kill the node and move on */ + save = it->link[1]; + tree->rel ( it->data ); + free ( it ); + } + else { + /* Rotate away the left link and check again */ + save = it->link[0]; + it->link[0] = save->link[1]; + save->link[1] = it; + } + + it = save; + } + + free ( tree ); +} + +/** + + Search for a copy of the specified + node data in a red black tree + + The tree to search + The data value to search for + + A pointer to the data value stored in the tree, + or a null pointer if no data could be found + +*/ +void *jsw_rbfind ( jsw_rbtree_t *tree, void *data ) +{ + jsw_rbnode_t *it = tree->root; + + while ( it != NULL ) { + int cmp = tree->cmp ( it->data, data ); + + if ( cmp == 0 ) + break; + + /* + If the tree supports duplicates, they should be + chained to the right subtree for this to work + */ + it = it->link[cmp < 0]; + } + + return it == NULL ? NULL : it->data; +} + +/** + + Insert a copy of the user-specified + data into a red black tree + + The tree to insert into + The data value to insert + + 1 if the value was inserted successfully, + 0 if the insertion failed for any reason + +*/ +int jsw_rbinsert ( jsw_rbtree_t *tree, void *data ) +{ + if ( tree->root == NULL ) { + /* + We have an empty tree; attach the + new node directly to the root + */ + tree->root = new_node ( tree, data ); + + if ( tree->root == NULL ) + return 0; + } + else { + jsw_rbnode_t head = {0}; /* False tree root */ + jsw_rbnode_t *g, *t; /* Grandparent & parent */ + jsw_rbnode_t *p, *q; /* Iterator & parent */ + int dir = 0, last = 0; + + /* Set up our helpers */ + t = &head; + g = p = NULL; + q = t->link[1] = tree->root; + + /* Search down the tree for a place to insert */ + for ( ; ; ) { + if ( q == NULL ) { + /* Insert a new node at the first null link */ + p->link[dir] = q = new_node ( tree, data ); + + if ( q == NULL ) + return 0; + } + else if ( is_red ( q->link[0] ) && is_red ( q->link[1] ) ) { + /* Simple red violation: color flip */ + q->red = 1; + q->link[0]->red = 0; + q->link[1]->red = 0; + } + + if ( is_red ( q ) && is_red ( p ) ) { + /* Hard red violation: rotations necessary */ + int dir2 = t->link[1] == g; + + if ( q == p->link[last] ) + t->link[dir2] = jsw_single ( g, !last ); + else + t->link[dir2] = jsw_double ( g, !last ); + } + + /* + Stop working if we inserted a node. This + check also disallows duplicates in the tree + */ + if ( tree->cmp ( q->data, data ) == 0 ) + break; + + last = dir; + dir = tree->cmp ( q->data, data ) < 0; + + /* Move the helpers down */ + if ( g != NULL ) + t = g; + + g = p, p = q; + q = q->link[dir]; + } + + /* Update the root (it may be different) */ + tree->root = head.link[1]; + } + + /* Make the root black for simplified logic */ + tree->root->red = 0; + ++tree->size; + + return 1; +} + +/** + + Remove a node from a red black tree + that matches the user-specified data + + The tree to remove from + The data value to search for + + 1 if the value was removed successfully, + 0 if the removal failed for any reason + + + The most common failure reason should be + that the data was not found in the tree + +*/ +int jsw_rberase ( jsw_rbtree_t *tree, void *data ) +{ + if ( tree->root != NULL ) { + jsw_rbnode_t head = {0}; /* False tree root */ + jsw_rbnode_t *q, *p, *g; /* Helpers */ + jsw_rbnode_t *f = NULL; /* Found item */ + int dir = 1; + + /* Set up our helpers */ + q = &head; + g = p = NULL; + q->link[1] = tree->root; + + /* + Search and push a red node down + to fix red violations as we go + */ + while ( q->link[dir] != NULL ) { + int last = dir; + + /* Move the helpers down */ + g = p, p = q; + q = q->link[dir]; + dir = tree->cmp ( q->data, data ) < 0; + + /* + Save the node with matching data and keep + going; we'll do removal tasks at the end + */ + if ( tree->cmp ( q->data, data ) == 0 ) + f = q; + + /* Push the red node down with rotations and color flips */ + if ( !is_red ( q ) && !is_red ( q->link[dir] ) ) { + if ( is_red ( q->link[!dir] ) ) + p = p->link[last] = jsw_single ( q, dir ); + else if ( !is_red ( q->link[!dir] ) ) { + jsw_rbnode_t *s = p->link[!last]; + + if ( s != NULL ) { + if ( !is_red ( s->link[!last] ) && !is_red ( s->link[last] ) ) { + /* Color flip */ + p->red = 0; + s->red = 1; + q->red = 1; + } + else { + int dir2 = g->link[1] == p; + + if ( is_red ( s->link[last] ) ) + g->link[dir2] = jsw_double ( p, last ); + else if ( is_red ( s->link[!last] ) ) + g->link[dir2] = jsw_single ( p, last ); + + /* Ensure correct coloring */ + q->red = g->link[dir2]->red = 1; + g->link[dir2]->link[0]->red = 0; + g->link[dir2]->link[1]->red = 0; + } + } + } + } + } + + /* Replace and remove the saved node */ + if ( f != NULL ) { + tree->rel ( f->data ); + f->data = q->data; + p->link[p->link[1] == q] = + q->link[q->link[0] == NULL]; + free ( q ); + } + + /* Update the root (it may be different) */ + tree->root = head.link[1]; + + /* Make the root black for simplified logic */ + if ( tree->root != NULL ) + tree->root->red = 0; + + --tree->size; + } + + return 1; +} + +/** + + Gets the number of nodes in a red black tree + + The tree to calculate a size for + The number of nodes in the tree +*/ +size_t jsw_rbsize ( jsw_rbtree_t *tree ) +{ + return tree->size; +} + +/** + + Create a new traversal object + + A pointer to the new object + + The traversal object is not initialized until + jsw_rbtfirst or jsw_rbtlast are called. + The pointer must be released with jsw_rbtdelete + +*/ +jsw_rbtrav_t *jsw_rbtnew ( void ) +{ + return (jsw_rbtrav_t*)malloc ( sizeof ( jsw_rbtrav_t ) ); +} + +/** + + Release a traversal object + + The object to release + + The object must have been created with jsw_rbtnew + +*/ +void jsw_rbtdelete ( jsw_rbtrav_t *trav ) +{ + free ( trav ); +} + +/** + + Initialize a traversal object. The user-specified + direction determines whether to begin traversal at the + smallest or largest valued node + + The traversal object to initialize + The tree that the object will be attached to + + The direction to traverse (0 = ascending, 1 = descending) + + A pointer to the smallest or largest data value + For jsw_rbtree.c internal use only +*/ +static void *start ( jsw_rbtrav_t *trav, jsw_rbtree_t *tree, int dir ) +{ + trav->tree = tree; + trav->it = tree->root; + trav->top = 0; + + /* Save the path for later traversal */ + if ( trav->it != NULL ) { + while ( trav->it->link[dir] != NULL ) { + trav->path[trav->top++] = trav->it; + trav->it = trav->it->link[dir]; + } + } + + return trav->it == NULL ? NULL : trav->it->data; +} + +/** + + Traverse a red black tree in the user-specified direction + + The initialized traversal object + + The direction to traverse (0 = ascending, 1 = descending) + + + A pointer to the next data value in the specified direction + + For jsw_rbtree.c internal use only +*/ +static void *move ( jsw_rbtrav_t *trav, int dir ) +{ + if ( trav->it->link[dir] != NULL ) { + /* Continue down this branch */ + trav->path[trav->top++] = trav->it; + trav->it = trav->it->link[dir]; + + while ( trav->it->link[!dir] != NULL ) { + trav->path[trav->top++] = trav->it; + trav->it = trav->it->link[!dir]; + } + } + else { + /* Move to the next branch */ + jsw_rbnode_t *last; + + do { + if ( trav->top == 0 ) { + trav->it = NULL; + break; + } + + last = trav->it; + trav->it = trav->path[--trav->top]; + } while ( last == trav->it->link[dir] ); + } + + return trav->it == NULL ? NULL : trav->it->data; +} + +/** + + Initialize a traversal object to the smallest valued node + + The traversal object to initialize + The tree that the object will be attached to + A pointer to the smallest data value +*/ +void *jsw_rbtfirst ( jsw_rbtrav_t *trav, jsw_rbtree_t *tree ) +{ + return start ( trav, tree, 0 ); /* Min value */ +} + +/** + + Initialize a traversal object to the largest valued node + + The traversal object to initialize + The tree that the object will be attached to + A pointer to the largest data value +*/ +void *jsw_rbtlast ( jsw_rbtrav_t *trav, jsw_rbtree_t *tree ) +{ + return start ( trav, tree, 1 ); /* Max value */ +} + +/** + + Traverse to the next value in ascending order + + The initialized traversal object + A pointer to the next value in ascending order +*/ +void *jsw_rbtnext ( jsw_rbtrav_t *trav ) +{ + return move ( trav, 1 ); /* Toward larger items */ +} + +/** + + Traverse to the next value in descending order + + The initialized traversal object + A pointer to the next value in descending order +*/ +void *jsw_rbtprev ( jsw_rbtrav_t *trav ) +{ + return move ( trav, 0 ); /* Toward smaller items */ +} + diff --git a/wrapper/lib/jsw_rbtree.h b/wrapper/lib/jsw_rbtree.h new file mode 100644 index 0000000..bd7ba77 --- /dev/null +++ b/wrapper/lib/jsw_rbtree.h @@ -0,0 +1,60 @@ +#ifndef JSW_RBTREE_H +#define JSW_RBTREE_H + +/* + Red Black balanced tree library + + > Created (Julienne Walker): August 23, 2003 + > Modified (Julienne Walker): March 14, 2008 + + This code is in the public domain. Anyone may + use it or change it in any way that they see + fit. The author assumes no responsibility for + damages incurred through use of the original + code or any variations thereof. + + It is requested, but not required, that due + credit is given to the original author and + anyone who has modified the code through + a header comment, such as this one. +*/ +#ifdef __cplusplus +#include + +using std::size_t; + +extern "C" { +#else +#include +#endif + +/* Opaque types */ +typedef struct jsw_rbtree jsw_rbtree_t; +typedef struct jsw_rbtrav jsw_rbtrav_t; + +/* User-defined item handling */ +typedef int (*cmp_f) ( const void *p1, const void *p2 ); +typedef void *(*dup_f) ( void *p ); +typedef void (*rel_f) ( void *p ); + +/* Red Black tree functions */ +jsw_rbtree_t *jsw_rbnew ( cmp_f cmp, dup_f dup, rel_f rel ); +void jsw_rbdelete ( jsw_rbtree_t *tree ); +void *jsw_rbfind ( jsw_rbtree_t *tree, void *data ); +int jsw_rbinsert ( jsw_rbtree_t *tree, void *data ); +int jsw_rberase ( jsw_rbtree_t *tree, void *data ); +size_t jsw_rbsize ( jsw_rbtree_t *tree ); + +/* Traversal functions */ +jsw_rbtrav_t *jsw_rbtnew ( void ); +void jsw_rbtdelete ( jsw_rbtrav_t *trav ); +void *jsw_rbtfirst ( jsw_rbtrav_t *trav, jsw_rbtree_t *tree ); +void *jsw_rbtlast ( jsw_rbtrav_t *trav, jsw_rbtree_t *tree ); +void *jsw_rbtnext ( jsw_rbtrav_t *trav ); +void *jsw_rbtprev ( jsw_rbtrav_t *trav ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/wrapper/process.c b/wrapper/process.c index a5421d2..e586d66 100644 --- a/wrapper/process.c +++ b/wrapper/process.c @@ -1,29 +1,212 @@ +#include + #include "wrapper.h" #include "translate_ip.h" +#include "storage.h" struct in6_addr ip6addr_wrapsix; -void process_packet6(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) +void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { - const struct s_ethernet *ethernet; /* the ethernet header */ - const struct s_ip6 *ip; /* the IP header */ - const unsigned char *payload; /* packet payload */ + const struct s_ethernet *eth; /* the ethernet header */ + const unsigned char *payload; /* the IP header + packet payload */ + + /* define ethernet header */ + eth = (struct s_ethernet*) (packet); + payload = packet + SIZE_ETHERNET; + + switch (htons(eth->type)) { + case ETHERTYPE_IP: + printf("\n IP: 4\n"); + process_packet4(eth, payload); + break; + case ETHERTYPE_IPV6: + printf("\n IP: 6\n"); + process_packet6(eth, payload); + break; + default: + printf("\n IP: unknown (%d/0x%x)\n", htons(eth->type), htons(eth->type)); + break; + } +} + +/*** IPv4 ***/ +void process_packet4(const struct s_ethernet *eth, const unsigned char *packet) +{ + struct s_ip4 *ip; /* the IP header */ + const unsigned char *payload; /* packet payload */ + + unsigned short header_length; + + /* define/compute IP header offset */ + ip = (struct s_ip4 *) packet; + header_length = (ip->ver_ihl & 0x0f) * 4; + + /* define/compute IP payload offset */ + payload = packet + header_length; + + /* DEBUG: print source and destination IP addresses */ + 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(dev_ip, &ip->ip_dest, 4)) { + printf("==> This packet is not ours! <==\n"); + return; + } + + /* determine protocol */ + switch (ip->proto) { + case IPPROTO_TCP: + printf(" Protocol: TCP\n"); + break; + case IPPROTO_UDP: + printf(" Protocol: UDP\n"); + break; + case IPPROTO_ICMP: + printf(" Protocol: ICMP\n"); + process_icmp4(eth, ip, payload, htons(ip->pckt_len) - header_length); + break; + default: + printf(" Protocol: unknown (%d/0x%x)\n", ip->proto, ip->proto); + break; + } +} + +void process_icmp4(const struct s_ethernet *eth_hdr, struct s_ip4 *ip_hdr, const unsigned char *payload, unsigned short data_size) +{ + struct s_icmp *icmp; + struct ip6_hdr *ip; + struct s_ethernet *eth; + + unsigned char *icmp_data; + unsigned char *packet; + unsigned int packet_size; + + struct stg_conn_icmp *ent = NULL; + struct stg_conn_icmp *ent_tmp; + + /* define ICMP header */ + icmp = (struct s_icmp *) payload; + /* define/compute ICMP data offset */ + icmp_data = (unsigned char *) (payload + sizeof(struct s_icmp)); + + /* decide what type of ICMP we have */ + switch (icmp->type) { + case ICMP4_ECHO_REPLY: + printf(" ICMP: Echo Reply\n"); + + struct s_icmp_ping *icmp_ping; + icmp_ping = (struct s_icmp_ping *) icmp_data; + + /* create temporary data entry for finding */ + if ((ent_tmp = (struct stg_conn_icmp *) malloc(sizeof(struct stg_conn_icmp))) == NULL) { + fprintf(stderr, "Fatal Error! Lack of free memory!\n"); + exit(EXIT_FAILURE); + } + + /* the only needed field is ID */ + ent_tmp->id = htons(icmp_ping->id); + + /* find the appropriate connection */ + ent = jsw_rbfind(stg_conn_icmp, ent_tmp); + + /* free allocated memory */ + free(ent_tmp); + + /* check if this packet is from wrapped connection */ + if (ent == NULL) { + fprintf(stderr, "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(" Ent-to: %s\n", inet_ntoa(ent->addr_to)); + printf(" IP-from: %s\n", inet_ntoa(ip_hdr->ip_src)); + return; + } + + /* wrap it back */ + icmp->type = ICMP6_ECHO_REPLY; + icmp->code = 0; + icmp->checksum = 0; + + break; + default: + printf(" ICMP: unknown (%d/0x%x)\n", icmp->type, icmp->type); + return; + break; + } + + packet_size = data_size + SIZE_ETHERNET + SIZE_IP6; + packet = (unsigned char *) malloc(packet_size); + + if (packet == NULL) { + fprintf(stderr, "Fatal error! Lack of free memory!\n"); + exit(EXIT_FAILURE); + } + + /* initialize the packet with zeros */ + memset(packet, 0x0, packet_size); + + /* parse the packet into structures */ + eth = (struct s_ethernet *) packet; + ip = (struct ip6_hdr *) (packet + SIZE_ETHERNET); + + /* assemble the ethernet header */ + memcpy(ð->src, mac, sizeof(struct s_mac_addr)); + eth->dest = ent->mac; + eth->type = htons(ETHERTYPE_IPV6); + + /* assemble the IPv6 header */ + build_ip6_hdr(ip, /* ip6_hdr structure */ + ipaddr_4to6(ent->addr_to), /* source address */ + ent->addr_from, /* destination address */ + data_size, /* payload length */ + IPPROTO_ICMPV6, /* protocol */ + 255); /* ttl */ + + char ip6addr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &ent->addr_from, ip6addr, sizeof(ip6addr)); + printf(" Send to: %s\n", ip6addr); + + /* copy ICMP header */ + memcpy(packet + SIZE_ETHERNET + SIZE_IP6, icmp, sizeof(struct s_icmp)); + + /* copy ICMP data */ + memcpy(packet + SIZE_ETHERNET + SIZE_IP6 + sizeof(struct s_icmp), icmp_data, data_size - sizeof(struct s_icmp)); + + /* compute the ICMP checksum */ + icmp->checksum = checksum_ipv6(ip->ip6_src, ip->ip6_dst, data_size, ip->ip6_nxt, (unsigned char *) (packet + SIZE_ETHERNET + SIZE_IP6)); + + /* return the checksum into the packet */ + memcpy(packet + SIZE_ETHERNET + SIZE_IP6, icmp, sizeof(struct s_icmp)); + + /* send the wrapped packet back */ + send_ipv6(packet, packet_size); + + /* free allocated memory */ + free(packet); +} + +/*** IPv6 ***/ +void process_packet6(const struct s_ethernet *eth, const unsigned char *packet) +{ + struct s_ip6 *ip; /* the IP header */ + const unsigned char *payload; /* packet payload */ struct in6_addr ip6addr_ndp_multicast; - /* define ethernet header */ - ethernet = (struct s_ethernet*) (packet); - /* define/compute IP header offset */ - ip = (struct s_ip6*) (packet + SIZE_ETHERNET); + ip = (struct s_ip6 *) packet; /* define/compute IP payload offset */ - payload = packet + SIZE_ETHERNET + SIZE_IP6; + payload = packet + SIZE_IP6; /* DEBUG: print source and destination IP addresses */ char ip6addr[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &ip->ip_src, ip6addr, sizeof(ip6addr)); - printf("\n From: %s\n", ip6addr); + printf(" From: %s\n", ip6addr); inet_ntop(AF_INET6, &ip->ip_dest, ip6addr, sizeof(ip6addr)); printf(" To: %s\n", ip6addr); @@ -41,20 +224,18 @@ void process_packet6(u_char *args, const struct pcap_pkthdr *header, const u_cha 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((const struct s_ethernet *) ethernet, (struct s_ip6 *) ip, payload); + process_icmp6(eth, ip, payload); break; default: - printf(" Protocol: unknown\n"); + printf(" Protocol: unknown (%d/0x%x)\n", ip->next_header, ip->next_header); break; } - return; } void process_icmp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigned char *payload) @@ -62,10 +243,14 @@ void process_icmp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigne struct s_icmp *icmp; struct in_addr ip4_addr; - unsigned char *icmp_data; - unsigned char *icmp_packet; + unsigned char *icmp_data; + unsigned char *icmp_packet; + unsigned char ent_save = 0; - int packet_size = htons(ip->len); + struct stg_conn_icmp *ent; + struct stg_conn_icmp *ent_tmp; + + unsigned short packet_size = htons(ip->len); /* define ICMP header */ icmp = (struct s_icmp *) (payload); @@ -85,10 +270,46 @@ void process_icmp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigne case ICMP6_ECHO_REQUEST: printf(" ICMP: Echo Request\n"); - /* DEBUG */ struct s_icmp_ping *icmp_ping = (struct s_icmp_ping *) icmp_data; + /* DEBUG */ printf("[id;seq]:[0x%x;0x%x]\n", htons(icmp_ping->id), htons(icmp_ping->seq)); + /* check whether the connection is not already saved */ + /* create temporary data entry for finding */ + if ((ent_tmp = (struct stg_conn_icmp *) malloc(sizeof(struct stg_conn_icmp))) == NULL) { + fprintf(stderr, "Fatal Error! Lack of free memory!\n"); + exit(EXIT_FAILURE); + } + + /* the only needed field is ID */ + ent_tmp->id = htons(icmp_ping->id); + + /* find the appropriate connection */ + ent = jsw_rbfind(stg_conn_icmp, ent_tmp); + + /* free allocated memory */ + free(ent_tmp); + + /* check if this packet is from wrapped connection */ + if (ent == NULL) { + printf("New connection\n"); + /* save the connection */ + ent = (struct stg_conn_icmp *) malloc(sizeof(struct stg_conn_icmp)); + ent->id = htons(icmp_ping->id); + ent->addr_from = ip->ip_src; + ent->mac = eth->src; + ent->is_ping = 1; + time(&ent->time); + memset(&ent->addr_to, 0x0, sizeof(struct in_addr)); + ent_save = 1; + } + else { + printf("Connection found\n"); + printf(" Conn #: %d\n", jsw_rbsize(stg_conn_icmp)); + /* set fresh timestamp */ + time(&ent->time); + } + /* fill into the header known statements */ icmp->type = ICMP4_ECHO_REQUEST; icmp->code = 0; @@ -100,7 +321,7 @@ void process_icmp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigne break; /* nothing interesting */ default: - printf(" ICMP: unknown: %d/0x%x\n", icmp->type, icmp->type); + printf(" ICMP: unknown: (%d/0x%x)\n", icmp->type, icmp->type); return; break; } @@ -127,12 +348,21 @@ void process_icmp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigne memcpy(icmp_packet, icmp, sizeof(struct s_icmp)); /* decide where to send this ICMP */ - ip4_addr = ipaddr_6to4((struct in6_addr) ip->ip_dest); + ip4_addr = ipaddr_6to4(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); + /* save the connection */ + if (ent_save == 1) { + ent->addr_to = ip4_addr; + jsw_rbinsert(stg_conn_icmp, ent); + printf(" Conn #: %d\n", jsw_rbsize(stg_conn_icmp)); + /* the entry is not needed now and should be freed */ + free(ent); + } + /* free allocated memory */ free(icmp_packet); icmp_packet = NULL; @@ -147,10 +377,7 @@ void process_ndp(const struct s_ethernet *eth_hdr, struct s_ip6 *ip_hdr, unsigne struct s_icmp_ndp_ns *ndp_ns; struct s_icmp_ndp_na *ndp_na; - unsigned char *buf_ip6_pseudo; - struct s_ip6_pseudo *ip6_pseudo; - - int packet_size; + unsigned short packet_size; /* get the NDP data */ ndp_ns = (struct s_icmp_ndp_ns *) icmp_data; @@ -182,13 +409,12 @@ void process_ndp(const struct s_ethernet *eth_hdr, struct s_ip6 *ip_hdr, unsigne eth->type = eth_hdr->type; /* assemble the IPv6 header */ - ip->ip6_src = ndp_ns->target; - ip->ip6_dst = ip_hdr->ip_src; - ip->ip6_flow = 0; - ip->ip6_vfc = 0x60; - ip->ip6_plen = htons(sizeof(struct s_icmp) + sizeof(struct s_icmp_ndp_na)); - ip->ip6_nxt = IPPROTO_ICMPV6; - ip->ip6_hlim = 255; + build_ip6_hdr(ip, /* ip6_hdr structure */ + ndp_ns->target, /* source address */ + ip_hdr->ip_src, /* destination address */ + sizeof(struct s_icmp) + sizeof(struct s_icmp_ndp_na), /* payload length */ + IPPROTO_ICMPV6, /* protocol */ + 255); /* ttl */ /* assemble the ICMP header */ icmp->type = ICMP6_NDP_NA; @@ -206,31 +432,12 @@ void process_ndp(const struct s_ethernet *eth_hdr, struct s_ip6 *ip_hdr, unsigne memcpy(&ndp_na->o_tlla, mac, sizeof(struct s_mac_addr)); /* compute the ICMP checksum */ - buf_ip6_pseudo = (unsigned char *) malloc(sizeof(struct s_ip6_pseudo) + htons(ip->ip6_plen)); - - if (buf_ip6_pseudo == NULL) { - fprintf(stderr, "Fatal error! Lack of free memory!\n"); - exit(EXIT_FAILURE); - } - - ip6_pseudo = (struct s_ip6_pseudo *) buf_ip6_pseudo; - - ip6_pseudo->ip_src = ip->ip6_src; - ip6_pseudo->ip_dest = ip->ip6_dst; - ip6_pseudo->len = ip->ip6_plen; - ip6_pseudo->zeros = 0x0; - ip6_pseudo->next_header = ip->ip6_nxt; - - memcpy(buf_ip6_pseudo + sizeof(struct s_ip6_pseudo), icmp, htons(ip->ip6_plen)); - - icmp->checksum = checksum(buf_ip6_pseudo, sizeof(struct s_ip6_pseudo) + htons(ip->ip6_plen)); + icmp->checksum = checksum_ipv6(ip->ip6_src, ip->ip6_dst, htons(ip->ip6_plen), ip->ip6_nxt, (unsigned char *) icmp); /* send the packet */ - send_ndp(ip, packet, packet_size); + send_ipv6(packet, packet_size); /* free allocated memory */ free(packet); - free(buf_ip6_pseudo); packet = NULL; - buf_ip6_pseudo = NULL; } diff --git a/wrapper/storage.c b/wrapper/storage.c new file mode 100644 index 0000000..743fde5 --- /dev/null +++ b/wrapper/storage.c @@ -0,0 +1,32 @@ +#include "storage.h" + +int stg_conn_icmp_cmp(const void *p1, const void *p2) +{ + struct stg_conn_icmp *pp1 = (struct stg_conn_icmp *) p1; + struct stg_conn_icmp *pp2 = (struct stg_conn_icmp *) p2; + + if (pp1->id < pp2->id) return -1; + if (pp1->id > pp2->id) return 1; + return 0; +} + +void *stg_conn_icmp_dup(void *p) +{ + struct stg_conn_icmp *pp = (struct stg_conn_icmp *) p; + struct stg_conn_icmp *p_new; + + if ((p_new = (struct stg_conn_icmp *) malloc(sizeof(struct stg_conn_icmp))) == NULL) { + fprintf(stderr, "Fatal Error! Lack of free memory!\n"); + exit(EXIT_FAILURE); + } + + memcpy(p_new, pp, sizeof(struct stg_conn_icmp)); + + return (void *) p_new; +} + +void stg_conn_icmp_rel(void *p) +{ + free(p); + p = NULL; +} diff --git a/wrapper/storage.h b/wrapper/storage.h new file mode 100644 index 0000000..a291416 --- /dev/null +++ b/wrapper/storage.h @@ -0,0 +1,28 @@ +#ifndef STORAGE_H +#define STORAGE_H + +#include +#include +#include +#include +#include + +#include "jsw_rbtree.h" +#include "wrapper.h" + +struct stg_conn_icmp { + unsigned short id; + struct in_addr addr_to; + struct in6_addr addr_from; + struct s_mac_addr mac; + unsigned char is_ping; + time_t time; +}; + +int stg_conn_icmp_cmp(const void *p1, const void *p2); +void *stg_conn_icmp_dup(void *p); +void stg_conn_icmp_rel(void *p); + +extern jsw_rbtree_t *stg_conn_icmp; + +#endif diff --git a/wrapper/translate_ip.c b/wrapper/translate_ip.c index 9379a46..b05c06b 100644 --- a/wrapper/translate_ip.c +++ b/wrapper/translate_ip.c @@ -16,3 +16,46 @@ struct in_addr ipaddr_6to4(const struct in6_addr ip6_addr) return ip4_addr; } + +struct in6_addr ipaddr_4to6(const struct in_addr ip4_addr) +{ + struct ip6addr_ip4part *addr; + struct in6_addr ip6_addr; + char ip4_str[15]; + char *ip4_p; + unsigned int ip4_a[4]; + + /* create a temporary IPv6 variable */ + addr = (struct ip6addr_ip4part *) malloc(sizeof(struct ip6addr_ip4part)); + + /* copy IPv6 prefix of WrapSix IPv6 addresses */ + memcpy(addr, &ip6addr_wrapsix, 12); + + /* copy the rest of the IPv6 address (the IPv4 address) */ + ip4_p = inet_ntoa(ip4_addr); + memcpy(&ip4_str, ip4_p, 15); + sscanf(ip4_str, "%d.%d.%d.%d", &ip4_a[0], &ip4_a[1], &ip4_a[2], &ip4_a[3]); + addr->a = (unsigned char) ip4_a[0]; + addr->b = (unsigned char) ip4_a[1]; + addr->c = (unsigned char) ip4_a[2]; + addr->d = (unsigned char) ip4_a[3]; + + /* copy the complete IPv6 address */ + memcpy(&ip6_addr, addr, sizeof(struct in6_addr)); + + /* free allocated memory */ + free(addr); + + return ip6_addr; +} + +void build_ip6_hdr(struct ip6_hdr *ip, struct in6_addr ip_src, struct in6_addr ip_dest, unsigned short paylen, unsigned char proto, unsigned char ttl) +{ + ip->ip6_src = ip_src; + ip->ip6_dst = ip_dest; + ip->ip6_flow = 0; + ip->ip6_vfc = 0x60; + ip->ip6_plen = htons(paylen); + ip->ip6_nxt = proto; + ip->ip6_hlim = ttl; +} diff --git a/wrapper/translate_ip.h b/wrapper/translate_ip.h index 9358c92..6616b50 100644 --- a/wrapper/translate_ip.h +++ b/wrapper/translate_ip.h @@ -1,6 +1,9 @@ #ifndef TRANSLATE_IP_H #define TRANSLATE_IP_H +#include /* in6_addr, in_addr */ +#include /* ip6_hdr */ + struct ip6addr_ip4part { long double prefix; unsigned char a; @@ -9,7 +12,9 @@ struct ip6addr_ip4part { unsigned char d; }; -struct in_addr ipaddr_6to4(const struct in6_addr ip6_addr); -//in6_addr ipaddr_4to6(in_addr ip_addr); +struct in_addr ipaddr_6to4(const struct in6_addr ip6_addr); +struct in6_addr ipaddr_4to6(const struct in_addr ip_addr); + +void build_ip6_hdr(struct ip6_hdr *ip, struct in6_addr ip_src, struct in6_addr ip_dest, unsigned short paylen, unsigned char proto, unsigned char ttl); #endif diff --git a/wrapper/wrapper.c b/wrapper/wrapper.c index 29f560a..e02acae 100644 --- a/wrapper/wrapper.c +++ b/wrapper/wrapper.c @@ -1,8 +1,13 @@ #include "wrapper.h" +#include "storage.h" struct s_mac_addr *mac; /* MAC address of the device */ char *dev; /* capture device name */ int dev_index; /* capture device index */ +struct in_addr *dev_ip; /* IP address associated with the device */ + +/* storage trees */ +jsw_rbtree_t *stg_conn_icmp; int main(int argc, char **argv) { @@ -11,10 +16,13 @@ int main(int argc, char **argv) pcap_t *handle; /* packet capture handle */ //char filter_exp[] = "ip6"; /* filter expression */ - char filter_exp[] = "icmp6"; /* filter expression */ + char filter_exp[] = "icmp6 or icmp"; /* filter expression */ struct bpf_program fp; /* compiled filter program (expression) */ int num_packets = 0; /* number of packets to capture; 0 = infinite */ + /* initialize the storage for connections */ + stg_conn_icmp = jsw_rbnew(&stg_conn_icmp_cmp, &stg_conn_icmp_dup, &stg_conn_icmp_rel); + /* find a capture device */ dev = NULL; dev = pcap_lookupdev(errbuf); @@ -48,6 +56,13 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + /* obtain IP address of the device */ + dev_ip = (struct in_addr *) malloc(sizeof(struct in_addr)); + if (get_ip_addr(dev, dev_ip) != 0) { + fprintf(stderr, "Couldn't get device IP address\n"); + exit(EXIT_FAILURE); + } + /* get index of the device */ dev_index = get_dev_index(dev); @@ -64,12 +79,17 @@ int main(int argc, char **argv) } /* now we can set our callback function */ - pcap_loop(handle, num_packets, process_packet6, NULL); + pcap_loop(handle, num_packets, process_packet, NULL); /* cleanup */ pcap_freecode(&fp); pcap_close(handle); + jsw_rbdelete(stg_conn_icmp); + + free(mac); + free(dev_ip); + printf("\nCapture complete.\n"); return 0; diff --git a/wrapper/wrapper.h b/wrapper/wrapper.h index cd07056..8eb3ece 100644 --- a/wrapper/wrapper.h +++ b/wrapper/wrapper.h @@ -41,6 +41,18 @@ struct s_ethernet { }; /* IPv4 header structure */ +struct s_ip4 { + unsigned char ver_ihl; + unsigned char tos; /* 8 b; type of service */ + unsigned short pckt_len; /* 16 b; total lenght of the packet (IP header + payload) */ + unsigned short id; /* 16 b; id of the packet - for purpose of fragmentation */ + unsigned short flags_offset; /* 16 b; 3 b - flags, 13 b - fragment offset in bytes */ + unsigned char ttl; /* 8 b; time to live */ + unsigned char proto; /* 8 b; protocol in the payload */ + unsigned short checksum; /* 16 b */ + struct in_addr ip_src; /* 32 b; source address */ + struct in_addr ip_dest; /* 32 b; destination address */ +}; /* IPv6 header structure */ struct s_ip6 { @@ -56,11 +68,9 @@ struct s_ip6 { /* pseudo IPv6 header for checksum */ struct s_ip6_pseudo { - //unsigned short ip_src[8]; - //unsigned short ip_dest[8]; struct in6_addr ip_src; /* 128 b; source address */ struct in6_addr ip_dest; /* 128 b; destination address */ - unsigned short len; /* 16 b; payload length */ + unsigned int len; /* 32 b; payload length */ unsigned int zeros:24; /* 24 b; reserved */ unsigned char next_header; /* 8 b; next header */ }; @@ -115,6 +125,9 @@ struct s_icmp_ndp_na { #define INNAF_S 0x40 /* solicited flag */ #define INNAF_O 0x20 /* override flag */ +/* Missing ethertypes */ +#define ETHERTYPE_IPV6 0x86dd + /* ICMP types */ #define ICMP4_ECHO_REQUEST 0x8 #define ICMP4_ECHO_REPLY 0x0 @@ -130,20 +143,29 @@ struct s_icmp_ndp_na { /* Prototypes */ int get_mac_addr(const char *dev, struct s_mac_addr *addr); +int get_ip_addr(const char *dev, struct in_addr *addr); int get_dev_index(const char *dev); -void process_packet6(u_char *args, const struct pcap_pkthdr *header, const u_char *packet); +void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet); + +void process_packet4(const struct s_ethernet *eth, const unsigned char *packet); +void process_icmp4(const struct s_ethernet *eth_hdr, struct s_ip4 *ip_hdr, const unsigned char *payload, unsigned short packet_size); + +void process_packet6(const struct s_ethernet *eth, const unsigned char *packet); void process_icmp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigned char *payload); void process_ndp(const struct s_ethernet *eth_hdr, struct s_ip6 *ip_hdr, unsigned char *icmp_data); void send_there(struct in_addr ip4_addr, unsigned char ttl, unsigned int type, unsigned char *payload, unsigned int paylen); -void send_ndp(struct ip6_hdr *ip, unsigned char *packet, int packet_size); +void send_ipv6(unsigned char *packet, int packet_size); unsigned short checksum(const void *_buf, int len); +unsigned short checksum_ipv6(struct in6_addr ip_src, struct in6_addr ip_dest, unsigned short paylen, unsigned char proto, unsigned char *data); /* Variables */ extern struct s_mac_addr *mac; /* MAC address of the device */ extern char *dev; /* capture device name */ extern int dev_index; /* capture device index */ +extern struct in_addr *dev_ip; /* IP address associated with the device */ +extern struct in6_addr ip6addr_wrapsix; /* IPv6 prefix of WrapSix addresses */ #endif