#include #include #include #include #include /** * Parse reply to STUN binding request * * \param req[in] Original request. Transaction id must match reply. * \param rep[in] Reply. Invalid after this function is called. * \param sz[in] Size of reply (in bytes). * * \return String containing server-reflexive address. Address is in the * form "ip:port". String overwrites reply. Reply must not be used after * this function. */ char* stun_parse_reply(const unsigned char*req, unsigned char* rep, size_t sz) { static char addr[23]; // length requirement if (sz < 32) { return NULL; } // type must be binding reply if (rep[0] != 0x01 || rep[1] != 0x01) { return NULL; } // magic cookie must match if (rep[4] != 0x21 || rep[5] != 0x12 || rep[6] != 0xa4 || rep[7] != 0x42) { return NULL; } // transaction id must match for (int i = 8; i < 20; i++) { if (req[i] != rep[i]) { return NULL; } } // first attribute expected to be of type XOR-MAPPED-ADDRESS if (rep[20] != 0x00 || rep[21] != 0x20) { return NULL; } // length expected to be 8 bytes if (rep[22] != 0x00 || rep[23] != 0x08) { return NULL; } // family expected to be IPv4 if (rep[24] != 0x00 || rep[25] != 0x01) { return NULL; } // get address and port sprintf(rep, "%d.%d.%d.%d:%d", rep[28] ^ 0x21, rep[29] ^ 0x12, rep[30] ^ 0xa4, rep[31] ^ 0x42, ((rep[26] ^ 0x21) << 8) | (rep[27] ^ 0x12)); return rep; } int rtc_stun_binding_request() { int fd; unsigned char req[] = { 0x00, 0x01, // binding request 0x00, 0x00, // length 0x21, 0x12, 0xa4, 0x42, // magic cookie rand(), rand(), rand(), rand(), // tx id rand(), rand(), rand(), rand(), // tx id (cont.) rand(), rand(), rand(), rand(), // tx id (cont.) }; if (fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP), -1 == fd) { perror("socket"); } struct sockaddr_in sa = { .sin_addr.s_addr = htonl(164 << 24 | 90 << 16 | 156 << 8 | 231), .sin_port = htons(3478), .sin_family = AF_INET }; if (-1 == sendto(fd, req, sizeof(req), 0, (struct sockaddr*)&sa, sizeof(sa))) { perror("sendto"); } unsigned char rep[4096]; int n; socklen_t sl = sizeof(struct sockaddr_in); if (n = recvfrom(fd, rep, sizeof(rep), 0, (struct sockaddr*)&sa, &sl), -1 == n) { perror("recvfrom"); } char* a; if (a = stun_parse_reply(req, rep, n), a) { printf("%s\n", a); } } int main() { srand(time(0)); rtc_stun_binding_request(); return 0; }