00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "asterisk.h"
00030
00031 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 346700 $")
00032
00033 #include "asterisk/_private.h"
00034 #include "asterisk/stun.h"
00035 #include "asterisk/cli.h"
00036 #include "asterisk/utils.h"
00037 #include "asterisk/channel.h"
00038
00039 static int stundebug;
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 typedef struct { unsigned int id[4]; } __attribute__((packed)) stun_trans_id;
00068
00069 struct stun_header {
00070 unsigned short msgtype;
00071 unsigned short msglen;
00072 stun_trans_id id;
00073 unsigned char ies[0];
00074 } __attribute__((packed));
00075
00076 struct stun_attr {
00077 unsigned short attr;
00078 unsigned short len;
00079 unsigned char value[0];
00080 } __attribute__((packed));
00081
00082
00083
00084
00085 struct stun_addr {
00086 unsigned char unused;
00087 unsigned char family;
00088 unsigned short port;
00089 unsigned int addr;
00090 } __attribute__((packed));
00091
00092
00093
00094
00095
00096
00097
00098
00099 #define STUN_BINDREQ 0x0001
00100 #define STUN_BINDRESP 0x0101
00101 #define STUN_BINDERR 0x0111
00102 #define STUN_SECREQ 0x0002
00103 #define STUN_SECRESP 0x0102
00104 #define STUN_SECERR 0x0112
00105
00106
00107
00108
00109 #define STUN_MAPPED_ADDRESS 0x0001
00110 #define STUN_RESPONSE_ADDRESS 0x0002
00111 #define STUN_CHANGE_REQUEST 0x0003
00112 #define STUN_SOURCE_ADDRESS 0x0004
00113 #define STUN_CHANGED_ADDRESS 0x0005
00114 #define STUN_USERNAME 0x0006
00115 #define STUN_PASSWORD 0x0007
00116 #define STUN_MESSAGE_INTEGRITY 0x0008
00117 #define STUN_ERROR_CODE 0x0009
00118 #define STUN_UNKNOWN_ATTRIBUTES 0x000a
00119 #define STUN_REFLECTED_FROM 0x000b
00120
00121
00122 static const char *stun_msg2str(int msg)
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 }
00140
00141
00142 static const char *stun_attr2str(int msg)
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 }
00170
00171
00172 struct stun_state {
00173 const char *username;
00174 const char *password;
00175 };
00176
00177 static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
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 }
00196
00197
00198 static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left)
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 }
00210
00211
00212 static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sin, int *len, int *left)
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 }
00229
00230
00231 static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
00232 {
00233 return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0,
00234 (struct sockaddr *)dst, sizeof(*dst));
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247 static int stun_id_cmp(stun_trans_id *left, stun_trans_id *right)
00248 {
00249 return memcmp(left, right, sizeof(*left));
00250 }
00251
00252
00253 static void stun_req_id(struct stun_header *req)
00254 {
00255 int x;
00256 for (x = 0; x < 4; x++)
00257 req->id.id[x] = ast_random();
00258 }
00259
00260 int ast_stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)
00261 {
00262 struct stun_header *hdr = (struct stun_header *)data;
00263 struct stun_attr *attr;
00264 struct stun_state st;
00265 int ret = AST_STUN_IGNORE;
00266 int x;
00267
00268
00269
00270
00271
00272 if (len < sizeof(struct stun_header)) {
00273 ast_debug(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
00274 return -1;
00275 }
00276 len -= sizeof(struct stun_header);
00277 data += sizeof(struct stun_header);
00278 x = ntohs(hdr->msglen);
00279 if (stundebug)
00280 ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), x);
00281 if (x > len) {
00282 ast_debug(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
00283 } else
00284 len = x;
00285 memset(&st, 0, sizeof(st));
00286 while (len) {
00287 if (len < sizeof(struct stun_attr)) {
00288 ast_debug(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
00289 break;
00290 }
00291 attr = (struct stun_attr *)data;
00292
00293 x = ntohs(attr->len) + sizeof(struct stun_attr);
00294 if (x > len) {
00295 ast_debug(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
00296 break;
00297 }
00298 if (stun_cb)
00299 stun_cb(attr, arg);
00300 if (stun_process_attr(&st, attr)) {
00301 ast_debug(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr));
00302 break;
00303 }
00304
00305
00306
00307 attr->attr = 0;
00308 data += x;
00309 len -= x;
00310 }
00311
00312
00313
00314
00315
00316
00317 *data = '\0';
00318
00319
00320
00321
00322 if (len == 0) {
00323 unsigned char respdata[1024];
00324 struct stun_header *resp = (struct stun_header *)respdata;
00325 int resplen = 0;
00326 int respleft = sizeof(respdata) - sizeof(struct stun_header);
00327
00328 resp->id = hdr->id;
00329 resp->msgtype = 0;
00330 resp->msglen = 0;
00331 attr = (struct stun_attr *)resp->ies;
00332 switch (ntohs(hdr->msgtype)) {
00333 case STUN_BINDREQ:
00334 if (stundebug)
00335 ast_verbose("STUN Bind Request, username: %s\n",
00336 st.username ? st.username : "<none>");
00337 if (st.username)
00338 append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
00339 append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft);
00340 resp->msglen = htons(resplen);
00341 resp->msgtype = htons(STUN_BINDRESP);
00342 stun_send(s, src, resp);
00343 ret = AST_STUN_ACCEPT;
00344 break;
00345 default:
00346 if (stundebug)
00347 ast_verbose("Dunno what to do with STUN message %04x (%s)\n", ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
00348 }
00349 }
00350 return ret;
00351 }
00352
00353
00354
00355
00356
00357 static int stun_get_mapped(struct stun_attr *attr, void *arg)
00358 {
00359 struct stun_addr *addr = (struct stun_addr *)(attr + 1);
00360 struct sockaddr_in *sa = (struct sockaddr_in *)arg;
00361
00362 if (ntohs(attr->attr) != STUN_MAPPED_ADDRESS || ntohs(attr->len) != 8)
00363 return 1;
00364 sa->sin_port = addr->port;
00365 sa->sin_addr.s_addr = addr->addr;
00366 return 0;
00367 }
00368
00369 int ast_stun_request(int s, struct sockaddr_in *dst,
00370 const char *username, struct sockaddr_in *answer)
00371 {
00372 struct stun_header *req;
00373 struct stun_header *rsp;
00374 unsigned char req_buf[1024];
00375 unsigned char rsp_buf[1024];
00376 int reqlen, reqleft;
00377 struct stun_attr *attr;
00378 int res = -1;
00379 int retry;
00380
00381 if (answer) {
00382
00383 memset(answer, 0, sizeof(struct sockaddr_in));
00384 }
00385
00386
00387 req = (struct stun_header *) req_buf;
00388 stun_req_id(req);
00389 reqlen = 0;
00390 reqleft = sizeof(req_buf) - sizeof(struct stun_header);
00391 req->msgtype = 0;
00392 req->msglen = 0;
00393 attr = (struct stun_attr *) req->ies;
00394 if (username) {
00395 append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft);
00396 }
00397 req->msglen = htons(reqlen);
00398 req->msgtype = htons(STUN_BINDREQ);
00399
00400 for (retry = 0; retry++ < 3;) {
00401
00402 struct sockaddr_in src;
00403 socklen_t srclen;
00404
00405
00406 res = stun_send(s, dst, req);
00407 if (res < 0) {
00408 ast_debug(1, "stun_send try %d failed: %s\n", retry, strerror(errno));
00409 break;
00410 }
00411 if (!answer) {
00412
00413 res = 0;
00414 break;
00415 }
00416
00417 try_again:
00418
00419 {
00420 struct pollfd pfds = { .fd = s, .events = POLLIN };
00421
00422 res = ast_poll(&pfds, 1, 3000);
00423 if (res < 0) {
00424
00425 continue;
00426 }
00427 if (!res) {
00428
00429 res = 1;
00430 continue;
00431 }
00432 }
00433
00434
00435 memset(&src, 0, sizeof(src));
00436 srclen = sizeof(src);
00437
00438
00439
00440 res = recvfrom(s, rsp_buf, sizeof(rsp_buf) - 1,
00441 0, (struct sockaddr *) &src, &srclen);
00442 if (res < 0) {
00443 ast_debug(1, "recvfrom try %d failed: %s\n", retry, strerror(errno));
00444 break;
00445 }
00446
00447
00448 rsp = (struct stun_header *) rsp_buf;
00449 if (ast_stun_handle_packet(s, &src, rsp_buf, res, stun_get_mapped, answer)
00450 || (rsp->msgtype != htons(STUN_BINDRESP)
00451 && rsp->msgtype != htons(STUN_BINDERR))
00452 || stun_id_cmp(&req->id, &rsp->id)) {
00453
00454 memset(answer, 0, sizeof(struct sockaddr_in));
00455
00456
00457 goto try_again;
00458 }
00459
00460 res = 0;
00461 break;
00462 }
00463 return res;
00464 }
00465
00466 static char *handle_cli_stun_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00467 {
00468 switch (cmd) {
00469 case CLI_INIT:
00470 e->command = "stun set debug {on|off}";
00471 e->usage =
00472 "Usage: stun set debug {on|off}\n"
00473 " Enable/Disable STUN (Simple Traversal of UDP through NATs)\n"
00474 " debugging\n";
00475 return NULL;
00476 case CLI_GENERATE:
00477 return NULL;
00478 }
00479
00480 if (a->argc != e->args)
00481 return CLI_SHOWUSAGE;
00482
00483 if (!strncasecmp(a->argv[e->args-1], "on", 2))
00484 stundebug = 1;
00485 else if (!strncasecmp(a->argv[e->args-1], "off", 3))
00486 stundebug = 0;
00487 else
00488 return CLI_SHOWUSAGE;
00489
00490 ast_cli(a->fd, "STUN Debugging %s\n", stundebug ? "Enabled" : "Disabled");
00491 return CLI_SUCCESS;
00492 }
00493
00494 static struct ast_cli_entry cli_stun[] = {
00495 AST_CLI_DEFINE(handle_cli_stun_set_debug, "Enable/Disable STUN debugging"),
00496 };
00497
00498
00499 void ast_stun_init(void)
00500 {
00501 ast_cli_register_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
00502 }