显示标签为“pptp”的博文。显示所有博文
显示标签为“pptp”的博文。显示所有博文

[转]PPTP连接过程分析

PPTP 协议的RFC 文档是 RFC2637:

pptp 的连接使用了TCP 1723 端口进行,通过此端口完成了pptp的握手之后,利用ppp协议进行认证以及数据传输。其中ppp协议数据在IP数据层之后,利用GRE进行封装,进行认证等操作,完成之后,数据传输是利用了ppp协议,添加GRE头部,ppp头部信息之后,进行数据的传输。其中在数据传输的时候,按照ppp有没有采用加密形式决定了,能不能通过抓包形式查看GRE信息后面隐藏的具体信息。

在此例子中 10.1.1.122 是客户端,10.1.1.130 是pptp服务器,在测试环境中抓到的数据包顺序以及格式如下:

PPTP连接过程分析【1】



此阶段的数据包结构如下:

PPTP连接过程分析【1】


跟着TCP 字段就是这个 Point-to-Point Tunnelling Protocol 的字段。
所以前面的PPTP握手的数据包格式为

以太头部信息
IP头部信息
TCP头部信息
PPTP信息

之后进入到了 ppp 的认证以及数据传输阶段,在此阶段,在IP头部后面添加了GRE头部信息,之后是ppp头部信息,并且无端口使用。
此过程如下图所示:
PPTP连接过程分析【1】
PPTP连接过程分析【1】

到了 PPP Comp 就是数据传输字段了,在此数据包中,看到这样的PPP数据包格式,

PPTP连接过程分析【2】 


其中 Call ID,是此次数据传输保持不变,而每个数据包的Sequence Number 是依次增加,而在 Point-to-Point Protocol 协议当中
Protocol 是 0X00fd 意味着压缩传输,看不到Datagram的具体内容。

在另外配置的16的明文pptp当中,看到的数据是
在明文传输的时候,比如双方互相ping的时候,
看到


 PPTP连接过程分析【2】

在PPP封装当中,可以看到后面的IP包头以及ICMP头部信息,并且发出ping的sequence number 为71,那么返回的replay 的数据包的PPP当中,Sequence Number是36,带着 Acknowledgement Number 71,回应此PING。
并且PPP的Protocol 为 0X0021,是IP协议。

[转]PPTP穿透NAT之深入分析

大家好,现在是人静时分,我公司人员都以溜光,只有我还在面对computer,在经过不解、迷惑、结论之后,现与大家分享结果,感谢朋友Zyliday,见贤思齐的实验帮助。

 

在研究技术原理之前,让我们先了解几个基本的概念。我们要了解NAT技术,这个就不用多说了吧!我们的主机大部分存在于一个内部网络中,有一个私有ip地址,所以所有去往Internet的数据包,都要将其源ip与端口转换,来实现数据通信。让我们感到幸运的是,我们对于互联网的服务应用,大部分用tcp与udp协议来传输,由于tcp与udp协议中含有端口,所以往返的数据包很容易找到归宿。但难免会有特殊出现,pptp协议,l2tp协议,ftp 协议,ipsec 协议等,根据其各自协议特殊原因,均无法顺利通过nat,俗话说兵来将挡水来土掩,nat 该怎么办going?今天重点我们放到pptp协议身上。pptp是什么?pptp是其vpn隧道协议中的一种,加以其它协议的配合,成功实现了身份验证、加密数据和协议配置等问题,为远程用户创建了一条穿越公网的安全连接,让我们去了解PPTP协议。

 

PPTP流量由两条连接产生:

• PPTP控制连接

这是一个逻辑连接,表示必须通过一系列PPTP消息创建、维持和终止的PPTP隧道。 PPTP控制连接流量使用PPTP客户端上动态分配的TCP端口,以及PPTP服务器上由IANA保留的TCP端口1723。

• PPTP数据连接

当数据通过PPTP连接发送时,PPP帧将使用通用路由封装(Generic Routing Encapsulation,GRE)报头进行封装,报头包含用于识别该数据包的特定PPTP隧道的信息。

