2010-04-12 4 views
0

DHCP RENEW 패킷을 네트워크로 보내고 응답을 수신하려고합니다. 패킷을 브로드 캐스트하고 Wireshark를 사용하여 성공적으로 전송되었음을 알 수 있습니다. 하지만 응답을받는 데 어려움이 있습니다. 패킷을 잡으려고 패킷 소켓을 사용합니다. 나는 Wireshark를 사용하여 나의 RENEW 패킷에 대한 응답이 있음을 볼 수 있지만, 'packet_receive_renew'함수는 때때로 패킷을 잡아 내지 만 때때로 패킷을 잡을 수 없다. FDSET를 사용하여 파일 디스크립터를 설정했지만 코드에서 'select'는 해당 파일 디스크립터에 대한 새로운 패킷이 있다는 것을 인식하지 못하고 타임 아웃이 발생합니다. 나는 왜 그것이 때때로 패킷을 잡는 지, 때로는 그렇지 않다는 것을 분명히 할 수 없었다. 누구나 아이디어가 있으십니까? 미리 감사드립니다. 패킷 소켓을 사용하여 브로드 캐스트 패킷 수신

다음은 수신 기능입니다.

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; 
} 

답변

0

나는이 문제를 해결했다. 타이밍 문제라고 생각합니다. 메시지를 보내기 전에 수신 대기 소켓을 열어 바인딩합니다. 따라서 문제없이 메시지를 잡을 수 있습니다. 감사합니다. .