我编写了一个简单的原始套接字,它应该接收使用 libnet 编写和组装的单个 ipv4 数据包。这是 libnet 数据包的代码,它工作得很好(我认为,没有办法检查发送的实际有效负载):
int main() {
uint32_t src, dst, seq, ack;
char payload1[1024], destip[16];
uint16_t sp = 2001, dp = 2000;
libnet_ptag_t tcp;
libnet_ptag_t ip4;
char errbuf[LIBNET_ERRBUF_SIZE];
int i, bytes;
int len;
libnet_t * l;
l = libnet_init(LIBNET_RAW4, NULL, errbuf);
//here follows the usual declaration of addresses and the payload using scanf
//and the command terminal (scanf("%s", payload);)
tcp = libnet_build_tcp(sp, dp, seq, ack, TH_SYN, 0, 0, 0, LIBNET_TCP_H +
strlen(payload), NULL, 0, l, 0);
ip4 = libnet_build_ipv4(LIBNET_TCP_H + LIBNET_IPV4_H + strlen(payload), 0, 1,
0, 64, IPPROTO_TCP, 0, src, dst, payload, strlen(payload), l, 0);
bytes = libnet_write(l);
return 0;
}
该程序有效,因为使用 tcpdump 时数据包出现在网络中。现在原始套接字的程序:
int main() {
struct sockaddr_in server_addr;
char message[2000];
int sockfd, bytes;
//server_addr is filled out for the listen() call...
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if(bind(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1)
{
printf("error binding\n");
perror("bind()");
exit(0);
}
while(1) {
bytes = recv(sockfd, message, 2000, 0);
if(bytes == -1)
continue;
printf("captured %d bytes\n%s\n", bytes, message);
printf("as hex: %x\n", message); //I tried that to find
//out, if there was any
//kind of received message
//because at first, the
//socket didn't receive
//anything, except that it
//assured me the receiving
//of ... bytes (, so I
//wanted to print out the
//raw bytes.)
memset(message, 0, 2000);
}
}
现在,套接字设法接收字节,因为打印出的字节值显示了一个数字,也是第一个程序作为数据包大小给出的确切数字(原始 ipv4 标头 + 有效负载 = 40 字节 + 有效负载大小)。只有收到的消息本身似乎存在某种错误,因为无论我在数据包中发送什么,消息的 %s 输出始终是“E”。十六进制输出因数据包而异,但它不会匹配我给定有效负载的十六进制版本(当我以十六进制从数据包程序中打印出有效负载时),而且它肯定没有任何相关值。现在我还想,也许 ipv4 标头也作为消息接收,所以我写了一个版本,它只读取消息缓冲区的 40+ 字节,但结果(“E”和随机十六进制)是相同的。
我究竟做错了什么?可能是错误的recv函数吗?或者我需要对我的消息缓冲区进行一点类型转换吗?或者它甚至可能是我的数据包发送程序中的错误?