在做 Linux 代理流量回放实验 的时候,因为遇到了问题,所以想看下 socket 的 IP_TRANSPARENT 选项是否设置了。该实验使用了 Linux 透明代理的功能,而 Linux 透明代理需要用户程序在使用 socket 的时候给 socket 设置 IP_TRANSPARENT 选项,参考资料 Transparent proxy support

在 Linux 中,如何查看 socket 的 IP_TRANSPARENT 选项呢?

尝试了 netstatlsof/proc 文件系统等工具,都无法查看该选项。

Linux 透明代理:

setsockopt 的实现

跳过系统调用,直接从 ip_setsockopt 函数看起吧。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// net/ipv4/ip_sockglue.c

int ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
		unsigned int optlen)
{
	int err;
	...
	err = do_ip_setsockopt(sk, level, optname, optval, optlen);
	...
	return err;
}

static int do_ip_setsockopt(struct sock *sk, int level, int optname,
		sockptr_t optval, unsigned int optlen)
{
	struct inet_sock *inet = inet_sk(sk);

	switch (optname) {
	...
	case IP_TRANSPARENT:
		...
		inet->transparent = !!val; // IP_TRANSPARENT 选项保存在 struct inet_sock.trasparent 中
		break;
	...
	}
}

// include/net/inet_sock.h

struct inet_sock {
	struct sock		sk;
	...
	__u8			recverr:1,
				is_icsk:1,
				freebind:1,
				hdrincl:1,
				mc_loop:1,
				transparent:1,
				mc_all:1,
				nodefrag:1;
	...
};

knetstat 自定义查看 socket 信息

遍寻 Linux 网络相关的工具,未能解决这问题。在找到 veithen/knetstat 这个工具的时候,看到了希望。该工具的作者想要查看 TCP socket 选项但苦于没有现成工具,他就萌生了开发一个相关工具的想法:给 Linux 内核提交补丁,或者实现一个内核模块去输出相关信息到 /proc/net 下;最终他采取了内核模块的方式去实现了需求,参考 Inspecting socket options on Linux

那就扩展该工具去查看 IP_TRANSPARENT 选项吧。

veithen/knetstat 里,核心是 tcp_seq_showudp_seq_show 这两个函数。在这两个函数的合适位置添加一行代码:

1
seq_printf(seq,",IP_TRANSPARENT=%d",inet_sk(sk)->transparent);

make && insmod knetstat.ko 后效果如下:

socket IP_TRANSPARENT option

源代码:github.com/Asphaltt/knetstat

总结

knetstat 作者所说,straceltrace 等工具功能强大、但不适合用来解决这问题,只能亲自下场打造合适的工具来解决这问题。