问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

VPN原理入门(非常详细)从零基础入门到精通,看完这一篇就够了

创作时间:
2025-03-17 10:22:57
作者:
@小白创作中心

VPN原理入门(非常详细)从零基础入门到精通,看完这一篇就够了

引用
CSDN
1.
https://blog.csdn.net/2401_86436868/article/details/142168849

VPN(虚拟私人网络)是一种用于连接中、大型企业或团体间私人网络的通讯方法,利用隧道协议(Tunneling Protocol)来达到发送端认证、消息保密与准确性等功能。本文将从TUN/TAP设备入手,逐步理解VPN中的技术细节,并结合simpletun源码进行原理验证。

0x01 VPN是什么

VPN全称为虚拟私人网络(Virtual Private Network),常用于连接中、大型企业或团体间私人网络的通讯方法,利用隧道协议(Tunneling Protocol)来达到发送端认证、消息保密与准确性等功能。

比如多地办公的公司,可以使用VPN将不同地区连接在同一内网下;或者在家办公的时候也可以通过VPN接入公司内网中。

VPN以CS架构运行,工作流程如下:

  1. VPN工作流程

在外网的用户可以使用VPN client连接组织搭建的VPN server以建立通信隧道,随后便建立了虚拟的私人网络,处于外网的worker和内网中的server可以相互通信。

那么我们可以简单理解VPN,由VPN client捕获用户发出的报文,封装报文后通过物理网络通信链路将报文发给VPN server,VPN server接收到报文后进行解包,再将其转发给实际的目标,反之同理;VPN在逻辑层面构建了虚拟网络。

0x02 TUN/TAP

那么在代码层面VPN是如何实现的呢?我们可以先来看看TUN/TAP。

TUN/TAP是操作系统内核中的虚拟网络设备,由软件进行实现,向操作系统和应用程序提供与硬件网络设备完全相同的功能。其中TAP是以太网设备(二层设备),操作和封装以太网数据帧,TUN则是网络层设备(三层设备),操作和封装网络层数据帧。

当应用程序发出报文后,报文将通过操作系统协议栈处理,到达网络设备,硬件网络设备将收到的报文转化为电信号发出,而虚拟网络设备(TUN/TAP)不具备实际的物理功能,报文需要上层应用进行处理,如下:

硬件/虚拟网络设备

我们直接使用命令创建TUN/TAP设备,并进行测试:

# ip tuntap 创建名为 tun0 的 tun 设备
sudo ip tuntap add dev tun0 mod tun
# 为 tun0 配置 ip
sudo ifconfig tun0 192.168.0.10 netmask 255.255.255.0
# 查看 tun0 网卡
ifconfig tun0

如下:

通过命令创建TUN设备

在VPN中我们可以借助TUN/TAP来捕获用户发出的报文。

0x03 虚拟通信链路

按照TUN/TAP的工作特性,我们可以编写程序直接读写虚拟网卡(也就是物理网卡实际收发报文的过程),来实现捕获用户数据以及传递用户数据。(TUN和TAP有不同的应用场景,下文我们将以更简单的TUN作为例子)

随后,位于不同主机上的程序通过socket进行通信,将从虚拟网卡的接收的数据通过socket发送给对端,这就是一个VPN的雏形了,如下:

虚拟通信链路工作流程

simpletun是这种方案的最小实现(源码仅300+行,感兴趣的小伙伴可以自行学习),在源码中实现了创建虚拟网络设备以及socket通信,借助simpletun可以帮助我们快速进行验证。

需要注意一点,simpletun启动后需要我们手动配置虚拟网卡的ip地址,当ip地址未配置时,两端相互发送数据(部分操作系统会自动发送)会造成程序异常退出,所以在代码中添加一个sleep(30)便于我们配置ip地址:

在simpletun中添加sleep

在两台Ubuntu测试环境下配置并进行验证:

# A主机
# 编译 simpletun
gcc simpletun.c -Wall -o vpn
# 作为 vpn server 启动,并开启 debug,默认监听 55555
sudo ./vpn -i tun0 -s -d
# 配置 tun 网卡地址
sudo ifconfig tun0 192.168.0.10 netmask 255.255.255.0
# B主机
# 编译 simpletun
gcc simpletun.c -Wall -o vpn
# 作为 vpn client 启动,连接 server,并开启 debug
sudo ./vpn -i tun0 -c 10.11.33.50 -d
# 配置 tun 网卡地址
sudo ifconfig tun0 192.168.0.11 netmask 255.255.255.0

此时两台主机位于192.168.0.0/24虚拟网络网段下,可以相互通信,如下:

虚拟通信链路两端通信

0x04 访问内网网段

在上文的验证中,我们可以实现两端的虚拟网络搭建和通信,但实际VPN的使用场景是需要通过VPN访问整个内网网段,在这种使用场景下,VPN server至少配置有两张物理网卡,其中一张接入内网网段,另一张则连接到互联网。

按照0x03虚拟通信链路的链路,VPN client发送报文到内网主机,VPN server接收到该报文后,将其写入到虚拟网卡中,随后报文进入TCP/IP协议栈,但是由于IP地址不是VPN server自己,该报文会被丢弃,无法正常进行通信;这里我们需要借助「报文转发」,将内网报文从虚拟网卡转发到内网网卡上。其新的工作流程如下:

VPN访问内网网段

VPN server一般会作为内网网关,内网主机无需任何额外配置就可以在虚拟网段下正常工作。

我们按照该流程配置测试环境,复用0x03虚拟通信链路中的环境,在VPN server上我们使用docker模拟内网网段和主机,其环境搭建如下:

VPN测试环境搭建

然后按照0x03虚拟通信链路中的方式,启动simpletun并使用ifconfig配置ip地址,创建虚拟通信链路;使用如下命令开启报文转发:

# 临时开启报文转发
echo "1" > /proc/sys/net/ipv4/ip_forward

实际上在该测试环境下,docker会自动开启报文转发

再通过iptables配置转发策略,如下:

# 将入口网卡、来源ip为 192.168.0.0/24 转发至 docker0
sudo iptables -A FORWARD -i tun0 -s 192.168.0.0/24 -o docker0 -j ACCEPT
# 将入口网卡、目的ip为 192.168.0.0/24 转发至 tun0
sudo iptables -A FORWARD -i docker0 -d 192.168.0.0/24 -o tun0 -j ACCEPT

实际上在该测试环境下,第二条可以不用配置,因为docker会自动配置转发策略,会覆盖这条策略

除此之外,为了在VPN client可以访问到内网主机,需要手动添加路由:

# VPN client 添加内网网段路由,设置为虚拟网络设备 tun0
sudo route add -net 172.17.0.0/24 tun0

此时VPN配置完成,内网主机和VPN client相互连通:

内网主机访问以及验证

0x05 拓展

上文中我们使用最小实现验证了VPN的工作原理,但是实际场景却比这个复杂很多,这里我们简单抛出一些问题作为拓展学习。

  1. VPN作为网关?
    VPN server一般作为网关进行配置,内网主机不用进行额外配置,也可以把报文发送给VPN server。

  2. UDP通信链路?
    在simpletun中VPN server和client之间使用TCP进行通信,但是在实际场景一般使用UDP进行通信。

当使用TCP作为通信隧道时,并且上层应用也使用TCP,也就是tcp in tcp,当出现丢包时,上层应用的TCP和VPN通信隧道的TCP都会进行重传,从而通信中出现大量的重传报文,降低通信效率;如果在这种情况下,以UDP作为通信隧道,tcp in udp,丢包后将只由上层应用的TCP进行重传。

  1. etc

0x06 总结

最后感谢rook1e@知道创宇404实验室小伙伴同我一起学习和研究,解决了诸多问题。

本文从VPN原理出发,介绍了关键作用的TUN/TAP虚拟网络设备,并结合simpletun创建了两端的虚拟通信链路,最后配合报文转发,实现并验证了VPN的通信工作原理。

VPN的实现较为简单,但涉及到各种细枝末节的网络知识;这里的最小验证,可以为我们实现更为复杂的VPN或基于VPN技术的其他项目提供参考。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号
VPN原理入门(非常详细)从零基础入门到精通,看完这一篇就够了