build_nacl.sh: made the script more 'userfriendly' and give a note on install
[netsniff-ng.git] / src / stun.c
blob42942e6b8ef7212e4ce47958ad1840d8a7f5c25f
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 Daniel Borkmann.
5 * Subject to the GPL, version 2.
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdint.h>
11 #include <string.h>
12 #include <time.h>
13 #include <unistd.h>
14 #include <netdb.h>
15 #include <netinet/in.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <sys/select.h>
21 #include "die.h"
22 #include "xmalloc.h"
23 #include "xsys.h"
24 #include "stun.h"
26 /* Discovery type result */
27 #define RESULT_NONE 0
28 #define RESULT_OPEN_INTERNET 1
29 #define RESULT_FIREWALL_BLOCKS_UDP 2
30 #define RESULT_SYMMETRIC_UDP_FIREWALL 3
31 #define RESULT_FULL_CONE_NAT 4
32 #define RESULT_SYMMETRIC_NAT 5
33 #define RESULT_RESTRICTED_CONE_NAT 6
34 #define RESULT_PORT_RESTR_CONE_NAT 7
36 /* Message types */
37 #define BINDING_REQUEST 0x0001
38 #define BINDING_RESPONSE 0x0101
39 #define BINDING_ERROR_RESPONSE 0x0111
40 #define SHARED_SECRET_REQUEST 0x0002
41 #define SHARED_SECRET_RESPONSE 0x0102
42 #define SHARED_SECRET_ERROR_RESPONSE 0x0112
44 /* Attribute types */
45 #define MAPPED_ADDRESS 0x0001
46 #define RESPONSE_ADDRESS 0x0002
47 #define CHANGE_REQUEST 0x0003
48 #define SOURCE_ADDRESS 0x0004
49 #define CHANGED_ADDRESS 0x0005
50 #define USERNAME 0x0006
51 #define PASSWORD 0x0007
52 #define MESSAGE_INTEGRITY 0x0008
53 #define ERROR_CODE 0x0009
54 #define UNKNOWN_ATTRIBUTES 0x000a
55 #define REFLECTED_FROM 0x000b
57 /* Error response codes */
58 #define ERROR_BAD_REQUEST 400
59 #define ERROR_UNAUTHORIZED 401
60 #define ERROR_UNKNOWN_ATTRIBUTE 420
61 #define ERROR_STALE_CREDENTIALS 430
62 #define ERROR_INTEGRITY_CHECK_FAIL 431
63 #define ERROR_MISSING_USERNAME 432
64 #define ERROR_USE_TLS 433
65 #define ERROR_SERVER_ERROR 500
66 #define ERROR_GLOBAL_FAILURE 600
68 #define TIMEOUT 1000
69 #define REQUEST_LEN 20
71 #define ID_COOKIE_FIELD htonl(((int) 'a' << 24) + \
72 ((int) 'c' << 16) + \
73 ((int) 'd' << 8) + \
74 (int) 'c')
76 struct stun_header {
77 uint16_t type;
79 * Message length is the count, in bytes, of the size of the
80 * message, not including the 20 byte header. (RFC-3489)
82 uint16_t len;
84 * transid also serves as salt to randomize the request and the
85 * response. All responses carry the same identifier as
86 * the request they correspond to.
88 /* For the new RFC this would be 0x2112A442 in network Byte order. */
89 uint32_t magic_cookie;
90 uint32_t transid[3];
93 struct stun_attrib {
94 uint16_t type;
95 uint16_t len;
96 uint8_t *value;
99 struct stun_mapped_addr {
100 uint8_t none;
101 uint8_t family;
102 uint16_t port;
103 uint32_t ip;
106 static int stun_test(const char *server_ip, uint16_t server_port,
107 uint16_t tun_port)
109 int ret, sock, set = 1;
110 uint8_t pkt[256];
111 uint8_t rpkt[256];
112 size_t len, off, max;
113 struct in_addr in;
114 struct timeval timeout;
115 struct stun_header *hdr, *rhdr;
116 struct stun_attrib *attr;
117 struct stun_mapped_addr *addr;
118 struct sockaddr_in saddr, daddr;
119 fd_set fdset;
121 if (!server_ip)
122 return -EINVAL;
124 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
125 if (sock < 0)
126 panic("Cannot obtain socket!\n");
128 ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
129 if (ret)
130 panic("Cannot set socket option!\n");
132 saddr.sin_family = PF_INET;
133 saddr.sin_port = htons(tun_port);
134 saddr.sin_addr.s_addr = INADDR_ANY;
136 ret = bind(sock, (struct sockaddr *) &saddr, sizeof(saddr));
137 if (ret)
138 panic("Cannot bind udp socket!\n");
140 len = REQUEST_LEN;
141 hdr = (struct stun_header *) pkt;
142 hdr->type = htons(BINDING_REQUEST);
143 hdr->len = 0;
144 hdr->magic_cookie = ID_COOKIE_FIELD;
145 hdr->transid[0] = htonl(rand());
146 hdr->transid[1] = htonl(rand());
147 hdr->transid[2] = htonl(rand());
149 daddr.sin_family = PF_INET;
150 daddr.sin_port = htons(server_port);
151 daddr.sin_addr.s_addr = inet_addr(server_ip);
153 ret = sendto(sock, pkt, len, 0, (struct sockaddr *) &daddr,
154 sizeof(daddr));
155 if (ret != len) {
156 whine("Error sending request (%s)!\n", strerror(errno));
157 return -EIO;
160 set_timeout(&timeout, TIMEOUT);
162 FD_ZERO(&fdset);
163 FD_SET(sock, &fdset);
165 ret = select(sock + 1, &fdset, NULL, NULL, &timeout);
166 if (ret <= 0) {
167 whine("STUN server timeout!\n");
168 return -EIO;
171 memset(rpkt, 0, sizeof(rpkt));
172 len = read(sock, rpkt, sizeof(rpkt));
174 close(sock);
176 if (len < REQUEST_LEN) {
177 whine("Bad STUN response (%s)!\n", strerror(errno));
178 return -EIO;
181 rhdr = (struct stun_header *) rpkt;
182 if (ntohs(rhdr->type) != BINDING_RESPONSE) {
183 whine("Wrong STUN response type!\n");
184 return -EIO;
187 if (rhdr->len == 0) {
188 whine("No attributes in STUN response!\n");
189 return -EIO;
192 if (rhdr->magic_cookie != hdr->magic_cookie ||
193 rhdr->transid[0] != hdr->transid[0] ||
194 rhdr->transid[1] != hdr->transid[1] ||
195 rhdr->transid[2] != hdr->transid[2]) {
196 whine("Got wrong STUN transaction id!\n");
197 return -EIO;
200 off = REQUEST_LEN;
201 max = ntohs(rhdr->len) + REQUEST_LEN;
203 while (off + 8 < max) {
204 attr = (struct stun_attrib *) (rpkt + off);
205 if (ntohs(attr->type) != MAPPED_ADDRESS)
206 goto next;
208 addr = (struct stun_mapped_addr *) (rpkt + off + 4);
209 if (addr->family != 0x1)
210 break;
212 in.s_addr = addr->ip;
213 info("Public mapping %s:%u!\n", inet_ntoa(in), ntohs(addr->port));
214 break;
215 next:
216 off += 4;
217 off += ntohs(attr->len);
220 return 0;
223 void print_stun_probe(char *server, uint16_t sport, uint16_t tunport)
225 char *address;
226 struct hostent *hp;
228 printf("STUN on %s:%u\n", server, sport);
229 srand(time(NULL));
230 hp = gethostbyname(server);
231 if (!hp)
232 return;
233 address = inet_ntoa(*(struct in_addr *) hp->h_addr_list[0]);
234 stun_test(address, sport, tunport);