C Program on ICMPv6 Neighbor Advertizement (unsolicited) Message

C Program on implementing ICMPv6 Neighbor Advertisement Message using Raw sockets

How to use the binary:

Neelkanth $sudo ./a.out  
Invalid input : 1
Help section
=====================================
Enter 5 arguments:
1. Outgoing Interface Name
2. Source IPV6 Address
3. ICMPV6 Target IP Address

Neelkanth $sudo ./a.out  wlp4s0 fe80::ad6:3956:56b0:97d7 fe80::1
MAC address for interface wlp4s0 is 7c:b0:c2:19:8e:f8
Index for interface wlp4s0 is 3
Destination IPV6 address derived from target: fe80::ad6:3956:56b0:97d7
The are bytes from the packets for calculating the checksum:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
fe80 0 0 0 ad6 3956 56b0 97d7 ff02 0 0 0 0 0 0 1 0 20 0 3a 8800 a000 0 fe80 0 0 0 ad6 3956 56b0 97d7 0 201 7cb0 c219 8ef8 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
sum: 8d59
1's complement of sum is answer(Final Checksum): a672

#####################################################

C Program Start here...

#####################################################


/*
 *##############################################################################################
 *
 *         ICMPv6 Neighbor Advertisement Unsolicited Message C program  
 *
 *##############################################################################################
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>           /* close() */
#include <string.h>           /* strcpy, memset(), and memcpy() */

#include <netdb.h>            /* struct addrinfo */
#include <sys/types.h>        /* needed for socket(), uint8_t, uint16_t */
#include <sys/socket.h>       /* needed for socket() */
#include <netinet/in.h>       /* IPPROTO_ICMPV6, INET6_ADDRSTRLEN */
#include <netinet/ip.h>       /* IP_MAXPACKET (which is 65535) */
#include <netinet/ip6.h>      /* struct ip6_hdr */
#include <netinet/icmp6.h>    /* struct icmp6_hdr and ICMP6_ECHO_REQUEST */
#include <arpa/inet.h>        /* inet_pton() and inet_ntop() */
#include <sys/ioctl.h>        /* macro ioctl is defined */
#include <bits/ioctls.h>      /* defines values for argument "request" of ioctl. */
#include <net/if.h>           /* struct ifreq */
#include <linux/if_ether.h>   /* ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD */
#include <linux/if_packet.h>  /* struct sockaddr_ll (see man 7 packet) */
#include <net/ethernet.h>

#include <errno.h>            /* errno, perror() */

/* Various Header Lengths  */
#define ETH_HDRLEN            14      /* Ethernet header length */
#define IPV6_HDRLEN           40      /* IPv6 header length */
#define ICMPV6_HDRLEN         24      /* ICMPv6 header length for neighbor advertisement unsolicited */
#define ICMPV6_OPTION_HDLEN    8      /* ICMPv6 option header length for neighbor advertisement unsolicited */

/* 
 * Function prototypes
 */
uint16_t checksum(uint16_t *, int);
uint16_t icmp6_checksum(struct ip6_hdr, 
                        struct nd_neighbor_advert, 
                        uint8_t *,
                        int);
char    *allocate_strmem(int);
uint8_t *allocate_ustrmem(int);

/*
 *#####################################################################################
 *                            MAIN FUNCTION STARTS HERE
 *#####################################################################################
 */
