Asterisk - The Open Source Telephony Project  18.5.0
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 44 of file stun.h.

Referenced by rtp_add_candidates_to_ice().

◆ 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 45 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 53 of file stun.h.

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

◆ ast_debug_stun_packet_is_allowed

Definition at line 57 of file stun.h.

Referenced by ast_stun_handle_packet(), handle_cli_stun_set_debug(), and stun_process_attr().

◆ AST_LOG_CATEGORY_STUN

#define AST_LOG_CATEGORY_STUN   "stun"

Definition at line 37 of file stun.h.

Referenced by ast_stun_init(), and stun_shutdown().

◆ AST_LOG_CATEGORY_STUN_PACKET

#define AST_LOG_CATEGORY_STUN_PACKET   "stun_packet"

Definition at line 39 of file stun.h.

Referenced by ast_stun_init(), handle_cli_stun_set_debug(), and stun_shutdown().

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 94 of file stun.h.

Enumeration Type Documentation

◆ ast_stun_result

Enumerator
AST_STUN_IGNORE 
AST_STUN_ACCEPT 

Definition at line 62 of file stun.h.

62  {
63  AST_STUN_IGNORE = 0,
65 };

Function Documentation

◆ ast_debug_category_stun_id()

uintmax_t ast_debug_category_stun_id ( void  )

Definition at line 522 of file stun.c.

References debug_category_stun_id.

523 {
524  return debug_category_stun_id;
525 }
static uintmax_t debug_category_stun_id
Definition: stun.c:520

◆ ast_debug_category_stun_packet_id()

uintmax_t ast_debug_category_stun_packet_id ( void  )

Definition at line 529 of file stun.c.

References debug_category_stun_packet_id.

530 {
532 }
static uintmax_t debug_category_stun_packet_id
Definition: stun.c:527

◆ 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 268 of file stun.c.

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, stun_attr::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().

