Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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  {
64  AST_STUN_IGNORE = 0,
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 {
557  return debug_category_stun_id;
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
#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
#define STUN_BINDREQ
STUN message types 'BIND' refers to transactions used to determine the externally visible addresses....
Definition: stun.c:101
static const char * stun_msg2str(int msg)
helper function to print message names
Definition: stun.c:126
static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
Definition: stun.c:181
static const char * stun_attr2str(int msg)
helper function to print attribute names
Definition: stun.c:146
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();
463 try_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:868
static int answer(void *data)
Definition: chan_pjsip.c:675
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: main/utils.c:2179
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:157

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().