36 #include "asterisk/logger_category.h"
69 typedef struct {
unsigned int id[4]; } __attribute__((packed))
stun_trans_id;
72 unsigned short msgtype;
73 unsigned short msglen;
76 } __attribute__((packed));
81 unsigned char value[0];
82 } __attribute__((packed));
92 } __attribute__((packed));
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
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
123 #define STUN_MAX_RETRIES 3
130 return "Binding Request";
132 return "Binding Response";
134 return "Binding Error Response";
136 return "Shared Secret Request";
138 return "Shared Secret Response";
140 return "Shared Secret Error Response";
142 return "Non-RFC3489 Message";
150 return "Mapped Address";
151 case STUN_RESPONSE_ADDRESS:
152 return "Response Address";
153 case STUN_CHANGE_REQUEST:
154 return "Change Request";
155 case STUN_SOURCE_ADDRESS:
156 return "Source Address";
157 case STUN_CHANGED_ADDRESS:
158 return "Changed Address";
163 case STUN_MESSAGE_INTEGRITY:
164 return "Message Integrity";
165 case STUN_ERROR_CODE:
167 case STUN_UNKNOWN_ATTRIBUTES:
168 return "Unknown Attributes";
169 case STUN_REFLECTED_FROM:
170 return "Reflected From";
172 return "Non-RFC3489 Attribute";
177 const char *username;
178 const char *password;
183 if (ast_debug_stun_packet_is_allowed) {
184 ast_verbose(
"Found STUN Attribute %s (%04x), length %d\n",
185 stun_attr2str(ntohs(attr->attr)), (
unsigned)ntohs(attr->attr), ntohs(attr->len));
187 switch (ntohs(attr->attr)) {
189 state->username = (
const char *) (attr->value);
192 state->password = (
const char *) (attr->value);
195 if (ast_debug_stun_packet_is_allowed) {
196 ast_verbose(
"Ignoring STUN attribute %s (%04x), length %d\n",
197 stun_attr2str(ntohs(attr->attr)), (
unsigned)ntohs(attr->attr), ntohs(attr->len));
207 int str_length = strlen(s);
208 int attr_length = str_length + ((~(str_length - 1)) & 0x3);
209 int size =
sizeof(**attr) + attr_length;
211 (*attr)->attr = htons(attrval);
212 (*attr)->len = htons(attr_length);
213 memcpy((*attr)->value, s, str_length);
214 memset((*attr)->value + str_length, 0, attr_length - str_length);
215 (*attr) = (
struct stun_attr *)((*attr)->value + attr_length);
224 int size =
sizeof(**attr) + 8;
227 (*attr)->attr = htons(attrval);
228 (*attr)->len = htons(8);
229 addr = (
struct stun_addr *)((*attr)->value);
232 addr->port = sin->sin_port;
233 addr->addr = sin->sin_addr.s_addr;
234 (*attr) = (
struct stun_attr *)((*attr)->value + 8);
240 static void handle_stun_timeout(
int retry,
struct sockaddr_in *dst)
242 char *stun_destination =
"";
246 if (retry < STUN_MAX_RETRIES) {
248 "Attempt %d to send STUN request %stimed out.\n",
253 "Attempt %d to send STUN request %stimed out. "
254 "Check that the server address is correct and reachable.\n",
259 ast_free(stun_destination);
266 return sendto(s, resp, ntohs(resp->msglen) +
sizeof(*resp), 0,
267 (
struct sockaddr *)dst,
sizeof(*dst));
282 return memcmp(left, right,
sizeof(*left));
289 for (x = 0; x < 4; x++)
290 req->id.id[x] = ast_random();
298 int ret = AST_STUN_IGNORE;
311 x = ntohs(hdr->msglen);
312 if (ast_debug_stun_packet_is_allowed)
313 ast_verbose(
"STUN Packet, msg %s (%04x), length: %d\n",
stun_msg2str(ntohs(hdr->msgtype)), (
unsigned)ntohs(hdr->msgtype), x);
315 ast_debug_stun(1,
"Scrambled STUN packet length (got %d, expecting %d)\n", x, (
int)len);
318 memset(&st, 0,
sizeof(st));
326 x = ntohs(attr->len) +
sizeof(
struct stun_attr);
328 ast_debug_stun(1,
"Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (
int)len);
333 if (stun_process_attr(&st, attr)) {
356 unsigned char respdata[1024];
359 int respleft =
sizeof(respdata) -
sizeof(
struct stun_header);
366 switch (ntohs(hdr->msgtype)) {
368 if (ast_debug_stun_packet_is_allowed)
369 ast_verbose(
"STUN Bind Request, username: %s\n",
370 st.username ? st.username :
"<none>");
378 snprintf(combined, 17,
"%16s", st.username + 16);
379 snprintf(combined + 16, 17,
"%16s", st.username);
385 resp->msglen = htons(resplen);
386 resp->msgtype = htons(STUN_BINDRESP);
389 ret = AST_STUN_ACCEPT;
392 if (ast_debug_stun_packet_is_allowed)
393 ast_verbose(
"Dunno what to do with STUN message %04x (%s)\n", (
unsigned)ntohs(hdr->msgtype),
stun_msg2str(ntohs(hdr->msgtype)));
406 struct sockaddr_in *sa = (
struct sockaddr_in *)arg;
410 sa->sin_port = addr->port;
411 sa->sin_addr.s_addr = addr->addr;
416 const char *username,
struct sockaddr_in *answer)
420 unsigned char req_buf[1024];
421 unsigned char rsp_buf[1024];
429 memset(answer, 0,
sizeof(
struct sockaddr_in));
436 reqleft =
sizeof(req_buf) -
sizeof(
struct stun_header);
441 req->msglen = htons(reqlen);
444 for (retry = 0; retry++ < STUN_MAX_RETRIES;) {
446 struct sockaddr_in src;
448 struct timeval start;
453 ast_debug_stun(1,
"stun_send try %d failed: %s\n", retry, strerror(errno));
466 struct pollfd pfds = { .fd = s, .events = POLLIN };
472 handle_stun_timeout(retry, dst);
476 res = ast_poll(&pfds, 1, ms);
483 handle_stun_timeout(retry, dst);
490 memset(&src, 0,
sizeof(src));
491 srclen =
sizeof(src);
495 res = recvfrom(s, rsp_buf,
sizeof(rsp_buf) - 1,
496 0, (
struct sockaddr *) &src, &srclen);
498 ast_debug_stun(1,
"recvfrom try %d failed: %s\n", retry, strerror(errno));
505 || (rsp->msgtype != htons(STUN_BINDRESP)
506 && rsp->msgtype != htons(STUN_BINDERR))
507 || stun_id_cmp(&req->id, &rsp->id)) {
509 memset(answer, 0,
sizeof(
struct sockaddr_in));
525 e->
command =
"stun set debug {on|off}";
527 "Usage: stun set debug {on|off}\n"
528 " Enable/Disable STUN (Simple Traversal of UDP through NATs)\n"
535 if (a->argc != e->
args)
536 return CLI_SHOWUSAGE;
538 if (!strncasecmp(a->argv[e->
args-1],
"on", 2))
539 ast_debug_category_set_sublevel(AST_LOG_CATEGORY_STUN_PACKET, AST_LOG_CATEGORY_ENABLED);
540 else if (!strncasecmp(a->argv[e->
args-1],
"off", 3))
541 ast_debug_category_set_sublevel(AST_LOG_CATEGORY_STUN_PACKET, AST_LOG_CATEGORY_DISABLED);
543 return CLI_SHOWUSAGE;
545 ast_cli(a->fd,
"STUN Debugging %s\n", ast_debug_stun_packet_is_allowed ?
"Enabled" :
"Disabled");
550 AST_CLI_DEFINE(handle_cli_stun_set_debug,
"Enable/Disable STUN debugging"),
553 static uintmax_t debug_category_stun_id;
555 uintmax_t ast_debug_category_stun_id(
void)
557 return debug_category_stun_id;
560 static uintmax_t debug_category_stun_packet_id;
562 uintmax_t ast_debug_category_stun_packet_id(
void)
564 return debug_category_stun_packet_id;
567 static void stun_shutdown(
void)
571 ast_debug_category_unregister(AST_LOG_CATEGORY_STUN_PACKET);
572 ast_debug_category_unregister(AST_LOG_CATEGORY_STUN);
579 debug_category_stun_id = ast_debug_category_register(AST_LOG_CATEGORY_STUN);
580 debug_category_stun_packet_id = ast_debug_category_register(AST_LOG_CATEGORY_STUN_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.
Asterisk main include file. File version handling, generic pbx functions.
static const char * stun_msg2str(int msg)
helper function to print message names
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define STUN_MAPPED_ADDRESS
Basic attribute types in stun messages. Messages can also contain custom attributes (codes above 0x7f...
descriptor for a cli entry.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
int ast_stun_request(int s, struct sockaddr_in *dst, const char *username, struct sockaddr_in *answer)
Generic STUN request.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
int args
This gets set in ast_cli_register()
void ast_stun_init(void)
Initialize the STUN system in Asterisk.
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...
General Asterisk PBX channel definitions.
static void stun_req_id(struct stun_header *req)
helper function to generate a random request id
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
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
#define ast_debug_stun(sublevel,...)
Log debug level STUN information.
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
#define STUN_BINDREQ
STUN message types 'BIND' refers to transactions used to determine the externally visible addresses...
int( stun_cb_f)(struct stun_attr *attr, void *arg)
callback type to be invoked on stun responses.
here we store credentials extracted from a message
const char * ast_inet_ntoa(struct in_addr ia)
thread-safe replacement for inet_ntoa().
Support for logging to various files, console and syslog Configuration in file logger.conf.
Prototypes for public functions only of internal interest,.
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
static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
wrapper to send an STUN message
static const char * stun_attr2str(int msg)
helper function to print attribute names