加入收藏 | 设为首页 | 会员中心 | 我要投稿 威海站长网 (https://www.0631zz.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

Linux原始套接字实现分析---转

发布时间:2021-01-25 16:24:25 所属栏目:Linux 来源:网络整理
导读:本文从IPV4协议栈原始套接字的分类入手,详细介绍了链路层和网络层原始套接字的特点及其内核实现细节。并结合原始套接字的实际应用,说明各类型原始套接字的适应范围,以及在实际使用时需要注意的问题。 一、原始套接字概述 链路层原始套接字可以直接用于接
<tr>
<td>

?????????

……?
  • sock->ops?=?answer->ops;?//将socket结构的ops设置为inet_sockraw_ops?
  • answer_prot?=?answer->prot;?
  • ……?
  • if?(SOCK_RAW?==?sock->type)?{?//SOCK_RAW类型的套接字,设置inet->num?
  • ??????? inet->num?=?protocol;?
  • ????????if?(IPPROTO_RAW?==?protocol)?//protocol为IPPROTO_RAW的特殊处理,?
  • ??????????????? inet->hdrincl?=?1;?后续在报文发送时会再讲到?
  • }?
  • ……
  • if?(inet->num)?{
  • ????????inet->sport?=?htons(inet->num);?
  • ?????? ?sk->sk_prot->hash(sk);?//调用raw_v4_hash()函数将套接字链到raw_v4_htable中?
  • }?
  • ……
  • 经过如上操作后,相应的套接字结构sock会通过raw_v4_hash()函数链到raw_v4_htable链表中,网络层原始套接字报文接收时需要使用到raw_v4_htable。如图5所示,共创建了3个网络层原始套接字,协议类型分别为、IPPROTO_ICMP和89。

    <p align="center">?


    <p align="center">?


    <p align="center">图5??raw_v4_htable链表

    2.3.2??报文接收

    网卡驱动收到报文后在软中断上下文由netif_receive_skb()处理,对于IP报文且目的地址为本机的会由ip_rcv()最终调用ip_local_deliver_finish()函数。ip_local_deliver_finish()主要功能的代码片段如下,先根据报文的L4层协议类型hash值在图5中的raw_v4_htable表中查找是否有匹配的sock。如果有匹配的sock结构,就进一步调用raw_v4_input()处理网络层原始套接字。不管是否有原始套接字要处理,该报文都会走后续的协议栈处理流程。即会继续匹配inet_protos[]数组,根据L4层协议类型走TCP、UDP、ICMP等不同处理流程。

    <table style="width: 100%;" cellspacing="0" cellpadding="0">

    <tr>
    <td>

    ?????????

    ……?
  • hash?=?protocol?&?(MAX_INET_PROTOS?-?1);?//根据报文协议类型取hash值?
  • raw_sk?=?sk_head(&raw_v4_htable[hash]);?//在raw_v4_htable中查找?
  • ……?
  • if?(raw_sk?&&?!raw_v4_input(skb,?skb->nh.iph,?hash))?//处理原始套接字?
  • ……?
  • if?((ipprot?=?rcu_dereference(inet_protos[hash]))?!=?NULL)?{?//匹配inet_protos[]数组?
  • ??????? ……?
  • ??????? ret?=?ipprot->handler(skb);?//调用传输层处理函数?
  • ??????? ……?
  • }?else?{?//如果在inet_protos[]数组中未匹配到,则释放报文
  • ??????? ……?
  • ??????? kfree_skb(skb);?
  • }?
  • ……
  • 如图6所示的inet_protos[]数组,每项由net_protocol结构组成。表示一个协议(包括传输层协议和网络层附属协议)的接收处理函数集,一般包括一个正常接收函数和一个出错接收函数。图中TCP、UDP和ICMP协议的接收处理函数分别为tcp_v4_rcv()、udp_rcv()和icmp_rcv()。如果在inet_protos[]数组中未配置到相应的net_protocol结构,报文就会被丢弃掉。比如OSPF报文(协议类型为89)在inet_protos[]数组中没有相应的项,内核会将其丢弃掉,这种报文只能提供网络层原始套接字接收到用户态来处理。

    <p align="center">?


    <p align="center">?


    <p align="center">图6??inet_protos[]数组结构

    ??? 网络层原始套接字的总体接收流程如下,最终会将skb挂到相应套接字上,并唤醒用户态进程读取报文数据。

    网卡驱动->netif_receive_skb()->ip_rcv()->ip_rcv_finish()->ip_local_deliver()->ip_local

    _deliver_finish()->raw_v4_input()->raw_rcv()->raw_rcv_skb()->sock_queue_rcv_skb()

    (编辑:威海站长网)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    链路层原始套接字的信息可通过/proc/net/packet进行查看。如下为图2和图3中创建的原始套接字的信息,可以查看到创建时指定的协议类型、是否绑定网口、已使用的接收缓存大小等信息。这些信息对于分析和定位问题有帮助。?

    cat /proc/net/packet
  • sk RefCnt Type Proto Iface R Rmem User Inode
  • ffff810007df8400 3 3 0810 0 1 0 0 1310
  • ffff810007df8800 3 3 0806 0 1 0 0 1309
  • ffff810007df8c00 3 3 0800 0 1 560 0 1308
  • ffff810007df8000 3 3 0003 0 1 560 0 1307
  • ffff810007df3800 3 3 0003 0 1 560 0 1306
  • 2.3??网络层原始套接字的实现

    2.3.1??套接字创建

    如图4所示,在IPV4协议栈中一个传输层协议(如TCP,UDP,UDP-Lite等)对应一个inet_protosw结构,而inet_protosw结构中又包含了proto_ops结构和proto结构。网络子系统初始化时将所有的inet_protosw结构hash到全局的inetsw[]数组中。proto_ops结构实现的是从与协议无关的套接口层到协议相关的传输层的转接,而proto结构又将传输层映射到网络层。

    ??? 调用socket()函数创建套接字的流程如下,网络层原始套接字最终由inet_create()创建。

    sys_socket()->sock_create()->__sock_create()->inet_create()

    ??? inet_create()函数除用于创建网络层原始套接字外,还用于创建TCP、UDP套接字。首先根据socket()函数的第二个参数(即SOCK_RAW)在inetsw[]数组中匹配到相应的inet_protosw结构。并将套接字结构的ops设置为inet_sockraw_ops,将套接字结构的sk_prot设置为raw_prot。然后对于SOCK_RAW类型套接字,还要将inet->num设置为协议类型,以便最后能调用proto结构的hash函数(即raw_v4_hash())。

    <table style="width: 100%;" cellspacing="0" cellpadding="0">

    热点阅读