Asterisk - The Open Source Telephony Project GIT-master-f36a736
Macros | Typedefs | Enumerations | Functions | Variables
stun.h File Reference

STUN support. More...

#include "asterisk/network.h"
#include "asterisk/logger_category.h"
Include dependency graph for stun.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define AST_DEBUG_CATEGORY_STUN   ast_debug_category_stun_id() /* STUN debug logging category id */
 
#define AST_DEBUG_CATEGORY_STUN_PACKET   ast_debug_category_stun_packet_id() /* STUN packet debug logging category id */
 
#define ast_debug_stun(sublevel, ...)    ast_debug_category(sublevel, AST_DEBUG_CATEGORY_STUN, __VA_ARGS__)
 Log debug level STUN information. More...
 
#define ast_debug_stun_packet_is_allowed    ast_debug_category_is_allowed(AST_LOG_CATEGORY_ENABLED, AST_DEBUG_CATEGORY_STUN_PACKET)
 
#define AST_LOG_CATEGORY_STUN   "stun"
 
#define AST_LOG_CATEGORY_STUN_PACKET   "stun_packet"
 

Typedefs

typedef int() stun_cb_f(struct stun_attr *attr, void *arg)
 callback type to be invoked on stun responses. More...
 

Enumerations

enum  ast_stun_result { AST_STUN_IGNORE = 0 , AST_STUN_ACCEPT }
 

Functions

uintmax_t ast_debug_category_stun_id (void)
 
uintmax_t ast_debug_category_stun_packet_id (void)
 
int ast_stun_handle_packet (int s, struct sockaddr_in *src, unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)
 handle an incoming STUN message. More...
 
int ast_stun_request (int s, struct sockaddr_in *dst, const char *username, struct sockaddr_in *answer)
 Generic STUN request. More...
 

Variables

static const int STANDARD_STUN_PORT = 3478
 

Detailed Description

STUN support.

STUN is defined in RFC 3489.

Definition in file stun.h.

Macro Definition Documentation

◆ AST_DEBUG_CATEGORY_STUN

#define AST_DEBUG_CATEGORY_STUN   ast_debug_category_stun_id() /* STUN debug logging category id */

Definition at line 45 of file stun.h.

◆ AST_DEBUG_CATEGORY_STUN_PACKET

#define AST_DEBUG_CATEGORY_STUN_PACKET   ast_debug_category_stun_packet_id() /* STUN packet debug logging category id */

Definition at line 46 of file stun.h.

◆ ast_debug_stun

#define ast_debug_stun (   sublevel,
  ... 
)     ast_debug_category(sublevel, AST_DEBUG_CATEGORY_STUN, __VA_ARGS__)

Log debug level STUN information.

Parameters
sublevelDebug output sublevel (>= 0)
...String format and any associated arguments

Definition at line 54 of file stun.h.

◆ ast_debug_stun_packet_is_allowed

Definition at line 58 of file stun.h.

◆ AST_LOG_CATEGORY_STUN

#define AST_LOG_CATEGORY_STUN   "stun"

Definition at line 38 of file stun.h.

◆ AST_LOG_CATEGORY_STUN_PACKET

#define AST_LOG_CATEGORY_STUN_PACKET   "stun_packet"

Definition at line 40 of file stun.h.

Typedef Documentation

◆ stun_cb_f

typedef int() stun_cb_f(struct stun_attr *attr, void *arg)

callback type to be invoked on stun responses.

Definition at line 95 of file stun.h.

Enumeration Type Documentation

◆ ast_stun_result

Enumerator
AST_STUN_IGNORE 
AST_STUN_ACCEPT 

Definition at line 63 of file stun.h.

63 {
66};
@ AST_STUN_ACCEPT
Definition: stun.h:65
@ AST_STUN_IGNORE
Definition: stun.h:64

Function Documentation

◆ ast_debug_category_stun_id()

uintmax_t ast_debug_category_stun_id ( void  )

Definition at line 555 of file stun.c.

556{
558}
static uintmax_t debug_category_stun_id
Definition: stun.c:553

References debug_category_stun_id.

◆ ast_debug_category_stun_packet_id()

uintmax_t ast_debug_category_stun_packet_id ( void  )

Definition at line 562 of file stun.c.

