docs: better description for uninstall, fixed typo
[netsniff-ng.git] / src / stun.c
blobc7c6bfe304743843ca9d82d5fcd32b03573c1543
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 <errno.h>
13 #include <time.h>
14 #include <unistd.h>
15 #include <netdb.h>
16 #include <netinet/in.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <sys/select.h>
22 #include "xmalloc.h"
23 #include "xutils.h"
24 #include "die.h"
26 extern int print_stun_probe(char *server, int sport, int tport);
28 #define BINDING_REQUEST 0x0001
29 #define BINDING_RESPONSE 0x0101
31 #define MAPPED_ADDRESS 0x0001
33 #define TIMEOUT 5000
34 #define REQUEST_LEN 20
36 #define ID_COOKIE_FIELD htonl(((int) 'a' << 24) + \
37 ((int) 'c' << 16) + \
38 ((int) 'd' << 8) + \
39 (int) 'c')
41 struct stun_header {
42 uint16_t type;
43 uint16_t len;
44 uint32_t magic_cookie;
45 uint32_t transid[3];
48 struct stun_attrib {
49 uint16_t type;
50 uint16_t len;
51 uint8_t *value;
54 struct stun_mapped_addr {
55 uint8_t none;
56 uint8_t family;
57 uint16_t port;
58 uint32_t ip;
61 static int stun_test(const char *server_ip, int server_port,
62 int tun_port)
64 int ret, sock, set = 1;
65 uint8_t pkt[256];
66 uint8_t rpkt[256];
67 size_t len, off, max;
68 struct in_addr in;
69 struct timeval timeout;
70 struct stun_header *hdr, *rhdr;
71 struct stun_attrib *attr;
72 struct stun_mapped_addr *addr;
73 struct sockaddr_in saddr, daddr;
74 fd_set fdset;
76 if (!server_ip)
77 return -EINVAL;
79 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
80 if (sock < 0)
81 panic("Cannot obtain socket!\n");
83 ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
84 if (ret)
85 panic("Cannot set socket option!\n");
87 saddr.sin_family = PF_INET;
88 saddr.sin_port = htons(tun_port);
89 saddr.sin_addr.s_addr = INADDR_ANY;
91 ret = bind(sock, (struct sockaddr *) &saddr, sizeof(saddr));
92 if (ret)
93 panic("Cannot bind udp socket!\n");
95 len = REQUEST_LEN;
96 hdr = (struct stun_header *) pkt;
97 hdr->type = htons(BINDING_REQUEST);
98 hdr->len = 0;
99 hdr->magic_cookie = ID_COOKIE_FIELD;
100 hdr->transid[0] = htonl(rand());
101 hdr->transid[1] = htonl(rand());
102 hdr->transid[2] = htonl(rand());
104 daddr.sin_family = PF_INET;
105 daddr.sin_port = htons(server_port);
106 daddr.sin_addr.s_addr = inet_addr(server_ip);
108 ret = sendto(sock, pkt, len, 0, (struct sockaddr *) &daddr,
109 sizeof(daddr));
110 if (ret != len) {
111 whine("Error sending request (%s)!\n", strerror(errno));
112 return -EIO;
115 set_timeout(&timeout, TIMEOUT);
117 FD_ZERO(&fdset);
118 FD_SET(sock, &fdset);
120 ret = select(sock + 1, &fdset, NULL, NULL, &timeout);
121 if (ret <= 0) {
122 whine("STUN server timeout!\n");
123 return -EIO;
126 memset(rpkt, 0, sizeof(rpkt));
127 len = read(sock, rpkt, sizeof(rpkt));
129 close(sock);
131 if (len < REQUEST_LEN) {
132 whine("Bad STUN response (%s)!\n", strerror(errno));
133 return -EIO;
136 rhdr = (struct stun_header *) rpkt;
137 if (ntohs(rhdr->type) != BINDING_RESPONSE) {
138 whine("Wrong STUN response type!\n");
139 return -EIO;
142 if (rhdr->len == 0) {
143 whine("No attributes in STUN response!\n");
144 return -EIO;
147 if (rhdr->magic_cookie != hdr->magic_cookie ||
148 rhdr->transid[0] != hdr->transid[0] ||
149 rhdr->transid[1] != hdr->transid[1] ||
150 rhdr->transid[2] != hdr->transid[2]) {
151 whine("Got wrong STUN transaction id!\n");
152 return -EIO;
155 off = REQUEST_LEN;
156 max = ntohs(rhdr->len) + REQUEST_LEN;
158 while (off + 8 < max) {
159 attr = (struct stun_attrib *) (rpkt + off);
160 if (ntohs(attr->type) != MAPPED_ADDRESS)
161 goto next;
163 addr = (struct stun_mapped_addr *) (rpkt + off + 4);
164 if (addr->family != 0x1)
165 break;
167 in.s_addr = addr->ip;
168 printf("Public mapping %s:%u!\n",
169 inet_ntoa(in), ntohs(addr->port));
170 break;
171 next:
172 off += 4;
173 off += ntohs(attr->len);
176 return 0;
179 int print_stun_probe(char *server, int sport, int tport)
181 char *address;
182 struct hostent *hp;
184 printf("STUN on %s:%u\n", server, sport);
186 srand(time(NULL));
187 hp = gethostbyname(server);
188 if (!hp)
189 return -EIO;
190 address = inet_ntoa(*(struct in_addr *) hp->h_addr_list[0]);
191 return stun_test(address, sport, tport);