之前我们说了,在一个局域网内打游戏,但是不能真正的上网仍然让人感觉到不爽,于是希望可以真正的上网,而终于有了一个校园网的IP,这个IP是一个更大的局域网内得IP,覆盖了整个校园,而我们宿舍内是更小的网络,校园网的ip假设是10.10.X.X;宿舍网的IP假设是 192.168.1.X
我们如何在宿舍连上校园网进行上网呢?
第一个办法,再买一个网卡,插在宿舍长的电脑上,这样宿舍长的电脑就有两个网卡,一个网卡连宿舍内得交换机,另一个连着是校园网的网口,如果这张新的网卡的IP地址要按照校园网的IP去配置,这种情况下,我们需要一直开着宿舍长的电脑
或者第二种方法,买个路由器,路由器当时会有内网网口和外网网口,将外网网口的线插到校园网口上,然后将这个外网的网口配置和网管部的一样,内网的随便连宿舍的电脑,这种情况下,上网只需要开着路由器就可以了
其实两种方法的内在都是一样的,第一个方法只不过是将路由器的功能换成了宿舍长电脑罢了
在宿舍长能够上网后,就是其他人的电脑怎么上网了,需要配置自己的网卡,当然Ip可以使用DHCP设置,但是除了IP,还需要设置一个Gateway的东西,就是网关
配置完成网关的设置之后,就能够跨网关访问了,但是这其中会涉及到MAC和IP的变化
所以我们需要将MAC和IP的细节详细的说下
mac头里面,先是mac地址,然后是源mac地址,然后有一个协议地址,这里面说明了是IP协议,IP里面有版本号,说明是IPV4.然后服务类型TOS说了,表明权重的,TTL说了,每过一次中转就减一的
然后还有IP层的协议,说明了下一层是TCP还是UDP,最重要的就是源ip和目标ip,先是源ip,后是目标ip
任何一个机器,访问另一个ip的时候,都先判断,这个目标ip地址,和当前的ip地址,是否是一个网段内,这需要用到CIDR和子网掩码,这个第三节讲到了
如果是同一个网段,比如旁边的兄弟的电脑,这就没网关什么事情了,将源地址和目的地址放在IP头内,查找对应的MAC地址,如果找不到,ARP协议吼一嗓子,获取了MAC地址,发送出去
如果不是一个网段,就需要发送到默认的网关上,然后Gateway的往往和源IP地址是一个网段,往往是该网段的第一个或者第二个地址
那么这个发往网关的过程,和发往其他机器的过程一直,就是讲源地址和目标地址放进去,然后获取到MAC地址,然后发送出去,网关怎么做,就是网关的事情了
那么我们就说说网关,其实往往是一个路由器,是一个三层转发的设备,其可以取出MAC层和IP层的数据,然后看里面的内容,要转发到哪里去
在这个场景下,网关就是宿舍长的电脑,一个路由器往往有多个网口,一个服务器做转发的事情,就是会有多个网卡,其中一个网卡和源ip同网段
路由器从本质上来说,是一个设备,有五个网口或者网卡,分别连着5个局域网,每个网口的ip和局域网的ip地址有着相同的网段,每个网口也是对应的局域网的网关
任何一个想要发给别的局域网的包,都会先到一个网口,然后获取到对应的MAC和IP,然后进行计算后,选择别的网口,发送出去
那选择哪一个网口,对于IP头和MAC头怎么处理,这就是一个新的问题,对于这个问题,我们可以分为两类来看其是如何处理的,一类是静态路由,一类是动态路由,我们先说下静态路由
静态路由,主要是在路由器上,配置了一条条的规则,就是想要访问BBS站,要从2口出去,然后下一跳是ip2,想要访问视频中心,从3口出去,下一跳是ip3
每当来了个新包并选择从那个口出去的时候,就要一条条的选择规则,找到合适的,然后从某个口抛出去,到下一跳
对于IP和MAC的转换关系
可以分为了两个类型,一种是IP不变”欧洲十国行” ,一种是IP改变,”玄奘西行”
因为在整体的过程中,IP很少变化,但是每过一个关卡,MAC都会改变,对于IP不变的网关,我们称呼为转发网关,对于IP改变的网关,我们称为NAT网关
首先是欧洲十国游型
服务器A去访问B,那么A会思考,因为不是本网段的,所以会先发给网关,那么网关收到了这个包,这个包的格式如下
然后收到了包之后,发现MAC一致,收进来,思考如何转发
因为路由器中定义了静态路由,访问 192.168.4.0/24,需要从192.168.56.1这个口出去,下一跳是192.168.56.2
路由器会从192.168.56.1这个口发出去,发往192.168.56.2,那么56.2的MAC地址是多少呢?
路由器A发送ARP获取192.168.56.2的MAC地址,然后发送包
然后路由器B就收到了这个路由,发现MAC一致,收了进来,同时思考往哪里发送,在路由表B中配置了静态路由,要访问192.168.4.0/24,需要从我的192.168.4.1这个口出去,而且因为是同一个网段,所以没有下一跳了,于是发送了出去,整个包如下
服务器B收到了这个包,匹配了MAC地址,收了进来
这个过程中可以看出,每到一个新的局域网,Mac都是要变的,但是IP不变,而下一跳就是,将下一个发送的网段IP,获取出来,然后转换为MAC地址,放到MAC头里面
这就好比欧洲十国游,整个过程中,IP的地址不会改变,签证也不会变
IP会变 玄奘西行
在发送包的时候,可能出现的问题是,IP段冲突了,本网段的地址是192.168.1.101,其他的网段的地址也是192.168.1.101,直接看起来,就好比自己访问自己
但是目标服务器会有一个国际身份,我就利用这个国际身份来发送,假设,国际身份是192.168.56.2,这个国际身份对应着一个国内身份 192.168.1.101,所有访问192.168.56.2,转为192.168.1.101
这样,源服务器会发送一个带有国际身份的包去请求服务器B,但是一开始,因为国际身份的包不是本网段的,所以先发给网关,这个网关假设是192.168.1.1,于是发送出去包带着网关的MAC
一开始发送的包如下
然后到了网关,收了进来,思考如何转发
路由器A中配置了静态路由,告诉路由器A,想要访问192.168.56.2/24,就要从192.168.56.1这个口出去,到了同一个网段了,
但是在发送出去的时候,服务器A需要一个国际身份,所以不能拿着192.168.1.101这个源IP发送,需要改写,改写为192.168.56.1,发送了出去
服务器B收到了这个请求,发现MAC一只,收了进来,这是一个NAT网关,配置了访问国际身份192.168.56.2对应国内身份192.168.1.101
然后进行发送给了服务器B
中间经过了ip的转换,源ip为服务器A的国际身份,返回包的时候,也是返回的国际身份,这时候路由器A是NAT网关,进行了身份转变
NAT网关:Network Address Translation 简称NAT
本章小结
如果需要离开局域网,需要一个网关
路由器是一个三层设备,可以获取到下一跳
经过路由器后MAC头要变,但是IP变不变,是看网关是NAT吗?
课后思考
1.在访问163网站的时候,自己的ip,肯定经过了NAT网关变成了公网ip,返回的时候如何返回回来的
2.对于路由规则,我们说了静态设置,如何动态设置呢?
1.其实在真正的转发的时候,Nat路由会借助端口来进行自己专有局域网内得对应的私有IP主机,将一个公网的IP+NAT端口映射称多个内网主机+主机端口,提高了IP利用率,详细点说就是
对于NAT这种直接的映射,很少使用,一般使用的是,NAPT,进行了IP地址和传输层端口改写
对于传出 NAT 路由器的数据包,NAT 根据源 IP 地址和传输层端口号在尽可能保留源端口号的情况下将其转写为 NAT 可用 IP 地址池里的 IP 地址和可用的 NAT 端口,并用 Session(TCP)或者活跃计时器(UDP)的方法来记忆”源IP地址+传输层端口号 <=> NAT IP 地址 + NAT 端口号“的映射。这样,当相应的回复数据包返回 NAT 路由器时,我们可以根据记录信息将 IP 地址和端口号转写回去。
更加具体点的可以解释为
我们说了iptables的时候,说了conntrack功能,记录了SNAT一去一回的关系
如果编译内核的时候开启了连接追踪的选项,Linux系统会为其收到的每一个数据包维持一个连接状态,用于记录这个连接的状态
对于网络包,会存在着三条路径
发给我的,从PREROUTING到INPUT
发给别人,从OUTPUT到POSTROUTING,发送出去
经过的,PREROUTING到FORWARD到POSTROUTING
跟踪一个网络包,对每一个路径,设置两个记录点,打两次卡,内核知道这个包的状态
这三种路径
发给我的,我会在PREROUTING时候调用ipv4_conntrack_in,创建连接跟踪记录,在INPUT中调用ipv4_confim,将这个连接记录挂在内核的连接跟踪表,只有确定接收的,才会记录连接
对于我发出的,会在OUTPUT掉用 ipv4_conntrack_local,创建连接跟踪记录,在POSTROUTING里调用ipv4_confirm,将这个记录跟踪挂在内核的连接跟踪表里
对于从我这里经过的,在PRETOURING调用ipv4_conntrack_in,创建连接跟踪记录,在POSTROUTING中调用ipv4_confirm,将这个连接追踪放在内核的追踪表里
网关的主要工作是转发,主要就好比NAT网关,从我这里经过的,再加上NAT,因而将NAT的过程融入连接追踪的过程中
如果是PREROUTING的话,先调用ipv4_conntrack_in,创建连接跟踪记录
如果是PREROUTING时候,有NAT规则,则调用nf_nat_ipv4_in进行地址转换
如果是POSTROUTING,有NAT规则,调用nf_nat_ipv4_out进行地址转换
涉及跟踪记录,连接跟踪表这两个数据结构
在前面说网络包处理的时候,我们说了每个网络包struct_sk_buff,有一个成员变量 _nfct指向一个连接跟踪记录 struct_nf_conn,当然当一个网络包刚进来的时候,不会指向一个结构的,但是这个网络包必然属于某个连接,会先去连接追踪表中查找,之后赋值给sk_buff这个成员变量,没找到的话,说明是一个新的连接,在连接追踪表里面新创建一个
在nf_conntrack是_nfct变量指向的地址
tuplehash是数组,但是里面只有两个变量,一个是IP_CT_DIR_OPIGINAL为下标0,表示连接发起的方向,IP_CT_DIR_REPLY是下标1,表示连接回复的方向
每当有一个网络包来了,就会将网络包里面的sk_buff中数据提取出来,形成nf_conntrack_tuple,利用里面的内容记算哈希值,然后在哈希表中查找,如果找到了,说明这个连接出现过,没找到则生成一个插入哈希表
通过nf_conntrack_tuple里面的内容,唯一标识一个连接
src:标识源IP,如果是TCP或者UDP,包含源端口,如果是ICMP,包含的是ID
dst:标识目标IP,如果是tcp或者udp,包含目标端口,如果是ICMP,包含type,code
当一个包发出去,到达了这个NAT网关的时候,先经过PREROUTING,调用ipv4_conntack_in,进来的包sk_buff为
{源ip:客户端ip,源端口:客户端port,目标ip:服务端ip,目标端口:服务端port} 将这个转换为nf_conntrack_tuple,然后进行哈希运算,然后查找是否有记录,如果没有就是一个新的连接
于是,创建一个新的连接记录,里面有两个nf_conntrack_tuple_hash
一去:{
源IP:客户端IP,客户端port, 目标IP:服务器IP,服务器port
}
一回{
源IP:服务端IP,服务端port, 目标IP:客户端IP,目标端口:客户端port
}
在进入POSTROUTING的过程,有NAT规则,调用nf_nat_ipv4_out地址,转换,这时候,源地址要变成NAT网关的IP地址,对于masquerade来说,会自动选择一个公网IP和随机端口
为了让包回来的时候,能够找到追踪连接,需要修改两个nf_conntrack_tuple_hash中回来的一项,
{
源IP:服务端IP,源端口:服务端port,目标IP:NAT网关IP,目标端口:随机端口
}
将这个转换为了nf_conntrack_tuple,进行哈希运算,在连接跟踪表里面查找,能找到相对应的记录,找到nf_conntrack_hash之后,可以获取到外面的连接追踪记录,nf_conn,通过这个找到来的方向的那个nf_conntrack_tuple_hash,找到对应的客户端的IP和端口,NAT回去
NAT能建立多少的连接
如果将端口号和IP都转换为公网IP和运算后的端口,端口最多65535个,会有这个上限吗?
SNAT多用于内网访问外网的场景
如果内网机器多,访问的外网不同,导致可以承载的内网数量不止65535个
如果所有的内网都访问同一个目标IP和端口,源IP只有一个,导致受到65535端口数目限制,一种方法就是多种源IP,利用多个NAT网关来分摊内网机器的访问
如果是公有云,65535个机器,放在一个VPC里面,可以做多个NAT网关的设置
nat支持一对一的转换,也支持一对多,如果是一对多的转换,需要维护一张映射的表
内网ip:port -> 外网 ip:port
只要路由器空闲ip足够多就可以了,但是,像是微信这样海量用户长连接的,路由器的port必然不够,如何处理的呢?
对于微信,服务器在数据中心内,无论多少长连接,服务器监听的都是少数的几个端口,是DNAT的场景,不需要担心端口数目,一个服务器也不会维护这么多的连接,因此NAT的网关后面会部署多个Nginx分摊
公网IP和私网IP需要进行意义绑定吗?
如果一个内网有十台机器,但是只有一个公网IP的情况,那么网络中只有一台可以连接外网,其他都连接不了
这个想法必然不对,对于需要对外提供服务的节气,接入层的Nginx需要公网IP,没有公网IP,使用SNAT也行,大家共享SNAT网关的公网IP地址
主要是区分是内网访问外网,还是外网访问内网