p2p穿透原理

今天想写一个p2p传输的工具,正好看到p2p的原理,于是记下来。

 

看下面的图:

A —– 「内网」—– A-NAT —– 「公网」 —– C —– 「公网」 —– B-NAT —– 「内网」—– B

A 和 B 都在私网,是没法直接通信的,这里我们借助C ,C 在公网。

1. 首先A 通过A-NAT 给C 发消息,C 就知道了A 从A-NAT出来的IP/PORT「这里成为映射IP/PORT,IP是公网」;B 也通过B-NAT给C 发消息,C 也知道了B 的映射IP/PORT 。

2. 然后 C 通知 A  B 的映射IP/PORT,通知B A 的映射IP/PORT ,此时A 知道了 B 的映射IP/PORT,B 知道了A 的映射IP/PORT 。

3. 此时A 和 B 不能通信,因为A-NAT 和 B-NAT 上还没有路由session。

这时候,C 发一个消息给B 让 B 给A 的映射IP/PORT 发一个消息,此时B-NAT上就有了session,此时 A 给 B 的映射IP/PORT 发消息,B-NAT 就会转发给B ,A 发消息的时候,A-NAT 上的session 也建立起来了,大功告成。

 

 

构建机房运维基础架构(十一): 搭建NAT服务

本文档介绍如何在一台服务器做NAT转发,以外网网卡是em1 ,源IP段10.0.0.0/16 为例。


1.开启forward ,并加入开机启动

# sysctl -w net.ipv4.ip_forward=1
# echo “sysctl -w net.ipv4.ip_forward=1” >> /etc/rc.d/rc.local

2.增加外网IP。

外网出口可以有多个IP,先增加这些IP (不配置的話NAT不生效)。

来个例子脚本( 执行而且把这段脚本写入/etc/rc.d/rc.local ):

ip_prefix=“121.14.25”
ip_min=131
ip_max=158
netmask=“255.255.255.224”

n=0
for i in `seq $ip_min $ip_max`
do
    /sbin/ifconfig em1:$n ${ip_prefix}.$i netmask $netmask up
    ((n++))
done

3.用iptables 增加nat 转发

类似:

# iptables -t nat -A POSTROUTING -s 10.0.0.0/16 -o em1 -j SNAT –to-source 121.14.25.17-121.14.25.22
# iptables-save > /etc/sysconfig/iptables

如果不指定出口IP,可以用:

# iptables -t nat -A POSTROUTING -s 10.0.0.0/16 -o em1 -j MASQUERADE

另外两点:

  1. 最好要两台NAT机器(接入一台交换机),起一个VIP指向这两台机器,并且在接入交换机上打开 源IP、源端口、目的IP、目的端口 的哈希功能(在等价路由基础上),这其实是实现了流量的负载均衡和高可用(具体咨询搞网络的同学)。

  2. 最好有安全策略,不要让所以机器都可以通过NAT访问外网,这个功能自己去调研方案啦。

aws 如何在创建实例的时候不自动生成公网IP,同时实例能够访问公网

一开始我的需求是如何在创建实例的时候不自动生成公网IP(为了安全),但是实例也能访问外网(有访问外网的需求,可以通过NAT),因为对aws的网络架构不了解,所以准备从头开始。

 

aws 提供四种网络架构,分别是

VPC with a Single Public Subnet

VPC with Public and Private Subnets

VPC with Public and Private Subnets and Hardware VPN Access

VPC with a Private Subnet Only and Hardware VPN Access

看了很多资料之后发现 aws提供这四种网络架构是为了方面配置,我们可以完全不管这四种网络架构,可以自定义适合自己需求的网络架构,比如我不止需要公有子网和私有子网,还同时需要NAT和VPN,这四种架构都满足不了,这时候可以自定义来解决。

先说下 公网 和 私网,公网可以直接访问外网,私网需要有NAT。一般在AWS里建立一个VPC,再在VPC里面建立多个子网,每个子网可以被指定为 公网 或者 私网,公网和私网的区别在于创建实例的时候是否自动分配公网IP,那么 是否分配公网IP 可以在子网页面的 Modify Auto-Assign Public IP 配置里修改,第一个问题解决了,很简单。

 

我准备说说 VPC with Public and Private Subnets 这种架构,同时证明我们可以自定义出这种网络架构。

aws的官方说明:

762b05ceb5a37091e9f523bd213813d0

此架构会 创建/16网段的VPC,然后在里面建立/24 的两个子网,一个是公有子网,另一个是私有子网,这两个子网默认都不创建公有IP。

公有子网里的实例可以绑定EIP并连接(如果无法连接可能是安全组问题);私有子网里的实例也可以绑定EIP,但是从外网没法连接(已实验)。

另外,创建此VPC架构的时候会在公有子网创建一个NAT实例,并会给这个NAT实例自动绑定EIP(可以连接),私有子网的实例通过此NAT连接外网,我们来看看。

我登陆我测试时的NAT实例,看了一下,也就是普通的 iptables 转发,所以NAT实例本身的配置我们可以自己搞定。
route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.0.0.1        0.0.0.0         UG    0      0        0 eth0
10.0.0.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
169.254.169.254 0.0.0.0         255.255.255.255 UH    0      0        0 eth0

# iptables -vnL -t nat
Chain PREROUTING (policy ACCEPT 15 packets, 1081 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain INPUT (policy ACCEPT 7 packets, 417 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 22 packets, 2157 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in     out     source               destination
   30  2821 MASQUERADE  all  —  *      eth0    10.0.0.0/16          0.0.0.0/0

另外,在私有网络创建的实例可以通过NAT访问外网:
ping www.baidu.com
PING www.a.shifen.com (180.76.3.151) 56(84) bytes of data.
64 bytes from 180.76.3.151: icmp_seq=1 ttl=49 time=79.7 ms
64 bytes from 180.76.3.151: icmp_seq=2 ttl=49 time=79.5 ms

route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.0.1.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
0.0.0.0         10.0.1.1        0.0.0.0         UG    0      0        0 eth0

这里可以看到,私有子网里的实例的默认网关是 XXX.XXX.XXX.1 这种格式,我们不用指定为NAT实例的内网IP。

最后,私有子网的路由表的默认路由会指向此NAT实例(i-e310e3c8),如图:
1111

那么参考上面,我们可以自己建立一个 VPC with Public and Private Subnets ,大概步骤如下:

1. 创建一个VPC,再创建两个子网,一个公有子网,一个私有子网(私有子网不分配公网IP,通过Modify Auto-Assign Public IP 修改。)

2. 在公有子网里创建一台NAT实例,配置iptables转发,同时把NAT实例的Change Source/Dest. Check 关掉 (此为一坑)。

3. 为私有子网创建一个Route Tables,把0.0.0.0/0 指向NAT实例的ID,比如下图。

2222

4. 在Route Tables 配置里,配置公有子网的Route Table,把它的Subnet (内网段)关联上,同时配置私有子网的Route Table,把它的Subnet (内网段) 关联上(此为另一坑,花费我很长时间排查)。

5. 在Subnet 配置里,把私有子网的Route Table 修改成 第3步添加的 Route Table

NAT实例配置正确之后,创建在私有子网中的机器就没有公网IP,而且能访问外网了。