diff --git a/wrapper/Makefile b/wrapper/Makefile index da2d495..4fb8d1d 100644 --- a/wrapper/Makefile +++ b/wrapper/Makefile @@ -2,7 +2,7 @@ CC = gcc CFLAGS = -Wall -O0 LDFLAGS = -L/usr/lib -lpcap -all: wrapper.o process.o translate_ip.o connections.o checksum.o +all: wrapper.o process.o translate_ip.o connections.o checksum.o if.o $(CC) $(CFLAGS) $(LDFLAGS) *.o -o wrapper wrapper.o: wrapper.c wrapper.h @@ -20,5 +20,8 @@ connections.o: connections.c wrapper.h checksum.o: checksum.c $(CC) $(CFLAGS) -c checksum.c -o checksum.o +if.o: if.c wrapper.h + $(CC) $(CFLAGS) -c if.c -o if.o + clean: rm -f wrapper *.o diff --git a/wrapper/connections.c b/wrapper/connections.c index f40fe8b..78e98dc 100644 --- a/wrapper/connections.c +++ b/wrapper/connections.c @@ -1,4 +1,6 @@ -#include +#include /* ifreq */ +#include /* ETH_P_IP, ETH_P_ALL */ +#include /* sockaddr_ll, PACKET_OTHERHOST */ #include "wrapper.h" @@ -21,3 +23,47 @@ void send_there(struct in_addr ip4_addr, unsigned char ttl, unsigned int type, u close(sock); } + +void send_ndp(struct ip6_hdr *ip, unsigned char *packet, int packet_size) +{ + struct sockaddr_ll socket_address; /* target address */ + struct ifreq ifr; /* interface */ + + int sock; + + /* 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_pkttype = PACKET_OTHERHOST; /* target host is another host */ + + /* initialize with zeros */ + memset(&ifr, 0, sizeof(struct ifreq)); + + /* set device */ + strncpy(ifr.ifr_name, dev, strlen(dev)); + + /* initialize raw socket */ + if ((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) { + fprintf(stderr, "Couldn't open RAW socket.\n"); + perror("socket()"); + exit(EXIT_FAILURE); + } + + /* bind the socket to the interface */ + if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(struct ifreq)) == -1){ + fprintf(stderr, "Couldn't bind the socket to the interface.\n"); + perror("setsockopt()"); + exit(EXIT_FAILURE); + } + + /* 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"); + perror("sendto()"); + exit(EXIT_FAILURE); + } + + /* close the socket */ + close(sock); +} diff --git a/wrapper/if.c b/wrapper/if.c new file mode 100644 index 0000000..83a7e3b --- /dev/null +++ b/wrapper/if.c @@ -0,0 +1,57 @@ +#include +#include + +#include "wrapper.h" + +/* + * Return the MAC (ie, ethernet hardware) address + */ +int get_mac_addr(const char *dev, struct s_mac_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, SIOCGIFHWADDR, &ifr) == 0) { + memcpy(addr, &ifr.ifr_hwaddr.sa_data, sizeof(struct s_mac_addr)); + ret = 0; + } + else { + ret = -1; + } + + close(s); + + return ret; +} + +/* + * Return device index + */ +int get_dev_index(const char *dev) +{ + struct ifreq ifr; + int s; + + memset(&ifr, 0x00, sizeof(ifr)); + + if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + return -1; + } + + strncpy((char *) ifr.ifr_name, dev, IFNAMSIZ); + if ((ioctl(s, SIOCGIFINDEX, &ifr)) == -1) { + printf("Error getting Interface index !\n"); + exit(-1); + } + + close(s); + + return ifr.ifr_ifindex; +} diff --git a/wrapper/process.c b/wrapper/process.c index 0b771d4..a5421d2 100644 --- a/wrapper/process.c +++ b/wrapper/process.c @@ -1,13 +1,14 @@ #include "wrapper.h" #include "translate_ip.h" +struct in6_addr ip6addr_wrapsix; + void process_packet6(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 */ - struct in6_addr ip6addr_wrapsix; struct in6_addr ip6addr_ndp_multicast; /* define ethernet header */ @@ -19,6 +20,13 @@ void process_packet6(u_char *args, const struct pcap_pkthdr *header, const u_cha /* define/compute IP payload offset */ payload = packet + SIZE_ETHERNET + 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); + inet_ntop(AF_INET6, &ip->ip_dest, ip6addr, sizeof(ip6addr)); + printf(" To: %s\n", ip6addr); + /* check if this packet is ours - partially hardcoded for now */ inet_pton(AF_INET6, "fc00:1::", &ip6addr_wrapsix); inet_pton(AF_INET6, "ff02::1:ff00:0", &ip6addr_ndp_multicast); @@ -29,13 +37,6 @@ void process_packet6(u_char *args, const struct pcap_pkthdr *header, const u_cha return; } - /* 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); - inet_ntop(AF_INET6, &ip->ip_dest, ip6addr, sizeof(ip6addr)); - printf(" To: %s\n", ip6addr); - /* determine protocol */ switch (ip->next_header) { case IPPROTO_TCP: @@ -47,7 +48,7 @@ void process_packet6(u_char *args, const struct pcap_pkthdr *header, const u_cha break; case IPPROTO_ICMPV6: printf(" Protocol: ICMPv6\n"); - process_icmp6((struct s_ip6 *) ip, payload); + process_icmp6((const struct s_ethernet *) ethernet, (struct s_ip6 *) ip, payload); break; default: printf(" Protocol: unknown\n"); @@ -56,39 +57,30 @@ void process_packet6(u_char *args, const struct pcap_pkthdr *header, const u_cha return; } -void process_icmp6(const struct s_ip6 *ip, const unsigned char *payload) +void process_icmp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigned char *payload) { struct s_icmp *icmp; struct in_addr ip4_addr; - const unsigned char *icmp_data; + unsigned char *icmp_data; unsigned char *icmp_packet; - int packet_size; + int packet_size = htons(ip->len); /* define ICMP header */ icmp = (struct s_icmp *) (payload); /* define/compute ICMP data offset */ icmp_data = (unsigned char *) (payload + sizeof(struct s_icmp)); - /* the checksum has to be zeros before we have data for its computation */ - icmp->checksum = 0; - - /* create one big ICMP packet */ - 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); - } /* decide what type of ICMP we have */ switch (icmp->type) { /* NDP */ case ICMP6_NDP_NS: printf(" ICMP: [NDP] Neighbor Solicitation\n"); + + process_ndp(eth, ip, icmp_data); + return; - break; /* ping */ case ICMP6_ECHO_REQUEST: printf(" ICMP: Echo Request\n"); @@ -113,10 +105,20 @@ void process_icmp6(const struct s_ip6 *ip, const unsigned char *payload) break; } + /* create one big ICMP packet */ + icmp_packet = (unsigned char *) malloc(packet_size); + + if (icmp_packet == NULL) { + fprintf(stderr, "Fatal error! Lack of free memory!\n"); + exit(EXIT_FAILURE); + } + + /* the checksum has to be zeros before we have data for its computation */ + icmp->checksum = 0; + /* copy data into the packet */ memcpy(icmp_packet, icmp, sizeof(struct s_icmp)); - memcpy(icmp_packet + sizeof(struct s_icmp), icmp_data, - packet_size - sizeof(struct s_icmp)); + memcpy(icmp_packet + sizeof(struct s_icmp), icmp_data, packet_size - sizeof(struct s_icmp)); /* compute the checksum */ icmp->checksum = checksum(icmp_packet, packet_size); @@ -134,6 +136,101 @@ void process_icmp6(const struct s_ip6 *ip, const unsigned char *payload) /* free allocated memory */ free(icmp_packet); icmp_packet = NULL; - - return; +} + +void process_ndp(const struct s_ethernet *eth_hdr, struct s_ip6 *ip_hdr, unsigned char *icmp_data) +{ + unsigned char *packet; + struct s_ethernet *eth; + struct ip6_hdr *ip; + struct s_icmp *icmp; + 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; + + /* get the NDP data */ + ndp_ns = (struct s_icmp_ndp_ns *) icmp_data; + + /* check if the requested address is ours */ + if (memcmp(&ip6addr_wrapsix, &ndp_ns->target, 12) != 0) { + printf("==> This NDP is not ours! <==\n"); + return; + } + + /* allocate memory for the packet */ + packet_size = SIZE_ETHERNET + SIZE_IP6 + sizeof(struct s_icmp) + sizeof(struct s_icmp_ndp_na); + packet = (unsigned char *) malloc(packet_size); + + if (packet == NULL) { + fprintf(stderr, "Fatal error! Lack of free memory!\n"); + exit(EXIT_FAILURE); + } + + /* parse the packet into structures */ + eth = (struct s_ethernet *) packet; + ip = (struct ip6_hdr *) (packet + SIZE_ETHERNET); + icmp = (struct s_icmp *) (packet + SIZE_ETHERNET + SIZE_IP6); + ndp_na = (struct s_icmp_ndp_na *) (packet + SIZE_ETHERNET + SIZE_IP6 + sizeof(struct s_icmp)); + + /* assemble the ethernet header */ + memcpy(ð->src, mac, sizeof(struct s_mac_addr)); + eth->dest = eth_hdr->src; + 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; + + /* assemble the ICMP header */ + icmp->type = ICMP6_NDP_NA; + icmp->code = 0; + icmp->checksum = 0; + + /* assemble the NDP */ + //ndp_na->flags |= INNAF_S; + //ndp_na->flags |= INNAF_O; + ndp_na->zeros = 0; + ndp_na->flags = 0x60; + ndp_na->target = ndp_ns->target; + ndp_na->o_type = 2; + ndp_na->o_len = 1; + 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)); + + /* send the packet */ + send_ndp(ip, packet, packet_size); + + /* free allocated memory */ + free(packet); + free(buf_ip6_pseudo); + packet = NULL; + buf_ip6_pseudo = NULL; } diff --git a/wrapper/wrapper.c b/wrapper/wrapper.c index 1161621..29f560a 100644 --- a/wrapper/wrapper.c +++ b/wrapper/wrapper.c @@ -1,35 +1,30 @@ #include "wrapper.h" +struct s_mac_addr *mac; /* MAC address of the device */ +char *dev; /* capture device name */ +int dev_index; /* capture device index */ + 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 */ + int num_packets = 0; /* number of packets to capture; 0 = infinite */ /* 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); } - - /* 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("Device: %s\n", dev); printf("Number of packets: %d\n", num_packets); printf("Filter expression: %s\n", filter_exp); @@ -46,17 +41,25 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + /* obtain MAC address of the device */ + mac = (struct s_mac_addr *) malloc(sizeof(struct s_mac_addr)); + if (get_mac_addr(dev, mac) != 0) { + fprintf(stderr, "Couldn't get device MAC address\n"); + exit(EXIT_FAILURE); + } + + /* get index of the device */ + dev_index = get_dev_index(dev); + /* 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)); + if (pcap_compile(handle, &fp, filter_exp, 0, 0) == -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)); + fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle)); exit(EXIT_FAILURE); } diff --git a/wrapper/wrapper.h b/wrapper/wrapper.h index 47c19ef..cd07056 100644 --- a/wrapper/wrapper.h +++ b/wrapper/wrapper.h @@ -5,12 +5,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include /* ip6_hdr */ /* Default snap length (maximum bytes per packet to capture) */ #define SNAP_LEN BUFSIZ @@ -18,22 +20,29 @@ /* 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/... */ +/* MAC address structure */ +struct s_mac_addr { + unsigned char a; + unsigned char b; + unsigned char c; + unsigned char d; + unsigned char e; + unsigned char f; }; -/* IPv4 header */ +/* Ethernet header structure */ +struct s_ethernet { + struct s_mac_addr dest; /* 48 b; destination host (MAC) address */ + struct s_mac_addr src; /* 48 b; source host (MAC) address */ + unsigned short type; /* 16 b; IP/ARP/RARP/... */ +}; -/* IPv6 header */ +/* IPv4 header structure */ + +/* IPv6 header structure */ struct s_ip6 { unsigned char ver; /* 8 b; version */ unsigned char traffic_class; /* 8 b; traffic class */ @@ -41,8 +50,19 @@ struct s_ip6 { 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 */ + struct in6_addr ip_src; /* 128 b; source address */ + struct in6_addr ip_dest; /* 128 b; destination address */ +}; + +/* 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 zeros:24; /* 24 b; reserved */ + unsigned char next_header; /* 8 b; next header */ }; /* TCP structure - only needed fields! */ @@ -65,8 +85,14 @@ struct s_icmp { /* 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 */ + unsigned short id; /* 16 b; ID value for ECHO REPLY */ + unsigned short seq; /* 16 b; sequence value for ECHO REPLY */ +}; + +/* ICMPv6 - NDP option structure */ +struct s_icmp_ndp_option { + unsigned char type; /* 8 b; type of the option */ + unsigned char len; /* 8 b; length of the option (including this header!) */ }; /* ICMPv6 - NDP NS structure */ @@ -74,10 +100,20 @@ struct s_icmp_ndp_ns { unsigned int zeros; /* 32 b; reserved section */ struct in6_addr target; /* 128 b; target IP address */ }; -struct s_icmp_ndp_option { - unsigned char type; /* 8 b; type of the option */ - unsigned char len; /* 8 b; length of the option (including this header!) */ + +/* ICMPv6 - NDP NA structure */ +struct s_icmp_ndp_na { + unsigned char flags; /* 8 b; 3 flags */ + unsigned int zeros:24; /* 24 b; reserved section */ + struct in6_addr target; /* 128 b; target IP address */ + unsigned char o_type; /* 8 b; option - type */ + unsigned char o_len; /* 8 b; option - length */ + struct s_mac_addr o_tlla; /* 48 b; option - target link-layer address */ }; +/* INNAF = ICMPv6 NDP NA Flag */ +#define INNAF_R 0x80 /* router flag */ +#define INNAF_S 0x40 /* solicited flag */ +#define INNAF_O 0x20 /* override flag */ /* ICMP types */ #define ICMP4_ECHO_REQUEST 0x8 @@ -93,11 +129,21 @@ struct s_icmp_ndp_option { #define ICMP6_NDP_RM 0x89 /* Prototypes */ +int get_mac_addr(const char *dev, struct s_mac_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_icmp6(const struct s_ip6 *ip, const unsigned char *payload); +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); unsigned short checksum(const void *_buf, int len); +/* 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 */ + #endif