现在来分析下,由于控制连接用了端口1723,所以这条连接我们就大可放心了,根据nat发送原则,会成功将数据包转发到pptp 服务器,如果你的vpn 服务器建立于内网中,在路由上映射其1723端口到服务器就OK.

 

让我们看下数据连接,我们发现以经没有了tcp协议参于,反而成了GRE协议包与PPP协议包,为什么它无法通过nat呢?来看下GRE协议格式:

每个字段的详解:

我们发现根本没有发现有端口这个字段,怎么映射?没有就不做端口映射呗~~~就转换ip不就得了。哈哈其实远远不是这样的,这种非常理的数据包格式,对于nat是个问题,对于防火墙也是个问题。今天我们先论nat:先来分析如果一个位于内部网络中( 公网IP2.2.2.2)的主机A192.168.1.2与pptp服务器5.5.5.5建立连接,控制连接成功建立,数据连接于由没有端口,nat只做其ip的转换,于是在2.2.2.2这个网络的nat设备上有这样的一个nat表:

ip

port

协议

公网ip

公网port

目标ip

目标port

192.168.1.2

 

GRE

2.2.2.2

 

5.5.5.5

 

192.168.1.3

 

GRE

2.2.2.2

 

5.5.5.5

 

当2.2.2.2这个网络收到来自于pptp服务器的数据流包时,2.2.2.2网络的nat设备发现来自于网络5.5.5.5的gre 协议数据包,是给内部主机192.168.1.2的,所以成功通信。分析如果位于2.2.2.2这个网络中的主机B192.168.1.3 也与5.5.5.5网络中的pptp服务器通信,结果就不太理想了~~如果在nat表中还有一条到达主机192.168.1.3的gre通信,到收到一个gre协议数据包时,2.2.2.2网络中的nat设备犹豫了,这个包给谁呢?192.168.1.2?还是192.168.1.3呢?在此大家也不要忘了,我们的实验环境是只有一个公网ip,内部主机A与B出去的时候,源ip都转换成了公网的ip2.2.2.2,所以收到的数据包都是目标ip为2.2.2.2,然后nat设备根据端口的不同转发到不同的主机。有两个客户端就无法通信,这就是网上说的位于内部的主机只能与同一服务器之间建立一个会话,不能有第二个客户端。

vpn 技术的流行,但技术上有约束,人们想办法开发能穿透nat的设备,实现多路复用。在细分析gre协议后,人们发现gre协议中有一个字段,可以拿来利用,那就是这个call id值,这个值并不固定,可以改变。这个值是怎么回事呢?用来标识唯一会话的。这个值最早出现在控制连接中,客户端与服务器互相通告彼此的call id值,然后在其数据连接中,服务器call  id值写上客户端的,客户端写上服务器的call id值。nat引入了一种技术nat编辑器,大家可以去看下我们的路由器,大部分自动开启了对ipsec隧道与pptp隧道协议的支持。路由器对pptp隧道的建立施全程监控,并在每一台PPTP客户机的私用IP地址、CALL ID和公共IP地址以及PPTP服务器接收的CALL ID之间建立单独的映射关系。我可以把call id值当做端口来看,然后添加到nat表中。

让大家看一个今天做的一个实例图(pptp客户端路由器NAT表):pptp数制连接我们可以认为它有两条nat映射记录,一个用于数据包的发送,一个用于数据包的接收。

ip

port

协议

公网ip

公网port

目标ip

目标port

192.168.1.10

5000

TCP

59.173.163.119

50001

221.217.151.68

1723

192.168.1.10

30061

GRE

59.173.163.119

32769

221.217.151.68

 进

192.168.1.10

256

GRE

59.173.163.119

256

221.217.151.68

 出

192.168.1.11

10000

TCP

59.173.163.119

50002

221.217.151.68

1723

192.168.1.11

5868

GRE

59.173.163.119

32770

221.217.151.68

 进

192.168.1.11

