如何通过两台机器之间的IP建立非静态L2TPv3套接字连接

时间:2019-06-27 14:47:19

标签: sockets linux-kernel tunnel netlink l2tp

我没有找到如何在IP上实现L2TPv3的示例

我只发现了L2TP的几个开源实现,

L2TPv3 rfc没有说明如何在Linux中实现它,这很明显

内核文档: https://github.com/torvalds/linux/blob/master/Documentation/networking/l2tp.txt说我们必须使用netlink +标准套接字,这可以告诉我们一些信息。但是我不明白为什么我们必须将netlink与标准套接字一起使用?

内核头文件: https://github.com/torvalds/linux/blob/master/include/uapi/linux/l2tp.h具有大量的enum和用于netlink + l2tpip结构的命令。我对如何正确使用它们感到困惑。

L2TPv3控制交换建立的最后一部分(SCCRQ,SCCRP,SCCCN)。阅读内核文档后,我只有自己的理解,这可能不正确,但这里是正确的。

服务器端:

  1. 准备隧道0套接字
  2. 为l2tp创建genl套接字
  3. 创建标准的套接字填充l2tpip结构(套接字创建+绑定),其中tunnel_id为0
  4. 使用genl socket创建通道0
  5. 等待SCCRQ(据我了解,标头的控制连接ID等于0)

  6. 在隧道0套接字上收到的SCCRQ上

  7. 从接收到的SCCRQ中获取AVL的分配的Conntrol连接ID,该ID在另一侧为receive_tunnel_id
  8. 为我们这边生成local_tunnel_id
  9. 创建标准的套接字填充l2tpip结构(套接字创建+绑定),其中tunnel_id为local_tunnel_id
  10. 使用genl socket创建带有local_tunnel_id的隧道
  11. 发送SCCRP时,标头的Controll Connaction ID等于Received_tunnel_id,并且AVL Assigned Conntrol Connection ID等于local_tunnel_id
  12. 在该套接字上等待SCCN

客户端

  1. 我不知道那边是怎么做的

据我了解,进一步的通信将通过第二个标准套接字,并且隧道ID零仅接收SCCRQ

很高兴澄清这些细节

1 个答案:

答案 0 :(得分:0)

很抱歉,此回复太晚了!但希望它对您或其他人仍然有用。

我将尝试依次解决您问题的各个方面。

但是我不明白为什么我们必须将netlink与标准套接字一起使用?

Linux L2TP子系统仅处理数据平面(即,通过L2TP会话承载的用户数据包)。用户空间的任务是处理控制平面(L2TP控制协议交换)。

从广义上讲,用户空间创建一个隧道套接字,以便与对等方交换L2TP控制消息。建立隧道(SCCRQ / SCCRP / SCCCN)后,在创建内核隧道上下文时,将使用netlink API将隧道FD传递给内核。然后将该隧道FD用于该隧道中的会话数据包。

内核头文件:https://github.com/torvalds/linux/blob/master/include/uapi/linux/l2tp.h,其中包含大量的enum和用于netlink + l2tpip结构的命令。我对如何正确使用它们感到困惑。

此博客文章可能会帮助您:Linux and L2TP -- a peek under the hood。它涵盖了netlink API中的命令,并概述了如何使用它们。

L2TPv3控制交换建立的最后一部分(SCCRQ,SCCRP,SCCCN)。阅读内核文档后,我只有一个自己的理解,那就是不正确,但在这里是正确的。

在服务器端,您大致上是正确的,但需注意以下几点:

  • 步骤4是不必要的。您不需要为隧道ID 0创建内核上下文,因为您只希望控制数据包(特别是SCCRQ,在某些情况下为STOPCCN)就到达隧道ID 0。
  • 第9步还应该connect(2)到对等方的地址和隧道ID。
  • 可以认为步骤10太早了,因为控制协议当然会在建立隧道之前失败。从服务器的角度来看,一旦传输已确认SCCCN消息,就可以认为已建立隧道。这表示尽早创建内核隧道上下文没有任何危害,只要您确保在控制协议失败的情况下将其拆除即可。

客户端...我不知道该怎么做

这与服务器端的基本过程相同。

用户空间应该执行控制协议消息交换(SCCRQ / SCCRP / SCCCN),一旦成功完成,就使用netlink消息在内核中实例化L2TP隧道上下文。

  1. 为L2TP创建一个通用套接字。
  2. 生成本地隧道ID。
  3. 创建一个隧道套接字,该套接字应绑定到本地地址和本地隧道ID。还未连接插座。
  4. 准备SCCRQ消息。应使用L2TP标头中的隧道ID 0将其发送给对等方。为此,您需要使用sendto(2)语义。
  5. 等待来自对等方的SCCRP。收到SCCRP后,您需要将套接字连接到SCCRP消息中“分配的控制连接AVP”中调出的隧道ID。
  6. 发送SCCCN。
  7. 等待SCCCN被确认。收到SCCCN ACK后,请使用L2TP Genl套接字使用控制协议交换中的隧道ID创建内核隧道上下文。

据我了解,进一步的通信将通过第二个标准套接字,并且隧道ID零仅接收SCCRQ

是的。认为隧道ID为零的套接字的一种方法是类似于您listen(2)用于HTTP服务器的套接字。套接字的目的是接收对知名端口的请求,随后的消息交换将通过不同端口上特定于连接的套接字进行。

当然IP没有端口,但是零隧道ID对于L2TPv3 IP封装服务器起着相同的作用。