以前分析了netlink的原理,可以知道:内核和用户态相互消息传递,最好的方法就是使用 netlink,比较可以双向传递消息,不像 proc sys 只能单向;
但是netlink有个缺点就是使用tcpdump抓不到!!
目前为了解决他,采取了以前dpdk抓包的方法,直接copy&&mirror到虚拟接口上即可!(主要是内核太老了!!)这是本人之前的一个改动,需要修改内核代码;
目前稍微新内核有个nlmon模块, 其原理和本人修改类似;都是copy&&mirror
insmod nlmon.ko ip link add netdbg type nlmon ip link set dev netdbg up
root@COMPILE:~# ifconfig netdbg netdbg Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 UP RUNNING NOARP MTU:3776 Metric:1 RX packets:4 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1 RX bytes:3588 (3.5 KB) TX bytes:0 (0.0 B)
kernel--->user:
netlink消息从内核态传递给用户态时:在发送之前会检查是否有netlink tap 设备,如果有且符合条件,则copy 一份到netdbg tap接口上
|netlink_sendskb |---->netlink_deliver_tap |---->---->__netlink_deliver_tap |---->---->---->netlink_filter_tap(skb) |---->---->---->__netlink_deliver_tap_skb(skb, tmp->dev);
static void __netlink_deliver_tap(struct sk_buff *skb) { int ret; struct netlink_tap *tmp; if (!netlink_filter_tap(skb)) return; list_for_each_entry_rcu(tmp, &netlink_tap_all, list) { ret = __netlink_deliver_tap_skb(skb, tmp->dev); if (unlikely(ret)) break; } }
static bool netlink_filter_tap(const struct sk_buff *skb) { struct sock *sk = skb->sk; /* We take the more conservative approach and * whitelist socket protocols that may pass. */ switch (sk->sk_protocol) { case NETLINK_ROUTE: case NETLINK_USERSOCK: case NETLINK_SOCK_DIAG: case NETLINK_NFLOG: case NETLINK_XFRM: case NETLINK_FIB_LOOKUP: case NETLINK_NETFILTER: case NETLINK_GENERIC: return true; } return false; }
可以看到 只有ROUTE USERSOCK SOCK_DIAG XFRM NETFILTER 等类型的netlink消息才会被传递给netlink tap 接口!!也就是这些类似的消息才能被tcpdump 抓到
执行:strace ip link add netlinkdee type ipvlan mode l3
结果如下:
execve("/sbin/ip", ["ip", "link", "add", "netlinkdede", "type", "ipvlan", "mode", "l2"], [/* 23 vars */]) = 0 socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE) = 3 setsockopt(3, SOL_SOCKET, SO_SNDBUF, [32768], 4) = 0 setsockopt(3, SOL_SOCKET, SO_RCVBUF, [1048576], 4) = 0 bind(3, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 0 getsockname(3, {sa_family=AF_NETLINK, pid=25920, groups=00000000}, [12]) = 0 sendto(3, " \0\0\0\20\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 32, 0, NULL, 0) = 32 recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"4\0\0\0\2\0\0\0\0\0\0\0@e\0\0\355\377\377\377 \0\0\0\20\0\5\0\0\0\0\0"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 52 access("/proc/net", R_OK) = 0 access("/proc/net/unix", R_OK) = 0 socket(PF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 4 ioctl(4, SIOCGIFINDEX, {ifr_name="netlinkdede"}) = -1 ENODEV (No such device) close(4) = 0 sendmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"L\0\0\0\20\0\5\6\360\3\270b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 76}], msg_controllen=0, msg_flags=0}, 0) = 76 recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"`\0\0\0\2\0\0\0\360\3\270b@e\0\0\352\377\377\377L\0\0\0\20\0\5\6\360\3\270b"..., 32768}], msg_controllen=0, msg_flags=0}, 0) = 96 write(2, "RTNETLINK answers: Invalid argum"..., 36RTNETLINK answers: Invalid argument
这是对netdbg 接口抓包接口