stun信令「建议收藏」

stun信令「建议收藏」#1.简介stun协议本身是用来进行NAT穿透使用,其本身实际上是NAT内部设备获取外部IP地址的一种协议。STUN协议在RFC上目前经过三种演变,其中RFC3489上定义的STUN和之后的RFC5389和8489上定义的stun在概念上存在明显区分:RFC3489定义:SimpleTraversalofUserDatagramProtocol(UDP)ThroughNetworkAddressTranslators(NATs)(STUN)RFC5389和RFC8489:Se

大家好,又见面了,我是你们的朋友全栈君。

1. 简介

stun协议本身是用来进行NAT穿透使用,其本身实际上是NAT内部设备获取外部IP地址的一种协议。STUN协议在RFC上目前经过三种演变,其中RFC3489上定义的STUN和之后的RFC5389和8489上定义的stun在概念上存在明显区分:
RFC3489定义:Simple Traversal of User Datagram Protocol (UDP) Through Network Address Translators (NATs) (STUN)
RFC5389和RFC8489:Session Traversal Utilities for NAT (STUN)
可以看到STUN协议的英文描述本身就已经发生了变化,3489中定义的是通过UDP进行NAT穿越的方式,而在RFC5389上定义的是对于NAT穿越的一整套工具集,这个工具集不在局限于UDP而是同时适用于UDP和TCP协议。

2. NAT类型

NAT类型是在RFC3489上提出的一个概念,这个概念旨在将NAT对于内部网络和外部网络数据包的不同处理上,对NAT进行一个系统的分类。但是在RFC5389上明确说明了RFC3489对于NAT分类的类型是不准确的,在很多场景下NAT设备的行为不能吻合到任何一个类型上。
尽管如此,但是将NAT设备进行分类有助于对于NAT类型的理解,以下是典型NAT的分类:
full cone:不受限的NAT处理模式,在这种NAT模式中,来自外部网络的数据包将被无条件路由到内部网络;
Restricted cone:IP受限型NAT,会将来自内部设备相同的IP+端口的数据包,统一映射成同一个外部IP+端口进行发送。当收到外部的数据包时,如果收到数据包的IP是之前发送数据包的目标IP,则转发到内部设备,否则丢弃。
restricted port cone:在IP受限型的基础上,添加了端口的约束。
Symmetric NAT:对称型NAT,则是在端口受限型的基础上,内部设备使用相同的IP+端口向不同的外部IP+端口(IP不同或端口不同或两者均不同)发送数据包时,NAT会分配不同的公网IP+端口。

这里多说一句,RFC3489将NAT类型分成以上几种模式之后,还定义了一整套的NAT发现的信令流程,通过stun请求去发现不同的NAT模式,不过这整个NAT发现的信令流程在RFC5389上已经被完全废弃,原因就在于实际工作在网络中NAT设备的行为比定义的远远要多样化,所以去发现NAT类型的实际意义不大。

3. Stun相关信令

在RFC3489中定义了许多stun使用的信令,但是在RFC5389中已经将其中的很多信令废弃,但是一些基本的信令依然存在。

binding request:stun中获取外部网络地址的请求,该请求获取的地址被称为server-reflex address。

binding request的格式如下:
image.png

binding response:binding response是binding request的响应,不同于很多协议的是,binding response直接在请求类型中就将response分为了两类,成功响应0x0101.失败响应0x0111。

stun indiction(RFC5389加入):这个stun信令在设计上就是为了简化传统stun流程中冗余的request-response的逻辑,在初始的stun请求获取server-reflex address成功之后,后续可能仅仅只需要维持这个地址,而不需要任何响应,这时候,终端就会使用indiction去对这个地址信息进行保活。信令值为0x0011。

3.1 RFC5389和RFC3489关于stun信令的区分

RFC5389和RFC3489最关键的stun信令区分就是RFC5389将RFC3489中规定的128transation Id字段中的前32位改为了magic cookie:0x2112a442
RFC3489
RFC5389

同时RFC5389由于将和其他协议进行多路复用,所以RFC5389额外将stun 的请求类型字段从RFC3489的16位变为14位,而使前两位变为全0,用于和其他协议进行区分。

同时RFC5389为了兼容RFC3489中的stun请求类型,特意将14位message type做了一下特殊处理,从而使其和RFC3489的请求类型进行兼容:
如图所示:在16位的字段中,已知前两位为了和其他协议进行区分从而为0,然后将第七位和地11位抽出作为class位。
image.png

class 0b00: 作为请求类别
class 0b01: 作为indiction(指示)类别
class 0b10: 作为成功响应类别
class 0b11: 作为失败响应类别
将其余剩下的位作为stun 的method:
stun协议仅定义了一种method binding, 其余的method会被其他协议拓展使用。

3.2 stun信令的组成部分

stun信令由stun头+stun属性两部分组成。其中stun头描述了基本的stun信息。stun属性则是对于这个stun信令的功能拓展。

