ml / util / stun.c @ 6575ae37
History | View | Annotate | Download (26 KB)
1 |
/*
|
---|---|
2 |
* Policy Management
|
3 |
*
|
4 |
* NEC Europe Ltd. PROPRIETARY INFORMATION
|
5 |
*
|
6 |
* This software is supplied under the terms of a license agreement
|
7 |
* or nondisclosure agreement with NEC Europe Ltd. and may not be
|
8 |
* copied or disclosed except in accordance with the terms of that
|
9 |
* agreement.
|
10 |
*
|
11 |
* Copyright (c) 2009 NEC Europe Ltd. All Rights Reserved.
|
12 |
*
|
13 |
* Authors: Kristian Beckers <beckers@nw.neclab.eu>
|
14 |
* Sebastian Kiesel <kiesel@nw.neclab.eu>
|
15 |
*
|
16 |
*
|
17 |
* NEC Europe Ltd. DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED,
|
18 |
* INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY
|
19 |
* AND FITNESS FOR A PARTICULAR PURPOSE AND THE WARRANTY AGAINST LATENT
|
20 |
* DEFECTS, WITH RESPECT TO THE PROGRAM AND THE ACCOMPANYING
|
21 |
* DOCUMENTATION.
|
22 |
*
|
23 |
* No Liability For Consequential Damages IN NO EVENT SHALL NEC Europe
|
24 |
* Ltd., NEC Corporation OR ANY OF ITS SUBSIDIARIES BE LIABLE FOR ANY
|
25 |
* DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS
|
26 |
* OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR
|
27 |
* OTHER PECUNIARY LOSS AND INDIRECT, CONSEQUENTIAL, INCIDENTAL,
|
28 |
* ECONOMIC OR PUNITIVE DAMAGES) ARISING OUT OF THE USE OF OR INABILITY
|
29 |
* TO USE THIS PROGRAM, EVEN IF NEC Europe Ltd. HAS BEEN ADVISED OF THE
|
30 |
* POSSIBILITY OF SUCH DAMAGES.
|
31 |
*
|
32 |
* THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
|
33 |
*/
|
34 |
|
35 |
#include <assert.h> |
36 |
#include <stdlib.h> |
37 |
#include <unistd.h> |
38 |
#include <errno.h> |
39 |
#include <string.h> |
40 |
|
41 |
#include <stdio.h> |
42 |
#include <unistd.h> |
43 |
|
44 |
#include <sys/time.h> |
45 |
#include <sys/types.h> |
46 |
|
47 |
#include <fcntl.h> |
48 |
|
49 |
#ifndef WIN32
|
50 |
#include <sys/ioctl.h> |
51 |
#include <sys/socket.h> |
52 |
#include <netdb.h> |
53 |
#include <netinet/in.h> |
54 |
//#include <arpa/nameser.h>
|
55 |
//#include <resolv.h>
|
56 |
#include <net/if.h> |
57 |
#include <arpa/inet.h> |
58 |
|
59 |
#else
|
60 |
|
61 |
#include <winsock2.h> |
62 |
#include <ws2tcpip.h> |
63 |
|
64 |
#endif
|
65 |
|
66 |
#include "ml_log.h" |
67 |
#include "stun.h" |
68 |
#include "udpSocket.h" |
69 |
|
70 |
#define STUN_VERBOSE false |
71 |
|
72 |
/// define a structure to hold a stun address
|
73 |
const UInt8 IPv4Family = 0x01; |
74 |
const UInt8 IPv6Family = 0x02; |
75 |
// define flags
|
76 |
const UInt32 ChangeIpFlag = 0x04; |
77 |
const UInt32 ChangePortFlag = 0x02; |
78 |
// define stun attributes
|
79 |
const UInt16 MappedAddress = 0x0001; |
80 |
const UInt16 ResponseAddress = 0x0002; |
81 |
const UInt16 ChangeRequest = 0x0003; |
82 |
const UInt16 SourceAddress = 0x0004; |
83 |
const UInt16 ChangedAddress = 0x0005; |
84 |
const UInt16 Username = 0x0006; |
85 |
const UInt16 Password = 0x0007; |
86 |
const UInt16 MessageIntegrity = 0x0008; |
87 |
const UInt16 ErrorCode = 0x0009; |
88 |
const UInt16 UnknownAttribute = 0x000A; |
89 |
const UInt16 ReflectedFrom = 0x000B; |
90 |
const UInt16 XorMappedAddress = 0x8020; |
91 |
const UInt16 XorOnly = 0x0021; |
92 |
const UInt16 ServerName = 0x8022; |
93 |
const UInt16 SecondaryAddress = 0x8050; // Non standard extention |
94 |
// define types for a stun message
|
95 |
const UInt16 BindRequestMsg = 0x0001; |
96 |
const UInt16 BindResponseMsg = 0x0101; |
97 |
const UInt16 BindErrorResponseMsg = 0x0111; |
98 |
const UInt16 SharedSecretRequestMsg = 0x0002; |
99 |
const UInt16 SharedSecretResponseMsg = 0x0102; |
100 |
const UInt16 SharedSecretErrorResponseMsg = 0x0112; |
101 |
|
102 |
void pmtu_error_cb_stun(char *buf,int bufsize){ |
103 |
|
104 |
error("error: MTU size of stun message too big !");
|
105 |
|
106 |
} |
107 |
|
108 |
/* sends a request to a stun server */
|
109 |
int send_stun_request(const int udpSocket,struct sockaddr_in *stunServ) |
110 |
{ |
111 |
|
112 |
assert( sizeof(UInt8 ) == 1 ); |
113 |
assert( sizeof(UInt16) == 2 ); |
114 |
assert( sizeof(UInt32) == 4 ); |
115 |
|
116 |
bool verbose = STUN_VERBOSE;
|
117 |
|
118 |
//set the verbose mode
|
119 |
verbose = true;
|
120 |
|
121 |
StunMessage req; |
122 |
memset(&req, 0, sizeof(StunMessage)); |
123 |
|
124 |
StunAtrString username; |
125 |
StunAtrString password; |
126 |
username.sizeValue = 0;
|
127 |
password.sizeValue = 0;
|
128 |
|
129 |
/* build a stun request message */
|
130 |
/* creates a stun message struct with the given atributes */
|
131 |
stunBuildReqSimple( &req, username, |
132 |
false , false , |
133 |
0x0c );
|
134 |
|
135 |
/* buffer for the stun request */
|
136 |
char buf[STUN_MAX_MESSAGE_SIZE];
|
137 |
int len = STUN_MAX_MESSAGE_SIZE;
|
138 |
|
139 |
/* encode the stun message */
|
140 |
len = stunEncodeMessage( req, buf, len, password, verbose); |
141 |
|
142 |
struct iovec iov;
|
143 |
iov.iov_len = len; |
144 |
iov.iov_base = buf; |
145 |
debug("Sending STUN %d!!!!!\n",len);
|
146 |
sendPacket(udpSocket,&iov,1,stunServ);
|
147 |
|
148 |
return 0; |
149 |
|
150 |
} |
151 |
|
152 |
/* sends a keep alive to a server */
|
153 |
int send_stun_keep_alive(const int udpSocket,struct sockaddr_in *stunServ) |
154 |
{ |
155 |
|
156 |
send_stun_request(udpSocket,stunServ); |
157 |
|
158 |
return 0; |
159 |
} |
160 |
|
161 |
/* parses a given stun message and sets the refelxive address */
|
162 |
int recv_stun_message(char *msgbuf,int msgLen,StunMessage *response){ |
163 |
|
164 |
//StunMessage resp;
|
165 |
//memset(&resp, 0, sizeof(StunMessage));
|
166 |
int returnValue = 0; |
167 |
//bool verbose = true;
|
168 |
bool verbose = STUN_VERBOSE;
|
169 |
|
170 |
//debug("still alive 4 \n ");
|
171 |
//if ( verbose ) info("Got a response \n");
|
172 |
|
173 |
bool ok = stunParseMessage(msgbuf, msgLen, response, verbose );
|
174 |
|
175 |
if (!ok){
|
176 |
|
177 |
returnValue = 1;
|
178 |
error("parse STUN message failed \n");
|
179 |
|
180 |
} |
181 |
|
182 |
UInt32 ip_addr = response->mappedAddress.ipv4.addr; |
183 |
char mapped_addr[16]; |
184 |
int length;
|
185 |
length = sprintf(mapped_addr,"%d.%d.%d.%d",(ip_addr >> 24) & 0xff,(ip_addr >> 16) & 0xff,(ip_addr >> 8) & 0xff,ip_addr & 0xff); |
186 |
|
187 |
ip_addr = response->changedAddress.ipv4.addr; |
188 |
char changed_addr[16]; |
189 |
length = sprintf(changed_addr,"%d.%d.%d.%d",(ip_addr >> 24) & 0xff,(ip_addr >> 16)\ |
190 |
& 0xff,(ip_addr >> 8) & 0xff,ip_addr & 0xff); |
191 |
|
192 |
if ( verbose )
|
193 |
{ |
194 |
|
195 |
info( "\t mappedAddr= ipv4 %s port %d \n \t changedAddr= ipv4 %s port %d \n",
|
196 |
mapped_addr , |
197 |
response->mappedAddress.ipv4.port, |
198 |
changed_addr, |
199 |
response->changedAddress.ipv4.port); |
200 |
|
201 |
} |
202 |
|
203 |
//reflexiveAddr.sin_addr.s_addr = inet_addr(changed_addr);
|
204 |
//reflexiveAddr->sin_addr.s_addr = inet_addr("1.1.1.1");
|
205 |
//reflexiveAddr->sin_port = htons(resp.mappedAddress.ipv4.port);
|
206 |
|
207 |
return returnValue;
|
208 |
} |
209 |
|
210 |
bool
|
211 |
stunParseAtrAddress( char* body, unsigned int hdrLen, StunAtrAddress4 *result, bool verbose ) |
212 |
{ |
213 |
if ( hdrLen != 8 ) |
214 |
{ |
215 |
error("hdrlen is not 8 \n ");
|
216 |
return false; |
217 |
} |
218 |
result->pad = *body++; |
219 |
result->family = *body++; |
220 |
|
221 |
if (result->family == IPv4Family)
|
222 |
{ |
223 |
|
224 |
UInt16 nport; |
225 |
memcpy(&nport, body, 2); body+=2; |
226 |
|
227 |
if (verbose) info("port %u \n",ntohs(nport)); |
228 |
|
229 |
result->ipv4.port = ntohs(nport); |
230 |
|
231 |
|
232 |
UInt32 naddr; |
233 |
memcpy(&naddr, body, 4); body+=4; |
234 |
//debug("port %d \n",ntohl(naddr));
|
235 |
|
236 |
if (verbose)
|
237 |
{ |
238 |
UInt32 ip_addr = ntohl(naddr); |
239 |
char str_p[20]; |
240 |
|
241 |
sprintf(str_p,"%d.%d.%d.%d",(ip_addr >> 24) & 0xff,(ip_addr >> 16) & 0xff,(ip_addr >> 8) & 0xff,ip_addr & 0xff); |
242 |
|
243 |
info(" ipv4 as str %s \n ",str_p);
|
244 |
} |
245 |
|
246 |
result->ipv4.addr = ntohl(naddr); |
247 |
|
248 |
return true; |
249 |
} |
250 |
|
251 |
else if (result->family == IPv6Family) |
252 |
|
253 |
{ |
254 |
warn("ipv6 not supported \n");
|
255 |
} |
256 |
else
|
257 |
{ |
258 |
error("bad address family: %i \n ",result->family );
|
259 |
} |
260 |
|
261 |
return false; |
262 |
} |
263 |
|
264 |
|
265 |
|
266 |
bool
|
267 |
stunParseMessage( char* buf, unsigned int bufLen, StunMessage *msg, bool verbose) |
268 |
{ |
269 |
if (verbose) info("Received stun message: %d bytes \n",bufLen); |
270 |
memset(msg, 0, sizeof(msg)); |
271 |
|
272 |
if (sizeof(StunMsgHdr) > bufLen) |
273 |
{ |
274 |
error("Bad message \n");
|
275 |
return false; |
276 |
} |
277 |
|
278 |
memcpy(&msg->msgHdr, buf, sizeof(StunMsgHdr));
|
279 |
msg->msgHdr.msgType = ntohs(msg->msgHdr.msgType); |
280 |
msg->msgHdr.msgLength = ntohs(msg->msgHdr.msgLength); |
281 |
|
282 |
if (msg->msgHdr.msgLength + sizeof(StunMsgHdr) != bufLen) |
283 |
{ |
284 |
error("Message header length doesn't match message size: %d - %d \n"
|
285 |
,msg->msgHdr.msgLength,bufLen); |
286 |
return false; |
287 |
} |
288 |
|
289 |
char* body = buf + sizeof(StunMsgHdr); |
290 |
unsigned int size = msg->msgHdr.msgLength; |
291 |
|
292 |
// debug("bytes after header = %d\n",size);
|
293 |
|
294 |
while ( size > 0 ) |
295 |
{ |
296 |
// !jf! should check that there are enough bytes left in the buffer
|
297 |
|
298 |
StunAtrHdr* attr = (StunAtrHdr*)(body); |
299 |
|
300 |
unsigned int attrLen = ntohs(attr->length); |
301 |
int atrType = ntohs(attr->type);
|
302 |
|
303 |
//if (verbose) clog << "Found attribute type=" << AttrNames[atrType] << " length=" << attrLen << endl;
|
304 |
if ( attrLen+4 > size ) |
305 |
{ |
306 |
debug( "claims attribute is larger than size of message " \
|
307 |
"(attribute type= %d \n" ,atrType);
|
308 |
return false; |
309 |
} |
310 |
|
311 |
body += 4; // skip the length and type in attribute header |
312 |
size -= 4;
|
313 |
|
314 |
if( atrType == MappedAddress)
|
315 |
{ |
316 |
msg->hasMappedAddress = true;
|
317 |
//debug("has mapped address \n");
|
318 |
if ( stunParseAtrAddress(body, attrLen, &msg->mappedAddress, verbose) == false) |
319 |
{ |
320 |
debug("problem parsing MappedAddress \n");
|
321 |
return false; |
322 |
} |
323 |
else
|
324 |
{ |
325 |
if (verbose) {info("MappedAddress -------------------\n");} |
326 |
} |
327 |
|
328 |
}else
|
329 |
if (atrType == ResponseAddress)
|
330 |
{ |
331 |
msg->hasResponseAddress = true;
|
332 |
if ( stunParseAtrAddress( body, attrLen, &msg->responseAddress, verbose )== false ) |
333 |
{ |
334 |
debug("problem parsing ResponseAddress \n");
|
335 |
return false; |
336 |
} |
337 |
else
|
338 |
{ |
339 |
if (verbose) {info("ResponseAddress ---------------------\n");} |
340 |
} |
341 |
|
342 |
}else if(atrType == ChangeRequest) |
343 |
{ |
344 |
msg->hasChangeRequest = true;
|
345 |
if (stunParseAtrChangeRequest( body, attrLen, &msg->changeRequest) == false) |
346 |
{ |
347 |
debug("problem parsing ChangeRequest \n");
|
348 |
return false; |
349 |
} |
350 |
else
|
351 |
{ |
352 |
if (verbose) info("ChangeRequest = %ud \n", msg->changeRequest.value); |
353 |
} |
354 |
|
355 |
} else if (atrType == SourceAddress) |
356 |
{ |
357 |
msg->hasSourceAddress = true;
|
358 |
if ( stunParseAtrAddress( body, attrLen, &msg->sourceAddress, verbose )== false ) |
359 |
{ |
360 |
debug("problem parsing SourceAddress \n");
|
361 |
return false; |
362 |
} |
363 |
else
|
364 |
{ |
365 |
if (verbose) info("SourceAddress ------------------\n"); |
366 |
} |
367 |
} else if (atrType == ChangedAddress) |
368 |
{ |
369 |
msg->hasChangedAddress = true;
|
370 |
if ( stunParseAtrAddress( body, attrLen, &msg->changedAddress, verbose )== false ) |
371 |
{ |
372 |
debug("problem parsing ChangedAddress \n");
|
373 |
return false; |
374 |
} |
375 |
else
|
376 |
{ |
377 |
if (verbose) info("ChangedAddress = ---------------------\n"); |
378 |
} |
379 |
} else if (atrType == Username) |
380 |
{ |
381 |
msg->hasUsername = true;
|
382 |
if (stunParseAtrString( body, attrLen, &msg->username) == false) |
383 |
{ |
384 |
debug("problem parsing Username \n");
|
385 |
return false; |
386 |
} |
387 |
else
|
388 |
{ |
389 |
if (verbose) info("Username = %s \n",msg->username.value); |
390 |
} |
391 |
}else if (atrType == Password) |
392 |
{ |
393 |
msg->hasPassword = true;
|
394 |
if (stunParseAtrString( body, attrLen, &msg->password) == false) |
395 |
{ |
396 |
debug("problem parsing Password \n");
|
397 |
return false; |
398 |
} |
399 |
else
|
400 |
{ |
401 |
if (verbose) info("Password = %s \n",(char *)&msg->password.value); |
402 |
} |
403 |
}else if (atrType == MessageIntegrity) |
404 |
{ |
405 |
msg->hasMessageIntegrity = true;
|
406 |
if (stunParseAtrIntegrity( body, attrLen,&msg->messageIntegrity) == false) |
407 |
{ |
408 |
debug("problem parsing MessageIntegrity \n");
|
409 |
return false; |
410 |
} |
411 |
else
|
412 |
{ |
413 |
//if (verbose) clog << "MessageIntegrity = " << msg.messageIntegrity.hash << endl;
|
414 |
} |
415 |
|
416 |
// read the current HMAC
|
417 |
// look up the password given the user of given the transaction id
|
418 |
// compute the HMAC on the buffer
|
419 |
// decide if they match or not
|
420 |
|
421 |
} else if (atrType == ErrorCode) |
422 |
{ |
423 |
msg->hasErrorCode = true;
|
424 |
if (stunParseAtrError(body, attrLen, &msg->errorCode) == false) |
425 |
{ |
426 |
debug("problem parsing ErrorCode \n");
|
427 |
return false; |
428 |
} |
429 |
else
|
430 |
{ |
431 |
if (verbose) info("ErrorCode = %d %d %s \n",(int)(msg->errorCode.errorClass) ,(int)(msg->errorCode.number) |
432 |
,msg->errorCode.reason); |
433 |
} |
434 |
|
435 |
} else if (atrType == UnknownAttribute) |
436 |
{ |
437 |
msg->hasUnknownAttributes = true;
|
438 |
if (stunParseAtrUnknown(body, attrLen,&msg->unknownAttributes) == false) |
439 |
{ |
440 |
debug("problem parsing UnknownAttribute \n");
|
441 |
return false; |
442 |
} |
443 |
} else if (atrType == ReflectedFrom) |
444 |
{ |
445 |
msg->hasReflectedFrom = true;
|
446 |
if ( stunParseAtrAddress( body, attrLen, &msg->reflectedFrom, verbose ) == false ) |
447 |
{ |
448 |
debug("problem parsing ReflectedFrom \n");
|
449 |
return false; |
450 |
} |
451 |
} else if (atrType == XorMappedAddress) |
452 |
{ |
453 |
msg->hasXorMappedAddress = true;
|
454 |
if ( stunParseAtrAddress( body, attrLen, &msg->xorMappedAddress, verbose ) == false ) |
455 |
{ |
456 |
debug("problem parsing XorMappedAddress \n");
|
457 |
return false; |
458 |
} |
459 |
else
|
460 |
{ |
461 |
if (verbose) info("XorMappedAddress ------------------- \n"); |
462 |
} |
463 |
} else if (atrType == XorOnly) |
464 |
{ |
465 |
msg->xorOnly = true;
|
466 |
if (verbose)
|
467 |
{ |
468 |
debug("xorOnly = true \n");
|
469 |
} |
470 |
} else if (atrType == ServerName) |
471 |
{ |
472 |
msg->hasServerName = true;
|
473 |
if (stunParseAtrString( body, attrLen, &msg->serverName) == false) |
474 |
{ |
475 |
debug("problem parsing ServerName \n");
|
476 |
return false; |
477 |
} |
478 |
else
|
479 |
{ |
480 |
if (verbose) info("ServerName = %s \n",(char *)&msg->serverName.value); |
481 |
} |
482 |
} else if (atrType == SecondaryAddress) |
483 |
{ |
484 |
msg->hasSecondaryAddress = true;
|
485 |
if ( stunParseAtrAddress( body, attrLen, &msg->secondaryAddress, verbose ) == false ) |
486 |
{ |
487 |
debug("problem parsing secondaryAddress \n");
|
488 |
return false; |
489 |
} |
490 |
else
|
491 |
{ |
492 |
if (verbose) info("SecondaryAddress ---------------- \n"); |
493 |
} |
494 |
} else
|
495 |
{ |
496 |
|
497 |
if (verbose) info("Unknown attribute: %i \n",atrType); |
498 |
if ( atrType <= 0x7FFF ) |
499 |
{ |
500 |
return false; |
501 |
} |
502 |
} |
503 |
|
504 |
|
505 |
body += attrLen; |
506 |
size -= attrLen; |
507 |
} |
508 |
|
509 |
return true; |
510 |
} |
511 |
|
512 |
|
513 |
void
|
514 |
stunBuildReqSimple(StunMessage* msg, |
515 |
const StunAtrString username,
|
516 |
bool changePort, bool changeIp, unsigned int id ) |
517 |
{ |
518 |
assert( msg ); |
519 |
memset( msg , 0 , sizeof(*msg) ); |
520 |
|
521 |
msg->msgHdr.msgType = BindRequestMsg; |
522 |
|
523 |
int i;
|
524 |
for (i=0; i<16; i=i+4 ) |
525 |
{ |
526 |
assert(i+3<16); |
527 |
int r = stunRand();
|
528 |
msg->msgHdr.id.octet[i+0]= r>>0; |
529 |
msg->msgHdr.id.octet[i+1]= r>>8; |
530 |
msg->msgHdr.id.octet[i+2]= r>>16; |
531 |
msg->msgHdr.id.octet[i+3]= r>>24; |
532 |
} |
533 |
|
534 |
if ( id != 0 ) |
535 |
{ |
536 |
msg->msgHdr.id.octet[0] = id;
|
537 |
} |
538 |
|
539 |
msg->hasChangeRequest = true;
|
540 |
msg->changeRequest.value =(changeIp?ChangeIpFlag:0) |
|
541 |
(changePort?ChangePortFlag:0);
|
542 |
|
543 |
if ( username.sizeValue > 0 ) |
544 |
{ |
545 |
msg->hasUsername = true;
|
546 |
msg->username = username; |
547 |
} |
548 |
} |
549 |
|
550 |
|
551 |
unsigned int |
552 |
stunEncodeMessage( const StunMessage msg,
|
553 |
char* buf,
|
554 |
unsigned int bufLen, |
555 |
const StunAtrString password,
|
556 |
bool verbose)
|
557 |
{ |
558 |
assert(bufLen >= sizeof(StunMsgHdr));
|
559 |
char* ptr = buf;
|
560 |
|
561 |
ptr = encode16(ptr, msg.msgHdr.msgType); |
562 |
char* lengthp = ptr;
|
563 |
ptr = encode16(ptr, 0);
|
564 |
ptr = encode(ptr, (const char*)(msg.msgHdr.id.octet), sizeof(msg.msgHdr.id)); |
565 |
|
566 |
if (verbose) debug("Encoding stun message: "); |
567 |
|
568 |
if (msg.hasMappedAddress)
|
569 |
{ |
570 |
//if (verbose) info("Encoding MappedAddress: %s \n",msg.mappedAddress.ipv4);
|
571 |
ptr = encodeAtrAddress4 (ptr, MappedAddress, msg.mappedAddress); |
572 |
} |
573 |
if (msg.hasResponseAddress)
|
574 |
{ |
575 |
//if (verbose) info("Encoding ResponseAddress: %s \n",msg.responseAddress.ipv4);
|
576 |
ptr = encodeAtrAddress4(ptr, ResponseAddress, msg.responseAddress); |
577 |
} |
578 |
if (msg.hasChangeRequest)
|
579 |
{ |
580 |
//if (verbose) info("Encoding ChangeRequest: %s \n",msg.changeRequest.value);
|
581 |
ptr = encodeAtrChangeRequest(ptr, msg.changeRequest); |
582 |
} |
583 |
if (msg.hasSourceAddress)
|
584 |
{ |
585 |
//if (verbose) info("Encoding SourceAddress: %s \n ",msg.sourceAddress.ipv4);
|
586 |
ptr = encodeAtrAddress4(ptr, SourceAddress, msg.sourceAddress); |
587 |
} |
588 |
if (msg.hasChangedAddress)
|
589 |
{ |
590 |
//if (verbose) info("Encoding ChangedAddress: %s \n ",msg.changedAddress.ipv4);
|
591 |
ptr = encodeAtrAddress4(ptr, ChangedAddress, msg.changedAddress); |
592 |
} |
593 |
if (msg.hasUsername)
|
594 |
{ |
595 |
if (verbose) info("Encoding Username: %s \n", msg.username.value); |
596 |
ptr = encodeAtrString(ptr, Username, msg.username); |
597 |
} |
598 |
if (msg.hasPassword)
|
599 |
{ |
600 |
if (verbose) info("Encoding Password: %s \n ",msg.password.value); |
601 |
ptr = encodeAtrString(ptr, Password, msg.password); |
602 |
} |
603 |
if (msg.hasErrorCode)
|
604 |
{ |
605 |
if (verbose) info("Encoding ErrorCode: class= %d number= %d reason= %s \n" |
606 |
,(int)msg.errorCode.errorClass
|
607 |
,(int)msg.errorCode.number
|
608 |
,msg.errorCode.reason |
609 |
); |
610 |
|
611 |
ptr = encodeAtrError(ptr, msg.errorCode); |
612 |
} |
613 |
if (msg.hasUnknownAttributes)
|
614 |
{ |
615 |
if (verbose) info("Encoding UnknownAttribute: ??? \n"); |
616 |
ptr = encodeAtrUnknown(ptr, msg.unknownAttributes); |
617 |
} |
618 |
if (msg.hasReflectedFrom)
|
619 |
{ |
620 |
//if (verbose) info("Encoding ReflectedFrom: %s \n ",msg.reflectedFrom.ipv4);
|
621 |
ptr = encodeAtrAddress4(ptr, ReflectedFrom, msg.reflectedFrom); |
622 |
} |
623 |
if (msg.hasXorMappedAddress)
|
624 |
{ |
625 |
//if (verbose) info("Encoding XorMappedAddress: %s \n ",msg.xorMappedAddress.ipv4 );
|
626 |
ptr = encodeAtrAddress4 (ptr, XorMappedAddress, msg.xorMappedAddress); |
627 |
} |
628 |
if (msg.xorOnly)
|
629 |
{ |
630 |
if (verbose) info("Encoding xorOnly: \n"); |
631 |
ptr = encodeXorOnly( ptr ); |
632 |
} |
633 |
if (msg.hasServerName)
|
634 |
{ |
635 |
if (verbose) info("Encoding ServerName: %s \n ",msg.serverName.value); |
636 |
ptr = encodeAtrString(ptr, ServerName, msg.serverName); |
637 |
} |
638 |
if (msg.hasSecondaryAddress)
|
639 |
{ |
640 |
//if (verbose) info("Encoding SecondaryAddress: %s \n", msg.secondaryAddress.ipv4);
|
641 |
ptr = encodeAtrAddress4 (ptr, SecondaryAddress, msg.secondaryAddress); |
642 |
} |
643 |
|
644 |
if (password.sizeValue > 0) |
645 |
{ |
646 |
if (verbose) info("HMAC with password: %s \n ",password.value); |
647 |
|
648 |
StunAtrIntegrity integrity; |
649 |
//computeHmac(integrity.hash, buf, (int)(ptr-buf) , password.value, password.sizeValue);
|
650 |
ptr = encodeAtrIntegrity(ptr, integrity); |
651 |
} |
652 |
|
653 |
encode16(lengthp, (UInt16)(ptr - buf - sizeof(StunMsgHdr)));
|
654 |
return (int)(ptr - buf); |
655 |
} |
656 |
|
657 |
|
658 |
int
|
659 |
stunRand() |
660 |
{ |
661 |
// return 32 bits of random stuff
|
662 |
assert( sizeof(int) == 4 ); |
663 |
static bool init=false; |
664 |
if ( !init )
|
665 |
{ |
666 |
init = true;
|
667 |
|
668 |
UInt64 tick; |
669 |
|
670 |
#if defined(__GNUC__) && ( defined(__i686__) || defined(__i386__) || defined(__amd64__) )
|
671 |
asm("rdtsc" : "=A" (tick)); |
672 |
#elif defined (__SUNPRO_CC) || defined( __sparc__ )
|
673 |
tick = gethrtime(); |
674 |
#elif defined(__MACH__)
|
675 |
int fd=open("/dev/random",O_RDONLY); |
676 |
read(fd,&tick,sizeof(tick));
|
677 |
closesocket(fd); |
678 |
#else
|
679 |
# error Need some way to seed the random number generator
|
680 |
#endif
|
681 |
int seed = (int)(tick); |
682 |
#ifdef WIN32
|
683 |
srand(seed); |
684 |
#else
|
685 |
srandom(seed); |
686 |
#endif
|
687 |
} |
688 |
|
689 |
|
690 |
return random();
|
691 |
|
692 |
} |
693 |
|
694 |
|
695 |
UInt64 |
696 |
stunGetSystemTimeSecs() |
697 |
{ |
698 |
UInt64 time=0;
|
699 |
#if defined(WIN32)
|
700 |
SYSTEMTIME t; |
701 |
// CJ TODO - this probably has bug on wrap around every 24 hours
|
702 |
GetSystemTime( &t ); |
703 |
time = (t.wHour*60+t.wMinute)*60+t.wSecond; |
704 |
#else
|
705 |
struct timeval now;
|
706 |
gettimeofday( &now , NULL );
|
707 |
//assert( now );
|
708 |
time = now.tv_sec; |
709 |
#endif
|
710 |
return time;
|
711 |
} |
712 |
|
713 |
|
714 |
bool
|
715 |
stunParseServerName( char* name, StunAddress4 addr)
|
716 |
{ |
717 |
assert(name); |
718 |
|
719 |
// TODO - put in DNS SRV stuff.
|
720 |
|
721 |
bool ret = stunParseHostName( name, addr.addr, addr.port, 3478); |
722 |
if ( ret != true ) |
723 |
{ |
724 |
addr.port=0xFFFF;
|
725 |
} |
726 |
return ret;
|
727 |
} |
728 |
|
729 |
|
730 |
// returns true if it scucceeded
|
731 |
bool
|
732 |
stunParseHostName( char* peerName,
|
733 |
UInt32 ip, |
734 |
UInt16 portVal, |
735 |
UInt16 defaultPort ) |
736 |
{ |
737 |
struct in_addr sin_addr;
|
738 |
|
739 |
char host[512]; |
740 |
strncpy(host,peerName,512);
|
741 |
host[512-1]='\0'; |
742 |
char* port = NULL; |
743 |
|
744 |
int portNum = defaultPort;
|
745 |
|
746 |
// pull out the port part if present.
|
747 |
char* sep = strchr(host,':'); |
748 |
|
749 |
if ( sep == NULL ) |
750 |
{ |
751 |
portNum = defaultPort; |
752 |
} |
753 |
else
|
754 |
{ |
755 |
*sep = '\0';
|
756 |
port = sep + 1;
|
757 |
// set port part
|
758 |
|
759 |
char* endPtr=NULL; |
760 |
|
761 |
portNum = strtol(port,&endPtr,10);
|
762 |
|
763 |
if ( endPtr != NULL ) |
764 |
{ |
765 |
if ( *endPtr != '\0' ) |
766 |
{ |
767 |
portNum = defaultPort; |
768 |
} |
769 |
} |
770 |
} |
771 |
|
772 |
if ( portNum < 1024 ) return false; |
773 |
if ( portNum >= 0xFFFF ) return false; |
774 |
|
775 |
// figure out the host part
|
776 |
struct hostent* h;
|
777 |
|
778 |
h = gethostbyname( host ); |
779 |
if ( h == NULL ) |
780 |
{ |
781 |
//int err = getErrno();
|
782 |
error("error was %d \n",errno);
|
783 |
ip = ntohl( 0x7F000001L );
|
784 |
return false; |
785 |
} |
786 |
else
|
787 |
{ |
788 |
sin_addr = *(struct in_addr*)h->h_addr;
|
789 |
ip = ntohl( sin_addr.s_addr ); |
790 |
} |
791 |
|
792 |
|
793 |
portVal = portNum; |
794 |
|
795 |
return true; |
796 |
} |
797 |
|
798 |
|
799 |
|
800 |
bool
|
801 |
stunParseAtrChangeRequest( char* body, unsigned int hdrLen, StunAtrChangeRequest *result ) |
802 |
{ |
803 |
if ( hdrLen != 4 ) |
804 |
{ |
805 |
error("hdr length = %u expecting %u \n ",hdrLen,sizeof(result)); |
806 |
|
807 |
error("Incorrect size for ChangeRequest \n ");
|
808 |
|
809 |
return false; |
810 |
} |
811 |
else
|
812 |
{ |
813 |
memcpy(&result->value, body, 4);
|
814 |
result->value = ntohl(result->value); |
815 |
return true; |
816 |
} |
817 |
} |
818 |
|
819 |
|
820 |
|
821 |
|
822 |
bool
|
823 |
stunParseAtrUnknown( char* body, unsigned int hdrLen, StunAtrUnknown *result) |
824 |
{ |
825 |
if ( hdrLen >= sizeof(StunAtrUnknown) ) |
826 |
{ |
827 |
return false; |
828 |
} |
829 |
else
|
830 |
{ |
831 |
if (hdrLen % 4 != 0) return false; |
832 |
result->numAttributes = hdrLen / 4;
|
833 |
int i;
|
834 |
for (i=0; i<result->numAttributes; i++) |
835 |
{ |
836 |
memcpy(&result->attrType[i], body, 2); body+=2; |
837 |
result->attrType[i] = ntohs(result->attrType[i]); |
838 |
} |
839 |
return true; |
840 |
} |
841 |
} |
842 |
|
843 |
|
844 |
|
845 |
bool
|
846 |
stunParseAtrString( char* body, unsigned int hdrLen, StunAtrString *result ) |
847 |
{ |
848 |
if ( hdrLen >= STUN_MAX_STRING )
|
849 |
{ |
850 |
debug( "String is too large \n");
|
851 |
return false; |
852 |
} |
853 |
else
|
854 |
{ |
855 |
if (hdrLen % 4 != 0) |
856 |
{ |
857 |
debug("Bad length string %d \n ",hdrLen);
|
858 |
return false; |
859 |
} |
860 |
|
861 |
result->sizeValue = hdrLen; |
862 |
memcpy(&result->value, body, hdrLen); |
863 |
result->value[hdrLen] = 0;
|
864 |
return true; |
865 |
} |
866 |
} |
867 |
|
868 |
|
869 |
bool
|
870 |
stunParseAtrIntegrity( char* body, unsigned int hdrLen,StunAtrIntegrity *result ) |
871 |
{ |
872 |
if ( hdrLen != 20) |
873 |
{ |
874 |
debug("MessageIntegrity must be 20 bytes \n");
|
875 |
return false; |
876 |
} |
877 |
else
|
878 |
{ |
879 |
memcpy(&result->hash, body, hdrLen); |
880 |
return true; |
881 |
} |
882 |
} |
883 |
|
884 |
|
885 |
void
|
886 |
stunCreateErrorResponse(StunMessage response, int cl, int number, const char* msg) |
887 |
{ |
888 |
response.msgHdr.msgType = BindErrorResponseMsg; |
889 |
response.hasErrorCode = true;
|
890 |
response.errorCode.errorClass = cl; |
891 |
response.errorCode.number = number; |
892 |
strcpy(response.errorCode.reason, msg); |
893 |
} |
894 |
|
895 |
bool
|
896 |
stunParseAtrError(char* body,unsigned int hdrLen,StunAtrError *result) |
897 |
{ |
898 |
if ( hdrLen >= sizeof(StunAtrError) ) |
899 |
{ |
900 |
debug("head on Error too large \n ");
|
901 |
return false; |
902 |
} |
903 |
else
|
904 |
{ |
905 |
memcpy(&result->pad, body, 2); body+=2; |
906 |
result->pad = ntohs(result->pad); |
907 |
result->errorClass = *body++; |
908 |
result->number = *body++; |
909 |
|
910 |
result->sizeReason = hdrLen - 4;
|
911 |
memcpy(&result->reason, body, result->sizeReason); |
912 |
result->reason[result->sizeReason] = 0;
|
913 |
return true; |
914 |
} |
915 |
} |
916 |
|
917 |
|
918 |
char*
|
919 |
encodeAtrString(char* ptr, UInt16 type, const StunAtrString atr) |
920 |
{ |
921 |
assert(atr.sizeValue % 4 == 0); |
922 |
|
923 |
ptr = encode16(ptr, type); |
924 |
ptr = encode16(ptr, atr.sizeValue); |
925 |
ptr = encode(ptr, atr.value, atr.sizeValue); |
926 |
return ptr;
|
927 |
} |
928 |
|
929 |
|
930 |
char*
|
931 |
encodeAtrIntegrity(char* ptr, const StunAtrIntegrity atr) |
932 |
{ |
933 |
ptr = encode16(ptr, MessageIntegrity); |
934 |
ptr = encode16(ptr, 20);
|
935 |
ptr = encode(ptr, atr.hash, sizeof(atr.hash));
|
936 |
return ptr;
|
937 |
} |
938 |
|
939 |
char*
|
940 |
encodeAtrError(char* ptr, const StunAtrError atr) |
941 |
{ |
942 |
ptr = encode16(ptr, ErrorCode); |
943 |
ptr = encode16(ptr, 6 + atr.sizeReason);
|
944 |
ptr = encode16(ptr, atr.pad); |
945 |
*ptr++ = atr.errorClass; |
946 |
*ptr++ = atr.number; |
947 |
ptr = encode(ptr, atr.reason, atr.sizeReason); |
948 |
return ptr;
|
949 |
} |
950 |
|
951 |
|
952 |
char*
|
953 |
encodeAtrUnknown(char* ptr, const StunAtrUnknown atr) |
954 |
{ |
955 |
ptr = encode16(ptr, UnknownAttribute); |
956 |
ptr = encode16(ptr, 2+2*atr.numAttributes); |
957 |
int i;
|
958 |
for (i=0; i<atr.numAttributes; i++) |
959 |
{ |
960 |
ptr = encode16(ptr, atr.attrType[i]); |
961 |
} |
962 |
return ptr;
|
963 |
} |
964 |
|
965 |
|
966 |
char*
|
967 |
encodeAtrAddress4(char* ptr, UInt16 type, const StunAtrAddress4 atr) |
968 |
{ |
969 |
ptr = encode16(ptr, type); |
970 |
ptr = encode16(ptr, 8);
|
971 |
*ptr++ = atr.pad; |
972 |
*ptr++ = IPv4Family; |
973 |
ptr = encode16(ptr, atr.ipv4.port); |
974 |
ptr = encode32(ptr, atr.ipv4.addr); |
975 |
|
976 |
return ptr;
|
977 |
} |
978 |
|
979 |
|
980 |
char*
|
981 |
encodeAtrChangeRequest(char* ptr, const StunAtrChangeRequest atr) |
982 |
{ |
983 |
ptr = encode16(ptr, ChangeRequest); |
984 |
ptr = encode16(ptr, 4);
|
985 |
ptr = encode32(ptr, atr.value); |
986 |
return ptr;
|
987 |
} |
988 |
|
989 |
char*
|
990 |
encodeXorOnly(char* ptr)
|
991 |
{ |
992 |
ptr = encode16(ptr, XorOnly ); |
993 |
return ptr;
|
994 |
} |
995 |
|
996 |
char*
|
997 |
encode(char* buf, const char* data, unsigned int length) |
998 |
{ |
999 |
memcpy(buf, data, length); |
1000 |
return buf + length;
|
1001 |
} |
1002 |
|
1003 |
char*
|
1004 |
encode16(char* buf, UInt16 data)
|
1005 |
{ |
1006 |
UInt16 ndata = htons(data); |
1007 |
memcpy(buf, (void*)(&ndata), sizeof(UInt16)); |
1008 |
return buf + sizeof(UInt16); |
1009 |
} |
1010 |
|
1011 |
char*
|
1012 |
encode32(char* buf, UInt32 data)
|
1013 |
{ |
1014 |
UInt32 ndata = htonl(data); |
1015 |
memcpy(buf, (void*)(&ndata), sizeof(UInt32)); |
1016 |
return buf + sizeof(UInt32); |
1017 |
} |
1018 |
|
1019 |
/// return a random number to use as a port
|
1020 |
int
|
1021 |
stunRandomPort() |
1022 |
{ |
1023 |
int min=0x4000; |
1024 |
int max=0x7FFF; |
1025 |
|
1026 |
int ret = stunRand();
|
1027 |
ret = ret|min; |
1028 |
ret = ret&max; |
1029 |
|
1030 |
return ret;
|
1031 |
} |
1032 |
|
1033 |
|
1034 |
void
|
1035 |
toHex(const char* buffer, int bufferSize, char* output) |
1036 |
{ |
1037 |
static char hexmap[] = "0123456789abcdef"; |
1038 |
|
1039 |
const char* p = buffer; |
1040 |
char* r = output;
|
1041 |
int i;
|
1042 |
for (i=0; i < bufferSize; i++) |
1043 |
{ |
1044 |
unsigned char temp = *p++; |
1045 |
|
1046 |
int hi = (temp & 0xf0)>>4; |
1047 |
int low = (temp & 0xf); |
1048 |
|
1049 |
*r++ = hexmap[hi]; |
1050 |
*r++ = hexmap[low]; |
1051 |
} |
1052 |
*r = 0;
|
1053 |
} |
1054 |
|
1055 |
|
1056 |
|