512

GRE

59.173.163.119

512

221.217.151.68

 出

nat把客户端的call id值当做源端口,然后告诉服务器一个假的call id来充当转换后的端口。这个修改是在控制连接中修改的,然后做nat记录后发送给服务器。说到此我说下,前两天在弯曲评论上看到了一文章,作者写到nat对其服务器的call id也转换,我认为不转换服务器的call id 值。在我们实验的时候,一开始我让多个不同外网的朋友建立vpn连接,连接我这边内部vpn服务器主机,抓包发现服务器通告的call id都一样,不解?如果在同一个内部网络中,有两个客户端连接进来,服务器通告的call id不改变,通信将出故障?今天又与见贤思齐做了一个同一内部网络中,多个客户端连接情况,抓包发现服务器对于同一个ip多个客户机的连接分配了不同的call id值,所以直接修改其客户端call id便可实现流量多路复用,vpn服务器自动解决了这个同一ip不同call  id值问题。

客户端192.168.1.10的连接:

服务器方抓包分析如下:

上图:客户端在控制连接中,告诉服务器它的call id值为32769。

上图:服务器控制连接中告诉它的call id值为256。

客户端抓包分析如下:

上面客户端告诉服务器它的call id为30061。

服务器告诉客户端它的call id值为256。

看了以后大家知道nat做数据包做了什么处理了吧,客户端12的连接我就不贴图了,道理一样。这样的端口改变还可以避免不同的客户端告诉服务器相同的call id,因为它无法意识到另一个主机也用了此call id ,如果nat不加转换,将出现问题。

[转]当NAT遇见PPTP

转自弯曲评论:http://www.tektalk.org/2010/03/13/%E5%BD%93nat%E9%81%87%E8%A7%81pptp/


我建了一个PPTP的帐号,想访问一下公司的内网资源,结果发现,没法传输数据,这是怎么回事?于是在Google里面输入rfc pptp,直接就点进去了第一条带有RFC 2637的链接,开始了今天的穿越。。。。。。

问题出在哪里

首先稍微介绍一下,PPTP有两个流,一个是控制流(RFC2637定义),另外一个数据流(GRE,RFC2784)。和一般的ALG不同的是(比如FTP),NAT遇到PPTP的时候,不是端口或者IP惹的祸,而是PPTP里面邪恶的callID(抛一个球给各位,为何PPTP把call ID整到PPTP控制流里面?)。在PPTP协议里面,有一个call ID的概念,客户端向服务器发起连接,会告诉服务端我的call ID是多少,服务端也会回应客户端它的call ID是多少,并且更重要的一点是,这个call ID在以后的某些(注意不是全部哦)控制传输中需要用到,在所有的数据传输中(GRE)需要用到。而接下来我们从两个方面一起来看一下问题是如何产生,以及如何去解决:
  • 从内网向外网发起PPTP连接请求
  • 从外网向内网发起PPTP连接请求(俗称静态映射)

走,咱们去看看外面的世界

(注:下面的结构是1)提一下PPTP协议;2)提一下GRE协议;3)如何搞定GRE数据流;4)如何搞定PPTP控制流。)
PPTP服务器是监听在TCP/1723端口。客户端发送的第一个携带call ID的数据包是被称为Outgoing-Call-Request的数据包,一个示例如下图所示(忽略了前面的以太网头,IP头,以及TCP头):
image
可以看到我们这边的示例客户端的call ID是16384(这个call ID是给自己分配的),那我就以Client-Call-ID表示吧。
服务端收到这个数据包之后,然后会回应一个称为Outgoing-Call-Reply的数据包,示例如下:
image
这个说明服务端自己的call ID是107(这个服务端是给自己分配的,我就以Server-Call-ID表示), 同时也把Client-Call-ID返回给客户端。咦,这样看来好像没有什么问题嘛,反正这个call ID改不改,对于这一条连接都没有影响,NAT也可以正常运作。但是,各位看官,PPTP还需要用到一个协议,那就是GRE(RFC 2784)。而GRE是一个和TCP以及UDP处在同一个水平线的协议。但是和TCP/UDP之流不同的是,GRE里面不携带端口信息,而它利用的就是call ID来作multiplex以及demultiplex的。我们看一下客户端发给服务端的一个GRE数据包(提示一点,GRE头后面的是PPP协议封装,不过这里不需要关心):
image
里面有call ID,这个call ID不是说自己的,而是说对方的(对,就是PPTP里面的那个Server-Call-ID),也就是服务端的,也就是我这个GRE数据要发给服务端的107"端口"。

