Networking Forums

Networking Forums > Computer Networking > Linux Networking > Receiving neighbor advertisement to extract link-layer (MAC) address

Reply
Thread Tools Display Modes

Receiving neighbor advertisement to extract link-layer (MAC) address

 
 
pdbuchan@yahoo.com
Guest
Posts: n/a

 
      11-19-2011, 03:02 AM
This is the second part of a two-part post on IPv6 socket
programming.

Part 1 was entitled, "Creating neighbor solicitation packet with c
language and ancillary data structures"

This post is the second part, with my solution to reading the neighbor
advertisement we get back from our solicitation and extracting various
pieces of data like the all-important link-layer (MAC) address of the
node we sent the solicitation to.

To be practical, it should probably have a timer on the recvmsg loop.
Also, it would normally be in the same program as that which sent the
solicitation.

Dave

// Receives a neighbor advertisement and extracts hop limit,
// destination address and interface index from ancillary
// data, and advertising link-layer address (i.e., MAC)
// from options data.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h> // close()
#include <netinet/icmp6.h> // struct nd_neighbor_solicit/advert,
which contains icmp6_hdr and ND_NEIGHBOR_ADVERT
#include <netinet/ip.h> // IP_MAXPACKET (65535)
#include <arpa/inet.h> // inet_pton() and inet_ntop()
#include <netdb.h> // struct addrinfo
#include <sys/ioctl.h> // macro ioctl is defined
#include <bits/ioctls.h> // defines values for argument "request"
of ioctl. Here, we need SIOCGIFHWADDR
#include <bits/socket.h> // structs msghdr and cmsghdr
#include <net/if.h> // struct ifreq

// Taken from <linux/ipv6.h>, also in <netinet/in.h>
struct in6_pktinfo {
struct in6_addr ipi6_addr;
int ipi6_ifindex;
};

// Function prototypes
static void *find_ancillary (struct msghdr *, int);

