Linux vxlan的NAT穿透和UDPspeeder黑科技

众所周知,Linux的vxlan实现不支持穿透NAT网络环境。并且由于它没有分离listen port和dst port(两者都使用dst_port),没法整活UDPspeeder这种暴力发包工具。

  • 为什么要折腾Linux vxlan?只是因为直面kernel性能好,实现(网络层面)简单高效,用来作为隧道传输通道,在带宽和延迟上爆杀一众用户态VPN工具。在我的测试环境,vxlan能随便跑满千兆接口,而openvpn即使去掉加密选项也只能跑250M

言归正传,要让vxlan支持NAT穿透,必然要改造源码,直接贴patch(针对linux-5.10.146)

Index: linux-5.10.146/drivers/net/vxlan.c
===================================================================
--- linux-5.10.146.orig/drivers/net/vxlan.c
+++ linux-5.10.146/drivers/net/vxlan.c
@@ -84,6 +84,14 @@ struct vxlan_fdb {
 	struct vxlan_dev  __rcu *vdev;
 };
 
+struct extra_config_req_t {
+	u8 daddr[4];
+	u32 kal;
+	u8 spl : 1;
+	u8 dpl : 1;
+	u8 bk: 1;
+};
+
 #define NTF_VXLAN_ADDED_BY_USER 0x100
 
 /* salt for hash table */
@@ -1460,7 +1468,7 @@ errout:
  */
 static bool vxlan_snoop(struct net_device *dev,
 			union vxlan_addr *src_ip, const u8 *src_mac,
-			u32 src_ifindex, __be32 vni)
+			u32 src_ifindex, __be32 vni, __be16 dstport)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct vxlan_fdb *f;
@@ -1477,7 +1485,7 @@ static bool vxlan_snoop(struct net_devic
 		struct vxlan_rdst *rdst = first_remote_rcu(f);
 
 		if (likely(vxlan_addr_equal(&rdst->remote_ip, src_ip) &&
-			   rdst->remote_ifindex == ifindex))
+			   rdst->remote_ifindex == ifindex && rdst->remote_port == dstport))
 			return false;
 
 		/* Don't migrate static entries, drop packets */
@@ -1494,6 +1502,7 @@ static bool vxlan_snoop(struct net_devic
 				    src_mac, &rdst->remote_ip.sa, &src_ip->sa);
 
 		rdst->remote_ip = *src_ip;
+		rdst->remote_port = dstport;
 		f->updated = jiffies;
 		vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH, true, NULL);
 	} else {
@@ -1507,7 +1516,7 @@ static bool vxlan_snoop(struct net_devic
 			vxlan_fdb_update(vxlan, src_mac, src_ip,
 					 NUD_REACHABLE,
 					 NLM_F_EXCL|NLM_F_CREATE,
-					 vxlan->cfg.dst_port,
+					 dstport,
 					 vni,
 					 vxlan->default_dst.remote_vni,
 					 ifindex, NTF_SELF, 0, true, NULL);
@@ -1791,9 +1800,10 @@ static bool vxlan_set_mac(struct vxlan_d
 		saddr.sa.sa_family = AF_INET6;
 #endif
 	}
-
+	
+	struct udphdr *udph = udp_hdr(skb);
 	if ((vxlan->cfg.flags & VXLAN_F_LEARN) &&
-	    vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, ifindex, vni))
+	    vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, ifindex, vni, vxlan->cfg.dpl ? udph->source : vxlan->cfg.dst_port))
 		return false;
 
 	return true;
@@ -2506,6 +2516,8 @@ static void vxlan_encap_bypass(struct sk
 	union vxlan_addr *remote_ip = &dst_vxlan->default_dst.remote_ip;
 	struct net_device *dev;
 	int len = skb->len;
+	
+	//printk("in vxlan_encap_bypass: vni %d, snoop %d\n", ntohl(vni), (int)snoop);
 
 	tx_stats = this_cpu_ptr(src_vxlan->dev->tstats);
 	rx_stats = this_cpu_ptr(dst_vxlan->dev->tstats);
@@ -2532,7 +2544,7 @@ static void vxlan_encap_bypass(struct sk
 	}
 
 	if ((dst_vxlan->cfg.flags & VXLAN_F_LEARN) && snoop)
-		vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni);
+		vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni, dst_vxlan->cfg.dst_port);
 
 	u64_stats_update_begin(&tx_stats->syncp);
 	tx_stats->tx_packets++;
@@ -2566,20 +2578,30 @@ static int encap_bypass_if_local(struct
 	BUILD_BUG_ON(RTCF_LOCAL != RTF_LOCAL);
 #endif
 	/* Bypass encapsulation if the destination is local */
+	//printk("in encap_bypass_if_local step1: rt_flags %d, dst_port %d\n", rt_flags, ntohs(dst_port));
+						 
 	if (rt_flags & RTCF_LOCAL &&
 	    !(rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
 		struct vxlan_dev *dst_vxlan;
 
-		dst_release(dst);
 		dst_vxlan = vxlan_find_vni(vxlan->net, dst_ifindex, vni,
 					   daddr->sa.sa_family, dst_port,
 					   vxlan->cfg.flags);
+					   
+		//printk("in encap_bypass_if_local step2: vxlan %lld dst_vxlan %lld\n", vxlan, dst_vxlan);
+		
+		/*
 		if (!dst_vxlan) {
 			dev->stats.tx_errors++;
 			kfree_skb(skb);
 
 			return -ENOENT;
-		}
+		}*/
+		
+		if(!dst_vxlan)
+			return 0;
+		
+		dst_release(dst);
 		vxlan_encap_bypass(skb, vxlan, dst_vxlan, vni, true);
 		return 1;
 	}
@@ -2675,7 +2697,7 @@ static void vxlan_xmit_one(struct sk_buf
 		label = info->key.label
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值