563{
565}
static uintmax_t debug_category_stun_packet_id
Definition: stun.c:560

References debug_category_stun_packet_id.

◆ ast_stun_handle_packet()

int ast_stun_handle_packet ( int  s,
struct sockaddr_in *  src,
unsigned char *  data,
size_t  len,
stun_cb_f stun_cb,
void *  arg 
)

handle an incoming STUN message.

Parameters
sSocket to send any response to.
srcAddress where packet came from.
dataSTUN packet buffer to process.
lenLength of packet
stun_cbIf not NULL, callback for each STUN attribute.
argArg to pass to callback.

Do some basic sanity checks on packet size and content, try to extract a bit of information, and possibly reply. At the moment this only processes BIND requests, and returns the externally visible address of the request. If a callback is specified, invoke it with the attribute.

Return values
AST_STUN_ACCEPTif responed to a STUN request
AST_STUN_IGNORE
-1on error

Definition at line 293 of file stun.c.

294{
295 struct stun_header *hdr = (struct stun_header *)data;
296 struct stun_attr *attr;
297 struct stun_state st;
298 int ret = AST_STUN_IGNORE;
299 int x;
300
301 /* On entry, 'len' is the length of the udp payload. After the
302 * initial checks it becomes the size of unprocessed options,
303 * while 'data' is advanced accordingly.
304 */
305 if (len < sizeof(struct stun_header)) {
306 ast_debug_stun(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
307 return -1;
308 }
309 len -= sizeof(struct stun_header);
310 data += sizeof(struct stun_header);
311 x = ntohs(hdr->msglen); /* len as advertised in the message */
313 ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), (unsigned)ntohs(hdr->msgtype), x);
314 if (x > len) {
315 ast_debug_stun(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
316 } else
317 len = x;
318 memset(&st, 0, sizeof(st));
319 while (len) {
320 if (len < sizeof(struct stun_attr)) {
321 ast_debug_stun(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
322 break;
323 }
324 attr = (struct stun_attr *)data;
325 /* compute total attribute length */
326 x = ntohs(attr->len) + sizeof(struct stun_attr);
327 if (x > len) {
328 ast_debug_stun(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
329 break;
330 }
331 if (stun_cb)
332 stun_cb(attr, arg);
333 if (stun_process_attr(&st, attr)) {
334 ast_debug_stun(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr));
335 break;
336 }
337 /* Clear attribute id: in case previous entry was a string,
338 * this will act as the terminator for the string.
339 */
340 attr->attr = 0;
341 data += x;
342 len -= x;
343 }
344 /* Null terminate any string.
345 * XXX NOTE, we write past the size of the buffer passed by the
346 * caller, so this is potentially dangerous. The only thing that
347 * saves us is that usually we read the incoming message in a
348 * much larger buffer in the struct ast_rtp
349 */
350 *data = '\0';
351
352 /* Now prepare to generate a reply, which at the moment is done
353 * only for properly formed (len == 0) STUN_BINDREQ messages.
354 */
355 if (len == 0) {
356 unsigned char respdata[1024];
357 struct stun_header *resp = (struct stun_header *)respdata;
358 int resplen = 0; /* len excluding header */
359 int respleft = sizeof(respdata) - sizeof(struct stun_header);
360 char combined[33];
361
362 resp->id = hdr->id;
363 resp->msgtype = 0;
364 resp->msglen = 0;
365 attr = (struct stun_attr *)resp->ies;
366 switch (ntohs(hdr->msgtype)) {
367 case STUN_BINDREQ:
369 ast_verbose("STUN Bind Request, username: %s\n",
370 st.username ? st.username : "<none>");
371 if (st.username) {
372 append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
373 /*
374 * For Google Voice, the stun username is made up of the local
375 * and remote usernames, each being fixed at 16 bytes. We have
376 * to swap the two at this point.
377 */
378 snprintf(combined, 17, "%16s", st.username + 16);
379 snprintf(combined + 16, 17, "%16s", st.username);
380 } else {
381 combined[0] = '\0';
382 }
383
384 append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft);
385 resp->msglen = htons(resplen);
386 resp->msgtype = htons(STUN_BINDRESP);
387 stun_send(s, src, resp);
388 ast_stun_request(s, src, combined, NULL);
389 ret = AST_STUN_ACCEPT;
390 break;
391 default:
393 ast_verbose("Dunno what to do with STUN message %04x (%s)\n", (unsigned)ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
394 }
395 }
396 return ret;
397}
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2206
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define NULL
Definition: resample.c:96
Definition: stun.c:78
unsigned short attr
Definition: stun.c:79
unsigned char ies[0]
Definition: stun.c:75
unsigned short msgtype
Definition: stun.c:72
unsigned short msglen
Definition: stun.c:73
stun_trans_id id
Definition: stun.c:74
here we store credentials extracted from a message
Definition: stun.c:176
static const char * stun_msg2str(int msg)
helper function to print message names
Definition: stun.c:126
#define STUN_BINDRESP
Definition: stun.c:102
int ast_stun_request(int s, struct sockaddr_in *dst, const char *username, struct sockaddr_in *answer)
Generic STUN request.
Definition: stun.c:415
#define STUN_MAPPED_ADDRESS
Basic attribute types in stun messages. Messages can also contain custom attributes (codes above 0x7f...
Definition: stun.c:111
#define STUN_USERNAME
Definition: stun.c:116
static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sin, int *len, int *left)
append an address to an STUN message
Definition: stun.c:222
static const char * stun_attr2str(int msg)
helper function to print attribute names
Definition: stun.c:146
#define STUN_BINDREQ
STUN message types 'BIND' refers to transactions used to determine the externally visible addresses....
Definition: stun.c:101
static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
Definition: stun.c:181
static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
wrapper to send an STUN message
Definition: stun.c:264
static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left)
append a string to an STUN message
Definition: stun.c:205
#define ast_debug_stun(sublevel,...)
Log debug level STUN information.
Definition: stun.h:54
#define ast_debug_stun_packet_is_allowed
Definition: stun.h:58

