#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/stun.h"
#include "asterisk/cli.h"
#include "asterisk/utils.h"
#include "asterisk/channel.h"
Go to the source code of this file.
Data Structures | |
struct | stun_addr |
struct | stun_attr |
struct | stun_header |
struct | stun_state |
here we store credentials extracted from a message More... | |
struct | stun_trans_id |
STUN support code. More... | |
Defines | |
#define | STUN_BINDERR 0x0111 |
#define | STUN_BINDREQ 0x0001 |
STUN message types 'BIND' refers to transactions used to determine the externally visible addresses. 'SEC' refers to transactions used to establish a session key for subsequent requests. 'SEC' functionality is not supported here. | |
#define | STUN_BINDRESP 0x0101 |
#define | STUN_CHANGE_REQUEST 0x0003 |
#define | STUN_CHANGED_ADDRESS 0x0005 |
#define | STUN_ERROR_CODE 0x0009 |
#define | STUN_MAPPED_ADDRESS 0x0001 |
Basic attribute types in stun messages. Messages can also contain custom attributes (codes above 0x7fff). | |
#define | STUN_MESSAGE_INTEGRITY 0x0008 |
#define | STUN_PASSWORD 0x0007 |
#define | STUN_REFLECTED_FROM 0x000b |
#define | STUN_RESPONSE_ADDRESS 0x0002 |
#define | STUN_SECERR 0x0112 |
#define | STUN_SECREQ 0x0002 |
#define | STUN_SECRESP 0x0102 |
#define | STUN_SOURCE_ADDRESS 0x0004 |
#define | STUN_UNKNOWN_ATTRIBUTES 0x000a |
#define | STUN_USERNAME 0x0006 |
Functions | |
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 | |
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 | |
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. | |
void | ast_stun_init (void) |
Initialize the STUN system in Asterisk. | |
int | ast_stun_request (int s, struct sockaddr_in *dst, const char *username, struct sockaddr_in *answer) |
Generic STUN request send a generic stun request to the server specified. | |
static char * | handle_cli_stun_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static const char * | stun_attr2str (int msg) |
helper function to print attribute names | |
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_response when called from ast_stun_request. | |
static const char * | stun_msg2str (int msg) |
helper function to print message names | |
static int | stun_process_attr (struct stun_state *state, struct stun_attr *attr) |
static void | stun_req_id (struct stun_header *req) |
helper function to generate a random request id | |
static int | stun_send (int s, struct sockaddr_in *dst, struct stun_header *resp) |
wrapper to send an STUN message | |
Variables | |
static struct ast_cli_entry | cli_stun [] |
static int | stundebug |
Definition in file stun.c.
#define STUN_BINDERR 0x0111 |
#define STUN_BINDREQ 0x0001 |
STUN message types 'BIND' refers to transactions used to determine the externally visible addresses. 'SEC' refers to transactions used to establish a session key for subsequent requests. 'SEC' functionality is not supported here.
Definition at line 99 of file stun.c.
Referenced by ast_stun_handle_packet(), ast_stun_request(), and stun_msg2str().
#define STUN_BINDRESP 0x0101 |
#define STUN_CHANGE_REQUEST 0x0003 |
#define STUN_CHANGED_ADDRESS 0x0005 |
#define STUN_ERROR_CODE 0x0009 |
#define STUN_MAPPED_ADDRESS 0x0001 |
Basic attribute types in stun messages. Messages can also contain custom attributes (codes above 0x7fff).
Definition at line 109 of file stun.c.
Referenced by ast_stun_handle_packet(), stun_attr2str(), and stun_get_mapped().
#define STUN_MESSAGE_INTEGRITY 0x0008 |
#define STUN_PASSWORD 0x0007 |
#define STUN_REFLECTED_FROM 0x000b |
#define STUN_RESPONSE_ADDRESS 0x0002 |
#define STUN_SECERR 0x0112 |
#define STUN_SECREQ 0x0002 |
#define STUN_SECRESP 0x0102 |
#define STUN_SOURCE_ADDRESS 0x0004 |
#define STUN_UNKNOWN_ATTRIBUTES 0x000a |
#define STUN_USERNAME 0x0006 |
Definition at line 114 of file stun.c.
Referenced by ast_stun_handle_packet(), ast_stun_request(), stun_attr2str(), and stun_process_attr().
static void append_attr_address | ( | struct stun_attr ** | attr, | |
int | attrval, | |||
struct sockaddr_in * | sin, | |||
int * | len, | |||
int * | left | |||
) | [static] |
append an address to an STUN message
Definition at line 212 of file stun.c.
References stun_addr::addr.
Referenced by ast_stun_handle_packet().
00213 { 00214 int size = sizeof(**attr) + 8; 00215 struct stun_addr *addr; 00216 if (*left > size) { 00217 (*attr)->attr = htons(attrval); 00218 (*attr)->len = htons(8); 00219 addr = (struct stun_addr *)((*attr)->value); 00220 addr->unused = 0; 00221 addr->family = 0x01; 00222 addr->port = sin->sin_port; 00223 addr->addr = sin->sin_addr.s_addr; 00224 (*attr) = (struct stun_attr *)((*attr)->value + 8); 00225 *len += size; 00226 *left -= size; 00227 } 00228 }
static void append_attr_string | ( | struct stun_attr ** | attr, | |
int | attrval, | |||
const char * | s, | |||
int * | len, | |||
int * | left | |||
) | [static] |
append a string to an STUN message
Definition at line 198 of file stun.c.
Referenced by ast_stun_handle_packet(), and ast_stun_request().
00199 { 00200 int size = sizeof(**attr) + strlen(s); 00201 if (*left > size) { 00202 (*attr)->attr = htons(attrval); 00203 (*attr)->len = htons(strlen(s)); 00204 memcpy((*attr)->value, s, strlen(s)); 00205 (*attr) = (struct stun_attr *)((*attr)->value + strlen(s)); 00206 *len += size; 00207 *left -= size; 00208 } 00209 }
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.
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.
Definition at line 253 of file stun.c.
References append_attr_address(), append_attr_string(), ast_debug, AST_STUN_ACCEPT, AST_STUN_IGNORE, ast_verbose, stun_attr::attr, stun_header::id, stun_header::ies, stun_header::msglen, stun_header::msgtype, stun_attr2str(), STUN_BINDREQ, STUN_BINDRESP, STUN_MAPPED_ADDRESS, stun_msg2str(), stun_process_attr(), stun_send(), and STUN_USERNAME.
Referenced by ast_rtp_read(), and ast_stun_request().
00254 { 00255 struct stun_header *hdr = (struct stun_header *)data; 00256 struct stun_attr *attr; 00257 struct stun_state st; 00258 int ret = AST_STUN_IGNORE; 00259 int x; 00260 00261 /* On entry, 'len' is the length of the udp payload. After the 00262 * initial checks it becomes the size of unprocessed options, 00263 * while 'data' is advanced accordingly. 00264 */ 00265 if (len < sizeof(struct stun_header)) { 00266 ast_debug(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header)); 00267 return -1; 00268 } 00269 len -= sizeof(struct stun_header); 00270 data += sizeof(struct stun_header); 00271 x = ntohs(hdr->msglen); /* len as advertised in the message */ 00272 if (stundebug) 00273 ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), x); 00274 if (x > len) { 00275 ast_debug(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len); 00276 } else 00277 len = x; 00278 memset(&st, 0, sizeof(st)); 00279 while (len) { 00280 if (len < sizeof(struct stun_attr)) { 00281 ast_debug(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr)); 00282 break; 00283 } 00284 attr = (struct stun_attr *)data; 00285 /* compute total attribute length */ 00286 x = ntohs(attr->len) + sizeof(struct stun_attr); 00287 if (x > len) { 00288 ast_debug(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len); 00289 break; 00290 } 00291 if (stun_cb) 00292 stun_cb(attr, arg); 00293 if (stun_process_attr(&st, attr)) { 00294 ast_debug(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr)); 00295 break; 00296 } 00297 /* Clear attribute id: in case previous entry was a string, 00298 * this will act as the terminator for the string. 00299 */ 00300 attr->attr = 0; 00301 data += x; 00302 len -= x; 00303 } 00304 /* Null terminate any string. 00305 * XXX NOTE, we write past the size of the buffer passed by the 00306 * caller, so this is potentially dangerous. The only thing that 00307 * saves us is that usually we read the incoming message in a 00308 * much larger buffer in the struct ast_rtp 00309 */ 00310 *data = '\0'; 00311 00312 /* Now prepare to generate a reply, which at the moment is done 00313 * only for properly formed (len == 0) STUN_BINDREQ messages. 00314 */ 00315 if (len == 0) { 00316 unsigned char respdata[1024]; 00317 struct stun_header *resp = (struct stun_header *)respdata; 00318 int resplen = 0; /* len excluding header */ 00319 int respleft = sizeof(respdata) - sizeof(struct stun_header); 00320 00321 resp->id = hdr->id; 00322 resp->msgtype = 0; 00323 resp->msglen = 0; 00324 attr = (struct stun_attr *)resp->ies; 00325 switch (ntohs(hdr->msgtype)) { 00326 case STUN_BINDREQ: 00327 if (stundebug) 00328 ast_verbose("STUN Bind Request, username: %s\n", 00329 st.username ? st.username : "<none>"); 00330 if (st.username) 00331 append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft); 00332 append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft); 00333 resp->msglen = htons(resplen); 00334 resp->msgtype = htons(STUN_BINDRESP); 00335 stun_send(s, src, resp); 00336 ret = AST_STUN_ACCEPT; 00337 break; 00338 default: 00339 if (stundebug) 00340 ast_verbose("Dunno what to do with STUN message %04x (%s)\n", ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype))); 00341 } 00342 } 00343 return ret; 00344 }
void ast_stun_init | ( | void | ) |
Initialize the STUN system in Asterisk.
Provided by stun.c
Definition at line 469 of file stun.c.
References ast_cli_register_multiple(), and cli_stun.
Referenced by main().
00470 { 00471 ast_cli_register_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry)); 00472 }
int ast_stun_request | ( | int | s, | |
struct sockaddr_in * | dst, | |||
const char * | username, | |||
struct sockaddr_in * | answer | |||
) |
Generic STUN request send a generic stun request to the server specified.
s | the socket used to send the request | |
dst | the address of the STUN server | |
username | if non null, add the username in the request | |
answer | if non null, the function waits for a response and puts here the externally visible address. |
Definition at line 376 of file stun.c.
References append_attr_string(), ast_log(), ast_poll, ast_stun_handle_packet(), stun_attr::attr, LOG_WARNING, STUN_BINDREQ, stun_get_mapped(), stun_req_id(), stun_send(), and STUN_USERNAME.
Referenced by ast_rtp_stun_request(), gtalk_update_externip(), and stun_monitor_request().
00378 { 00379 struct stun_header *req; 00380 unsigned char reqdata[1024]; 00381 int reqlen, reqleft; 00382 struct stun_attr *attr; 00383 int res = 0; 00384 int retry; 00385 00386 req = (struct stun_header *)reqdata; 00387 stun_req_id(req); 00388 reqlen = 0; 00389 reqleft = sizeof(reqdata) - sizeof(struct stun_header); 00390 req->msgtype = 0; 00391 req->msglen = 0; 00392 attr = (struct stun_attr *)req->ies; 00393 if (username) 00394 append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft); 00395 req->msglen = htons(reqlen); 00396 req->msgtype = htons(STUN_BINDREQ); 00397 for (retry = 0; retry < 3; retry++) { /* XXX make retries configurable */ 00398 /* send request, possibly wait for reply */ 00399 unsigned char reply_buf[1024]; 00400 struct pollfd pfds = { .fd = s, .events = POLLIN }; 00401 struct sockaddr_in src; 00402 socklen_t srclen; 00403 00404 res = stun_send(s, dst, req); 00405 if (res < 0) { 00406 ast_log(LOG_WARNING, "ast_stun_request send #%d failed error %d, retry\n", 00407 retry, res); 00408 continue; 00409 } 00410 if (answer == NULL) 00411 break; 00412 res = ast_poll(&pfds, 1, 3000); 00413 if (res <= 0) /* timeout or error */ 00414 continue; 00415 memset(&src, 0, sizeof(src)); 00416 srclen = sizeof(src); 00417 /* XXX pass -1 in the size, because stun_handle_packet might 00418 * write past the end of the buffer. 00419 */ 00420 res = recvfrom(s, reply_buf, sizeof(reply_buf) - 1, 00421 0, (struct sockaddr *)&src, &srclen); 00422 if (res < 0) { 00423 ast_log(LOG_WARNING, "ast_stun_request recvfrom #%d failed error %d, retry\n", 00424 retry, res); 00425 continue; 00426 } 00427 memset(answer, 0, sizeof(struct sockaddr_in)); 00428 ast_stun_handle_packet(s, &src, reply_buf, res, 00429 stun_get_mapped, answer); 00430 res = 0; /* signal regular exit */ 00431 break; 00432 } 00433 return res; 00434 }
static char* handle_cli_stun_set_debug | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 436 of file stun.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.
00437 { 00438 switch (cmd) { 00439 case CLI_INIT: 00440 e->command = "stun set debug {on|off}"; 00441 e->usage = 00442 "Usage: stun set debug {on|off}\n" 00443 " Enable/Disable STUN (Simple Traversal of UDP through NATs)\n" 00444 " debugging\n"; 00445 return NULL; 00446 case CLI_GENERATE: 00447 return NULL; 00448 } 00449 00450 if (a->argc != e->args) 00451 return CLI_SHOWUSAGE; 00452 00453 if (!strncasecmp(a->argv[e->args-1], "on", 2)) 00454 stundebug = 1; 00455 else if (!strncasecmp(a->argv[e->args-1], "off", 3)) 00456 stundebug = 0; 00457 else 00458 return CLI_SHOWUSAGE; 00459 00460 ast_cli(a->fd, "STUN Debugging %s\n", stundebug ? "Enabled" : "Disabled"); 00461 return CLI_SUCCESS; 00462 }
static const char* stun_attr2str | ( | int | msg | ) | [static] |
helper function to print attribute names
Definition at line 142 of file stun.c.
References STUN_CHANGE_REQUEST, STUN_CHANGED_ADDRESS, STUN_ERROR_CODE, STUN_MAPPED_ADDRESS, STUN_MESSAGE_INTEGRITY, STUN_PASSWORD, STUN_REFLECTED_FROM, STUN_RESPONSE_ADDRESS, STUN_SOURCE_ADDRESS, STUN_UNKNOWN_ATTRIBUTES, and STUN_USERNAME.
Referenced by ast_stun_handle_packet(), and stun_process_attr().
00143 { 00144 switch (msg) { 00145 case STUN_MAPPED_ADDRESS: 00146 return "Mapped Address"; 00147 case STUN_RESPONSE_ADDRESS: 00148 return "Response Address"; 00149 case STUN_CHANGE_REQUEST: 00150 return "Change Request"; 00151 case STUN_SOURCE_ADDRESS: 00152 return "Source Address"; 00153 case STUN_CHANGED_ADDRESS: 00154 return "Changed Address"; 00155 case STUN_USERNAME: 00156 return "Username"; 00157 case STUN_PASSWORD: 00158 return "Password"; 00159 case STUN_MESSAGE_INTEGRITY: 00160 return "Message Integrity"; 00161 case STUN_ERROR_CODE: 00162 return "Error Code"; 00163 case STUN_UNKNOWN_ATTRIBUTES: 00164 return "Unknown Attributes"; 00165 case STUN_REFLECTED_FROM: 00166 return "Reflected From"; 00167 } 00168 return "Non-RFC3489 Attribute"; 00169 }
static int stun_get_mapped | ( | struct stun_attr * | attr, | |
void * | arg | |||
) | [static] |
Extract the STUN_MAPPED_ADDRESS from the stun response. This is used as a callback for stun_handle_response when called from ast_stun_request.
Definition at line 350 of file stun.c.
References stun_addr::addr, stun_attr::attr, stun_attr::len, stun_addr::port, and STUN_MAPPED_ADDRESS.
Referenced by ast_stun_request().
00351 { 00352 struct stun_addr *addr = (struct stun_addr *)(attr + 1); 00353 struct sockaddr_in *sa = (struct sockaddr_in *)arg; 00354 00355 if (ntohs(attr->attr) != STUN_MAPPED_ADDRESS || ntohs(attr->len) != 8) 00356 return 1; /* not us. */ 00357 sa->sin_port = addr->port; 00358 sa->sin_addr.s_addr = addr->addr; 00359 return 0; 00360 }
static const char* stun_msg2str | ( | int | msg | ) | [static] |
helper function to print message names
Definition at line 122 of file stun.c.
References STUN_BINDERR, STUN_BINDREQ, STUN_BINDRESP, STUN_SECERR, STUN_SECREQ, and STUN_SECRESP.
Referenced by ast_stun_handle_packet().
00123 { 00124 switch (msg) { 00125 case STUN_BINDREQ: 00126 return "Binding Request"; 00127 case STUN_BINDRESP: 00128 return "Binding Response"; 00129 case STUN_BINDERR: 00130 return "Binding Error Response"; 00131 case STUN_SECREQ: 00132 return "Shared Secret Request"; 00133 case STUN_SECRESP: 00134 return "Shared Secret Response"; 00135 case STUN_SECERR: 00136 return "Shared Secret Error Response"; 00137 } 00138 return "Non-RFC3489 Message"; 00139 }
static int stun_process_attr | ( | struct stun_state * | state, | |
struct stun_attr * | attr | |||
) | [static] |
Definition at line 177 of file stun.c.
References ast_verbose, stun_attr::attr, stun_attr::len, state, stun_attr2str(), STUN_PASSWORD, STUN_USERNAME, and stun_attr::value.
Referenced by ast_stun_handle_packet().
00178 { 00179 if (stundebug) 00180 ast_verbose("Found STUN Attribute %s (%04x), length %d\n", 00181 stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len)); 00182 switch (ntohs(attr->attr)) { 00183 case STUN_USERNAME: 00184 state->username = (const char *) (attr->value); 00185 break; 00186 case STUN_PASSWORD: 00187 state->password = (const char *) (attr->value); 00188 break; 00189 default: 00190 if (stundebug) 00191 ast_verbose("Ignoring STUN attribute %s (%04x), length %d\n", 00192 stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len)); 00193 } 00194 return 0; 00195 }
static void stun_req_id | ( | struct stun_header * | req | ) | [static] |
helper function to generate a random request id
Definition at line 238 of file stun.c.
References ast_random(), stun_trans_id::id, and stun_header::id.
Referenced by ast_stun_request().
00239 { 00240 int x; 00241 for (x = 0; x < 4; x++) 00242 req->id.id[x] = ast_random(); 00243 }
static int stun_send | ( | int | s, | |
struct sockaddr_in * | dst, | |||
struct stun_header * | resp | |||
) | [static] |
wrapper to send an STUN message
Definition at line 231 of file stun.c.
References stun_header::msglen.
Referenced by ast_stun_handle_packet(), and ast_stun_request().
00232 { 00233 return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0, 00234 (struct sockaddr *)dst, sizeof(*dst)); 00235 }
struct ast_cli_entry cli_stun[] [static] |
Initial value:
{ { .handler = handle_cli_stun_set_debug , .summary = "Enable/Disable STUN debugging" ,__VA_ARGS__ }, }
Definition at line 464 of file stun.c.
Referenced by ast_stun_init().