Mon Aug 31 12:30:13 2015

Asterisk developer's documentation


stun.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2008, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*!
00020  * \file
00021  *
00022  * \brief STUN Support
00023  *
00024  * \author Mark Spencer <markster@digium.com>
00025  *
00026  * \note STUN is defined in RFC 3489.
00027  */
00028 
00029 /*** MODULEINFO
00030    <support_level>core</support_level>
00031  ***/
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $")
00036 
00037 #include "asterisk/_private.h"
00038 #include "asterisk/stun.h"
00039 #include "asterisk/cli.h"
00040 #include "asterisk/utils.h"
00041 #include "asterisk/channel.h"
00042 
00043 static int stundebug;         /*!< Are we debugging stun? */
00044 
00045 /*!
00046  * \brief STUN support code
00047  *
00048  * This code provides some support for doing STUN transactions.
00049  * Eventually it should be moved elsewhere as other protocols
00050  * than RTP can benefit from it - e.g. SIP.
00051  * STUN is described in RFC3489 and it is based on the exchange
00052  * of UDP packets between a client and one or more servers to
00053  * determine the externally visible address (and port) of the client
00054  * once it has gone through the NAT boxes that connect it to the
00055  * outside.
00056  * The simplest request packet is just the header defined in
00057  * struct stun_header, and from the response we may just look at
00058  * one attribute, STUN_MAPPED_ADDRESS, that we find in the response.
00059  * By doing more transactions with different server addresses we
00060  * may determine more about the behaviour of the NAT boxes, of
00061  * course - the details are in the RFC.
00062  *
00063  * All STUN packets start with a simple header made of a type,
00064  * length (excluding the header) and a 16-byte random transaction id.
00065  * Following the header we may have zero or more attributes, each
00066  * structured as a type, length and a value (whose format depends
00067  * on the type, but often contains addresses).
00068  * Of course all fields are in network format.
00069  */
00070 
00071 typedef struct { unsigned int id[4]; } __attribute__((packed)) stun_trans_id;
00072 
00073 struct stun_header {
00074    unsigned short msgtype;
00075    unsigned short msglen;
00076    stun_trans_id  id;
00077    unsigned char ies[0];
00078 } __attribute__((packed));
00079 
00080 struct stun_attr {
00081    unsigned short attr;
00082    unsigned short len;
00083    unsigned char value[0];
00084 } __attribute__((packed));
00085 
00086 /*
00087  * The format normally used for addresses carried by STUN messages.
00088  */
00089 struct stun_addr {
00090    unsigned char unused;
00091    unsigned char family;
00092    unsigned short port;
00093    unsigned int addr;
00094 } __attribute__((packed));
00095 
00096 /*! \brief STUN message types
00097  * 'BIND' refers to transactions used to determine the externally
00098  * visible addresses. 'SEC' refers to transactions used to establish
00099  * a session key for subsequent requests.
00100  * 'SEC' functionality is not supported here.
00101  */
00102 
00103 #define STUN_BINDREQ 0x0001
00104 #define STUN_BINDRESP   0x0101
00105 #define STUN_BINDERR 0x0111
00106 #define STUN_SECREQ  0x0002
00107 #define STUN_SECRESP 0x0102
00108 #define STUN_SECERR  0x0112
00109 
00110 /*! \brief Basic attribute types in stun messages.
00111  * Messages can also contain custom attributes (codes above 0x7fff)
00112  */
00113 #define STUN_MAPPED_ADDRESS   0x0001
00114 #define STUN_RESPONSE_ADDRESS 0x0002
00115 #define STUN_CHANGE_REQUEST   0x0003
00116 #define STUN_SOURCE_ADDRESS   0x0004
00117 #define STUN_CHANGED_ADDRESS  0x0005
00118 #define STUN_USERNAME      0x0006
00119 #define STUN_PASSWORD      0x0007
00120 #define STUN_MESSAGE_INTEGRITY   0x0008
00121 #define STUN_ERROR_CODE    0x0009
00122 #define STUN_UNKNOWN_ATTRIBUTES  0x000a
00123 #define STUN_REFLECTED_FROM   0x000b
00124 
00125 /*! \brief helper function to print message names */
00126 static const char *stun_msg2str(int msg)
00127 {
00128    switch (msg) {
00129    case STUN_BINDREQ:
00130       return "Binding Request";
00131    case STUN_BINDRESP:
00132       return "Binding Response";
00133    case STUN_BINDERR:
00134       return "Binding Error Response";
00135    case STUN_SECREQ:
00136       return "Shared Secret Request";
00137    case STUN_SECRESP:
00138       return "Shared Secret Response";
00139    case STUN_SECERR:
00140       return "Shared Secret Error Response";
00141    }
00142    return "Non-RFC3489 Message";
00143 }
00144 
00145 /*! \brief helper function to print attribute names */
00146 static const char *stun_attr2str(int msg)
00147 {
00148    switch (msg) {
00149    case STUN_MAPPED_ADDRESS:
00150       return "Mapped Address";
00151    case STUN_RESPONSE_ADDRESS:
00152       return "Response Address";
00153    case STUN_CHANGE_REQUEST:
00154       return "Change Request";
00155    case STUN_SOURCE_ADDRESS:
00156       return "Source Address";
00157    case STUN_CHANGED_ADDRESS:
00158       return "Changed Address";
00159    case STUN_USERNAME:
00160       return "Username";
00161    case STUN_PASSWORD:
00162       return "Password";
00163    case STUN_MESSAGE_INTEGRITY:
00164       return "Message Integrity";
00165    case STUN_ERROR_CODE:
00166       return "Error Code";
00167    case STUN_UNKNOWN_ATTRIBUTES:
00168       return "Unknown Attributes";
00169    case STUN_REFLECTED_FROM:
00170       return "Reflected From";
00171    }
00172    return "Non-RFC3489 Attribute";
00173 }
00174 
00175 /*! \brief here we store credentials extracted from a message */
00176 struct stun_state {
00177    const char *username;
00178    const char *password;
00179 };
00180 
00181 static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
00182 {
00183    if (stundebug)
00184       ast_verbose("Found STUN Attribute %s (%04x), length %d\n",
00185              stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr), ntohs(attr->len));
00186    switch (ntohs(attr->attr)) {
00187    case STUN_USERNAME:
00188       state->username = (const char *) (attr->value);
00189       break;
00190    case STUN_PASSWORD:
00191       state->password = (const char *) (attr->value);
00192       break;
00193    default:
00194       if (stundebug)
00195          ast_verbose("Ignoring STUN attribute %s (%04x), length %d\n",
00196                 stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr), ntohs(attr->len));
00197    }
00198    return 0;
00199 }
00200 
00201 /*! \brief append a string to an STUN message */
00202 static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left)
00203 {
00204    int size = sizeof(**attr) + strlen(s);
00205    if (*left > size) {
00206       (*attr)->attr = htons(attrval);
00207       (*attr)->len = htons(strlen(s));
00208       memcpy((*attr)->value, s, strlen(s));
00209       (*attr) = (struct stun_attr *)((*attr)->value + strlen(s));
00210       *len += size;
00211       *left -= size;
00212    }
00213 }
00214 
00215 /*! \brief append an address to an STUN message */
00216 static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sin, int *len, int *left)
00217 {
00218    int size = sizeof(**attr) + 8;
00219    struct stun_addr *addr;
00220    if (*left > size) {
00221       (*attr)->attr = htons(attrval);
00222       (*attr)->len = htons(8);
00223       addr = (struct stun_addr *)((*attr)->value);
00224       addr->unused = 0;
00225       addr->family = 0x01;
00226       addr->port = sin->sin_port;
00227       addr->addr = sin->sin_addr.s_addr;
00228       (*attr) = (struct stun_attr *)((*attr)->value + 8);
00229       *len += size;
00230       *left -= size;
00231    }
00232 }
00233 
00234 /*! \brief wrapper to send an STUN message */
00235 static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
00236 {
00237    return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0,
00238             (struct sockaddr *)dst, sizeof(*dst));
00239 }
00240 
00241 /*!
00242  * \internal
00243  * \brief Compare the STUN tranaction IDs.
00244  *
00245  * \param left Transaction ID.
00246  * \param right Transaction ID.
00247  *
00248  * \retval 0 if match.
00249  * \retval non-zero if not match.
00250  */
00251 static int stun_id_cmp(stun_trans_id *left, stun_trans_id *right)
00252 {
00253    return memcmp(left, right, sizeof(*left));
00254 }
00255 
00256 /*! \brief helper function to generate a random request id */
00257 static void stun_req_id(struct stun_header *req)
00258 {
00259    int x;
00260    for (x = 0; x < 4; x++)
00261       req->id.id[x] = ast_random();
00262 }
00263 
00264 int ast_stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)
00265 {
00266    struct stun_header *hdr = (struct stun_header *)data;
00267    struct stun_attr *attr;
00268    struct stun_state st;
00269    int ret = AST_STUN_IGNORE;
00270    int x;
00271 
00272    /* On entry, 'len' is the length of the udp payload. After the
00273     * initial checks it becomes the size of unprocessed options,
00274     * while 'data' is advanced accordingly.
00275     */
00276    if (len < sizeof(struct stun_header)) {
00277       ast_debug(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
00278       return -1;
00279    }
00280    len -= sizeof(struct stun_header);
00281    data += sizeof(struct stun_header);
00282    x = ntohs(hdr->msglen); /* len as advertised in the message */
00283    if (stundebug)
00284       ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), (unsigned)ntohs(hdr->msgtype), x);
00285    if (x > len) {
00286       ast_debug(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
00287    } else
00288       len = x;
00289    memset(&st, 0, sizeof(st));
00290    while (len) {
00291       if (len < sizeof(struct stun_attr)) {
00292          ast_debug(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
00293          break;
00294       }
00295       attr = (struct stun_attr *)data;
00296       /* compute total attribute length */
00297       x = ntohs(attr->len) + sizeof(struct stun_attr);
00298       if (x > len) {
00299          ast_debug(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
00300          break;
00301       }
00302       if (stun_cb)
00303          stun_cb(attr, arg);
00304       if (stun_process_attr(&st, attr)) {
00305          ast_debug(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr));
00306          break;
00307       }
00308       /* Clear attribute id: in case previous entry was a string,
00309        * this will act as the terminator for the string.
00310        */
00311       attr->attr = 0;
00312       data += x;
00313       len -= x;
00314    }
00315    /* Null terminate any string.
00316     * XXX NOTE, we write past the size of the buffer passed by the
00317     * caller, so this is potentially dangerous. The only thing that
00318     * saves us is that usually we read the incoming message in a
00319     * much larger buffer in the struct ast_rtp
00320     */
00321    *data = '\0';
00322 
00323    /* Now prepare to generate a reply, which at the moment is done
00324     * only for properly formed (len == 0) STUN_BINDREQ messages.
00325     */
00326    if (len == 0) {
00327       unsigned char respdata[1024];
00328       struct stun_header *resp = (struct stun_header *)respdata;
00329       int resplen = 0;  /* len excluding header */
00330       int respleft = sizeof(respdata) - sizeof(struct stun_header);
00331 
00332       resp->id = hdr->id;
00333       resp->msgtype = 0;
00334       resp->msglen = 0;
00335       attr = (struct stun_attr *)resp->ies;
00336       switch (ntohs(hdr->msgtype)) {
00337       case STUN_BINDREQ:
00338          if (stundebug)
00339             ast_verbose("STUN Bind Request, username: %s\n",
00340                    st.username ? st.username : "<none>");
00341          if (st.username)
00342             append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
00343          append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft);
00344          resp->msglen = htons(resplen);
00345          resp->msgtype = htons(STUN_BINDRESP);
00346          stun_send(s, src, resp);
00347          ret = AST_STUN_ACCEPT;
00348          break;
00349       default:
00350          if (stundebug)
00351             ast_verbose("Dunno what to do with STUN message %04x (%s)\n", (unsigned)ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
00352       }
00353    }
00354    return ret;
00355 }
00356 
00357 /*! \brief Extract the STUN_MAPPED_ADDRESS from the stun response.
00358  * This is used as a callback for stun_handle_response
00359  * when called from ast_stun_request.
00360  */
00361 static int stun_get_mapped(struct stun_attr *attr, void *arg)
00362 {
00363    struct stun_addr *addr = (struct stun_addr *)(attr + 1);
00364    struct sockaddr_in *sa = (struct sockaddr_in *)arg;
00365 
00366    if (ntohs(attr->attr) != STUN_MAPPED_ADDRESS || ntohs(attr->len) != 8)
00367       return 1;   /* not us. */
00368    sa->sin_port = addr->port;
00369    sa->sin_addr.s_addr = addr->addr;
00370    return 0;
00371 }
00372 
00373 int ast_stun_request(int s, struct sockaddr_in *dst,
00374    const char *username, struct sockaddr_in *answer)
00375 {
00376    struct stun_header *req;
00377    struct stun_header *rsp;
00378    unsigned char req_buf[1024];
00379    unsigned char rsp_buf[1024];
00380    int reqlen, reqleft;
00381    struct stun_attr *attr;
00382    int res = -1;
00383    int retry;
00384 
00385    if (answer) {
00386       /* Always clear answer in case the request fails. */
00387       memset(answer, 0, sizeof(struct sockaddr_in));
00388    }
00389 
00390    /* Create STUN bind request */
00391    req = (struct stun_header *) req_buf;
00392    stun_req_id(req);
00393    reqlen = 0;
00394    reqleft = sizeof(req_buf) - sizeof(struct stun_header);
00395    req->msgtype = 0;
00396    req->msglen = 0;
00397    attr = (struct stun_attr *) req->ies;
00398    if (username) {
00399       append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft);
00400    }
00401    req->msglen = htons(reqlen);
00402    req->msgtype = htons(STUN_BINDREQ);
00403 
00404    for (retry = 0; retry++ < 3;) {  /* XXX make retries configurable */
00405       /* send request, possibly wait for reply */
00406       struct sockaddr_in src;
00407       socklen_t srclen;
00408 
00409       /* Send STUN message. */
00410       res = stun_send(s, dst, req);
00411       if (res < 0) {
00412          ast_debug(1, "stun_send try %d failed: %s\n", retry, strerror(errno));
00413          break;
00414       }
00415       if (!answer) {
00416          /* Successful send since we don't care about any response. */
00417          res = 0;
00418          break;
00419       }
00420 
00421 try_again:
00422       /* Wait for response. */
00423       {
00424          struct pollfd pfds = { .fd = s, .events = POLLIN };
00425 
00426          res = ast_poll(&pfds, 1, 3000);
00427          if (res < 0) {
00428             /* Error */
00429             continue;
00430          }
00431          if (!res) {
00432             /* No response, timeout */
00433             res = 1;
00434             continue;
00435          }
00436       }
00437 
00438       /* Read STUN response. */
00439       memset(&src, 0, sizeof(src));
00440       srclen = sizeof(src);
00441       /* XXX pass sizeof(rsp_buf) - 1 in the size, because stun_handle_packet might
00442        * write past the end of the buffer.
00443        */
00444       res = recvfrom(s, rsp_buf, sizeof(rsp_buf) - 1,
00445          0, (struct sockaddr *) &src, &srclen);
00446       if (res < 0) {
00447          ast_debug(1, "recvfrom try %d failed: %s\n", retry, strerror(errno));
00448          break;
00449       }
00450 
00451       /* Process the STUN response. */
00452       rsp = (struct stun_header *) rsp_buf;
00453       if (ast_stun_handle_packet(s, &src, rsp_buf, res, stun_get_mapped, answer)
00454          || (rsp->msgtype != htons(STUN_BINDRESP)
00455             && rsp->msgtype != htons(STUN_BINDERR))
00456          || stun_id_cmp(&req->id, &rsp->id)) {
00457          /* Bad STUN packet, not right type, or transaction ID did not match. */
00458          memset(answer, 0, sizeof(struct sockaddr_in));
00459 
00460          /* Was not a resonse to our request. */
00461          goto try_again;
00462       }
00463       /* Success.  answer contains the external address if available. */
00464       res = 0;
00465       break;
00466    }
00467    return res;
00468 }
00469 
00470 static char *handle_cli_stun_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00471 {
00472    switch (cmd) {
00473    case CLI_INIT:
00474       e->command = "stun set debug {on|off}";
00475       e->usage =
00476          "Usage: stun set debug {on|off}\n"
00477          "       Enable/Disable STUN (Simple Traversal of UDP through NATs)\n"
00478          "       debugging\n";
00479       return NULL;
00480    case CLI_GENERATE:
00481       return NULL;
00482    }
00483 
00484    if (a->argc != e->args)
00485       return CLI_SHOWUSAGE;
00486 
00487    if (!strncasecmp(a->argv[e->args-1], "on", 2))
00488       stundebug = 1;
00489    else if (!strncasecmp(a->argv[e->args-1], "off", 3))
00490       stundebug = 0;
00491    else
00492       return CLI_SHOWUSAGE;
00493 
00494    ast_cli(a->fd, "STUN Debugging %s\n", stundebug ? "Enabled" : "Disabled");
00495    return CLI_SUCCESS;
00496 }
00497 
00498 static struct ast_cli_entry cli_stun[] = {
00499    AST_CLI_DEFINE(handle_cli_stun_set_debug, "Enable/Disable STUN debugging"),
00500 };
00501 
00502 static void stun_shutdown(void)
00503 {
00504    ast_cli_unregister_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
00505 }
00506 
00507 /*! \brief Initialize the STUN system in Asterisk */
00508 void ast_stun_init(void)
00509 {
00510    ast_cli_register_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
00511    ast_register_atexit(stun_shutdown);
00512 }

Generated on 31 Aug 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1