1 /*
2  * pstun.cxx
3  *
4  * STUN Client
5  *
6  * Portable Windows Library
7  *
8  * Copyright (c) 2003 Equivalence Pty. Ltd.
9  *
10  * The contents of this file are subject to the Mozilla Public License
11  * Version 1.0 (the "License"); you may not use this file except in
12  * compliance with the License. You may obtain a copy of the License at
13  * http://www.mozilla.org/MPL/
14  *
15  * Software distributed under the License is distributed on an "AS IS"
16  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17  * the License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * The Original Code is Portable Windows Library.
21  *
22  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23  *
24  * Contributor(s): ______________________________________.
25  *
26  * $Revision: 26549 $
27  * $Author: rjongbloed $
28  * $Date: 2011-10-05 23:24:38 -0500 (Wed, 05 Oct 2011) $
29  */
30 
31 #ifdef __GNUC__
32 #pragma implementation "pstun.h"
33 #endif
34 
35 #include <ptlib.h>
36 #include <ptclib/pstun.h>
37 #include <ptclib/random.h>
38 
39 #define new PNEW
40 
41 
42 // Sample server is at larry.gloo.net
43 
44 #define DEFAULT_REPLY_TIMEOUT 800
45 #define DEFAULT_POLL_RETRIES  3
46 #define DEFAULT_NUM_SOCKETS_FOR_PAIRING 4
47 
48 
49 typedef PSTUNClient PNatMethod_STUN;
50 PCREATE_NAT_PLUGIN(STUN);
51 
52 PFACTORY_CREATE(PFactory<PNatMethod>, PSTUNClient, "STUN");
53 
54 
55 ///////////////////////////////////////////////////////////////////////
56 
PSTUNClient()57 PSTUNClient::PSTUNClient()
58   : serverPort(DefaultPort),
59     replyTimeout(DEFAULT_REPLY_TIMEOUT),
60     pollRetries(DEFAULT_POLL_RETRIES),
61     numSocketsForPairing(DEFAULT_NUM_SOCKETS_FOR_PAIRING),
62     natType(UnknownNat),
63     cachedExternalAddress(0),
64     timeAddressObtained(0)
65 {
66 }
67 
PSTUNClient(const PString & server,WORD portBase,WORD portMax,WORD portPairBase,WORD portPairMax)68 PSTUNClient::PSTUNClient(const PString & server,
69                          WORD portBase, WORD portMax,
70                          WORD portPairBase, WORD portPairMax)
71   : serverPort(DefaultPort),
72     replyTimeout(DEFAULT_REPLY_TIMEOUT),
73     pollRetries(DEFAULT_POLL_RETRIES),
74     numSocketsForPairing(DEFAULT_NUM_SOCKETS_FOR_PAIRING),
75     natType(UnknownNat),
76     cachedExternalAddress(0),
77     timeAddressObtained(0)
78 {
79   SetServer(server);
80   SetPortRanges(portBase, portMax, portPairBase, portPairMax);
81 }
82 
83 
PSTUNClient(const PIPSocket::Address & address,WORD port,WORD portBase,WORD portMax,WORD portPairBase,WORD portPairMax)84 PSTUNClient::PSTUNClient(const PIPSocket::Address & address, WORD port,
85                          WORD portBase, WORD portMax,
86                          WORD portPairBase, WORD portPairMax)
87   : serverHost(address.AsString()),
88     serverPort(port),
89     replyTimeout(DEFAULT_REPLY_TIMEOUT),
90     pollRetries(DEFAULT_POLL_RETRIES),
91     numSocketsForPairing(DEFAULT_NUM_SOCKETS_FOR_PAIRING),
92     natType(UnknownNat),
93     cachedExternalAddress(0),
94     timeAddressObtained(0)
95 {
96   SetPortRanges(portBase, portMax, portPairBase, portPairMax);
97 }
98 
99 
Initialise(const PString & server,WORD portBase,WORD portMax,WORD portPairBase,WORD portPairMax)100 void PSTUNClient::Initialise(const PString & server,
101                              WORD portBase, WORD portMax,
102                              WORD portPairBase, WORD portPairMax)
103 {
104   SetServer(server);
105   SetPortRanges(portBase, portMax, portPairBase, portPairMax);
106 }
107 
108 
GetServerAddress(PIPSocket::Address & address,WORD & port) const109 bool PSTUNClient::GetServerAddress(PIPSocket::Address & address, WORD & port) const
110 {
111   if (serverPort == 0)
112     return false;
113 
114   port = serverPort;
115 
116   if (cachedServerAddress.IsValid()) {
117     address = cachedServerAddress;
118     return true;
119   }
120 
121   return PIPSocket::GetHostAddress(serverHost, address);
122 }
123 
124 
SetServer(const PString & server)125 PBoolean PSTUNClient::SetServer(const PString & server)
126 {
127   PString host;
128   WORD port = serverPort;
129 
130   PINDEX colon = server.Find(':');
131   if (colon == P_MAX_INDEX)
132     host = server;
133   else {
134     host = server.Left(colon);
135     PString service = server.Mid(colon+1);
136     if ((port = PIPSocket::GetPortByService("udp", service)) == 0) {
137       PTRACE(2, "STUN\tCould not find service \"" << service << "\".");
138       return false;
139     }
140   }
141 
142   if (host.IsEmpty() || port == 0)
143     return false;
144 
145   if (serverHost == host && serverPort == port)
146     return true;
147 
148   serverHost = host;
149   serverPort = port;
150   InvalidateCache();
151   return true;
152 }
153 
154 
SetServer(const PIPSocket::Address & address,WORD port)155 PBoolean PSTUNClient::SetServer(const PIPSocket::Address & address, WORD port)
156 {
157   if (!address.IsValid() || port == 0)
158     return false;
159 
160   serverHost = address.AsString();
161   cachedServerAddress = address;
162   serverPort = port;
163   return true;
164 }
165 
166 #pragma pack(1)
167 
168 struct PSTUNAttribute
169 {
170   enum Types {
171     MAPPED_ADDRESS = 0x0001,
172     RESPONSE_ADDRESS = 0x0002,
173     CHANGE_REQUEST = 0x0003,
174     SOURCE_ADDRESS = 0x0004,
175     CHANGED_ADDRESS = 0x0005,
176     USERNAME = 0x0006,
177     PASSWORD = 0x0007,
178     MESSAGE_INTEGRITY = 0x0008,
179     ERROR_CODE = 0x0009,
180     UNKNOWN_ATTRIBUTES = 0x000a,
181     REFLECTED_FROM = 0x000b,
182     MaxValidCode
183   };
184 
185   PUInt16b type;
186   PUInt16b length;
187 
GetNextPSTUNAttribute188   PSTUNAttribute * GetNext() const { return (PSTUNAttribute *)(((const BYTE *)this)+length+4); }
189 };
190 
191 class PSTUNAddressAttribute : public PSTUNAttribute
192 {
193 public:
194   BYTE     pad;
195   BYTE     family;
196   PUInt16b port;
197   BYTE     ip[4];
198 
GetIP() const199   PIPSocket::Address GetIP() const { return PIPSocket::Address(4, ip); }
200 
201 protected:
202   enum { SizeofAddressAttribute = sizeof(BYTE)+sizeof(BYTE)+sizeof(WORD)+sizeof(PIPSocket::Address) };
InitAddrAttr(Types newType)203   void InitAddrAttr(Types newType)
204   {
205     type = (WORD)newType;
206     length = SizeofAddressAttribute;
207     pad = 0;
208     family = 1;
209   }
IsValidAddrAttr(Types checkType) const210   bool IsValidAddrAttr(Types checkType) const
211   {
212     return type == checkType && length == SizeofAddressAttribute;
213   }
214 };
215 
216 class PSTUNMappedAddress : public PSTUNAddressAttribute
217 {
218 public:
Initialise()219   void Initialise() { InitAddrAttr(MAPPED_ADDRESS); }
IsValid() const220   bool IsValid() const { return IsValidAddrAttr(MAPPED_ADDRESS); }
221 };
222 
223 class PSTUNChangedAddress : public PSTUNAddressAttribute
224 {
225 public:
Initialise()226   void Initialise() { InitAddrAttr(CHANGED_ADDRESS); }
IsValid() const227   bool IsValid() const { return IsValidAddrAttr(CHANGED_ADDRESS); }
228 };
229 
230 class PSTUNChangeRequest : public PSTUNAttribute
231 {
232 public:
233   BYTE flags[4];
234 
PSTUNChangeRequest()235   PSTUNChangeRequest() { }
236 
PSTUNChangeRequest(bool changeIP,bool changePort)237   PSTUNChangeRequest(bool changeIP, bool changePort)
238   {
239     Initialise();
240     SetChangeIP(changeIP);
241     SetChangePort(changePort);
242   }
243 
Initialise()244   void Initialise()
245   {
246     type = CHANGE_REQUEST;
247     length = sizeof(flags);
248     memset(flags, 0, sizeof(flags));
249   }
IsValid() const250   bool IsValid() const { return type == CHANGE_REQUEST && length == sizeof(flags); }
251 
GetChangeIP() const252   bool GetChangeIP() const { return (flags[3]&4) != 0; }
SetChangeIP(bool on)253   void SetChangeIP(bool on) { if (on) flags[3] |= 4; else flags[3] &= ~4; }
254 
GetChangePort() const255   bool GetChangePort() const { return (flags[3]&2) != 0; }
SetChangePort(bool on)256   void SetChangePort(bool on) { if (on) flags[3] |= 2; else flags[3] &= ~2; }
257 };
258 
259 class PSTUNMessageIntegrity : public PSTUNAttribute
260 {
261 public:
262   BYTE hmac[20];
263 
Initialise()264   void Initialise()
265   {
266     type = MESSAGE_INTEGRITY;
267     length = sizeof(hmac);
268     memset(hmac, 0, sizeof(hmac));
269   }
IsValid() const270   bool IsValid() const { return type == MESSAGE_INTEGRITY && length == sizeof(hmac); }
271 };
272 
273 struct PSTUNMessageHeader
274 {
275   PUInt16b       msgType;
276   PUInt16b       msgLength;
277   BYTE           transactionId[16];
278 };
279 
280 
281 #pragma pack()
282 
283 
284 class PSTUNMessage : public PBYTEArray
285 {
286 public:
287   enum MsgType {
288     BindingRequest  = 0x0001,
289     BindingResponse = 0x0101,
290     BindingError    = 0x0111,
291 
292     SharedSecretRequest  = 0x0002,
293     SharedSecretResponse = 0x0102,
294     SharedSecretError    = 0x0112,
295   };
296 
PSTUNMessage()297   PSTUNMessage()
298   { }
299 
PSTUNMessage(MsgType newType,const BYTE * id=NULL)300   PSTUNMessage(MsgType newType, const BYTE * id = NULL)
301     : PBYTEArray(sizeof(PSTUNMessageHeader))
302   {
303     SetType(newType, id);
304   }
305 
SetType(MsgType newType,const BYTE * id=NULL)306   void SetType(MsgType newType, const BYTE * id = NULL)
307   {
308     SetMinSize(sizeof(PSTUNMessageHeader));
309     PSTUNMessageHeader * hdr = (PSTUNMessageHeader *)theArray;
310     hdr->msgType = (WORD)newType;
311     for (PINDEX i = 0; i < ((PINDEX)sizeof(hdr->transactionId)); i++)
312       hdr->transactionId[i] = id != NULL ? id[i] : (BYTE)PRandom::Number();
313   }
314 
operator ->() const315   const PSTUNMessageHeader * operator->() const { return (PSTUNMessageHeader *)theArray; }
316 
GetFirstAttribute()317   PSTUNAttribute * GetFirstAttribute() {
318 
319     int length = ((PSTUNMessageHeader *)theArray)->msgLength;
320     if (theArray == NULL || length < (int) sizeof(PSTUNMessageHeader))
321       return NULL;
322 
323     PSTUNAttribute * attr = (PSTUNAttribute *)(theArray+sizeof(PSTUNMessageHeader));
324     PSTUNAttribute * ptr = attr;
325 
326     if (attr->length > GetSize() || attr->type >= PSTUNAttribute::MaxValidCode)
327       return NULL;
328 
329     while (ptr && (BYTE*) ptr < (BYTE*)(theArray+GetSize()) && length >= (int) ptr->length+4) {
330 
331       length -= ptr->length + 4;
332       ptr = ptr->GetNext();
333     }
334 
335     if (length != 0)
336       return NULL;
337 
338     return attr;
339   }
340 
Validate(const PSTUNMessage & request)341   bool Validate(const PSTUNMessage & request)
342   {
343     int length = ((PSTUNMessageHeader *)theArray)->msgLength;
344     PSTUNAttribute * attrib = GetFirstAttribute();
345     while (attrib && length > 0) {
346       length -= attrib->length + 4;
347       attrib = attrib->GetNext();
348     }
349 
350     if (length != 0) {
351       PTRACE(2, "STUN\tInvalid reply packet received, incorrect attribute length.");
352       return false;
353     }
354 
355     if (memcmp(request->transactionId, (*this)->transactionId, sizeof(request->transactionId)) != 0) {
356       PTRACE(2, "STUN\tInvalid reply packet received, transaction ID does not match.");
357       return false;
358     }
359 
360     return true;
361   }
362 
AddAttribute(const PSTUNAttribute & attribute)363   void AddAttribute(const PSTUNAttribute & attribute)
364   {
365     PSTUNMessageHeader * hdr = (PSTUNMessageHeader *)theArray;
366     int oldLength = hdr->msgLength;
367     int attrSize = attribute.length + 4;
368     int newLength = oldLength + attrSize;
369     hdr->msgLength = (WORD)newLength;
370     // hdr pointer may be invalidated by next statement
371     SetMinSize(newLength+sizeof(PSTUNMessageHeader));
372     memcpy(theArray+sizeof(PSTUNMessageHeader)+oldLength, &attribute, attrSize);
373   }
374 
SetAttribute(const PSTUNAttribute & attribute)375   void SetAttribute(const PSTUNAttribute & attribute)
376   {
377     int length = ((PSTUNMessageHeader *)theArray)->msgLength;
378     PSTUNAttribute * attrib = GetFirstAttribute();
379     while (length > 0) {
380       if (attrib->type == attribute.type) {
381         if (attrib->length == attribute.length)
382           *attrib = attribute;
383         else {
384           // More here
385         }
386         return;
387       }
388 
389       length -= attrib->length + 4;
390       attrib = attrib->GetNext();
391     }
392 
393     AddAttribute(attribute);
394   }
395 
FindAttribute(PSTUNAttribute::Types type)396   PSTUNAttribute * FindAttribute(PSTUNAttribute::Types type)
397   {
398     int length = ((PSTUNMessageHeader *)theArray)->msgLength;
399     PSTUNAttribute * attrib = GetFirstAttribute();
400     while (length > 0) {
401       if (attrib->type == type)
402         return attrib;
403 
404       length -= attrib->length + 4;
405       attrib = attrib->GetNext();
406     }
407     return NULL;
408   }
409 
410 
Read(PUDPSocket & socket)411   bool Read(PUDPSocket & socket)
412   {
413     if (!socket.Read(GetPointer(1000), 1000))
414       return false;
415 
416     SetSize(socket.GetLastReadCount());
417     return true;
418   }
419 
Write(PUDPSocket & socket) const420   bool Write(PUDPSocket & socket) const
421   {
422     if (socket.Write(theArray, ((PSTUNMessageHeader *)theArray)->msgLength+sizeof(PSTUNMessageHeader)))
423       return true;
424 
425     PTRACE(1, "STUN\tError writing to " << socket.GetSendAddress()
426            << " - " << socket.GetErrorText(PChannel::LastWriteError));
427     return false;
428   }
429 
Poll(PUDPSocket & socket,const PSTUNMessage & request,PINDEX pollRetries)430   bool Poll(PUDPSocket & socket, const PSTUNMessage & request, PINDEX pollRetries)
431   {
432     for (PINDEX retry = 0; retry < pollRetries; retry++) {
433       if (!request.Write(socket))
434         return false;
435 
436       if (Read(socket) && Validate(request))
437         return true;
438     }
439 
440     PTRACE(5, "STUN\tNo response from " << socket.GetSendAddress() << " after " << pollRetries << " retries.");
441     return false;
442   }
443 };
444 
445 
OpenSocket(PUDPSocket & socket,PortInfo & portInfo,const PIPSocket::Address & binding)446 bool PSTUNClient::OpenSocket(PUDPSocket & socket, PortInfo & portInfo, const PIPSocket::Address & binding)
447 {
448   if (serverPort == 0) {
449     PTRACE(1, "STUN\tServer port not set.");
450     return false;
451   }
452 
453   if (!PIPSocket::GetHostAddress(serverHost, cachedServerAddress) || !cachedServerAddress.IsValid()) {
454     PTRACE(2, "STUN\tCould not find host \"" << serverHost << "\".");
455     return false;
456   }
457 
458   PWaitAndSignal mutex(portInfo.mutex);
459 
460   WORD startPort = portInfo.currentPort;
461 
462   do {
463     portInfo.currentPort++;
464     if (portInfo.currentPort > portInfo.maxPort)
465       portInfo.currentPort = portInfo.basePort;
466 
467     if (socket.Listen(binding, 1, portInfo.currentPort)) {
468       socket.SetSendAddress(cachedServerAddress, serverPort);
469       socket.SetReadTimeout(replyTimeout);
470       return true;
471     }
472 
473   } while (portInfo.currentPort != startPort);
474 
475   PTRACE(1, "STUN\tFailed to bind to local UDP port in range "
476          << portInfo.currentPort << '-' << portInfo.maxPort);
477   return false;
478 }
479 
480 
GetNatType(PBoolean force)481 PSTUNClient::NatTypes PSTUNClient::GetNatType(PBoolean force)
482 {
483   if (!force && natType != UnknownNat)
484     return natType;
485 
486   PList<PUDPSocket> sockets;
487 
488   PIPSocket::InterfaceTable interfaces;
489   if (PIPSocket::GetInterfaceTable(interfaces)) {
490     for (PINDEX i = 0; i < interfaces.GetSize(); i++) {
491       PIPSocket::Address binding = interfaces[i].GetAddress();
492       if (!binding.IsLoopback() && binding.GetVersion() == 4) {
493         PUDPSocket * socket = new PUDPSocket;
494         if (OpenSocket(*socket, singlePortInfo, binding))
495           sockets.Append(socket);
496         else
497           delete socket;
498       }
499     }
500     if (interfaces.IsEmpty()) {
501       PTRACE(1, "STUN\tNo interfaces available to find STUN server.");
502       return natType = UnknownNat;
503     }
504   }
505   else {
506     PUDPSocket * socket = new PUDPSocket;
507     sockets.Append(socket);
508     if (!OpenSocket(*socket, singlePortInfo, PIPSocket::GetDefaultIpAny()))
509       return natType = UnknownNat;
510   }
511 
512   // RFC3489 discovery
513 
514   /* test I - the client sends a STUN Binding Request to a server, without
515      any flags set in the CHANGE-REQUEST attribute, and without the
516      RESPONSE-ADDRESS attribute. This causes the server to send the response
517      back to the address and port that the request came from. */
518   PSTUNMessage requestI(PSTUNMessage::BindingRequest);
519   requestI.AddAttribute(PSTUNChangeRequest(false, false));
520   PSTUNMessage responseI;
521 
522   PUDPSocket * replySocket = NULL;
523 
524   for (PINDEX retry = 0; retry < pollRetries; ++retry) {
525     PSocket::SelectList selectList;
526     for (PList<PUDPSocket>::iterator socket = sockets.begin(); socket != sockets.end(); ++socket) {
527       if (requestI.Write(*socket))
528         selectList += *socket;
529     }
530 
531     if (selectList.IsEmpty())
532       return natType = UnknownNat; // Could not send on any interface!
533 
534     PChannel::Errors error = PIPSocket::Select(selectList, replyTimeout);
535     if (error != PChannel::NoError) {
536       PTRACE(1, "STUN\tError in select - " << PChannel::GetErrorText(error));
537       return natType = UnknownNat;
538     }
539 
540     if (!selectList.IsEmpty()) {
541       PUDPSocket & udp = (PUDPSocket &)selectList.front();
542       if (responseI.Read(udp) && responseI.Validate(requestI)) {
543         replySocket = &udp;
544         break;
545       }
546     }
547   }
548 
549   if (replySocket == NULL) {
550     PTRACE(3, "STUN\tNo response to " << *this);
551     return natType = BlockedNat; // No response usually means blocked
552   }
553 
554   replySocket->GetLocalAddress(interfaceAddress);
555 
556   PSTUNMappedAddress * mappedAddress = (PSTUNMappedAddress *)responseI.FindAttribute(PSTUNAttribute::MAPPED_ADDRESS);
557   if (mappedAddress == NULL) {
558     PTRACE(2, "STUN\tExpected mapped address attribute from " << *this);
559     return natType = UnknownNat; // Protocol error
560   }
561 
562   PIPSocket::Address mappedAddressI = mappedAddress->GetIP();
563   WORD mappedPortI = mappedAddress->port;
564   bool notNAT = replySocket->GetPort() == mappedPortI && PIPSocket::IsLocalHost(mappedAddressI);
565 
566   /* Test II - the client sends a Binding Request with both the "change IP"
567      and "change port" flags from the CHANGE-REQUEST attribute set. */
568   PSTUNMessage requestII(PSTUNMessage::BindingRequest);
569   requestII.AddAttribute(PSTUNChangeRequest(true, true));
570   PSTUNMessage responseII;
571   bool testII = responseII.Poll(*replySocket, requestII, pollRetries);
572 
573   if (notNAT) {
574     // Is not NAT or symmetric firewall
575     return natType = (testII ? OpenNat : SymmetricFirewall);
576   }
577 
578   cachedExternalAddress = mappedAddressI;
579   timeAddressObtained.SetCurrentTime();
580 
581   if (testII)
582     return natType = ConeNat;
583 
584   PSTUNChangedAddress * changedAddress = (PSTUNChangedAddress *)responseI.FindAttribute(PSTUNAttribute::CHANGED_ADDRESS);
585   if (changedAddress == NULL)
586     return natType = UnknownNat; // Protocol error
587 
588   // Send test I to another server, to see if restricted or symmetric
589   PIPSocket::Address secondaryServer = changedAddress->GetIP();
590   WORD secondaryPort = changedAddress->port;
591   replySocket->SetSendAddress(secondaryServer, secondaryPort);
592   PSTUNMessage requestI2(PSTUNMessage::BindingRequest);
593   requestI2.AddAttribute(PSTUNChangeRequest(false, false));
594   PSTUNMessage responseI2;
595   if (!responseI2.Poll(*replySocket, requestI2, pollRetries)) {
596     PTRACE(2, "STUN\tPoll of secondary server " << secondaryServer << ':' << secondaryPort
597            << " failed, NAT partially blocked by firwall rules.");
598     return natType = PartialBlockedNat;
599   }
600 
601   mappedAddress = (PSTUNMappedAddress *)responseI2.FindAttribute(PSTUNAttribute::MAPPED_ADDRESS);
602   if (mappedAddress == NULL) {
603     PTRACE(2, "STUN\tExpected mapped address attribute from " << *this);
604     return UnknownNat; // Protocol error
605   }
606 
607   if (mappedAddress->port != mappedPortI || mappedAddress->GetIP() != mappedAddressI)
608     return natType = SymmetricNat;
609 
610   replySocket->SetSendAddress(cachedServerAddress, serverPort);
611   PSTUNMessage requestIII(PSTUNMessage::BindingRequest);
612   requestIII.SetAttribute(PSTUNChangeRequest(false, true));
613   PSTUNMessage responseIII;
614   return natType = (responseIII.Poll(*replySocket, requestIII, pollRetries) ? RestrictedNat : PortRestrictedNat);
615 }
616 
617 
GetNatTypeString(NatTypes type)618 PString PSTUNClient::GetNatTypeString(NatTypes type)
619 {
620   static const char * const Names[NumNatTypes] = {
621     "Unknown NAT",
622     "Open NAT",
623     "Cone NAT",
624     "Restricted NAT",
625     "Port Restricted NAT",
626     "Symmetric NAT",
627     "Symmetric Firewall",
628     "Blocked",
629     "Partially Blocked"
630   };
631 
632   if (type < NumNatTypes)
633     return Names[type];
634 
635   return psprintf("<NATType %u>", type);
636 }
637 
638 
GetRTPSupport(PBoolean force)639 PSTUNClient::RTPSupportTypes PSTUNClient::GetRTPSupport(PBoolean force)
640 {
641   switch (GetNatType(force)) {
642     // types that do support RTP
643     case OpenNat:
644     case ConeNat:
645       return RTPSupported;
646 
647     // types that support RTP if media sent first
648     case SymmetricFirewall:
649     case RestrictedNat:
650     case PortRestrictedNat:
651       return RTPIfSendMedia;
652 
653     // types that do not support RTP
654     case BlockedNat:
655     case SymmetricNat:
656       return RTPUnsupported;
657 
658     // types that have unknown RTP support
659     default:
660       return RTPUnknown;
661   }
662 }
663 
GetExternalAddress(PIPSocket::Address & externalAddress,const PTimeInterval & maxAge)664 PBoolean PSTUNClient::GetExternalAddress(PIPSocket::Address & externalAddress,
665                                      const PTimeInterval & maxAge)
666 {
667   if (cachedExternalAddress.IsValid() && (PTime() - timeAddressObtained < maxAge)) {
668     externalAddress = cachedExternalAddress;
669     return PTrue;
670   }
671 
672   externalAddress = 0; // Set to invalid address
673 
674   PUDPSocket socket;
675   if (!OpenSocket(socket, singlePortInfo, PIPSocket::GetDefaultIpAny()))
676     return false;
677 
678   PSTUNMessage request(PSTUNMessage::BindingRequest);
679   request.AddAttribute(PSTUNChangeRequest(false, false));
680   PSTUNMessage response;
681   if (!response.Poll(socket, request, pollRetries))
682   {
683     PTRACE(1, "STUN\t" << *this << " unexpectedly went offline getting external address.");
684     return false;
685   }
686 
687   PSTUNMappedAddress * mappedAddress = (PSTUNMappedAddress *)response.FindAttribute(PSTUNAttribute::MAPPED_ADDRESS);
688   if (mappedAddress == NULL)
689   {
690     PTRACE(2, "STUN\tExpected mapped address attribute from " << *this);
691     return false;
692   }
693 
694 
695   externalAddress = cachedExternalAddress = mappedAddress->GetIP();
696   timeAddressObtained.SetCurrentTime();
697   return true;
698 }
699 
700 
GetInterfaceAddress(PIPSocket::Address & internalAddress) const701 bool PSTUNClient::GetInterfaceAddress(PIPSocket::Address & internalAddress) const
702 {
703   if (!interfaceAddress.IsValid())
704     return false;
705 
706   internalAddress = interfaceAddress;
707   return true;
708 }
709 
710 
InvalidateCache()711 void PSTUNClient::InvalidateCache()
712 {
713   cachedServerAddress = 0;
714   cachedExternalAddress = 0;
715   interfaceAddress = 0;
716   natType = UnknownNat;
717 }
718 
719 
CreateSocket(PUDPSocket * & socket,const PIPSocket::Address & binding,WORD localPort)720 PBoolean PSTUNClient::CreateSocket(PUDPSocket * & socket, const PIPSocket::Address & binding, WORD localPort)
721 {
722   socket = NULL;
723 
724   switch (GetNatType(PFalse)) {
725     case OpenNat :
726     case ConeNat :
727     case RestrictedNat :
728     case PortRestrictedNat :
729       break;
730 
731     case SymmetricNat :
732       if (localPort == 0 && (singlePortInfo.basePort == 0 || singlePortInfo.basePort > singlePortInfo.maxPort))
733       {
734         PTRACE(1, "STUN\tInvalid local UDP port range "
735                << singlePortInfo.currentPort << '-' << singlePortInfo.maxPort);
736         return PFalse;
737       }
738       break;
739 
740     default : // UnknownNet, SymmetricFirewall, BlockedNat
741       PTRACE(1, "STUN\tCannot create socket using NAT type " << GetNatTypeName());
742       return PFalse;
743   }
744 
745   if (!IsAvailable(binding)) {
746     PTRACE(1, "STUN\tCannot create socket using binding " << binding);
747     return PFalse;
748   }
749 
750   PSTUNUDPSocket * stunSocket = new PSTUNUDPSocket;
751 
752   PBoolean opened;
753   if (localPort == 0)
754     opened = OpenSocket(*stunSocket, singlePortInfo, interfaceAddress);
755   else {
756     PortInfo portInfo = localPort;
757     opened = OpenSocket(*stunSocket, portInfo, interfaceAddress);
758   }
759 
760   if (opened)
761   {
762     PSTUNMessage request(PSTUNMessage::BindingRequest);
763     request.AddAttribute(PSTUNChangeRequest(false, false));
764     PSTUNMessage response;
765 
766     if (response.Poll(*stunSocket, request, pollRetries))
767     {
768       PSTUNMappedAddress * mappedAddress = (PSTUNMappedAddress *)response.FindAttribute(PSTUNAttribute::MAPPED_ADDRESS);
769       if (mappedAddress != NULL)
770       {
771         stunSocket->externalIP = mappedAddress->GetIP();
772         if (GetNatType(PFalse) != SymmetricNat)
773           stunSocket->port = mappedAddress->port;
774         stunSocket->SetSendAddress(0, 0);
775         stunSocket->SetReadTimeout(PMaxTimeInterval);
776         socket = stunSocket;
777         return true;
778       }
779 
780       PTRACE(2, "STUN\tExpected mapped address attribute from " << *this);
781     }
782     else
783       PTRACE(1, "STUN\t" << *this << " unexpectedly went offline creating socket.");
784   }
785 
786   delete stunSocket;
787   return false;
788 }
789 
790 
CreateSocketPair(PUDPSocket * & socket1,PUDPSocket * & socket2,const PIPSocket::Address & binding)791 PBoolean PSTUNClient::CreateSocketPair(PUDPSocket * & socket1,
792                                    PUDPSocket * & socket2,
793                                    const PIPSocket::Address & binding)
794 {
795   socket1 = NULL;
796   socket2 = NULL;
797 
798   switch (GetNatType(PFalse)) {
799     case OpenNat :
800     case ConeNat :
801     case RestrictedNat :
802     case PortRestrictedNat :
803       break;
804 
805     case SymmetricNat :
806       if (pairedPortInfo.basePort == 0 || pairedPortInfo.basePort > pairedPortInfo.maxPort)
807       {
808         PTRACE(1, "STUN\tInvalid local UDP port range "
809                << pairedPortInfo.currentPort << '-' << pairedPortInfo.maxPort);
810         return PFalse;
811       }
812       break;
813 
814     default : // UnknownNet, SymmetricFirewall, BlockedNat
815       PTRACE(1, "STUN\tCannot create socket pair using NAT type " << GetNatTypeName());
816       return PFalse;
817   }
818 
819   if (!IsAvailable(binding)) {
820     PTRACE(1, "STUN\tCannot create socket using binding " << binding);
821     return PFalse;
822   }
823 
824   PINDEX i;
825 
826   PArray<PSTUNUDPSocket> stunSocket;
827   PArray<PSTUNMessage> request;
828   PArray<PSTUNMessage> response;
829 
830   for (i = 0; i < numSocketsForPairing; i++)
831   {
832     PINDEX idx = stunSocket.Append(new PSTUNUDPSocket);
833     if (!OpenSocket(stunSocket[idx], pairedPortInfo, interfaceAddress)) {
834       PTRACE(1, "STUN\tUnable to open socket to " << *this);
835       return false;
836     }
837 
838     idx = request.Append(new PSTUNMessage(PSTUNMessage::BindingRequest));
839     request[idx].AddAttribute(PSTUNChangeRequest(false, false));
840 
841     response.Append(new PSTUNMessage);
842   }
843 
844   for (i = 0; i < numSocketsForPairing; i++)
845   {
846     if (!response[i].Poll(stunSocket[i], request[i], pollRetries))
847     {
848       PTRACE(1, "STUN\t" << *this << " unexpectedly went offline creating socket pair.");
849       return false;
850     }
851   }
852 
853   for (i = 0; i < numSocketsForPairing; i++)
854   {
855     PSTUNMappedAddress * mappedAddress = (PSTUNMappedAddress *)response[i].FindAttribute(PSTUNAttribute::MAPPED_ADDRESS);
856     if (mappedAddress == NULL)
857     {
858       PTRACE(2, "STUN\tExpected mapped address attribute from " << *this);
859       return false;
860     }
861     if (GetNatType(PFalse) != SymmetricNat)
862       stunSocket[i].port = mappedAddress->port;
863     stunSocket[i].externalIP = mappedAddress->GetIP();
864   }
865 
866   for (i = 0; i < numSocketsForPairing; i++)
867   {
868     for (PINDEX j = 0; j < numSocketsForPairing; j++)
869     {
870       if ((stunSocket[i].port&1) == 0 && (stunSocket[i].port+1) == stunSocket[j].port) {
871         stunSocket[i].SetSendAddress(0, 0);
872         stunSocket[i].SetReadTimeout(PMaxTimeInterval);
873         stunSocket[j].SetSendAddress(0, 0);
874         stunSocket[j].SetReadTimeout(PMaxTimeInterval);
875         socket1 = &stunSocket[i];
876         socket2 = &stunSocket[j];
877         stunSocket.DisallowDeleteObjects();
878         stunSocket.Remove(socket1);
879         stunSocket.Remove(socket2);
880         stunSocket.AllowDeleteObjects();
881         return true;
882       }
883     }
884   }
885 
886   PTRACE(2, "STUN\tCould not get a pair of adjacent port numbers from NAT");
887   return false;
888 }
889 
IsAvailable(const PIPSocket::Address & binding)890 bool PSTUNClient::IsAvailable(const PIPSocket::Address & binding)
891 {
892   switch (GetNatType(PFalse)) {
893     case ConeNat :
894     case RestrictedNat :
895     case PortRestrictedNat :
896       break;
897 
898     case SymmetricNat :
899       if (pairedPortInfo.basePort == 0 || pairedPortInfo.basePort > pairedPortInfo.maxPort)
900         return false;
901       break;
902 
903     default : // UnknownNet, SymmetricFirewall, BlockedNat
904       return false;
905   }
906 
907   return binding.IsAny() || binding == interfaceAddress || binding == cachedExternalAddress;
908 }
909 
910 ////////////////////////////////////////////////////////////////
911 
PSTUNUDPSocket()912 PSTUNUDPSocket::PSTUNUDPSocket()
913   : externalIP(0)
914 {
915 }
916 
917 
GetLocalAddress(Address & addr)918 PBoolean PSTUNUDPSocket::GetLocalAddress(Address & addr)
919 {
920   if (!externalIP.IsValid())
921     return PUDPSocket::GetLocalAddress(addr);
922 
923   addr = externalIP;
924   return true;
925 }
926 
927 
GetLocalAddress(Address & addr,WORD & port)928 PBoolean PSTUNUDPSocket::GetLocalAddress(Address & addr, WORD & port)
929 {
930   if (!externalIP.IsValid())
931     return PUDPSocket::GetLocalAddress(addr, port);
932 
933   addr = externalIP;
934   port = GetPort();
935   return true;
936 }
937 
938 
939 // End of File ////////////////////////////////////////////////////////////////
940