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