之前在使用ipv4的时候,有一个模块是使用raw socket来发包,它使用的一个option是:IP_HDRINCL。
如果设置了IP_HDRINCL选项,则raw会绕过source validate逻辑,即构造的IP源地址可以是非本机地址,比如我们在流媒体中发送udp包,替换码流源就可以用到这种。
或者通过劫持DNS请求,用别人ip给请求方发包,也可以利用这个特性,诸如此类。
如果没有设置IP_HDRINCL选项忽略构造的IP源地址,以路由查找逻辑动态确定IP源地址。
很显然,我们的应用场景需要利用这个特性。
v4迁移到v6的时候,我们很自信地写上了 IPV6_HDRINCL ,结果发现没有用。我的内核版本是3.10,然后git一份高版本内核,发现这个是有的:
static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, char __user *optval, unsigned int optlen) { struct raw6_sock *rp = raw6_sk(sk); int val; if (get_user(val, (int __user *)optval)) return -EFAULT; switch (optname) { case IPV6_HDRINCL: if (sk->sk_type != SOCK_RAW) return -EINVAL; inet_sk(sk)->hdrincl = !!val; return 0;
反向移植到我们的版本就可以搞定。