2010-04-12 2 views
0

J'essaie d'envoyer des paquets DHCP RENEW au réseau et de recevoir les réponses. J'ai diffusé le paquet et je peux voir qu'il est envoyé avec succès en utilisant Wireshark. Mais j'ai des difficultés à recevoir les réponses. J'utilise des sockets packet pour attraper les paquets. Je peux voir qu'il y a des réponses à mon paquet RENEW en utilisant Wireshark, mais ma fonction 'packet_receive_renew' attrape parfois les paquets mais parfois il ne peut pas attraper les paquets. Je définis le descripteur de fichier en utilisant FDSET mais le 'select' dans mon code ne peut pas réaliser qu'il y a de nouveaux paquets pour ce descripteur de fichier et que le délai d'expiration se produit. Je ne pouvais pas préciser pourquoi il attrape parfois les paquets et parfois non. Quelqu'un a une idée? Merci d'avance.Réception de paquets de diffusion à l'aide d'une socket de paquets

Voici la fonction de réception.

int packet_receive_renew(struct client_info* info) 
{ 
    int fd; 
    struct sockaddr_ll sock, si_other; 
    struct sockaddr_in si_me; 
    fd_set rfds; 
    struct timeval tv; 
    time_t start, end; 
    int bcast = 1; 

    int ret = 0, try = 0; 
    char buf[1500] = {'\0'}; 
    uint8_t tmp[BUFLEN] = {'\0'}; 
    struct dhcp_packet pkt; 
    socklen_t slen = sizeof(si_other); 
    struct dhcps* new_dhcps; 

    memset((char *) &si_me, 0, sizeof(si_me)); 
    memset((char *) &si_other, 0, sizeof(si_other)); 
    memset(&pkt, 0, sizeof(struct dhcp_packet)); 

#define SERVER_AND_CLIENT_PORTS ((67 << 16) + 68) 

    static const struct sock_filter filter_instr[] = { 
     /* check for udp */ 
     BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9), 
     BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 4),  /* L5, L1, is UDP? */ 
     /* skip IP header */ 
     BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),      /* L5: */ 
     /* check udp source and destination ports */ 
     BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0), 
     BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1), /* L3, L4 */ 
     /* returns */ 
     BPF_STMT(BPF_RET|BPF_K, 0x0fffffff),     /* L3: pass */ 
     BPF_STMT(BPF_RET|BPF_K, 0),        /* L4: reject */ 
    }; 

    static const struct sock_fprog filter_prog = { 
     .len = sizeof(filter_instr)/sizeof(filter_instr[0]), 
     /* casting const away: */ 
     .filter = (struct sock_filter *) filter_instr, 
    }; 

    printf("opening raw socket on ifindex %d\n", info->interf.if_index); 

    if (-1==(fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)))) 
    { 
     perror("packet_receive_renew::socket"); 
     return -1; 
    } 

    printf("got raw socket fd %d\n", fd); 

    /* Use only if standard ports are in use */ 
    /* Ignoring error (kernel may lack support for this) */ 
    if (-1==setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog))) 
     perror("packet_receive_renew::setsockopt"); 

    sock.sll_family = AF_PACKET; 
    sock.sll_protocol = htons(ETH_P_IP); 
    //sock.sll_pkttype = PACKET_BROADCAST; 
    sock.sll_ifindex = info->interf.if_index; 
    if (-1 == bind(fd, (struct sockaddr *) &sock, sizeof(sock))) { 
     perror("packet_receive_renew::bind"); 
     close(fd); 
     return -3; 
    } 

    if (-1 == setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast))) { 
     perror("packet_receive_renew::setsockopt"); 
     close(fd); 
     return -1; 
    } 

    FD_ZERO(&rfds); 
    FD_SET(fd, &rfds); 
    tv.tv_sec = TIMEOUT; 
    tv.tv_usec = 0; 
    ret = time(&start); 
    if (-1 == ret) { 
     perror("packet_receive_renew::time"); 
     close(fd); 
     return -1; 
    } 

    while(1) { 
     ret = select(fd + 1, &rfds, NULL, NULL, &tv); 
     time(&end); 
     if (TOTAL_PENDING <= (end - start)) { 
      fprintf(stderr, "End receiving\n"); 
      break; 
     } 
     if (-1 == ret) 
     { 
      perror("packet_receive_renew::select"); 
      close(fd); 
      return -4; 
     } 
     else if (ret) { 
      new_dhcps = (struct dhcps*)calloc(1, sizeof(struct dhcps)); 
      if (-1 == recvfrom(fd, buf, 1500, 0, (struct sockaddr*)&si_other, &slen)) { 
       perror("packet_receive_renew::recvfrom"); 
       close(fd); 
       return -4; 
      } 
      deref_packet((unsigned char*)buf, &pkt, info); 
      if (-1!=(ret=get_option_val(pkt.options, DHO_DHCP_SERVER_IDENTIFIER, tmp))) { 
       sprintf((char*)tmp, "%d.%d.%d.%d", tmp[0],tmp[1],tmp[2],tmp[3]); 
       fprintf(stderr, "Received renew from %s\n", tmp); 
      } 
      else 
      { 
       fprintf(stderr, "Couldnt get DHO_DHCP_SERVER_IDENTIFIER%s\n", tmp); 
       close(fd); 
       return -5; 
      } 
      new_dhcps->dhcps_addr = strdup((char*)tmp); 

      //add to list 
      if (info->dhcps_list) 
       info->dhcps_list->next = new_dhcps; 
      else 
       info->dhcps_list = new_dhcps; 
      new_dhcps->next = NULL; 
     } 
     else { 
      try++; 
      tv.tv_sec = TOTAL_PENDING - try * TIMEOUT; 
      tv.tv_usec = 0; 
      fprintf(stderr, "Timeout occured\n"); 
     } 
    } 
    close(fd); 
    printf("close fd:%d\n", fd); 
    return 0; 
} 

Répondre

0

J'ai résolu le problème. Je pense que c'était un problème de synchronisation. J'ai ouvert la prise d'écoute et la lier avant d'envoyer le message. Ainsi, il peut attraper le message sans problème. Merci.

Questions connexes