int main (int argc, char **argv)
{
    int i, status, frame_length, sd, bytes;
    char *interface = NULL, 
         *target    = NULL, 
         *src_ip    = NULL, 
         *dst_ip    = NULL;

    uint8_t *src_mac     = NULL, 
            *ether_frame = NULL;

    uint8_t *multicast_dest_mac_in_bytes = NULL;
    struct addrinfo hints, *res;
    struct sockaddr_in6 *ipv6;
    struct sockaddr_in6 icmpv6_target_ipv6_address;
    struct sockaddr_ll device;
    struct ifreq ifr;
    void *tmp = NULL;
    char multicast_dest_mac_in_str[24] = {0};    
    char *ipv6_header_dest_ip_addr = NULL;

    /*
     * Structures for ipv6 , icmpv6 Neighbor Advertisement and
     * icmpv6 options header.
     */
    struct ip6_hdr ipv6_hdr;
    struct icmp6_hdr icmphdr;
    struct nd_neighbor_advert na;
    unsigned char icmpv6_option1[ICMPV6_OPTION_HDLEN]={0};    

    /*
     * argv[1]: Outgoing interface
     * argv[2]: source ipv6 address
     * argv[3]: destination ipv6 address
     */
    if (argc != 4) {
        printf("Invalid input : %d\n", argc);
        printf("Help section\n"
                "=====================================\n"
                "Enter 3 arguments:\n"
                "1. Outgoing Interface Name\n"
                "2. Source IPV6 Address\n"
                "3. ICMPV6 Target IP Address\n"
              );
        printf("Input Arguments: %s %s %s\n",
               argv[1], argv[2], argv[3]);
        return -1;
    }

    /* 
     * Allocate memory for various arrays.
     */
    src_mac = allocate_ustrmem(6);
    multicast_dest_mac_in_bytes = allocate_ustrmem(6);
    ether_frame = allocate_ustrmem(IP_MAXPACKET);
    interface   = allocate_strmem(40);
    target = allocate_strmem(INET6_ADDRSTRLEN);
    src_ip = allocate_strmem(INET6_ADDRSTRLEN);
    dst_ip = allocate_strmem(INET6_ADDRSTRLEN);
    ipv6_header_dest_ip_addr = allocate_strmem(INET6_ADDRSTRLEN);

    /*
     *****************************************************************************
     *   INTERFACE, SOURCE IPV6 ADDRESS, DESTINATION IPV6 ADDRESS, 
     *   DESTINATION MAC ADDRESS  AND SOURCE MAC ADDRESS
     *****************************************************************************
     * */
    /* Interface to send packet through.  */
    strcpy(interface, argv[1]);

    /* Source IPv6 address: you need to fill this out */
    strcpy(src_ip, argv[2]);

    /*
     *  Destination IPv6 address either:
     *  1) unicast address of node which sent solicitation, or if the
     *  solicitation came from the unspecified address (::), use the
     *  2) IPv6 "all nodes" link-local multicast address (ff02::1).
     *  You need to fill this out.
     *  ipv6 address to be programmed in IPV6 header--> all nodes link local multicast address  
     */
    strcpy(ipv6_header_dest_ip_addr, "ff02::1");

    /* ICMPV6 target ip address.. is the link local ip address of the router  */
    strcpy (target, argv[3]);

    /* ethernet header ipv6 destination multicast MAC */
    strcpy(multicast_dest_mac_in_str, "33:33:00:00:00:01");
    sscanf(multicast_dest_mac_in_str, "%x:%x:%x:%x:%x:%x", 
           (unsigned int *)&multicast_dest_mac_in_bytes[0],
           (unsigned int *)&multicast_dest_mac_in_bytes[1],
           (unsigned int *)&multicast_dest_mac_in_bytes[2],
           (unsigned int *)&multicast_dest_mac_in_bytes[3],
           (unsigned int *)&multicast_dest_mac_in_bytes[4],
           (unsigned int *)&multicast_dest_mac_in_bytes[5]);

    /******************************************************************************/

    /* Submit request for a socket descriptor to look up interface.  */
    if ((sd = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {
        perror ("socket() failed to get socket descriptor for using ioctl() ");
        exit (EXIT_FAILURE);
    }

    /* Use ioctl() to look up interface name and get its MAC address.  */
    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);
    }
    close (sd);

    /* Copy source MAC address.  */
    memcpy(src_mac, ifr.ifr_hwaddr.sa_data, 6 * sizeof (uint8_t));
    /* 
     * Print Source MAC address of source interface from which the 
     * packet will go out. 
     */
    printf("MAC address for interface %s is ", interface);
    for (i=0; i<5; i++) {
        printf("%02x:", src_mac[i]);
    }
    printf("%02x\n", src_mac[5]);

    /* 
     * Find interface index from interface name and store index in
     * struct sockaddr_ll device, 
     * which will be used as an argument of sendto().
     */
    memset(&device, 0, sizeof (device));
    if ((device.sll_ifindex = if_nametoindex (interface)) == 0) {
        perror ("if_nametoindex() failed to obtain interface index ");
        exit (EXIT_FAILURE);
    }
    printf ("Index for interface %s is %i\n", interface, device.sll_ifindex);


    /*
     * THIS IS ONLY NEEDED WHEN TARGET IS URL AND NOT IP ADDRESS. IN THAT CASE,
     * IP ADDRESS OF THE DESTINATION IS DERIVED USING 'getaddrinfo() API 
     */
    /* Fill out hints for getaddrinfo(). */
    memset (&hints, 0, sizeof (hints));
    hints.ai_family = AF_INET6;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = hints.ai_flags | AI_CANONNAME;
    /*  Resolve target using getaddrinfo().  */
    if ((status = getaddrinfo (src_ip, NULL, &hints, &res)) != 0) {
        fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (status));
        exit (EXIT_FAILURE);
    }
    
    memset(&icmpv6_target_ipv6_address, '\0', sizeof(icmpv6_target_ipv6_address));
    memcpy(&icmpv6_target_ipv6_address, res->ai_addr, res->ai_addrlen);

    ipv6 = (struct sockaddr_in6 *)res->ai_addr;
    tmp = &(ipv6->sin6_addr);
    if (inet_ntop (AF_INET6, tmp, dst_ip, INET6_ADDRSTRLEN) == NULL) {
        status = errno;
        fprintf (stderr, "inet_ntop() failed.\nError message: %s", strerror (status));
        exit (EXIT_FAILURE);
    }
    freeaddrinfo (res);
    printf("Destination IPV6 address derived from target: %s\n", dst_ip);    

   /* 
    *#################################################################################
    *          THE ACTUAL ICMPV6 PACKET HEADER FORMATION BEGINS FROM THIS PLACE
    *#################################################################################
    */
    /* Fill out sockaddr_ll.   */
    device.sll_family = AF_PACKET;
    memcpy (device.sll_addr, src_mac, 6 * sizeof (uint8_t));
    device.sll_halen = 6;

    /*
     * Frame 10635: 86 bytes on wire (688 bits), 86 bytes captured (688 bits) on interface 0
        Interface id: 0 (wlp4s0)
        Interface name: wlp4s0

       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       @                                 L2 Ethernet header
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       Ethernet II, Src: IntelCor_19:8e:f8 (7c:b0:c2:19:8e:f8), Dst: IPv6mcast_01 (33:33:00:00:00:01)
        Destination: IPv6mcast_01 (33:33:00:00:00:01)
        Address: IPv6mcast_01 (33:33:00:00:00:01)
        .... ..1. .... .... .... .... = LG bit: Locally administered address (this is NOT the factory default)
        .... ...1 .... .... .... .... = IG bit: Group address (multicast/broadcast)
        Source: IntelCor_19:8e:f8 (7c:b0:c2:19:8e:f8)
        Address: IntelCor_19:8e:f8 (7c:b0:c2:19:8e:f8)
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
        Type: IPv6 (0x86dd)
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       @                                 L3 IPV6 header  
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       Internet Protocol Version 6, Src: fe80::ad6:3956:56b0:97d7, Dst: ff02::1
        0110 .... = Version: 6
        .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
        .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
        .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
        .... .... .... 0000 0000 0000 0000 0000 = Flow Label: 0x00000
        Payload Length: 32
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       @                                 ICMPV6 header   (24 bytes) 
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       Next Header: ICMPv6 (58)
        Hop Limit: 255
        Source: fe80::ad6:3956:56b0:97d7
        Destination: ff02::1
        Internet Control Message Protocol v6
        Type: Neighbor Advertisement (136)
        Code: 0
        Checksum: 0xa672 [correct]
        [Checksum Status: Good]
        Flags: 0xa0000000, Router, Override
        1... .... .... .... .... .... .... .... = Router: Set
        .0.. .... .... .... .... .... .... .... = Solicited: Not set
        ..1. .... .... .... .... .... .... .... = Override: Set
        ...0 0000 0000 0000 0000 0000 0000 0000 = Reserved: 0
        Target Address: fe80::ad6:3956:56b0:97d7
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       @                                 ICMPV6 option header  (8 bytes) 
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       ICMPv6 Option (Target link-layer address : 7c:b0:c2:19:8e:f8)
        Type: Target link-layer address (2)
        Length: 1 (8 bytes)
        Link-layer address: IntelCor_19:8e:f8 (7c:b0:c2:19:8e:f8)
    */

    /*                            IPV6 HEADER                     */
    /*  
     * 0 and 1)  IPv6 version (4 bits), Traffic class (8 bits), Flow label (20 bits)  = [32 bits or 4 bytes]
     * 2) Payload length = ICMP header(24 bytes) + ICMP option header(8 bytes)        =  [32 bytes]
     * 3) Next header (8 bits): 58 for ICMP                                           = [1 byte]
     * 4) Hop limit (8 bits): default to maximum value                                = [1 byte] 
     * 5) Source IPv6 address (128 bits)                                              = [16 bytes] 
     * 6) Destination IPv6 address (128 bits)                                          = [16 bytes]
     */
    ipv6_hdr.ip6_flow = htonl ((6 << 28) | (0 << 20) | 0);
    ipv6_hdr.ip6_plen = htons(ICMPV6_HDRLEN + ICMPV6_OPTION_HDLEN);
    ipv6_hdr.ip6_nxt = IPPROTO_ICMPV6;
    ipv6_hdr.ip6_hops = 255;
    if ((status = inet_pton(AF_INET6, src_ip, &(ipv6_hdr.ip6_src))) != 1) {
        fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
        exit (EXIT_FAILURE);
    }
    if ((status = inet_pton(AF_INET6, ipv6_header_dest_ip_addr, &(ipv6_hdr.ip6_dst))) != 1) {
        fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
        exit (EXIT_FAILURE);
    }


    /*                   IPMPV6 HEADER                    */
    /*  Populate icmp6_hdr portion of neighbor advertisement struct. */
    memset(&na, 0, sizeof(na));
    na.nd_na_hdr.icmp6_type  = ND_NEIGHBOR_ADVERT;   /* 136 (RFC 4861) */
    na.nd_na_hdr.icmp6_code  = 0;                    /* zero for neighbor solicitation (RFC 4861) */
    na.nd_na_hdr.icmp6_cksum = htons(0);            /* zero when calculating checksum */

    /*  Set R/S/O flags as: R=1, S=1, O=1. Set reserved to zero (RFC 4861) */
    na.nd_na_flags_reserved = htonl((1 << 31) + (1 << 29));
    na.nd_na_target = icmpv6_target_ipv6_address.sin6_addr;      /* Target address (NOT MULTICAST) (as type in6_addr) */

    /*                   ICMPV6 OPTIONS HEADER                 */
    icmpv6_option1[0] = 2;                        /* Option Type - "Target link layer address" (Section 4.6 of RFC 4861) */
    icmpv6_option1[1] = ICMPV6_OPTION_HDLEN/8;    /* Option Length - units of 8 octets (RFC 4861) */
    for (i = 0; i < 6; i++) {
        icmpv6_option1[i+2] = (uint8_t) src_mac[i];
    }

    /* 
     * Ethernet frame header.
     */

    #define ETH_DEST_MAC_OFFSET       0
    #define ETH_DEST_MAC_LEN          6    
    #define ETH_SRC_MAC_OFFSET        (ETH_DEST_MAC_OFFSET + ETH_DEST_MAC_LEN)
    #define ETH_SRC_MAC_LEN           6
    #define ETH_ETHERTYPE_LB_OFFSET   (ETH_SRC_MAC_OFFSET + ETH_SRC_MAC_LEN)
    #define ETH_ETHERTYPE_UB_OFFSET   (ETH_ETHERTYPE_LB_OFFSET + 1)
    #define ETHER_TYPE_LEN            2

    /* 
     * Ethernet frame length = 
     * ethernet header (MAC + MAC + ether type) + IP6 header + ICMPV6 header + ICMPV6 OPTIONS header
     */
    frame_length = ETH_DEST_MAC_LEN + ETH_SRC_MAC_LEN + 
                   ETHER_TYPE_LEN + IPV6_HDRLEN + ICMPV6_HDRLEN + ICMPV6_OPTION_HDLEN;

    /* Destination and Source MAC addresses */
    memcpy (ether_frame, multicast_dest_mac_in_bytes, ETH_DEST_MAC_LEN * sizeof (uint8_t));
    memcpy (ether_frame + ETH_SRC_MAC_OFFSET, src_mac, ETH_SRC_MAC_LEN * sizeof (uint8_t));

    /* 
     * Next is ethernet type code (ETH_P_IPV6 for IPv6).
     * http://www.iana.org/assignments/ethernet-numbers
     */
    ether_frame[ETH_ETHERTYPE_LB_OFFSET] = ETH_P_IPV6 / 256;
    ether_frame[ETH_ETHERTYPE_UB_OFFSET] = ETH_P_IPV6 % 256;

    /* Next is ethernet frame data (IPv6 header + ICMPV6 header + ICMPV6 option header). */

    /* IPv6 header */
    memcpy (ether_frame + ETH_HDRLEN, 
            &ipv6_hdr, IPV6_HDRLEN * sizeof (uint8_t));

    struct nd_neighbor_advert *ns_ptr = NULL;
    /* ICMPV6 header */
    memcpy (ether_frame + ETH_HDRLEN + IPV6_HDRLEN, 
            &na, ICMPV6_HDRLEN * sizeof (uint8_t));


    /* ICMPV6 Option header */
    memcpy(ether_frame + ETH_HDRLEN + IPV6_HDRLEN + ICMPV6_HDRLEN, 
           icmpv6_option1, ICMPV6_OPTION_HDLEN * sizeof (uint8_t));

    /* 
     * In order to update the checksum, retrieve the location of checksum 
     * from the packet 
     */
    ns_ptr = (struct nd_neighbor_advert *)(ether_frame + ETH_HDRLEN + IPV6_HDRLEN);
    ns_ptr->nd_na_hdr.icmp6_cksum = icmp6_checksum(ipv6_hdr,       /* ip header structure     */ 
                                                   na,             /* icmpv6 NA header structure */
                                                   icmpv6_option1, /* icmpv6 options header */        
                                                   ICMPV6_OPTION_HDLEN);

    /*  
     *  Create a raw socket to put the packet on the Wire. 
     */
    if ((sd = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {
        perror ("socket() failed ");
        exit (EXIT_FAILURE);
    }

    /* Send ethernet frame to socket. */
    if ((bytes = sendto (sd, ether_frame, frame_length, 
                         0, (struct sockaddr *) &device, 
                         sizeof (device))) <= 0) {
        perror ("sendto() failed");
        exit (EXIT_FAILURE);
    }

    /* Close socket descriptor. */
    close (sd);

    /* Free allocated memory. */
    free (src_mac);
    free (multicast_dest_mac_in_bytes);
    free (ether_frame);
    free (interface);
    free (target);
    free (src_ip);
    free (dst_ip);
    free (ipv6_header_dest_ip_addr);

    return (EXIT_SUCCESS);
}

/* 
 * Computing the internet checksum (RFC 1071).
 * Note that the internet checksum does not preclude collisions.
 */
uint16_t checksum (uint16_t *addr, int len)
{
    int count = len;
    register uint32_t sum = 0;
    uint16_t answer = 0;

    /* Sum up 2-byte values until none or only one byte left. */
    printf("The are bytes from the packets for calculating the checksum:\n");
    printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
    while (count > 1) {
        printf("%x ", htons(*addr));
        sum += *(addr++);
        count -= 2;
    }
    printf("\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");

    /* Add left-over byte, if any. */
    if (count > 0) {
        sum += *(uint8_t *) addr;
    }

    /* 
     * Fold 32-bit sum into 16 bits; we lose information by doing this,
     * increasing the chances of a collision.
     * sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
     */
    while (sum >> 16) {
        sum = (sum & 0xffff) + (sum >> 16);
    }
    printf("sum: %x\n", sum);

    /* Checksum is one's compliment of sum. */
    answer = ~sum;
    printf("1's complement of sum is answer(Final Checksum): %x\n", htons(answer));

    return (answer);
}

/* 
 * Build IPv6 ICMP pseudo-header and call checksum function 
 * (Section 8.1 of RFC 2460).
 */
uint16_t icmp6_checksum (struct ip6_hdr ipv6_hdr, 
                         struct nd_neighbor_advert na, 
                         uint8_t *payload, 
                         int payloadlen)
{
    char buf[IP_MAXPACKET];
    char *ptr = NULL;
    int chksumlen = 0;
    int i;

    /* ptr points to beginning of buffer buf */
    ptr = &buf[0];  

    /* Copy source IP address into buf (128 bits) */
    memcpy (ptr, &ipv6_hdr.ip6_src.s6_addr, sizeof (ipv6_hdr.ip6_src.s6_addr));
    ptr += sizeof (ipv6_hdr.ip6_src);
    chksumlen += sizeof (ipv6_hdr.ip6_src);

    /* Copy destination IP address into buf (128 bits) */
    memcpy (ptr, &ipv6_hdr.ip6_dst.s6_addr, sizeof (ipv6_hdr.ip6_dst.s6_addr));
    ptr += sizeof (ipv6_hdr.ip6_dst.s6_addr);
    chksumlen += sizeof (ipv6_hdr.ip6_dst.s6_addr);

    /* 
     * Copy Upper Layer Packet length into buf (32 bits).
     * Should not be greater than 65535 (i.e., 2 bytes).
     */ 
    *ptr = 0; ptr++;
    *ptr = 0; ptr++;
    *ptr = (ICMPV6_HDRLEN + payloadlen) / 256;
    ptr++;
    *ptr = (ICMPV6_HDRLEN + payloadlen) % 256;
    ptr++;
    chksumlen += 4;

    /* Copy zero field to buf (24 bits) */
    *ptr = 0; ptr++;
    *ptr = 0; ptr++;
    *ptr = 0; ptr++;
    chksumlen += 3;

    /* Copy next header field to buf (8 bits) */
    memcpy (ptr, &ipv6_hdr.ip6_nxt, sizeof (ipv6_hdr.ip6_nxt));
    ptr += sizeof (ipv6_hdr.ip6_nxt);
    chksumlen += sizeof (ipv6_hdr.ip6_nxt);

    /* Copy ICMPv6 type to buf (8 bits) */
    memcpy (ptr, &na.nd_na_hdr.icmp6_type, sizeof (na.nd_na_hdr.icmp6_type));
    ptr += sizeof (na.nd_na_hdr.icmp6_type);
    chksumlen += sizeof (na.nd_na_hdr.icmp6_type);

    /* Copy ICMPv6 code to buf (8 bits) */
    memcpy (ptr, &na.nd_na_hdr.icmp6_code, sizeof (na.nd_na_hdr.icmp6_code));
    ptr += sizeof (na.nd_na_hdr.icmp6_code);
    chksumlen += sizeof (na.nd_na_hdr.icmp6_code);

    /* Copy ICMPv6 ID to buf (16 bits) */
    memcpy (ptr, &na.nd_na_hdr.icmp6_id, sizeof (na.nd_na_hdr.icmp6_id));
    ptr += sizeof (na.nd_na_hdr.icmp6_id);
    chksumlen += sizeof (na.nd_na_hdr.icmp6_id);

    /* Copy ICMPv6 sequence number to buff (16 bits) */
    memcpy (ptr, &na.nd_na_hdr.icmp6_seq, sizeof (na.nd_na_hdr.icmp6_seq));
    ptr += sizeof (na.nd_na_hdr.icmp6_seq);
    chksumlen += sizeof (na.nd_na_hdr.icmp6_seq);

    /* Copy ICMPv6 Neighbor Target IP6 address to buff (128 bits) */
    memcpy (ptr, &na.nd_na_target, sizeof (na.nd_na_target));
    ptr += sizeof (na.nd_na_target);
    chksumlen += sizeof (na.nd_na_target);


    /* 
     * Copy ICMPv6 checksum to buf (16 bits)
     * Zero, since we don't know it yet.
     */ 
    *ptr = 0; ptr++;
    *ptr = 0; ptr++;
    chksumlen += 2;

    /* Copy ICMPv6 payload to buf */
    memcpy (ptr, payload, payloadlen * sizeof (uint8_t));
    ptr += payloadlen;
    chksumlen += payloadlen;

    /* Pad to the next 16-bit boundary */
    for (i = 0; i < payloadlen%2; i++, ptr++) {
        *ptr = 0;
        ptr += 1;
        chksumlen += 1;
    }

    return checksum ((uint16_t *) buf, chksumlen);
}

/* Allocate memory for an array of chars. */
char * allocate_strmem(int len)
{
    void *tmp;

    if (len <= 0) {
        fprintf(stderr, "ERROR: Cannot allocate memory because len = %i in allocate_strmem().\n", len);
        exit(EXIT_FAILURE);
    }

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

/* Allocate memory for an array of unsigned chars. */
uint8_t *allocate_ustrmem(int len)
{
    void *tmp;

    if (len <= 0) {
        fprintf(stderr, "ERROR: Cannot allocate memory because len = %i in allocate_ustrmem().\n", len);
        exit(EXIT_FAILURE);
    }

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



[IPV6] Neighbor Discovery Protocols Introduction

Neighbor Discovery Protocols Introduction

Neighbor Discovery protocol combines Address Resolution Protocol (ARP) and ICMP router  discovery and Redirect. With IPv4, we have no means to detect whether or not a neighbor is reachable. With the neighbor discovery protocol, a neighbor unreachability detection mechanism has been defined. Duplicate IP address detection has been implemented, too.

The neighbor discovery protocol consists of five ICMP messages: 

1. a pair of Router Solicitation/Router Advertisement messages
2. a pair of Neighbor Solicitation/Neighbor Advertisement messages
3. an ICMP redirect message

Neighbor solicitation and advertisement messages

Neighbor solicitation and advertisement messages enable a node to determine the link-layer address of another node (neighbor) on the same link. (This function is similar to the function provided by the Address Resolution Protocol [ARP] in IPv4.) 
For example, node 1 on a link wants to determine the link-layer address of node 2 on the same link. To do so, node 1, the source node, multicasts a neighbor solicitation message. 

The neighbor solicitation message, which has a value of 135 in the Type field of the ICMP packet header, contains the following information:
Source address: IPv6 address of node 1 interface that sends the message.
Destination address: solicited-node multicast address (FF02:0:0:0:0:1:FF00::/104) that corresponds the IPv6 address of node 2.
Link-layer address of node 1.
A query for the link-layer address of node 2.


After receiving the neighbor solicitation message from node 1, node 2 replies by sending a neighbor advertisement message, which has a value of 136 in the Type field of the ICMP packet header. 
The neighbor solicitation message contains the following information:Source address: IPv6 address of the node 2 interface that sends the message.
Destination address: IPv6 address of node 1.
Link-layer address of node 2.
1. After node 1 receives the neighbor advertisement message from node 2, nodes 1 and 2 can now exchange packets on the link.   (equivalent to ARP resolution in IPv4)
2. After the link-layer address of node 2 is determined, node 1 can send neighbor solicitation messages to node 2 to verify that it is reachable.   (Neighbor Reachability)


Neighbor advertisement – 
1. A response to a Neighbor Solicitation message.
2. A node can also send unsolicited neighbor advertisements to announce a link-layer address change.
    The received node would then update the link-layer of the node sending NA into it's neighbor
    cache.

    This can be viewed in "ip -6 neighbor" command output on a linux machine.

RS — Router Solicitation (ICMPv6 type 133)

When an interface becomes enabled, hosts may send out RSes that request that routers generate Router Advertisements (RAs) immediately rather than at their next scheduled time.

RA — Router Advertisement (ICMPv6 type 134)

Routers advertise their presence together with various link and Internet parameters either periodically, or in response to an RS message. RAs contain prefixes that are used for determining whether another address shares the same link (on-link determination) and/or address configuration, a suggested hop limit value, and so forth.

C Program on ICMPv6 Neighbor Solicitation Message

C Program on implementing ICMPv6 Neighbor Solicitation Message using Raw sockets

How to use the binary:

Neelkanth $sudo ./a.out wlp4s0 fe80::ad6:3956:56b0:97d7 ff02::1 44:82:e5:11:aa:6e 
Invalid input : 5
Help section
=====================================
Enter 5 arguments:
1. Outgoing Interface Name
2. Source IPV6 Address
3. Destination IPV6 Address
4. Destination MAC Address
5. Unicast(0) / Multicast(1)
Input Arguments: wlp4s0 fe80::ad6:3956:56b0:97d7 ff02::1 44:82:e5:11:aa:6e (null)

Neighbor Solicitation Unicast

Neelkanth $sudo ./a.out wlp4s0 fe80::ad6:3956:56b0:97d7 fe80::1 44:82:e5:11:aa:6e 0
MAC address for interface wlp4s0 is 7c:b0:c2:19:8e:f8
Index for interface wlp4s0 is 3
IPV6 header multicast destination address: fe80::1
The are bytes from the packets for calculating the checksum:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
fe80 0 0 0 ad6 3956 56b0 97d7 fe80 0 0 0 0 0 0 1 0 20 0 3a 8700 0 0 fe80 0 0 0 0 0 0 1 0 101 7cb0 c219 8ef8 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

sum: 5784
1's complement of sum is answer(Final Checksum): a87b

Neighbor Solicitation Multicast

Neelkanth $sudo ./a.out wlp4s0 fe80::ad6:3956:56b0:97d7 fe80::1 44:82:e5:11:aa:6e 1
MAC address for interface wlp4s0 is 7c:b0:c2:19:8e:f8
Index for interface wlp4s0 is 3
IPV6 header multicast destination address: ff02::1:ff00:1
The are bytes from the packets for calculating the checksum:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
fe80 0 0 0 ad6 3956 56b0 97d7 ff02 0 0 0 0 1 ff00 1 0 20 0 3a 8700 0 0 fe80 0 0 0 0 0 0 1 0 101 7cb0 c219 8ef8
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

sum: db83
1's complement of sum is answer(Final Checksum): 247c

####################################################

C Program Start here...

####################################################

/*
 *##############################################################################
 *
 *         ICMPv6 Neighbor solicitation Multicast Message C program  
 *
 *##############################################################################
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>           /* close() */
#include <string.h>           /* strcpy, memset(), and memcpy() */

#include <netdb.h>            /* struct addrinfo */
#include <sys/types.h>        /* needed for socket(), uint8_t, uint16_t */
#include <sys/socket.h>       /* needed for socket() */
#include <netinet/in.h>       /* IPPROTO_ICMPV6, INET6_ADDRSTRLEN */
#include <netinet/ip.h>       /* IP_MAXPACKET (which is 65535) */
#include <netinet/ip6.h>      /* struct ip6_hdr */
#include <netinet/icmp6.h>    /* struct icmp6_hdr and ICMP6_ECHO_REQUEST */
#include <arpa/inet.h>        /* inet_pton() and inet_ntop() */
#include <sys/ioctl.h>        /* macro ioctl is defined */
#include <bits/ioctls.h>      /* defines values for argument "request" of ioctl. */
#include <net/if.h>           /* struct ifreq */
#include <linux/if_ether.h>   /* ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD */
#include <linux/if_packet.h>  /* struct sockaddr_ll (see man 7 packet) */
#include <net/ethernet.h>

#include <errno.h>            /* errno, perror() */

/* Various Header Lengths  */
#define ETH_HDRLEN            14      /* Ethernet header length */
#define IPV6_HDRLEN           40      /* IPv6 header length */
#define ICMPV6_HDRLEN         24      /* ICMPv6 header length for neighbor solicitation */
#define ICMPV6_OPTION_HDLEN    8      /* ICMPv6 option header length for neighbor solicitation */

/*
 * Function prototypes
 */
uint16_t checksum(uint16_t *, int);
uint16_t icmp6_checksum(struct ip6_hdr,
                         struct nd_neighbor_solicit,
                         uint8_t *,
                         int);
char *allocate_strmem(int);
uint8_t *allocate_ustrmem(int);


/*
 *#####################################################################################
 *                            MAIN FUNCTION STARTS HERE 
 *#####################################################################################
 */
int main (int argc, char **argv)
{
    int i, status, datalen, frame_length, sd, bytes;
    uint8_t *src_mac = NULL,
            *dst_mac = NULL,
            *ether_frame = NULL;

    struct addrinfo hints, *res = NULL;
 
    char *interface = NULL,
         *src_ip = NULL,
         *input_ipcmv6_dest_ipaddr = NULL,
         *multicast_icmpv6_dest_ipaddr = NULL;

    struct sockaddr_in6 dest_icmpv6_header_unicast;
    struct sockaddr_in6 dest_ipv6_header_multicast;
    struct sockaddr_in6 *dest_ipv6_header_multicast_ptr;

    struct sockaddr_ll device;
    void *tmp;
 
    struct ifreq ifr;
    char dest_mac_in_str[24] = {0}; 

    /*
     * Structures for ipv6 , icmpv6 Neighbor Solicitation and
     * icmpv6 options header.
     */
    struct ip6_hdr ipv6_hdr;
    struct icmp6_hdr icmphdr;
    struct nd_neighbor_solicit ns;
    unsigned char icmpv6_option1[ICMPV6_OPTION_HDLEN]={0}; 

    /*
     * argv[1]: Outgoing Interface
     * argv[2]: source ipv6 address
     * argv[3]: destination ipv6 address
     * argv[4]: destination MAC address
     * argv[5]: Unicast/Multicast 
     */
    if (argc != 6) {
        printf("Invalid input : %d\n", argc);
        printf("Help section\n"
                "=====================================\n"
                "Enter 5 arguments:\n"
                "1. Outgoing Interface Name\n"
                "2. Source IPV6 Address\n"
                "3. Destination IPV6 Address\n"
                "4. Destination MAC Address\n"
                "5. Unicast(0) / Multicast(1)\n"
              );
        printf("Input Arguments: %s %s %s %s %s\n",
                  argv[1], argv[2], argv[3], argv[4], argv[5]);
        return -1;
    }


    /*
     * Allocate memory for various arrays.
     */
    src_mac     = allocate_ustrmem(6);
    dst_mac     = allocate_ustrmem(6);
    ether_frame = allocate_ustrmem(IP_MAXPACKET);
    interface   = allocate_strmem(40);
    src_ip      = allocate_strmem(INET6_ADDRSTRLEN);
    input_ipcmv6_dest_ipaddr     = allocate_strmem(INET6_ADDRSTRLEN);
    multicast_icmpv6_dest_ipaddr = allocate_strmem(INET6_ADDRSTRLEN);

    /*
     *****************************************************************************
     *   INTERFACE, SOURCE IPV6 ADDRESS, DESTINATION IPV6 ADDRESS, 
     *   DESTINATION MAC ADDRESS  AND SOURCE MAC ADDRESS
     *****************************************************************************
     * */

    /* Interface to send packet through.  */
    strcpy(interface, argv[1]);

    /* Source IPv6 address: you need to fill this out */
    strcpy(src_ip, argv[2]);

    /* Destination IPV6 address */
    strcpy(input_ipcmv6_dest_ipaddr, argv[3]);

    /* Set destination MAC address: you need to fill these out */
    strcpy(dest_mac_in_str, argv[4]);
    sscanf(dest_mac_in_str, "%x:%x:%x:%x:%x:%x",
           (unsigned int *) &dst_mac[0],
           (unsigned int *) &dst_mac[1],
           (unsigned int *) &dst_mac[2],
           (unsigned int *) &dst_mac[3],
           (unsigned int *) &dst_mac[4],
           (unsigned int *) &dst_mac[5]);

    if (strcmp(argv[5], "1") == 0) {
        /* Convert destimation mac into Multicast MAC */
        dst_mac[0] = 0x33; 
        dst_mac[1] = 0x33; 
        dst_mac[2] = 0xff; 
    }

    /* Submit request for a socket descriptor to look up interface.  */
    if ((sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
        perror("socket() failed to get socket descriptor for using ioctl() ");
        exit (EXIT_FAILURE);
    }

    /* Use ioctl() to look up interface name and get its MAC address.  */
    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);
    }
    close(sd);

    /* Copy source MAC address.  */
    memcpy(src_mac, ifr.ifr_hwaddr.sa_data, 6 * sizeof (uint8_t));
    /*
     * Print Source MAC address of source interface from which the
     * packet will go out.
     */
    printf("MAC address for interface %s is ", interface);
    for(i=0; i<5; i++) {
        printf ("%02x:", src_mac[i]);
    }
    printf("%02x\n", src_mac[5]);
    /******************************************************************************/

    /*
     * Find interface index from interface name and store index in
     * struct sockaddr_ll device,
     * which will be used as an argument of sendto().
     */
    memset(&device, 0, sizeof (device));
    if ((device.sll_ifindex = if_nametoindex(interface)) == 0) {
        perror("if_nametoindex() failed to obtain interface index ");
        exit(EXIT_FAILURE);
    }
    printf("Index for interface %s is %i\n", interface, device.sll_ifindex);


    /*
     * THIS IS ONLY NEEDED WHEN <input_ipcmv6_dest_ipaddr> IS URL AND NOT IP ADDRESS. IN THAT CASE,
     * IP ADDRESS OF THE DESTINATION IS DERIVED USING 'getaddrinfo() API 
     */

    /* Fill out hints for getaddrinfo(). */
    memset (&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET6;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = hints.ai_flags | AI_CANONNAME;

    /*  Resolve <input_ipcmv6_dest_ipaddr> using getaddrinfo().  */
    if ((status = getaddrinfo(input_ipcmv6_dest_ipaddr, NULL, &hints, &res)) != 0) {
        fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror(status));
        exit (EXIT_FAILURE);
    }


    /*
     * ICMPV6 destination address.
     */
    memset(&dest_icmpv6_header_unicast, '\0', sizeof(dest_icmpv6_header_unicast));
    memcpy(&dest_icmpv6_header_unicast, res->ai_addr, res->ai_addrlen);


    /*
     *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     *  PREPARE ICMPV6 MULTICAST DESTINATION ADDRESS [START]  
     *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     */

    /*
     * Convert Unicast 'input_ipcmv6_dest_ipaddr' into 'destination Multicast Address'
     * Section 2.7.1 of RFC 4291.
     */
    memset(&dest_ipv6_header_multicast, '\0', sizeof(dest_ipv6_header_multicast));
    memcpy(&dest_ipv6_header_multicast, res->ai_addr, res->ai_addrlen);

    if (strcmp(argv[5], "1") == 0) {
        dest_ipv6_header_multicast.sin6_addr.s6_addr[0] = 255;
        dest_ipv6_header_multicast.sin6_addr.s6_addr[1] = 2;
        for(i = 2; i < 11; i++) {
            dest_ipv6_header_multicast.sin6_addr.s6_addr[i] = 0;
        }
        dest_ipv6_header_multicast.sin6_addr.s6_addr[11] = 1;
        dest_ipv6_header_multicast.sin6_addr.s6_addr[12] = 255;
    }

    memset(multicast_icmpv6_dest_ipaddr, 0, INET6_ADDRSTRLEN * sizeof (char));

    /* ICMPV6 header's Target's solicited-node multicast address. */
    dest_ipv6_header_multicast_ptr = (struct sockaddr_in6 *)&dest_ipv6_header_multicast;
    tmp = &(dest_ipv6_header_multicast_ptr->sin6_addr);
    if (inet_ntop (AF_INET6, tmp, multicast_icmpv6_dest_ipaddr, INET6_ADDRSTRLEN) == NULL) {
        status = errno;
        fprintf(stderr, "inet_ntop() failed.\nError message: %s", strerror (status));
        exit (EXIT_FAILURE);
    }
    printf("IPV6 header multicast destination address: %s\n", multicast_icmpv6_dest_ipaddr);

    /* 
     *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     * PREPARE ICMPV6 MULTICAST DESTINATION ADDRESS    [END]  
     *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     */

    freeaddrinfo (res);

   /* 
    *#################################################################################
    *          THE ACTUAL ICMPV6 PACKET HEADER FORMATION BEGINS FROM THIS PLACE
    *#################################################################################
    */
    /* Fill out sockaddr_ll.   */
    device.sll_family = AF_PACKET;
    memcpy (device.sll_addr, src_mac, 6 * sizeof (uint8_t));
    device.sll_halen = 6;

    /*
     *
     *Frame 4282: 86 bytes on wire (688 bits), 86 bytes captured (688 bits) on interface 0
      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
      @                                 L2 Ethernet header
      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
      Ethernet II, Src: IntelCor_19:8e:f8 (7c:b0:c2:19:8e:f8), Dst: IPv6mcast_ff:11:aa:6e (33:33:ff:11:aa:6e)
        Destination: IPv6mcast_ff:11:aa:6e (33:33:ff:11:aa:6e)
        Address: IPv6mcast_ff:11:aa:6e (33:33:ff:11:aa:6e)
        .... ..1. .... .... .... .... = LG bit: Locally administered address (this is NOT the factory default)
        .... ...1 .... .... .... .... = IG bit: Group address (multicast/broadcast)
        Source: IntelCor_19:8e:f8 (7c:b0:c2:19:8e:f8)
        Address: IntelCor_19:8e:f8 (7c:b0:c2:19:8e:f8)
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
        Type: IPv6 (0x86dd)
      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
      @                                 L3 IPV6 header  
      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
      Internet Protocol Version 6, Src: fe80::ad6:3956:56b0:97d7, Dst: ff02::1:ff00:1
        0110 .... = Version: 6
        .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
        .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
        .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
        .... .... .... 0000 0000 0000 0000 0000 = Flow Label: 0x00000
        Payload Length: 32
        Next Header: ICMPv6 (58)
        Hop Limit: 255
        Source: fe80::ad6:3956:56b0:97d7
        Destination: ff02::1:ff00:1
     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     @                                 ICMPV6 header   (24 bytes) 
     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
      Internet Control Message Protocol v6
        Type: Neighbor Solicitation (135)
        Code: 0
        Checksum: 0x7c24 [correct]
        [Checksum Status: Good]
        Reserved: 00000000
        Target Address: fe80::1
     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     @                                 ICMPV6 option header  (8 bytes) 
     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
      ICMPv6 Option (Source link-layer address : 7c:b0:c2:19:8e:f8)
        Type: Source link-layer address (1)
        Length: 1 (8 bytes)
        Link-layer address: IntelCor_19:8e:f8 (7c:b0:c2:19:8e:f8)
    */

    /*          
     *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@          
     *                                  IPV6 HEADER  
     *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     */
    /*
     * 0 and 1)  IPv6 version (4 bits), Traffic class (8 bits), Flow label (20 bits)  = [32 bits or 4 bytes]
     * 2) Payload length = ICMP header(24 bytes) + ICMP option header(8 bytes)        =  [32 bytes]
     * 3) Next header (8 bits): 58 for ICMP                                           = [1 byte]
     * 4) Hop limit (8 bits): default to maximum value                                = [1 byte]
     * 5) Source IPv6 address (128 bits)                                              = [16 bytes]
     * 6) Destination IPv6 address (128 bits)                                          = [16 bytes]
     */
    ipv6_hdr.ip6_flow = htonl ((6 << 28) | (0 << 20) | 0);
    ipv6_hdr.ip6_plen = htons(ICMPV6_HDRLEN + ICMPV6_OPTION_HDLEN);
    ipv6_hdr.ip6_nxt = IPPROTO_ICMPV6;
    ipv6_hdr.ip6_hops = 255;
    if ((status = inet_pton(AF_INET6, src_ip, &(ipv6_hdr.ip6_src))) != 1) {
        fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
        exit (EXIT_FAILURE);
    }
    if ((status = inet_pton(AF_INET6, multicast_icmpv6_dest_ipaddr, &(ipv6_hdr.ip6_dst))) != 1) {
        fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
        exit (EXIT_FAILURE);
    }


    /*
     *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     *                                IPMPV6 HEADER
     *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     */
    /*  Populate icmp6_hdr portion of neighbor solicit struct. */
    memset(&ns, 0, sizeof(ns));
    ns.nd_ns_hdr.icmp6_type = ND_NEIGHBOR_SOLICIT;                   /* 135 (RFC 4861) */
    ns.nd_ns_hdr.icmp6_code = 0;                                     /* zero for neighbor solicitation (RFC 4861) */
    ns.nd_ns_hdr.icmp6_cksum = htons(0);                             /* zero when calculating checksum */
    ns.nd_ns_reserved = htonl(0);                                    /* Reserved - must be set to zero (RFC 4861) */
    ns.nd_ns_target = dest_icmpv6_header_unicast.sin6_addr;          /* Target address (NOT MULTICAST) (as type in6_addr) */

    /*
     *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                 
     *                             ICMPV6 OPTIONS HEADER               
     *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                 
     */
    icmpv6_option1[0] = 1;                        /* Option Type - "source link layer address" (Section 4.6 of RFC 4861) */
    icmpv6_option1[1] = ICMPV6_OPTION_HDLEN/8;    /* Option Length - units of 8 octets (RFC 4861) */
    for (i = 0; i < 6; i++) {
        icmpv6_option1[i+2] = (uint8_t) src_mac[i];
    }

    /*
     *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                 
     *                              Ethernet frame header.
     *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                 
     */

    #define ETH_DEST_MAC_OFFSET       0
    #define ETH_DEST_MAC_LEN          6 
    #define ETH_SRC_MAC_OFFSET        (ETH_DEST_MAC_OFFSET + ETH_DEST_MAC_LEN)
    #define ETH_SRC_MAC_LEN           6
    #define ETH_ETHERTYPE_LB_OFFSET   (ETH_SRC_MAC_OFFSET + ETH_SRC_MAC_LEN)
    #define ETH_ETHERTYPE_UB_OFFSET   (ETH_ETHERTYPE_LB_OFFSET + 1)
    #define ETHER_TYPE_LEN            2

    /*
     * Ethernet frame length =
     * ethernet header (MAC + MAC + ether type) + IP6 header + ICMPV6 header + ICMPV6 OPTIONS header
     */
    frame_length = ETH_DEST_MAC_LEN + ETH_SRC_MAC_LEN +
                   ETHER_TYPE_LEN + IPV6_HDRLEN + ICMPV6_HDRLEN + ICMPV6_OPTION_HDLEN;

    /* Destination and Source MAC addresses */
    memcpy (ether_frame, dst_mac, ETH_DEST_MAC_LEN * sizeof (uint8_t));
    memcpy (ether_frame + ETH_SRC_MAC_OFFSET, src_mac, ETH_SRC_MAC_LEN * sizeof (uint8_t));

    /*
     * Next is ethernet type code (ETH_P_IPV6 for IPv6).
     * http://www.iana.org/assignments/ethernet-numbers
     */
    ether_frame[ETH_ETHERTYPE_LB_OFFSET] = ETH_P_IPV6 / 256;
    ether_frame[ETH_ETHERTYPE_UB_OFFSET] = ETH_P_IPV6 % 256;

    /* Next is ethernet frame data (IPv6 header + ICMPV6 header + ICMPV6 option header). */

    /* IPv6 header */
    memcpy (ether_frame + ETH_HDRLEN,
            &ipv6_hdr, IPV6_HDRLEN * sizeof (uint8_t));

    struct nd_neighbor_solicit *ns_ptr = NULL;
    /* ICMPV6 header */
    memcpy (ether_frame + ETH_HDRLEN + IPV6_HDRLEN,
            &ns, ICMPV6_HDRLEN * sizeof (uint8_t));


    /* ICMPV6 Option header */
    memcpy(ether_frame + ETH_HDRLEN + IPV6_HDRLEN + ICMPV6_HDRLEN,
           icmpv6_option1, ICMPV6_OPTION_HDLEN * sizeof (uint8_t));

    /*
     * In order to update the checksum, retrieve the location of checksum
     * from the packet
     */
    ns_ptr = (struct nd_neighbor_solicit *)(ether_frame + ETH_HDRLEN + IPV6_HDRLEN);

    ns_ptr->nd_ns_hdr.icmp6_cksum = icmp6_checksum(ipv6_hdr,       /* ipv6 header structure     */
                                                   ns,             /* icmpv6 NS header structure */
                                                   icmpv6_option1, /* icmpv6 options header */     
                                                   ICMPV6_OPTION_HDLEN);

    /*
     *  Create a raw socket to put the packet on the Wire.
     */
    if ((sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
        perror("socket() failed ");
        exit (EXIT_FAILURE);
    }

    /* Send ethernet frame to socket. */
    if ((bytes = sendto(sd, ether_frame, frame_length, 0,
                        (struct sockaddr *) &device,
                        sizeof (device))) <= 0) {
        perror("sendto() failed");
        exit(EXIT_FAILURE);
    }

    /* Close socket descriptor. */
    close (sd);

    /* Free allocated memory. */
    free (src_mac);
    free (dst_mac);
    free (ether_frame);
    free (interface);
    free (input_ipcmv6_dest_ipaddr);
    free (multicast_icmpv6_dest_ipaddr);
    free (src_ip);

    return (EXIT_SUCCESS);
}

/* Computing the internet checksum (RFC 1071). */
/* Note that the internet checksum does not preclude collisions. */
uint16_t checksum(uint16_t *addr, int len)
{
    int count = len;
    register uint32_t sum = 0;
    uint16_t answer = 0;

    /* Sum up 2-byte values until none or only one byte left. */
    printf("The are bytes from the packets for calculating the checksum:\n");
    printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
    while (count > 1) {
        printf("%x ", htons(*addr));
        sum += *(addr++);
        count -= 2;
    }
    printf("\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
    printf("\n");

    /* Add left-over byte, if any. */
    if (count > 0) {
        sum += *(uint8_t *)addr;
    }

    /*
     * Fold 32-bit sum into 16 bits; we lose information by doing this,
     * increasing the chances of a collision.
     * sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
    */
    while (sum >> 16) {
        sum = (sum & 0xffff) + (sum >> 16);
    }

    printf("sum: %x\n", sum);

    /* Checksum is one's compliment of sum. */
    answer = ~sum;
    printf("1's complement of sum is answer(Final Checksum): %x\n", answer);

    return (answer);
}

/* Build IPv6 ICMP pseudo-header and call checksum function (Section 8.1 of RFC 2460). */
uint16_t icmp6_checksum (struct ip6_hdr ipv6_hdr,
                         struct nd_neighbor_solicit nd,
                         uint8_t *payload, int payloadlen)
{
    char buf[IP_MAXPACKET] = {0};
    char *ptr = NULL;
    int chksumlen = 0;
    int i = 0;

    /* ptr points to beginning of buffer buf */
    ptr = &buf[0];

    /* Copy source IP address into buf (128 bits) */
    memcpy (ptr, &ipv6_hdr.ip6_src.s6_addr, sizeof (ipv6_hdr.ip6_src.s6_addr));
    ptr += sizeof (ipv6_hdr.ip6_src);
    chksumlen += sizeof (ipv6_hdr.ip6_src);

    /* Copy destination IP address into buf (128 bits) */
    memcpy (ptr, &ipv6_hdr.ip6_dst.s6_addr, sizeof (ipv6_hdr.ip6_dst.s6_addr));
    ptr += sizeof (ipv6_hdr.ip6_dst.s6_addr);
    chksumlen += sizeof (ipv6_hdr.ip6_dst.s6_addr);

    /*
     * Copy Upper Layer Packet length into buf (32 bits).
     * Should not be greater than 65535 (i.e., 2 bytes).
     */
    *ptr = 0; ptr++;
    *ptr = 0; ptr++;
    *ptr = (ICMPV6_HDRLEN + payloadlen) / 256;
    ptr++;
    *ptr = (ICMPV6_HDRLEN + payloadlen) % 256;
    ptr++;
    chksumlen += 4;

    /* Copy zero field to buf (24 bits) */
    *ptr = 0; ptr++;
    *ptr = 0; ptr++;
    *ptr = 0; ptr++;
    chksumlen += 3;

    /* Copy next header field to buf (8 bits) */
    memcpy (ptr, &ipv6_hdr.ip6_nxt, sizeof (ipv6_hdr.ip6_nxt));
    ptr += sizeof (ipv6_hdr.ip6_nxt);
    chksumlen += sizeof (ipv6_hdr.ip6_nxt);

    /* Copy ICMPv6 type to buf (8 bits) */
    memcpy (ptr, &nd.nd_ns_hdr.icmp6_type, sizeof (nd.nd_ns_hdr.icmp6_type));
    ptr += sizeof (nd.nd_ns_hdr.icmp6_type);
    chksumlen += sizeof (nd.nd_ns_hdr.icmp6_type);

    /* Copy ICMPv6 code to buf (8 bits) */
    memcpy (ptr, &nd.nd_ns_hdr.icmp6_code, sizeof (nd.nd_ns_hdr.icmp6_code));
    ptr += sizeof (nd.nd_ns_hdr.icmp6_code);
    chksumlen += sizeof (nd.nd_ns_hdr.icmp6_code);

    /* Copy ICMPv6 ID to buf (16 bits) */
    memcpy (ptr, &nd.nd_ns_hdr.icmp6_id, sizeof (nd.nd_ns_hdr.icmp6_id));
    ptr += sizeof (nd.nd_ns_hdr.icmp6_id);
    chksumlen += sizeof (nd.nd_ns_hdr.icmp6_id);

    /* Copy ICMPv6 sequence number to buff (16 bits) */
    memcpy (ptr, &nd.nd_ns_hdr.icmp6_seq, sizeof (nd.nd_ns_hdr.icmp6_seq));
    ptr += sizeof (nd.nd_ns_hdr.icmp6_seq);
    chksumlen += sizeof (nd.nd_ns_hdr.icmp6_seq);

    /* Copy ICMPv6 in6_addr to buff (128 bits) */
    memcpy (ptr, &nd.nd_ns_target, sizeof (nd.nd_ns_target));
    ptr += sizeof (nd.nd_ns_target);
    chksumlen += sizeof (nd.nd_ns_target);

    /*
     * Copy ICMPv6 checksum to buf (16 bits)
     * Zero, since we don't know it yet.
     */
    *ptr = 0; ptr++;
    *ptr = 0; ptr++;
    chksumlen += 2;

    /* Copy ICMPv6 payload to buf */
    memcpy (ptr, payload, payloadlen * sizeof (uint8_t));
    ptr += payloadlen;
    chksumlen += payloadlen;

    /* Pad to the next 16-bit boundary */
    for (i=0; i<payloadlen%2; i++, ptr++) {
        *ptr = 0;
        ptr += 1;
        chksumlen += 1;
    }

    return checksum ((uint16_t *) buf, chksumlen);
}

/*
 * Allocate memory for an array of chars.
 */
char *allocate_strmem(int len)
{
    void *tmp = NULL;

    if (len <= 0) {
        fprintf (stderr, "ERROR: Cannot allocate memory because len = %i in allocate_strmem().\n", len);
        exit (EXIT_FAILURE);
    }

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

/* Allocate memory for an array of unsigned chars. */
uint8_t *allocate_ustrmem(int len)
{
    void *tmp = NULL;

    if (len <= 0) {
        fprintf (stderr, "ERROR: Cannot allocate memory because len = %i in allocate_ustrmem().\n", len);
        exit (EXIT_FAILURE);
    }

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


Beginner's Guide to start web programming

EVERY DEVELOPER WHO WISHES TO EMBRACE NEW TECHNOLOGY, HAS ONE QUESTION TO BEING WITH...


FROM WHERE AND HOW DO I START FROM ??

THIS IS HOW I STARTED BUILDING MY PROFILE IN WEB-DEVELOPEMNT



############################################################################
# Software stacks for LAMP developers                                      #
# --> 'L'inux                                                              #
# --> 'A'pache                                                             #
# --> 'M'ySQL                                                              #
# --> 'P'HP                                                                #
############################################################################
The humble LAMP stack is popular for a reason. It combines several powerful
open-source software packages – a Linux OS, the Apache web server, the MySQL
database and the PHP scripting language – with each component complementing
the others to provide a full range of web development functionality.

But the LAMP stack isn’t the only option. In fact, it’s just the beginning.
With a whole host of variations on the LAMP stack, it’s possible to find a
web service stack that meets the exact needs of virtually any project.

Whether it’s substituting Apache for NGINX with LEMP, or choosing Windows
instead of Linux with WAMP, the LAMP stack model provides the ideal foundation
for many web applications. Then there are alternative takes on the web stack
concept, such as the MEAN stack and its variants. But with so much choice when
it comes to web software bundles, the right solution isn’t always obvious.

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@        What is a web stack?           @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Web stacks, AKA software stacks or solution stacks, are bundles of software
used in web development. A web stack includes several components, typically
an operating system, web server, database and scripting language. Taken as a
whole, the stack provides everything needed to build a complete platform –
i.e. nothing else is required to run a specific application.

The operating system – usually Windows or Linux-based – provides the main interface
between the server hardware and the other parts of the software stack.

The web server – often Apache or NGINX – stacks on top of the OS to serve client
requests (e.g. from web browsers) with the appropriate content. This content can
be static, like HTML files and images that appear the same way for every user, or
dynamic, such as interactive forms and anything that reacts to user input. While
static content can be served directly by the web server, dynamic content is only
possible with the help of databases and scripting.

The database – which might be MySQL or MariaDB, just to name a couple of options –
stores the data that the web server needs to access in order to serve dynamic content
to clients. The database also needs to work in tight coordination with a scripting
language to deliver advanced functionality.

And scripting languages like PHP, Python, Perl and JavaScript run either on the server
or client-side. This code allows complex processes to be automated and executed on the
fly, enabling dynamic content to be generated based on a huge range of variables.

Working together, these services form a platform for a wide variety of websites and
applications. Depending on the needs of the project, different stack configurations
can fulfil very different needs. For example, while the LAMP stack is great for PHP-based applications such as WordPress, more JavaScript-focused projects will need a stack
that includes specialised frameworks.

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@   The LAMP stack and beyond     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Developers love LAMP for its open-source accessibility, community support and
customisation. As such, the LAMP stack provides the basis for a number of variations.
Twists on the LAMP formula include:

LEMP – which swaps out Apache for NGINX (the E comes from the pronunciation of
“engine-X”, since LNMP doesn’t exactly roll off the tongue)

LLMP – replacing Apache with lighttpd
LAPP – switching MySQL for PostgreSQL

With so many Linux distributions out there, it’s no surprise that these LAMP variants
all begin with L. If you’re a Linux developer, you’re likely to find a LAMP-like stack
that supports your tools of choice, whether it’s a specific web server or a particular
database. And for other operating systems, there are yet more options.

############################################################################
# Software stacks for MEAN developers
#
# --> 'M'ongoDB – a NoSQL database
# --> 'E'xpress – a web application framework for Node.js
# --> 'A'ngularJS – a JavaScript-based web application framework
# --> 'N'ode.js – a runtime environment
############################################################################
An alternative to the traditional LAMP stack setup, a MEAN stack comprises:

MongoDB – a NoSQL database
Express – a web application framework for Node.js
AngularJS – a JavaScript-based web application framework
Node.js – a runtime environment

Obviously, this is not the classic LAMP stack structure. The MEAN model isn’t dependent
on a particular OS, and Node.js can provide the functionality of a web server. This
means that MEAN is a slimmed-down option compared to LAMP, and because a single language – JavaScript – runs at every level of the stack, MEAN offers significant performance
advantages for JavaScript-based applications.

#######################################################
#  Some variations on a MEAN software stack include:
#######################################################
MERN – using React instead of AngularJS
MEEN – replacing AngularJS with Ember.js


In a LAMP vs MEAN comparison, the deciding factor could well be the database:
MySQL vs MongoDB – or in other words, SQL vs NoSQL.
While SQL (relational) databases like MySQL and MariaDB are well-liked for their ability
to efficiently manage large data volumes in complex structures, NoSQL databases like
MongoDB are often preferred for their increased flexibility in smaller applications. 

Ultimately, your choice of web stack will probably boil down to a particular tool or
set of tools that you need to use. Frequently this is a particular scripting language
like PHP or JavaScript, but equally it could be a specific web server, database or
framework. With so many possible configurations, the final decision rests on the
details of your project and your skill set as a developer.




###########################################################################
#                          IDE for web-development:
###########################################################################

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    1. How to install Net Beans in ubuntu     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Netbeans is a full-featured cross-platform IDE that helps you build applications in
Java, PHP, and many other languages.

It has built-in debugging support, embedded Git control, integrates major build
automation tools such as Maven, Ant, and Gradle, syntax highlighting, code generators,
code templates, code refactoring, and rich navigation capabilities.

Netbeans is extensible via plugins and has well-documented APIs. It can also be used
for development in other programming languages such as C/C++, Groovy, Javadoc, JavaScript,
and more.

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@               Prerequisites                  @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
You’ll need to be logged in as a user with sudo access to be able to install packages
on your Ubuntu system.
Installing Java OpenJDK
Netbeans requires Java version 8 or above to be installed to your system.

We’ll install OpenJDK 8. The installation is pretty simple, start by updating the
package index:

--> sudo apt update
Install the OpenJDK 8 package by typing:

--> sudo apt install openjdk-8-jdk
Verify the installation by typing the following command which will print the
Java version:

--> java -version
The output should look something like this:

openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-2ubuntu0.18.04.1-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Installing Netbeans IDE
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
sudo snap install netbeans --classic

netbeans 10.0 from 'apache-netbeans' installed
That’s it. Netbeans IDE has been installed on your Ubuntu desktop.

Starting Netbeans IDE
Now that Netbeans is installed on your Ubuntu system you can start it typing netbeans in your terminal or by clicking on the Netbeans icon (Activities -> Netbeans):

Once the Netbeans IDE is loaded, you’ll be presented with the Start page:






Netlink Socket program (from User space process to Kernel Space process)

Netlink is a Linux kernel socket interface, which is used for inter-process communication between the user space and the kernel, and also between different user space processes. It reduces dependence on system calls, ioctls and proc files. Netlink also helps preserve kernel purity.
There are various ways by which processes in the user space can communicate with the kernel. These are system calls, ioctl and the proc file system. The problem with system calls is that they are linked statically to kernel code. So, any new feature that is to be provided has to be compiled with the kernel, but with dynamic linking modules such as device drivers, any feature that these modules want to provide cannot always be pre-configured as a system call. Similarly, for every new feature, it is hard to provide communication through the file system. All these communication mechanisms also require that the processes initiate the communication the kernel cannot initiate the communication.


Create 3 files in a folder:

1. Do 'make all'
2. If sudo password is asked, enter that.
3. Run, ./netlinkKernel.ko 
4. do 'dmesg' to view messages received from userspace process and sent to user space process.

Neelkanth $cat Makefile 

KDIR := /lib/modules/$(shell uname -r)/build

obj-m += netlinkKernel.o
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
gcc netlinkUser.c -o netlinkUser
sudo insmod netlinkKernel.ko
clean:
rm -rf *.o *.ko *.mod.* *.cmd .module* modules* Module* .*.cmd .tmp*
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
sudo rmmod netlinkKernel.ko

Neelkanth $cat netlinkKernel.c 

/*
 ************************************************************************** 
 *    Steps to create netlink socket in kernel driver. Read and Write     *
 *    messages to userspace process via netlink socket.                   *
 **************************************************************************
 * 1. In 'module_init', create a netlink socket using                     
 *    "netlink_kernel_create". The ouput of this function returns a 
 *    "netlink socket id".
 *
 * 2. Pass "init_net" structure to "netlink_kernel_create" as 1st 
 *    argument. A struct net contains information about the network 
 *    namespace, a set of network resources available to processes.
 *    Note that there could be multiple network namespaces (i.e. 
 *    multiple instances of the networking stack), but most drivers 
 *    use the init_net namespace. 
 *    File location: "net/core/net_namespace.c"
 *
 * 3. Pass "netlink_kernel_cfg" structure as 3rd argument to 
 *    "netlink_kernel_create". These are the optional kernel netlink 
 *    parameters. 
 *
 * 4. In structure "netlink_kernel_cfg" passed to "netlink_kernel_create"
 *    register a callback function to receive and send messages to 
 *    userspace process over netlink socket.    
 *    "hello_nl_recv_msg"
 *
 **************************************************************************     
 */

/*
 ********************************************************************
 * How to receive messages from userspace process to kernel driver  * 
 * module over netlink socket and reply back to user space process  *
 ********************************************************************
 * 1. "hello_nl_recv_msg" is the registered callback function 
 *    that would receive incoming messages over netlink socket 
 *    from userspace process and can repond back over the same 
 *    netlink socket.
 *
 * 2. The message received by "hello_nl_recv_msg" is via structure
 *    sk_buff. 
 *    [this is "socket buffer" File: "include/linux/skbuff.h"] 
 *
 *    "sk_buff is socket buffer organized in form of double linked
 *    list and has some of the below members."
 *    struct sk_buff {
 *       struct sk_buff * next;
 *       struct sk_buff * prev;
 *       struct sock * sk;
 *       struct skb_timeval tstamp;
 *       struct net_device * dev;
 *       struct net_device * input_dev;
 *    }
 * 
 * 3. 
 *   Netlink messages consist of a byte stream with one or multiple
 *   'nlmsghdr' headers and associated payload.
 *   Extact 'nlmsghdr' from sk_buff and print the incoming message
 *   from user space process.
 *
 * 4. 'nlmsg_new' and 'sk_buff' -- create a new message to be sent to 
 *    userspace process over netlink socket.
 *
 * 5. nlmsg_put --> nlmsg_data --> nlmsg_unicast   
 *
 ********************************************************************     
 */

#include <linux/module.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>


#define NETLINK_USER 31
struct sock *netlink_socket = NULL;

static void hello_nl_recv_msg(struct sk_buff *skb) {
    struct nlmsghdr *nlh;
    int pid;
    struct sk_buff *skb_out;
    int msg_size;
    char *msg="Hello..This is neelkanth from kernel driver module...";
    int res;

    printk(KERN_INFO "Entering: %s\n", __FUNCTION__);

    /* Read the message content from 'sk_buff' structure */
    /*
     * Message received from User space process via Net link socket 
     */
    nlh = (struct nlmsghdr*)skb->data;
    /*
     * Print the message received from the user space process over NL socket
     */
    printk(KERN_INFO "Netlink received msg payload(from userspace):%s\n",
           (char*)nlmsg_data(nlh));
    pid = nlh->nlmsg_pid; /*pid of sending process */
    printk("PID of userspace process from which message is received: %d\n", pid);


    /*
     * Message sent from Kernel driver to Userspace process over Netlink socket
     */
    msg_size=strlen(msg);
    /* Create new message using Netlink msg new API */
    skb_out = nlmsg_new(msg_size, 0);
    if (!skb_out) {
        printk(KERN_ERR "Failed to allocate new skb\n");
        return;
    }
    /* write the message content into 'sk_buff' structure */
    nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0); 
    NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
    strncpy(nlmsg_data(nlh), msg, msg_size);
    /* Send a Unicast message to userspace process over netlink socket */
    res = nlmsg_unicast(netlink_socket, skb_out, pid);
    if (res < 0) {
        printk(KERN_INFO "Error while sending bak to user\n");
    }
   
    return;
}

/*
 * When insmod of the kernel module is done, this function is invoked.
 */
static int __init hello_init(void)
{
    printk("Entering: %s\n",__FUNCTION__);
    /* 
     * This is for 3.6 kernels and above.
     */
    struct netlink_kernel_cfg cfg = {
        .input = hello_nl_recv_msg,
    };

    /* Create netlink socket in the kernel driver */
    netlink_socket = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
    if (!netlink_socket) {
        printk(KERN_ALERT "Error creating socket.\n");
        return -10;
    }

    return 0;
}

/*
 * When rmmod of kernel module is done, this function is invoked. 
 */
static void __exit hello_exit(void)
{
    printk(KERN_INFO "exiting hello module\n");
    netlink_kernel_release(netlink_socket);

    return;
}

/* insmod */
module_init(hello_init);
/* rmmod  */
module_exit(hello_exit);

MODULE_LICENSE("GPL");

Neelkanth $cat netlinkUser.c 

#include <sys/socket.h>
#include <linux/netlink.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>


#define NETLINK_USER 31

#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd = 0;
struct msghdr msg;

int main(void)
{
    memset(&src_addr, 0, sizeof(src_addr));
    memset(&dest_addr, 0, sizeof(dest_addr));

    printf("My process ID: %d\n", getpid());

    /* 
     * Create a netlink socket for communicating with kernel
     * driver module.
     */
    sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
    if (sock_fd < 0) {
        return -1;
    }

    /*
     * Set the parameters of netlink socket for sending unicast
     * message to linux kernel.  
     */
    src_addr.nl_family = AF_NETLINK;
    /* self pid */
    src_addr.nl_pid = getpid();   
    dest_addr.nl_family = AF_NETLINK;
    /* For Linux Kernel, PID will be 0 */
    dest_addr.nl_pid = 0;     
     /* 
      * For unicast message to Linux Kernel driver, 
      * set the below to 0 
      */
    dest_addr.nl_groups = 0; 

    /*  
     * Bind 'src addr' to netlink socket.  
     */
    bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));

    /*
     * Build netlink message Header from userspace process
     * to linux kernel driver Module. 
     */
    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
    memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
    nlh->nlmsg_pid = getpid();
    nlh->nlmsg_flags = 0;

    strcpy(NLMSG_DATA(nlh), "This is neelkanth from userspace");

    #if 0
    Build Final Message header.
     
    struct msghdr {
       void             __user *msg_name;    /* ptr to socket address structure */
       int              msg_namelen;         /* size of socket address structure */
       struct iovec     __user *msg_iov;     /* scatter/gather array */
       __kernel_size_t  msg_iovlen;          /* # elements in msg_iov */
       void             __user *msg_control; /* ancillary data */
       __kernel_size_t  msg_controllen;      /* ancillary data buffer length */
    unsigned int        msg_flags;           /* flags on received message */

    };

    #endif

    iov.iov_base = (void *)nlh;
    iov.iov_len = nlh->nlmsg_len;
    msg.msg_name = (void *)&dest_addr;
    msg.msg_namelen = sizeof(dest_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    /* Send Message to Kernel */
    printf("Sending message to kernel\n");
    sendmsg(sock_fd, &msg, 0);

    /* Read message from kernel */
    printf("Waiting for message from kernel\n");
    recvmsg(sock_fd, &msg, 0);
    printf("Received message payload: %s\n", (char *)NLMSG_DATA(nlh));
    close(sock_fd);

    return 0;
}

[Python]How to open multiple tabs in chrome using selenium webdriver

##################################################################################
#  Steps to install chrome webdriver in windows and start multiple tabs
#  from python script

#  1. Download chrome webdriver from "Google chrome" official site
#  2. copy the chrome webdriver to "C:\webdriver\chromedriver"
#  3. Add this to the windows C driver environment PATH, so that this is
#     recognized as an executable. 
#################################################################################

import selenium.webdriver as webdriver

websites = ["https://www.w3schools.com/php/default.asp",
            "https://www.w3schools.com/python/python_classes.asp",
            "https://www.w3schools.com/js/default.asp",
           ]


# Open the main window (1st window)
driver = webdriver.Chrome('C:\webdriver\chromedriver')
driver.get(websites[0])

# Switch to the new window
driver.execute_script("window.open('');")
driver.switch_to.window(driver.window_handles[1])
driver.get(websites[1])

# Switch to the new window
driver.execute_script("window.open('');")
driver.switch_to.window(driver.window_handles[2])
driver.get(websites[2])


# close the active tab
#driver.close()

How to parse ping (ICMP request) packets in python

#! /usr/local/bin/python3.5

import socket
import struct
import textwrap

TAB_1 = '\t - '
TAB_2 = '\t\t - '
TAB_3 = '\t\t\t - '
TAB_4 = '\t\t\t\t - '

DATA_TAB_1 = '\t   '
DATA_TAB_2 = '\t\t   '
DATA_TAB_3 = '\t\t\t   '
DATA_TAB_4 = '\t\t\t\t   '

def main():
    conn = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(3))
    while True:
        raw_data, addr = conn.recvfrom(65536)
        dest_mac, src_mac, eth_proto, data = ethernet_frame(raw_data)

        #######################################################################################
        # Print only ICMP ping packets
        #######################################################################################
        if eth_proto == 8:
            print('\n Ethernet Frame: ')
            print(TAB_1 + 'Destination: {}, Source: {}, Protocol: {}'.format(dest_mac, src_mac, eth_proto))
            (version, header_length, ttl, proto, src, target, data) = ipv4_Packet(data)
            print(TAB_1 + "IPV4 Packet:")
            print(TAB_2 + 'Version: {}, Header Length: {}, TTL: {}'.format(version, header_length, ttl))
            print(TAB_3 + 'protocol: {}, Source: {}, Target: {}'.format(proto, src, target))

            # ICMP
            if proto == 1:
                icmp_type, code, checksum, data = icmp_packet(data)
                print(TAB_1 + 'ICMP Packet:')
                print(TAB_2 + 'Type: {}, Code: {}, Checksum: {},'.format(icmp_type, code, checksum))
                print(TAB_2 + 'ICMP Data:')
                print(format_output_line(DATA_TAB_3, data))



# Unpack Ethernet Frame
def ethernet_frame(data):
    dest_mac, src_mac, proto = struct.unpack('! 6s 6s H', data[:14])
    return get_mac_addr(dest_mac), get_mac_addr(src_mac), socket.htons(proto), data[14:]

    # Format MAC Address
def get_mac_addr(bytes_addr):
    bytes_str = map('{:02x}'.format, bytes_addr)
    mac_addr = ':'.join(bytes_str).upper()
    return mac_addr

# Unpack IPv4 Packets Recieved
def ipv4_Packet(data):
    version_header_len = data[0]
    version = version_header_len >> 4
    header_len = (version_header_len & 15) * 4
    ttl, proto, src, target = struct.unpack('! 8x B B 2x 4s 4s', data[:20])
    return version, header_len, ttl, proto, ipv4(src), ipv4(target), data[header_len:]

# Returns Formatted IP Address
def ipv4(addr):
    return '.'.join(map(str, addr))


# Unpacks for any ICMP Packet
def icmp_packet(data):
    icmp_type, code, checksum = struct.unpack('! B B H', data[:4])
    return icmp_type, code, checksum, data[4:]

# Formats the output line
def format_output_line(prefix, string, size=80):
    size -= len(prefix)
    if isinstance(string, bytes):
        string = ''.join(r'\x{:02x}'.format(byte) for byte in string)
        if size % 2:
            size-= 1
            return '\n'.join([prefix + line for line in textwrap.wrap(string, size)])


main()