how tcpdump work with vlan filter

  • 问题描述:
    tcpdump在网口抓包和读取pcap文件,相同的filter表达式”icmp“,对vlan报文有不同的处理结果。
    在网口上抓包可以看到vlan和非vlan两种流量, 而读取pcap只能看到非vlan流量一种流量。

  • 原因:
    kernel里在tcpdump抓包之前会把报文的vlan提前解析掉,并把vlan信息放到skb的metadata里了。
    所以tcpdump(内核的af_packet对应的ptype_all)处理的报文都是不带vlan的,因此这两类报文都会被过滤出来。
    而读取pcap时候,因为vlan报文并没有被剥离掉,所以vlan报文不满足过滤条件,被丢弃了。

国外已经有人发现并分析过这个问题
https://andreaskaris.github.io/blog/networking/bpf-and-tcpdump/

Read More

tcpdump and ebpf

以内核v6.6代码,介绍tcpdump程序如何与内核交互,加载bpf程序的。

加载:

libpcap通过sockopt里的“SO_ATTACH_FILTER“,
在 packet socket下的”sk_filter“挂载prog呈现。

运行:

当skb报文到达packet_rcv时候, 通过调用___bpf_prog_run函数(注意,这个函数是3个下滑线,区别于2个下划线的函数)
运行”sk_filter“对应的prog。
其中prog的
==>packet_rcv
==> ==> run_filter
==> ==> ==>bpf_prog_run_clear_cb

Read More

how tcpdump work with cbpf

tcpdump通过libpcap库以及内核的af_packet对数据包问题进行抓取。
关于这两部分的如何协作抓包,之前blog里已经写过。
这里主要记录分析,在ebpf之前的内核(以v3.0)如何处理tcpdump里的filter的。

filter编译后,如何加载到内核里的:

在filter被翻译为一系列的指令后,这个指令buff被libpcap,
通过sockopt里的SO_ATTACH_FILTE选项,
最终挂载到AF_PACKET socket下的sk_filter上。

Read More

tcpdump如何实现参数-报文抓取长度

用法

tcpdump -s len

原理

tcpdump会把这个长度值编译到ebpf代码中。 ebpf代码执行完后,如果filter成功,则作为返回值(return)返回给调用方(内核协议栈),内核协议栈根据返回值,修改 skb报文到指定的长度,并借助 af socket 返回给用户空间。

tcpdump命令解析

tcpdump snaplen参数: ebpf指令对比

Read More

策略路由的实现

概述

IPv4 rule route 配置示意图

测路路由介绍

关于策略路由是什么,为什么需要策略路由, man手册里写的这一段,我认为是最经典的一个解释。
清晰明了,这里借用并翻译下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Classic routing algorithms used in the Internet make routing
decisions based only on the destination address of packets (and
in theory, but not in practice, on the TOS field).

In some circumstances, we want to route packets differently
depending not only on destination addresses but also on other
packet fields: source address, IP protocol, transport protocol
ports or even packet payload. This task is called 'policy
routing'.

To solve this task, the conventional destination based routing
table, ordered according to the longest match rule, is replaced
with a 'routing policy database' (or RPDB), which selects routes
by executing some set of rules.

尝试翻译下:

1
2
3
4
5
6
传统的路由方法,是基于报文的目的地地址做路由查找(理论上支持,但没啥卵用的 TOS 字段就不讨论了)

在一些场景下, 我们不仅想根据你报文的目的地做选择路由, 同时还想根据报文的其他字段:源地址、ip 协议、tcp 端口 甚至是报文负载,选择路由。
这个功能就被称为"测路路由(policy route)"

为了实现这个功能,传统的基于路由表和最长匹配规则的路由查找方式,就被'routing policy database(RPDB)'取代(包装+升级)了。RPDB通过执行一些规则路由集合来选择路由。

对需求背景说的非常清楚,具体实现,后续我们展开讲解。
取代,我个人任务这里用replaced 不够严谨:
这里的RPDB取代传统路由,是在原有传统路由的基础上,增加新的模块,提供更多样的路由查找方式。也许原作想表达的是路由查找接口被取掉。
所以这里保留直译。

如何使用

假设一个场景:为了方便,这里使用一个容器做实验,容器有三个网口,veth0,veth2,veth4, 并配有/24掩码的IP地址。
veth0: 192.168.0.1/24
veth2: 192.168.2.1/24
veth4: 192.168.4.1/24
系统配置一条缺省路由指向veth4

添加rule

添加table

规则路由(rule route)

这部分详见ip rule命令帮助手册,
https://man7.org/linux/man-pages/man8/ip-rule.8.html
简要总结:

  • 支持多种形式的路由查找,不再仅仅局限于传统路由,根据目的地址查找一种模式。
  • 每条规则(rule) 都有一个优先级, 内核按照priority从高到底按顺序放到一个链表中。priority值越小,优先级越高,0对应优先级最高。
  • rule route采用了类似match-action模式, 不过rule route称之为SELECTORACTION
  • SELECTOR 支持多种形式,比如IP、PORT、进出网口、tos以及非操作(not)
  • ACTION 中几个重要的类型:
    • table:到指定的TABLE_ID对应的路由表里查找(所以这里要求必须支持多table)
    • goto: 跳转到指定的rule。这里只能往链表中,当前节点后面的节点去跳,不能往前跳。
    • nat: 支持IP地址nat(TODO nat 废弃?)
  • 路由查找时候使用,按链表里顺序(优先级)依次比较每个节点的的match 条件,如果满足则执行对应的 action,否则跳到下一个节点,继续执行。如果满足
    • ACTION 是跳转,则直接跳过中间节点,继续匹配链表剩余节点。
    • action是table X,则使用目的地ip去路由表table X里查找最长匹配的路由,查找的路由结果即为最终路由查找结果。
      说明:
  • route里goto 可以反复多次嵌套多条rule,其他action均不能嵌套执行。比如lookup,table查找的结果就是最终结果,不会再有其他跳转和嵌套。

Read More

xfrm: configure xfrm state and policy with iproute2

测试环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ip netns exec ns1 ip l s veth1 down
ip l delete veth0
ip netns delete ns1

ip l add type veth
ip netns add ns1

ip l s dev veth1 netns ns1
ip l set veth0 up
ip netns exec ns1 ip l set veth1 up

ip a a dev veth0 192.168.100.1/24
ip netns exec ns1 ip a a dev veth1 192.168.100.2/24
ip netns exec ns1 ip r a default via 192.168.100.1

Read More

WHAT is TFO

什么是tcp fast open(TFO)

背景

网络上有大量的短连接,传输的数据很少。google统计显示,其访问请求里有30%左右的流量是短连接。

原理

针对tcp 短连接的一个优化。在syn请求里携带请求数据,让server端尽早处理,进而降低一个RTT的延迟。
client端发送时候在syn报文里,增加一个tcp option选项(TFO),server端通过它校验client端的合法性。

Read More

How to use kpatch

搭建kpatch builder

以centos7.2为例。

默认centos7.2的安装的内核版本是3.10.0-327.el7.x86_64,这个内核版本当初是通过gcc 4.8.3编译的。
而centos7.2自带gcc rpm包的版本则是 4.8.5

kpatch build命令执行的时候,首先检查gcc的版本是否一致,
因为两者的版本不一致,所以kpatch build命令会失败。
当然我们可以使用--skip-gcc-check,跳过这个检查,我也测试发现在一些简单补丁下可以打包通过。
但是系统不推荐这样做的,会有一定的风险。

Read More