Asterisk - The Open Source Telephony Project  18.5.0
stun.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2008, Digium, Inc.
5  *
6  * Mark Spencer <[email protected]>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*!
20  * \file
21  *
22  * \brief STUN Support
23  *
24  * \author Mark Spencer <[email protected]>
25  *
26  * \note STUN is defined in RFC 3489.
27  */
28 
29 /*** MODULEINFO
30  <support_level>core</support_level>
31  ***/
32 
33 #include "asterisk.h"
34 
35 #include "asterisk/logger.h"
37 #include "asterisk/_private.h"
38 #include "asterisk/stun.h"
39 #include "asterisk/cli.h"
40 #include "asterisk/utils.h"
41 #include "asterisk/channel.h"
42 
43 /*!
44  * \brief STUN support code
45  *
46  * This code provides some support for doing STUN transactions.
47  * Eventually it should be moved elsewhere as other protocols
48  * than RTP can benefit from it - e.g. SIP.
49  * STUN is described in RFC3489 and it is based on the exchange
50  * of UDP packets between a client and one or more servers to
51  * determine the externally visible address (and port) of the client
52  * once it has gone through the NAT boxes that connect it to the
53  * outside.
54  * The simplest request packet is just the header defined in
55  * struct stun_header, and from the response we may just look at
56  * one attribute, STUN_MAPPED_ADDRESS, that we find in the response.
57  * By doing more transactions with different server addresses we
58  * may determine more about the behaviour of the NAT boxes, of
59  * course - the details are in the RFC.
60  *
61  * All STUN packets start with a simple header made of a type,
62  * length (excluding the header) and a 16-byte random transaction id.
63  * Following the header we may have zero or more attributes, each
64  * structured as a type, length and a value (whose format depends
65  * on the type, but often contains addresses).
66  * Of course all fields are in network format.
67  */
68 
69 typedef struct { unsigned int id[4]; } __attribute__((packed)) stun_trans_id;
70 
71 struct stun_header {
72  unsigned short msgtype;
73  unsigned short msglen;
75  unsigned char ies[0];
76 } __attribute__((packed));
77 
78 struct stun_attr {
79  unsigned short attr;
80  unsigned short len;
81  unsigned char value[0];
82 } __attribute__((packed));
83 
84 /*
85  * The format normally used for addresses carried by STUN messages.
86  */
87 struct stun_addr {
88  unsigned char unused;
89  unsigned char family;
90  unsigned short port;
91  unsigned int addr;
92 } __attribute__((packed));
93 
94 /*! \brief STUN message types
95  * 'BIND' refers to transactions used to determine the externally
96  * visible addresses. 'SEC' refers to transactions used to establish
97  * a session key for subsequent requests.
98  * 'SEC' functionality is not supported here.
99  */
100 
101 #define STUN_BINDREQ 0x0001
102 #define STUN_BINDRESP 0x0101
103 #define STUN_BINDERR 0x0111
104 #define STUN_SECREQ 0x0002
105 #define STUN_SECRESP 0x0102
106 #define STUN_SECERR 0x0112
107 
108 /*! \brief Basic attribute types in stun messages.
109  * Messages can also contain custom attributes (codes above 0x7fff)
110  */
111 #define STUN_MAPPED_ADDRESS 0x0001
112 #define STUN_RESPONSE_ADDRESS 0x0002
113 #define STUN_CHANGE_REQUEST 0x0003
114 #define STUN_SOURCE_ADDRESS 0x0004
115 #define STUN_CHANGED_ADDRESS 0x0005
116 #define STUN_USERNAME 0x0006
117 #define STUN_PASSWORD 0x0007
118 #define STUN_MESSAGE_INTEGRITY 0x0008
119 #define STUN_ERROR_CODE 0x0009
120 #define STUN_UNKNOWN_ATTRIBUTES 0x000a
121 #define STUN_REFLECTED_FROM 0x000b
122 
123 /*! \brief helper function to print message names */
124 static const char *stun_msg2str(int msg)
125 {
126  switch (msg) {
127  case STUN_BINDREQ:
128  return "Binding Request";
129  case STUN_BINDRESP:
130  return "Binding Response";
131  case STUN_BINDERR:
132  return "Binding Error Response";
133  case STUN_SECREQ:
134  return "Shared Secret Request";
135  case STUN_SECRESP:
136  return "Shared Secret Response";
137  case STUN_SECERR:
138  return "Shared Secret Error Response";
139  }
140  return "Non-RFC3489 Message";
141 }
142 
143 /*! \brief helper function to print attribute names */
144 static const char *stun_attr2str(int msg)
145 {
146  switch (msg) {
147  case STUN_MAPPED_ADDRESS:
148  return "Mapped Address";
150  return "Response Address";
151  case STUN_CHANGE_REQUEST:
152  return "Change Request";
153  case STUN_SOURCE_ADDRESS:
154  return "Source Address";
156  return "Changed Address";
157  case STUN_USERNAME:
158  return "Username";
159  case STUN_PASSWORD:
160  return "Password";
162  return "Message Integrity";
163  case STUN_ERROR_CODE:
164  return "Error Code";
166  return "Unknown Attributes";
167  case STUN_REFLECTED_FROM:
168  return "Reflected From";
169  }
170  return "Non-RFC3489 Attribute";
171 }
172 
173 /*! \brief here we store credentials extracted from a message */
174 struct stun_state {
175  const char *username;
176  const char *password;
177 };
178 
179 static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
180 {
182  ast_verbose("Found STUN Attribute %s (%04x), length %d\n",
183  stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr), ntohs(attr->len));
184  }
185  switch (ntohs(attr->attr)) {
186  case STUN_USERNAME:
187  state->username = (const char *) (attr->value);
188  break;
189  case STUN_PASSWORD:
190  state->password = (const char *) (attr->value);
191  break;
192  default:
194  ast_verbose("Ignoring STUN attribute %s (%04x), length %d\n",
195  stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr), ntohs(attr->len));
196  }
197  }
198 
199  return 0;
200 }
201 
202 /*! \brief append a string to an STUN message */
203 static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left)
204 {
205  int str_length = strlen(s);
206  int attr_length = str_length + ((~(str_length - 1)) & 0x3);
207  int size = sizeof(**attr) + attr_length;
208  if (*left > size) {
209  (*attr)->attr = htons(attrval);
210  (*attr)->len = htons(attr_length);
211  memcpy((*attr)->value, s, str_length);
212  memset((*attr)->value + str_length, 0, attr_length - str_length);
213  (*attr) = (struct stun_attr *)((*attr)->value + attr_length);
214  *len += size;
215  *left -= size;
216  }
217 }
218 
219 /*! \brief append an address to an STUN message */
220 static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sin, int *len, int *left)
221 {
222  int size = sizeof(**attr) + 8;
223  struct stun_addr *addr;
224  if (*left > size) {
225  (*attr)->attr = htons(attrval);
226  (*attr)->len = htons(8);
227  addr = (struct stun_addr *)((*attr)->value);
228  addr->unused = 0;
229  addr->family = 0x01;
230  addr->port = sin->sin_port;
231  addr->addr = sin->sin_addr.s_addr;
232  (*attr) = (struct stun_attr *)((*attr)->value + 8);
233  *len += size;
234  *left -= size;
235  }
236 }
237 
238 /*! \brief wrapper to send an STUN message */
239 static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
240 {
241  return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0,
242  (struct sockaddr *)dst, sizeof(*dst));
243 }
244 
245 /*!
246  * \internal
247  * \brief Compare the STUN tranaction IDs.
248  *
249  * \param left Transaction ID.
250  * \param right Transaction ID.
251  *
252  * \retval 0 if match.
253  * \retval non-zero if not match.
254  */
255 static int stun_id_cmp(stun_trans_id *left, stun_trans_id *right)
256 {
257  return memcmp(left, right, sizeof(*left));
258 }
259 
260 /*! \brief helper function to generate a random request id */
261 static void stun_req_id(struct stun_header *req)
262 {
263  int x;
264  for (x = 0; x < 4; x++)
265  req->id.id[x] = ast_random();
266 }
267 
268 int ast_stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)
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 }
367 
368 /*! \brief Extract the STUN_MAPPED_ADDRESS from the stun response.
369  * This is used as a callback for stun_handle_response
370  * when called from ast_stun_request.
371  */
372 static int stun_get_mapped(struct stun_attr *attr, void *arg)
373 {
374  struct stun_addr *addr = (struct stun_addr *)(attr + 1);
375  struct sockaddr_in *sa = (struct sockaddr_in *)arg;
376 
377  if (ntohs(attr->attr) != STUN_MAPPED_ADDRESS || ntohs(attr->len) != 8)
378  return 1; /* not us. */
379  sa->sin_port = addr->port;
380  sa->sin_addr.s_addr = addr->addr;
381  return 0;
382 }
383 
384 int ast_stun_request(int s, struct sockaddr_in *dst,
385  const char *username, struct sockaddr_in *answer)
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 }
487 
488 static char *handle_cli_stun_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
489 {
490  switch (cmd) {
491  case CLI_INIT:
492  e->command = "stun set debug {on|off}";
493  e->usage =
494  "Usage: stun set debug {on|off}\n"
495  " Enable/Disable STUN (Simple Traversal of UDP through NATs)\n"
496  " debugging\n";
497  return NULL;
498  case CLI_GENERATE:
499  return NULL;
500  }
501 
502  if (a->argc != e->args)
503  return CLI_SHOWUSAGE;
504 
505  if (!strncasecmp(a->argv[e->args-1], "on", 2))
507  else if (!strncasecmp(a->argv[e->args-1], "off", 3))
509  else
510  return CLI_SHOWUSAGE;
511 
512  ast_cli(a->fd, "STUN Debugging %s\n", ast_debug_stun_packet_is_allowed ? "Enabled" : "Disabled");
513  return CLI_SUCCESS;
514 }
515 
516 static struct ast_cli_entry cli_stun[] = {
517  AST_CLI_DEFINE(handle_cli_stun_set_debug, "Enable/Disable STUN debugging"),
518 };
519 
520 static uintmax_t debug_category_stun_id;
521 
523 {
524  return debug_category_stun_id;
525 }
526 
528 
530 {
532 }
533 
534 static void stun_shutdown(void)
535 {
536  ast_cli_unregister_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
537 
540 }
541 
542 /*! \brief Initialize the STUN system in Asterisk */
543 void ast_stun_init(void)
544 {
545  ast_cli_register_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
547 
548  debug_category_stun_id = ast_debug_category_register(AST_LOG_CATEGORY_STUN);
549  debug_category_stun_packet_id = ast_debug_category_register(AST_LOG_CATEGORY_STUN_PACKET);
550 }
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
STUN support code.
Definition: stun.c:69
unsigned char unused
Definition: stun.c:88
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
#define STUN_PASSWORD
Definition: stun.c:117
Asterisk main include file. File version handling, generic pbx functions.
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
static void stun_shutdown(void)
Definition: stun.c:534
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define STUN_MAPPED_ADDRESS
Basic attribute types in stun messages. Messages can also contain custom attributes (codes above 0x7f...
Definition: stun.c:111
int ast_debug_category_set_sublevel(const char *name, int sublevel)
Set the debug category&#39;s sublevel.
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define STUN_CHANGE_REQUEST
Definition: stun.c:113
Definition: stun.c:78
const char * username
Definition: stun.c:175
Definition: cli.h:152
if(!yyg->yy_init)
Definition: ast_expr2f.c:868
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define STUN_MESSAGE_INTEGRITY
Definition: stun.c:118
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
static uintmax_t debug_category_stun_packet_id
Definition: stun.c:527
int value
Definition: syslog.c:37
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
int ast_stun_request(int s, struct sockaddr_in *dst, const char *username, struct sockaddr_in *answer)
Generic STUN request.
Definition: stun.c:384
static struct ast_cli_entry cli_stun[]
Definition: stun.c:516
Utility functions.
int args
This gets set in ast_cli_register()
Definition: cli.h:185
#define STUN_USERNAME
Definition: stun.c:116
unsigned int id[4]
Definition: stun.c:69
void ast_stun_init(void)
Initialize the STUN system in Asterisk.
Definition: stun.c:543
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
General Asterisk PBX channel definitions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
static void stun_req_id(struct stun_header *req)
helper function to generate a random request id
Definition: stun.c:261
unsigned int addr
Definition: stun.c:91
const int fd
Definition: cli.h:159
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
Definition: stun.c:87
uintmax_t ast_debug_category_stun_packet_id(void)
Definition: stun.c:529
long int ast_random(void)
Definition: main/utils.c:2064
STUN support.
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
static int answer(void *data)
Definition: chan_pjsip.c:682
#define STUN_CHANGED_ADDRESS
Definition: stun.c:115
static uintmax_t debug_category_stun_id
Definition: stun.c:520
const char *const * argv
Definition: cli.h:161
#define ast_debug_stun(sublevel,...)
Log debug level STUN information.
Definition: stun.h:53
unsigned char family
Definition: stun.c:89
const char * password
Definition: stun.c:176
stun_trans_id id
Definition: stun.c:74
#define AST_LOG_CATEGORY_DISABLED
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define STUN_REFLECTED_FROM
Definition: stun.c:121
#define STUN_RESPONSE_ADDRESS
Definition: stun.c:112
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
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
int errno
static int stun_id_cmp(stun_trans_id *left, stun_trans_id *right)
Definition: stun.c:255
static char * handle_cli_stun_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: stun.c:488
here we store credentials extracted from a message
Definition: stun.c:174
char * command
Definition: cli.h:186
uintmax_t ast_debug_category_stun_id(void)
Definition: stun.c:522
Prototypes for public functions only of internal interest,.
int() stun_cb_f(struct stun_attr *attr, void *arg)
callback type to be invoked on stun responses.
Definition: stun.h:94
#define STUN_SECERR
Definition: stun.c:106
static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
Definition: stun.c:179
Support for logging to various files, console and syslog Configuration in file logger.conf.
unsigned char ies[0]
Definition: stun.c:75
const char * usage
Definition: cli.h:177
unsigned short attr
Definition: stun.c:79
int ast_debug_category_unregister(const char *name)
Un-register a debug level logger category.
#define CLI_SUCCESS
Definition: cli.h:44
Standard Command Line Interface.
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
#define STUN_ERROR_CODE
Definition: stun.c:119
#define STUN_BINDERR
Definition: stun.c:103
#define STUN_SECRESP
Definition: stun.c:105
#define AST_LOG_CATEGORY_STUN
Definition: stun.h:37
uintmax_t ast_debug_category_register(const char *name)
Register a debug level logger category.
unsigned short port
Definition: stun.c:90
#define AST_LOG_CATEGORY_ENABLED
unsigned char value[0]
Definition: stun.c:81
#define AST_LOG_CATEGORY_STUN_PACKET
Definition: stun.h:39
static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
wrapper to send an STUN message
Definition: stun.c:239
#define STUN_SOURCE_ADDRESS
Definition: stun.c:114
#define STUN_UNKNOWN_ATTRIBUTES
Definition: stun.c:120
#define STUN_SECREQ
Definition: stun.c:104
static struct test_val a
static const char * stun_attr2str(int msg)
helper function to print attribute names
Definition: stun.c:144