4. stun协议工作流程

4.1 获取外部网络地址

stun协议的最简单的工作流程就是获取外部网络地址,这个流程有时被称为打洞,又被称为获取绑定地址,相关流程如下:

  1. client 发送stun请求至外部网络的server
  2. 外部网络的server获取到这个请求之后,将数据包的实际来源地址填入到response信令中
  3. client解析response信令,获取该设备的外部网络地址

这里运用的一个原理是,所有的NAT只要内部网络的设备使用IP+端口向外部网络的某个设备的IP+端口发送过数据包,那么来自这个外部网络IP+端口的数据包就一定能到达内部网络的设备。
在第一点中client发送的请求时stun request,
在第二点中外部的server会将数据包的实际来源地址,填入到stun 响应的属性中,这个属性在RFC3489中位mapped address, 而在RFC5389中为xor-mapped address。很多服务器的实现都会同时在这两个属性中将本地地址添加上,进而对终端进行更好的兼容。

4.2 维持地址绑定

当内部设备获取到自身的外部网络地址后,此时NAT上的处理就是建立了一个地址绑定关系,但是NAT对于这个地址绑定关系的存在时间具有限制,所以在一段时间后,这个绑定关系会被NAT回收,如果想一直持有这个绑定关系,就需要内部设备不断通过这个地址绑定关系向外部发送数据包。
对于一个stun client来说,这里最简单的处理就是发送stun request,通过stun request就可以不断刷新这个绑定关系(很多文章中称为NAT上的洞)的持续时间。
当然,这里还可以使用stun indiction去进行刷新,这样会更加轻量化,但是使用stun indction将会存在一个,如果NAT上这个绑定关系由于某些原因被重置,这将会导致内部设备无法感知到这一变化,所以交替使用stun request和stun indiction可能是一个更优的选择,不过在webRTC的实现中,一直都使用stun request去刷新绑定关系。

4.3 stun client的鉴权流程

stun 协议定义了两套鉴权流程,分别是短期凭证机制和长期凭证机制。这二者实际上都是运用了账号密码这个机制,所不同的是短期凭证机制是通过其他协议传递stun的用户名和密码,这个用户名和密码的有效期的使用期限非常短,可能仅在一次通话中使用。而长期凭证机制是直接获取到的,可以长期使用。

短期凭证机制和长期凭证机制的逻辑实际上都是通过stun协议的附加属性来完成,在鉴权流程中需要用到的属性是MESSAGE-INTEGRITY和USERNAME属性。

4.3.1 短期凭证机制

短期凭证机制实际的应用场景是ICE处理流程(ICE是定义了交互式连接的相关规范)。

4.3.1.1 请求的构建

短期凭证机制的使用很简单,就是在USERNAME和MESSAFE-INTERGRITY属性上填充相关的数据即可。
USERNAME只要填充用户名属性即可,而MESSAGE-INTERGRITY属性的填充则需要遵循如下规则:

  1. 消息完整性属性可以在任何stun请求中出现;
  2. 消息完整性属性使用SHA1算法得到
  3. 进行消息完整性属性极端的数据包含stun头,以及所有在MESSAGE-INTERGRITY属性前的数据,如果存在MESSAGE-INTERGRITY属性之后的属性,那么不在计入到消息完整性计算中;
  4. stun头中的长度在计算消息完整性之前,长度需要忽略MESSAGE-INTERGRITY属性之后的内容,消息完整性计算完毕之后,需要重新设置stun头中的长度为stun请求的实际长度;
  5. 计算出key,这个key=(密码的SASLPrep的格式)
  6. 运用这个key和stun请求中内容计算HMACSHA1的结果,然后添加到MESSAGE-INTERGRITY属性中

4.3.1.2 请求的处理

收到请求后的处理如下:

当请求不包含USERNAME和MESSAFE-INTERGRITY属性时,如果时stun request则回复400, 如果时indiction则丢弃不再处理;
当用户名非法,请求返回401, indiction则丢弃;
当消息完整性校验失败,请求返回401,indiction则直接丢弃;

成功的响应需要按照请求中的消息完整性生成逻辑添加MESSAFE-INTERGRITY属性,失败则不需要。

4.3.1.3 响应的处理

计算消息完整性是否匹配,匹配则可以继续其他流程,失败则继续请求的重传流程。

4.3.2 长期凭证机制

长期凭证机制的处理其实和短期凭证机制的差不多,只不过由于长期凭证机制的密码和用户名的使用上添加了额外的机制来进行保护,其实长期凭证机制的处理和SIP的鉴权流程差不多。

  1. 发送请求,不携带任何账户和密码信息;
  2. 接收到401 响应后,提取响应中的nonce值和realm值,nonce值是对一次鉴权流程的标记,可以一直在鉴权成功之后的流程使用,realm标记的是所属的域;
    获取计算消息完整性时HMAC-SHA1流程需要使用的key,在长期凭证机制中为:
    key = MD5(username “:” realm “:” SASLprep(password))
    后续流程和短期凭证机制相同

