STUN不需要修改NAT,并可工作在应用实体和因特网前后间有任意数量的NAT的情况下。
用UDP简单穿过NAT(STUN),允许NAT后的实体首先发现NAT的存在和其类型,接着知道NAT分配的地址捆绑。
完全锥形:从同个内部IP地址和端口号发出的所有请求映射为相同的外部IP地址和端口号,任何外部主机使用映射后的外部IP+端口即可向内部主机发送数据。
限制锥形:比完全锥形多一个约束条件:即内部主机只有先向外部主机(IP为X)发数据,该外部主机才可向内部主机发数据(IP为约束条件)。
端口限制锥形:比限制锥形的约束更严格,要求内部主机先向(IP为X,端口为N的)外部主机发数据,外部主机才可向内部主机发数据(IP+端口均为约束),若该外部主机改变了IP或者端口,然后让内部主机发送数据,则内部主机收不到。
对称NAT:前三种都是在内部主机的源IP地址+端口与外部IP地址+端口之间建立一一映射,对称NAT使用内部主机的目的IP+端口与外部IP+端口之间建立映射。此外,对称NAT在外部主机收到数据后才可向内部主机发数据。
由STUN客户向STUN服务器发送请求,STUN服务器响应。
主要是两种请求:一、使用TLS TCP的共享私密请求;二、使用UDP的捆绑请求。
共享私密请求主要是为了从服务器获取一个临时的用户名和密码,该用户名和密码用于后续的捆绑请求以及捆绑响应,认证及检验消息的完整性。
捆绑请求使得STUN客户可以从捆绑响应中分析出NAT的类型(4种之一)及位置(内部主机在NAT之前还是之后),并获知NAT为它分配的捆绑(内部主机的源IP+端口与外部IP+端口之间的映射关系)。
消息结构:消息头+0个 或者多个消息属性,消息头包括消息类型、长度及事务ID;消息属性包括属性类型、长度及属性值
消息类型六种:捆绑请求、捆绑响应、捆绑错误响应;共享私密请求、共享私密响应、共享私密错误响应。
消息属性11种:
MAPPED-ADDRESS:表示服务器看到的发出捆绑请求的主机的IP地址+端口,用于捆绑响应消息中。
PESPONSE-ADDRESS:用在捆绑请求中,该地址接收捆绑响应;如果不存在,那么服务器把捆绑响应发到捆绑请求的源地址上。
CHANGE-REQUEST:只用于捆绑请求中,它要求服务器从不同的源IP+端口发送捆绑响应,主要是为了判断NAT是否限制锥形与端口限制锥形。
CHANGED-ADDRESS:用于捆绑响应,
SOURCE-ADDRESS:只用于捆绑响应,表示服务器发送捆绑响应时使用的IP地址+端口。
USERNAME:当用于共享私密响应时,表示为客户临时提供的用户名;当用于捆绑请求时,表示共享私密的索引。
PASSWORD:用于共享私密响应,表示为客户临时提供的密码。
MESSAGE-INTEGRITY:用于捆绑请求和捆绑响应,必须是任何STUN消息的最后一个属性,可以检验消息的完整性。
ERROR-CODE:用于捆绑错误响应和共享私密错误响应,指示发生的错误。
UNKNOWN-ATTRIBUTES:用于捆绑错误响应和共享私密错误响应,服务器不认识请求中的属性,它对应的ERROR-CODE为420。
REFLECTED-FROM:当捆绑请求中包含RESPONSE-ADDRESS属性时,服务端的捆绑响应使用该属性包含捆绑请求发送的IP地址和端口号。
属性空间分为可选部分与强制部分:属性值超过0x7fff属于可选的属性值,客户或者服务器即使不认识该属性值也能够处理消息;当属性值小于0x7fff时,客户或者服务器必须认识该属性值才能够处理消息。
共享私密请求:
一般情况下,客户端会配置STUN服务器的域名,服务器名为“stun”,stun协议缺省端口号为3478。
为提供完整性检查,STUN在客户与服务器之间使用128bit的共享私密,作为捆绑请求及响应中的密匙。
一、客户端使用STUN域名对应的IP+端口,与服务器进行TLS协商
二、服务端收到TLS请求后,对站点用证书进行认证
三、客户端验证服务器的标识,并发送共享私密请求
四、服务器收到共享私密请求后,首先验证该请求是否来自TLS连接,若否,则生成共享私密错误响应,ERROR-CODE响应号为433,该消息错误响应的回传方式取决于接到该请求的方式(TCP或者UDP);然后检查请求中的所有属性,若有不认识的强制属性(值小于0x7fff),则生成共享私密错误响应,ERROR-CODE响应号为420,并在响应消息中加入UNKNOWN-ATTRIBUTES属性,属性值就是那些不认识的属性,该错误响应通过TLS连接发送回去;若所有验证通过,服务器生成共享私密响应,包含USERNAME和PASSWORD属性,用户名至少10分钟内有效
共享私密响应与请求使用相同的TLS连接发送,该连接由客户负责关闭。
捆绑请求:
一、客户发送捆绑请求,携带一些属性(可选的如RESPONSE-ADDRESS、CHANGE-REQUEST,必选的有MESSAGE-INTEGRITY、USERNAME),捆绑请求发出后,如没有响应,则间隔100ms后重传,每次重传间隔加倍,直至1.6s,之后都按1.6s重传,重传最多8次(第8次重传后等1.6s仍未收到响应则认为请求失败)
二、服务器首先检查MESSAGE-INTEGRITY属性,若不存在,则生成捆绑错误响应,ERROR-CODE响应号为401;若存在则计算HMAC键值(与USERNAME相关)
三、服务器检查USERNAME属性,若不存在,而生成捆绑错误响应,ERROR-CODE响应号为432;若存在,但不认识该USERNAME的共享私密(例如超时了),则ERROR-CODE响应号为430;若认识USERNAME的共享私密,但由其计算得到的HMAC键值与请求的不同,则ERROR-CODE为431
四、完整性验证通过后,服务器继续检查其他所有属性值,若有不理解的强制属性(值小于0x7fff),则生成捆绑错误响应,ERROR-CODE响应号为420
五、所有验证通过后,服务器生成捆绑响应,事务ID与捆绑请求相同,加入MAPPED-ADDRESS属性,IP与端口置为服务器看到的发出捆绑请求的主机的IP和端口
六、捆绑响应发往的目的地址,若捆绑请求中有RESPONSE-ADDRESS属性,则目的地址同该属性值,若没有该属性,目的地址即为捆绑请求的源地址
七、捆绑响应发出时需要加入SOURCE-ADDRESS和CHANGE-ADDRESS属性,SOURCE-ADDRESS属性值为服务器的源IP+端口,其值取决于捆绑请求中CHANGE-REQUEST的标志(改变IP还是改变端口,还是根本没有CHANGE-REQUEST);CHANGE-ADDRESS属性值是固定的
八、捆绑响应中还需要加入USERNAME、MESSAGE-INTEGRITY
九、如果捆绑请求中有RESPONSE-ADDRESS属性,服务器响应中还需加入REFLECTED-FROM属性
十、客户端接收捆绑响应或者捆绑错误响应
根据情况发送三种测试消息,看是否得到响应:
一、客户向服务器发送STUN捆绑请求,不含RESPONSE-ADDRESS属性,CHANGE-REQUEST属性中不设任何标志
二、捆绑请求中,设置CHANGE-REQUEST属性的标志为改变IP和改变端口
三、捆绑请求中,只设置CHANGE-REQUEST属性的改变端口标志