c++ - 以太网数据包具有尾部而不是通过套接字原始的 udp 标头
问题描述
我正在尝试使用具有特殊结构 sockaddr_ll 的套接字 raw 发送 udp 数据包,但我只得到一个带有预告片的以太网标头和没有 udp 标头的 ip 标头。我想发送一个没有预告片的普通 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 而言,没有有效载荷。您需要确保将 IP 总长度字段设置为 IP 标头的大小加上整个有效负载的大小。特别是,这一行是错误的:
iph->tot_len = htons(sizeof (struct iphdr));
推荐阅读
- html - 在 div 中垂直间隔项目(flexbox space-around 不起作用..)
- python - 我正在尝试制作一个“自上而下”的基于瓷砖的游戏。我不知道如何最初制作瓷砖地图以放置图像
- unity3d - 客户端未收到来自套接字 js 服务器的消息
- php - 如何在前端显示“待审核帖子计数”
- css - 第一个元素内联块 CSS 选择器
- python - Python 的 splat 运算符……在某一时刻吗?
- google-apps-script - 根据单元格值/复选框添加空白行
- python - 从 BeautifulSoup 行中提取标签文本
- azure-devops - 如何始终将 Azure DevOps 发布任务中的“出错时继续”字段标记为 true?
- jmeter - 如何从 Jmeter 日志查看器获取数据并发送到另一个下一个请求