reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
Stun.cxx
Go to the documentation of this file.
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include "rutil/ResipAssert.h"
6#include <cstring>
7#include <iostream>
8#include <cstdlib>
9#include <errno.h>
10#include <ctype.h>
11
12#ifdef WIN32
13#include <winsock2.h>
14#include <stdlib.h>
15#include <io.h>
16#include <time.h>
17#else
18
19#include <stdlib.h>
20#include <unistd.h>
21#include <string.h>
22#include <sys/ioctl.h>
23#include <sys/socket.h>
24#include <sys/time.h>
25#include <sys/types.h>
26#include <arpa/inet.h>
27#include <fcntl.h>
28#include <netdb.h>
29#include <netinet/in.h>
30
31#ifndef __CYGWIN__
32#include <arpa/nameser.h>
33#include <resolv.h>
34#endif
35
36#include <net/if.h>
37
38#if defined (__SUNPRO_CC) || defined (__sun__)
39#include <sys/sockio.h> // solaris only?
40#endif
41
42#endif
43
44#include "Udp.hxx"
45#include "Stun.hxx"
46#include "rutil/Socket.hxx"
47#include "rutil/Random.hxx"
48#ifndef USE_SSL
49#include "rutil/Sha1.hxx"
50#endif
52
53using namespace std;
54
55namespace resip
56{
57
58 static bool
59 stunParseAtrAddress(char* body, unsigned int hdrLen, StunAtrAddress4& result)
60 {
61 if (hdrLen != 8)
62 {
63 // clog << "hdrLen wrong for Address" <<endl;
64 return false;
65 }
66 result.pad = *body++;
67 result.family = *body++;
68 if (result.family == IPv4Family)
69 {
70 uint16_t nport;
71 memcpy(&nport, body, 2); body += 2;
72 result.ipv4.port = ntohs(nport);
73
74 uint32_t naddr;
75 memcpy(&naddr, body, 4); body += 4;
76 result.ipv4.addr = ntohl(naddr);
77 return true;
78 }
79 else if (result.family == IPv6Family)
80 {
81 //clog << "ipv6 not supported" << endl;
82 }
83 else
84 {
85 //clog << "bad address family: " << result.family << endl;
86 }
87
88 return false;
89 }
90
91 static bool
92 stunParseUInt32(char* body, unsigned int hdrLen, uint32_t& result)
93 {
94 if (hdrLen != 4)
95 {
96 return false;
97 }
98 else
99 {
100 uint32_t tmp;
101 memcpy(&tmp, body, 4);
102 result = ntohl(tmp);
103 return true;
104 }
105 }
106
107 static bool
108 stunParseAtrChangeRequest(char* body, unsigned int hdrLen, StunAtrChangeRequest& result)
109 {
110 if (hdrLen != 4)
111 {
112 //clog << "hdr length = " << hdrLen << " expecting " << sizeof(result) << endl;
113
114 //clog << "Incorrect size for ChangeRequest" << endl;
115 return false;
116 }
117 else
118 {
119 memcpy(&result.value, body, 4);
120 result.value = ntohl(result.value);
121 return true;
122 }
123 }
124
125 static bool
126 stunParseAtrError(char* body, unsigned int hdrLen, StunAtrError& result)
127 {
128 if (hdrLen >= (sizeof(result) - sizeof(result.sizeReason))) // Note: result.sizeReason is extra info in StunAtrError that is not on the wire
129 {
130 //clog << "head on Error too large" << endl;
131 return false;
132 }
133 else if (hdrLen < 4) // check for min len
134 {
135 return false;
136 }
137 else
138 {
139 memcpy(&result.pad, body, 2); body += 2;
140 result.pad = ntohs(result.pad);
141 result.errorClass = *body++;
142 result.number = *body++;
143
144 result.sizeReason = hdrLen - 4;
145 memcpy(&result.reason, body, result.sizeReason);
146 result.reason[result.sizeReason] = 0;
147 return true;
148 }
149 }
150
151 static bool
152 stunParseAtrUnknown(char* body, unsigned int hdrLen, StunAtrUnknown& result)
153 {
154 if (hdrLen >= sizeof(result))
155 {
156 return false;
157 }
158 else
159 {
160 if (hdrLen % 4 != 0) return false;
161 result.numAttributes = hdrLen / 4;
162 for (int i = 0; i < result.numAttributes; i++)
163 {
164 memcpy(&result.attrType[i], body, 2); body += 2;
165 result.attrType[i] = ntohs(result.attrType[i]);
166 }
167 return true;
168 }
169 }
170
171
172 static bool
173 stunParseAtrString(char* body, unsigned int hdrLen, StunAtrString& result)
174 {
175 if (hdrLen >= STUN_MAX_STRING)
176 {
177 //clog << "String is too large" << endl;
178 return false;
179 }
180 else
181 {
182 // !jr! Removed - newer RFCs don't require individual attributes to have this
183 // 4 byte boundary restriction. (Note the overall structure of the
184 // stun message attributes must still be padded to 4 byte boundaries)
185 //if (hdrLen % 4 != 0)
186 //{
187 // //clog << "Bad length string " << hdrLen << endl;
188 // return false;
189 //}
190
191 result.sizeValue = hdrLen;
192 memcpy(&result.value, body, hdrLen);
193 result.value[hdrLen] = 0;
194 return true;
195 }
196 }
197
198 static bool
199 stunParseAtrUInt32(char* body, unsigned int hdrLen, uint32_t& result)
200 {
201 if (hdrLen != 4)
202 {
203 // clog << "hdrLen wrong for UInt32 attribute";
204 return false;
205 }
206 else
207 {
208 memcpy(&result, body, 4);
209 result = ntohl(result);
210 return true;
211 }
212 }
213
214
215 static bool
216 stunParseAtrIntegrity(char* body, unsigned int hdrLen, StunAtrIntegrity& result)
217 {
218 if (hdrLen != 20)
219 {
220 //clog << "MessageIntegrity must be 20 bytes" << endl;
221 return false;
222 }
223 else
224 {
225 memcpy(&result.hash, body, hdrLen);
226 return true;
227 }
228 }
229
230
231
232 bool
233 stunParseMessage(char* buf, unsigned int bufLen, StunMessage& msg, bool verbose)
234 {
235 if (verbose) clog << "Received stun message: " << bufLen << " bytes" << endl;
236
237 if (sizeof(StunMsgHdr) > bufLen)
238 {
239 clog << "Bad message" << endl;
240 return false;
241 }
242
243 memcpy(&msg.msgHdr, buf, sizeof(StunMsgHdr));
244 msg.msgHdr.msgType = ntohs(msg.msgHdr.msgType);
245 msg.msgHdr.msgLength = ntohs(msg.msgHdr.msgLength);
246
247 if (msg.msgHdr.msgLength + sizeof(StunMsgHdr) != bufLen)
248 {
249 clog << "Message header length doesn't match message size: " << msg.msgHdr.msgLength << " - " << bufLen << endl;
250 return false;
251 }
252
253 char* body = buf + sizeof(StunMsgHdr);
254 unsigned int size = msg.msgHdr.msgLength;
255
256 if (verbose) clog << "bytes after header = " << size << endl;
257
258 while (size > 0)
259 {
260 if (size < sizeof(StunAtrHdr))
261 {
262 return false;
263 }
264
265 StunAtrHdr* attr = reinterpret_cast<StunAtrHdr*>(body);
266
267 unsigned int attrLen = ntohs(attr->length);
268
269 // attrLen may not be on 4 byte boundary, in which case we need to pad to 4 bytes when advancing to next attribute
270 unsigned int attrLenPad = attrLen % 4 == 0 ? 0 : 4 - (attrLen % 4);
271
272 int atrType = ntohs(attr->type);
273
274 if (verbose) clog << "Found attribute type=" << atrType << " length=" << attrLen << endl;
275 if (attrLen + attrLenPad + 4 > size)
276 {
277 clog << "claims attribute is larger than size of message " << "(attribute type=" << atrType << ")" << endl;
278 return false;
279 }
280
281 body += 4; // skip the length and type in attribute header
282 size -= 4;
283
284 switch (atrType)
285 {
286 case MappedAddress:
287 msg.hasMappedAddress = true;
288 if (stunParseAtrAddress(body, attrLen, msg.mappedAddress) == false)
289 {
290 clog << "problem parsing MappedAddress" << endl;
291 return false;
292 }
293 else
294 {
295 if (verbose) clog << "MappedAddress = " << msg.mappedAddress.ipv4 << endl;
296 }
297
298 break;
299
300 case ResponseAddress:
301 msg.hasResponseAddress = true;
302 if (stunParseAtrAddress(body, attrLen, msg.responseAddress) == false)
303 {
304 if (verbose) clog << "problem parsing ResponseAddress" << endl;
305 return false;
306 }
307 else
308 {
309 if (verbose) clog << "ResponseAddress = " << msg.responseAddress.ipv4 << endl;
310 }
311 break;
312
313 case ChangeRequest:
314 msg.hasChangeRequest = true;
315 if (stunParseAtrChangeRequest(body, attrLen, msg.changeRequest) == false)
316 {
317 if (verbose) clog << "problem parsing ChangeRequest" << endl;
318 return false;
319 }
320 else
321 {
322 if (verbose) clog << "ChangeRequest = " << msg.changeRequest.value << endl;
323 }
324 break;
325
326 case SourceAddress:
327 msg.hasSourceAddress = true;
328 if (stunParseAtrAddress(body, attrLen, msg.sourceAddress) == false)
329 {
330 if (verbose) clog << "problem parsing SourceAddress" << endl;
331 return false;
332 }
333 else
334 {
335 if (verbose) clog << "SourceAddress = " << msg.sourceAddress.ipv4 << endl;
336 }
337 break;
338
339 case ChangedAddress:
340 msg.hasChangedAddress = true;
341 if (stunParseAtrAddress(body, attrLen, msg.changedAddress) == false)
342 {
343 if (verbose) clog << "problem parsing ChangedAddress" << endl;
344 return false;
345 }
346 else
347 {
348 if (verbose) clog << "ChangedAddress = " << msg.changedAddress.ipv4 << endl;
349 }
350 break;
351
352 case Username:
353 msg.hasUsername = true;
354 if (stunParseAtrString(body, attrLen, msg.username) == false)
355 {
356 if (verbose) clog << "problem parsing Username" << endl;
357 return false;
358 }
359 else
360 {
361 if (verbose) clog << "Username = " << msg.username.value << endl;
362 }
363
364 break;
365
366 case Password:
367 msg.hasPassword = true;
368 if (stunParseAtrString(body, attrLen, msg.password) == false)
369 {
370 if (verbose) clog << "problem parsing Password" << endl;
371 return false;
372 }
373 else
374 {
375 if (verbose) clog << "Password = " << msg.password.value << endl;
376 }
377 break;
378
379 case MessageIntegrity:
380 msg.hasMessageIntegrity = true;
381 // Record where the MESSAGE-INTEGRITY attribute header begins so the
382 // HMAC can be verified later (body currently points just past the
383 // 4-byte attribute header). See stunVerifyMessageIntegrity().
384 msg.messageIntegrityOffset = static_cast<unsigned int>((body - 4) - buf);
385 if (stunParseAtrIntegrity(body, attrLen, msg.messageIntegrity) == false)
386 {
387 if (verbose) clog << "problem parsing MessageIntegrity" << endl;
388 return false;
389 }
390 else
391 {
392 if (verbose) clog << "MessageIntegrity = " << msg.messageIntegrity.hash << endl;
393 }
394 break;
395
396 case ErrorCode:
397 msg.hasErrorCode = true;
398 if (stunParseAtrError(body, attrLen, msg.errorCode) == false)
399 {
400 if (verbose) clog << "problem parsing ErrorCode" << endl;
401 return false;
402 }
403 else
404 {
405 if (verbose) clog << "ErrorCode = " << int(msg.errorCode.errorClass)
406 << " " << int(msg.errorCode.number)
407 << " " << msg.errorCode.reason << endl;
408 }
409
410 break;
411
412 case UnknownAttribute:
413 msg.hasUnknownAttributes = true;
414 if (stunParseAtrUnknown(body, attrLen, msg.unknownAttributes) == false)
415 {
416 if (verbose) clog << "problem parsing UnknownAttribute" << endl;
417 return false;
418 }
419 break;
420
421 case ReflectedFrom:
422 msg.hasReflectedFrom = true;
423 if (stunParseAtrAddress(body, attrLen, msg.reflectedFrom) == false)
424 {
425 if (verbose) clog << "problem parsing ReflectedFrom" << endl;
426 return false;
427 }
428 break;
429
430 case Realm:
431 if (!msg.hasRealm)
432 {
433 if (attrLen > MAX_REALM_BYTES)
434 {
435 if (verbose) clog << "Realm length=" << attrLen << " is longer than max allowed=" << MAX_REALM_BYTES << endl;
436 return false;
437 }
438 msg.hasRealm = true;
439 msg.realm = new resip::Data(resip::Data::Share, body, attrLen);
440 if (verbose) clog << "Realm = " << *msg.realm << endl;
441 }
442 else
443 {
444 if (verbose) clog << "Duplicate Realm in message - ignoring." << endl;
445 }
446 break;
447
448 case Nonce:
449 if (!msg.hasNonce)
450 {
451 if (attrLen > MAX_NONCE_BYTES)
452 {
453 if (verbose) clog << "Nonce length=" << attrLen << " is longer than max allowed=" << MAX_NONCE_BYTES << endl;
454 return false;
455 }
456 msg.hasNonce = true;
457 msg.nonce = new resip::Data(resip::Data::Share, body, attrLen);
458 if (verbose) clog << "Nonce = " << *msg.nonce << endl;
459 }
460 else
461 {
462 if (verbose) clog << "Duplicate Nonce in message - ignoring." << endl;
463 }
464 break;
465
466 case XorMappedAddress:
468 msg.hasXorMappedAddress = true;
469 if (stunParseAtrAddress(body, attrLen, msg.xorMappedAddress) == false)
470 {
471 if (verbose) clog << "problem parsing XorMappedAddress" << endl;
472 return false;
473 }
474 else
475 {
476 if (verbose) clog << "XorMappedAddress = " << msg.xorMappedAddress.ipv4 << endl;
477 }
478 break;
479
480 case XorOnly:
481 msg.xorOnly = true;
482 if (verbose)
483 {
484 if (verbose) clog << "xorOnly = true" << endl;
485 }
486 break;
487
488 case Software:
489 // case ServerName: // Was non-standard "ServerName" attribute(0x8022) now standardardized as SOFTWARE(0x8022)
490 msg.hasSoftware = true;
491 if (stunParseAtrString(body, attrLen, msg.software) == false)
492 {
493 if (verbose) clog << "problem parsing ServerName" << endl;
494 return false;
495 }
496 else
497 {
498 if (verbose) clog << "ServerName = " << msg.software.value << endl;
499 }
500 break;
501
502 case AlternateServer:
503 if (!msg.hasAlternateServer)
504 {
505 msg.hasAlternateServer = true;
506 if (stunParseAtrAddress(body, attrLen, msg.alternateServer) == false)
507 {
508 if (verbose) clog << "problem parsing AlternateServer" << endl;
509 return false;
510 }
511 if (verbose) clog << "AlternateServer = " << msg.alternateServer.ipv4;
512 }
513 else
514 {
515 if (verbose) clog << "Duplicate AlternateServer in message - ignoring." << endl;
516 }
517 break;
518
519 case Fingerprint:
520 if (!msg.hasFingerprint)
521 {
522 msg.hasFingerprint = true;
523 if (stunParseAtrUInt32(body, attrLen, msg.fingerprint) == false)
524 {
525 if (verbose) clog << "problem parsing Fingerprint" << endl;
526 return false;
527 }
528 if (verbose) clog << "Fingerprint = " << msg.fingerprint;
529 }
530 else
531 {
532 if (verbose) clog << "Duplicate Fingerprint in message - ignoring." << endl;
533 }
534 break;
535
536
537 case SecondaryAddress:
538 msg.hasSecondaryAddress = true;
539 if (stunParseAtrAddress(body, attrLen, msg.secondaryAddress) == false)
540 {
541 if (verbose) clog << "problem parsing secondaryAddress" << endl;
542 return false;
543 }
544 else
545 {
546 if (verbose) clog << "SecondaryAddress = " << msg.secondaryAddress.ipv4 << endl;
547 }
548 break;
549
550 // End STUN attributes
551
552 // TURN attributes
553 case TurnLifetime:
554 msg.hasTurnLifetime = true;
555 if (stunParseUInt32(body, attrLen, msg.turnLifetime) == false)
556 {
557 return false;
558 }
559 break;
560
562 msg.hasTurnAlternateServer = true;
563 if (stunParseAtrAddress(body, attrLen, msg.turnAlternateServer) == false)
564 {
565 return false;
566 }
567 break;
568
569 case TurnMagicCookie:
570 msg.hasTurnMagicCookie = true;
571 if (stunParseUInt32(body, attrLen, msg.turnMagicCookie) == false)
572 {
573 return false;
574 }
575 break;
576
577 case TurnBandwidth:
578 msg.hasTurnBandwidth = true;
579 if (stunParseUInt32(body, attrLen, msg.turnBandwidth) == false)
580 {
581 return false;
582 }
583 break;
584
586 msg.hasTurnDestinationAddress = true;
587 if (stunParseAtrAddress(body, attrLen, msg.turnDestinationAddress) == false)
588 {
589 return false;
590 }
591 break;
592
594 msg.hasTurnRemoteAddress = true;
595 if (stunParseAtrAddress(body, attrLen, msg.turnRemoteAddress) == false)
596 {
597 return false;
598 }
599 break;
600
601 //overlay on parse, ownership is buffer parsed from
602 case TurnData:
603 msg.hasTurnData = true;
604 msg.turnData = new resip::Data(resip::Data::Share, body, attrLen);
605 break;
606
607 //case TurnNonce:
608 //break;
609 //case TurnRealm:
610 //break;
611
612 default:
613 if (verbose) clog << "Unknown attribute: " << atrType << endl;
614 if (atrType <= 0x7FFF)
615 {
616 return false;
617 }
618 }
619
620 body += attrLen + attrLenPad;
621 size -= attrLen + attrLenPad;
622 }
623
624 return true;
625 }
626
627 static char*
628 encode16(char* buf, uint16_t data)
629 {
630 uint16_t ndata = htons(data);
631 memcpy(buf, reinterpret_cast<void*>(&ndata), sizeof(uint16_t));
632 return buf + sizeof(uint16_t);
633 }
634
635 static char*
636 encode32(char* buf, uint32_t data)
637 {
638 uint32_t ndata = htonl(data);
639 memcpy(buf, reinterpret_cast<void*>(&ndata), sizeof(uint32_t));
640 return buf + sizeof(uint32_t);
641 }
642
643
644 static char*
645 encode(char* buf, const char* data, unsigned int length)
646 {
647 memcpy(buf, data, length);
648 return buf + length;
649 }
650
651 static char*
652 encodeTurnData(char* ptr, const resip::Data* td)
653 {
654 ptr = encode16(ptr, TurnData);
655 ptr = encode16(ptr, (uint16_t)td->size());
656 memcpy(ptr, td->data(), td->size());
657 ptr += td->size();
658
659 return ptr;
660 }
661
662 static char*
663 encodeAtrUInt32(char* ptr, uint16_t type, uint32_t value)
664 {
665 ptr = encode16(ptr, type);
666 ptr = encode16(ptr, 4);
667 ptr = encode32(ptr, value);
668 return ptr;
669 }
670
671 static char*
672 encodeAtrAddress4(char* ptr, uint16_t type, const StunAtrAddress4& atr)
673 {
674 ptr = encode16(ptr, type);
675 ptr = encode16(ptr, 8);
676 *ptr++ = atr.pad;
677 *ptr++ = IPv4Family;
678 ptr = encode16(ptr, atr.ipv4.port);
679 ptr = encode32(ptr, atr.ipv4.addr);
680
681 return ptr;
682 }
683
684 static char*
686 {
687 ptr = encode16(ptr, ChangeRequest);
688 ptr = encode16(ptr, 4);
689 ptr = encode32(ptr, atr.value);
690 return ptr;
691 }
692
693 static char*
695 {
696 ptr = encode16(ptr, TurnMagicCookie);
697 ptr = encode16(ptr, 4);
698 ptr = encode32(ptr, cookie);
699 return ptr;
700 }
701
702
703 static char*
704 encodeAtrError(char* ptr, const StunAtrError& atr)
705 {
706 ptr = encode16(ptr, ErrorCode);
707 ptr = encode16(ptr, 4 + atr.sizeReason);
708 ptr = encode16(ptr, atr.pad);
709 *ptr++ = atr.errorClass;
710 *ptr++ = atr.number;
711 ptr = encode(ptr, atr.reason, atr.sizeReason);
712 return ptr;
713 }
714
715
716 static char*
717 encodeAtrUnknown(char* ptr, const StunAtrUnknown& atr)
718 {
719 ptr = encode16(ptr, UnknownAttribute);
720 ptr = encode16(ptr, 2 + 2 * atr.numAttributes);
721 for (int i = 0; i < atr.numAttributes; i++)
722 {
723 ptr = encode16(ptr, atr.attrType[i]);
724 }
725 return ptr;
726 }
727
728
729 static char*
730 encodeXorOnly(char* ptr)
731 {
732 ptr = encode16(ptr, XorOnly);
733 return ptr;
734 }
735
736
737 static char*
738 encodeAtrString(char* ptr, uint16_t type, const StunAtrString& atr)
739 {
740 resip_assert(atr.sizeValue % 4 == 0);
741
742 ptr = encode16(ptr, type);
743 ptr = encode16(ptr, atr.sizeValue);
744 ptr = encode(ptr, atr.value, atr.sizeValue);
745 return ptr;
746 }
747
748
749 static char*
751 {
752 ptr = encode16(ptr, MessageIntegrity);
753 ptr = encode16(ptr, 20);
754 ptr = encode(ptr, atr.hash, sizeof(atr.hash));
755 return ptr;
756 }
757
758
759 unsigned int
761 char* buf,
762 unsigned int bufLen,
763 const StunAtrString& password,
764 bool verbose)
765 {
766 resip_assert(bufLen >= sizeof(StunMsgHdr));
767 char* ptr = buf;
768
769 if (verbose) clog << "Encoding stun message: " << endl;
770
771 ptr = encode16(ptr, msg.msgHdr.msgType);
772 char* lengthp = ptr;
773 ptr = encode16(ptr, 0);
774 ptr = encode(ptr, reinterpret_cast<const char*>(msg.msgHdr.id.octet), sizeof(msg.msgHdr.id));
775
776 if (msg.hasTurnMagicCookie)
777 {
778 if (verbose) clog << "Encoding TurnMagicCookie: " << msg.turnMagicCookie << endl;
779 ptr = encodeMagicCookie(ptr, msg.turnMagicCookie);
780 }
782 {
783 if (verbose) clog << "Encoding TurnDestinationAddress: " << msg.turnDestinationAddress.ipv4 << endl;
785 }
786 if (msg.hasMappedAddress)
787 {
788 if (verbose) clog << "Encoding MappedAddress: " << msg.mappedAddress.ipv4 << endl;
790 }
791 if (msg.hasResponseAddress)
792 {
793 if (verbose) clog << "Encoding ResponseAddress: " << msg.responseAddress.ipv4 << endl;
795 }
797 {
798 if (verbose) clog << "Encoding AlternateServer: " << msg.turnAlternateServer.ipv4 << endl;
800 }
801 if (msg.hasChangeRequest)
802 {
803 if (verbose) clog << "Encoding ChangeRequest: " << msg.changeRequest.value << endl;
805 }
806 if (msg.hasSourceAddress)
807 {
808 if (verbose) clog << "Encoding SourceAddress: " << msg.sourceAddress.ipv4 << endl;
810 }
811 if (msg.hasChangedAddress)
812 {
813 if (verbose) clog << "Encoding ChangedAddress: " << msg.changedAddress.ipv4 << endl;
815 }
816 if (msg.hasUsername)
817 {
818 if (verbose) clog << "Encoding Username: " << msg.username.value << endl;
819 ptr = encodeAtrString(ptr, Username, msg.username);
820 }
821 if (msg.hasPassword)
822 {
823 if (verbose) clog << "Encoding Password: " << msg.password.value << endl;
824 ptr = encodeAtrString(ptr, Password, msg.password);
825 }
826 if (msg.hasErrorCode)
827 {
828 if (verbose) clog << "Encoding ErrorCode: class="
829 << int(msg.errorCode.errorClass)
830 << " number=" << int(msg.errorCode.number)
831 << " reason="
832 << msg.errorCode.reason
833 << endl;
834
835 ptr = encodeAtrError(ptr, msg.errorCode);
836 }
837 if (msg.hasUnknownAttributes)
838 {
839 if (verbose) clog << "Encoding UnknownAttribute: ???" << endl;
840 ptr = encodeAtrUnknown(ptr, msg.unknownAttributes);
841 }
842 if (msg.hasReflectedFrom)
843 {
844 if (verbose) clog << "Encoding ReflectedFrom: " << msg.reflectedFrom.ipv4 << endl;
846 }
847 if (msg.hasXorMappedAddress)
848 {
849 if (verbose) clog << "Encoding XorMappedAddress: " << msg.xorMappedAddress.ipv4 << endl;
851 }
852 if (msg.xorOnly)
853 {
854 if (verbose) clog << "Encoding xorOnly: " << endl;
855 ptr = encodeXorOnly(ptr);
856 }
857 if (msg.hasSoftware)
858 {
859 if (verbose) clog << "Encoding Software: " << msg.software.value << endl;
860 ptr = encodeAtrString(ptr, Software, msg.software);
861 }
862 if (msg.hasSecondaryAddress)
863 {
864 if (verbose) clog << "Encoding SecondaryAddress: " << msg.secondaryAddress.ipv4 << endl;
866 }
867 if (msg.hasTurnLifetime)
868 {
869 if (verbose) clog << "Encoding Turn Lifetime: " << msg.turnLifetime << endl;
871 }
872 if (msg.hasTurnBandwidth)
873 {
874 if (verbose) clog << "Encoding Turn Bandwidth: " << msg.turnBandwidth << endl;
876 }
877 if (msg.hasTurnData)
878 {
879 if (verbose) clog << "Encoding TurnData (not shown)" << endl;
880 ptr = encodeTurnData(ptr, msg.turnData);
881 }
882 if (password.sizeValue > 0)
883 {
884 if (verbose) clog << "HMAC with password: " << password.value << endl;
885
886 // allocate space for message integrity attribute (hash + attribute type + size)
887 char* ptrMessageIntegrity = ptr;
888 ptr += 20 + sizeof(MessageIntegrity) + sizeof(uint16_t);
889 encode16(lengthp, uint16_t(ptr - buf - sizeof(StunMsgHdr)));
890
891 StunAtrIntegrity integrity;
892 // RFC 5389 section 15.4: the HMAC-SHA1 is computed over the STUN message
893 // up to (but not including) the MESSAGE-INTEGRITY attribute, with the
894 // message-length field in the header already set to include the
895 // MESSAGE-INTEGRITY attribute (done above). No additional block padding
896 // is applied to the input.
897 int len = int(ptrMessageIntegrity - buf);
898 computeHmac(integrity.hash, buf, len, password.value, password.sizeValue);
899 encodeAtrIntegrity(ptrMessageIntegrity, integrity);
900 }
901
902 if (verbose) clog << endl;
903 encode16(lengthp, uint16_t(ptr - buf - sizeof(StunMsgHdr)));
904 return int(ptr - buf);
905 }
906
907 int
909 {
910 // Delegate to the portable, self-initializing resip Random class. This
911 // used to hand-roll a platform-specific seed (rdtsc / gethrtime /
912 // /dev/urandom + srand/srandom) and #error on unlisted platforms such as
913 // OpenBSD/arm64 (resiprocate issue #150); Random handles all of that.
914 return Random::getRandom();
915 }
916
917
919 int
921 {
922 int min = 0x4000;
923 int max = 0x7FFF;
924
925 int ret = stunRand();
926 ret = ret | min;
927 ret = ret & max;
928
929 return ret;
930 }
931
932
933#ifdef USE_SSL
934#ifdef WIN32
935 //hack for name collision of OCSP_RESPONSE and wincrypt.h in latest openssl release 0.9.8h
936 //http://www.google.com/search?q=OCSP%5fRESPONSE+wincrypt%2eh
937 //continue to watch this issue for a real fix.
938#undef OCSP_RESPONSE
939#endif
940#include <openssl/hmac.h>
941
942 void
943 computeHmac(char* hmac, const char* input, int length, const char* key, int sizeKey)
944 {
945 unsigned int resultSize = 0;
946 HMAC(EVP_sha1(),
947 key, sizeKey,
948 reinterpret_cast<const unsigned char*>(input), length,
949 reinterpret_cast<unsigned char*>(hmac), &resultSize);
950 resip_assert(resultSize == 20);
951 }
952#else
953 void
954 computeHmac(char* hmac, const char* input, int length, const char* key, int sizeKey)
955 {
956 // HMAC-SHA1 (RFC 2104) using the bundled Sha1 implementation, for builds
957 // without OpenSSL.
958 const int blockSize = 64; // SHA1 block size in bytes
959
960 unsigned char paddedKey[blockSize];
961 memset(paddedKey, 0, sizeof(paddedKey));
962 if (sizeKey > blockSize)
963 {
964 // Keys longer than the block size are first hashed down.
965 Sha1 keyHash;
966 keyHash.update(std::string(key, sizeKey));
967 const Data hashedKey = keyHash.finalBin();
968 memcpy(paddedKey, hashedKey.data(),
969 hashedKey.size() < static_cast<size_t>(blockSize) ? hashedKey.size() : blockSize);
970 }
971 else if (sizeKey > 0)
972 {
973 memcpy(paddedKey, key, sizeKey);
974 }
975
976 unsigned char ipad[blockSize];
977 unsigned char opad[blockSize];
978 for (int i = 0; i < blockSize; ++i)
979 {
980 ipad[i] = paddedKey[i] ^ 0x36;
981 opad[i] = paddedKey[i] ^ 0x5c;
982 }
983
984 // inner = SHA1( (key XOR ipad) || message )
985 Sha1 inner;
986 inner.update(std::string(reinterpret_cast<const char*>(ipad), blockSize));
987 inner.update(std::string(input, length));
988 const Data innerDigest = inner.finalBin();
989
990 // hmac = SHA1( (key XOR opad) || inner )
991 Sha1 outer;
992 outer.update(std::string(reinterpret_cast<const char*>(opad), blockSize));
993 outer.update(std::string(innerDigest.data(), innerDigest.size()));
994 const Data outerDigest = outer.finalBin();
995
996 resip_assert(outerDigest.size() == 20);
997 memcpy(hmac, outerDigest.data(), 20);
998 }
999#endif
1000
1001
1002 bool
1004 unsigned int bufLen,
1005 const StunMessage& message,
1006 const StunAtrString& password)
1007 {
1008 if (!message.hasMessageIntegrity || password.sizeValue == 0)
1009 {
1010 return false;
1011 }
1012
1013 const unsigned int miOffset = message.messageIntegrityOffset;
1014 // The MESSAGE-INTEGRITY attribute is a 4-byte header followed by a 20-byte
1015 // HMAC-SHA1 value. Reject anything that does not fit inside the buffer.
1016 if (miOffset < sizeof(StunMsgHdr) ||
1017 miOffset + 4 + 20 > bufLen ||
1018 miOffset > STUN_MAX_MESSAGE_SIZE)
1019 {
1020 return false;
1021 }
1022
1023 // RFC 5389 section 15.4: the HMAC is computed over the STUN message up to
1024 // (but not including) the MESSAGE-INTEGRITY attribute, with the message
1025 // length field in the header set to point at the end of the
1026 // MESSAGE-INTEGRITY attribute. We copy the prefix so we can adjust the
1027 // length field without mutating the caller's buffer (and so any trailing
1028 // attributes, e.g. FINGERPRINT, are excluded).
1029 char hashInput[STUN_MAX_MESSAGE_SIZE];
1030 memcpy(hashInput, buf, miOffset);
1031 const uint16_t adjustedLength = htons(static_cast<uint16_t>(miOffset + 4));
1032 memcpy(hashInput + 2, &adjustedLength, sizeof(adjustedLength));
1033
1034 char computed[20] = { 0 };
1035 computeHmac(computed, hashInput, static_cast<int>(miOffset),
1036 password.value, password.sizeValue);
1037
1038 // Constant-time comparison to avoid leaking HMAC bytes via timing.
1039 unsigned char diff = 0;
1040 for (int i = 0; i < 20; ++i)
1041 {
1042 diff |= static_cast<unsigned char>(computed[i]) ^
1043 static_cast<unsigned char>(message.messageIntegrity.hash[i]);
1044 }
1045 return diff == 0;
1046 }
1047
1048
1049 static void
1050 toHex(const char* buffer, int bufferSize, char* output)
1051 {
1052 static char hexmap[] = "0123456789abcdef";
1053
1054 const char* p = buffer;
1055 char* r = output;
1056 for (int i = 0; i < bufferSize; i++)
1057 {
1058 unsigned char temp = *p++;
1059
1060 int hi = (temp & 0xf0) >> 4;
1061 int low = (temp & 0xf);
1062
1063 *r++ = hexmap[hi];
1064 *r++ = hexmap[low];
1065 }
1066 *r = 0;
1067 }
1068
1069 void
1071 {
1073 time -= (time % 20 * 60);
1074 //UInt64 hitime = time >> 32;
1075 uint64_t lotime = time & 0xFFFFFFFF;
1076
1077 constexpr size_t bufferSize = 256;
1078 char buffer[bufferSize];
1079 int expectedSize = std::snprintf(buffer,
1080 bufferSize,
1081 "%08x:%08x:%08x:",
1082 uint32_t(source.addr),
1083 uint32_t(Random::getCryptoRandom()), // CSPRNG nonce (CWE-338)
1084 uint32_t(lotime));
1085 resip_assert(expectedSize > 0 && static_cast<size_t>(expectedSize) < bufferSize);
1086
1087 resip_assert(strlen(buffer) + 41 < STUN_MAX_STRING);
1088
1089 char hmac[20] = { 0 };
1090 char key[] = "Jason";
1091 computeHmac(hmac, buffer, (int)strlen(buffer), key, (int)strlen(key));
1092 char hmacHex[41] = { 0 };
1093 toHex(hmac, 20, hmacHex);
1094 hmacHex[40] = 0;
1095
1096 snprintf(buffer + expectedSize, bufferSize - expectedSize, "%s", hmacHex);
1097
1098 int l = (int)strlen(buffer);
1100 resip_assert(l % 4 == 0);
1101
1102 username->sizeValue = l;
1103 memcpy(username->value, buffer, l);
1104 username->value[l] = 0;
1105
1106 //if (verbose) clog << "computed username=" << username.value << endl;
1107 }
1108
1109 void
1111 {
1112 char hmac[20] = { 0 };
1113 char key[] = "Fluffy";
1114 //char buffer[STUN_MAX_STRING];
1115 computeHmac(hmac, username.value, (int)strlen(username.value), key, (int)strlen(key));
1116 toHex(hmac, 20, password->value);
1117 password->sizeValue = 40;
1118 password->value[40] = 0;
1119
1120 //clog << "password=" << password->value << endl;
1121 }
1122
1123
1124 uint64_t
1126 {
1127 uint64_t time = 0;
1128#if defined(WIN32)
1129 SYSTEMTIME t;
1130 // CJ TODO - this probably has bug on wrap around every 24 hours
1131 GetSystemTime(&t);
1132 time = (t.wHour * 60 + t.wMinute) * 60 + t.wSecond;
1133#else
1134 struct timeval now;
1135 gettimeofday(&now, NULL);
1136 //assert( now );
1137 time = now.tv_sec;
1138#endif
1139 return time;
1140 }
1141
1142
1143 ostream& operator<< (ostream& strm, const UInt128& r)
1144 {
1145 strm << int(r.octet[0]);
1146 for (int i = 1; i < 16; i++)
1147 {
1148 strm << ':' << int(r.octet[i]);
1149 }
1150
1151 return strm;
1152 }
1153
1154 ostream&
1155 operator<<(ostream& strm, const StunAddress4& addr)
1156 {
1157 uint32_t ip = addr.addr;
1158 strm << ((int)(ip >> 24) & 0xFF) << ".";
1159 strm << ((int)(ip >> 16) & 0xFF) << ".";
1160 strm << ((int)(ip >> 8) & 0xFF) << ".";
1161 strm << ((int)(ip >> 0) & 0xFF);
1162
1163 strm << ":" << addr.port;
1164
1165 return strm;
1166 }
1167
1168 ostream&
1169 operator<<(ostream& os, const StunMsgHdr& h)
1170 {
1171 os << "STUN: ";
1172 switch (h.msgType) {
1173 case BindRequestMsg:
1174 os << "BindingRequest";
1175 break;
1176 case BindResponseMsg:
1177 os << "BindingResponse";
1178 break;
1180 os << "BindingErrorResponse";
1181 break;
1183 os << "TurnAllocateRequest";
1184 break;
1186 os << "TurnAllocateResponse";
1187 break;
1189 os << "TurnAllocateErrorResponse";
1190 break;
1191 case TurnSendRequest:
1192 os << "TurnSendRequest";
1193 break;
1194 case TurnSendResponse:
1195 os << "TurnSendResponse";
1196 break;
1198 os << "TurnSendErrorResponse";
1199 break;
1200 case TurnDataIndication:
1201 os << "TurnDataIndication";
1202 break;
1204 os << "TurnSetActiveDestinationRequest";
1205 break;
1207 os << "TurnSetActiveDestinationResponse";
1208 break;
1210 os << "TurnSetActiveDestinationErrorResponse";
1211 break;
1212 }
1213
1214 os << ", id ";
1215
1216 os << std::hex;
1217 for (unsigned int i = 0; i < sizeof(UInt128); i++) {
1218 os << static_cast<int>(h.id.octet[i]);
1219 }
1220 os << std::dec;
1221
1222 return os;
1223 }
1224
1225
1226 // returns true if it scucceeded
1227 bool
1228 stunParseHostName(char* peerName,
1229 uint32_t& ip,
1230 uint16_t& portVal,
1231 uint16_t defaultPort)
1232 {
1233 in_addr sin_addr;
1234
1235 char host[512];
1236 snprintf(host, sizeof(host), "%s", peerName);
1237 host[512 - 1] = '\0';
1238 char* port = NULL;
1239
1240 int portNum = defaultPort;
1241
1242 // pull out the port part if present.
1243 char* sep = strchr(host, ':');
1244
1245 if (sep == NULL)
1246 {
1247 portNum = defaultPort;
1248 }
1249 else
1250 {
1251 *sep = '\0';
1252 port = sep + 1;
1253 // set port part
1254
1255 char* endPtr = NULL;
1256
1257 portNum = strtol(port, &endPtr, 10);
1258
1259 if (endPtr != NULL)
1260 {
1261 if (*endPtr != '\0')
1262 {
1263 portNum = defaultPort;
1264 }
1265 }
1266 }
1267
1268 if (portNum < 1024) return false;
1269 if (portNum >= 0xFFFF) return false;
1270
1271 // figure out the host part
1272#ifdef WIN32
1273 resip_assert(strlen(host) >= 1);
1274 if (isdigit(static_cast<unsigned char>(host[0])))
1275 {
1276 // assume it is an ip address
1277 unsigned long a = 0;
1278 inet_pton(AF_INET, host, &a);
1279 ip = ntohl(a);
1280 }
1281 else
1282#endif
1283 {
1284 // assume it is a host name - getaddrinfo replaces deprecated gethostbyname
1285 // it is thread-safe and supports both IPv4 and IPv6
1286 struct addrinfo hints = {};
1287 struct addrinfo* res = NULL;
1288 hints.ai_family = AF_INET; // IPv4 only for now, matching original behaviour
1289 hints.ai_socktype = SOCK_STREAM;
1290
1291 int err = getaddrinfo(host, NULL, &hints, &res);
1292 if (err != 0 || res == NULL)
1293 {
1294 std::cerr << "getaddrinfo error: " << gai_strerror(err) << std::endl;
1295#ifdef WIN32
1297#endif
1298 ip = ntohl(0x7F000001L);
1299 return false;
1300 }
1301
1302 sin_addr = ((struct sockaddr_in*)res->ai_addr)->sin_addr;
1303 ip = ntohl(sin_addr.s_addr);
1304 freeaddrinfo(res);
1305 }
1306
1307 portVal = portNum;
1308 return true;
1309 }
1310
1311
1312 bool
1314 {
1315 resip_assert(name);
1316
1317 // TODO - put in DNS SRV stuff.
1318
1319 bool ret = stunParseHostName(name, addr.addr, addr.port, 3478);
1320 if (ret != true)
1321 {
1322 addr.port = 0xFFFF;
1323 }
1324 return ret;
1325 }
1326
1327 static void
1328 stunCreateErrorResponse(StunMessage& response, int cl, int number, const char* msg)
1329 {
1331 response.hasErrorCode = true;
1332 response.errorCode.errorClass = cl;
1333 response.errorCode.number = number;
1334 snprintf(response.errorCode.reason, sizeof(response.errorCode.reason), "%s", msg);
1335 response.errorCode.sizeReason = (uint16_t)strlen(msg);
1336 }
1337
1338#if 0
1339 static void
1340 stunCreateSharedSecretErrorResponse(StunMessage& response, int cl, int number, const char* msg)
1341 {
1342 response.msgHdr.msgType = SharedSecretErrorResponseMsg;
1343 response.hasErrorCode = true;
1344 response.errorCode.errorClass = cl;
1345 response.errorCode.number = number;
1346 strcpy(response.errorCode.reason, msg);
1347 }
1348#endif
1349
1350 static void
1351 stunCreateSharedSecretResponse(const StunMessage& request, const StunAddress4& source, StunMessage& response)
1352 {
1354 response.msgHdr.id = request.msgHdr.id;
1355
1356 response.hasUsername = true;
1357 stunCreateUserName(source, &response.username);
1358
1359 response.hasPassword = true;
1360 stunCreatePassword(response.username, &response.password);
1361 }
1362
1363
1364 // This funtion takes a single message sent to a stun server, parses
1365 // and constructs an apropriate repsonse - returns true if message is
1366 // valid
1367 bool
1369 unsigned int bufLen,
1370 StunAddress4& from,
1371 StunAddress4& secondary,
1372 StunAddress4& myAddr,
1373 StunAddress4& altAddr,
1374 StunMessage* resp,
1375 StunAddress4* destination,
1376 StunAtrString* hmacPassword,
1377 bool* changePort,
1378 bool* changeIp,
1379 bool verbose)
1380 {
1381 *changeIp = false;
1382 *changePort = false;
1383
1384 StunMessage req;
1385 bool ok = stunParseMessage(buf, bufLen, req, verbose);
1386
1387 if (!ok) // Complete garbage, drop it on the floor
1388 {
1389 if (verbose) clog << "Request did not parse" << endl;
1390 return false;
1391 }
1392 if (verbose) clog << "Request parsed ok" << endl;
1393
1394 StunAddress4 mapped = req.mappedAddress.ipv4;
1395 StunAddress4 respondTo = req.responseAddress.ipv4;
1397
1398 switch (req.msgHdr.msgType)
1399 {
1401 if (verbose) clog << "Received SharedSecretRequestMsg on udp. send error 433." << endl;
1402 // !cj! - should fix so you know if this came over TLS or UDP
1403 stunCreateSharedSecretResponse(req, from, *resp);
1404 //stunCreateSharedSecretErrorResponse(*resp, 4, 33, "this request must be over TLS");
1405 return true;
1406
1407 case BindRequestMsg:
1408 if (!req.hasMessageIntegrity)
1409 {
1410 if (verbose) clog << "BindRequest does not contain MessageIntegrity" << endl;
1411
1412 if (0) // !jf! mustAuthenticate
1413 {
1414 if (verbose) clog << "Received BindRequest with no MessageIntegrity. Sending 401." << endl;
1415 stunCreateErrorResponse(*resp, 4, 1, "Missing MessageIntegrity");
1416 return true;
1417 }
1418 }
1419 else
1420 {
1421 if (!req.hasUsername)
1422 {
1423 if (verbose) clog << "No UserName. Send 432." << endl;
1424 stunCreateErrorResponse(*resp, 4, 32, "No UserName and contains MessageIntegrity");
1425 return true;
1426 }
1427 else
1428 {
1429 if (verbose) clog << "Validating username: " << req.username.value << endl;
1430
1431 // Derive the password for this username with the same
1432 // shared-secret scheme stunCreateSharedSecretResponse() used
1433 // to hand the credential out (stunCreatePassword), then verify
1434 // the request's MESSAGE-INTEGRITY against it.
1435 //
1436 // This replaces a check that (a) compared the wrong bytes
1437 // (the message header instead of the received HMAC), (b) read
1438 // an uninitialized buffer when built without OpenSSL, and
1439 // (c) only ever recognized a single hard-coded "test"/"1234"
1440 // credential while silently accepting any other username
1441 // without verification.
1442 StunAtrString password;
1443 stunCreatePassword(req.username, &password);
1444
1445 if (!stunVerifyMessageIntegrity(buf, bufLen, req, password))
1446 {
1447 if (verbose) clog << "MessageIntegrity is bad. Sending 431." << endl;
1448 stunCreateErrorResponse(*resp, 4, 31, "Integrity Check Failure");
1449 return true;
1450 }
1451
1452 if (verbose) clog << "MessageIntegrity validated" << endl;
1453
1454 // Authenticated: echo USERNAME and request MESSAGE-INTEGRITY on
1455 // the response. The response HMAC is computed by
1456 // stunEncodeMessage() using hmacPassword, which is set below.
1458 resp->hasMessageIntegrity = true;
1459 resp->hasUsername = true;
1460 resp->username = req.username; // copy username in
1461 }
1462 }
1463
1464 // TODO !jf! should check for unknown attributes here and send 420 listing the
1465 // unknown attributes.
1466
1467 if (respondTo.port == 0) respondTo = from;
1468 if (mapped.port == 0) mapped = from;
1469
1470 *changeIp = (flags & ChangeIpFlag) ? true : false;
1471 *changePort = (flags & ChangePortFlag) ? true : false;
1472
1473 if (verbose)
1474 {
1475 clog << "Request is valid:" << endl;
1476 clog << "\t flags=" << flags << endl;
1477 clog << "\t changeIp=" << *changeIp << endl;
1478 clog << "\t changePort=" << *changePort << endl;
1479 clog << "\t from = " << from << endl;
1480 clog << "\t respond to = " << respondTo << endl;
1481 clog << "\t mapped = " << mapped << endl;
1482 }
1483
1484 // form the outgoing message
1486 for (int i = 0; i < 16; i++)
1487 {
1488 resp->msgHdr.id.octet[i] = req.msgHdr.id.octet[i];
1489 }
1490
1491 if (req.xorOnly == false)
1492 {
1493 resp->hasMappedAddress = true;
1494 resp->mappedAddress.ipv4.port = mapped.port;
1495 resp->mappedAddress.ipv4.addr = mapped.addr;
1496 }
1497
1498 if (1) // do xorMapped address or not
1499 {
1500 resp->hasXorMappedAddress = true;
1501 uint16_t id16 = req.msgHdr.id.octet[0] << 8
1502 | req.msgHdr.id.octet[1];
1503 uint32_t id32 = req.msgHdr.id.octet[0] << 24
1504 | req.msgHdr.id.octet[1] << 16
1505 | req.msgHdr.id.octet[2] << 8
1506 | req.msgHdr.id.octet[3];
1507 resp->xorMappedAddress.ipv4.port = mapped.port ^ id16;
1508 resp->xorMappedAddress.ipv4.addr = mapped.addr ^ id32;
1509 }
1510
1511 resp->hasSourceAddress = true;
1512 resp->sourceAddress.ipv4.port = (*changePort) ? altAddr.port : myAddr.port;
1513 resp->sourceAddress.ipv4.addr = (*changeIp) ? altAddr.addr : myAddr.addr;
1514
1515 resp->hasChangedAddress = true;
1516 resp->changedAddress.ipv4.port = altAddr.port;
1517 resp->changedAddress.ipv4.addr = altAddr.addr;
1518
1519 if (secondary.port != 0)
1520 {
1521 resp->hasSecondaryAddress = true;
1522 resp->secondaryAddress.ipv4.port = secondary.port;
1523 resp->secondaryAddress.ipv4.addr = secondary.addr;
1524 }
1525
1526 if (req.hasUsername && req.username.sizeValue > 0)
1527 {
1528 // copy username in
1529 resp->hasUsername = true;
1530 resip_assert(req.username.sizeValue % 4 == 0);
1532 memcpy(resp->username.value, req.username.value, req.username.sizeValue);
1534 }
1535
1536 if (1) // add Software
1537 {
1538 resp->hasSoftware = true;
1539 const char software[] = "Vovida.org " STUN_VERSION; // must pad to mult of 4
1540
1541 resip_assert(sizeof(software) < STUN_MAX_STRING);
1542 //cerr << "sizeof serverName is " << sizeof(serverName) << endl;
1543 resip_assert(sizeof(software) % 4 == 0);
1544 memcpy(resp->software.value, software, sizeof(software));
1545 resp->software.sizeValue = sizeof(software);
1546 }
1547
1548 if (req.hasMessageIntegrity & req.hasUsername)
1549 {
1550 // this creates the password that will be used in the HMAC when then
1551 // messages is sent
1552 stunCreatePassword(req.username, hmacPassword);
1553 }
1554
1555 if (req.hasUsername && (req.username.sizeValue > 64))
1556 {
1557 uint32_t source;
1558 resip_assert(sizeof(int) == sizeof(uint32_t));
1559
1560 source = strtoul(req.username.value, nullptr, 16);
1561 resp->hasReflectedFrom = true;
1562 resp->reflectedFrom.ipv4.port = 0;
1563 resp->reflectedFrom.ipv4.addr = source;
1564 }
1565
1566 destination->port = respondTo.port;
1567 destination->addr = respondTo.addr;
1568
1569 return true;
1570
1571 default:
1572 if (verbose) clog << "Unknown or unsupported request " << endl;
1573 return false;
1574 }
1575
1576 resip_assert(0);
1577 return false;
1578 }
1579
1580 bool
1582 const StunAddress4& altAddr, int startMediaPort, bool verbose)
1583 {
1584 resip_assert(myAddr.port != 0);
1585 resip_assert(altAddr.port != 0);
1586 resip_assert(myAddr.addr != 0);
1587 //assert( altAddr.addr != 0 );
1588
1589 info.myAddr = myAddr;
1590 info.altAddr = altAddr;
1591
1592 info.myFd = INVALID_SOCKET;
1594 info.altIpFd = INVALID_SOCKET;
1596
1597 memset(info.relays, 0, sizeof(info.relays));
1598 if (startMediaPort > 0)
1599 {
1600 info.relay = true;
1601
1602 for (int i = 0; i < MAX_MEDIA_RELAYS; ++i)
1603 {
1604 StunMediaRelay* relay = &info.relays[i];
1605 relay->relayPort = startMediaPort + i;
1606 relay->fd = 0;
1607 relay->expireTime = 0;
1608 }
1609 }
1610 else
1611 {
1612 info.relay = false;
1613 }
1614
1615 if ((info.myFd = openPort(myAddr.port, myAddr.addr, verbose)) == INVALID_SOCKET)
1616 {
1617 if (verbose) clog << "Can't open " << myAddr << endl;
1618 stunStopServer(info);
1619
1620 return false;
1621 }
1622 //if (verbose) clog << "Opened " << myAddr.addr << ":" << myAddr.port << " --> " << info.myFd << endl;
1623
1624 if ((info.altPortFd = openPort(altAddr.port, myAddr.addr, verbose)) == INVALID_SOCKET)
1625 {
1626 if (verbose) clog << "Can't open " << myAddr << endl;
1627 stunStopServer(info);
1628 return false;
1629 }
1630 //if (verbose) clog << "Opened " << myAddr.addr << ":" << altAddr.port << " --> " << info.altPortFd << endl;
1631
1632
1633 info.altIpFd = INVALID_SOCKET;
1634 if (altAddr.addr != 0)
1635 {
1636 if ((info.altIpFd = openPort(myAddr.port, altAddr.addr, verbose)) == INVALID_SOCKET)
1637 {
1638 if (verbose) clog << "Can't open " << altAddr << endl;
1639 stunStopServer(info);
1640 return false;
1641 }
1642 //if (verbose) clog << "Opened " << altAddr.addr << ":" << myAddr.port << " --> " << info.altIpFd << endl;;
1643 }
1644
1646 if (altAddr.addr != 0)
1647 {
1648 if ((info.altIpPortFd = openPort(altAddr.port, altAddr.addr, verbose)) == INVALID_SOCKET)
1649 {
1650 if (verbose) clog << "Can't open " << altAddr << endl;
1651 stunStopServer(info);
1652 return false;
1653 }
1654 //if (verbose) clog << "Opened " << altAddr.addr << ":" << altAddr.port << " --> " << info.altIpPortFd << endl;;
1655 }
1656
1657 return true;
1658 }
1659
1660 void
1662 {
1663 if (info.myFd > 0) closeSocket(info.myFd);
1664 if (info.altPortFd > 0) closeSocket(info.altPortFd);
1665 if (info.altIpFd > 0) closeSocket(info.altIpFd);
1666 if (info.altIpPortFd > 0) closeSocket(info.altIpPortFd);
1667
1668 if (info.relay)
1669 {
1670 for (int i = 0; i < MAX_MEDIA_RELAYS; ++i)
1671 {
1672 StunMediaRelay* relay = &info.relays[i];
1673 if (relay->fd)
1674 {
1675 closeSocket(relay->fd);
1676 relay->fd = 0;
1677 }
1678 }
1679 }
1680 }
1681
1682 bool
1684 {
1685 char msg[STUN_MAX_MESSAGE_SIZE];
1686 int msgLen = sizeof(msg);
1687
1688 bool ok = false;
1689 bool recvAltIp = false;
1690 bool recvAltPort = false;
1691
1692 fd_set fdSet;
1693 resip::Socket maxFd = 0;
1694
1695 FD_ZERO(&fdSet);
1696 FD_SET(info.myFd, &fdSet);
1697 if (info.myFd >= maxFd) maxFd = info.myFd + 1;
1698 FD_SET(info.altPortFd, &fdSet);
1699 if (info.altPortFd >= maxFd) maxFd = info.altPortFd + 1;
1700
1701 if (info.altIpFd != INVALID_SOCKET)
1702 {
1703 FD_SET(info.altIpFd, &fdSet);
1704 if (info.altIpFd >= maxFd) maxFd = info.altIpFd + 1;
1705 }
1706 if (info.altIpPortFd != INVALID_SOCKET)
1707 {
1708 FD_SET(info.altIpPortFd, &fdSet);
1709 if (info.altIpPortFd >= maxFd) maxFd = info.altIpPortFd + 1;
1710 }
1711
1712 if (info.relay)
1713 {
1714 for (int i = 0; i < MAX_MEDIA_RELAYS; ++i)
1715 {
1716 StunMediaRelay* relay = &info.relays[i];
1717 if (relay->fd)
1718 {
1719 FD_SET(relay->fd, &fdSet);
1720 if ((resip::Socket)relay->fd >= maxFd)
1721 {
1722 maxFd = relay->fd + 1;
1723 }
1724 }
1725 }
1726 }
1727
1728 if (info.altIpFd != INVALID_SOCKET)
1729 {
1730 FD_SET(info.altIpFd, &fdSet);
1731 if (info.altIpFd >= maxFd) maxFd = info.altIpFd + 1;
1732 }
1733 if (info.altIpPortFd != INVALID_SOCKET)
1734 {
1735 FD_SET(info.altIpPortFd, &fdSet);
1736 if (info.altIpPortFd >= maxFd) maxFd = info.altIpPortFd + 1;
1737 }
1738
1739 struct timeval tv;
1740 tv.tv_sec = 0;
1741 tv.tv_usec = 1000;
1742
1743 int e = (int)select((int)maxFd, &fdSet, NULL, NULL, &tv);
1744 if (e < 0)
1745 {
1746 int err = getErrno();
1747 if (verbose) clog << "Error on select: " << strError(err) << endl;
1748 }
1749 else if (e >= 0)
1750 {
1751 StunAddress4 from;
1752
1753 // do the media relaying
1754 if (info.relay)
1755 {
1756 time_t now = time(0);
1757 for (int i = 0; i < MAX_MEDIA_RELAYS; ++i)
1758 {
1759 StunMediaRelay* relay = &info.relays[i];
1760 if (relay->fd)
1761 {
1762 if (FD_ISSET(relay->fd, &fdSet))
1763 {
1764 char msg[MAX_RTP_MSG_SIZE];
1765 int msgLen = sizeof(msg);
1766
1767 StunAddress4 rtpFrom;
1768 ok = getMessage(relay->fd, msg, &msgLen, &rtpFrom.addr, &rtpFrom.port, verbose);
1769 if (ok)
1770 {
1771 sendMessage(info.myFd, msg, msgLen, relay->destination.addr, relay->destination.port, verbose);
1772 relay->expireTime = now + MEDIA_RELAY_TIMEOUT;
1773 if (verbose) clog << "Relay packet on "
1774 << relay->fd
1775 << " from " << rtpFrom
1776 << " -> " << relay->destination
1777 << endl;
1778 }
1779 }
1780 else if (now > relay->expireTime)
1781 {
1782 closeSocket(relay->fd);
1783 relay->fd = 0;
1784 }
1785 }
1786 }
1787 }
1788
1789
1790 if (FD_ISSET(info.myFd, &fdSet))
1791 {
1792 if (verbose) clog << "received on A1:P1" << endl;
1793 recvAltIp = false;
1794 recvAltPort = false;
1795 ok = getMessage(info.myFd, msg, &msgLen, &from.addr, &from.port, verbose);
1796 }
1797 else if (FD_ISSET(info.altPortFd, &fdSet))
1798 {
1799 if (verbose) clog << "received on A1:P2" << endl;
1800 recvAltIp = false;
1801 recvAltPort = true;
1802 ok = getMessage(info.altPortFd, msg, &msgLen, &from.addr, &from.port, verbose);
1803 }
1804 else if ((info.altIpFd != INVALID_SOCKET) && FD_ISSET(info.altIpFd, &fdSet))
1805 {
1806 if (verbose) clog << "received on A2:P1" << endl;
1807 recvAltIp = true;
1808 recvAltPort = false;
1809 ok = getMessage(info.altIpFd, msg, &msgLen, &from.addr, &from.port, verbose);
1810 }
1811 else if ((info.altIpPortFd != INVALID_SOCKET) && FD_ISSET(info.altIpPortFd, &fdSet))
1812 {
1813 if (verbose) clog << "received on A2:P2" << endl;
1814 recvAltIp = true;
1815 recvAltPort = true;
1816 ok = getMessage(info.altIpPortFd, msg, &msgLen, &from.addr, &from.port, verbose);
1817 }
1818 else
1819 {
1820 return true;
1821 }
1822
1823 int relayPort = 0;
1824 if (info.relay)
1825 {
1826 for (int i = 0; i < MAX_MEDIA_RELAYS; ++i)
1827 {
1828 StunMediaRelay* relay = &info.relays[i];
1829 if (relay->destination.addr == from.addr &&
1830 relay->destination.port == from.port)
1831 {
1832 relayPort = relay->relayPort;
1833 relay->expireTime = time(0) + MEDIA_RELAY_TIMEOUT;
1834 break;
1835 }
1836 }
1837
1838 if (relayPort == 0)
1839 {
1840 for (int i = 0; i < MAX_MEDIA_RELAYS; ++i)
1841 {
1842 StunMediaRelay* relay = &info.relays[i];
1843 if (relay->fd == 0)
1844 {
1845 if (verbose) clog << "Open relay port " << relay->relayPort << endl;
1846
1847 relay->fd = (int)openPort(relay->relayPort, info.myAddr.addr, verbose);
1848 relay->destination.addr = from.addr;
1849 relay->destination.port = from.port;
1850 relay->expireTime = time(0) + MEDIA_RELAY_TIMEOUT;
1851 relayPort = relay->relayPort;
1852 break;
1853 }
1854 }
1855 }
1856 }
1857
1858 if (!ok)
1859 {
1860 if (verbose) clog << "Get message did not return a valid message" << endl;
1861 return true;
1862 }
1863
1864 if (verbose) clog << "Got a request (len=" << msgLen << ") from " << from << endl;
1865
1866 if (msgLen <= 0)
1867 {
1868 return true;
1869 }
1870
1871 bool changePort = false;
1872 bool changeIp = false;
1873
1874 StunMessage resp;
1875 StunAddress4 dest;
1876 StunAtrString hmacPassword;
1877 hmacPassword.sizeValue = 0;
1878
1879 StunAddress4 secondary;
1880 secondary.port = 0;
1881 secondary.addr = 0;
1882
1883 if (info.relay && relayPort)
1884 {
1885 secondary = from;
1886
1887 from.addr = info.myAddr.addr;
1888 from.port = relayPort;
1889 }
1890
1891 ok = stunServerProcessMsg(msg, msgLen, from, secondary,
1892 recvAltIp ? info.altAddr : info.myAddr,
1893 recvAltIp ? info.myAddr : info.altAddr,
1894 &resp,
1895 &dest,
1896 &hmacPassword,
1897 &changePort,
1898 &changeIp,
1899 verbose);
1900
1901 if (!ok)
1902 {
1903 if (verbose) clog << "Failed to parse message" << endl;
1904 return true;
1905 }
1906
1907 char buf[STUN_MAX_MESSAGE_SIZE];
1908 int len = sizeof(buf);
1909
1910 len = stunEncodeMessage(resp, buf, len, hmacPassword, verbose);
1911
1912 if (dest.addr == 0) ok = false;
1913 if (dest.port == 0) ok = false;
1914
1915 if (ok)
1916 {
1917 resip_assert(dest.addr != 0);
1918 resip_assert(dest.port != 0);
1919
1920 resip::Socket sendFd;
1921
1922 bool sendAltIp = recvAltIp; // send on the received IP address
1923 bool sendAltPort = recvAltPort; // send on the received port
1924
1925 if (changeIp) sendAltIp = !sendAltIp; // if need to change IP, then flip logic
1926 if (changePort) sendAltPort = !sendAltPort; // if need to change port, then flip logic
1927
1928 if (!sendAltPort)
1929 {
1930 if (!sendAltIp)
1931 {
1932 sendFd = info.myFd;
1933 }
1934 else
1935 {
1936 sendFd = info.altIpFd;
1937 }
1938 }
1939 else
1940 {
1941 if (!sendAltIp)
1942 {
1943 sendFd = info.altPortFd;
1944 }
1945 else
1946 {
1947 sendFd = info.altIpPortFd;
1948 }
1949 }
1950
1951 if (sendFd != INVALID_SOCKET)
1952 {
1953 sendMessage(sendFd, buf, len, dest.addr, dest.port, verbose);
1954 }
1955 }
1956 }
1957
1958 return true;
1959 }
1960
1961 int
1962 stunFindLocalInterfaces(uint32_t* addresses, int maxRet)
1963 {
1964#if defined(WIN32) || defined(__sparc__)
1965 return 0;
1966#else
1967 struct ifconf ifc;
1968
1969 int s = socket(AF_INET, SOCK_DGRAM, 0);
1970 const int len = 100 * sizeof(struct ifreq);
1971
1972 char buf[len];
1973
1974 ifc.ifc_len = len;
1975 ifc.ifc_buf = buf;
1976
1977 int e = ioctl(s, SIOCGIFCONF, &ifc);
1978 char* ptr = buf;
1979 int tl = ifc.ifc_len;
1980 int count = 0;
1981
1982 while ((tl > 0) && (count < maxRet))
1983 {
1984 struct ifreq* ifr = (struct ifreq*)ptr;
1985
1986 int si = sizeof(ifr->ifr_name) + sizeof(struct sockaddr);
1987 tl -= si;
1988 ptr += si;
1989 //char* name = ifr->ifr_ifrn.ifrn_name;
1990 //cerr << "name = " << name << endl;
1991
1992 struct ifreq ifr2;
1993 ifr2 = *ifr;
1994
1995 e = ioctl(s, SIOCGIFADDR, &ifr2);
1996 if (e == -1)
1997 {
1998 break;
1999 }
2000
2001 //cerr << "ioctl addr e = " << e << endl;
2002
2003 struct sockaddr a = ifr2.ifr_addr;
2004 struct sockaddr_in* addr = (struct sockaddr_in*)&a;
2005
2006 uint32_t ai = ntohl(addr->sin_addr.s_addr);
2007 if (int((ai >> 24) & 0xFF) != 127)
2008 {
2009 addresses[count++] = ai;
2010 }
2011
2012#if 0
2013 cerr << "Detected interface "
2014 << int((ai >> 24) & 0xFF) << "."
2015 << int((ai >> 16) & 0xFF) << "."
2016 << int((ai >> 8) & 0xFF) << "."
2017 << int((ai) & 0xFF) << endl;
2018#endif
2019 }
2020
2021 closeSocket(s);
2022
2023 return count;
2024#endif
2025 }
2026
2027
2028 void
2030 const StunAtrString& username,
2031 bool changePort, bool changeIp, unsigned int id)
2032 {
2033 resip_assert(msg);
2034
2036
2037 for (int i = 0; i < 16; i = i + 4)
2038 {
2039 resip_assert(i + 3 < 16);
2040 // STUN transaction IDs must be unpredictable (CWE-338/CWE-345): a
2041 // predictable ID lets an attacker forge STUN responses. Use the CSPRNG
2042 // rather than the weak stunRand() generator.
2043 int r = Random::getCryptoRandom();
2044 msg->msgHdr.id.octet[i + 0] = r >> 0;
2045 msg->msgHdr.id.octet[i + 1] = r >> 8;
2046 msg->msgHdr.id.octet[i + 2] = r >> 16;
2047 msg->msgHdr.id.octet[i + 3] = r >> 24;
2048 }
2049
2050 if (id != 0)
2051 {
2052 msg->msgHdr.id.octet[0] = id;
2053 }
2054
2055 msg->hasChangeRequest = true;
2056 msg->changeRequest.value = (changeIp ? ChangeIpFlag : 0) |
2057 (changePort ? ChangePortFlag : 0);
2058
2059 if (username.sizeValue > 0)
2060 {
2061 msg->hasUsername = true;
2062 msg->username = username;
2063 }
2064 }
2065
2066
2067 static void
2069 const StunAtrString& username, const StunAtrString& password,
2070 int testNum, bool verbose)
2071 {
2072 resip_assert(dest.addr != 0);
2073 resip_assert(dest.port != 0);
2074
2075 bool changePort = false;
2076 bool changeIP = false;
2077
2078 switch (testNum)
2079 {
2080 case 1:
2081 case 5:
2082 case 10:
2083 case 11:
2084 break;
2085 case 2:
2086 //changePort=true;
2087 changeIP = true;
2088 break;
2089 case 3:
2090 changePort = true;
2091 break;
2092 case 4:
2093 changeIP = true;
2094 break;
2095 default:
2096 cerr << "Test " << testNum << " is unknown\n";
2097 resip_assert(0);
2098 }
2099
2100 StunMessage req;
2101 stunBuildReqSimple(&req, username,
2102 changePort, changeIP,
2103 testNum);
2104
2105 char buf[STUN_MAX_MESSAGE_SIZE];
2106 int len = STUN_MAX_MESSAGE_SIZE;
2107
2108 len = stunEncodeMessage(req, buf, len, password, verbose);
2109
2110 if (verbose)
2111 {
2112 clog << "About to send msg of len " << len << " to " << dest << endl;
2113 }
2114
2115 sendMessage(myFd, buf, len, dest.addr, dest.port, verbose);
2116
2117 }
2118
2119
2120 void
2122 StunAtrString* username,
2123 StunAtrString* password)
2124 {
2125 // !cj! This is totally bogus - need to make TLS connection to dest and get a
2126 // username and password to use
2127 stunCreateUserName(dest, username);
2128 stunCreatePassword(*username, password);
2129 }
2130
2131
2132 bool
2133 stunTest(StunAddress4& dest, int testNum, bool verbose, StunAddress4* sAddr, unsigned long timeoutMs)
2134 {
2135 resip_assert(dest.addr != 0);
2136 resip_assert(dest.port != 0);
2137
2138 int port = stunRandomPort();
2139 uint32_t interfaceIp = 0;
2140 if (sAddr)
2141 {
2142 interfaceIp = sAddr->addr;
2143 if (sAddr->port != 0)
2144 {
2145 port = sAddr->port;
2146 }
2147 }
2148 resip::Socket myFd = openPort(port, interfaceIp, verbose);
2149
2150 if (myFd == INVALID_SOCKET)
2151 {
2152 return false;
2153 }
2154
2155 // make socket non-blocking
2156 if (!makeSocketNonBlocking(myFd))
2157 {
2158 closeSocket(myFd);
2159 return false;
2160 }
2161
2162 StunAtrString username;
2163 StunAtrString password;
2164
2165 username.sizeValue = 0;
2166 password.sizeValue = 0;
2167
2168#ifdef USE_TLS
2169 stunGetUserNameAndPassword(dest, username, password);
2170#endif
2171
2172 stunSendTest(myFd, dest, username, password, testNum, verbose);
2173
2174 char msg[STUN_MAX_MESSAGE_SIZE];
2175 int msgLen = STUN_MAX_MESSAGE_SIZE;
2176
2177 // Wait to receive a packet
2178 resip::FdSet myFdSet;
2179 myFdSet.setRead(myFd);
2180 if (myFdSet.selectMilliSeconds(timeoutMs) < 1)
2181 {
2182 // no packet received or an error occured
2183 closeSocket(myFd);
2184 return false;
2185 }
2186
2187 StunAddress4 from;
2188 if (!getMessage(myFd, msg, &msgLen, &from.addr, &from.port, verbose))
2189 {
2190 closeSocket(myFd);
2191 return false;
2192 }
2193
2194 if (verbose) clog << "Got a response" << endl;
2195
2196 StunMessage resp;
2197 bool ok = stunParseMessage(msg, msgLen, resp, verbose);
2198
2199 if (verbose)
2200 {
2201 clog << "\t ok=" << ok << endl;
2202 clog << "\t id=" << resp.msgHdr.id << endl;
2203 clog << "\t mappedAddr=" << resp.mappedAddress.ipv4 << endl;
2204 clog << "\t changedAddr=" << resp.changedAddress.ipv4 << endl;
2205 clog << endl;
2206 }
2207
2208 if (sAddr)
2209 {
2210 sAddr->port = resp.mappedAddress.ipv4.port;
2211 sAddr->addr = resp.mappedAddress.ipv4.addr;
2212 }
2213
2214 closeSocket(myFd);
2215 return ok;
2216 }
2217
2218
2219 NatType
2221 bool verbose,
2222 bool* preservePort, // if set, is return for if NAT preservers ports or not
2223 bool* hairpin, // if set, is the return for if NAT will hairpin packets
2224 int port, // port to use for the test, 0 to choose random port
2225 StunAddress4* sAddr // NIC to use
2226 )
2227 {
2228 resip_assert(dest.addr != 0);
2229 resip_assert(dest.port != 0);
2230
2231 if (hairpin)
2232 {
2233 *hairpin = false;
2234 }
2235
2236 if (port == 0)
2237 {
2238 port = stunRandomPort();
2239 }
2240 uint32_t interfaceIp = 0;
2241 if (sAddr)
2242 {
2243 interfaceIp = sAddr->addr;
2244 }
2245 resip::Socket myFd1 = openPort(port, interfaceIp, verbose);
2246 resip::Socket myFd2 = openPort(port + 1, interfaceIp, verbose);
2247
2248 if ((myFd1 == INVALID_SOCKET) || (myFd2 == INVALID_SOCKET))
2249 {
2250 if (myFd1 != INVALID_SOCKET) closeSocket(myFd1);
2251 if (myFd2 != INVALID_SOCKET) closeSocket(myFd2);
2252 cerr << "Some problem opening port/interface to send on" << endl;
2253 return StunTypeFailure;
2254 }
2255
2256 resip_assert(myFd1 != INVALID_SOCKET);
2257 resip_assert(myFd2 != INVALID_SOCKET);
2258
2259 bool respTestI = false;
2260 bool isNat = true;
2261 StunAddress4 testImappedAddr;
2262 bool respTestI2 = false;
2263 bool mappedIpSame = true;
2264 StunAddress4 testI2mappedAddr;
2265 StunAddress4 testI2dest = dest;
2266 bool respTestII = false;
2267 bool respTestIII = false;
2268
2269 bool respTestHairpin = false;
2270 bool respTestPreservePort = false;
2271
2272 memset(&testImappedAddr, 0, sizeof(testImappedAddr));
2273
2274 StunAtrString username;
2275 StunAtrString password;
2276
2277 username.sizeValue = 0;
2278 password.sizeValue = 0;
2279
2280#ifdef USE_TLS
2281 stunGetUserNameAndPassword(dest, username, password);
2282#endif
2283
2284 int count = 0;
2285 while (count < 7)
2286 {
2287 struct timeval tv;
2288 fd_set fdSet;
2289#ifdef WIN32
2290 typedef unsigned int FdSetSize;
2291#else
2292 typedef int FdSetSize;
2293#endif
2294 FdSetSize fdSetSize;
2295 FD_ZERO(&fdSet); fdSetSize = 0;
2296 FD_SET(myFd1, &fdSet); fdSetSize = ((FdSetSize)myFd1 + 1 > fdSetSize) ? (FdSetSize)myFd1 + 1 : fdSetSize;
2297 FD_SET(myFd2, &fdSet); fdSetSize = ((FdSetSize)myFd2 + 1 > fdSetSize) ? (FdSetSize)myFd2 + 1 : fdSetSize;
2298 tv.tv_sec = 0;
2299 tv.tv_usec = 150 * 1000; // 150 ms
2300 if (count == 0) tv.tv_usec = 0;
2301
2302 int err = select(fdSetSize, &fdSet, NULL, NULL, &tv);
2303 int e = getErrno();
2304 if (err == SOCKET_ERROR)
2305 {
2306 // error occured
2307 closeSocket(myFd1);
2308 closeSocket(myFd2);
2309 cerr << "Error " << e << " " << strError(e) << " in select" << endl;
2310 return StunTypeFailure;
2311 }
2312 else if (err == 0)
2313 {
2314 // timeout occured
2315 count++;
2316
2317 if (!respTestI)
2318 {
2319 stunSendTest(myFd1, dest, username, password, 1, verbose);
2320 }
2321
2322 if ((!respTestI2) && respTestI)
2323 {
2324 // check the address to send to if valid
2325 if ((testI2dest.addr != 0) &&
2326 (testI2dest.port != 0))
2327 {
2328 stunSendTest(myFd1, testI2dest, username, password, 10, verbose);
2329 }
2330 }
2331
2332 if (!respTestII)
2333 {
2334 stunSendTest(myFd2, dest, username, password, 2, verbose);
2335 }
2336
2337 if (!respTestIII)
2338 {
2339 stunSendTest(myFd2, dest, username, password, 3, verbose);
2340 }
2341
2342 if (respTestI && (!respTestHairpin))
2343 {
2344 if ((testImappedAddr.addr != 0) &&
2345 (testImappedAddr.port != 0))
2346 {
2347 stunSendTest(myFd1, testImappedAddr, username, password, 11, verbose);
2348 }
2349 }
2350 }
2351 else
2352 {
2353 //if (verbose) clog << "-----------------------------------------" << endl;
2354 resip_assert(err > 0);
2355 // data is avialbe on some fd
2356
2357 for (int i = 0; i < 2; i++)
2358 {
2359 resip::Socket myFd;
2360 if (i == 0)
2361 {
2362 myFd = myFd1;
2363 }
2364 else
2365 {
2366 myFd = myFd2;
2367 }
2368
2369 if (myFd != INVALID_SOCKET)
2370 {
2371 if (FD_ISSET(myFd, &fdSet))
2372 {
2373 char msg[STUN_MAX_MESSAGE_SIZE];
2374 int msgLen = sizeof(msg);
2375
2376 StunAddress4 from;
2377
2378 getMessage(myFd,
2379 msg,
2380 &msgLen,
2381 &from.addr,
2382 &from.port,
2383 verbose);
2384
2385 StunMessage resp;
2386 stunParseMessage(msg, msgLen, resp, verbose);
2387
2388 if (verbose)
2389 {
2390 clog << "Received message of type " << resp.msgHdr.msgType
2391 << " id=" << (int)(resp.msgHdr.id.octet[0]) << endl;
2392 }
2393
2394 switch (resp.msgHdr.id.octet[0])
2395 {
2396 case 1:
2397 {
2398 if (!respTestI)
2399 {
2400
2401 testImappedAddr.addr = resp.mappedAddress.ipv4.addr;
2402 testImappedAddr.port = resp.mappedAddress.ipv4.port;
2403
2404 respTestPreservePort = (testImappedAddr.port == port);
2405 if (preservePort)
2406 {
2407 *preservePort = respTestPreservePort;
2408 }
2409
2410 testI2dest.addr = resp.changedAddress.ipv4.addr;
2411
2412 if (sAddr)
2413 {
2414 sAddr->port = testImappedAddr.port;
2415 sAddr->addr = testImappedAddr.addr;
2416 }
2417
2418 count = 0;
2419 }
2420 respTestI = true;
2421 }
2422 break;
2423 case 2:
2424 {
2425 respTestII = true;
2426 }
2427 break;
2428 case 3:
2429 {
2430 respTestIII = true;
2431 }
2432 break;
2433 case 10:
2434 {
2435 if (!respTestI2)
2436 {
2437 testI2mappedAddr.addr = resp.mappedAddress.ipv4.addr;
2438 testI2mappedAddr.port = resp.mappedAddress.ipv4.port;
2439
2440 mappedIpSame = false;
2441 if ((testI2mappedAddr.addr == testImappedAddr.addr) &&
2442 (testI2mappedAddr.port == testImappedAddr.port))
2443 {
2444 mappedIpSame = true;
2445 }
2446
2447
2448 }
2449 respTestI2 = true;
2450 }
2451 break;
2452 case 11:
2453 {
2454
2455 if (hairpin)
2456 {
2457 *hairpin = true;
2458 }
2459 respTestHairpin = true;
2460 }
2461 break;
2462 }
2463 }
2464 }
2465 }
2466 }
2467 }
2468
2469 closeSocket(myFd1);
2470 closeSocket(myFd2);
2471
2472 // see if we can bind to this address
2473 //cerr << "try binding to " << testImappedAddr << endl;
2474 resip::Socket s = openPort(0/*use ephemeral*/, testImappedAddr.addr, false);
2475 if (s != INVALID_SOCKET)
2476 {
2477 closeSocket(s);
2478 isNat = false;
2479 //cerr << "binding worked" << endl;
2480 }
2481 else
2482 {
2483 isNat = true;
2484 //cerr << "binding failed" << endl;
2485 }
2486
2487 if (verbose)
2488 {
2489 clog << "test I = " << respTestI << endl;
2490 clog << "test II = " << respTestII << endl;
2491 clog << "test III = " << respTestIII << endl;
2492 clog << "test I(2) = " << respTestI2 << endl;
2493 clog << "is nat = " << isNat << endl;
2494 clog << "mapped IP same = " << mappedIpSame << endl;
2495 clog << "hairpin = " << respTestHairpin << endl;
2496 clog << "preserver port = " << respTestPreservePort << endl;
2497 }
2498
2499#if 0
2500 // implement logic flow chart from draft RFC
2501 if (respTestI)
2502 {
2503 if (isNat)
2504 {
2505 if (respTestII)
2506 {
2507 return StunTypeConeNat;
2508 }
2509 else
2510 {
2511 if (mappedIpSame)
2512 {
2513 if (respTestIII)
2514 {
2515 return StunTypeRestrictedNat;
2516 }
2517 else
2518 {
2519 return StunTypePortRestrictedNat;
2520 }
2521 }
2522 else
2523 {
2524 return StunTypeSymNat;
2525 }
2526 }
2527 }
2528 else
2529 {
2530 if (respTestII)
2531 {
2532 return StunTypeOpen;
2533 }
2534 else
2535 {
2536 return StunTypeSymFirewall;
2537 }
2538 }
2539 }
2540 else
2541 {
2542 return StunTypeBlocked;
2543 }
2544#else
2545 if (respTestI) // not blocked
2546 {
2547 if (isNat)
2548 {
2549 if (mappedIpSame)
2550 {
2551 if (respTestII)
2552 {
2554 }
2555 else
2556 {
2557 if (respTestIII)
2558 {
2560 }
2561 else
2562 {
2564 }
2565 }
2566 }
2567 else // mappedIp is not same
2568 {
2570 }
2571 }
2572 else // isNat is false
2573 {
2574 if (respTestII)
2575 {
2576 return StunTypeOpen;
2577 }
2578 else
2579 {
2580 return StunTypeFirewall;
2581 }
2582 }
2583 }
2584 else
2585 {
2586 return StunTypeBlocked;
2587 }
2588#endif
2589
2590 return StunTypeUnknown;
2591 }
2592
2593
2594 int
2596 int port, StunAddress4* srcAddr,
2597 bool verbose)
2598 {
2599 resip_assert(dest.addr != 0);
2600 resip_assert(dest.port != 0);
2601 resip_assert(mapAddr);
2602
2603 if (port == 0)
2604 {
2605 port = stunRandomPort();
2606 }
2607 unsigned int interfaceIp = 0;
2608 if (srcAddr)
2609 {
2610 interfaceIp = srcAddr->addr;
2611 }
2612
2613 resip::Socket myFd = openPort(port, interfaceIp, verbose);
2614 if (myFd == INVALID_SOCKET)
2615 {
2616 return (int)myFd;
2617 }
2618
2619 char msg[STUN_MAX_MESSAGE_SIZE];
2620 int msgLen = sizeof(msg);
2621
2622 StunAtrString username;
2623 StunAtrString password;
2624
2625 username.sizeValue = 0;
2626 password.sizeValue = 0;
2627
2628#ifdef USE_TLS
2629 stunGetUserNameAndPassword(dest, username, password);
2630#endif
2631
2632 stunSendTest(myFd, dest, username, password, 1, 0/*false*/);
2633
2634 StunAddress4 from;
2635
2636 getMessage(myFd, msg, &msgLen, &from.addr, &from.port, verbose);
2637
2638 StunMessage resp;
2639 bool ok = stunParseMessage(msg, msgLen, resp, verbose);
2640 if (!ok)
2641 {
2642 closeSocket(myFd);
2643 return -1;
2644 }
2645
2646 StunAddress4 mappedAddr = resp.mappedAddress.ipv4;
2647
2648 //clog << "--- stunOpenSocket --- " << endl;
2649 //clog << "\treq id=" << req.id << endl;
2650 //clog << "\tresp id=" << id << endl;
2651 //clog << "\tmappedAddr=" << mappedAddr << endl;
2652
2653 *mapAddr = mappedAddr;
2654
2655 return (int)myFd;
2656 }
2657
2658
2659 bool
2661 int* fd1, int* fd2,
2662 int port, StunAddress4* srcAddr,
2663 bool verbose)
2664 {
2665 resip_assert(dest.addr != 0);
2666 resip_assert(dest.port != 0);
2667 resip_assert(mapAddr);
2668
2669 const int NUM = 3;
2670
2671 if (port == 0)
2672 {
2673 port = stunRandomPort();
2674 }
2675
2676 *fd1 = -1;
2677 *fd2 = -1;
2678
2679 char msg[STUN_MAX_MESSAGE_SIZE];
2680 int msgLen = sizeof(msg);
2681
2682 StunAddress4 from;
2683 int fd[NUM];
2684 int i;
2685
2686 unsigned int interfaceIp = 0;
2687 if (srcAddr)
2688 {
2689 interfaceIp = srcAddr->addr;
2690 }
2691
2692 for (i = 0; i < NUM; i++)
2693 {
2694 fd[i] = (int)openPort((port == 0) ? 0 : (port + i),
2695 interfaceIp, verbose);
2696 if (fd[i] < 0)
2697 {
2698 while (i > 0)
2699 {
2700 closeSocket(fd[--i]);
2701 }
2702 return false;
2703 }
2704 }
2705
2706 StunAtrString username;
2707 StunAtrString password;
2708
2709 username.sizeValue = 0;
2710 password.sizeValue = 0;
2711
2712#ifdef USE_TLS
2713 stunGetUserNameAndPassword(dest, username, password);
2714#endif
2715
2716 for (i = 0; i < NUM; i++)
2717 {
2718 stunSendTest(fd[i], dest, username, password, 1/*testNum*/, verbose);
2719 }
2720
2721 StunAddress4 mappedAddr[NUM];
2722 for (i = 0; i < NUM; i++)
2723 {
2724 msgLen = sizeof(msg) / sizeof(*msg);
2725 getMessage(fd[i],
2726 msg,
2727 &msgLen,
2728 &from.addr,
2729 &from.port, verbose);
2730
2731 StunMessage resp;
2732 bool ok = stunParseMessage(msg, msgLen, resp, verbose);
2733 if (!ok)
2734 {
2735 return false;
2736 }
2737
2738 mappedAddr[i] = resp.mappedAddress.ipv4;
2739 }
2740
2741 if (verbose)
2742 {
2743 clog << "--- stunOpenSocketPair --- " << endl;
2744 for (i = 0; i < NUM; i++)
2745 {
2746 clog << "\t mappedAddr=" << mappedAddr[i] << endl;
2747 }
2748 }
2749
2750 if (mappedAddr[0].port % 2 == 0)
2751 {
2752 if (mappedAddr[0].port + 1 == mappedAddr[1].port)
2753 {
2754 *mapAddr = mappedAddr[0];
2755 *fd1 = fd[0];
2756 *fd2 = fd[1];
2757 closeSocket(fd[2]);
2758 return true;
2759 }
2760 }
2761 else
2762 {
2763 if ((mappedAddr[1].port % 2 == 0)
2764 && (mappedAddr[1].port + 1 == mappedAddr[2].port))
2765 {
2766 *mapAddr = mappedAddr[1];
2767 *fd1 = fd[1];
2768 *fd2 = fd[2];
2769 closeSocket(fd[0]);
2770 return true;
2771 }
2772 }
2773
2774 // something failed, close all and return error
2775 for (i = 0; i < NUM; i++)
2776 {
2777 closeSocket(fd[i]);
2778 }
2779
2780 return false;
2781 }
2782
2783 bool
2784 operator<(const UInt128& lhs, const UInt128& rhs)
2785 {
2786 return memcmp(&lhs, &rhs, sizeof(lhs)) < 0;
2787 }
2788
2789 bool operator==(const UInt128& lhs, const UInt128& rhs)
2790 {
2791 return memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
2792 }
2793
2794 bool
2795 operator<(const StunMsgHdr& lhs, const StunMsgHdr& rhs)
2796 {
2797 return lhs.id < rhs.id;
2798 }
2799
2800}
2801
2802/* ====================================================================
2803 * Copyright (c) 2026 SIP Spectrum, Inc. https://www.sipspectrum.com
2804 * The Vovida Software License, Version 1.0
2805 *
2806 * Redistribution and use in source and binary forms, with or without
2807 * modification, are permitted provided that the following conditions
2808 * are met:
2809 *
2810 * 1. Redistributions of source code must retain the above copyright
2811 * notice, this list of conditions and the following disclaimer.
2812 *
2813 * 2. Redistributions in binary form must reproduce the above copyright
2814 * notice, this list of conditions and the following disclaimer in
2815 * the documentation and/or other materials provided with the
2816 * distribution.
2817 *
2818 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
2819 * and "Vovida Open Communication Application Library (VOCAL)" must
2820 * not be used to endorse or promote products derived from this
2821 * software without prior written permission. For written
2822 * permission, please contact vocal@vovida.org.
2823 *
2824 * 4. Products derived from this software may not be called "VOCAL", nor
2825 * may "VOCAL" appear in their name, without prior written
2826 * permission of Vovida Networks, Inc.
2827 *
2828 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
2829 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2830 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
2831 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
2832 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
2833 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
2834 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2835 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2836 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2837 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2838 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2839 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2840 * DAMAGE.
2841 *
2842 */
2843
2844 // Local Variables:
2845 // mode:c++
2846 // c-file-style:"ellemtel"
2847 // c-file-offsets:((case-label . +))
2848 // indent-tabs-mode:nil
2849 // End:
2850
2851
static const char hexmap[]
Definition Data.cxx:59
#define max(x, y)
static const Data cookie("z9hG4bK")
static const Data sep("[]")
#define resip_assert(x)
This file needs to work for both C and C++ code.
Handles cross-platform sockets compatibility.
#define WSANOTINITIALISED
Definition Socket.hxx:82
#define INVALID_SOCKET
Definition Socket.hxx:95
#define SOCKET_ERROR
Definition Socket.hxx:96
#define MAX_RTP_MSG_SIZE
Definition Stun.hxx:323
#define MAX_REALM_BYTES
Definition Stun.hxx:58
#define STUN_MAX_MESSAGE_SIZE
Definition Stun.hxx:23
#define STUN_VERSION
Definition Stun.hxx:19
#define MEDIA_RELAY_TIMEOUT
Definition Stun.hxx:324
#define STUN_MAX_STRING
Definition Stun.hxx:21
#define MAX_NONCE_BYTES
Definition Stun.hxx:59
#define MAX_MEDIA_RELAYS
Definition Stun.hxx:322
resip::Socket openPort(unsigned short port, unsigned int interfaceIp, bool verbose)
Open a UDP socket to receive on the given port - if port is 0, pick a a port, if interfaceIp!...
Definition Udp.cxx:38
bool getMessage(resip::Socket fd, char *buf, int *len, uint32_t *srcIp, unsigned short *srcPort, bool verbose)
recive a UDP message
Definition Udp.cxx:118
bool sendMessage(resip::Socket fd, char *buf, int l, unsigned int dstIp, unsigned short dstPort, bool verbose)
send a UDP message
Definition Udp.cxx:187
static const struct nv flags[]
Definition adig.c:62
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
@ Share
The Data instance will use the buffer in a read-only mode.
Definition Data.hxx:266
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Definition Data.hxx:608
Object-oriented wrapper for your platform's file-descriptor set.
Definition Socket.hxx:162
void setRead(Socket fd)
Definition Socket.hxx:204
int selectMilliSeconds(unsigned long ms)
Definition Socket.hxx:181
static int getRandom()
Returns a postive integer (31 bits) of randomness.
Definition Random.cxx:261
static int getCryptoRandom()
Definition Random.cxx:330
dcm! – add UnusedChecking(_enum) below;
const uint16_t TurnSendResponse
Definition Stun.hxx:111
static void stunSendTest(resip::Socket myFd, StunAddress4 &dest, const StunAtrString &username, const StunAtrString &password, int testNum, bool verbose)
Definition Stun.cxx:2068
bool stunParseServerName(char *name, StunAddress4 &addr)
find the IP address of a the specified stun server - return false is fails parse
Definition Stun.cxx:1313
void stunCreateUserName(const StunAddress4 &source, StunAtrString *username)
Definition Stun.cxx:1070
const uint16_t TurnSetActiveDestinationRequest
Definition Stun.hxx:114
bool stunInitServer(StunServerInfo &info, const StunAddress4 &myAddr, const StunAddress4 &altAddr, int startMediaPort, bool verbose)
return true if all is OK Create a media relay and do the STERN thing if startMediaPort is non-zero
Definition Stun.cxx:1581
static bool stunParseAtrChangeRequest(char *body, unsigned int hdrLen, StunAtrChangeRequest &result)
Definition Stun.cxx:108
void computeHmac(char *hmac, const char *input, int length, const char *key, int sizeKey)
Definition Stun.cxx:943
static bool stunParseAtrIntegrity(char *body, unsigned int hdrLen, StunAtrIntegrity &result)
Definition Stun.cxx:216
const uint16_t TurnLifetime
Definition Stun.hxx:87
static const uint16_t Username
Definition Stun.hxx:68
static char * encodeAtrUnknown(char *ptr, const StunAtrUnknown &atr)
Definition Stun.cxx:717
static const uint16_t AlternateServer
Definition Stun.hxx:82
const uint16_t SharedSecretErrorResponseMsg
Definition Stun.hxx:104
static char * encodeAtrString(char *ptr, uint16_t type, const StunAtrString &atr)
Definition Stun.cxx:738
static char * encodeAtrError(char *ptr, const StunAtrError &atr)
Definition Stun.cxx:704
NatType stunNatType(StunAddress4 &dest, bool verbose, bool *preservePort, bool *hairpin, int port, StunAddress4 *sAddr)
Definition Stun.cxx:2220
const uint16_t TurnSendErrorResponse
Definition Stun.hxx:112
const uint16_t TurnMagicCookie
Definition Stun.hxx:89
static char * encodeAtrAddress4(char *ptr, uint16_t type, const StunAtrAddress4 &atr)
Definition Stun.cxx:672
void stunCreatePassword(const StunAtrString &username, StunAtrString *password)
Definition Stun.cxx:1110
static const uint16_t XorMappedAddress
Definition Stun.hxx:76
static char * encodeTurnData(char *ptr, const resip::Data *td)
Definition Stun.cxx:652
static bool stunParseAtrUnknown(char *body, unsigned int hdrLen, StunAtrUnknown &result)
Definition Stun.cxx:152
const uint8_t IPv4Family
define a structure to hold a stun address
Definition Stun.hxx:51
const uint16_t TurnDestinationAddress
Definition Stun.hxx:91
static const uint16_t ChangedAddress
Definition Stun.hxx:67
int stunFindLocalInterfaces(uint32_t *addresses, int maxRet)
returns number of address found - take array or addres
Definition Stun.cxx:1962
const uint16_t TurnData
Definition Stun.hxx:93
static void toHex(const char *buffer, int bufferSize, char *output)
Definition Stun.cxx:1050
bool stunServerProcessMsg(char *buf, unsigned int bufLen, StunAddress4 &from, StunAddress4 &secondary, StunAddress4 &myAddr, StunAddress4 &altAddr, StunMessage *resp, StunAddress4 *destination, StunAtrString *hmacPassword, bool *changePort, bool *changeIp, bool verbose)
Definition Stun.cxx:1368
static bool stunParseAtrString(char *body, unsigned int hdrLen, StunAtrString &result)
Definition Stun.cxx:173
static bool stunParseAtrError(char *body, unsigned int hdrLen, StunAtrError &result)
Definition Stun.cxx:126
static void stunCreateErrorResponse(StunMessage &response, int cl, int number, const char *msg)
Definition Stun.cxx:1328
unsigned short uint16_t
Definition Stun.hxx:30
static const uint16_t Software
Definition Stun.hxx:81
static char * encode16(char *buf, uint16_t data)
Definition Stun.cxx:628
const uint16_t BindResponseMsg
Definition Stun.hxx:100
static char * encodeAtrChangeRequest(char *ptr, const StunAtrChangeRequest &atr)
Definition Stun.cxx:685
static bool stunParseAtrAddress(char *body, unsigned int hdrLen, StunAtrAddress4 &result)
Definition Stun.cxx:59
static const uint16_t Realm
Definition Stun.hxx:74
const uint16_t TurnRemoteAddress
Definition Stun.hxx:92
static void stunCreateSharedSecretResponse(const StunMessage &request, const StunAddress4 &source, StunMessage &response)
Definition Stun.cxx:1351
const uint16_t TurnSetActiveDestinationErrorResponse
Definition Stun.hxx:116
NatType
Definition Stun.hxx:302
@ StunTypeIndependentFilter
Definition Stun.hxx:308
@ StunTypeFirewall
Definition Stun.hxx:318
@ StunTypeDependentMapping
Definition Stun.hxx:311
@ StunTypeOpen
Definition Stun.hxx:305
@ StunTypeUnknown
Definition Stun.hxx:303
@ StunTypePortDependedFilter
Definition Stun.hxx:310
@ StunTypeDependentFilter
Definition Stun.hxx:309
@ StunTypeBlocked
Definition Stun.hxx:306
@ StunTypeFailure
Definition Stun.hxx:304
static const uint16_t SourceAddress
Definition Stun.hxx:66
static const uint16_t XorMappedAddress_old
Definition Stun.hxx:78
int Socket
Definition Socket.hxx:94
const uint16_t TurnSetActiveDestinationResponse
Definition Stun.hxx:115
static const uint16_t ResponseAddress
Definition Stun.hxx:64
static const uint16_t Fingerprint
Definition Stun.hxx:83
int stunRand()
Definition Stun.cxx:908
const uint32_t ChangePortFlag
Definition Stun.hxx:56
int stunOpenSocket(StunAddress4 &dest, StunAddress4 *mapAddr, int port, StunAddress4 *srcAddr, bool verbose)
Definition Stun.cxx:2595
unsigned long long uint64_t
Definition Stun.hxx:39
static const uint16_t Nonce
Definition Stun.hxx:75
bool stunVerifyMessageIntegrity(const char *buf, unsigned int bufLen, const StunMessage &message, const StunAtrString &password)
Verify the MESSAGE-INTEGRITY attribute of a parsed message against the supplied short-term credential...
Definition Stun.cxx:1003
const uint16_t TurnAllocateRequest
Definition Stun.hxx:107
unsigned int uint32_t
Definition Stun.hxx:34
void stunBuildReqSimple(StunMessage *msg, const StunAtrString &username, bool changePort, bool changeIp, unsigned int id)
Definition Stun.cxx:2029
bool operator<(const Data &lhs, const Data &rhs)
Definition Data.cxx:778
const uint16_t TurnSendRequest
Definition Stun.hxx:110
bool stunParseHostName(char *peerName, uint32_t &ip, uint16_t &portVal, uint16_t defaultPort)
Definition Stun.cxx:1228
int closeSocket(Socket fd)
Definition Socket.cxx:134
const uint32_t ChangeIpFlag
Definition Stun.hxx:55
static const uint16_t ErrorCode
Definition Stun.hxx:71
static const uint16_t SecondaryAddress
Definition Stun.hxx:84
static const uint16_t MappedAddress
Definition Stun.hxx:63
static char * encodeAtrUInt32(char *ptr, uint16_t type, uint32_t value)
Definition Stun.cxx:663
const uint16_t BindErrorResponseMsg
Definition Stun.hxx:101
void stunStopServer(StunServerInfo &info)
Definition Stun.cxx:1661
const uint16_t TurnAllocateErrorResponse
Definition Stun.hxx:109
static char * encodeMagicCookie(char *ptr, const uint32_t &cookie)
Definition Stun.cxx:694
const uint16_t SharedSecretResponseMsg
Definition Stun.hxx:103
static const uint16_t XorOnly
Definition Stun.hxx:77
static const uint16_t ReflectedFrom
Definition Stun.hxx:73
int getErrno()
Definition Socket.hxx:97
void stunGetUserNameAndPassword(const StunAddress4 &dest, StunAtrString *username, StunAtrString *password)
Definition Stun.cxx:2121
bool stunParseMessage(char *buf, unsigned int bufLen, StunMessage &msg, bool verbose)
Definition Stun.cxx:233
std::string strError(int err)
Definition compat.hxx:274
static char * encode32(char *buf, uint32_t data)
Definition Stun.cxx:636
static const uint16_t Password
Definition Stun.hxx:69
static char * encode(char *buf, const char *data, unsigned int length)
Definition Stun.cxx:645
const uint16_t TurnAlternateServer
Definition Stun.hxx:88
static const uint16_t MessageIntegrity
Definition Stun.hxx:70
static const uint16_t UnknownAttribute
Definition Stun.hxx:72
bool stunServerProcess(StunServerInfo &info, bool verbose)
return true if all is OK
Definition Stun.cxx:1683
const uint16_t BindRequestMsg
Definition Stun.hxx:99
bool makeSocketNonBlocking(Socket fd)
Definition Socket.cxx:21
uint64_t stunGetSystemTimeSecs()
Definition Stun.cxx:1125
int stunRandomPort()
return a random number to use as a port
Definition Stun.cxx:920
const uint16_t TurnAllocateResponse
Definition Stun.hxx:108
const uint16_t TurnBandwidth
Definition Stun.hxx:90
const uint16_t SharedSecretRequestMsg
Definition Stun.hxx:102
static bool stunParseAtrUInt32(char *body, unsigned int hdrLen, uint32_t &result)
Definition Stun.cxx:199
EncodeStream & operator<<(EncodeStream &strm, const BaseException &e)
static char * encodeXorOnly(char *ptr)
Definition Stun.cxx:730
bool stunTest(StunAddress4 &dest, int testNum, bool verbose, StunAddress4 *sAddr, unsigned long timeoutMs)
Definition Stun.cxx:2133
const uint8_t IPv6Family
Definition Stun.hxx:52
bool operator==(const char *lhs, const Data &rhs)
Definition Data.hxx:1197
static char * encodeAtrIntegrity(char *ptr, const StunAtrIntegrity &atr)
Definition Stun.cxx:750
static const uint16_t ChangeRequest
Definition Stun.hxx:65
bool stunOpenSocketPair(StunAddress4 &dest, StunAddress4 *mapAddr, int *fd1, int *fd2, int port, StunAddress4 *srcAddr, bool verbose)
Definition Stun.cxx:2660
static bool stunParseUInt32(char *body, unsigned int hdrLen, uint32_t &result)
Definition Stun.cxx:92
unsigned int stunEncodeMessage(const StunMessage &msg, char *buf, unsigned int bufLen, const StunAtrString &password, bool verbose)
Definition Stun.cxx:760
const uint16_t TurnDataIndication
Definition Stun.hxx:113
unsigned __int64 uint64_t
Definition stdint.h:95
StunAddress4 ipv4
Definition Stun.hxx:147
uint8_t errorClass
Definition Stun.hxx:158
char reason[STUN_MAX_STRING]
Definition Stun.hxx:160
uint16_t sizeReason
Definition Stun.hxx:161
uint16_t length
Definition Stun.hxx:134
uint16_t type
Definition Stun.hxx:133
uint16_t sizeValue
Definition Stun.hxx:173
char value[STUN_MAX_STRING]
Definition Stun.hxx:172
uint16_t attrType[STUN_MAX_UNKNOWN_ATTRIBUTES]
Definition Stun.hxx:166
uint16_t numAttributes
Definition Stun.hxx:167
StunAddress4 destination
Definition Stun.hxx:330
bool hasChangedAddress
Definition Stun.hxx:223
bool hasUnknownAttributes
Definition Stun.hxx:242
StunAtrString software
Definition Stun.hxx:260
uint32_t turnLifetime
Definition Stun.hxx:272
bool hasResponseAddress
Definition Stun.hxx:214
bool hasMessageIntegrity
Definition Stun.hxx:232
StunAtrAddress4 reflectedFrom
Definition Stun.hxx:246
StunAtrAddress4 secondaryAddress
Definition Stun.hxx:263
StunAtrString password
Definition Stun.hxx:230
bool hasTurnAlternateServer
Definition Stun.hxx:274
StunAtrAddress4 turnRemoteAddress
Definition Stun.hxx:287
unsigned int messageIntegrityOffset
Definition Stun.hxx:237
StunAtrAddress4 changedAddress
Definition Stun.hxx:224
bool hasTurnBandwidth
Definition Stun.hxx:280
bool hasChangeRequest
Definition Stun.hxx:217
StunAtrError errorCode
Definition Stun.hxx:240
resip::Data * nonce
Definition Stun.hxx:252
bool hasTurnMagicCookie
Definition Stun.hxx:277
uint32_t turnMagicCookie
Definition Stun.hxx:278
StunAtrChangeRequest changeRequest
Definition Stun.hxx:218
StunAtrString username
Definition Stun.hxx:227
StunAtrAddress4 sourceAddress
Definition Stun.hxx:221
StunAtrAddress4 alternateServer
Definition Stun.hxx:266
StunAtrAddress4 turnDestinationAddress
Definition Stun.hxx:284
bool hasMappedAddress
Definition Stun.hxx:211
bool hasReflectedFrom
Definition Stun.hxx:245
StunAtrUnknown unknownAttributes
Definition Stun.hxx:243
bool hasXorMappedAddress
Definition Stun.hxx:254
bool hasSecondaryAddress
Definition Stun.hxx:262
StunAtrAddress4 xorMappedAddress
Definition Stun.hxx:255
bool hasSourceAddress
Definition Stun.hxx:220
bool hasTurnDestinationAddress
Definition Stun.hxx:283
bool hasAlternateServer
Definition Stun.hxx:265
StunAtrAddress4 turnAlternateServer
Definition Stun.hxx:275
resip::Data * realm
Definition Stun.hxx:249
uint32_t fingerprint
Definition Stun.hxx:269
StunMsgHdr msgHdr
Definition Stun.hxx:209
resip::Data * turnData
Definition Stun.hxx:290
bool hasTurnRemoteAddress
Definition Stun.hxx:286
StunAtrAddress4 mappedAddress
Definition Stun.hxx:212
StunAtrAddress4 responseAddress
Definition Stun.hxx:215
uint32_t turnBandwidth
Definition Stun.hxx:281
StunAtrIntegrity messageIntegrity
Definition Stun.hxx:233
uint16_t msgType
Definition Stun.hxx:122
uint16_t msgLength
Definition Stun.hxx:123
resip::Socket altIpPortFd
Definition Stun.hxx:341
resip::Socket altIpFd
Definition Stun.hxx:340
resip::Socket altPortFd
Definition Stun.hxx:339
StunAddress4 myAddr
Definition Stun.hxx:336
StunAddress4 altAddr
Definition Stun.hxx:337
resip::Socket myFd
Definition Stun.hxx:338
StunMediaRelay relays[MAX_MEDIA_RELAYS]
Definition Stun.hxx:343
unsigned char octet[16]
Definition Stun.hxx:43