`
totoxian
  • 浏览: 1080690 次
  • 性别: Icon_minigender_2
  • 来自: 西安
文章分类
社区版块
存档分类
最新评论

OpenVPN中虚拟ip地址的分配

 
阅读更多

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隧道建立过程中的第一步。

分享到:
评论

相关推荐

    基于openvpn的web管理系统,前后端分离设计。

    基于openvpn的web管理系统,前后端分离设计。

    openvpn的几种组网方式

    openvpn的几种组网方式

    openvpn 2.5.10版本

    openvpn 2.5.10版本,通过三板斧即可安装,证书生成需要的easy-rsa3.1.5版本也在压缩包里面。

    k8s上部署openvpn

    openvpn 服务端需要的文件,通过helm 3 部署

    Win10系统—VPN连接无法启动虚拟网卡任务.pdf

    Win10系统—VPN连接无法启动虚拟网卡任务.pdf

    open-build-master+Open虚拟专网2.5源代码+依赖项源代码

    与原版open-build-master相比,我做了稍稍修改,已经包含Open虚拟专网2.5源代码和依赖项源代码,需要VS2019、ActivePerl、WDK10,可以直接按照我写的教程进行编译,100%可编译。

    同一个IP地址,在windows上能用,但是在linux下不能用,原因是,如何解决.zip

    在Windows和Linux操作系统中,IP地址的使用和网络连接的管理方式有所不同,这可能是导致问题的原因。以下是一些相关的知识点: 1. **IP地址原理**:IP地址是互联网上的唯一标识,用于在网络中定位设备。它遵循TCP/...

    IP地址精确查询 能精确到门牌号

    此外,由于ISP路由策略的改变或用户使用虚拟私人网络(VPN),IP定位的准确性可能会受到影响。因此,在使用IP定位技术时,需要遵守相关法律法规,尊重用户隐私,并考虑到技术的可能误差。 总的来说,IP地址精确查询...

    中国电信IP地址备案表格

    填写完毕后打印盖章交到当地电信即可,公司里有专线的最好备案一个,如果没有域名也可以备案,这个是IP地址备案哦,不备案影响你的VPN系统登录。你的域名要在申请的地方备案,例如阿里。两个地方都要备案。

    网络系统管理赛项软件包

    它们负责网络中的命名解析、IP地址分配以及文件共享等功能。通过这些服务模块,管理员可以有效地管理和维护网络环境,确保服务的稳定性和安全性。 2. **普通PC软件包**:这部分可能包含常用的操作系统(如Windows或...

    IP——-地址随意换工具

    这种工具可能通过代理服务器、虚拟私人网络(VPN)服务或者动态主机配置协议(DHCP)来实现IP地址的切换。 标签“ip”明确了讨论的主题,与IP地址及其相关的技术紧密相关。 文件“IP地址随意换.au3”表明这是一个...

    inode配置及报错解决方法

    12. **IP地址问题**:IP地址随机分配,不同地址段不影响网络访问。 遇到网络连接问题时,可以参考这份指南进行自我排查,如设置IP地址,检查网络客户端安装等。如果问题仍然存在,应及时联系网络与信息管理中心获取...

    e语言-易语言IP自动更新

    在现代网络环境中,动态IP地址分配是一个常见的需求,尤其在企业网络中,为了节约有限的公网IP资源,通常会使用DHCP(Dynamic Host Configuration Protocol)服务来动态分配IP地址。IP自动更新程序能够帮助用户在IP...

    Tap-Windows Adapter 虚拟网卡

    Tap-Windows Adapter 虚拟网卡 vpn 多联 神器

    Java获取客户端真实IP地址过程解析

    在上面的代码中,首先通过x-forwarded-for请求头获取客户端IP地址,然后将其分割以获取第一个IP地址,哪个就是客户端真实IP地址。 此外,还有其他方法可以获取客户端真实IP地址,例如通过Proxy-Client-IP、WL-Proxy...

    计算机通信中虚拟现实技术的应用.pdf

    2. **基于IP网络的专用数据网络,如IP-VPN**:虚拟现实技术在IP网络上的应用,可以构建专用数据网络,如IP虚拟私有网络(IP-VPN)。这些网络允许用户在虚拟环境中进行安全的数据传输和通信,为远程工作、协同设计和...

    易语言获取外网ip5种方法

    易语言中可以通过网络组件调用这些接口,获取返回的JSON数据,然后解析JSON以获取IP地址。 4. **P2P技术** P2P技术中,节点之间可以直接通信,可以通过向其他节点询问自身的IP来获取公网IP。在易语言中实现P2P通信...

    XenDesktop虚拟桌面规划

    DHCP 服务器负责 IP 地址的动态分配。在企业环境中,可以启用 DHCP 服务器上的多播作用域和 option 66,67。 DDC 服务器 DDC 服务器是虚拟桌面交付的基础架构服务器,负责分配桌面给授权用户访问,设定访问策略等。...

    配置DHCP服务***************

    总结,配置DHCP服务是Windows 2008网络服务的重要组成部分,它能有效地管理网络中的IP地址分配,减少管理负担,提高网络效率,并为其他关键服务如DNS、Web、FTP和RAS/VPN等提供支持。正确配置和管理DHCP服务是构建...

    计算机通信中虚拟现实技术的运用.docx

    IP虚拟专用网(IPVPN)是另一种虚拟现实技术在计算机通信中的应用示例。IPVPN利用现有的互联网基础设施来构建一个安全的虚拟网络环境。它通过加密技术保护数据的安全传输,使得不同地理位置的用户能够像在同一网络内...

Global site tag (gtag.js) - Google Analytics