以太网数据包有尾部而不是 udp header via socket raw

Ethernet packet has trailer instead udp header via socket raw

我正在尝试使用具有特殊结构 sockaddr_ll 的 socket raw 发送 udp 数据包,但我得到的只是一个带尾部的以太网 header 和没有 udp 的 ip header header。我想发送一个没有预告片的普通 udp 数据包并收到我的消息。我使用 wireshark 检查了包裹。我怎样才能解决这个问题? 我的包裹:

我的代码:

int main(int argc, char *argv[])
{
    int sockfd;
    struct ifreq if_idx;
    struct ifreq if_mac;
  struct ifreq ifreq_ip;
    int tx_len = 0;
    unsigned char* sendbuf;
  sendbuf=(unsigned char*)malloc(64); 
    memset(sendbuf,0,64);

    struct ether_header *eh = (struct ether_header *) sendbuf;
    struct iphdr *iph = (struct iphdr *) (sendbuf + sizeof(struct ether_header));
  struct udphdr *uph = (struct udphdr *) (sendbuf + sizeof(struct ether_header) + sizeof(struct iphdr));
    struct sockaddr_ll socket_address;
    char ifName[IFNAMSIZ];
    
    /* Get interface name */
    if (argc > 1)
        strcpy(ifName, argv[1]);
    else
        strcpy(ifName, DEFAULT_IF);

    /* Open RAW socket to send on */
    if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
        perror("socket");
    }

    /* Get the index of the interface to send on */
    memset(&if_idx, 0, sizeof(struct ifreq));
    strncpy(if_idx.ifr_name, ifName, IFNAMSIZ-1);
    if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0)
        perror("SIOCGIFINDEX");
    /* Get the MAC address of the interface to send on */
    memset(&if_mac, 0, sizeof(struct ifreq));
    strncpy(if_mac.ifr_name, ifName, IFNAMSIZ-1);
    if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0)
        perror("SIOCGIFHWADDR");
  /* get ip */
  memset(&ifreq_ip,0,sizeof(ifreq_ip));
    strncpy(ifreq_ip.ifr_name,ifName,IFNAMSIZ-1);
  if(ioctl(sockfd,SIOCGIFADDR,&ifreq_ip)<0)
    {
        printf("error in SIOCGIFADDR \n");
    }



    /* Construct the Ethernet header */
    /* Ethernet header */
    eh->ether_shost[0] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0];
    eh->ether_shost[1] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1];
    eh->ether_shost[2] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2];
    eh->ether_shost[3] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3];
    eh->ether_shost[4] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4];
    eh->ether_shost[5] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5];
    eh->ether_dhost[0] = MY_DEST_MAC0;
    eh->ether_dhost[1] = MY_DEST_MAC1;
    eh->ether_dhost[2] = MY_DEST_MAC2;
    eh->ether_dhost[3] = MY_DEST_MAC3;
    eh->ether_dhost[4] = MY_DEST_MAC4;
    eh->ether_dhost[5] = MY_DEST_MAC5;
    /* Ethertype field */
    eh->ether_type = htons(ETH_P_IP);
    tx_len += sizeof(struct ether_header);

    /* ip header */
    iph->ihl = 5;
    iph->version = 4;
    iph->tos = 0;
    iph->tot_len = htons(sizeof (struct iphdr));
    iph->id = htonl (54321);    //Id of this packet
    iph->frag_off = 0;
    iph->ttl = 255;
    iph->protocol = IPPROTO_UDP;
    iph->check = 0;     
    iph->saddr = inet_addr(inet_ntoa((((struct sockaddr_in *)&(ifreq_ip.ifr_addr))->sin_addr)));    
    iph->daddr = inet_addr ( "127.0.0.1" );
    
    //Ip checksum
    iph->check = csum ((unsigned short *) sendbuf, iph->tot_len);
  tx_len += sizeof(struct iphdr);

  uph->source   = htons(80);
    uph->dest   = htons(43521);
    uph->check  = 0;

    tx_len+= sizeof(struct udphdr);
    sendbuf[tx_len++]   =   0xAA;
    sendbuf[tx_len++]   =   0xBB;
    sendbuf[tx_len++]   =   0xCC;
    sendbuf[tx_len++]   =   0xDD;
    sendbuf[tx_len++]   =   0xEE;
    uph->len        = htons((tx_len - sizeof(struct iphdr) - sizeof(struct ethhdr)));

    /* Index of the network device */
    socket_address.sll_ifindex = if_idx.ifr_ifindex;
    /* Address length*/
    socket_address.sll_halen = ETH_ALEN;
    /* Destination MAC */
    socket_address.sll_addr[0] = MY_DEST_MAC0;
    socket_address.sll_addr[1] = MY_DEST_MAC1;
    socket_address.sll_addr[2] = MY_DEST_MAC2;
    socket_address.sll_addr[3] = MY_DEST_MAC3;
    socket_address.sll_addr[4] = MY_DEST_MAC4;
    socket_address.sll_addr[5] = MY_DEST_MAC5;

    /* Send packet */
    if (sendto(sockfd, sendbuf, tx_len, 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0)
        printf("Send failed\n");

    return 0;
}

IP Total Length字段只有20个字节,刚好是IP的大小Header,所以对于IP来说,是没有payload的。您需要确保 IP 总长度字段设置为 IP 的大小 header 加上整个有效负载的大小。特别是,这一行是错误的:

iph->tot_len = htons(sizeof (struct iphdr));