DIY——共享上网(NAPT)
Write By richardwang
Mail : linux_ace@163.com
Date :2012-05-27
写在前:此博文纯属个人饭后所写,因精力能力所限,必定存在诸多不足和缺陷,甚至有些观点或知识点太过片面或者理解偏差导致错误,尽请见谅,欢迎各位博友提意见或建议,一起探讨学习,若转发请注明出处,TKU,^_^。
背后的故事
我们生活场所一般网络接入数量有限制,可能只有一个接口接入或者少数几个,此时可能你有电脑却无法上网的烦恼,当然现在很多系统如Windows/Linux自身提供了一些共享上网的方法,你可以轻松解决眼下的难题,如通过配置设置NAT模式上网,这确实是可以的。但你可能是一个喜欢挑战或者喜欢自己DIY来解决问题的人,这里就NAT技术共享上网的一个分支“端口地址映射技术”介绍一种适合自己闲暇DIY的双网卡共享上网技术,与大家分享,也许对于喜欢DIY又不太了解其具体原理或流程的你会有一定的帮助,不过对于技术大牛这就是十足烂文了,定位很低,o(∩_∩)o 哈哈,希望各位朋友指正或者一起探讨,o(∩_∩)o 哈哈。
注:这不是一种什么新奇的技术,其实早已有了,只不过很多都是大致的原理介绍或者相关的实现产品,不能窥探其具体实现,此文结合自己学校时代自己动手实现的一个双网卡共享上网软件NAPT具体介绍一下其实现过程,很多图文可能不够专业具体或者甚至有一定的错误,不过相信大致还是能描述清楚的,因时间等多方面的原因缺陷肯定很多,一些细节可能不是很到位,请各位朋友见谅o(∩_∩)o 哈哈。
远大的目标
闲暇之余,通过你得双手DIY出一款能够在双网卡主机实现数据包截获,地址映射并从指定网卡转发的小软件,实现内网用户共享合法ip上网的目的。
神秘面纱
共享实际上就是将私有网络数据包ip头部伪造为合法的ip头部,重组内网数据包,已达到私有网络主机访问远程Internet的目的,即已经很成熟的NAT技术(Network Address Translation,网络地址转换)。
NAT的实现方式有三种,即静态转换Static Nat、动态转换Dynamic Nat和端口多路复用OverLoad。
端口多路复用(Port address Translation,PAT)是指改变外出数据包的源端口并进行端口转换,即端口地址转换(PAT,Port Address Translation).采用端口多路复用方式。内部网络的所有主机均可共享一个合法外部IP地址实现对Internet的访问,从而可以最大限度地节约IP地址资源。同时,又可隐藏网络内部的所有主机,有效避免来自internet的攻击。因此,目前网络中应用最多的就是端口多路复用方式。
本文主要介绍通过端口地址转换,共享一个合法ip实现共享上网,因此对于另外两种方式不做介绍,有兴趣的朋友可以Google相关介绍,o(∩_∩)o 哈哈偷懒了。
DIY所需特技
硬件要求:计算机主机一台,配备双网卡,一个网卡连接Internet,另外一个网卡连接内部私有网络。
DIY专业技能要求:有一定的软件开发基础,了解或熟悉计算机网络基础知识,对DIY有浓厚兴趣,并有一定的业余时间o(∩_∩)o 哈哈。
面纱后的风景
以一台配置双网卡的普通PC机扮演路由角色,网卡NIC1连接内网,无法访问Internet,网卡NIC2连接外网,可以访问Internet,在该host上运行自己DIY开发出来的网络地址转换软件,此处暂命名为NAPT Core,此时PC即被改造为一个简易route了,内网主机可通过该主机访问internet。具体的实现机制和访问流程将在后续介绍。NAPT整体架构如下图所示。
软件构架
NAPT软件主要组成构架图如下:
从图大致可看出共享软件主要由两部分组成,运行于用户态的模块实现了共享软件的核心逻辑,如数据帧重组,地址转换,映射表维护等。运行于kernel模块(可能有些其他实现不在这一层)的模块主要完成链路层数据帧截获与发送。我们DIY的主要任务是通过第三方库或者系统自带一些功能接口捕获链路帧,并实现用户层的共享软件模块。不在kernel层做文章是否听起来就简单很多了呢,对DIY实现的担心减少了不少对吧,o(∩_∩)o 哈哈。
整个实现的关键就是让数据按照红线和绿线的方向传输,完成这个整个软件已经实现大半了,丷哈。
NAPT Core实现关键技术
共享软件的核心主要包括数据链路帧的截获,通过指定网卡转发链路帧,以及重新构造ip头部共享外网的合法ip,并且动态构建、维护一张端口地址映射表(内网请求包构建表项,外网响应包查询表项)以用于请求包和响应包的重新构建封装,可以类比路由器的路由表,o(∩_∩)o 哈哈,当然木有那么复杂,具体介绍如下。
关键技术一——链路帧截获
共享软件实现的第一步是要解决如何获取链路帧(木有处理过的包含MAC头部的原始数据帧)?
关于这一点,Windows/Linux等系统各有神兵利器来解决这一难题,下面将大致介绍一下DIY将如何克服这一难题。
其实不同的系统实现链路帧的整体思想都大同小异,就是链路帧向上层协议提交时不走寻常路,不经过其上层的协议层处理,直接通过内核提交到用户层。
1)Windows比较保守,不过实现也不麻烦,有第三方库帮我们完成链路帧的截获(o(∩_∩)o 哈哈够简单吧,装个第三方库就搞定),比如知名的WinPcap开源库,安装此库,并通过其导出的pcap_xxx等一系列API即可获取到链路帧了,当然还有其他方式,比如通过WinNetCatchWork驱动开发库也可以实现,通过导出的ndis_xxx等API可以达到相同的目的,WinNetCatchWork的不同点是需要显示安装一个nids驱动程序(有源码的哦,你也可以直接倒腾驱动程序在内核层实现所有的功能,哈哈)。
注:WinNetCatchWork是一个校园开源作品,你可以通过http://home.cuit.edu.cn/Js/PZ7/GRT/winnetcatchwork/default.htm这里获得,算是打广告吧,我和几个同学在学生时代做的,o(∩_∩)o 哈哈。
2)Linux相对就开放许多了,整个kernel都是开源的,你可以在kernel实现你需要的所有功能,当然也可以在用户层实现核心功能,通过类似的LibPcap实现链路层数据帧的截获,Linux还提供了直接通过socket原始套接字的方式截获链路层数据帧,强大吧,如果你熟悉socket编程,那相当于你已经可以直接开始干了,o(∩_∩)o 哈哈。
关键技术二——地址映射共享外网IP
链路帧截获的难题搞定了,现在该真正进入正题,如何共享外网合法ip地址实现共享上网呢?
端口地址隐射实现共享上网的思想其实很简单,前面已经略有提及,即将内网请求帧的目的mac地址替换为外网网管的mac地址,目的ip替换为外网网卡配置的合法ip地址,同时为映射的数据帧分配一个唯一的映射端口,重新封装一下这个数据帧即可,其帧结构转换的大致示意图如下:
将转换好的数据链路帧通过指定网卡转发出去,该数据帧即可发送到远程目的主机了,不过这里还木有完成,整个过程还只完成了1/3,o(∩_∩)o 哈哈。想想为什么呢?
数据帧发送出去了,那远程主机的响应帧回来,我们肿么提交给内网的主机呢,o(∩_∩)o 哈哈,是的,我们还需要完成很重要的一步,根据转发至外网的数据帧构建端口地址映射表,其映射表的大致组成示意图如下:
现在响应数据帧回来就有据可查了,这样响应数据帧就可以找到回家的路了,看起来是不是很简单呢,o(∩_∩)o 哈哈。
当响应数据帧返回双网卡目标主机,链路帧被截获到之后,共享软件具体肿么知道链路帧应该怎么提交给内网的哪台主机呢,很简单,前面请求包构建了一张简单的地址映射表,现在派上用户醋疗,是的,类似路由器一样,查表获取目的主机地址。
根据响应数据帧的协议类型、目的端口号(映射的端口VPort)查询地址映射表,若无法找到表项,这直接丢弃,否则根据表项重新构建数据帧,从内网网卡转发数据帧至内网主机,其逆映帧封装示意如下:
是不是很简单呢,你DIY出来的共享软件只需完成链路帧重组,构建地址映射查询表,从指定网络设备转发即可实现内网主机访问外部公共网络的目的,足够简单,适合DIY,心动了把,赶快行动,so easy,......o(∩_∩)o 哈哈。
千里之行始于足下,剩下的工作就要靠你来了,o(∩_∩)o 哈哈,自己DIY其乐无穷。如果你觉得这个双网卡共享上网太过简单,你可以充分发挥你的想象,逐步完善,将其做成一个拿得出手的产品也是有可能的,比如NAT主机支持多网卡,每个网卡连接不同的网段,NAPT软件支持不同的协议,这样NAPT主机就成了一个货真价实的路由器了,o(∩_∩)o 哈哈,一切皆由你来掌控,发挥你的想象力把,o(∩_∩)o 哈哈。