PTLib  Version 2.14.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
pstun.h
Go to the documentation of this file.
1 /*
2  * pstun.h
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: 31475 $
27  * $Author: rjongbloed $
28  * $Date: 2014-02-15 14:40:04 +1100 (Sat, 15 Feb 2014) $
29  */
30 
31 #ifndef PTLIB_PSTUN_H
32 #define PTLIB_PSTUN_H
33 
34 #ifdef P_USE_PRAGMA
35 #pragma interface
36 #endif
37 
38 #include <ptlib.h>
39 
40 #if P_STUN
41 
42 #include <ptclib/pnat.h>
43 #include <ptlib/sockets.h>
44 #include <ptclib/cypher.h>
45 
46 
48 
49 class PSTUNMessage;
50 class PSTUNUDPSocket;
51 
52 class PSTUN {
53  public:
54  enum {
55  DefaultPort = 3478
56  };
57 
58  enum {
59  MinChannelNumber = 0x4000,
60  MaxChannelNumber = 0x7ffe,
61  };
62 
63  PSTUN();
64  virtual ~PSTUN() { }
65 
68  virtual PNatMethod::NatTypes DoRFC3489Discovery(
69  PSTUNUDPSocket * socket,
70  const PIPSocketAddressAndPort & serverAddress,
71  PIPSocketAddressAndPort & baseAddressAndPort,
72  PIPSocketAddressAndPort & externalAddressAndPort
73  );
74 
75  virtual PNatMethod::NatTypes FinishRFC3489Discovery(
76  PSTUNMessage & responseI,
77  PSTUNUDPSocket * socket,
78  PIPSocketAddressAndPort & externalAddressAndPort
79  );
80 
81  virtual int MakeAuthenticatedRequest(
82  PSTUNUDPSocket * socket,
83  PSTUNMessage & request,
84  PSTUNMessage & response
85  );
86 
87  virtual bool GetFromBindingResponse(
88  const PSTUNMessage & response,
89  PIPSocketAddressAndPort & externalAddress
90  );
91 
92  virtual void AppendMessageIntegrity(
93  PSTUNMessage & message
94  );
95 
96  virtual void SetCredentials(
97  const PString & username,
98  const PString & password,
99  const PString & realm
100  );
101 
104  virtual const PTimeInterval GetTimeout() const { return replyTimeout; }
105 
108  virtual void SetTimeout(
109  const PTimeInterval & timeout
110  ) { replyTimeout = timeout; }
111 
114  virtual PINDEX GetRetries() const { return m_pollRetries; }
115 
118  virtual void SetRetries(
119  PINDEX retries
120  ) { m_pollRetries = retries; }
121 
126  PBYTEArray m_password; // text for short term, MD5 for long term
130 };
131 
133 
134 #pragma pack(1)
135 
137 {
138  enum Types {
139  MAPPED_ADDRESS = 0x0001, // RFC 3489 & RFC 5389
140  RESPONSE_ADDRESS = 0x0002, // RFC 3489 & RFC 5389
141  CHANGE_REQUEST = 0x0003, // RFC 3489 & RFC 5389 (added in RFC 5780)
142  SOURCE_ADDRESS = 0x0004, // RFC 3489
143  CHANGED_ADDRESS = 0x0005, // RFC 3489
144  USERNAME = 0x0006, // RFC 3489 & RFC 5389
145  PASSWORD = 0x0007, // RFC 3489 (deprecated)
146  MESSAGE_INTEGRITY = 0x0008, // RFC 3489 & RFC 5389
147  ERROR_CODE = 0x0009, // RFC 3489 & RFC 5389
148  UNKNOWN_ATTRIBUTES = 0x000a, // RFC 3489 & RFC 5389
149  REFLECTED_FROM = 0x000b, // RFC 3489
150 
151  CHANNEL_NUMBER = 0x000C, // RFC 5766
152  LIFETIME = 0x000D, // RFC 5766
153  //BANDWIDTH = 0x0010,
154  XOR_PEER_ADDRESS = 0x0012, // RFC 5766
155  DATA = 0x0013, // RFC 5766
156 
157  REALM = 0x0014, // RFC 5389
158  NONCE = 0x0015, // RFC 5389
159 
160  XOR_RELAYED_ADDRESS = 0x0016, // RFC 5766
161  EVEN_PORT = 0x0018, // RFC 5766
162  REQUESTED_TRANSPORT = 0x0019, // RFC 5766
163  DONT_FRAGMENT = 0x001A, // RFC 5766
164  XOR_MAPPED_ADDRESS = 0x0020, // RFC 5389
165 
166  // TIMER-VAL = 0x0021,
167  RESERVATION_TOKEN = 0x0022, // RFC 5766
168 
169  PRIORITY = 0x0024, // RFC 5245 (ICE)
170  USE_CANDIDATE = 0x0025, // RFC 5245 (ICE)
171  ICE_CONTROLLED = 0x8029, // RFC 5245 (ICE)
172  ICE_CONTROLLING = 0x802A, // RFC 5245 (ICE)
173 
174  PADDING = 0x0026, // RFC 5389 (added in RFC 5780)
175  RESPONSE_PORT = 0x0027, // RFC 5389 (added in RFC 5780)
176 
177  FINGERPRINT = 0x8028, // RFC 5389
178 
179  ALTERNATE_SERVER = 0x8023, // RFC 5389
180 
181  RESPONSE_ORIGIN = 0x802b, // RFC 5389 (added in RFC 5780)
182  OTHER_ADDRESS = 0x802c // RFC 5389 (added in RFC 5780)
183  };
184 
185  PUInt16b type;
186  PUInt16b length;
187 
188  PSTUNAttribute(Types newType = ERROR_CODE, size_t len = 0)
189  : type((WORD)newType)
190  , length((WORD)len)
191  {
192  }
193 
194  PSTUNAttribute * GetNext() const;
195 };
196 
198 
200 {
201  protected:
202  BYTE pad;
203  BYTE family;
204  PUInt16b port;
205  BYTE ip[4];
206 
207  public:
210  , pad(0)
211  , family(1)
212  {
213  SetIPAndPort(addrAndPort);
214  }
215 
216  WORD GetPort() const;
217  PIPSocket::Address GetIP() const;
218  void SetIPAndPort(const PIPSocketAddressAndPort & addrAndPort);
219  void GetIPAndPort(PIPSocketAddressAndPort & addrAndPort);
220 
221  protected:
222  enum { SizeofAddressAttribute = sizeof(BYTE)+sizeof(BYTE)+sizeof(WORD)+4 };
223  bool IsValidAddrAttr(Types checkType) const { return type == checkType && length == SizeofAddressAttribute; }
224 };
225 
226 
228 {
229  public:
230  char m_string[763]; // not actually 763, but this will do
231 
232  PSTUNStringAttribute(Types newType, const PString & str)
233  : PSTUNAttribute(newType, str.GetLength())
234  {
235  memcpy(m_string, (const char *)str, length);
236  }
237 
238  PString GetString() const
239  {
240  return PString(m_string, length);
241  }
242 
243  bool IsValidStringAttr(Types checkType) const
244  {
245  return (type == checkType) && (length == strlen(m_string));
246  }
247 };
248 
249 
251 {
252  public:
253  BYTE flags[4];
254 
255  PSTUNChangeRequest(bool changeIP = false, bool changePort = false)
256  : PSTUNAttribute(CHANGE_REQUEST, sizeof(flags))
257  {
258  memset(flags, 0, sizeof(flags));
259  SetChangeIP(changeIP);
260  SetChangePort(changePort);
261  }
262 
263  bool IsValid() const { return type == CHANGE_REQUEST && length == sizeof(flags); }
264 
265  bool GetChangeIP() const { return (flags[3]&4) != 0; }
266  void SetChangeIP(bool on) { if (on) flags[3] |= 4; else flags[3] &= ~4; }
267 
268  bool GetChangePort() const { return (flags[3]&2) != 0; }
269  void SetChangePort(bool on) { if (on) flags[3] |= 2; else flags[3] &= ~2; }
270 };
271 
272 
274 {
275  public:
276  BYTE m_hmac[PHMAC::KeyLength];
277 
278  PSTUNMessageIntegrity(const BYTE * hmac = NULL)
279  : PSTUNAttribute(MESSAGE_INTEGRITY, sizeof(m_hmac))
280  {
281  if (hmac == NULL)
282  memset(m_hmac, 0, sizeof(m_hmac));
283  else
284  memcpy(m_hmac, hmac, sizeof(m_hmac));
285  }
286 
287  bool IsValid() const { return type == MESSAGE_INTEGRITY && length == sizeof(m_hmac); }
288 };
289 
290 
292 {
293  public:
294  PUInt32b m_crc;
295 
296  PSTUNFingerprint(DWORD crc = 0)
297  : PSTUNAttribute(FINGERPRINT, sizeof(m_crc))
298  , m_crc(crc)
299  {
300  }
301 
302  bool IsValid() const { return type == FINGERPRINT && length == sizeof(m_crc); }
303 };
304 
305 
307 {
308  public:
310  {
311  Initialise();
312  }
313 
314  PSTUNErrorCode(int code, const PString & reason = PString::Empty())
315  {
316  Initialise();
317  SetErrorCode(code, reason);
318  }
319 
320  BYTE m_zero1;
321  BYTE m_zero2;
323  BYTE m_units;
324  char m_reason[256]; // not actually 256, but this will do
325 
326  void Initialise();
327  void SetErrorCode(int code, const PString & reason);
328  int GetErrorCode() const { return (m_hundreds * 100) + m_units; }
329  PString GetReason() { return PString(m_reason); }
330  bool IsValid() const { return (type == ERROR_CODE) && (length == 4 + strlen(m_reason) + 1); }
331 };
332 
334 {
336  { Initialise(); }
337 
338  PUInt16b m_channelNumber;
339  PUInt16b m_rffu;
340 
341  void Initialise();
342 };
343 
345 {
346  PUInt16b msgType;
347  PUInt16b msgLength;
348  BYTE transactionId[16];
349 };
350 
351 #pragma pack()
352 
354 
355 
356 class PSTUNClient;
357 
360 class PSTUNUDPSocket : public PNATUDPSocket
361 {
362  PCLASSINFO(PSTUNUDPSocket, PNATUDPSocket);
363  public:
365  PNatMethod::Component component
366  );
367 
368  virtual const char * GetNatName() const;
369 
370  bool OpenSTUN(PSTUNClient & client);
371  virtual void GetCandidateInfo(PNatCandidate & candidate);
372 
373  bool BaseWriteTo(const void * buf, PINDEX len, const PIPSocketAddressAndPort & ap)
374  { Slice slice((void *)buf, len); return PUDPSocket::InternalWriteTo(&slice, 1, ap); }
375 
376  bool BaseReadFrom(void * buf, PINDEX len, PIPSocketAddressAndPort & ap)
377  { Slice slice(buf, len); return PUDPSocket::InternalReadFrom(&slice, 1, ap); }
378 
379  protected:
380  friend class PSTUN;
381  friend class PSTUNClient;
382 
385 
386  bool InternalGetLocalAddress(PIPSocketAddressAndPort & addr);
387 
388  private:
389  PNatMethod::NatTypes m_natType;
390 };
391 
393 
394 class PSTUNMessage : public PBYTEArray
395 {
396  public:
397  enum MsgType {
399 
400  BindingRequest = 0x0001,
401  BindingResponse = 0x0101,
402  BindingError = 0x0111,
403 
404  SharedSecretRequest = 0x0002,
405  SharedSecretResponse = 0x0102,
406  SharedSecretError = 0x0112,
407 
408  Allocate = 0x0003, // RFC 5766
409  AllocateResponse = 0x0103, // RFC 5766
410  AllocateError = 0x0113, // RFC 5766
411 
412  Refresh = 0x0004, // RFC 5766
413  Send = 0x0006, // RFC 5766
414  Data = 0x0007, // RFC 5766
415  CreatePermission = 0x0008, // RFC 5766
416  ChannelBind = 0x0009, // RFC 5766
417 
418  };
419 
420  PSTUNMessage();
421  PSTUNMessage(MsgType newType, const BYTE * id = NULL);
422  PSTUNMessage(const BYTE * data, PINDEX size, const PIPSocketAddressAndPort & srcAddr);
423 
424 #if PTRACING
425  void PrintOn(ostream & strm) const;
426 #endif
427 
428  bool IsValid() const;
429  bool IsValidFor(const PSTUNMessage & request) const;
430 
431  const BYTE * GetTransactionID() const;
432 
433  bool IsRFC5389() const;
434 
435  const PSTUNMessageHeader * operator->() const { return (const PSTUNMessageHeader *)theArray; }
436 
437  MsgType GetType() const;
438  void SetType(MsgType newType, const BYTE * id = NULL);
439  void SetErrorType(int code, const BYTE * id, const char * reason = NULL);
440 
441  PSTUNAttribute * AddAttribute(const PSTUNAttribute & attribute);
442  PSTUNAttribute * SetAttribute(const PSTUNAttribute & attribute);
443  PSTUNAttribute * FindAttribute(PSTUNAttribute::Types type) const;
444 
445  template <class Type> Type * FindAttributeAs(PSTUNAttribute::Types type) const
446  { return static_cast<Type *>(FindAttribute(type)); }
447 
448  bool Read(PUDPSocket & socket);
449  bool Write(PUDPSocket & socket) const;
450  bool Write(PUDPSocket & socket, const PIPSocketAddressAndPort & ap) const;
451  bool Poll(PUDPSocket & socket, const PSTUNMessage & request, PINDEX pollRetries);
452 
453  const PIPSocketAddressAndPort GetSourceAddressAndPort() const { return m_sourceAddressAndPort; }
454 
455  void AddMessageIntegrity(const PBYTEArray & credentialsHash) { AddMessageIntegrity(credentialsHash, credentialsHash.GetSize()); }
456  void AddMessageIntegrity(const BYTE * credentialsHashPtr, PINDEX credentialsHashLen, PSTUNMessageIntegrity * mi = NULL);
457 
458  bool CheckMessageIntegrity(const PBYTEArray & credentialsHash) const { return CheckMessageIntegrity(credentialsHash, credentialsHash.GetSize()); }
459  bool CheckMessageIntegrity(const BYTE * credentialsHashPtr, PINDEX credentialsHashLen) const;
460 
461  void AddFingerprint(PSTUNFingerprint * fp = NULL);
462  bool CheckFingerprint(bool required) const;
463 
464  protected:
465  PSTUNAttribute * GetFirstAttribute() const;
466  void CalculateMessageIntegrity(const BYTE * credentialsHash, PINDEX credentialsHashLen, PSTUNMessageIntegrity * mi, BYTE * hmac) const;
467  DWORD CalculateFingerprint(PSTUNFingerprint * fp) const;
468 
470 };
471 
473 
476 class PSTUNClient : public PNatMethod, public PSTUN
477 {
478  PCLASSINFO(PSTUNClient, PNatMethod);
479  public:
480  enum { DefaultPriority = 40 };
481  PSTUNClient(unsigned priority = DefaultPriority);
482  ~PSTUNClient();
483 
486  static const char * MethodName();
487  virtual PCaselessString GetMethodName() const;
488 
495  bool SetServer(
496  const PString & server
497  );
498 
502  virtual PString GetServer() const;
503 
504  virtual bool GetServerAddress(
505  PIPSocketAddressAndPort & serverAddressAndPort
506  ) const;
507 
508  virtual bool GetInterfaceAddress(
509  PIPSocket::Address & internalAddress
510  ) const;
511 
512  virtual bool Open(
513  const PIPSocket::Address & ifaceAddr
514  );
515 
516  virtual bool IsAvailable(
517  const PIPSocket::Address & binding,
518  PObject * userData
519  );
520 
521  virtual void Close();
522 
535  virtual bool CreateSocket(
536  PUDPSocket * & socket,
538  WORD localPort = 0,
539  PObject * context = NULL,
540  Component component = eComponent_Unknown
541  );
542 
556  virtual bool CreateSocketPair(
557  PUDPSocket * & socket1,
558  PUDPSocket * & socket2,
560  PObject * context = NULL
561  );
562 
563  protected:
564  virtual PNATUDPSocket * InternalCreateSocket(Component component, PObject * context);
565  virtual void InternalUpdate();
566  bool InternalSetServer(const PIPSocketAddressAndPort & addr);
567 
569 
570  private:
571  PString m_serverName;
572  PINDEX m_numSocketsForPairing;
573 };
574 
575 
577 
582 {
583  public:
584  enum {
585  ProtocolUDP = IPPROTO_UDP,
586  ProtocolTCP = IPPROTO_TCP
587  };
589  BYTE m_rffu1;
590  BYTE m_rffu2;
591  BYTE m_rffu3;
592 
593  PTURNRequestedTransport(BYTE protocol = ProtocolUDP)
594  { Initialise(protocol); }
595 
596  void Initialise(BYTE protocol = ProtocolUDP);
597  bool IsValid() const { return (type == REQUESTED_TRANSPORT) && (length == 4); }
598 };
599 
600 
602 {
603  public:
604  PUInt32b m_lifetime;
605 
606  PTURNLifetime(DWORD lifetime = 600)
607  : m_lifetime(lifetime)
608  { type = LIFETIME; length = 4; }
609 
610  bool IsValid() const { return (type == LIFETIME) && (length == 8); }
611 
612  DWORD GetLifetime() const { return m_lifetime; }
613 };
614 
615 
617 {
618  public:
619  BYTE m_bits;
620 
621  PTURNEvenPort(bool evenPort = true)
622  { type = EVEN_PORT; m_bits = evenPort ? 1 : 0; length = 1; }
623 
624  bool IsValid() const { return (type == EVEN_PORT) && (length == 1); }
625 
626  bool IsEven() const { return (m_bits & 1) != 0; }
627 };
628 
630 
631 class PTURNClient;
632 
633 #pragma pack(1)
634 
636  PUInt16b m_channelNumber;
637  PUInt16b m_length;
638 };
639 
640 #pragma pack()
641 
642 class PTURNUDPSocket : public PSTUNUDPSocket, public PSTUN
643 {
644  public:
645 
646  friend class PTURNClient;
647 
649  PNatMethod::Component component
650  );
651  ~PTURNUDPSocket();
652 
653  virtual const char * GetNatName() const;
654 
655  virtual bool Close();
656 
657  virtual void GetCandidateInfo(PNatCandidate & candidate);
658 
659  int OpenTURN(PTURNClient & client);
660 
661  protected:
662  bool InternalGetLocalAddress(PIPSocketAddressAndPort & addr);
663  bool InternalWriteTo(const Slice * slices, size_t sliceCount, const PIPSocketAddressAndPort & ipAndPort);
664  bool InternalReadFrom(Slice * slices, size_t sliceCount, PIPSocketAddressAndPort & ipAndPort);
665  void InternalSetSendAddress(const PIPSocketAddressAndPort & addr);
666  void InternalGetSendAddress(PIPSocketAddressAndPort & addr);
667 
671 
674  DWORD m_lifeTime;
676 
677  std::vector<Slice> m_txVect;
679  BYTE m_txPadding[4];
680 
681  std::vector<Slice> m_rxVect;
683  BYTE m_rxPadding[4];
684 };
685 
687 
688 class PTURNClient : public PSTUNClient
689 {
691  public:
692 
693  friend class PTURNUDPSocket;
694 
697  static const char * MethodName();
698  virtual PCaselessString GetMethodName() const;
699 
700  enum { DefaultPriority = 30 };
701  PTURNClient(unsigned priority = DefaultPriority);
702 
703  // overrides from PNatMethod
704  bool CreateSocket(
705  PUDPSocket * & socket,
707  WORD localPort = 0,
708  PObject * context = NULL,
709  Component component = eComponent_Unknown
710  );
711 
712  bool CreateSocketPair(
713  PUDPSocket * & socket1,
714  PUDPSocket * & socket2,
716  PObject * context = NULL
717  );
718 
722  virtual RTPSupportTypes GetRTPSupport(
723  bool force = false
724  );
725 
726  protected:
727  virtual PNATUDPSocket * InternalCreateSocket(Component component, PObject * context);
728  // New functions
729  virtual bool RefreshAllocation(DWORD lifetime = 600);
730 };
731 
732 
733 #endif // P_STUN
734 
735 #endif // PTLIB_PSTUN_H