Mon Jun 27 16:51:21 2011

Asterisk developer's documentation


stun.c File Reference

STUN Support. More...

#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


Detailed Description

STUN Support.

Author:
Mark Spencer <markster@digium.com>
Note:
STUN is defined in RFC 3489.

Definition in file stun.c.


Define Documentation

#define STUN_BINDERR   0x0111

Definition at line 101 of file stun.c.

Referenced by stun_msg2str().

#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

Definition at line 100 of file stun.c.

Referenced by ast_stun_handle_packet(), and stun_msg2str().

#define STUN_CHANGE_REQUEST   0x0003

Definition at line 111 of file stun.c.

Referenced by stun_attr2str().

#define STUN_CHANGED_ADDRESS   0x0005

Definition at line 113 of file stun.c.

Referenced by stun_attr2str().

#define STUN_ERROR_CODE   0x0009

Definition at line 117 of file stun.c.

Referenced by stun_attr2str().

#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

Definition at line 116 of file stun.c.

Referenced by stun_attr2str().

#define STUN_PASSWORD   0x0007

Definition at line 115 of file stun.c.

Referenced by stun_attr2str(), and stun_process_attr().

#define STUN_REFLECTED_FROM   0x000b

Definition at line 119 of file stun.c.

Referenced by stun_attr2str().

#define STUN_RESPONSE_ADDRESS   0x0002

Definition at line 110 of file stun.c.

Referenced by stun_attr2str().

#define STUN_SECERR   0x0112

Definition at line 104 of file stun.c.

Referenced by stun_msg2str().

#define STUN_SECREQ   0x0002

Definition at line 102 of file stun.c.

Referenced by stun_msg2str().

#define STUN_SECRESP   0x0102

Definition at line 103 of file stun.c.

Referenced by stun_msg2str().

#define STUN_SOURCE_ADDRESS   0x0004

Definition at line 112 of file stun.c.

Referenced by stun_attr2str().

#define STUN_UNKNOWN_ATTRIBUTES   0x000a

Definition at line 118 of file stun.c.

Referenced by stun_attr2str().

#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().


Function Documentation

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.

Parameters:
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.
Returns:
0 on success, other values on error.

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 }


Variable Documentation

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().

int stundebug [static]

Are we debugging stun?

Definition at line 39 of file stun.c.


Generated on Mon Jun 27 16:51:21 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7