linux网络发包工具,linux发送udp包

套接字层

UDP层

IP层

网络设备子系统

设备驱动

其他

本文以Linux系统上接收UDP数据包的过程为例,展示数据包是如何从应用程序一步步发送到网卡并最终发送出去的。

套接字层

Socket(.):创建socket结构体并初始化相应的操作函数。由于我们定义了一个UDP 套接字,因此所有与UDP 相关的函数都将存储在该套接字上。

sendto(sock,):应用层程序(应用程序)调用该函数开始发送数据包。该函数调用后续的inet_sendmsg。

inet_sendmsg:该函数主要检查当前socket是否有绑定的源端口。如果没有,则调用inet_autobind分配一个端口,然后调用UDP层函数。

inet_autobind:该函数调用绑定到套接字的get_port函数来获取可用端口。由于socket是UDP套接字,因此get_port函数被转发到UDP代码中的相应函数。

UDP层

udp_sendmsg:发送数据包的UDP模块入口点。在这个函数中,我们首先调用ip_route_output_flow获取路由信息(主要包括源IP和网卡),然后调用ip_make_skb,最后将网卡信息与skb关联起来。

ip_route_output_flow:该函数根据路由表和目的IP查找发送该数据包的设备。如果套接字没有绑定到源IP,该函数也会据此找到最佳的源IP。路由表。如果socket绑定了一个源IP,但根据路由表,该源IP对应的网卡无法到达目的地址,则该数据包将被丢弃,因此数据发送将失败,sendto函数也会失败。 我会回来的。错误。该函数最后将找到的设备和源IP填充到flowi4结构中,并将其返回给udp_sendmsg。

ip_make_skb:该函数的作用是构建skb包。构建好的skb包被分配了一个IP头,并初始化了一些信息(这里设置IP头的源IP)。该函数将同时被调用。 __ip_append_dat 如果需要分段,则__ip_append_data 函数执行分段并检查套接字的发送缓冲区是否已使用,如果已使用则返回ENOBUFS。

udp_send_skb(skb, fl4)主要是将UDP头嵌入到skb中,同时处理校验和,然后调用IP层相应的函数。

IP层

ip_send_skb:IP模块发送数据包的入口点。该函数简单地调用以下函数:

__ip_local_out_sk:设置IP数据包头的长度和校验和,并调用以下netfilter钩子。

NF_INET_LOCAL_OUT:网络过滤器挂钩。如果数据包没有被丢弃,您可以使用iptables来配置如何处理数据包。

dst_output_sk:该函数根据skb中的信息调用相应的输出函数。对于UDP IPv4,调用ip_output。

ip_output:将上面用udp_sendmsg获得的网卡信息写入skb,并调用NF_INET_POST_ROUTING钩子。

NF_INET_POST_ROUTING:用户可能在这里配置了SNAT。这会更改skb 路由信息。

ip_finish_output:现在确定路由信息自上一步以来是否已更改。如果它已更改,您将需要再次调用dst_output_sk (再次调用此函数可能会将您移至ip_output 而不是ip_output 指定的任何位置)。对于netfilter,这可能是xfrm4_transport_output。不然的话,就会下跌。

ip_finish_output2:根据目的IP在路由表中查找下一跳地址,调用__ipv4_neigh_lookup_noref在arp表中查找下一跳邻居信息。如果没有找到,则调用__neigh_create 来构造它。空邻居结构。

dst_neigh_output:在该函数中,如果上一步ip_finish_output2没有获取到邻域信息,则继续执行函数neigh_resolve_output,否则直接调用neigh_hh_output。在这个函数中,邻居信息的MAC地址被输入到skb中。然后调用dev_queue_xmit发送数据包

neigh_resolve_output:该函数发送一个arp请求以获取下一跳的MAC地址,用该MAC地址填充skb,并调用dev_queue_xmit。

网络设备子系统

dev_queue_xmit:netdevice子系统的入口函数。在该函数中,首先获取设备对应的qdisc。否则,直接调用dev_hard_start_xmit。由流量控制模块处理。

流量控制:这主要是一些过滤和优先级处理,如果队列满了,数据包就会被丢弃。有关更多信息,还可以在此步骤完成后转到dev_hard_start_xmit。

dev_hard_start_xmit:该函数首先将skb的副本复制到“数据包tap”。这里tcpdump获取数据然后调用ndo_start_xmit。如果dev_hard_start_xmit 返回错误(大多数情况下可能是NETDEV_TX_BUSY),则调用它的函数会将skb 放置到位,抛出软中断NET_TX_SOFTIRQ,并将其传递给软中断处理程序net_tx_action 以便稍后重试(如果发生错误)。对于环回或IP隧道,失败后没有重试逻辑)

ndo_start_xmit:这是一个函数指针,指向特定驱动程序向其发送数据的函数。

设备驱动

这一步之后,ndo_start_xmit就被置于具体网卡驱动的控制之下。我这里就不详细说了。一般流程是:

将skb放入网卡自己的发送队列中

通知网卡发送数据包。

当网卡完成传输后,向CPU发送中断。

收到中断后清理skb

网卡驱动程序发送数据包的过程中有几个地方必须与网络设备子系统进行交互。例如,如果网卡的队列已满,则需要告诉更高层不要这样做。发送更多数据将通知高层在队列空闲后继续发送数据。

其他

SO_SNDBUF: 从上面的过程可以看出,对于UDP来说,SO_SNDBUF只是一个限制,如果这个socket分配的skb占用的内存超过这个值,就会返回ENOBUFS。增加该值是没有意义的,因为它会导致ENOBUFS 错误。从sendto函数的帮助文件中,我找到了下面这句话:(通常这在Linux上不会发生;如果设备队列溢出,数据包就会被默默地丢弃。)这里的设备队列应该指的是流量控制队列。那么,在Linux上,问题是如果队列长度和数量太大,是否可以设置。按理说ENOBUFS是可以的。

txqueuelen: 很多地方都说这个是用来控制qdisc的队列长度,但是只有某些类型的qdisc使用这个配置,比如Linux默认的pfifo_fast。

硬件RX: 网卡通常有自己的环形队列,并且可以使用ethtool 配置该队列的大小。通常,驱动程序将发送请求放在该队列上,并通知网卡发送数据。如果队列已满,则返回NETDEV_TX_BUSY 给上层调用。

packet Taps(AF_PACKET): 第一次发送数据包和重试发送数据包时都会经过这里。

本文来自网络,不代表服装搭配_服装搭配的技巧_衣服的穿配法_服装搭配网立场,转载请注明出处:https://www.fzdapei.com/317842.html
上一篇
下一篇

为您推荐

返回顶部