博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Resiprocate 如何使用STUN
阅读量:4121 次
发布时间:2019-05-25

本文共 4512 字,大约阅读时间需要 15 分钟。

STUN-Simple Traversal of User Datagram Protocol (UDP) Through NetworkAddress Translators (NATs),基于UDP,关于STUN介绍不再赘述,想要了解的话可以参考

 

Resiprocate可能用到STUN的场合

一、proxy架设在内网,需要获得proxy外网IP(也可以用DNS实现);二、实现两个内网客户端SIP通信。客户端支持Stun,路由器类型属于完全圆锥NAT,地址受限NAT,或端口受限NAT,可以利用stun穿越。或者是通过路由器端口映射。

NAT

 

检测NAT类型步骤

NAT的四种类型

  • Full cone NAT,亦即著名的一對一(one-to-one NAT

    • 一旦一个内部地址(iAddr:port1)映射到外部地址(eAddr:port2),所有发自iAddr:port1的包都经由eAddr:port2向外发送.任意外部主机都能通过给eAddr:port2发包到达iAddr:port1

 

  • Address-Restricted cone NAT

    • 一旦一个内部地址(iAddr:port1)映射到外部地址(eAddr:port2),所有发自iAddr:port1的包都经由eAddr:port2向外发送.任意外部主机(hostAddr:any)都能通过给eAddr:port2发包到达iAddr:port1的前提是:iAddr:port1之前发送过包到hostAddr:any. "any"也就是说端口不受限制

  • Port-Restricted cone NAT

    类似受限制錐形NAT(Restricted cone NAT),但是还有端口限制。

    • 一旦一个内部地址(iAddr:port1)映射到外部地址(eAddr:port2),所有发自iAddr:port1的包都经由eAddr:port2向外发送.一个外部主机(hostAddr:port3)能够发包到达iAddr:port1的前提是:iAddr:port1之前发送过包到hostAddr:port3.

  • Symmetric NAT(對稱NAT)

    • 每一個來自相同內部IP與port的請求到一個特定目的地的IP地址和端口,映射到一個獨特的外部來源的IP地址和端口。
      同一個內部主機發出一個信息包到不同的目的端,不同的映射使用
    • 只有曾经收到过内部主机封包的外部主机,才能够把封包发回来

 

ResiprocateSTUN的支持

Resiprocate使用了ResiprocateStun的支持可以参考,说的比较详尽。简单来说,ResiprocateStun支持全在UdpTransport:

UdpTransport::process接收监听端口数据封包包括了Stunresponse Stun request以及SIP message

UdpTransport::stunSendTest发送Stun请求。

UdpTransport::stunResult输出外网地址。

如果作为Stun Client,需要当添加transport的时候保存返回的UdpTransport指针。发送Stun请求,并获得外网地址是异步的,如果需要同步的话,如下使用:

boolstunSendTest(const Tuple& dest);bool stunResult(Tuple& mappedAddress); voidSendStunTest(){     if (!m_pUdpTransport) return;     hostent* h =gethostbyname(STUNServer);     in_addr sin_addr = *(structin_addr*)h->h_addr;     resip::Tuple tStunDest(sin_addr,STUNPort, UDP, Data::Empty);     m_pUdpTransport->stunSendTest(tStunDest);     mLastStunTestTime= GetTickCount();} resip::TupleGetStunAddress(){    resip::Tuple mMappedAddress;    mMappedAddress.setPort(0);    if(!m_pUdpTransport) return mMappedAddress;    if(!m_pUdpTransport->stunResult(mMappedAddress))    {         // no valid result available,send another request         SendStunTest();    }    else if((GetTickCount() - mLastStunTestTime) > 1000 * 60 * 3)     {         // don't use a STUN responsethat is older than 3 minutes         SendStunTest();    }    DWORDdwTmpLastStunTestTime = mLastStunTestTime;    while((GetTickCount() - dwTmpLastStunTestTime) < 5 * 1000) // wait 5s forresult    {         if(m_pUdpTransport->stunResult(mMappedAddress))              break;         Sleep(200);    }    returnmMappedAddress;}

 

附加我自己的用法,实现proxy假设在内网的情况下,获得外网IP

  UdpTransport::process

   

//每30s向mStunServer发送stun请求,发送失败的话,使用DNS(mStunServer为域名)   if(mUseStun)   {              static UInt64last=Timer::getTimeMs();  UInt64 now=Timer::getTimeMs();  if(now-last>30000)  //30s 执行一次  {            hostent* h =gethostbyname(mStunServer); if(h) {            in_addr sin_addr = *(structin_addr*)h->h_addr;resip::Tupledest(sin_addr, 3478, UDP,Data::Empty);                        if(!stunSendTest(dest)){h= gethostbyname(mDomainName.c_str());if(h){mStunSuccess= true;         sin_addr= *(struct in_addr*)h->h_addr;mStunMappedAddress= Tuple(sin_addr,mStunMappedAddress.getPort(), UDP); } }}last=Timer::getTimeMs();  }        }

 

获得外网IP,外网IP存储在mExternalIP

   

resip::SdpContents*pSipSdp = dynamic_cast
(msg->getContents()); if ( pSipSdp ) { UdpTransport* temp =dynamic_cast
(target.transport);if(pSipSdp->session().origin().getAddress()== temp->mDomainName || pSipSdp->session().connection().getAddress() == temp->mDomainName){Tupletuple;boolbRet = temp->stunResult(tuple);DataexternalIP = Tuple::inet_ntop(tuple);ErrLog(<<"StunResultret "<<(bRet?"true. ":"false.")<<"local IP change to "<
session().connection().getAddress() == "0.0.0.0" ) { //只修改 pSipSdp->session().origin().setAddress(externalIP); }else { pSipSdp->session().origin().setAddress(externalIP); pSipSdp->session().connection().setAddress(externalIP); } mExternalIp = externalIP;}elseif(!mExternalIp.empty()){ if (pSipSdp->session().connection().getAddress() == "0.0.0.0" ) { //只修改 pSipSdp->session().origin().setAddress(mExternalIp); }else { pSipSdp->session().origin().setAddress(mExternalIp); pSipSdp->session().connection().setAddress(mExternalIp); } } } }
     

 

 

 

 

 

 

 

转载地址:http://wkppi.baihongyu.com/

你可能感兴趣的文章
SQL1015N The database is in an inconsistent state. SQLSTATE=55025
查看>>
RQP-DEF-0177
查看>>
Linux查看mac地址
查看>>
Linux修改ip
查看>>
MySQL字段类型的选择与MySQL的查询效率
查看>>
Java的Properties配置文件用法【续】
查看>>
JAVA操作properties文件的代码实例
查看>>
IPS开发手记【一】
查看>>
Java通用字符处理类
查看>>
文件上传时生成“日期+随机数”式文件名前缀的Java代码
查看>>
Java代码检查工具Checkstyle常见输出结果
查看>>
北京十大情人分手圣地
查看>>
Android自动关机代码
查看>>
Android中启动其他Activity并返回结果
查看>>
2009年33所高校被暂停或被限制招生
查看>>
GlassFish 部署及应用入门
查看>>
iWatch报错: Authorization request cancled
查看>>
iWatch报错: Authorizationsession time out
查看>>
如何运行从网上下载的iWatch项目详细步骤.
查看>>
X-code7 beta error: warning: Is a directory
查看>>