1 /*
2 * Copyright (C) 2011, 2012, 2013 Citrix Systems
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the project nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <err.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37
38 #include "ns_turn_utils.h"
39 #include "apputils.h"
40 #include "stun_buffer.h"
41
42 #ifdef __cplusplus
43 #include "TurnMsgLib.h"
44 #endif
45
46 ////////////////////////////////////////////////////
47
48 static int udp_fd = -1;
49 static ioa_addr real_local_addr;
50 static int counter = 0;
51
52 #ifdef __cplusplus
53
run_stunclient(const char * rip,int rport,int * port,int * rfc5780,int response_port,int change_ip,int change_port,int padding)54 static int run_stunclient(const char* rip, int rport, int *port, int *rfc5780, int response_port, int change_ip, int change_port, int padding)
55 {
56
57 ioa_addr remote_addr;
58 int new_udp_fd = -1;
59
60 memset((void *) &remote_addr, 0, sizeof(ioa_addr));
61 if (make_ioa_addr((const uint8_t*) rip, rport, &remote_addr) < 0)
62 err(-1, NULL);
63
64 if (udp_fd < 0) {
65 udp_fd = socket(remote_addr.ss.sa_family, SOCK_DGRAM, 0);
66 if (udp_fd < 0)
67 err(-1, NULL);
68
69 if (!addr_any(&real_local_addr)) {
70 if (addr_bind(udp_fd, &real_local_addr,0,1,UDP_SOCKET) < 0)
71 err(-1, NULL);
72 }
73 }
74
75 if (response_port >= 0) {
76
77 new_udp_fd = socket(remote_addr.ss.sa_family, SOCK_DGRAM, 0);
78 if (new_udp_fd < 0)
79 err(-1, NULL);
80
81 addr_set_port(&real_local_addr, response_port);
82
83 if (addr_bind(new_udp_fd, &real_local_addr, 0, 1, UDP_SOCKET) < 0)
84 err(-1, NULL);
85 }
86
87 turn::StunMsgRequest req(STUN_METHOD_BINDING);
88
89 req.constructBindingRequest();
90
91 if (response_port >= 0) {
92 turn::StunAttrResponsePort rpa;
93 rpa.setResponsePort((uint16_t)response_port);
94 try {
95 req.addAttr(rpa);
96 } catch(turn::WrongStunAttrFormatException &ex1) {
97 printf("Wrong rp attr format\n");
98 exit(-1);
99 } catch(turn::WrongStunBufferFormatException &ex2) {
100 printf("Wrong stun buffer format (1)\n");
101 exit(-1);
102 } catch(...) {
103 printf("Wrong something (1)\n");
104 exit(-1);
105 }
106 }
107 if (change_ip || change_port) {
108 turn::StunAttrChangeRequest cra;
109 cra.setChangeIp(change_ip);
110 cra.setChangePort(change_port);
111 try {
112 req.addAttr(cra);
113 } catch(turn::WrongStunAttrFormatException &ex1) {
114 printf("Wrong cr attr format\n");
115 exit(-1);
116 } catch(turn::WrongStunBufferFormatException &ex2) {
117 printf("Wrong stun buffer format (2)\n");
118 exit(-1);
119 } catch(...) {
120 printf("Wrong something (2)\n");
121 exit(-1);
122 }
123 }
124 if (padding) {
125 turn::StunAttrPadding pa;
126 pa.setPadding(1500);
127 try {
128 req.addAttr(pa);
129 } catch(turn::WrongStunAttrFormatException &ex1) {
130 printf("Wrong p attr format\n");
131 exit(-1);
132 } catch(turn::WrongStunBufferFormatException &ex2) {
133 printf("Wrong stun buffer format (3)\n");
134 exit(-1);
135 } catch(...) {
136 printf("Wrong something (3)\n");
137 exit(-1);
138 }
139 }
140
141 {
142 int len = 0;
143 int slen = get_ioa_addr_len(&remote_addr);
144
145 do {
146 len = sendto(udp_fd, req.getRawBuffer(), req.getSize(), 0, (struct sockaddr*) &remote_addr, (socklen_t) slen);
147 } while (len < 0 && ((errno == EINTR) || (errno == ENOBUFS) || (errno == EAGAIN)));
148
149 if (len < 0)
150 err(-1, NULL);
151
152 }
153
154 if (addr_get_from_sock(udp_fd, &real_local_addr) < 0) {
155 printf("%s: Cannot get address from local socket\n", __FUNCTION__);
156 } else {
157 *port = addr_get_port(&real_local_addr);
158 }
159
160 {
161 if(new_udp_fd >= 0) {
162 close(udp_fd);
163 udp_fd = new_udp_fd;
164 new_udp_fd = -1;
165 }
166 }
167
168 {
169 int len = 0;
170 stun_buffer buf;
171 uint8_t *ptr = buf.buf;
172 int recvd = 0;
173 const int to_recv = sizeof(buf.buf);
174
175 do {
176 len = recv(udp_fd, ptr, to_recv - recvd, 0);
177 if (len > 0) {
178 recvd += len;
179 ptr += len;
180 break;
181 }
182 } while (len < 0 && (errno == EINTR));
183
184 if (recvd > 0)
185 len = recvd;
186 buf.len = len;
187
188 try {
189 turn::StunMsgResponse res(buf.buf, sizeof(buf.buf), (size_t)buf.len, true);
190
191 if (res.isCommand()) {
192
193 if(res.isSuccess()) {
194
195 if (res.isBindingResponse()) {
196
197 ioa_addr reflexive_addr;
198 addr_set_any(&reflexive_addr);
199 turn::StunAttrIterator iter(res,STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS);
200 if (!iter.eof()) {
201
202 turn::StunAttrAddr addr(iter);
203 addr.getAddr(reflexive_addr);
204
205 turn::StunAttrIterator iter1(res,STUN_ATTRIBUTE_OTHER_ADDRESS);
206 if (!iter1.eof()) {
207 *rfc5780 = 1;
208 printf("\n========================================\n");
209 printf("RFC 5780 response %d\n",++counter);
210 ioa_addr other_addr;
211 turn::StunAttrAddr addr1(iter1);
212 addr1.getAddr(other_addr);
213 turn::StunAttrIterator iter2(res,STUN_ATTRIBUTE_RESPONSE_ORIGIN);
214 if (!iter2.eof()) {
215 ioa_addr response_origin;
216 turn::StunAttrAddr addr2(iter2);
217 addr2.getAddr(response_origin);
218 addr_debug_print(1, &response_origin, "Response origin: ");
219 }
220 addr_debug_print(1, &other_addr, "Other addr: ");
221 }
222 addr_debug_print(1, &reflexive_addr, "UDP reflexive addr");
223
224 } else {
225 printf("Cannot read the response\n");
226 }
227 } else {
228 printf("Wrong type of response\n");
229 }
230 } else {
231 int err_code = res.getError();
232 std::string reason = res.getReason();
233
234 printf("The response is an error %d (%s)\n", err_code, reason.c_str());
235 }
236 } else {
237 printf("The response is not a response message\n");
238 }
239 } catch(...) {
240 printf("The response is not a well formed STUN message\n");
241 }
242 }
243
244 return 0;
245 }
246
247 #else
248
run_stunclient(const char * rip,int rport,int * port,int * rfc5780,int response_port,int change_ip,int change_port,int padding)249 static int run_stunclient(const char* rip, int rport, int *port, int *rfc5780, int response_port, int change_ip, int change_port, int padding)
250 {
251
252 ioa_addr remote_addr;
253 int new_udp_fd = -1;
254 stun_buffer buf;
255
256 bzero(&remote_addr, sizeof(remote_addr));
257 if (make_ioa_addr((const uint8_t*) rip, rport, &remote_addr) < 0)
258 err(-1, NULL);
259
260 if (udp_fd < 0) {
261 udp_fd = socket(remote_addr.ss.sa_family, CLIENT_DGRAM_SOCKET_TYPE, CLIENT_DGRAM_SOCKET_PROTOCOL);
262 if (udp_fd < 0)
263 err(-1, NULL);
264
265 if (!addr_any(&real_local_addr)) {
266 if (addr_bind(udp_fd, &real_local_addr,0,1,UDP_SOCKET) < 0)
267 err(-1, NULL);
268 }
269 }
270
271 if (response_port >= 0) {
272
273 new_udp_fd = socket(remote_addr.ss.sa_family, CLIENT_DGRAM_SOCKET_TYPE, CLIENT_DGRAM_SOCKET_PROTOCOL);
274 if (new_udp_fd < 0)
275 err(-1, NULL);
276
277 addr_set_port(&real_local_addr, response_port);
278
279 if (addr_bind(new_udp_fd, &real_local_addr,0,1,UDP_SOCKET) < 0)
280 err(-1, NULL);
281 }
282
283 stun_prepare_binding_request(&buf);
284
285 if (response_port >= 0) {
286 stun_attr_add_response_port_str((uint8_t*) (buf.buf), (size_t*) &(buf.len), (uint16_t) response_port);
287 }
288 if (change_ip || change_port) {
289 stun_attr_add_change_request_str((uint8_t*) buf.buf, (size_t*) &(buf.len), change_ip, change_port);
290 }
291 if (padding) {
292 if(stun_attr_add_padding_str((uint8_t*) buf.buf, (size_t*) &(buf.len), 1500)<0) {
293 printf("%s: ERROR: Cannot add padding\n",__FUNCTION__);
294 }
295 }
296
297 {
298 int len = 0;
299 int slen = get_ioa_addr_len(&remote_addr);
300
301 do {
302 len = sendto(udp_fd, buf.buf, buf.len, 0, (struct sockaddr*) &remote_addr, (socklen_t) slen);
303 } while (len < 0 && ((errno == EINTR) || (errno == ENOBUFS) || (errno == EAGAIN)));
304
305 if (len < 0)
306 err(-1, NULL);
307
308 }
309
310 if (addr_get_from_sock(udp_fd, &real_local_addr) < 0) {
311 printf("%s: Cannot get address from local socket\n", __FUNCTION__);
312 } else {
313 *port = addr_get_port(&real_local_addr);
314 }
315
316 {
317 if(new_udp_fd >= 0) {
318 socket_closesocket(udp_fd);
319 udp_fd = new_udp_fd;
320 new_udp_fd = -1;
321 }
322 }
323
324 {
325 int len = 0;
326 uint8_t *ptr = buf.buf;
327 int recvd = 0;
328 const int to_recv = sizeof(buf.buf);
329
330 do {
331 len = recv(udp_fd, ptr, to_recv - recvd, 0);
332 if (len > 0) {
333 recvd += len;
334 ptr += len;
335 break;
336 }
337 } while (len < 0 && ((errno == EINTR) || (errno == EAGAIN)));
338
339 if (recvd > 0)
340 len = recvd;
341 buf.len = len;
342
343 if (stun_is_command_message(&buf)) {
344
345 if (stun_is_response(&buf)) {
346
347 if (stun_is_success_response(&buf)) {
348
349 if (stun_is_binding_response(&buf)) {
350
351 ioa_addr reflexive_addr;
352 addr_set_any(&reflexive_addr);
353 if (stun_attr_get_first_addr(&buf, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, &reflexive_addr, NULL) >= 0) {
354
355 stun_attr_ref sar = stun_attr_get_first_by_type_str(buf.buf, buf.len, STUN_ATTRIBUTE_OTHER_ADDRESS);
356 if (sar) {
357 *rfc5780 = 1;
358 printf("\n========================================\n");
359 printf("RFC 5780 response %d\n",++counter);
360 ioa_addr other_addr;
361 stun_attr_get_addr_str((uint8_t *) buf.buf, (size_t) buf.len, sar, &other_addr, NULL);
362 sar = stun_attr_get_first_by_type_str(buf.buf, buf.len, STUN_ATTRIBUTE_RESPONSE_ORIGIN);
363 if (sar) {
364 ioa_addr response_origin;
365 stun_attr_get_addr_str((uint8_t *) buf.buf, (size_t) buf.len, sar, &response_origin, NULL);
366 addr_debug_print(1, &response_origin, "Response origin: ");
367 }
368 addr_debug_print(1, &other_addr, "Other addr: ");
369 }
370 addr_debug_print(1, &reflexive_addr, "UDP reflexive addr");
371
372 } else {
373 printf("Cannot read the response\n");
374 }
375 } else {
376 printf("Wrong type of response\n");
377 }
378 } else {
379 int err_code = 0;
380 uint8_t err_msg[1025] = "\0";
381 size_t err_msg_size = sizeof(err_msg);
382 if (stun_is_error_response(&buf, &err_code, err_msg, err_msg_size)) {
383 printf("The response is an error %d (%s)\n", err_code, (char*) err_msg);
384 } else {
385 printf("The response is an unrecognized error\n");
386 }
387 }
388 } else {
389 printf("The response is not a response message\n");
390 }
391 } else {
392 printf("The response is not a STUN message\n");
393 }
394 }
395
396 return 0;
397 }
398 #endif
399
400 //////////////// local definitions /////////////////
401
402 static char Usage[] =
403 "Usage: stunclient [options] address\n"
404 "Options:\n"
405 " -p STUN server port (Default: 3478)\n"
406 " -L Local address to use (optional)\n"
407 " -f Force RFC 5780 processing\n";
408
409 //////////////////////////////////////////////////
410
main(int argc,char ** argv)411 int main(int argc, char **argv)
412 {
413 int port = DEFAULT_STUN_PORT;
414 char local_addr[256]="\0";
415 int c=0;
416 int forceRfc5780 = 0;
417
418 set_logfile("stdout");
419 set_system_parameters(0);
420
421 bzero(local_addr, sizeof(local_addr));
422
423 while ((c = getopt(argc, argv, "p:L:f")) != -1) {
424 switch(c) {
425 case 'f':
426 forceRfc5780 = 1;
427 break;
428 case 'p':
429 port = atoi(optarg);
430 break;
431 case 'L':
432 STRCPY(local_addr, optarg);
433 break;
434 default:
435 fprintf(stderr,"%s\n", Usage);
436 exit(1);
437 }
438 }
439
440 if(optind>=argc) {
441 fprintf(stderr, "%s\n", Usage);
442 exit(-1);
443 }
444
445 addr_set_any(&real_local_addr);
446
447 if(local_addr[0]) {
448 if(make_ioa_addr((const uint8_t*)local_addr, 0, &real_local_addr)<0) {
449 err(-1,NULL);
450 }
451 }
452
453 int local_port = -1;
454 int rfc5780 = 0;
455
456 run_stunclient(argv[optind], port, &local_port, &rfc5780,-1,0,0,0);
457
458 if(rfc5780 || forceRfc5780) {
459 run_stunclient(argv[optind], port, &local_port, &rfc5780,local_port+1,1,1,0);
460 run_stunclient(argv[optind], port, &local_port, &rfc5780,-1,1,1,1);
461 }
462
463 socket_closesocket(udp_fd);
464
465 return 0;
466 }
467