123456789888888888888
使用OpenVPN时,有几点需要注意: 1.如果不是OpenVPN客户端将自己的虚拟IP地址作为源地址发出的数据包,而是由其forward的数据包,那么就要在数据进入虚拟网卡之前做一个SNAT了,否则OpenVPN服务器将会拒绝接收这种数据包; 2.如果使用的是tap虚拟网卡模式,那么一定要将OpenVPN服务器的虚拟ip设置成网关而不能仅仅设置一个出口设备,因为tap模式需要进行arp,如果目的地址不在OpenVPN服务器上或者即使在OpenVPN服务器上但是其arp_ignore设置了不同的值,arp都会不成功进而无法发送数据; 3.在开启了client-to-client的情况下并且使用tun模式时,不要以为所有的client和server均在同一子网内,tun是点对点的,没有子网的概念,所以一个client或者其后的主机为了访问另一个client c2后面的资源,不能将网关设置成c2,除非做复杂的源/目的地址转换,因为OpenVPN服务器将不认识c2后面的目的地址。 4.如果使用tap模式,并且开启了c2c,那么所有的client连同server共同组成一个虚拟子网,内部arp可流通,作为一个虚拟以太网和真实的以太网是一样的,OpenVPN服务器就是一个以太网交换机,可以设置任意的client或者server作为网关,这个意义上,OpenVPN服务器是一个三层交换机。 具体的代码都在multi_process_incoming_link中: bool multi_process_incoming_link (struct multi_context *m, struct multi_instance *instance, const unsigned int mpp_flags) { struct context *c; struct mroute_addr src, dest; unsigned int mroute_flags; struct multi_instance *mi; bool ret = true; ... if (BLEN (&c->c2.buf) > 0) { process_incoming_link (c); //此操作进行解密,vpn作为客户段来说只调用这一个函数而不进行下面的地址判断 if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TUN) { mroute_flags = mroute_extract_addr_from_packet (&src, //从ip数据报中解析出源/目的ip地址 &dest, NULL, NULL, &c->c2.to_tun, DEV_TYPE_TUN); //确保源ip地址是自己的一个客户端的,这就是说,要在客户端进行源地址转换 else if (multi_get_instance_by_virtual_addr (m, &src, true) != m->pending) { ...//打印错误日志 c->c2.to_tun.len = 0; //不再往虚拟网卡写入 } else if (m->enable_c2c) { ...//多播情况,tun模式下,通过判断ip地址类型设置多播标志,tun没有arp else { //以目的ip地址作为键值查找以目的地址为虚拟地址的自己的客户端,如果没有做目的地址转换的话,此处将找不到任何客户端,最终数据将发往虚拟网卡,等待内核标准路由系统的路由,很可能就发往默认网关了 mi = multi_get_instance_by_virtual_addr (m, &dest, true); if (mi) { multi_unicast (m, &c->c2.to_tun, mi); //向目的地址单播 register_activity (c, BLEN(&c->c2.to_tun)); c->c2.to_tun.len = 0; } } } } else if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TAP) { mroute_flags = mroute_extract_addr_from_packet (&src, //从以太网数据帧中解析出源/目的mac地址 &dest, NULL, NULL, &c->c2.to_tun, DEV_TYPE_TAP); if (multi_learn_addr (m, m->pending, &src, 0) == m->pending) { if (m->enable_c2c) { //以下是广播/多播情况,比如tap模式下的arp就是广播,可以看出mroute_extract_addr_ether处理了arp,设置了多播标志,OpenVPN中,多播和广播统一处理 if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) { multi_bcast (m, &c->c2.to_tun, m->pending, NULL); } else { //下面根据目的mac来判断目的地是否是同一个虚拟子网的,如果是,则将以太帧发过去 mi = multi_get_instance_by_virtual_addr (m, &dest, false); if (mi) { multi_unicast (m, &c->c2.to_tun, mi); //单播发送以太帧 register_activity (c, BLEN(&c->c2.to_tun)); c->c2.to_tun.len = 0; //不再写入虚拟网卡 } } } ... } else { c->c2.to_tun.len = 0; } } } //所有其它情况都将受到的数据包写入虚拟网卡中,一旦写入虚拟网卡以后,数据包的流向就不再受OpenVPN的控制了,而是完全受内核路由表的控制 ret = multi_process_post (m, m->pending, mpp_flags); ... } 在multi_process_incoming_tun中有下面一个判断: multi_set_pending (m, multi_get_instance_by_virtual_addr (m, &dest, dev_type == DEV_TYPE_TUN)); if (m->pending) --->后续处理 这是判断目的地址的有效性,作为OpenVPN服务器来讲,从虚拟网卡中来的数据包就是要发往OpenVPN客户端的数据包,因此需要判断目的地址,和multi_process_incoming_link的判断相反。 结论是:tun模式按照ip地址路由,tap模式按照mac地址路由。在客户端,没有服务器端这么复杂的判断,只是经过“in-tun--out-link-加密,in-link--out-tun-解密”的过程即可