References append_attr_address(), append_attr_string(), ast_debug_stun, ast_debug_stun_packet_is_allowed, AST_STUN_ACCEPT, AST_STUN_IGNORE, ast_stun_request(), ast_verbose(), stun_attr::attr, stun_header::id, stun_header::ies, len(), stun_header::msglen, stun_header::msgtype, NULL, stun_attr2str(), STUN_BINDREQ, STUN_BINDRESP, STUN_MAPPED_ADDRESS, stun_msg2str(), stun_process_attr(), stun_send(), STUN_USERNAME, and stun_state::username.

Referenced by ast_rtcp_read(), ast_rtp_read(), and ast_stun_request().

◆ ast_stun_request()

int ast_stun_request ( int  s,
struct sockaddr_in *  dst,
const char *  username,
struct sockaddr_in *  answer 
)

Generic STUN request.

Parameters
sThe socket used to send the request.
dstIf non null, the address of the STUN server. Only needed if the socket is not bound or connected.
usernameIf non null, add the username in the request.
answerIf non null, the function waits for a response and puts here the externally visible address.

Send a generic STUN request to the server specified, possibly waiting for a reply and filling the answer parameter with the externally visible address. Note that in this case the request will be blocking.

Note
The interface may change slightly in the future.
Return values
0on success.
<0on error.
>0on timeout.

Definition at line 415 of file stun.c.