而服务端也采用同样的策略,只不过call ID表明的是客户端的,一个示例如下:
image
(注:上面的都是一些协议的原理,如果你读了RFC,未必不懂这些。插一个情景,来自一个电影:C开一辆车在公路上,前面有一个人D骑一辆自行车。C在追D的,C紧张的说:"你。。。你骑自行车未必比我开车快!")
问题是这些个数据包也要经过我们可怜的NAT啊,GRE会问NAT:"我这个call ID,管还是不管?",NAT答曰:"不管。"话虽如此,但是谈何容易,因为GRE里面没有端口,如果NAT不伪造一个端口的话,下面的情形就不堪设想了:
  • 一个主机A的IP地址是192.168.1.2,向1.1.1.1(声明:这里仅仅是假设,没有对其进行真正的试验,1.1.1.1请不要见怪)发起PPTP连接请求,Client-Call-ID是16384,Server-Call-ID是107;
  • 还有一个主机B在内网,IP地址是192.168.1.3,也向1.1.1.1发起PPTP连接请求,Client-Call-ID2是16385, Server-Call-ID2是108。
NAT如果仅仅是转换IP地址(假设NAT的公网IP是116.238.184.159),那么数据到能够到达1.1.1.1,可是GRE数据包回到116.238.184.159的时候,NAT这个时候是该把它发给192.168.1.2呢,还是192.168.1.3呢?在这种情况下,NAT必须要找一个"端口",来决定这个数据包是发给谁,而"端口"需要满足以下特性:
  • 在一台主机上,这个是唯一的;
  • 必须每个数据包中都存在。
而扫描整个GRE数据包,只有call ID具有此特性。所以这个关系是这样的,由于GRE数据包里面没有像TCP/UDP的端口信息,所以需要这样一个信息,而call ID的存在恰恰满足了这样一个条件。但是call ID和TCP/UDP端口有不一样的地方:
  • TCP/UDP的端口在传输层中的位置是一样的,相对偏移量是0,而call ID在传输层里面的偏移量是6;
  • TCP/UDP的端口在每个数据包里面都会携带源端口和目的端口,但是call ID仅仅携带一个,并且是指对方的。
意识到这些不同点非常重要,这会影响到NAT对待TCP/UDP和GRE要完全不同,而也正是PPTP ALG的原因之一!
嘿嘿,是否对为何需要针对GRE作特殊处理的原因了吧?好,那我们看如果保证GRE数据包能够顺利通过NAT。
我们知道,有一个NAT会话的概念(不要嫌我罗嗦。。。),里面有以下几个关键的元素:
  • 内网地址(innerip)
  • 内网端口(innerport)
  • NAT公网地址(outerip)
  • NAT公网端口(outerport)
  • 目的地址(destip)
  • 目的端口(destport)
  • 协议(Protocol)
