从Linux中的原始套接字以ICMP数据包的形式发送数据(C)

时间:2019-01-19 18:12:39

标签: linux sockets icmp sendto

我正在尝试编写一个代码(用于实验室),该代码以ICMP数据包(类型ICMP_ECHO)发送数据

这是我的发送功能:

int send_data(int sid, struct in_addr to, FILE*fp, int fraglen){
    long flength;
    struct icmp icmph;
    struct sockaddr_in sa;
    struct stat buf;
    uint8_t *msg;
    long i, max;
    int snd,c,j,is_EOF = FALSE;
    uint16_t csum;
    memset(&icmph,0,sizeof(icmph));
    memset(&sa,0,sizeof(sa));
    sa.sin_family = AF_INET;
    sa.sin_addr = to;
    if(fp == NULL){
        perror("send_data : file pointer is NULL \n");
        return FALSE;
    }
    if((msg = malloc((ICMP_HDRLEN+fraglen)*sizeof(uint8_t)))==NULL){
        perror("send_data : failed to allocate memory \n");
        return FALSE;
    }
    if(init_icmphdr(&icmph, ICMP_ECHO,0,0,0)==FALSE){
        free(msg);
        perror("send_data : failed to initialize icmp header \n");
        return FALSE;
    }

    fstat(fileno(fp),&buf);
    flength = buf.st_size;
    uint8_t *data = msg+sizeof(uint8_t)*ICMP_HDRLEN;
    max = (flength % fraglen == 0 ? flength/fraglen : flength/fraglen+1);
    printf("sending data to %s \n",inet_ntoa(sa.sin_addr));
    for(i = 0; i<max;i++){
        memset(msg,0,ICMP_HDRLEN+fraglen);
        if(init_icmphdr(&icmph,ICMP_ECHO,0,1,i)==FALSE){
            perror("send_to : icmp header init failed \n");
            return FALSE;
        }
        memcpy(msg,&icmph, ICMP_HDRLEN);
        for(j=0;j<fraglen && is_EOF == FALSE;j++){
            c = getc(fp);
            if(c == EOF) 
                is_EOF = TRUE;  
            else
                *(data+sizeof(uint8_t)*j) = c;
        }
        csum=ip_checksum(msg,ICMP_HDRLEN+fraglen); //Checksum and write it to package
        memcpy(&icmph,msg,ICMP_HDRLEN);
        icmph.icmp_cksum = csum;
        memcpy(msg,&icmph,ICMP_HDRLEN);

        printf("msg %lu checksum written :%" PRIu16 "\n", i,csum);

        if((snd=sendto(sid,msg,ICMP_HDRLEN+fraglen,0,(struct sockaddr*)&sa,sizeof(sa)))<0){
            printf("sending of data-msg %lu failed \n",i);
            return FALSE;
        }
        printf("Sent %i Bytes \n", snd);
    }

    //Send final message

    memset(&icmph,0,ICMP_HDRLEN);
    memset(msg,0,ICMP_HDRLEN+fraglen);
    init_icmphdr(&icmph,ICMP_ECHO,0,2,0); //ID 0 <=> stop transmission
    memcpy(msg,&icmph,ICMP_HDRLEN);
    csum = ip_checksum(msg,ICMP_HDRLEN+fraglen);
    icmph.icmp_cksum = csum;
    memcpy(msg,&icmph,ICMP_HDRLEN);

    if((snd=sendto(sid,msg,ICMP_HDRLEN+fraglen,0,(struct sockaddr*)&sa,sizeof(sa)))<0){
        printf("sending of data-msg %lu failed \n",i);
        return FALSE;
    }

    free(msg); 
    return TRUE;
}


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


    struct in_addr dst;
    FILE *fp;
    int sid;
    struct ifreq ifr;
    if(argc < 4){
        printf("To few args? \n");
        return 1;
    }

    if((fp = fopen(argv[2],"r")) == NULL ){
        printf("opening file failed \n");
        return 1;
    }

    if((sid = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) < 0){
        printf("opening socket failed \n");
        return 1;
    }
    printf("CLIENT SOCKET ID: %i \n", sid);

    memset(&ifr,0,sizeof(ifr));
        snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
        if (ioctl (sid, SIOCGIFINDEX, &ifr) < 0) {  //Interface index
                perror ("ioctl() failed to find interface ");
                return (EXIT_FAILURE);
        }
    if (setsockopt (sid, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof (ifr)) < 0) { 
                perror ("setsockopt() failed to bind to interface "); //Bind to interface
                return (EXIT_FAILURE);
        }
    if(inet_aton(argv[1],&dst)==0){
        perror("invalid IP \n");
        return (EXIT_FAILURE);  
    }
    if(send_shake(sid,dst) != TRUE){
        perror("send_shake failed \n");
        return(EXIT_FAILURE);
    }
    printf("Sent shake \n");
    if(recv_shake(sid,dst)==TRUE){
        printf("shake made, sending data.. \n");
        send_data(sid,dst,fp,atoi(argv[3]));    
    }   
    fclose(fp);
    close(sid);

    return 0;
}

我一直在尝试发送仅包含“ Hello!Hello!”的文本文件。在里面。 从我的角度来看,我有一些奇怪的错误。

以下是此函数的两次运行的输出:

1。

  

将数据发送到127.0.0.1
  写入的味精0校验和:65300已发送69字节   写入的味精1校验和:64325已发送69字节
  写入的味精2校验和:28063已发送69字节   发送数据消息3失败

2。

  

将数据发送到127.0.0.1
  写入的味精0校验和:57116已发送69字节   写入的味精1校验和:56141已发送69字节
  写入的味精2校验和:19879发送69字节   发送数据消息3失败\ n

所以,由于我要多次检查程序,所以3个程序包的校验和总是会变化。虽然在写包之前我清除了整个消息缓冲区 最后一次打包总是失败。

我还编码了一个接收已发送包裹的接收者。我总是在一台计算机上测试它们,使用原始套接字绑定到环回接口“ lo”

两个星期以来,我一直坐在这个小地方,这让我发疯。一些建议,将不胜感激:D

0 个答案:

没有答案