ano*_*_16 5 c sockets networking packet-capture
我有一个带有两个物理接口的 linux 系统。我需要通过一个接口拦截(读取)传入的数据包,读取(或处理)数据并按原样通过另一个接口将其发送出去 - 就像中间人一样。我能够从数据包中提取所有标头字段和有效载荷数据,但我无法再次将其放回线路上。如何在通过另一个接口的途中发送数据包?
// All #includes
struct sockaddr_in source,dest;
int i,j,k;
int main()
{
int saddr_size , data_size;
struct sockaddr_in saddr;
unsigned char *buffer=malloc(65535);
int sock_raw = socket( AF_PACKET , SOCK_RAW , htons(ETH_P_ALL)) ;
if(sock_raw < 0)
perror("setsockopt");
setsockopt(sock_raw , SOL_SOCKET , SO_BINDTODEVICE , "eth0" , strlen("eth0")+ 1 );
if(sock_raw < 0)
{
perror("Socket Error");
return 1;
}
while(1)
{
saddr_size = sizeof (struct sockaddr);
//Receive a packet
data_size = recvfrom(sock_raw , buffer , 65536 , 0 ,(struct sockaddr *) &saddr , (socklen_t*)&saddr_size);
if(data_size <0 )
{
printf("Recvfrom error , failed to get packets\n");
return 1;
}
else{
printf("Received %d bytes\n",data_size);
//Huge code to process the packet
//Send it out through "eth1" here
}
}
close(sock_raw);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
假设只有 UDP 或 ICMP 数据包更容易解释(可能使用简单的“sendto”功能) - 我可以处理排序。不要担心预期的目的地,我只想将数据包放回线路上 - 交付并不重要。
编辑1:
如果我这样做,它会给我一个运行时错误,提示“无效参数”。我是否发送缓冲区甚至“Hello World”都没有关系。
bytes_sent=sendto(sock_raw, buffer, 65536, 0,(struct sockaddr *) &saddr ,saddr_size);
if (bytes_sent < 0) {
perror("sendto");
exit(1);
}
Run Code Online (Sandbox Code Playgroud)
编辑 2:让我简单点 - 我有两个管道 A 和 B。球从 A 滚入,我收到了它们。我只想把它们放在管道 B 中,然后将它们送去。以太网桥接器以类似的方式工作——只是通过所有涉及的接口发送所有数据包。如果我不必从数据包头中获取一些基本信息,我肯定会使用网桥。而且我不擅长修改内核桥驱动程序。
编辑 3:我会最后一次尝试一个不同的问题。如果我收到了一个完整的原始数据包,其中包含在标头中的源/目标地址以及所有内容,我如何使用 sendto 简单地将它发送到任何地方(我不在乎在哪里)?我应该在 sendto 调用中向“struct sockaddr”添加任何信息,还是可以简单地使用我在 recvfrom 调用中所做的相同的信息?
我终于让它工作了!我能够将 eth0 上收到的数据包发送到 eth1 不变。
更正:
我匆忙把它放在一起,所以那里可能会有一些多余的线。我不知道daddr是否是必需的,但它确实有效。这是完整的代码:
// All #includes
int main()
{
int saddr_size , data_size, daddr_size, bytes_sent;
struct sockaddr_ll saddr, daddr;
unsigned char *buffer=malloc(65535);
int sock_raw = socket( AF_PACKET , SOCK_RAW , htons(ETH_P_ALL)) ; //For receiving
int sock = socket( PF_PACKET , SOCK_RAW , IPPROTO_RAW) ; //For sending
memset(&saddr, 0, sizeof(struct sockaddr_ll));
saddr.sll_family = AF_PACKET;
saddr.sll_protocol = htons(ETH_P_ALL);
saddr.sll_ifindex = if_nametoindex("eth0");
if (bind(sock_raw, (struct sockaddr*) &saddr, sizeof(saddr)) < 0) {
perror("bind failed\n");
close(sock_raw);
}
memset(&daddr, 0, sizeof(struct sockaddr_ll));
daddr.sll_family = AF_PACKET;
daddr.sll_protocol = htons(ETH_P_ALL);
daddr.sll_ifindex = if_nametoindex("eth1");
if (bind(sock, (struct sockaddr*) &daddr, sizeof(daddr)) < 0) {
perror("bind failed\n");
close(sock);
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth1");
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
perror("bind to eth1");
}
while(1)
{
saddr_size = sizeof (struct sockaddr);
daddr_size = sizeof (struct sockaddr);
//Receive a packet
data_size = recvfrom(sock_raw , buffer , 65536 , 0 ,(struct sockaddr *) &saddr , (socklen_t*)&saddr_size);
if(data_size <0 )
{
printf("Recvfrom error , failed to get packets\n");
return 1;
}
else{
printf("Received %d bytes\n",data_size);
//Huge code to process the packet (optional)
//Send the same packet out
bytes_sent=write(sock,buffer,data_size);
printf("Sent %d bytes\n",bytes_sent);
if (bytes_sent < 0) {
perror("sendto");
exit(1);
}
}
}
close(sock_raw);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
感谢所有回复的人。
| 归档时间: |
|
| 查看次数: |
11564 次 |
| 最近记录: |