【发布时间】:2015-01-10 13:44:07
【问题描述】:
我有一个带有两个物理接口的 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;
}
假设只有 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);
}
编辑 2 : 让我让它更简单- 我有两个管道 A 和 B。球从 A 滚进来,我收到它们。我只是想把它们放在管道 B 中,然后将它们发送出去。 以太网网桥以类似的方式工作 - 只是通过所有相关接口发送所有数据包。如果我不必从数据包头中获取一些基本信息,我肯定会使用网桥。而且我不擅长修改内核桥驱动。
编辑 3 : 我会最后一次尝试一个不同的问题。如果我收到了一个完整的原始数据包,其中包含标头和所有源/目标地址,我如何简单地使用 sendto 将其发送到任何地方(我不在乎在哪里)?我应该在 sendto 调用中向“struct sockaddr”添加任何信息,还是可以简单地使用我在 recvfrom 调用中所做的相同信息?
【问题讨论】:
-
I only want to put the packets back on the wire - delivery is not important...... 这是什么意思,顺便说一句? -
我只是想将数据包发送出去,我不在乎它们是否到达目的地。使用wireshark我可以检查它们是否已经发送出去。
-
如果您能够通过原始接口处理接收到的数据,请将数据放入单独的缓冲区,然后将缓冲区
sendto()发送到另一个目标地址。 [假设两个 i/fs 在 diff n/w..]. -
为什么就像一个中间人发送需要在
raw套接字上?需要相同的目的地地址[从您的问题中不清楚]? -
即使我使用从 IP 标头中提取的目标地址打开一个新套接字,我仍然会收到“无效参数”错误。它不必是原始套接字 - 您可以建议任何看起来正确的更改。
标签: c sockets networking packet-capture