Getting Npcap IPv6 source and destination addresses

369 Views Asked by At

I'm trying to get the source and destination addresses for all packets using the npcap SDK (https://nmap.org/npcap/) in Windows. It works for IPv4, but it is returning the same address for the source and destination for IPv6 addresses. Here is the code for my packet_handler callback function:

void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data)
{
    u_int ip_len;
    u_short eth_type;
    const sniff_ip* iph;
    const in6_addr* orig_saddr6;
    const in6_addr* orig_daddr6;
    in6_addr swapped_saddr;
    in6_addr swapped_daddr;

    const struct sniff_ethernet* ethernet; /* The ethernet header */

    ip_len = header->len;
    ethernet = (struct sniff_ethernet*)(pkt_data);
    eth_type = ntohs(ethernet->ether_type);

    iph = (sniff_ip*)(pkt_data +
        14); //length of ethernet header

    if (eth_type == 0x0800) {
        char str_saddr[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &(iph->ip_src), str_saddr, INET_ADDRSTRLEN);

        char str_daddr[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &(iph->ip_dst), str_daddr, INET_ADDRSTRLEN);
        printf("%s %s\n", str_saddr, str_daddr);
    }
    else if (eth_type == 0x86DD)
    {
        char str_saddr[INET6_ADDRSTRLEN];
        orig_saddr6 = (const in6_addr*)&(iph->ip_src);
        ipv6_sbyteswap(orig_saddr6, &swapped_saddr);
        inet_ntop(AF_INET6, &swapped_saddr, str_saddr, INET6_ADDRSTRLEN);

        char str_daddr[INET6_ADDRSTRLEN];
        orig_daddr6 = (const in6_addr*)&(iph->ip_dst);
        ipv6_dbyteswap(orig_daddr6, &swapped_daddr);
        inet_ntop(AF_INET6, &swapped_daddr, str_daddr, INET6_ADDRSTRLEN);

        printf("%s %s\n", str_saddr, str_daddr);
    }
}

The problem I am seeing is that the saddr and daddr are the same IP address when the eth_type is for IPv6 packets (e.g. eth_type == 0x86DD), except the bytes are in a different order. I've doubled and tripled check the code, but when I check the iph->ip_src and iph->ip_dst I see the same types, so it looks like the npcap library is returning the same address. I don't see anything I can do to change the behavior. Has anyone ran into this?

2

There are 2 best solutions below

0
On

To resolve the problem, you have to cast the IP header using the appropriate IPv6 structure. Here is the working code:

/* IPv4 header */
typedef struct ip4_header {
    u_char  ver_ihl;        // Version (4 bits) + Internet header length (4 bits)
    u_char  tos;            // Type of service 
    u_short tlen;           // Total length 
    u_short identification; // Identification
    u_short flags_fo;       // Flags (3 bits) + Fragment offset (13 bits)
    u_char  ttl;            // Time to live
    u_char  proto;          // Protocol
    u_short crc;            // Header checksum
    ip_address  saddr;      // Source address
    ip_address  daddr;      // Destination address
    u_int   op_pad;         // Option + Padding
}ip4_header;

/* IPv6 header */
typedef struct ipv6_header
{
    unsigned int
        version : 4,
        traffic_class : 8,
        flow_label : 20;
    uint16_t length;
    uint8_t  next_header;
    uint8_t  hop_limit;
    struct in6_addr saddr;
    struct in6_addr daddr;
} ipv6_header;

/* Process IPv6 packets*/
void ipv6_handler(const u_char* pkt_data) {
    const ipv6_header* iph;

    iph = (ipv6_header*)(pkt_data + ETHERNET_HEADER_LEN);
    char str_saddr[INET6_ADDRSTRLEN];
    memset(str_saddr, 0, sizeof(str_saddr));
    inet_ntop(AF_INET6, &iph->saddr, str_saddr, INET6_ADDRSTRLEN);

    char str_daddr[INET6_ADDRSTRLEN];
    memset(str_daddr, 0, sizeof(str_saddr));
    inet_ntop(AF_INET6, &iph->daddr, str_daddr, INET6_ADDRSTRLEN);

    printf("%s %s\n", str_saddr, str_daddr);
}

void packet_handler2(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data)
{

    const struct sniff_ethernet* ethernet; /* The ethernet header */

    u_short eth_type;
    ethernet = (struct sniff_ethernet*)(pkt_data);
    eth_type = ntohs(ethernet->ether_type);

    if (eth_type == ETHERNET_TYPE_IPv4) {
        ipv4_handler(pkt_data);
    }
    else if (eth_type == ETHERNET_TYPE_IPv6)
    {
        ipv6_handler(pkt_data);
    }
}
0
On

Just remove the ipv6_sbyteswap function. Just follow the below code and it will work. It works in my case.

else if (eth_type == 0x86DD)
    {
        char str_saddr[INET6_ADDRSTRLEN];
        inet_ntop(AF_INET6, &(iph->ip_src), str_saddr, INET6_ADDRSTRLEN);
        char str_daddr[INET6_ADDRSTRLEN];
        inet_ntop(AF_INET6, &(iph->ip_dst), str_daddr, INET6_ADDRSTRLEN);
        printf("%s %s\n", str_saddr, str_daddr);
    }