1 /*
2 	liblinphone_tester - liblinphone test suite
3 	Copyright (C) 2013  Belledonne Communications SARL
4 
5 	This program is free software: you can redistribute it and/or modify
6 	it under the terms of the GNU General Public License as published by
7 	the Free Software Foundation, either version 2 of the License, or
8 	(at your option) any later version.
9 
10 	This program is distributed in the hope that it will be useful,
11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 	GNU General Public License for more details.
14 
15 	You should have received a copy of the GNU General Public License
16 	along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include "linphone/core.h"
22 #include "linphone/lpconfig.h"
23 #include "private.h"
24 #include "liblinphone_tester.h"
25 
26 /* Retrieve the public IP from a given hostname */
get_ip_from_hostname(const char * tunnel_hostname,char * ip,size_t ip_size)27 int get_ip_from_hostname(const char * tunnel_hostname, char *ip, size_t ip_size){
28 	struct addrinfo hints;
29 	struct addrinfo *res = NULL;
30 	int err;
31 	memset(&hints, 0, sizeof(hints));
32 	hints.ai_family = AF_UNSPEC;
33 	hints.ai_socktype = SOCK_STREAM;
34 	if ((err = getaddrinfo(tunnel_hostname, NULL, &hints, &res))){
35 		ms_error("error while retrieving IP from %s: %s", tunnel_hostname, gai_strerror(err));
36 		return err;
37 	}
38 
39 	bctbx_addrinfo_to_ip_address(res, ip, ip_size, NULL);
40 	freeaddrinfo(res);
41 	return err;
42 }
get_public_contact_ip(LinphoneCore * lc)43 static char* get_public_contact_ip(LinphoneCore* lc)  {
44 	const LinphoneAddress * contact = linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(lc));
45 	BC_ASSERT_PTR_NOT_NULL(contact);
46 	return ms_strdup(linphone_address_get_domain(contact));
47 }
48 
49 
call_with_tunnel_base(LinphoneTunnelMode tunnel_mode,bool_t with_sip,LinphoneMediaEncryption encryption,bool_t with_video_and_ice,bool_t dual_socket)50 static void call_with_tunnel_base(LinphoneTunnelMode tunnel_mode, bool_t with_sip, LinphoneMediaEncryption encryption, bool_t with_video_and_ice, bool_t dual_socket) {
51 	if (linphone_core_tunnel_available()){
52 		LinphoneCoreManager *pauline = linphone_core_manager_new( "pauline_rc");
53 		LinphoneCoreManager *marie = linphone_core_manager_new( "marie_rc");
54 		LinphoneCall *pauline_call, *marie_call;
55 		LinphoneProxyConfig *proxy = linphone_core_get_default_proxy_config(pauline->lc);
56 		LinphoneAddress *server_addr = linphone_address_new(linphone_proxy_config_get_server_addr(proxy));
57 		LinphoneAddress *route = linphone_address_new(linphone_proxy_config_get_route(proxy));
58 		char  tunnel_ip[64];
59 		char *public_ip, *public_ip2=NULL;
60 		BC_ASSERT_FALSE(get_ip_from_hostname("tunnel.linphone.org",tunnel_ip,sizeof(tunnel_ip)));
61 
62 		BC_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneRegistrationOk,1));
63 		public_ip = get_public_contact_ip(pauline->lc);
64 		BC_ASSERT_STRING_NOT_EQUAL(public_ip, tunnel_ip);
65 
66 		linphone_core_set_media_encryption(pauline->lc, encryption);
67 
68 		if (with_video_and_ice){
69 			/*we want to test that tunnel is able to work with long SIP message, above mtu.
70 			 * Enable ICE and many codec to make the SIP message bigger*/
71 			linphone_core_set_firewall_policy(marie->lc, LinphonePolicyUseIce);
72 			linphone_core_set_firewall_policy(pauline->lc, LinphonePolicyUseIce);
73 			linphone_core_enable_payload_type(pauline->lc,
74 				linphone_core_find_payload_type(pauline->lc, "speex", 32000, 1), TRUE);
75 			linphone_core_enable_payload_type(pauline->lc,
76 				linphone_core_find_payload_type(pauline->lc, "speex", 16000, 1), TRUE);
77 			linphone_core_enable_payload_type(pauline->lc,
78 				linphone_core_find_payload_type(pauline->lc, "G722", 8000, 1), TRUE);
79 		}
80 
81 		if (tunnel_mode != LinphoneTunnelModeDisable){
82 			LinphoneTunnel *tunnel = linphone_core_get_tunnel(pauline->lc);
83 			LinphoneTunnelConfig *config = linphone_tunnel_config_new();
84 
85 			linphone_tunnel_config_set_host(config, "tunnel.linphone.org");
86 			linphone_tunnel_config_set_port(config, 443);
87 			if (!dual_socket) {
88 				linphone_tunnel_config_set_host(config, "tunnel.linphone.org");
89 				linphone_tunnel_config_set_port(config, 443);
90 				linphone_tunnel_config_set_remote_udp_mirror_port(config, 12345);
91 			} else {
92 				linphone_tunnel_config_set_host(config, "94.23.19.176");
93 				linphone_tunnel_config_set_port(config, 4443);
94 				linphone_tunnel_config_set_host2(config, "188.165.40.171");
95 				linphone_tunnel_config_set_port2(config, 4443);
96 				linphone_tunnel_config_set_remote_udp_mirror_port(config, -1);
97 				linphone_tunnel_enable_dual_mode(tunnel, TRUE);
98 			}
99 			linphone_tunnel_add_server(tunnel, config);
100 			linphone_tunnel_set_mode(tunnel, tunnel_mode);
101 			linphone_tunnel_enable_sip(tunnel, with_sip);
102 			linphone_tunnel_config_unref(config);
103 
104 			/*
105 			 * Enabling the tunnel with sip cause another REGISTER to be made.
106 			 * In automatic mode, the udp test should conclude (assuming we have a normal network), that no
107 			 * tunnel is needed. Thus the number of registrations should stay to 1.
108 			 * The library is missing a notification of "tunnel connectivity test finished" to enable the
109 			 * full testing of the automatic mode.
110 			 */
111 
112 			if (tunnel_mode == LinphoneTunnelModeEnable && with_sip) {
113 				BC_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneRegistrationOk,2));
114 				/* Ensure that we did use the tunnel. If so, we should see contact changed from:
115 				Contact: <sip:pauline@192.168.0.201>;.[...]
116 				To:
117 				Contact: <sip:pauline@91.121.209.194:43867>;[....] (91.121.209.194 must be tunnel.liphone.org)
118 				*/
119 				ms_free(public_ip);
120 				public_ip = get_public_contact_ip(pauline->lc);
121 				if (!dual_socket) {
122 					BC_ASSERT_STRING_EQUAL(public_ip, tunnel_ip);
123 				} else {
124 					BC_ASSERT_STRING_EQUAL(public_ip, "94.23.19.176");
125 				}
126 			} else {
127 				public_ip2 = get_public_contact_ip(pauline->lc);
128 				BC_ASSERT_STRING_EQUAL(public_ip, public_ip2);
129 			}
130 		}
131 
132 		BC_ASSERT_TRUE(call(pauline,marie));
133 		pauline_call=linphone_core_get_current_call(pauline->lc);
134 		BC_ASSERT_PTR_NOT_NULL(pauline_call);
135 		if (pauline_call!=NULL){
136 			BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(linphone_call_get_current_params(pauline_call)),
137 				encryption, int, "%d");
138 		}
139 		if (tunnel_mode == LinphoneTunnelModeEnable && with_sip){
140 			/* make sure the call from pauline arrived from the tunnel by checking the contact address*/
141 			marie_call = linphone_core_get_current_call(marie->lc);
142 			BC_ASSERT_PTR_NOT_NULL(marie_call);
143 			if (marie_call){
144 				const char *remote_contact = linphone_call_get_remote_contact(marie_call);
145 				BC_ASSERT_PTR_NOT_NULL(remote_contact);
146 				if (remote_contact){
147 					LinphoneAddress *tmp = linphone_address_new(remote_contact);
148 					BC_ASSERT_PTR_NOT_NULL(tmp);
149 					if (tmp){
150 						if (!dual_socket) {
151 							BC_ASSERT_STRING_EQUAL(linphone_address_get_domain(tmp), tunnel_ip);
152 						} else {
153 							BC_ASSERT_STRING_EQUAL(linphone_address_get_domain(tmp), "94.23.19.176");
154 						}
155 						linphone_address_unref(tmp);
156 					}
157 				}
158 			}
159 		}
160 #ifdef VIDEO_ENABLED
161 		if (with_video_and_ice){
162 			BC_ASSERT_TRUE(request_video(pauline, marie, TRUE));
163 		}
164 #endif
165 		end_call(pauline,marie);
166 
167 		ms_free(public_ip);
168 		if(public_ip2 != NULL) ms_free(public_ip2);
169 		linphone_address_unref(server_addr);
170 		linphone_address_unref(route);
171 		linphone_core_manager_destroy(pauline);
172 		linphone_core_manager_destroy(marie);
173 	}else{
174 		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
175 	}
176 }
177 
178 
call_with_tunnel(void)179 static void call_with_tunnel(void) {
180 	call_with_tunnel_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionNone, FALSE, FALSE);
181 }
182 
call_with_tunnel_srtp(void)183 static void call_with_tunnel_srtp(void) {
184 	call_with_tunnel_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionSRTP, FALSE, FALSE);
185 }
186 
call_with_tunnel_without_sip(void)187 static void call_with_tunnel_without_sip(void) {
188 	call_with_tunnel_base(LinphoneTunnelModeEnable, FALSE, LinphoneMediaEncryptionNone, FALSE, FALSE);
189 }
190 
call_with_tunnel_auto(void)191 static void call_with_tunnel_auto(void) {
192 	call_with_tunnel_base(LinphoneTunnelModeAuto, TRUE, LinphoneMediaEncryptionNone, FALSE, FALSE);
193 }
194 
call_with_tunnel_auto_without_sip_with_srtp(void)195 static void call_with_tunnel_auto_without_sip_with_srtp(void) {
196 	call_with_tunnel_base(LinphoneTunnelModeAuto, FALSE, LinphoneMediaEncryptionSRTP, FALSE, FALSE);
197 }
198 
199 #ifdef VIDEO_ENABLED
200 
full_tunnel_video_ice_call(void)201 static void full_tunnel_video_ice_call(void){
202 	if (linphone_core_tunnel_available()){
203 		call_with_tunnel_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionNone, TRUE, FALSE);
204 	}else
205 		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
206 }
207 
tunnel_srtp_video_ice_call(void)208 static void tunnel_srtp_video_ice_call(void) {
209 	if (linphone_core_tunnel_available())
210 		call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce,TRUE);
211 	else
212 		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
213 }
tunnel_zrtp_video_ice_call(void)214 static void tunnel_zrtp_video_ice_call(void) {
215 	if (linphone_core_tunnel_available())
216 		call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce,TRUE);
217 	else
218 		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
219 }
220 
tunnel_dtls_video_ice_call(void)221 static void tunnel_dtls_video_ice_call(void) {
222 	if (linphone_core_tunnel_available())
223 		call_base(LinphoneMediaEncryptionDTLS,TRUE,FALSE,LinphonePolicyUseIce,TRUE);
224 	else
225 		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
226 }
227 
tunnel_video_ice_call(void)228 static void tunnel_video_ice_call(void) {
229 	if (linphone_core_tunnel_available())
230 		call_base(LinphoneMediaEncryptionNone,TRUE,FALSE,LinphonePolicyUseIce,TRUE);
231 	else
232 		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
233 }
234 #endif
235 
tunnel_srtp_ice_call(void)236 static void tunnel_srtp_ice_call(void) {
237 	if (linphone_core_tunnel_available())
238 		call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce,TRUE);
239 	else
240 		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
241 }
242 
tunnel_zrtp_ice_call(void)243 static void tunnel_zrtp_ice_call(void) {
244 	if (linphone_core_tunnel_available())
245 		call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce,TRUE);
246 	else
247 		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
248 }
249 
tunnel_ice_call(void)250 static void tunnel_ice_call(void) {
251 	if (linphone_core_tunnel_available())
252 		call_base(LinphoneMediaEncryptionNone,FALSE,FALSE,LinphonePolicyUseIce,TRUE);
253 	else
254 		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
255 }
256 
register_on_second_tunnel(void)257 static void register_on_second_tunnel(void) {
258 	if (linphone_core_tunnel_available()) {
259 		LinphoneCoreManager *pauline = linphone_core_manager_new( "pauline_rc");
260 		LinphoneTunnel *tunnel = linphone_core_get_tunnel(pauline->lc);
261 		LinphoneTunnelConfig *config1 = linphone_tunnel_config_new();
262 		LinphoneTunnelConfig *config2 = linphone_tunnel_config_new();
263 		char tunnel_ip[64];
264 		char* public_ip;
265 
266 		BC_ASSERT_FALSE(get_ip_from_hostname("tunnel.linphone.org",tunnel_ip,sizeof(tunnel_ip)));
267 		linphone_tunnel_simulate_udp_loss(tunnel, TRUE);
268 
269 		// add a first tunnel config with an invalid port
270 		linphone_tunnel_config_set_host(config1, "sip3.linphone.org");
271 		linphone_tunnel_config_set_port(config1, 4141);
272 		linphone_tunnel_config_set_remote_udp_mirror_port(config1, 54321);
273 		linphone_tunnel_add_server(tunnel, config1);
274 
275 		// then a proper server
276 		linphone_tunnel_config_set_host(config2, "tunnel.linphone.org");
277 		linphone_tunnel_config_set_port(config2, 443);
278 		linphone_tunnel_config_set_remote_udp_mirror_port(config2, 12345);
279 		linphone_tunnel_add_server(tunnel, config2);
280 
281 		linphone_tunnel_set_mode(tunnel, LinphoneTunnelModeAuto);
282 		linphone_tunnel_enable_sip(tunnel, TRUE);
283 
284 		reset_counters(&pauline->stat);
285 
286 		linphone_core_refresh_registers(pauline->lc);
287 		// we should expect 2 registers: since tunnel autodetection takes several seconds, a first
288 		// register will be made, then tunnel will be configured and another register will be fired up
289 		BC_ASSERT_TRUE(wait_for(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk,2));
290 
291 		public_ip = get_public_contact_ip(pauline->lc);
292 		BC_ASSERT_STRING_EQUAL(public_ip, tunnel_ip);
293 		ms_free(public_ip);
294 
295 		linphone_tunnel_config_unref(config1);
296 		linphone_tunnel_config_unref(config2);
297 		linphone_core_manager_destroy(pauline);
298 	} else {
299 		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
300 	}
301 }
302 
dual_socket_mode(void)303 static void dual_socket_mode(void) {
304 	if (linphone_core_tunnel_available())
305 		call_with_tunnel_base(LinphoneTunnelModeEnable, FALSE, LinphoneMediaEncryptionNone, FALSE, TRUE);
306 	else
307 		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
308 }
309 
dual_socket_mode_with_sip(void)310 static void dual_socket_mode_with_sip(void) {
311 	if (linphone_core_tunnel_available())
312 		call_with_tunnel_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionNone, FALSE, TRUE);
313 	else
314 		ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
315 }
316 
317 test_t tunnel_tests[] = {
318 	TEST_NO_TAG("Simple", call_with_tunnel),
319 	TEST_NO_TAG("With SRTP", call_with_tunnel_srtp),
320 	TEST_NO_TAG("Without SIP", call_with_tunnel_without_sip),
321 	TEST_NO_TAG("In automatic mode", call_with_tunnel_auto),
322 	TEST_NO_TAG("In automatic mode with SRTP without SIP", call_with_tunnel_auto_without_sip_with_srtp),
323 	TEST_NO_TAG("Ice call", tunnel_ice_call),
324 	TEST_NO_TAG("SRTP ice call", tunnel_srtp_ice_call),
325 	TEST_NO_TAG("ZRTP ice call", tunnel_zrtp_ice_call),
326 #ifdef VIDEO_ENABLED
327 	TEST_NO_TAG("Ice video call", tunnel_video_ice_call),
328 	TEST_NO_TAG("With SIP - ice video call", full_tunnel_video_ice_call),
329 	TEST_NO_TAG("SRTP ice video call", tunnel_srtp_video_ice_call),
330 	TEST_NO_TAG("DTLS ice video call", tunnel_dtls_video_ice_call),
331 	TEST_NO_TAG("ZRTP ice video call", tunnel_zrtp_video_ice_call),
332 #endif
333 	TEST_NO_TAG("Register on second tunnel", register_on_second_tunnel),
334 	TEST_NO_TAG("Dual socket mode", dual_socket_mode),
335 	TEST_NO_TAG("Dual socket mode with SIP", dual_socket_mode_with_sip),
336 };
337 
338 test_suite_t tunnel_test_suite = {"Tunnel", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,
339 								  sizeof(tunnel_tests) / sizeof(tunnel_tests[0]), tunnel_tests};
340