отправка данных в виде пакетов ICMP из необработанного сокета в Linux (C) - PullRequest
0 голосов
/ 19 января 2019

Я пытаюсь написать код (для лаборатории), который отправляет данные в пакетах 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
msg 0 контрольная сумма написана: 65300 отправлено 69 байт Сообщение контрольной суммы сообщения 1: 64325 Отправлено 69 байт
msg 2 контрольная сумма написана: 28063 отправлено 69 байт отправка данных-сообщения 3 не удалась

2

отправка данных на 127.0.0.1
msg 0 контрольная сумма написана: 57116 отправлено 69 байт Сообщение контрольной суммы сообщения 1: 56141 Отправлено 69 байт
msg 2 контрольная сумма написана: 19879 отправлено 69 байт отправка данных-сообщения 3 не удалась \ n

ТАК, так как я проверяю программу несколько раз, контрольные суммы 3 пакетов всегда меняются. Хотя перед записью в пакет я очищаю весь буфер сообщений Последний пакет всегда терпит неудачу.

Я также закодировал приемник, который получает отправленные посылки. Я всегда проверяю их на одном компьютере, используя необработанные сокеты, привязываемые к интерфейсу обратной связи "lo"

Я сижу на этом маленьком кусочке уже две недели, и он сводит меня с ума. Некоторые советы будут оценены: D

...