2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2008, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
24 * \author Mark Spencer <markster@digium.com>
26 * \note STUN is defined in RFC 3489.
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33 #include "asterisk/_private.h"
34 #include "asterisk/stun.h"
35 #include "asterisk/cli.h"
36 #include "asterisk/utils.h"
37 #include "asterisk/channel.h"
39 static int stundebug; /*!< Are we debugging stun? */
42 * \brief STUN support code
44 * This code provides some support for doing STUN transactions.
45 * Eventually it should be moved elsewhere as other protocols
46 * than RTP can benefit from it - e.g. SIP.
47 * STUN is described in RFC3489 and it is based on the exchange
48 * of UDP packets between a client and one or more servers to
49 * determine the externally visible address (and port) of the client
50 * once it has gone through the NAT boxes that connect it to the
52 * The simplest request packet is just the header defined in
53 * struct stun_header, and from the response we may just look at
54 * one attribute, STUN_MAPPED_ADDRESS, that we find in the response.
55 * By doing more transactions with different server addresses we
56 * may determine more about the behaviour of the NAT boxes, of
57 * course - the details are in the RFC.
59 * All STUN packets start with a simple header made of a type,
60 * length (excluding the header) and a 16-byte random transaction id.
61 * Following the header we may have zero or more attributes, each
62 * structured as a type, length and a value (whose format depends
63 * on the type, but often contains addresses).
64 * Of course all fields are in network format.
67 typedef struct { unsigned int id[4]; } __attribute__((packed)) stun_trans_id;
70 unsigned short msgtype;
71 unsigned short msglen;
74 } __attribute__((packed));
79 unsigned char value[0];
80 } __attribute__((packed));
83 * The format normally used for addresses carried by STUN messages.
90 } __attribute__((packed));
92 /*! \brief STUN message types
93 * 'BIND' refers to transactions used to determine the externally
94 * visible addresses. 'SEC' refers to transactions used to establish
95 * a session key for subsequent requests.
96 * 'SEC' functionality is not supported here.
99 #define STUN_BINDREQ 0x0001
100 #define STUN_BINDRESP 0x0101
101 #define STUN_BINDERR 0x0111
102 #define STUN_SECREQ 0x0002
103 #define STUN_SECRESP 0x0102
104 #define STUN_SECERR 0x0112
106 /*! \brief Basic attribute types in stun messages.
107 * Messages can also contain custom attributes (codes above 0x7fff)
109 #define STUN_MAPPED_ADDRESS 0x0001
110 #define STUN_RESPONSE_ADDRESS 0x0002
111 #define STUN_CHANGE_REQUEST 0x0003
112 #define STUN_SOURCE_ADDRESS 0x0004
113 #define STUN_CHANGED_ADDRESS 0x0005
114 #define STUN_USERNAME 0x0006
115 #define STUN_PASSWORD 0x0007
116 #define STUN_MESSAGE_INTEGRITY 0x0008
117 #define STUN_ERROR_CODE 0x0009
118 #define STUN_UNKNOWN_ATTRIBUTES 0x000a
119 #define STUN_REFLECTED_FROM 0x000b
121 /*! \brief helper function to print message names */
122 static const char *stun_msg2str(int msg)
126 return "Binding Request";
128 return "Binding Response";
130 return "Binding Error Response";
132 return "Shared Secret Request";
134 return "Shared Secret Response";
136 return "Shared Secret Error Response";
138 return "Non-RFC3489 Message";
141 /*! \brief helper function to print attribute names */
142 static const char *stun_attr2str(int msg)
145 case STUN_MAPPED_ADDRESS:
146 return "Mapped Address";
147 case STUN_RESPONSE_ADDRESS:
148 return "Response Address";
149 case STUN_CHANGE_REQUEST:
150 return "Change Request";
151 case STUN_SOURCE_ADDRESS:
152 return "Source Address";
153 case STUN_CHANGED_ADDRESS:
154 return "Changed Address";
159 case STUN_MESSAGE_INTEGRITY:
160 return "Message Integrity";
161 case STUN_ERROR_CODE:
163 case STUN_UNKNOWN_ATTRIBUTES:
164 return "Unknown Attributes";
165 case STUN_REFLECTED_FROM:
166 return "Reflected From";
168 return "Non-RFC3489 Attribute";
171 /*! \brief here we store credentials extracted from a message */
173 const char *username;
174 const char *password;
177 static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
180 ast_verbose("Found STUN Attribute %s (%04x), length %d\n",
181 stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
182 switch (ntohs(attr->attr)) {
184 state->username = (const char *) (attr->value);
187 state->password = (const char *) (attr->value);
191 ast_verbose("Ignoring STUN attribute %s (%04x), length %d\n",
192 stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
197 /*! \brief append a string to an STUN message */
198 static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left)
200 int size = sizeof(**attr) + strlen(s);
202 (*attr)->attr = htons(attrval);
203 (*attr)->len = htons(strlen(s));
204 memcpy((*attr)->value, s, strlen(s));
205 (*attr) = (struct stun_attr *)((*attr)->value + strlen(s));
211 /*! \brief append an address to an STUN message */
212 static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sin, int *len, int *left)
214 int size = sizeof(**attr) + 8;
215 struct stun_addr *addr;
217 (*attr)->attr = htons(attrval);
218 (*attr)->len = htons(8);
219 addr = (struct stun_addr *)((*attr)->value);
222 addr->port = sin->sin_port;
223 addr->addr = sin->sin_addr.s_addr;
224 (*attr) = (struct stun_attr *)((*attr)->value + 8);
230 /*! \brief wrapper to send an STUN message */
231 static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
233 return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0,
234 (struct sockaddr *)dst, sizeof(*dst));
239 * \brief Compare the STUN tranaction IDs.
241 * \param left Transaction ID.
242 * \param right Transaction ID.
244 * \retval 0 if match.
245 * \retval non-zero if not match.
247 static int stun_id_cmp(stun_trans_id *left, stun_trans_id *right)
249 return memcmp(left, right, sizeof(*left));
252 /*! \brief helper function to generate a random request id */
253 static void stun_req_id(struct stun_header *req)
256 for (x = 0; x < 4; x++)
257 req->id.id[x] = ast_random();
260 int ast_stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)
262 struct stun_header *hdr = (struct stun_header *)data;
263 struct stun_attr *attr;
264 struct stun_state st;
265 int ret = AST_STUN_IGNORE;
268 /* On entry, 'len' is the length of the udp payload. After the
269 * initial checks it becomes the size of unprocessed options,
270 * while 'data' is advanced accordingly.
272 if (len < sizeof(struct stun_header)) {
273 ast_debug(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
276 len -= sizeof(struct stun_header);
277 data += sizeof(struct stun_header);
278 x = ntohs(hdr->msglen); /* len as advertised in the message */
280 ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), x);
282 ast_debug(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
285 memset(&st, 0, sizeof(st));
287 if (len < sizeof(struct stun_attr)) {
288 ast_debug(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
291 attr = (struct stun_attr *)data;
292 /* compute total attribute length */
293 x = ntohs(attr->len) + sizeof(struct stun_attr);
295 ast_debug(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
300 if (stun_process_attr(&st, attr)) {
301 ast_debug(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr));
304 /* Clear attribute id: in case previous entry was a string,
305 * this will act as the terminator for the string.
311 /* Null terminate any string.
312 * XXX NOTE, we write past the size of the buffer passed by the
313 * caller, so this is potentially dangerous. The only thing that
314 * saves us is that usually we read the incoming message in a
315 * much larger buffer in the struct ast_rtp
319 /* Now prepare to generate a reply, which at the moment is done
320 * only for properly formed (len == 0) STUN_BINDREQ messages.
323 unsigned char respdata[1024];
324 struct stun_header *resp = (struct stun_header *)respdata;
325 int resplen = 0; /* len excluding header */
326 int respleft = sizeof(respdata) - sizeof(struct stun_header);
331 attr = (struct stun_attr *)resp->ies;
332 switch (ntohs(hdr->msgtype)) {
335 ast_verbose("STUN Bind Request, username: %s\n",
336 st.username ? st.username : "<none>");
338 append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
339 append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft);
340 resp->msglen = htons(resplen);
341 resp->msgtype = htons(STUN_BINDRESP);
342 stun_send(s, src, resp);
343 ret = AST_STUN_ACCEPT;
347 ast_verbose("Dunno what to do with STUN message %04x (%s)\n", ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
353 /*! \brief Extract the STUN_MAPPED_ADDRESS from the stun response.
354 * This is used as a callback for stun_handle_response
355 * when called from ast_stun_request.
357 static int stun_get_mapped(struct stun_attr *attr, void *arg)
359 struct stun_addr *addr = (struct stun_addr *)(attr + 1);
360 struct sockaddr_in *sa = (struct sockaddr_in *)arg;
362 if (ntohs(attr->attr) != STUN_MAPPED_ADDRESS || ntohs(attr->len) != 8)
363 return 1; /* not us. */
364 sa->sin_port = addr->port;
365 sa->sin_addr.s_addr = addr->addr;
369 int ast_stun_request(int s, struct sockaddr_in *dst,
370 const char *username, struct sockaddr_in *answer)
372 struct stun_header *req;
373 struct stun_header *rsp;
374 unsigned char req_buf[1024];
375 unsigned char rsp_buf[1024];
377 struct stun_attr *attr;
382 /* Always clear answer in case the request fails. */
383 memset(answer, 0, sizeof(struct sockaddr_in));
386 /* Create STUN bind request */
387 req = (struct stun_header *) req_buf;
390 reqleft = sizeof(req_buf) - sizeof(struct stun_header);
393 attr = (struct stun_attr *) req->ies;
395 append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft);
397 req->msglen = htons(reqlen);
398 req->msgtype = htons(STUN_BINDREQ);
400 for (retry = 0; retry++ < 3;) { /* XXX make retries configurable */
401 /* send request, possibly wait for reply */
402 struct sockaddr_in src;
405 /* Send STUN message. */
406 res = stun_send(s, dst, req);
408 ast_debug(1, "stun_send try %d failed: %s\n", retry, strerror(errno));
412 /* Successful send since we don't care about any response. */
418 /* Wait for response. */
420 struct pollfd pfds = { .fd = s, .events = POLLIN };
422 res = ast_poll(&pfds, 1, 3000);
428 /* No response, timeout */
434 /* Read STUN response. */
435 memset(&src, 0, sizeof(src));
436 srclen = sizeof(src);
437 /* XXX pass sizeof(rsp_buf) - 1 in the size, because stun_handle_packet might
438 * write past the end of the buffer.
440 res = recvfrom(s, rsp_buf, sizeof(rsp_buf) - 1,
441 0, (struct sockaddr *) &src, &srclen);
443 ast_debug(1, "recvfrom try %d failed: %s\n", retry, strerror(errno));
447 /* Process the STUN response. */
448 rsp = (struct stun_header *) rsp_buf;
449 if (ast_stun_handle_packet(s, &src, rsp_buf, res, stun_get_mapped, answer)
450 || (rsp->msgtype != htons(STUN_BINDRESP)
451 && rsp->msgtype != htons(STUN_BINDERR))
452 || stun_id_cmp(&req->id, &rsp->id)) {
453 /* Bad STUN packet, not right type, or transaction ID did not match. */
454 memset(answer, 0, sizeof(struct sockaddr_in));
456 /* Was not a resonse to our request. */
459 /* Success. answer contains the external address if available. */
466 static char *handle_cli_stun_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
470 e->command = "stun set debug {on|off}";
472 "Usage: stun set debug {on|off}\n"
473 " Enable/Disable STUN (Simple Traversal of UDP through NATs)\n"
480 if (a->argc != e->args)
481 return CLI_SHOWUSAGE;
483 if (!strncasecmp(a->argv[e->args-1], "on", 2))
485 else if (!strncasecmp(a->argv[e->args-1], "off", 3))
488 return CLI_SHOWUSAGE;
490 ast_cli(a->fd, "STUN Debugging %s\n", stundebug ? "Enabled" : "Disabled");
494 static struct ast_cli_entry cli_stun[] = {
495 AST_CLI_DEFINE(handle_cli_stun_set_debug, "Enable/Disable STUN debugging"),
498 /*! \brief Initialize the STUN system in Asterisk */
499 void ast_stun_init(void)
501 ast_cli_register_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));