417{
418 struct stun_header *req;
419 struct stun_header *rsp;
420 unsigned char req_buf[1024];
421 unsigned char rsp_buf[1024];
422 int reqlen, reqleft;
423 struct stun_attr *attr;
424 int res = -1;
425 int retry;
426
427 if (answer) {
428 /* Always clear answer in case the request fails. */
429 memset(answer, 0, sizeof(struct sockaddr_in));
430 }
431
432 /* Create STUN bind request */
433 req = (struct stun_header *) req_buf;
434 stun_req_id(req);
435 reqlen = 0;
436 reqleft = sizeof(req_buf) - sizeof(struct stun_header);
437 attr = (struct stun_attr *) req->ies;
438 if (username) {
439 append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft);
440 }
441 req->msglen = htons(reqlen);
442 req->msgtype = htons(STUN_BINDREQ);
443
444 for (retry = 0; retry++ < STUN_MAX_RETRIES;) { /* XXX make retries configurable */
445 /* send request, possibly wait for reply */
446 struct sockaddr_in src;
447 socklen_t srclen;
448 struct timeval start;
449
450 /* Send STUN message. */
451 res = stun_send(s, dst, req);
452 if (res < 0) {
453 ast_debug_stun(1, "stun_send try %d failed: %s\n", retry, strerror(errno));
454 break;
455 }
456 if (!answer) {
457 /* Successful send since we don't care about any response. */
458 res = 0;
459 break;
460 }
461
462 start = ast_tvnow();
463try_again:
464 /* Wait for response. */
465 {
466 struct pollfd pfds = { .fd = s, .events = POLLIN };
467 int ms;
468
469 ms = ast_remaining_ms(start, 3000);
470 if (ms <= 0) {
471 /* No response, timeout */
472 handle_stun_timeout(retry, dst);
473 res = 1;
474 continue;
475 }
476 res = ast_poll(&pfds, 1, ms);
477 if (res < 0) {
478 /* Error */
479 continue;
480 }
481 if (!res) {
482 /* No response, timeout */
483 handle_stun_timeout(retry, dst);
484 res = 1;
485 continue;
486 }
487 }
488
489 /* Read STUN response. */
490 memset(&src, 0, sizeof(src));
491 srclen = sizeof(src);
492 /* XXX pass sizeof(rsp_buf) - 1 in the size, because stun_handle_packet might
493 * write past the end of the buffer.
494 */
495 res = recvfrom(s, rsp_buf, sizeof(rsp_buf) - 1,
496 0, (struct sockaddr *) &src, &srclen);
497 if (res < 0) {
498 ast_debug_stun(1, "recvfrom try %d failed: %s\n", retry, strerror(errno));
499 break;
500 }
501
502 /* Process the STUN response. */
503 rsp = (struct stun_header *) rsp_buf;
504 if (ast_stun_handle_packet(s, &src, rsp_buf, res, stun_get_mapped, answer)
505 || (rsp->msgtype != htons(STUN_BINDRESP)
506 && rsp->msgtype != htons(STUN_BINDERR))
507 || stun_id_cmp(&req->id, &rsp->id)) {
508 /* Bad STUN packet, not right type, or transaction ID did not match. */
509 memset(answer, 0, sizeof(struct sockaddr_in));
510
511 /* Was not a resonse to our request. */
512 goto try_again;
513 }
514 /* Success. answer contains the external address if available. */
515 res = 0;
516 break;
517 }
518 return res;
519}
if(!yyg->yy_init)
Definition: ast_expr2f.c:854
static int answer(void *data)
Definition: chan_pjsip.c:687
int errno
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
static int stun_get_mapped(struct stun_attr *attr, void *arg)
Extract the STUN_MAPPED_ADDRESS from the stun response. This is used as a callback for stun_handle_re...
Definition: stun.c:403
#define STUN_MAX_RETRIES
Definition: stun.c:123
static void handle_stun_timeout(int retry, struct sockaddr_in *dst)
Definition: stun.c:240
int ast_stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)
handle an incoming STUN message.
Definition: stun.c:293
static int stun_id_cmp(stun_trans_id *left, stun_trans_id *right)
Definition: stun.c:280
#define STUN_BINDERR
Definition: stun.c:103
static void stun_req_id(struct stun_header *req)
helper function to generate a random request id
Definition: stun.c:286
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:2281
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References answer(), append_attr_string(), ast_debug_stun, ast_poll, ast_remaining_ms(), ast_stun_handle_packet(), ast_tvnow(), stun_attr::attr, errno, handle_stun_timeout(), stun_header::id, stun_header::ies, if(), stun_header::msglen, stun_header::msgtype, STUN_BINDERR, STUN_BINDREQ, STUN_BINDRESP, stun_get_mapped(), stun_id_cmp(), STUN_MAX_RETRIES, stun_req_id(), stun_send(), and STUN_USERNAME.

Referenced by ast_rtp_stun_request(), ast_stun_handle_packet(), and stun_monitor_request().

Variable Documentation

◆ STANDARD_STUN_PORT

const int STANDARD_STUN_PORT = 3478
static

Definition at line 61 of file stun.h.

Referenced by rtp_reload(), and setup_stunaddr().