1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <netinet/in.h>
#include <sys/socket.h>
/**
* 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;
}
|