#include "asterisk/network.h"
Go to the source code of this file.
Typedefs | |
typedef int( | stun_cb_f )(struct stun_attr *attr, void *arg) |
callback type to be invoked on stun responses. | |
Enumerations | |
enum | ast_stun_result { AST_STUN_IGNORE = 0, AST_STUN_ACCEPT } |
Functions | |
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. | |
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. | |
Variables | |
static const int | STANDARD_STUN_PORT = 3478 |
STUN is defined in RFC 3489.
Definition in file stun.h.
enum ast_stun_result |
Definition at line 37 of file stun.h.
00037 { 00038 AST_STUN_IGNORE = 0, 00039 AST_STUN_ACCEPT, 00040 };
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 }
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 }
const int STANDARD_STUN_PORT = 3478 [static] |