之前在使用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 ;
反向移植到我们的版本就可以搞定。