简体   繁体   中英

Linux - RAW socket - packet has bad tcp and ip checksum

i have a problem with raw socket packet.

Based on Vivek Ramachandran and Sukumar Nandi's idea( https://www.researchgate.net/publication/221160823_Detecting_ARP_Spoofing_An_Active_Technique ) i'm trying to create a TCP SYN packet to check if the host that send the ARP response is real and the ARP was not spoofed.

I worte this code in C to send a TCP SYN packet when an ARP reply is recived but, unfortunately, on wireshark the TCP and IP checksum is not valid.

I tryed to figure out why the checksum was not valid without success, this is the code (please don't judge me...it's my first program):

#include <stdio.h>
#include <errno.h>
#include <pcap.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <net/ethernet.h>
#include <stdlib.h>
#include <linux/if_packet.h>
#define ARP_REPLY 2


struct pseudoPack {
  uint32_t srcAddr;
  uint32_t dstAddr;
  uint8_t zero;
  uint8_t protocol;
  uint16_t TCP_len;
};

struct arp_header { 
    u_int16_t htype;    /* Hardware Type           */ 
    u_int16_t ptype;    /* Protocol Type           */ 
    u_char hlen;        /* Hardware Address Length */ 
    u_char plen;        /* Protocol Address Length */ 
    u_int16_t oper;     /* Operation Code          */ 
    u_char sha[6];      /* Sender hardware address */ 
    u_char spa[4];      /* Sender IP address       */ 
    u_char tha[6];      /* Target hardware address */ 
    u_char tpa[4];      /* Target IP address       */ 
}; 
struct ether_header *eth_h;
struct arp_header *arp_h;
struct sockaddr_in sa;


unsigned short arp_checksum(unsigned short *ptr,int nbytes) {

    long sum;
    unsigned short oddbyte;
    short answer;

    sum=0;
    while(nbytes>1) {
        sum+=*ptr++;
        nbytes-=2;
    }
    if(nbytes==1) {
        oddbyte=0;
        *((u_char*)&oddbyte)=*(u_char*)ptr;
        sum+=oddbyte;
    }

    sum = (sum>>16)+(sum & 0xffff);
    sum = sum + (sum>>16);
    answer=(short)~sum;

    return(answer);
}


void packet_analyzer(u_char *args , const struct pcap_pkthdr *header, const u_char *packet){

    char *dev = (char *)args;
    struct ifreq ifreq_i;
    struct ifreq ifreq_c;
    struct ifreq ifreq_ip;
    struct sockaddr_ll sadr_ll;
    struct pseudoPack PP;
    char *pseudo_packet;
    char sendbuff[1024];
    uint32_t SeqNum = 1138083240;                                                    //!TO CHANGE TO RANDOM!
    char *data;
    int raw_sock, i, total_len = 0, sPort = 8080, dPort = 8081;                          //!TO CHANGE TO RANDOM!
    eth_h = (struct ethernet_header *) packet;
    arp_h = (struct arp_header *)(packet+14);


    printf("\nPakcet recived");


    if(ntohs(eth_h->ether_type) == ETHERTYPE_ARP && ntohs(arp_h->oper) == ARP_REPLY && ntohs(arp_h->ptype) == 0x0800){


        printf("\n\nARP RECIVED!");


            if((raw_sock = socket(AF_PACKET, SOCK_RAW, IPPROTO_TCP)) == -1) {
                perror("\nERROR CREATING SOCKET FOR ARP CHECK");
                return;
            }
            memset(&ifreq_i,0,sizeof(ifreq_i));                                      
            strncpy(ifreq_i.ifr_name,dev,IFNAMSIZ-1);
            if((ioctl(raw_sock,SIOCGIFINDEX,&ifreq_i))<0){
                perror("ERROR READING INDEX OF DEVICE: ");
                return;
            }
            memset(&ifreq_c,0,sizeof(ifreq_c));
            strncpy(ifreq_c.ifr_name,dev,IFNAMSIZ-1);
            if((ioctl(raw_sock,SIOCGIFHWADDR,&ifreq_c))<0){
                perror("ERROR GETTING MAC OF DEVICE");
            return;
            }
            memset(&ifreq_ip,0,sizeof(ifreq_ip));
            strncpy(ifreq_ip.ifr_name,dev,IFNAMSIZ-1);
            if(ioctl(raw_sock,SIOCGIFADDR,&ifreq_ip)<0){
                perror("ERROR GETTING IP OF DEVICE");
            return;
            }
            memset(sendbuff,0,sizeof(sendbuff));


        sa.sin_family = AF_INET;
        sa.sin_port = htons(dPort);
        sa.sin_addr.s_addr = inet_addr("192.168.1.67");


        struct ethhdr *eth = (struct ethhdr *)(sendbuff);
            struct iphdr *iph = (struct iphdr*)(sendbuff + sizeof(struct ethhdr));
        struct tcphdr *tcph = (struct tcph *)(sendbuff + sizeof(struct iphdr) + sizeof(struct ethhdr));
        data = (char *) (sendbuff + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct tcphdr));


            eth->h_source[0] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[0]);
            eth->h_source[1] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[1]);
            eth->h_source[2] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[2]);
            eth->h_source[3] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[3]);
            eth->h_source[4] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[4]);
            eth->h_source[5] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[5]);


        for(i=0;i<5;i++){
            eth->h_dest[i] = eth_h->ether_shost[i];
        }
            eth->h_proto = htons(ETH_P_IP);
        total_len =+ sizeof(struct ethhdr);


            iph->ihl = 5;
            iph->version = 4;
            iph->tos = 16;
        //iph->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr)) /**+ strlen(data)**/;
            iph->id = htons(10201);
            iph->ttl = 64;
            iph->protocol = 6;
            iph->saddr = inet_addr(inet_ntoa((((struct sockaddr_in *)&(ifreq_ip.ifr_addr))->sin_addr)));
            iph->daddr = inet_addr("192.168.1.254");
            total_len =+ sizeof(struct iphdr);


            tcph->source = htons(sPort);                                                    
            tcph->dest = htons(dPort);
            tcph->seq = htonl(SeqNum++);
            tcph->ack_seq = 0x0;
            tcph->doff = 5;
            tcph->res1 = 0;
            tcph->urg = 0;
            tcph->ack = 0;
            tcph->psh = 0;
            tcph->rst = 0;
            tcph->syn = 1;
            tcph->fin = 0;
            tcph->window = htons(155);
            tcph->check = 0;
            tcph->urg_ptr = 0;


        //iph->tot_len = htons(total_len - sizeof(struct ethhdr));                          


        PP.srcAddr = inet_addr(inet_ntoa((((struct sockaddr_in *)&(ifreq_ip.ifr_addr))->sin_addr)));
        PP.dstAddr = inet_addr("192.168.1.254");
        PP.zero = 0;
        PP.protocol = 6;
        PP.TCP_len = sizeof(struct tcphdr);//htons(sizeof(struct tcphdr) + strlen(data));


        pseudo_packet = (char *) malloc((int) (sizeof(struct pseudoPack) + sizeof(struct tcphdr) + strlen(data)));
        memset(pseudo_packet, 0, sizeof(struct pseudoPack) + sizeof(struct tcphdr) + strlen(data));
        memcpy(pseudo_packet, (char *) &PP, sizeof(struct pseudoPack));
        memcpy(pseudo_packet + sizeof(struct pseudoPack), tcph, sizeof(struct tcphdr) + strlen(data));


        tcph->check = arp_checksum((unsigned short *) sendbuff,sizeof(struct tcphdr));
        iph->check = arp_checksum((unsigned short *) sendbuff, sizeof(struct iphdr) + sizeof(struct tcphdr))/**iph->tot_len**/;


        sadr_ll.sll_ifindex = ifreq_i.ifr_ifindex;
        sadr_ll.sll_halen = ETH_ALEN;
        for(i=0;i<5;i++){
            sadr_ll.sll_addr[i] = eth_h->ether_shost[i];
        }

        int arp_sendpack = sendto(raw_sock,sendbuff,1024,0,(const struct sockaddr*)&sadr_ll,sizeof(struct sockaddr_ll));
        if(arp_sendpack>0){
            printf("\nSended...");
            return;
        }
        else{
            perror("\nError sending packet: ");
            return;
        }

        close(raw_sock);
    }

}


