HairPin Mode

hairpin mode 指允许网络设备从一个端口收到包后,回包仍从原端口发出。

在 Linux 中 bridge 设备默认不支持 hairpin mode,用户需要通过brctl hairpin <bridge> <dev> on 开启指定端口的 hairpin mode。

hairpin mode 特性常用于 NAT 场景下,比如docker的nat网络,一个容器访问其自身映射到主机的端口时,包到达bridge设备后走到ip协议栈,经过iptables规则的dnat转换后发现又需要从bridge的收包端口发出,此时需要开启端口的hairpin mode。

Linux 数据包的接收与发送过程

参考资料:https://morven.life/posts/networking-1-pkg-snd-rcv

  • 数据包的接受过程

    • 网卡 –> 内存

      • 根据目的地址以及网卡混杂模式(ifconfig eth0 promisc / ifconfig eth0 -promisc)判断,网卡判断是否接收网络包
      • 通过 DMA 将数据包写入指定内存(网卡驱动初始化时分配了这段内存)
      • 网卡触发 IRQ(硬件中断) -> CPU根据中断表调用 NIC Driver -> NIC Driver 关闭 IRQ -> NIC Driver 触发软中断 -> ksoftirqd 有序处理软中断
    • 内核处理数据包

      • 数据包转换为skb(socket buffer) -> __netif_receive_skb_core 根据数据包类型进一步处理
        • 原始套接字:AF_PACKET socket
        • 标准套接字:数据包进入TCP/IP 协议栈处理
      • 内存存中所有数据包处理完成 -> NIC Driver 开启 IRQ
    • 内核协议栈处理数据包

      • IP网络层
        • ip_rcv 函数:目的mac地址一致、网卡是否处于混杂模式 -> 决定是否丢弃数据包
        • NF_INET_PRE_ROUTING
        • routing:目的IP一致、是否开启 ip 转发功能 -> 决定是否丢弃数据包
          • 本地包:
            • NF_INET_LOCAL_IN -> 进入传输层
          • 转发包:
            • NF_INET_FORWARD -> dst_output_sk 函数
      • 传输层
        • udp_rcv函数:目的 IP 和端口是否存在 -> 决定是否丢弃数据包
  • 数据包的发送过程

    • 应用层

      • 构建socket(目的IP/端口),并绑定源Port
    • 传输层

      • ip_route_output_flow:根据路由表目的IP,确定源IP/源设备的MAC
      • ip_make_skb:从socket构造skb
      • udp_send_skb:向skb中填充UDP的包头,同时处理校验信息,然后交给IP层处理
    • IP 网络层

      • NF_INET_LOCAL_OUT
      • dst_output_sk:
        • NF_INET_POST_ROUTING:这里可能发生SNAT
      • 根据目的 IP找到下一跳的MAC地址,并填充到skb
    • 内核处理数据包:

      • 将skb 放入网卡自己的发送队列
      • 通知网卡发送数据包
      • 网卡发送完成后发送中断给 CPU
      • 收到中断后进行 skb 的清理工作

其他知识点:

  • ksoftirqd/n 进程:每个CPU用于辅助处理软中断的内核线程,用来避免大量软中断时(软中断返回时自行再次触发的场景)用户进程无法获取CPU处于饥饿状态。【关于ksoftirqd进程】
  • SKB(Struct sk_buffer)是TCP/IP堆栈中用于收发包的缓冲区域

2. 虚拟网络设备

参考资料:https://morven.life/posts/networking-2-virtual-devices/

  • 虚拟网络设备与物理网络设备没有什么区别,它们的一端连接着内核协议栈,而另一端的行为是什么取决于不同网络设备的驱动实现

  • TUN/TAP

    • TUN/TAP 虚拟网络设备:一端是协议栈,另一端是处于用户空间的应用程序
    • TUN 设备是一个虚拟的端到端 IP 层设备,用户空间的应用程序通过 TUN 设备只能读写 IP 网络数据包(三层)
    • TAP 设备是一个虚拟的链路层设备,通过 TAP 设备能读写链路层数据包(二层)
  • veth

    • veth:一端连着协议栈,另外一端是另一个 veth 设备,成对的 veth 设备每个都可以配置 IP 地址,并参与三层 IP 网络的路由过程。
    • 成对的 veth 设备对处于不同的网络命名空间中,数据包的转发在不同网络命名空间之间进行
  • bridge

    • bridge 是一个虚拟交换机,一端连接着协议栈,另外一端有多个端口,数据在各个端口间转发数据包是基于 MAC 地址。
    • bridge 可以工作在二层(链路层),也可以工作在三层(IP 网路层)。当给 bridge 分配了 IP 地址,也就开启了该 bridge 的三层工作模式。
    • 设备接入网桥时,它受到的数据包不会发到内核协议栈,而是发到对应的网桥。

iptables

参考资料:https://morven.life/posts/iptables-wiki/

  • 据其工作机制来区分防火墙有:包过滤型防火墙(netfilter)、代理服务器(Proxy)、 TCP Wrappers

  • 五链:netfilter 提供的内核中的 Hook 点上,一串顺序执行的规则称为链

    • PreRouting:发生在路由选择之前,因此进行DNAT
    • Forward:
    • Input:过滤进入本机的数据包
    • Output:过滤本机发出的数据包
    • PostRouting:决定发出数据包的网络设备,因此进行SNAT
  • 四表:根据规则划分的不同集合

    • filter:负责过滤功能
    • nat:网络地址转换功能,典型的比如 SNAT、DNAT
    • mangle:解包报文、修改并封包
    • raw:关闭 nat 表上启用的连接追踪机制(conntrack)
  • 链表关系

    允许的规则
    PreRouting raw, mangle, nat
    Forward mangle, filter
    Input mangle, filter, nat
    Output raw, mangle, filter, nat
    PostRouting mangle, nat
  • 表链关系

    表的优先级(越小越优先)
    raw PreRouting, Output 1
    mangle PreRouting, Forward, Input, Output, PostRouting 2
    nat PreRouting, Input, Output, PostRouting 4
    filter Forward, Input, Output 3
  • 默认动作

ACTION 说明 后续匹配
ACCEPT 允许数据包通过 下一个规则炼
DROP 丢弃数据包 中断
REJECT 丢弃数据包,发送拒绝信息 中断
SNAT 源地址转换 下一个规则炼
DNAT 目标地址转换 下一个规则炼
REDIRECT 目标端口转换 继续
MARK 将数据包打上标记 继续
RETURN 调用规则链
MASQUERADE 改写SRC IP为当前IP 下一个规则炼
LOG 记录信息到/var/log 继续
MIRROR 调换源IP和目的IP,将包发回 中断
QUEUE 封包放入队列,交给其它程序处理 中断
  • 可以使用 iptables 创建自定义的“链”,自定义的“链”不能直接使用,只能被某个默认的“链”当作处理动作 action 去调用。

  • iptables命令参考