PTLib  Version 2.12.9
 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: 28623 $
27  * $Author: rjongbloed $
28  * $Date: 2012-12-03 15:09:17 +1100 (Mon, 03 Dec 2012) $
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 <ptbuildopts.h>
39 
40 #if P_STUN
41 
42 #include <ptclib/pnat.h>
43 #include <ptlib/sockets.h>
44 
46 
47 class PSTUNMessage;
48 class PSTUNUDPSocket;
49 
50 class PSTUN {
51  public:
52  enum {
53  DefaultPort = 3478
54  };
55 
56  enum {
57  MinChannelNumber = 0x4000,
58  MaxChannelNumber = 0x7ffe,
59  };
60 
61  PSTUN();
62  virtual ~PSTUN() { }
63 
66  virtual PNatMethod::NatTypes DoRFC3489Discovery(
67  PSTUNUDPSocket * socket,
68  const PIPSocketAddressAndPort & serverAddress,
69  PIPSocketAddressAndPort & baseAddressAndPort,
70  PIPSocketAddressAndPort & externalAddressAndPort
71  );
72 
73  virtual PNatMethod::NatTypes FinishRFC3489Discovery(
74  PSTUNMessage & responseI,
75  PSTUNUDPSocket * socket,
76  PIPSocketAddressAndPort & externalAddressAndPort
77  );
78 
79  virtual int MakeAuthenticatedRequest(
80  PSTUNUDPSocket * socket,
81  PSTUNMessage & request,
82  PSTUNMessage & response
83  );
84 
85  virtual bool GetFromBindingResponse(
86  const PSTUNMessage & response,
87  PIPSocketAddressAndPort & externalAddress
88  );
89 
90  virtual void AppendMessageIntegrity(
91  PSTUNMessage & message
92  );
93 
94  virtual void SetCredentials(
95  const PString & username,
96  const PString & password,
97  const PString & realm
98  );
99 
102  virtual const PTimeInterval GetTimeout() const { return replyTimeout; }
103 
106  virtual void SetTimeout(
107  const PTimeInterval & timeout
108  ) { replyTimeout = timeout; }
109 
112  virtual PINDEX GetRetries() const { return m_pollRetries; }
113 
116  virtual void SetRetries(
117  PINDEX retries
118  ) { m_pollRetries = retries; }
119 
120  PNatMethod::NatTypes m_natType;
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
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  PADDING = 0x0026, // RFC 5389 (added in RFC 5780)
170  RESPONSE_PORT = 0x0027, // RFC 5389 (added in RFC 5780)
171 
172  ALTERNATE_SERVER = 0x8023, // RFC 5389
173 
174  RESPONSE_ORIGIN = 0x802b, // RFC 5389 (added in RFC 5780)
175  OTHER_ADDRESS = 0x802c // RFC 5389 (added in RFC 5780)
176  };
177 
178  PUInt16b type;
179  PUInt16b length;
180 
181  PSTUNAttribute * GetNext() const;
182 };
183 
185 
187 {
188  protected:
189  BYTE pad;
190  BYTE family;
191  PUInt16b port;
192  BYTE ip[4];
193 
194  public:
195  void InitAddrAttr(Types newType)
196  {
197  pad = 0;
198  family = 1;
199  type = (WORD)newType;
201  }
202 
203  WORD GetPort() const;
204  PIPSocket::Address GetIP() const;
205  void SetIPAndPort(const PIPSocketAddressAndPort & addrAndPort);
206  void GetIPAndPort(PIPSocketAddressAndPort & addrAndPort);
207 
208  protected:
209  enum { SizeofAddressAttribute = sizeof(BYTE)+sizeof(BYTE)+sizeof(WORD)+4 };
210  bool IsValidAddrAttr(Types checkType) const
211  {
212  return type == checkType && length == SizeofAddressAttribute;
213  }
214 };
215 
216 
218 {
219  public:
220  char m_string[763]; // not actually 763, but this will do
221 
222  PSTUNStringAttribute(Types newType, const PString & str)
223  { InitStringAttr(newType, str); }
224 
225  PString GetString() const { return PString(m_string, length); }
226 
227  void InitStringAttr(Types newType, const PString & str)
228  {
229  type = (WORD)newType;
230  length = (WORD)str.GetLength();
231  memcpy(m_string, (const char *)str, length);
232  }
233 
234  bool IsValidStringAttr(Types checkType) const
235  {
236  return (type == checkType) && (length == strlen(m_string));
237  }
238 };
239 
240 
242 {
243  public:
244  BYTE flags[4];
245 
247 
248  PSTUNChangeRequest(bool changeIP, bool changePort)
249  {
250  Initialise();
251  SetChangeIP(changeIP);
252  SetChangePort(changePort);
253  }
254 
255  void Initialise()
256  {
258  length = sizeof(flags);
259  memset(flags, 0, sizeof(flags));
260  }
261 
262  bool IsValid() const { return type == CHANGE_REQUEST && length == sizeof(flags); }
263 
264  bool GetChangeIP() const { return (flags[3]&4) != 0; }
265  void SetChangeIP(bool on) { if (on) flags[3] |= 4; else flags[3] &= ~4; }
266 
267  bool GetChangePort() const { return (flags[3]&2) != 0; }
268  void SetChangePort(bool on) { if (on) flags[3] |= 2; else flags[3] &= ~2; }
269 };
270 
272 {
273  public:
274  BYTE hmac[20];
275 
276  PSTUNMessageIntegrity(const BYTE * data = NULL)
277  { Initialise(data); }
278 
279  void Initialise(const BYTE * data = NULL)
280  {
282  length = sizeof(hmac);
283  if (data == NULL)
284  memset(hmac, 0, sizeof(hmac));
285  else
286  memcpy(hmac, data, sizeof(hmac));
287  }
288  bool IsValid() const { return type == MESSAGE_INTEGRITY && length == sizeof(hmac); }
289 };
290 
292 {
293  public:
295  { Initialise(); }
296 
297  BYTE m_zero1;
298  BYTE m_zero2;
300  BYTE m_units;
301  char m_reason[256]; // not actually 256, but this will do
302 
303  void Initialise();
304  void SetErrorCode(int code, const PString & reason);
305  int GetErrorCode() const { return (m_hundreds * 100) + m_units; }
306  PString GetReason() { return PString(m_reason); }
307  bool IsValid() const { return (type == ERROR_CODE) && (length == 4 + strlen(m_reason) + 1); }
308 };
309 
311 {
313  { Initialise(); }
314 
315  PUInt16b m_channelNumber;
316  PUInt16b m_rffu;
317 
318  void Initialise();
319 };
320 
322 {
323  PUInt16b msgType;
324  PUInt16b msgLength;
325  BYTE transactionId[16];
326 };
327 
328 #pragma pack()
329 
331 
332 
333 class PSTUNClient;
334 
337 class PSTUNUDPSocket : public PNATUDPSocket
338 {
339  PCLASSINFO(PSTUNUDPSocket, PNATUDPSocket);
340  public:
341  PSTUNUDPSocket();
342 
343  bool OpenSTUN(PSTUNClient & client);
344  PNatCandidate GetCandidateInfo();
345 
346  bool BaseWriteTo(const void * buf, PINDEX len, const PIPSocketAddressAndPort & ap)
347  { Slice slice((void *)buf, len); return PUDPSocket::InternalWriteTo(&slice, 1, ap); }
348 
349  bool BaseReadFrom(void * buf, PINDEX len, PIPSocketAddressAndPort & ap)
350  { Slice slice(buf, len); return PUDPSocket::InternalReadFrom(&slice, 1, ap); }
351 
352  protected:
353  friend class PSTUN;
354  friend class PSTUNClient;
355 
358 
359  bool InternalGetLocalAddress(PIPSocketAddressAndPort & addr);
360  bool InternalGetBaseAddress(PIPSocketAddressAndPort & addr);
361 
362  private:
363  PNatMethod::NatTypes m_natType;
364 };
365 
367 
368 class PSTUNMessage : public PBYTEArray
369 {
370  public:
371  enum MsgType {
372  BindingRequest = 0x0001,
373  BindingResponse = 0x0101,
374  BindingError = 0x0111,
375 
376  SharedSecretRequest = 0x0002,
377  SharedSecretResponse = 0x0102,
378  SharedSecretError = 0x0112,
379 
380  Allocate = 0x0003, // RFC 5766
381  AllocateResponse = 0x0103, // RFC 5766
382  AllocateError = 0x0113, // RFC 5766
383 
384  Refresh = 0x0004, // RFC 5766
385  Send = 0x0006, // RFC 5766
386  Data = 0x0007, // RFC 5766
387  CreatePermission = 0x0008, // RFC 5766
388  ChannelBind = 0x0009, // RFC 5766
389 
390  };
391 
392  PSTUNMessage();
393  PSTUNMessage(MsgType newType, const BYTE * id = NULL);
394 
395  void SetType(MsgType newType, const BYTE * id = NULL);
396  MsgType GetType() const;
397 
398  const BYTE * GetTransactionID() const;
399 
400  const PSTUNMessageHeader * operator->() const { return (const PSTUNMessageHeader *)theArray; }
401 
402  PSTUNAttribute * GetFirstAttribute() const;
403 
404  bool Validate();
405  bool Validate(const PSTUNMessage & request);
406 
407  PSTUNAttribute * AddAttribute(const PSTUNAttribute & attribute);
408  PSTUNAttribute * SetAttribute(const PSTUNAttribute & attribute);
409  PSTUNAttribute * FindAttribute(PSTUNAttribute::Types type) const;
410 
411  template <class Type> Type * FindAttributeOfType(PSTUNAttribute::Types type) const
412  { return static_cast<Type *>(FindAttribute(type)); }
413 
414  bool Read(PUDPSocket & socket);
415  bool Write(PUDPSocket & socket) const;
416  bool Poll(PUDPSocket & socket, const PSTUNMessage & request, PINDEX pollRetries);
417 
418  bool IsRFC5389() const { return m_isRFC5389; }
419 
420  const PIPSocketAddressAndPort GetSourceAddressAndPort() const { return m_sourceAddressAndPort; }
421 
422  void InsertMessageIntegrity(BYTE * credentialsHash, PINDEX credentialsHashLen);
423  void InsertMessageIntegrity(BYTE * credentialsHash, PINDEX credentialsHashLen, PSTUNMessageIntegrity * mi);
424 
425  bool CheckMessageIntegrity(BYTE * credentialsHash, PINDEX credentialsHashLen);
426  void CalculateMessageIntegrity(BYTE * credentialsHash, PINDEX credentialsHashLen, PSTUNMessageIntegrity * mi, BYTE * hmac);
427 
428  protected:
431 };
432 
434 
437 class PSTUNClient : public PNatMethod, public PSTUN
438 {
439  PCLASSINFO(PSTUNClient, PNatMethod);
440  public:
441  PSTUNClient();
442  ~PSTUNClient();
443 
446  static PString GetNatMethodName();
447  virtual PString GetName() const;
448 
455  bool SetServer(
456  const PString & server
457  );
458 
462  virtual PString GetServer() const;
463 
464  virtual bool GetServerAddress(
465  PIPSocketAddressAndPort & serverAddressAndPort
466  ) const;
467 
468  virtual bool GetExternalAddress(
469  PIPSocket::Address & externalAddress,
470  const PTimeInterval & maxAge = 1000
471  );
472 
473  virtual bool GetInterfaceAddress(
474  PIPSocket::Address & internalAddress
475  ) const;
476 
477  virtual bool Open(
478  const PIPSocket::Address & ifaceAddr
479  );
480 
481  bool IsAvailable(
482  const PIPSocket::Address & binding
483  );
484 
485  virtual void Close();
486 
487  // new functions
488  NatTypes FindNatType(
489  const PIPSocket::Address & binding
490  );
491 
504  bool CreateSocket(
505  Component component,
506  PUDPSocket * & socket,
508  WORD port = 0
509  );
510 
524  virtual bool CreateSocketPair(
525  PUDPSocket * & socket1,
526  PUDPSocket * & socket2,
528  );
529 
530  bool InternalOpenSocket(Component component, const PIPSocket::Address & binding, PSTUNUDPSocket & socket, PortInfo & portInfo);
531 
532  protected:
533  virtual NatTypes InternalGetNatType(bool forced, const PTimeInterval & maxAge);
534 
537 
538  private:
539  PIPSocketAddressAndPort m_externalAddress;
540  PINDEX numSocketsForPairing;
541 };
542 
543 
545 
550 {
551  public:
552  enum {
553  ProtocolUDP = IPPROTO_UDP,
554  ProtocolTCP = IPPROTO_TCP
555  };
557  BYTE m_rffu1;
558  BYTE m_rffu2;
559  BYTE m_rffu3;
560 
561  PTURNRequestedTransport(BYTE protocol = ProtocolUDP)
562  { Initialise(protocol); }
563 
564  void Initialise(BYTE protocol = ProtocolUDP);
565  bool IsValid() const { return (type == REQUESTED_TRANSPORT) && (length == 4); }
566 };
567 
568 
570 {
571  public:
572  PUInt32b m_lifetime;
573 
574  PTURNLifetime(DWORD lifetime = 600)
575  : m_lifetime(lifetime)
576  { type = LIFETIME; length = 4; }
577 
578  bool IsValid() const { return (type == LIFETIME) && (length == 8); }
579 
580  DWORD GetLifetime() const { return m_lifetime; }
581 };
582 
583 
585 {
586  public:
587  BYTE m_bits;
588 
589  PTURNEvenPort(bool evenPort = true)
590  { type = EVEN_PORT; m_bits = evenPort ? 1 : 0; length = 1; }
591 
592  bool IsValid() const { return (type == EVEN_PORT) && (length == 1); }
593 
594  bool IsEven() const { return (m_bits & 1) != 0; }
595 };
596 
598 
599 class PTURNClient;
600 
601 #pragma pack(1)
602 
604  PUInt16b m_channelNumber;
605  PUInt16b m_length;
606 };
607 
608 #pragma pack()
609 
610 class PTURNUDPSocket : public PSTUNUDPSocket, public PSTUN
611 {
612  public:
613 
614  friend class PTURNClient;
615 
616  PTURNUDPSocket();
617  ~PTURNUDPSocket();
618 
619  virtual bool Close();
620 
621  virtual PNatCandidate GetCandidateInfo();
622 
623  int OpenTURN(PTURNClient & client);
624 
625  protected:
626  bool InternalGetLocalAddress(PIPSocketAddressAndPort & addr);
627  bool InternalWriteTo(const Slice * slices, size_t sliceCount, const PIPSocketAddressAndPort & ipAndPort);
628  bool InternalReadFrom(Slice * slices, size_t sliceCount, PIPSocketAddressAndPort & ipAndPort);
629  void InternalSetSendAddress(const PIPSocketAddressAndPort & addr);
630  void InternalGetSendAddress(PIPSocketAddressAndPort & addr);
631 
635 
638  DWORD m_lifeTime;
640 
641  std::vector<Slice> m_txVect;
643  BYTE m_txPadding[4];
644 
645  std::vector<Slice> m_rxVect;
647  BYTE m_rxPadding[4];
648 };
649 
651 
652 class PTURNClient : public PSTUNClient
653 {
655  public:
656 
657  friend class PTURNUDPSocket;
658 
661  static PString GetNatMethodName();
662  virtual PString GetName() const;
663 
664  PTURNClient();
665 
666  // overrides from PNatMethod
667  virtual bool Open(
668  const PIPSocket::Address & iface
669  );
670 
671  virtual void SetCredentials(
672  const PString & username,
673  const PString & password,
674  const PString & realm
675  );
676 
677  bool CreateSocket(
678  Component component,
679  PUDPSocket * & socket,
681  WORD port = 0
682  );
683 
684  bool CreateSocketPair(
685  PUDPSocket * & socket1,
686  PUDPSocket * & socket2,
687  const PIPSocket::Address & binding
688  );
689 
693  virtual RTPSupportTypes GetRTPSupport(
694  bool force = false
695  );
696 
697  protected:
698  // New functions
699  virtual bool RefreshAllocation(DWORD lifetime = 600);
701 };
702 
703 
704 #endif // P_STUN
705 
706 #endif // PTLIB_PSTUN_H