int
main (int argc, char **argv)
{
int i, status, sd, on, ifindex, hoplimit;
struct nd_neighbor_advert *na;
unsigned char *inpack;
int len;
struct msghdr msghdr;
struct iovec iov[2];
unsigned char *opt, *pkt;
char *interface, *target, *destination;
struct in6_addr dst;
int rcv_ifindex;
struct ifreq ifr;
void *tmp;

// Allocate memory for various arrays.
tmp = (unsigned char *) malloc (IP_MAXPACKET * sizeof (unsigned
char));
if (tmp != NULL) {
inpack = tmp;}
else {
fprintf (stderr, "ERROR: Cannot allocate memory for array 'inpack'.
\n");
exit (EXIT_FAILURE);
}
memset (inpack, 0, IP_MAXPACKET * sizeof (unsigned char));

tmp = (char *) malloc (40 * sizeof (char));
if (tmp != NULL) {
target = tmp;}
else {
fprintf (stderr, "ERROR: Cannot allocate memory for array 'target'.
\n");
exit (EXIT_FAILURE);
}
memset (target, 0, 40 * sizeof (char));

tmp = (char *) malloc (20 * sizeof (char));
if (tmp != NULL) {
interface = tmp;}
else {
fprintf (stderr, "ERROR: Cannot allocate memory for array
'interface'.\n");
exit (EXIT_FAILURE);
}
memset (interface, 0, sizeof (interface));
strcpy (interface, "wlan0");

tmp = (char *) malloc (40 * sizeof (char));
if (tmp != NULL) {
destination = tmp;}
else {
fprintf (stderr, "ERROR: Cannot allocate memory for array
'destination'.\n");
exit (EXIT_FAILURE);
}
memset (destination, 0, sizeof (destination));

// Prepare msghdr for recvmsg().
memset (&msghdr, 0, sizeof (msghdr));
msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
memset (&iov, 0, sizeof (iov));
iov[0].iov_base = (unsigned char *) inpack;
iov[0].iov_len = IP_MAXPACKET;
msghdr.msg_iov = iov;
msghdr.msg_iovlen = 1;

msghdr.msg_control = (unsigned char *) malloc (IP_MAXPACKET * sizeof
(unsigned char));
msghdr.msg_controllen = IP_MAXPACKET * sizeof (unsigned char);

// Request a socket descriptor sd.
if ((sd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
perror ("Failed to get socket descriptor ");
exit (EXIT_FAILURE);
}

// Set flag so we receive hop limit from recvmsg.
on = 1;
if ((status = setsockopt (sd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
sizeof (on))) < 0) {
perror ("setsockopt to IPV6_RECVHOPLIMIT failed ");
exit (EXIT_FAILURE);
}

// Set flag so we receive destination address from recvmsg.
on = 1;
if ((status = setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
sizeof (on))) < 0) {
perror ("setsockopt to IPV6_RECVPKTINFO failed ");
exit (EXIT_FAILURE);
}

// Obtain MAC address of this node.
memset (&ifr, 0, sizeof (ifr));
snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
if (ioctl (sd, SIOCGIFHWADDR, &ifr) < 0) {
perror ("ioctl() failed to get source MAC address ");
return (EXIT_FAILURE);
}

// Retrieve interface index of this node.
if ((ifindex = if_nametoindex (interface)) == 0) {
perror ("if_nametoindex() failed to obtain interface index ");
exit (EXIT_FAILURE);
}
printf ("\nOn this node, index for interface %s is %i\n", interface,
ifindex);

// Bind socket to interface of this node.
if (setsockopt (sd, SOL_SOCKET, SO_BINDTODEVICE, (void *) &ifr,
sizeof (ifr)) < 0) {
perror ("SO_BINDTODEVICE failed");
exit (EXIT_FAILURE);
}

// Grab incoming message from socket sd.
// Keep at it until we get a neighbor advertisement.
na = (struct nd_neighbor_advert *) inpack;
while (na->nd_na_hdr.icmp6_type != ND_NEIGHBOR_ADVERT) {
if ((len = recvmsg (sd, &msghdr, 0)) < 0) {
perror ("recvmsg failed ");
return (EXIT_FAILURE);
}
}

// Ancillary data
printf ("\nIPv6 header data:\n");
opt = find_ancillary (&msghdr, IPV6_HOPLIMIT);
if (opt == NULL) {
fprintf (stderr, "Unknown hop limit\n");
exit (EXIT_FAILURE);
}
hoplimit = *(unsigned int *) opt;
printf ("Hop limit: %u\n", hoplimit);

opt = find_ancillary (&msghdr, IPV6_PKTINFO);
if (opt == NULL) {
fprintf (stderr, "Unkown destination address\n");
exit (EXIT_FAILURE);
}
dst = ((struct in6_pktinfo *) opt)->ipi6_addr;
inet_ntop (AF_INET6, &dst, destination, 40);
printf ("Destination address: %s\n", destination);

rcv_ifindex = ((struct in6_pktinfo *) opt)->ipi6_ifindex;
printf ("Destination interface index: %i\n", rcv_ifindex);

// ICMPv6 header and options data
printf ("\nICMPv6 header data:\n");
printf ("Type: %u\n", na->nd_na_hdr.icmp6_type);
printf ("Code: %u\n", na->nd_na_hdr.icmp6_code);
printf ("Checksum: %x\n", ntohs (na->nd_na_hdr.icmp6_cksum));
printf ("Router flag: %u\n", ntohl (na->nd_na_hdr.icmp6_data32[0])
>> 31);

printf ("Solicited flag: %u\n", ((ntohl (na-
>nd_na_hdr.icmp6_data32[0])) >> 30) & 1);

printf ("Override flag: %u\n", ((ntohl (na-
>nd_na_hdr.icmp6_data32[0])) >> 29) & 1);

printf ("Reserved: %i\n", (ntohl (na->nd_na_hdr.icmp6_data32[0])) &
536870911u);
inet_ntop (AF_INET6, &(na->nd_na_target), target, 40);
printf ("Target address of neighbor solicitation: %s\n", target);
printf ("\nOptions:\n");
pkt = (unsigned char *) inpack;
printf ("Type: %u\n", pkt[sizeof (struct nd_neighbor_advert)]);
printf ("Length: %u (units of 8 octets)\n", pkt[sizeof (struct
nd_neighbor_advert) + 1]);
printf ("MAC address: ");
for (i=2; i<7; i++) {
printf ("%02x:", pkt[sizeof (struct nd_neighbor_advert) + i]);
}
printf ("%02x\n", pkt[sizeof (struct nd_neighbor_advert) + 7]);

close (sd);

free (inpack);
free (target);
free (interface);
free (destination);
free (msghdr.msg_control);

return (EXIT_SUCCESS);
}

static void *
find_ancillary (struct msghdr *msg, int cmsg_type)
{
struct cmsghdr *cmsg = NULL;

for (cmsg = CMSG_FIRSTHDR (msg); cmsg != NULL; cmsg = CMSG_NXTHDR
(msg, cmsg)) {
if ((cmsg->cmsg_level == IPPROTO_IPV6) && (cmsg->cmsg_type ==
cmsg_type)) {
return (CMSG_DATA (cmsg));
}
}

return (NULL);
}
 
Reply With Quote
 
 
 
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Retransmission in Data link layer? SaranJothy Linux Networking 3 02-08-2007 06:01 PM
Suppressing Link Layer address in RA kewlemer Linux Networking 0 03-08-2006 10:15 PM
extract ip address from WLAN interface, programming in C burn Linux Networking 0 06-18-2005 06:06 PM
Which function at link layer sends packet? kernel.lover Linux Networking 0 02-03-2005 12:06 PM
Effect of link-layer compression on TCP bandwidth Shashank Khanvilkar Linux Networking 1 02-05-2004 03:50 AM



1 2 3 4 5 6 7 8 9 10 11