stun.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2008, Digium, Inc.
  5. *
  6. * Mark Spencer <markster@digium.com>
  7. *
  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.
  13. *
  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.
  17. */
  18. /*!
  19. * \file
  20. *
  21. * \brief STUN Support
  22. *
  23. * \author Mark Spencer <markster@digium.com>
  24. *
  25. * \note STUN is defined in RFC 3489.
  26. */
  27. /*** MODULEINFO
  28. <support_level>core</support_level>
  29. ***/
  30. #include "asterisk.h"
  31. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  32. #include "asterisk/_private.h"
  33. #include "asterisk/stun.h"
  34. #include "asterisk/cli.h"
  35. #include "asterisk/utils.h"
  36. #include "asterisk/channel.h"
  37. static int stundebug; /*!< Are we debugging stun? */
  38. /*!
  39. * \brief STUN support code
  40. *
  41. * This code provides some support for doing STUN transactions.
  42. * Eventually it should be moved elsewhere as other protocols
  43. * than RTP can benefit from it - e.g. SIP.
  44. * STUN is described in RFC3489 and it is based on the exchange
  45. * of UDP packets between a client and one or more servers to
  46. * determine the externally visible address (and port) of the client
  47. * once it has gone through the NAT boxes that connect it to the
  48. * outside.
  49. * The simplest request packet is just the header defined in
  50. * struct stun_header, and from the response we may just look at
  51. * one attribute, STUN_MAPPED_ADDRESS, that we find in the response.
  52. * By doing more transactions with different server addresses we
  53. * may determine more about the behaviour of the NAT boxes, of
  54. * course - the details are in the RFC.
  55. *
  56. * All STUN packets start with a simple header made of a type,
  57. * length (excluding the header) and a 16-byte random transaction id.
  58. * Following the header we may have zero or more attributes, each
  59. * structured as a type, length and a value (whose format depends
  60. * on the type, but often contains addresses).
  61. * Of course all fields are in network format.
  62. */
  63. typedef struct { unsigned int id[4]; } __attribute__((packed)) stun_trans_id;
  64. struct stun_header {
  65. unsigned short msgtype;
  66. unsigned short msglen;
  67. stun_trans_id id;
  68. unsigned char ies[0];
  69. } __attribute__((packed));
  70. struct stun_attr {
  71. unsigned short attr;
  72. unsigned short len;
  73. unsigned char value[0];
  74. } __attribute__((packed));
  75. /*
  76. * The format normally used for addresses carried by STUN messages.
  77. */
  78. struct stun_addr {
  79. unsigned char unused;
  80. unsigned char family;
  81. unsigned short port;
  82. unsigned int addr;
  83. } __attribute__((packed));
  84. /*! \brief STUN message types
  85. * 'BIND' refers to transactions used to determine the externally
  86. * visible addresses. 'SEC' refers to transactions used to establish
  87. * a session key for subsequent requests.
  88. * 'SEC' functionality is not supported here.
  89. */
  90. #define STUN_BINDREQ 0x0001
  91. #define STUN_BINDRESP 0x0101
  92. #define STUN_BINDERR 0x0111
  93. #define STUN_SECREQ 0x0002
  94. #define STUN_SECRESP 0x0102
  95. #define STUN_SECERR 0x0112
  96. /*! \brief Basic attribute types in stun messages.
  97. * Messages can also contain custom attributes (codes above 0x7fff)
  98. */
  99. #define STUN_MAPPED_ADDRESS 0x0001
  100. #define STUN_RESPONSE_ADDRESS 0x0002
  101. #define STUN_CHANGE_REQUEST 0x0003
  102. #define STUN_SOURCE_ADDRESS 0x0004
  103. #define STUN_CHANGED_ADDRESS 0x0005
  104. #define STUN_USERNAME 0x0006
  105. #define STUN_PASSWORD 0x0007
  106. #define STUN_MESSAGE_INTEGRITY 0x0008
  107. #define STUN_ERROR_CODE 0x0009
  108. #define STUN_UNKNOWN_ATTRIBUTES 0x000a
  109. #define STUN_REFLECTED_FROM 0x000b
  110. /*! \brief helper function to print message names */
  111. static const char *stun_msg2str(int msg)
  112. {
  113. switch (msg) {
  114. case STUN_BINDREQ:
  115. return "Binding Request";
  116. case STUN_BINDRESP:
  117. return "Binding Response";
  118. case STUN_BINDERR:
  119. return "Binding Error Response";
  120. case STUN_SECREQ:
  121. return "Shared Secret Request";
  122. case STUN_SECRESP:
  123. return "Shared Secret Response";
  124. case STUN_SECERR:
  125. return "Shared Secret Error Response";
  126. }
  127. return "Non-RFC3489 Message";
  128. }
  129. /*! \brief helper function to print attribute names */
  130. static const char *stun_attr2str(int msg)
  131. {
  132. switch (msg) {
  133. case STUN_MAPPED_ADDRESS:
  134. return "Mapped Address";
  135. case STUN_RESPONSE_ADDRESS:
  136. return "Response Address";
  137. case STUN_CHANGE_REQUEST:
  138. return "Change Request";
  139. case STUN_SOURCE_ADDRESS:
  140. return "Source Address";
  141. case STUN_CHANGED_ADDRESS:
  142. return "Changed Address";
  143. case STUN_USERNAME:
  144. return "Username";
  145. case STUN_PASSWORD:
  146. return "Password";
  147. case STUN_MESSAGE_INTEGRITY:
  148. return "Message Integrity";
  149. case STUN_ERROR_CODE:
  150. return "Error Code";
  151. case STUN_UNKNOWN_ATTRIBUTES:
  152. return "Unknown Attributes";
  153. case STUN_REFLECTED_FROM:
  154. return "Reflected From";
  155. }
  156. return "Non-RFC3489 Attribute";
  157. }
  158. /*! \brief here we store credentials extracted from a message */
  159. struct stun_state {
  160. const char *username;
  161. const char *password;
  162. };
  163. static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
  164. {
  165. if (stundebug)
  166. ast_verbose("Found STUN Attribute %s (%04x), length %d\n",
  167. stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr), ntohs(attr->len));
  168. switch (ntohs(attr->attr)) {
  169. case STUN_USERNAME:
  170. state->username = (const char *) (attr->value);
  171. break;
  172. case STUN_PASSWORD:
  173. state->password = (const char *) (attr->value);
  174. break;
  175. default:
  176. if (stundebug)
  177. ast_verbose("Ignoring STUN attribute %s (%04x), length %d\n",
  178. stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr), ntohs(attr->len));
  179. }
  180. return 0;
  181. }
  182. /*! \brief append a string to an STUN message */
  183. static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left)
  184. {
  185. int str_length = strlen(s);
  186. int attr_length = str_length + ((~(str_length - 1)) & 0x3);
  187. int size = sizeof(**attr) + attr_length;
  188. if (*left > size) {
  189. (*attr)->attr = htons(attrval);
  190. (*attr)->len = htons(attr_length);
  191. memcpy((*attr)->value, s, str_length);
  192. memset((*attr)->value + str_length, 0, attr_length - str_length);
  193. (*attr) = (struct stun_attr *)((*attr)->value + attr_length);
  194. *len += size;
  195. *left -= size;
  196. }
  197. }
  198. /*! \brief append an address to an STUN message */
  199. static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sin, int *len, int *left)
  200. {
  201. int size = sizeof(**attr) + 8;
  202. struct stun_addr *addr;
  203. if (*left > size) {
  204. (*attr)->attr = htons(attrval);
  205. (*attr)->len = htons(8);
  206. addr = (struct stun_addr *)((*attr)->value);
  207. addr->unused = 0;
  208. addr->family = 0x01;
  209. addr->port = sin->sin_port;
  210. addr->addr = sin->sin_addr.s_addr;
  211. (*attr) = (struct stun_attr *)((*attr)->value + 8);
  212. *len += size;
  213. *left -= size;
  214. }
  215. }
  216. /*! \brief wrapper to send an STUN message */
  217. static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
  218. {
  219. return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0,
  220. (struct sockaddr *)dst, sizeof(*dst));
  221. }
  222. /*!
  223. * \internal
  224. * \brief Compare the STUN tranaction IDs.
  225. *
  226. * \param left Transaction ID.
  227. * \param right Transaction ID.
  228. *
  229. * \retval 0 if match.
  230. * \retval non-zero if not match.
  231. */
  232. static int stun_id_cmp(stun_trans_id *left, stun_trans_id *right)
  233. {
  234. return memcmp(left, right, sizeof(*left));
  235. }
  236. /*! \brief helper function to generate a random request id */
  237. static void stun_req_id(struct stun_header *req)
  238. {
  239. int x;
  240. for (x = 0; x < 4; x++)
  241. req->id.id[x] = ast_random();
  242. }
  243. int ast_stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)
  244. {
  245. struct stun_header *hdr = (struct stun_header *)data;
  246. struct stun_attr *attr;
  247. struct stun_state st;
  248. int ret = AST_STUN_IGNORE;
  249. int x;
  250. /* On entry, 'len' is the length of the udp payload. After the
  251. * initial checks it becomes the size of unprocessed options,
  252. * while 'data' is advanced accordingly.
  253. */
  254. if (len < sizeof(struct stun_header)) {
  255. ast_debug(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
  256. return -1;
  257. }
  258. len -= sizeof(struct stun_header);
  259. data += sizeof(struct stun_header);
  260. x = ntohs(hdr->msglen); /* len as advertised in the message */
  261. if (stundebug)
  262. ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), (unsigned)ntohs(hdr->msgtype), x);
  263. if (x > len) {
  264. ast_debug(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
  265. } else
  266. len = x;
  267. memset(&st, 0, sizeof(st));
  268. while (len) {
  269. if (len < sizeof(struct stun_attr)) {
  270. ast_debug(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
  271. break;
  272. }
  273. attr = (struct stun_attr *)data;
  274. /* compute total attribute length */
  275. x = ntohs(attr->len) + sizeof(struct stun_attr);
  276. if (x > len) {
  277. ast_debug(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
  278. break;
  279. }
  280. if (stun_cb)
  281. stun_cb(attr, arg);
  282. if (stun_process_attr(&st, attr)) {
  283. ast_debug(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr));
  284. break;
  285. }
  286. /* Clear attribute id: in case previous entry was a string,
  287. * this will act as the terminator for the string.
  288. */
  289. attr->attr = 0;
  290. data += x;
  291. len -= x;
  292. }
  293. /* Null terminate any string.
  294. * XXX NOTE, we write past the size of the buffer passed by the
  295. * caller, so this is potentially dangerous. The only thing that
  296. * saves us is that usually we read the incoming message in a
  297. * much larger buffer in the struct ast_rtp
  298. */
  299. *data = '\0';
  300. /* Now prepare to generate a reply, which at the moment is done
  301. * only for properly formed (len == 0) STUN_BINDREQ messages.
  302. */
  303. if (len == 0) {
  304. unsigned char respdata[1024];
  305. struct stun_header *resp = (struct stun_header *)respdata;
  306. int resplen = 0; /* len excluding header */
  307. int respleft = sizeof(respdata) - sizeof(struct stun_header);
  308. char combined[33];
  309. resp->id = hdr->id;
  310. resp->msgtype = 0;
  311. resp->msglen = 0;
  312. attr = (struct stun_attr *)resp->ies;
  313. switch (ntohs(hdr->msgtype)) {
  314. case STUN_BINDREQ:
  315. if (stundebug)
  316. ast_verbose("STUN Bind Request, username: %s\n",
  317. st.username ? st.username : "<none>");
  318. if (st.username) {
  319. append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
  320. snprintf(combined, sizeof(combined), "%16s%16s", st.username + 16, st.username);
  321. } else {
  322. combined[0] = '\0';
  323. }
  324. append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft);
  325. resp->msglen = htons(resplen);
  326. resp->msgtype = htons(STUN_BINDRESP);
  327. stun_send(s, src, resp);
  328. ast_stun_request(s, src, combined, NULL);
  329. ret = AST_STUN_ACCEPT;
  330. break;
  331. default:
  332. if (stundebug)
  333. ast_verbose("Dunno what to do with STUN message %04x (%s)\n", (unsigned)ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
  334. }
  335. }
  336. return ret;
  337. }
  338. /*! \brief Extract the STUN_MAPPED_ADDRESS from the stun response.
  339. * This is used as a callback for stun_handle_response
  340. * when called from ast_stun_request.
  341. */
  342. static int stun_get_mapped(struct stun_attr *attr, void *arg)
  343. {
  344. struct stun_addr *addr = (struct stun_addr *)(attr + 1);
  345. struct sockaddr_in *sa = (struct sockaddr_in *)arg;
  346. if (ntohs(attr->attr) != STUN_MAPPED_ADDRESS || ntohs(attr->len) != 8)
  347. return 1; /* not us. */
  348. sa->sin_port = addr->port;
  349. sa->sin_addr.s_addr = addr->addr;
  350. return 0;
  351. }
  352. int ast_stun_request(int s, struct sockaddr_in *dst,
  353. const char *username, struct sockaddr_in *answer)
  354. {
  355. struct stun_header *req;
  356. struct stun_header *rsp;
  357. unsigned char req_buf[1024];
  358. unsigned char rsp_buf[1024];
  359. int reqlen, reqleft;
  360. struct stun_attr *attr;
  361. int res = -1;
  362. int retry;
  363. if (answer) {
  364. /* Always clear answer in case the request fails. */
  365. memset(answer, 0, sizeof(struct sockaddr_in));
  366. }
  367. /* Create STUN bind request */
  368. req = (struct stun_header *) req_buf;
  369. stun_req_id(req);
  370. reqlen = 0;
  371. reqleft = sizeof(req_buf) - sizeof(struct stun_header);
  372. attr = (struct stun_attr *) req->ies;
  373. if (username) {
  374. append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft);
  375. }
  376. req->msglen = htons(reqlen);
  377. req->msgtype = htons(STUN_BINDREQ);
  378. for (retry = 0; retry++ < 3;) { /* XXX make retries configurable */
  379. /* send request, possibly wait for reply */
  380. struct sockaddr_in src;
  381. socklen_t srclen;
  382. struct timeval start;
  383. /* Send STUN message. */
  384. res = stun_send(s, dst, req);
  385. if (res < 0) {
  386. ast_debug(1, "stun_send try %d failed: %s\n", retry, strerror(errno));
  387. break;
  388. }
  389. if (!answer) {
  390. /* Successful send since we don't care about any response. */
  391. res = 0;
  392. break;
  393. }
  394. start = ast_tvnow();
  395. try_again:
  396. /* Wait for response. */
  397. {
  398. struct pollfd pfds = { .fd = s, .events = POLLIN };
  399. int ms;
  400. ms = ast_remaining_ms(start, 3000);
  401. if (ms <= 0) {
  402. /* No response, timeout */
  403. res = 1;
  404. continue;
  405. }
  406. res = ast_poll(&pfds, 1, ms);
  407. if (res < 0) {
  408. /* Error */
  409. continue;
  410. }
  411. if (!res) {
  412. /* No response, timeout */
  413. res = 1;
  414. continue;
  415. }
  416. }
  417. /* Read STUN response. */
  418. memset(&src, 0, sizeof(src));
  419. srclen = sizeof(src);
  420. /* XXX pass sizeof(rsp_buf) - 1 in the size, because stun_handle_packet might
  421. * write past the end of the buffer.
  422. */
  423. res = recvfrom(s, rsp_buf, sizeof(rsp_buf) - 1,
  424. 0, (struct sockaddr *) &src, &srclen);
  425. if (res < 0) {
  426. ast_debug(1, "recvfrom try %d failed: %s\n", retry, strerror(errno));
  427. break;
  428. }
  429. /* Process the STUN response. */
  430. rsp = (struct stun_header *) rsp_buf;
  431. if (ast_stun_handle_packet(s, &src, rsp_buf, res, stun_get_mapped, answer)
  432. || (rsp->msgtype != htons(STUN_BINDRESP)
  433. && rsp->msgtype != htons(STUN_BINDERR))
  434. || stun_id_cmp(&req->id, &rsp->id)) {
  435. /* Bad STUN packet, not right type, or transaction ID did not match. */
  436. memset(answer, 0, sizeof(struct sockaddr_in));
  437. /* Was not a resonse to our request. */
  438. goto try_again;
  439. }
  440. /* Success. answer contains the external address if available. */
  441. res = 0;
  442. break;
  443. }
  444. return res;
  445. }
  446. static char *handle_cli_stun_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  447. {
  448. switch (cmd) {
  449. case CLI_INIT:
  450. e->command = "stun set debug {on|off}";
  451. e->usage =
  452. "Usage: stun set debug {on|off}\n"
  453. " Enable/Disable STUN (Simple Traversal of UDP through NATs)\n"
  454. " debugging\n";
  455. return NULL;
  456. case CLI_GENERATE:
  457. return NULL;
  458. }
  459. if (a->argc != e->args)
  460. return CLI_SHOWUSAGE;
  461. if (!strncasecmp(a->argv[e->args-1], "on", 2))
  462. stundebug = 1;
  463. else if (!strncasecmp(a->argv[e->args-1], "off", 3))
  464. stundebug = 0;
  465. else
  466. return CLI_SHOWUSAGE;
  467. ast_cli(a->fd, "STUN Debugging %s\n", stundebug ? "Enabled" : "Disabled");
  468. return CLI_SUCCESS;
  469. }
  470. static struct ast_cli_entry cli_stun[] = {
  471. AST_CLI_DEFINE(handle_cli_stun_set_debug, "Enable/Disable STUN debugging"),
  472. };
  473. static void stun_shutdown(void)
  474. {
  475. ast_cli_unregister_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
  476. }
  477. /*! \brief Initialize the STUN system in Asterisk */
  478. void ast_stun_init(void)
  479. {
  480. ast_cli_register_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
  481. ast_register_cleanup(stun_shutdown);
  482. }