linux raw socket编程问题

时间:2009-10-22 09:18:48

标签: linux sockets

我正在尝试创建一个原始套接字,它在linux下使用ip / tcp头发送和接收消息。 我可以成功绑定到端口并接收tcp消息(即:syn) 但是,消息似乎是由操作系统处理的,但不是我的。我只是它的读者(像wireshark)。 我的原始套接字绑定到端口8888,然后我尝试telnet到该端口。 在wireshark中,它显示端口8888在收到“syn”请求时回复“rst ack”。在我的程序中,它显示它收到一条新消息,并且不会回复任何消息。

任何实际绑定到该端口的方法?(防止操作系统处理它)

以下是我的代码的一部分,我尝试删除那些错误检查以便于阅读

sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);

int tmp = 1;
const int *val = &tmp;
setsockopt (sockfd, IPPROTO_IP, IP_HDRINCL, val, sizeof (tmp));

servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(8888);
bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));

//call recv in loop 

4 个答案:

答案 0 :(得分:4)

当你的内核收到来自远程主机的SYN / ACK时,它没有发现它已将SYN发送到该IP:PORT组合(从你的原始套接字发送)的记录,这就是为什么它假设已经存在错误并将RST发送到远程主机。通过设置阻止该端口上所有TCP流量的IP过滤器可以解决此问题(请查看iptables联机帮助页)。这样您就不必在内核空间中编程,也不会对现有的内核TCP模块产生任何影响。

答案 1 :(得分:3)

man 7 raw说:

  

原始套接字可以利用Linux中的所有IP协议,甚至是内核中具有协议模块的ICMP或TCP等协议。在这种情况下,数据包将传递给内核模块和原始套接字。

我认为这意味着你不能在没有内核干扰的情况下在原始套接字上“做TCP”,除非你的内核缺乏TCP支持 - 当然,这不是你想要的。什么原始套接字适用于实现内核处理的其他IP协议,或者用于发送精心设计的ICMP数据包等特殊应用程序。

答案 2 :(得分:2)

要访问原始标头,您不要将原始套接字绑定到端口。多数民众赞成没有。

只需编写一个嗅探器,“拾取”所有传入的数据包并找出“你的”数据包。这也可以让您访问所有数据包内容等。

您就是这样做的:

int sock_raw = socket( AF_PACKET , SOCK_RAW , htons(ETH_P_ALL)) ;

while(true)
{
    saddr_size = sizeof saddr;
    //Receive a packet
    data_size = recvfrom(sock_raw , buffer , 65536 , 0 , &saddr , (socklen_t*)&saddr_size);
    if(data_size <0 )
    {
        printf("Recvfrom error , failed to get packets\n");
        return 1;
    }
    //Now process the packet
    ProcessPacket(buffer , data_size);
}

在ProcessPacket函数中分析数据包并查看它们是否属于您的应用程序。

答案 3 :(得分:1)

编辑: 如果您打算编写原始套接字,请检查this

它有一些如何发送和接收原始数据包的示例。

如果您想使用SOCK_STREAMSOCK_SEQPACKET面向连接的类型套接字:

你需要告诉它在绑定到给定地址后监听:port。

int connectionQueue = 10;
if ( -1 == listen(sockfd, connectionQueue) )
{
  // Error occurred
}

之后,您需要使用select验证传入连接的描述符,并接受服务器套接字上的传入连接(这将导致不接受新连接)或专用客户端套接字。