而从内网的数据包,至少需要innerip以及innerport才能NAT出去(请读者思考protocol在什么情况下也需要作为一个依据;destip在symmetric NAT的情况下也需要考虑,不过这里我们就不关心了),而数据包返回的时候需要outerip, outerport。他们两者虽然查找的依据不一样,但是查找到的会话对于一条连接必须是同一个,这是保证通信畅通的前提。为了要使GRE顺利通过NAT,我们以主机A为例就把其分解为从里面到外面,从外面到里面两个方向。
  • 从里面到外面。这个时候,call ID是Server-Call-ID(107)。innerip是192.168.1.2,可以把Server-Call-ID作为innerport,outerip是116.238.184.159,outerport假设是1234(NAT分配的呢)。OK这个数据包可以发送给服务端;
  • 从外面到里面。这个时候,call ID是Client-Call-ID(16384),数据包的目的是116.238.184.159,那么NAT如何将其发送给192.168.1.2?大家可以看到这个时候16384帮不上任何的忙,因为outerport是1234啊。哦,等等,如果再创建一条NAT会话,把16384作为outerport,innerip作为192.168.1.2,innerport随便了(反正不用),这样不就可以发送给192.168.1.2呢?
所以,为了能够使GRE数据顺利来回,需要创建两条GRE的NAT会话,如下:
维护从里面到外面的数据传输(GRE-SESSION-1):
image
维护从外面到里面的数据传输(GRE-SESSION-2):
image
各位看到问题没有,outerport是16384,如果内网还有一台PC也是使用16384的call ID,那么这样就不出现两个outerport为16384的NAT会话呢?呵呵,这个后果很严重。所以outerport需要有NAT自己来分配一个唯一的(比如1244),这样就算内网还有一台PC使用16384,NAT也可以识别。不过既然outerport不是16384了,也就意味着一个非常重要的话题,就是NAT必须要让服务端知道Client-Call-ID是1244,而不是16384,这是PPTP ALG的另外的原因。这个带来的影响:
  • 在PPTP所有的控制包里面,如果牵扯了Client-Call-ID,都需要修改为1244,如果不修改,服务端就会认为Client-Call-ID是16384了;
  • 从服务端过来的GRE数据包中的call ID从1244还原为16384;
  • 从外面到里面的NAT会话(GRE-SESSION-2)需要存储16384,咦,上面不是说Innerport没有用到吗?我们就可以把1244存储在innerport这个位置,不过仅仅是用来作为call ID从1244还原为16384的依据。
更新后的GRE-SESSION-2应该是这个样子的:
image
这样子的话,GRE就是通行无阻了,从里面到外面匹配GRE-SESSION-1,从外面到里面匹配GRE-SESSION-2。接下来我们看看这两条会话是在什么时候生成的以及控制流中需要做的工作。
前面说到,Client-Call-ID在第一个Outgoing-Call-Request里面首次亮相,那么就可以先生成GRE-SESSION-2(获取outerport,即1244),然后根据GRE-SESSION-2中的outerport再把这个数据包中的call ID改成1244,之后就放了它。
收到Outgoing-Call-Request之后,服务端会返回Outgoing-Call-Reply,此时就可以:
  • 生成GRE-SESSION-1;
  • 把里面的Client-Call-ID从1244还原成16384。
在其后的控制连接中,再次强调,NAT你得记住有一点,只要是牵扯到Client-Call-ID,你就要动手脚。如果是从客户端到服务端,那么得将其修改成1244;如果是从服务端到客户端,那么你就得把它还原成16384。而GRE数据流,就可以让它自己匹配GRE-SESSION-1和GRE-SESSION-2了。

哦,回城了

如果是从外面主动发起请求,希望读者能够自己分析一下。给一点点提示:
  • Outgoing-Call-Request里面的Call ID(Client-Call-ID)就不用修改了,因为这个是外面的;
  • 而Outgoing-Call-Reply里面的Server-Call-ID需要修改,因为这个是属于里面的。

结语

造成PPTP需要做ALG的原因,是GRE数据里面没有携带端口,而又只能通过call ID来模拟"端口"作NAT,而由于需要模拟'端口",进而需要修改PPTP控制流中的相关call ID。
还有一个特点是,call ID的修改是单方面,而决定其是否要修改的原因就是这个call ID是由内网的机器产生还是由外网的机器产生。
由于call ID是固定2个字节,这个修改在PPTP中只需要更新TCP和IP校验和,不需要处理seq/ack问题;在GRE中只需要关心IP校验和(由于修改了IP地址),因为GRE自己压根就没有校验和。