STUN support. More...
#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 |
| enum ast_stun_result |
Definition at line 37 of file stun.h.
{
AST_STUN_IGNORE = 0,
AST_STUN_ACCEPT,
};
| 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_attr::len, stun_header::msglen, stun_header::msgtype, 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_rtp_read(), and ast_stun_request().
{
struct stun_header *hdr = (struct stun_header *)data;
struct stun_attr *attr;
struct stun_state st;
int ret = AST_STUN_IGNORE;
int x;
/* On entry, 'len' is the length of the udp payload. After the
* initial checks it becomes the size of unprocessed options,
* while 'data' is advanced accordingly.
*/
if (len < sizeof(struct stun_header)) {
ast_debug(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
return -1;
}
len -= sizeof(struct stun_header);
data += sizeof(struct stun_header);
x = ntohs(hdr->msglen); /* len as advertised in the message */
if (stundebug)
ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), x);
if (x > len) {
ast_debug(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
} else
len = x;
memset(&st, 0, sizeof(st));
while (len) {
if (len < sizeof(struct stun_attr)) {
ast_debug(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
break;
}
attr = (struct stun_attr *)data;
/* compute total attribute length */
x = ntohs(attr->len) + sizeof(struct stun_attr);
if (x > len) {
ast_debug(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
break;
}
if (stun_cb)
stun_cb(attr, arg);
if (stun_process_attr(&st, attr)) {
ast_debug(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr));
break;
}
/* Clear attribute id: in case previous entry was a string,
* this will act as the terminator for the string.
*/
attr->attr = 0;
data += x;
len -= x;
}
/* Null terminate any string.
* XXX NOTE, we write past the size of the buffer passed by the
* caller, so this is potentially dangerous. The only thing that
* saves us is that usually we read the incoming message in a
* much larger buffer in the struct ast_rtp
*/
*data = '\0';
/* Now prepare to generate a reply, which at the moment is done
* only for properly formed (len == 0) STUN_BINDREQ messages.
*/
if (len == 0) {
unsigned char respdata[1024];
struct stun_header *resp = (struct stun_header *)respdata;
int resplen = 0; /* len excluding header */
int respleft = sizeof(respdata) - sizeof(struct stun_header);
resp->id = hdr->id;
resp->msgtype = 0;
resp->msglen = 0;
attr = (struct stun_attr *)resp->ies;
switch (ntohs(hdr->msgtype)) {
case STUN_BINDREQ:
if (stundebug)
ast_verbose("STUN Bind Request, username: %s\n",
st.username ? st.username : "<none>");
if (st.username)
append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft);
resp->msglen = htons(resplen);
resp->msgtype = htons(STUN_BINDRESP);
stun_send(s, src, resp);
ret = AST_STUN_ACCEPT;
break;
default:
if (stundebug)
ast_verbose("Dunno what to do with STUN message %04x (%s)\n", ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
}
}
return ret;
}
| 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. |
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, stun_header::ies, LOG_WARNING, stun_header::msglen, stun_header::msgtype, 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().
{
struct stun_header *req;
unsigned char reqdata[1024];
int reqlen, reqleft;
struct stun_attr *attr;
int res = 0;
int retry;
req = (struct stun_header *)reqdata;
stun_req_id(req);
reqlen = 0;
reqleft = sizeof(reqdata) - sizeof(struct stun_header);
req->msgtype = 0;
req->msglen = 0;
attr = (struct stun_attr *)req->ies;
if (username)
append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft);
req->msglen = htons(reqlen);
req->msgtype = htons(STUN_BINDREQ);
for (retry = 0; retry < 3; retry++) { /* XXX make retries configurable */
/* send request, possibly wait for reply */
unsigned char reply_buf[1024];
struct pollfd pfds = { .fd = s, .events = POLLIN };
struct sockaddr_in src;
socklen_t srclen;
res = stun_send(s, dst, req);
if (res < 0) {
ast_log(LOG_WARNING, "ast_stun_request send #%d failed error %d, retry\n",
retry, res);
continue;
}
if (answer == NULL)
break;
res = ast_poll(&pfds, 1, 3000);
if (res <= 0) /* timeout or error */
continue;
memset(&src, 0, sizeof(src));
srclen = sizeof(src);
/* XXX pass -1 in the size, because stun_handle_packet might
* write past the end of the buffer.
*/
res = recvfrom(s, reply_buf, sizeof(reply_buf) - 1,
0, (struct sockaddr *)&src, &srclen);
if (res < 0) {
ast_log(LOG_WARNING, "ast_stun_request recvfrom #%d failed error %d, retry\n",
retry, res);
continue;
}
memset(answer, 0, sizeof(struct sockaddr_in));
ast_stun_handle_packet(s, &src, reply_buf, res,
stun_get_mapped, answer);
res = 0; /* signal regular exit */
break;
}
return res;
}
const int STANDARD_STUN_PORT = 3478 [static] |
Definition at line 35 of file stun.h.
Referenced by gtalk_load_config(), and load_config().