int main(int argc,char* argv[]){

    int sock, i = 0;
    char *dev, errbuf[PCAP_ERRBUF_SIZE], filter_exp[24] = "dst host ";
    pcap_t *handle;
    struct ifreq ifr;
    struct pcap_pkthdr header;
    struct bpf_program fp;
    bpf_u_int32 mask;
    bpf_u_int32 net;
    const u_char *packet;

    if(argc>2){         
        printf("\nToo many arguments.\nUSAGE: ViEmme [interface]\n");
        return(1);
    }
    else if(argc==2){
        dev = argv[1];
        printf("\nStarting with device %s\n", dev);
    }
    else{
        dev = pcap_lookupdev(errbuf);
        if(dev==NULL){
            perror("\nCouldn't find default device: \n");
            return(1);
        }
        printf("\nDefault device %s selected...\n", dev);
    }                                                                     



    sock = socket(AF_INET, SOCK_DGRAM, 0);
    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name, dev, IFNAMSIZ-1);
    ioctl(sock, SIOCGIFADDR, &ifr);
    close(sock);


    strcat(filter_exp, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
    if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
        fprintf(stderr, "Can't get netmask for device %s\n", dev);
        net = 0;
        mask = 0;
     }                                                                     


    handle = pcap_open_live(dev, BUFSIZ, 0, 1000, errbuf);             
    if(handle==NULL){
        perror("\nCouldn't open selected device: \n");
        return(1);
    }
    if(pcap_compile(handle, &fp, filter_exp, 0, net) == -1){
        perror("\nCouldn't parse filter: \n");
        return(1);
    }
    if(pcap_setfilter(handle, &fp) == -1){
        perror("\nCouldn't set filters: \n");
        return(1);
    }                                                      


    printf("\nStart sniffing...\n");
    pcap_loop(handle, 0, packet_analyzer, (u_char *)dev);               

    printf("\n\nStopping\n\n");
    pcap_close(handle);
    return(0);

}

Here is a screenshot of the checksum error:

screenshot

You are passing the entire frame/packet to the arp_checksum function. Look at the two lines where you call arp_checksum . The first argument should not be send buffer , but the offset of the relevant header in the send buffer, since otherwise you would be including the ethernet header in the calculation. You should probably use iph and tcph (respectively) there instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM