server将topology推送至client,这就是为何必须实现net30模式的原因,就是为了兼容windows,由于windows的低版本tap-win32驱动只支持这种模式,而后的topology为p2p(实际上windows的tap-win32驱动通过简单修改,比如改掉自问自答的那一部分逻辑看上去也支持这种拓扑,但是如果涉及到dhcp,事情就复杂了,因为通过net30拓扑分给windows的两个主机ip中有一个会充当虚假的dhcp服务器,如果在windows上采用了p2p拓扑,那么tap-win32网卡将直连server的虚拟网卡,而server的虚拟网卡可不敢担此大任),对于server来讲,没有什么变化,只是对于client来讲,解放了ip的占用,但是client必须是非windows的,不过server倒是可以是 windows,因为对于net30和p2p而言,server端的虚拟ip地址是一样的,不同的是对client的影响
vpn服务器中有一个ifconfig_pool结构体用于保存ip地址池的重要信息:
struct ifconfig_pool
{
in_addr_t base; //初始ip地址
int size; //pool的大小,也就是容量,即能同时分配给几个client
int type; //指示topology
bool duplicate_cn;
struct ifconfig_pool_entry *list;//每一个pool保存一个链表,用于遍历和查找,每次分配和释放时要用
};
服务器启动的时候首先要初始化ip地址的pool,用于以后为连接的客户端分配ip地址,在multi_init有以下代码:
if (t->options.ifconfig_pool_defined) {
if (dev == DEV_TYPE_TAP) { //tap模式的初始化
m->ifconfig_pool = ifconfig_pool_init (IFCONFIG_POOL_INDIV,
t->options.ifconfig_pool_start,
t->options.ifconfig_pool_end,
t->options.duplicate_cn);
} else if (dev == DEV_TYPE_TUN) { //tun模式的初始化
m->ifconfig_pool = ifconfig_pool_init (
(t->options.topology == TOP_NET30) ? IFCONFIG_POOL_30NET : IFCONFIG_POOL_INDIV,
t->options.ifconfig_pool_start,
t->options.ifconfig_pool_end,
t->options.duplicate_cn);
}
...
}
struct ifconfig_pool *ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn)
{
struct gc_arena gc = gc_new ();
struct ifconfig_pool *pool = NULL;
pool->type = type;
pool->duplicate_cn = duplicate_cn;
switch (type) {
case IFCONFIG_POOL_30NET://兼容诸如windows的tap-win32之类驱动,每次分配4个ip地址,当中除去一个网络地址一个广播地址,仅剩下两个可用,这就是tap-win32网卡的本地地址和虚拟出来的远端地址(详情可见arp自问自答)
pool->base = start & ~3;//252掩码模式中,ip分配是按照4个一组分配的,因此要按4对齐
pool->size = (((end | 3) + 1) - pool->base) >> 2;//最后要除以4,因为4个ip一组
break;
case IFCONFIG_POOL_INDIV://其余的模式就是实打实得分配,是几个就是几个
pool->base = start;
pool->size = end - start + 1;
break;
...
}
...
}
static void multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
{
struct gc_arena gc = gc_new ();
...//省略从文件中导入ip地址,只看动态分配
else if (m->ifconfig_pool && mi->vaddr_handle < 0) {
in_addr_t local=0, remote=0;
const char *cn = NULL;
if (!mi->context.options.duplicate_cn)
cn = tls_common_name (mi->context.c2.tls_multi, true);
mi->vaddr_handle = ifconfig_pool_acquire (m->ifconfig_pool, &local, &remote, cn); //见下面分析
if (mi->vaddr_handle >= 0) {
const int tunnel_type = TUNNEL_TYPE (mi->context.c1.tuntap);
const int tunnel_topology = TUNNEL_TOPOLOGY (mi->context.c1.tuntap);
mi->context.c2.push_ifconfig_local = remote; //无论如何都要将从pool中找到的ip地址给与client,余下的client虚拟网卡的配置信息还差两个,如果是net30或者p2p拓扑的话,需要一个“对端”地址,如果是subnet拓扑的话,需要一个子网掩码,故push_ifconfig_remote_netmask的含义就是既可以表示“对端”地址又可以表示子网掩码
if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) {
//对于subnet来讲,最简单,直接将从pool中找到的ip地址分配给client,然后将自己的子网掩码给client的子网掩码
mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.ifconfig_pool_netmask;
if (!mi->context.c2.push_ifconfig_remote_netmask)
mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->remote_netmask;
} else if (tunnel_type == DEV_TYPE_TUN) { //只有tun模式拥有topology的概念
if (tunnel_topology == TOP_P2P) //对于p2p来讲,直接将server端虚拟网卡的ip给client作为ifconfig命令pointopoint的另一端,注意client不能是windows这种多事又麻烦的系统
mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->local;
else if (tunnel_topology == TOP_NET30) //对于net30来讲,
mi->context.c2.push_ifconfig_remote_netmask = local;
}
if (mi->context.c2.push_ifconfig_remote_netmask)
mi->context.c2.push_ifconfig_defined = true;
...
}
ifconfig_pool_handle ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, const char *common_name)
{
int i;
i = ifconfig_pool_find (pool, common_name); //在所有可用的ip-entry中选择一个索引,注意并不是直接选择ip,选择ip的逻辑在下面。OpenVPN内核将每次分配给client的一系列(一个或者四个)ip地址组织成ifconfig_pool_entry结构体,这样就将ip的分配和topology的配置分离了。该算法很简单,就是遍历链表,然后选出in_use为0的。
if (i >= 0) {
struct ifconfig_pool_entry *ipe = &pool->list[i];
ifconfig_pool_entry_free (ipe, true);
ipe->in_use = true; //设置使用标志
if (common_name)
ipe->common_name = string_alloc (common_name, NULL);
switch (pool->type) {
case IFCONFIG_POOL_30NET: {
in_addr_t b = pool->base + (i << 2); //由于按照4个一组分配,所以要i*4
*local = b + 1; //对于client来讲是remote
*remote = b + 2; //对于server来讲是remote
break;
}
case IFCONFIG_POOL_INDIV: {
in_addr_t b = pool->base + i;
*local = 0; //其余的两种topology,client直连server的实际虚拟ip
*remote = b; //直接将可用的ip地址分配给client,无需再分配一个模拟的server端ip
break;
}
...
}
}
return i;
}
因此,OpenVPN为client端分配ip地址实际上很简单,总结如下:
tun模式:
1.subnet:a.从pool中选择一个ip作为client的虚拟网卡ip;b.将自己的子网掩码作为client的子网掩码。
2.p2p:a.从pool中选择一个ip作为client的虚拟网卡ip;b.将自己的实际虚拟网卡ip作为client的对端ip。
3.net30:a.从pool中选择4个掩码为30的ip,将中间两个ip中的大者作为client的虚拟网卡ip;b.将小者作为client的对端ip。
tap模式:
1.完全按照tun模式的1来分配。
信息一旦被push到了client端,client就会打开虚拟网卡设备,并且初始化之,然后会按照server端push过去的信息进行虚拟网卡的配置,最终调用do_ifconfig完成网卡配置,在这最后一步中,需要按照不同的OS进行不同的定制,可以想见,windows还是最多事最麻烦的,事实证明正是如此。
可以看到,ip地址的分配逻辑主要在multi_select_virtual_addr中进行,可是multi_select_virtual_addr是在何时被调用的呢?不考虑复杂的情况,最基本的是在multi_connection_established中被调用的,而multi_connection_established则是在client连接到server的时候被调用的。client连接server的时候,首先要进行TLS/SSL握手,这个过程在tls_process中进行,一旦成功将会调用link_socket_set_outgoing_addr,之后逐步地到达multi_connection_established,由此可见,隧道是在TLS握手成功之后才建立的,隧道的建立和client的虚拟网卡被初始化是同时进行的。tls_process是在check_tls的路径中被调用的,而check_tls则是vpn隧道建立过程中的第一步。
分享到:
相关推荐
与原版open-build-master相比,我做了稍稍修改,已经包含Open虚拟专网2.5源代码和依赖项源代码,需要VS2019、ActivePerl、WDK10,可以直接按照我写的教程进行编译,100%可编译。
Windows11 装不了虚拟网卡,可能可以帮助您解决问题
Win10系统—VPN连接无法启动虚拟网卡任务.pdf
同一个IP地址,在windows上能用,但是在linux下不能用,原因是,如何解决.zip
填写完毕后打印盖章交到当地电信即可,公司里有专线的最好备案一个,如果没有域名也可以备案,这个是IP地址备案哦,不备案影响你的VPN系统登录。你的域名要在申请的地方备案,例如阿里。两个地方都要备案。
Tap-Windows Adapter 虚拟网卡 vpn 多联 神器
网络系统管理赛项软件包(服务模块软件包、普通PC软件包、无线地勘系统等)
2.1MPLSVPN技术在计算机网络安全中的应用 MPLSVPN技术说的就是MPLS技术的实际应用,实质上就是在运营商宽带IP网络中为企业搭建了一个专用IP网络,从而使企业的数据信息在跨地域传输过程中更加的安全,并且该项技术...
一个基于DELPHI的远程屏幕传输(差异截图)
根据本人运维经验,结合openVPN社区相关案例,针对TAP-Windows-adapter安装失败“an error occured installing the TAP device driver”错误提示,提出五种解决方案
vpn-instance的原理是将一台物理设备虚拟成多个虚拟设备,并将相应的物理接口分配至虚拟设备中使用,从而实现每个虚拟设备之间及和根物理设备之间完全隔离。并且每一个逻辑设备之间都是相互独立的,使用自己独立的...
Book Description Angular 2 introduces an entirely new paradigm of applications. It wholly embraces all the newest concepts that are built into the next generation of browsers, and it cuts away all the...
第一章 路由器配置基础 一、基本设置...二、交换机间链路(ISL)协议 三、虚拟局域网(VLAN)路由实例 附录一:Cisco路由器口令恢复 附录二:IP地址分配 附录三:Cisco 路由配置语句汇总 附录四:Cisco VPN连接配置实例
IP地址分配的方式 静态地址分配 给网络中每台计算机、网络设备分配一个固定的、静态不变的IP地址 提供网络服务的网络设备,如WEB服务器、邮件服务器、FTP服务器等服务器,一般为其分配静态IP地址 动态地址分配 在...
4.1 网络层提供的两种服务 4.2 网际协议 IP 4.2.1 虚拟互连网络 4.2.2 分类的 IP 地址 4.2.3 IP 地址与硬件地址 ...4.7 虚拟专用网 VPN 和网络地址转换 NAT 4.7.1 虚拟专用网 VPN 4.7.2 网络地址转换 NAT
交叉编译器3.4.5,下载解压,按照交叉编译器安装过程安装。
安装OpenVPN 保护OpenVPN 在局域网中安装Orthanc ? 先决条件 Ansible> 2.5 Ansible> 2.9(用于SSH-sec角色) 在客户端计算机和服务器计算机之间已正确配置SSH身份验证。 安装 克隆项目并安装角色: git clone...
win10mi版+Linux CentOS-7+苹果系统驱动加满的无敌合集
Angular 2 Cookbook Angular 2 Cookbook Angular 2 Cookbook
ARM9平台上的嵌入式Linux系统移植研究