269 {
270  struct stun_header *hdr = (struct stun_header *)data;
271  struct stun_attr *attr;
272  struct stun_state st;
273  int ret = AST_STUN_IGNORE;
274  int x;
275 
276  /* On entry, 'len' is the length of the udp payload. After the
277  * initial checks it becomes the size of unprocessed options,
278  * while 'data' is advanced accordingly.
279  */
280  if (len < sizeof(struct stun_header)) {
281  ast_debug_stun(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
282  return -1;
283  }
284  len -= sizeof(struct stun_header);
285  data += sizeof(struct stun_header);
286  x = ntohs(hdr->msglen); /* len as advertised in the message */
288  ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), (unsigned)ntohs(hdr->msgtype), x);
289  if (x > len) {
290  ast_debug_stun(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
291  } else
292  len = x;
293  memset(&st, 0, sizeof(st));
294  while (len) {
295  if (len < sizeof(struct stun_attr)) {
296  ast_debug_stun(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
297  break;
298  }
299  attr = (struct stun_attr *)data;
300  /* compute total attribute length */
301  x = ntohs(attr->len) + sizeof(struct stun_attr);
302  if (x > len) {
303  ast_debug_stun(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
304  break;
305  }
306  if (stun_cb)
307  stun_cb(attr, arg);
308  if (stun_process_attr(&st, attr)) {
309  ast_debug_stun(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr));
310  break;
311  }
312  /* Clear attribute id: in case previous entry was a string,
313  * this will act as the terminator for the string.
314  */
315  attr->attr = 0;
316  data += x;
317  len -= x;
318  }
319  /* Null terminate any string.
320  * XXX NOTE, we write past the size of the buffer passed by the
321  * caller, so this is potentially dangerous. The only thing that
322  * saves us is that usually we read the incoming message in a
323  * much larger buffer in the struct ast_rtp
324  */
325  *data = '\0';
326 
327  /* Now prepare to generate a reply, which at the moment is done
328  * only for properly formed (len == 0) STUN_BINDREQ messages.
329  */
330  if (len == 0) {
331  unsigned char respdata[1024];
332  struct stun_header *resp = (struct stun_header *)respdata;
333  int resplen = 0; /* len excluding header */
334  int respleft = sizeof(respdata) - sizeof(struct stun_header);
335  char combined[33];
336 
337  resp->id = hdr->id;
338  resp->msgtype = 0;
339  resp->msglen = 0;
340  attr = (struct stun_attr *)resp->ies;
341  switch (ntohs(hdr->msgtype)) {
342  case STUN_BINDREQ:
344  ast_verbose("STUN Bind Request, username: %s\n",
345  st.username ? st.username : "<none>");
346  if (st.username) {
347  append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
348  snprintf(combined, sizeof(combined), "%16s%16s", st.username + 16, st.username);
349  } else {
350  combined[0] = '\0';
351  }
352 
353  append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft);
354  resp->msglen = htons(resplen);
355  resp->msgtype = htons(STUN_BINDRESP);
356  stun_send(s, src, resp);
357  ast_stun_request(s, src, combined, NULL);
358  ret = AST_STUN_ACCEPT;
359  break;
360  default:
362  ast_verbose("Dunno what to do with STUN message %04x (%s)\n", (unsigned)ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
363  }
364  }
365  return ret;
366 }
unsigned short msglen
Definition: stun.c:73
static const char * stun_msg2str(int msg)
helper function to print message names
Definition: stun.c:124
#define STUN_BINDRESP
Definition: stun.c:102
unsigned short msgtype
Definition: stun.c:72
#define STUN_MAPPED_ADDRESS
Basic attribute types in stun messages. Messages can also contain custom attributes (codes above 0x7f...
Definition: stun.c:111
Definition: stun.c:78
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2207
#define ast_debug_stun_packet_is_allowed
Definition: stun.h:57
#define NULL
Definition: resample.c:96
int ast_stun_request(int s, struct sockaddr_in *dst, const char *username, struct sockaddr_in *answer)
Generic STUN request.
Definition: stun.c:384
#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:220
#define ast_debug_stun(sublevel,...)
Log debug level STUN information.
Definition: stun.h:53
stun_trans_id id
Definition: stun.c:74
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define STUN_BINDREQ
STUN message types &#39;BIND&#39; refers to transactions used to determine the externally visible addresses...
Definition: stun.c:101
here we store credentials extracted from a message
Definition: stun.c:174
static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
Definition: stun.c:179
unsigned char ies[0]
Definition: stun.c:75
unsigned short attr
Definition: stun.c:79
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:203
unsigned short len
Definition: stun.c:80
static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
wrapper to send an STUN message
Definition: stun.c:239
static const char * stun_attr2str(int msg)
helper function to print attribute names
Definition: stun.c:144

◆ 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 384 of file stun.c.

References append_attr_string(), ast_debug_stun, ast_poll, ast_remaining_ms(), ast_stun_handle_packet(), ast_tvnow(), stun_attr::attr, errno, 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_req_id(), stun_send(), and STUN_USERNAME.

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

386 {
387  struct stun_header *req;
388  struct stun_header *rsp;
389  unsigned char req_buf[1024];
390  unsigned char rsp_buf[1024];
391  int reqlen, reqleft;
392  struct stun_attr *attr;
393  int res = -1;
394  int retry;
395 
396  if (answer) {
397  /* Always clear answer in case the request fails. */
398  memset(answer, 0, sizeof(struct sockaddr_in));
399  }
400 
401  /* Create STUN bind request */
402  req = (struct stun_header *) req_buf;
403  stun_req_id(req);
404  reqlen = 0;
405  reqleft = sizeof(req_buf) - sizeof(struct stun_header);
406  attr = (struct stun_attr *) req->ies;
407  if (username) {
408  append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft);
409  }
410  req->msglen = htons(reqlen);
411  req->msgtype = htons(STUN_BINDREQ);
412 
413  for (retry = 0; retry++ < 3;) { /* XXX make retries configurable */
414  /* send request, possibly wait for reply */
415  struct sockaddr_in src;
416  socklen_t srclen;
417  struct timeval start;
418 
419  /* Send STUN message. */
420  res = stun_send(s, dst, req);
421  if (res < 0) {
422  ast_debug_stun(1, "stun_send try %d failed: %s\n", retry, strerror(errno));
423  break;
424  }
425  if (!answer) {
426  /* Successful send since we don't care about any response. */
427  res = 0;
428  break;
429  }
430 
431  start = ast_tvnow();
432 try_again:
433  /* Wait for response. */
434  {
435  struct pollfd pfds = { .fd = s, .events = POLLIN };
436  int ms;
437 
438  ms = ast_remaining_ms(start, 3000);
439  if (ms <= 0) {
440  /* No response, timeout */
441  res = 1;
442  continue;
443  }
444  res = ast_poll(&pfds, 1, ms);
445  if (res < 0) {
446  /* Error */
447  continue;
448  }
449  if (!res) {
450  /* No response, timeout */
451  res = 1;
452  continue;
453  }
454  }
455 
456  /* Read STUN response. */
457  memset(&src, 0, sizeof(src));
458  srclen = sizeof(src);
459  /* XXX pass sizeof(rsp_buf) - 1 in the size, because stun_handle_packet might
460  * write past the end of the buffer.
461  */
462  res = recvfrom(s, rsp_buf, sizeof(rsp_buf) - 1,
463  0, (struct sockaddr *) &src, &srclen);
464  if (res < 0) {
465  ast_debug_stun(1, "recvfrom try %d failed: %s\n", retry, strerror(errno));
466  break;
467  }
468 
469  /* Process the STUN response. */
470  rsp = (struct stun_header *) rsp_buf;
471  if (ast_stun_handle_packet(s, &src, rsp_buf, res, stun_get_mapped, answer)
472  || (rsp->msgtype != htons(STUN_BINDRESP)
473  && rsp->msgtype != htons(STUN_BINDERR))
474  || stun_id_cmp(&req->id, &rsp->id)) {
475  /* Bad STUN packet, not right type, or transaction ID did not match. */
476  memset(answer, 0, sizeof(struct sockaddr_in));
477 
478  /* Was not a resonse to our request. */
479  goto try_again;
480  }
481  /* Success. answer contains the external address if available. */
482  res = 0;
483  break;
484  }
485  return res;
486 }
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:268
unsigned short msglen
Definition: stun.c:73
#define STUN_BINDRESP
Definition: stun.c:102
unsigned short msgtype
Definition: stun.c:72
Definition: stun.c:78
if(!yyg->yy_init)
Definition: ast_expr2f.c:868
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define STUN_USERNAME
Definition: stun.c:116
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:372
static void stun_req_id(struct stun_header *req)
helper function to generate a random request id
Definition: stun.c:261
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
static int answer(void *data)
Definition: chan_pjsip.c:682
#define ast_debug_stun(sublevel,...)
Log debug level STUN information.
Definition: stun.h:53
stun_trans_id id
Definition: stun.c:74
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: main/utils.c:2033
#define STUN_BINDREQ
STUN message types &#39;BIND&#39; refers to transactions used to determine the externally visible addresses...
Definition: stun.c:101
int errno
static int stun_id_cmp(stun_trans_id *left, stun_trans_id *right)
Definition: stun.c:255
unsigned char ies[0]
Definition: stun.c:75
unsigned short attr
Definition: stun.c:79
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:203
#define STUN_BINDERR
Definition: stun.c:103
static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
wrapper to send an STUN message
Definition: stun.c:239

Variable Documentation

◆ STANDARD_STUN_PORT

const int STANDARD_STUN_PORT = 3478
static

Definition at line 60 of file stun.h.

Referenced by rtp_reload(), and setup_stunaddr().