Linux - RAW 套接字 - 数据包有错误的 tcp 和 ip 校验和

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

原始套接字数据包有问题。

基于 Vivek Ramachandran 和 Sukumar Nandi 的 想法(https://www.researchgate.net/publication/221160823_Detecting_ARP_Spoofing_An_Active_Technique)我正在尝试创建一个 TCP SYN 数据包来检查发送 ARP 响应的主机是否是真实的并且 ARP 没有被欺骗。

我在 C 中编写了这段代码,以便在收到 ARP 回复时发送 TCP SYN 数据包,但不幸的是,在 wireshark 上,TCP 和 IP 校验和无效。

我试图弄清楚为什么校验和无效但没有成功,这是代码(请不要评判我......这是我的第一个程序):

#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);

}

这里是校验和错误的截图:

screenshot

您正在将整个 frame/packet 传递给 arp_checksum 函数。看你调用arp_checksum的那两行。第一个参数不应是 send buffer,而是发送缓冲区中相关 header 的偏移量,否则您将在计算中包括以太网 header。您可能应该在那里使用 iphtcph(分别)。