说明一下nonce值和realm,nonce值本身时一个随机数,用来对这个鉴权流程和后续的处理流程进行绑定,负责确认后续的stun请求是经过之前的鉴权的,不需要重复鉴权。realm标志的是需要使用那个用户名和密码,realm是一个域,终端可以根据相关的域选用对应域的账户名和密码(不过没有终端这么实现,基本上都是配置一个用户名和密码),在安全性上也是对相关的参数进行保护。

需要注意的是长期凭证机制不能使用indication,因其不能进行响应,让终端进行鉴权。当nonce值改变的使用,终端需要重新进行鉴权。

4.3.2.1 请求处理

  1. 当请求不包含消息完整性,则回复401,响应需包含realm和nonce,不需包含消息完整性和用户名;
  2. 当请求包含消息完整性,但是不包含realm和nonce,则回复400,,该响应不要包含realm,消息完整性,用户名和nonce;
  3. nonce值非法需要回复436响应需包含realm和nonce,不需包含消息完整性和用户名;
  4. 如果不包含用户名,则回复401,响应需包含realm和nonce,不需包含消息完整性和用户名;
  5. 消息完整性校验失败,回复401,响应需包含realm和nonce,不需包含消息完整性和用户名;

4.3.2.2 响应处理

和短期凭证机制类似,不再赘述。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160540.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Window下Tomcat端口被占用(Several ports (8005, 8080, 8009) required by Tomcat v7.0 Server at localhost are)

    Window下Tomcat端口被占用(Several ports (8005, 8080, 8009) required by Tomcat v7.0 Server at localhost are)问题:Eclipse中启动Tomcat时,遇到端口占有问题。解决方案:window下打开命令窗口(win+R)→输入cmd:输入 netstat -ano|findstr 8080(那个端口被占有,就输入那个端口),回车再次输入 taskkill /pid 12712/f(12712对应上图的12712 ),回车。 结束进程,重新启动Tomcat即可正常启动。  —…

  • Pycharm 提示:this license * has been cancelled – Python零基础入门教程

    Pycharm 提示:this license * has been cancelled – Python零基础入门教程目录一.前言一.找到hosts文件二.修改hosts文件三.检查hosts文件是否修改成功四.pycharm安装激活详细教程五.猜你喜欢一.前言零基础Python学习路线推荐:Python学习目录>>Python基础入门Pycharm安装激活过程中,提示thislicense****hasbeencancelled。这个问题并不是你的激活码不对,而是需要修改系统的hosts文件,下面详细讲解下如何修改hosts文件

  • linux卸载javajdk_tomcat拒绝连接

    linux卸载javajdk_tomcat拒绝连接–卸载jdk–查看jdk安装包名称rpm-qa|grepjdk–卸载rpm-e`rpm-qa|grepjdk`(或rpm-e加上面rpm-qa|grepjdk显示的结果)–注释或删除环境变量vi/etc/profile#exportJAVA_HOME=/usr/java/jdk1.6.0_20#exportCLASSPATH=.;$…

  • java代码大全_java新手入门-java新手代码大全[通俗易懂]

    java代码大全_java新手入门-java新手代码大全[通俗易懂]在开发中,我们常常需要使用到测试功能,因为我们不确定运行真正的代码会发生什么事情,今天我们就来介绍一下该如何在idea中进行junit单元测试吧。一、依赖安装Junit4Idea默认是使用的arquillianjunit4作为测试框架,这里我们我们把它改为Junit4。Settings->Plugins->搜索栏中搜索Junit并勾选->安装完成二、开…

  • oracle数据文件恢复 步骤_oracle数据库文件扩展名

    oracle数据文件恢复 步骤_oracle数据库文件扩展名1、基于linux操作系统文件恢复条件:1、误强制删除linux下的数据文件(rm-rf)。2、未重启数据库或操作系统。3、数据库是归档模式恢复原理:句柄恢复文件–因为我们的操作系统是linux,当数据文件从操作系统级别被rm掉,但之前打开该文件的进程仍然持有相应的文件句柄,所以指向的文件仍然可以读写,并且该文件的文件描述符可以从/proc目录中获得。…

  • Spring Boot 2.x: 定时给对象发送天气

    Spring Boot 2.x: 定时给对象发送天气使用Java写一个定时给对象发送天气的功能前言技术栈快速创建实例pom.xml文件新建接收天气api的实体天气接口封装的天气api简单演示获取天气api与发送邮件的逻辑设置发送账号信息配置appliction.properties控制层启动类效果源码地址前言不知不觉,又到了雨季,你对象是不是经常忘记带伞呢,这个时候写一个自动定时发送邮件的程序,提醒她带伞,会不会对你崇拜有加呢,当然,如果你对象是一位攻城狮,当我没讲~技术栈SpringBoot2.3.1Jdk1.8Maven快速创

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号