1
0
mirror of https://code.semirocket.science/wrapsix synced 2024-11-10 08:10:59 +02:00

Completed the implementation of NDP

This commit is contained in:
xHire 2009-01-03 16:24:39 +01:00
parent 322eeabefb
commit 39ba6988c0
6 changed files with 317 additions and 65 deletions

View File

@ -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

View File

@ -1,4 +1,6 @@
#include <unistd.h>
#include <net/if.h> /* ifreq */
#include <netinet/if_ether.h> /* ETH_P_IP, ETH_P_ALL */
#include <netpacket/packet.h> /* 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);
}

57
wrapper/if.c Normal file
View File

@ -0,0 +1,57 @@
#include <sys/ioctl.h>
#include <net/if.h>
#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;
}

View File

@ -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(&eth->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;
}

View File

@ -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);
}

View File

@ -5,12 +5,14 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip6.h> /* 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