Refuse to create a permission without a peer instead of not sending the XOR_PEER_ADDRESS
[sipe-libnice.git] / stun / usages / turn.c
blob5bcf89b8a7984954affe5170112901f09b5a2410
1 /*
2 * This file is part of the Nice GLib ICE library.
4 * (C) 2008-2009 Collabora Ltd.
5 * Contact: Youness Alaoui
6 * (C) 2007-2009 Nokia Corporation. All rights reserved.
7 * Contact: Rémi Denis-Courmont
9 * The contents of this file are subject to the Mozilla Public License Version
10 * 1.1 (the "License"); you may not use this file except in compliance with
11 * the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
14 * Software distributed under the License is distributed on an "AS IS" basis,
15 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16 * for the specific language governing rights and limitations under the
17 * License.
19 * The Original Code is the Nice GLib ICE library.
21 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
22 * Corporation. All Rights Reserved.
24 * Contributors:
25 * Youness Alaoui, Collabora Ltd.
26 * Rémi Denis-Courmont, Nokia
28 * Alternatively, the contents of this file may be used under the terms of the
29 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
30 * case the provisions of LGPL are applicable instead of those above. If you
31 * wish to allow use of your version of this file only under the terms of the
32 * LGPL and not to allow others to use your version of this file under the
33 * MPL, indicate your decision by deleting the provisions above and replace
34 * them with the notice and other provisions required by the LGPL. If you do
35 * not delete the provisions above, a recipient may use your version of this
36 * file under either the MPL or the LGPL.
39 #ifdef HAVE_CONFIG_H
40 # include <config.h>
41 #endif
43 #ifdef _WIN32
44 #include <winsock2.h>
45 #else
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #endif
50 #include "stun/stunagent.h"
51 #include "turn.h"
53 #include <string.h>
54 #include <stdlib.h>
55 #include <fcntl.h>
59 #define REQUESTED_PROPS_E 0x80000000
60 #define REQUESTED_PROPS_R 0x40000000
61 #define REQUESTED_PROPS_P 0x20000000
64 #define STUN_ATTRIBUTE_MSN_MAPPED_ADDRESS 0x8000
67 #define TURN_REQUESTED_TRANSPORT_UDP 0x11000000
69 /** Non-blocking mode STUN TURN usage */
71 size_t stun_usage_turn_create (StunAgent *agent, StunMessage *msg,
72 uint8_t *buffer, size_t buffer_len,
73 StunMessage *previous_response,
74 StunUsageTurnRequestPorts request_props,
75 int32_t bandwidth, int32_t lifetime,
76 uint8_t *username, size_t username_len,
77 uint8_t *password, size_t password_len,
78 StunUsageTurnCompatibility compatibility)
80 stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_ALLOCATE);
82 if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 ||
83 compatibility == STUN_USAGE_TURN_COMPATIBILITY_RFC5766) {
84 if (stun_message_append32 (msg, STUN_ATTRIBUTE_REQUESTED_TRANSPORT,
85 TURN_REQUESTED_TRANSPORT_UDP) != STUN_MESSAGE_RETURN_SUCCESS)
86 return 0;
87 if (bandwidth >= 0) {
88 if (stun_message_append32 (msg, STUN_ATTRIBUTE_BANDWIDTH, bandwidth) !=
89 STUN_MESSAGE_RETURN_SUCCESS)
90 return 0;
92 } else {
93 if (stun_message_append32 (msg, STUN_ATTRIBUTE_MAGIC_COOKIE,
94 TURN_MAGIC_COOKIE) != STUN_MESSAGE_RETURN_SUCCESS)
95 return 0;
98 if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_OC2007) {
99 stun_message_append32(msg, STUN_ATTRIBUTE_MS_VERSION, 1);
102 if (lifetime >= 0) {
103 if (stun_message_append32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime) !=
104 STUN_MESSAGE_RETURN_SUCCESS)
105 return 0;
108 if ((compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 ||
109 compatibility == STUN_USAGE_TURN_COMPATIBILITY_RFC5766) &&
110 request_props != STUN_USAGE_TURN_REQUEST_PORT_NORMAL) {
111 uint32_t req = 0;
114 if (request_props & STUN_USAGE_TURN_REQUEST_PORT_EVEN_AND_RESERVE) {
115 req |= REQUESTED_PROPS_R;
116 req |= REQUESTED_PROPS_E;
117 } else if (request_props & STUN_USAGE_TURN_REQUEST_PORT_EVEN) {
118 req |= REQUESTED_PROPS_E;
121 if (stun_message_append32 (msg, STUN_ATTRIBUTE_REQUESTED_PORT_PROPS,
122 req) != STUN_MESSAGE_RETURN_SUCCESS)
123 return 0;
126 if (previous_response) {
127 uint8_t *realm;
128 uint8_t *nonce;
129 uint64_t reservation;
130 uint16_t len;
132 realm = (uint8_t *) stun_message_find (previous_response,
133 STUN_ATTRIBUTE_REALM, &len);
134 if (realm != NULL) {
135 if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM, realm, len) !=
136 STUN_MESSAGE_RETURN_SUCCESS)
137 return 0;
139 nonce = (uint8_t *) stun_message_find (previous_response,
140 STUN_ATTRIBUTE_NONCE, &len);
141 if (nonce != NULL) {
142 if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE, nonce, len) !=
143 STUN_MESSAGE_RETURN_SUCCESS)
144 return 0;
146 if (stun_message_find64 (previous_response,
147 STUN_ATTRIBUTE_RESERVATION_TOKEN,
148 &reservation) == STUN_MESSAGE_RETURN_SUCCESS) {
149 if (stun_message_append64 (msg, STUN_ATTRIBUTE_RESERVATION_TOKEN,
150 reservation) != STUN_MESSAGE_RETURN_SUCCESS)
151 return 0;
155 if (username != NULL && username_len > 0) {
156 if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME,
157 username, username_len) != STUN_MESSAGE_RETURN_SUCCESS)
158 return 0;
161 return stun_agent_finish_message (agent, msg, password, password_len);
164 size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg,
165 uint8_t *buffer, size_t buffer_len,
166 StunMessage *previous_response, int32_t lifetime,
167 uint8_t *username, size_t username_len,
168 uint8_t *password, size_t password_len,
169 StunUsageTurnCompatibility compatibility)
172 if (compatibility != STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 &&
173 compatibility != STUN_USAGE_TURN_COMPATIBILITY_RFC5766) {
174 return stun_usage_turn_create (agent, msg, buffer, buffer_len,
175 previous_response, STUN_USAGE_TURN_REQUEST_PORT_NORMAL, 0, lifetime,
176 username, username_len, password, password_len, compatibility);
179 stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_REFRESH);
180 if (lifetime >= 0) {
181 if (stun_message_append32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime) !=
182 STUN_MESSAGE_RETURN_SUCCESS)
183 return 0;
186 if (previous_response) {
187 uint8_t *realm;
188 uint8_t *nonce;
189 uint16_t len;
191 realm = (uint8_t *) stun_message_find (previous_response,
192 STUN_ATTRIBUTE_REALM, &len);
193 if (realm != NULL) {
194 if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM, realm, len) !=
195 STUN_MESSAGE_RETURN_SUCCESS)
196 return 0;
198 nonce = (uint8_t *) stun_message_find (previous_response,
199 STUN_ATTRIBUTE_NONCE, &len);
200 if (nonce != NULL) {
201 if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE, nonce, len) !=
202 STUN_MESSAGE_RETURN_SUCCESS)
203 return 0;
208 if (username != NULL && username_len > 0) {
209 if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME,
210 username, username_len) != STUN_MESSAGE_RETURN_SUCCESS)
211 return 0;
215 return stun_agent_finish_message (agent, msg, password, password_len);
218 size_t stun_usage_turn_create_permission (StunAgent *agent, StunMessage *msg,
219 uint8_t *buffer, size_t buffer_len,
220 uint8_t *username, size_t username_len,
221 uint8_t *password, size_t password_len,
222 uint8_t *realm, size_t realm_len,
223 uint8_t *nonce, size_t nonce_len,
224 struct sockaddr *peer,
225 StunUsageTurnCompatibility compatibility)
227 if (!peer)
228 return 0;
230 stun_agent_init_request (agent, msg, buffer, buffer_len,
231 STUN_CREATEPERMISSION);
233 /* PEER address */
234 if (stun_message_append_xor_addr (msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS,
235 peer, sizeof(*peer)) != STUN_MESSAGE_RETURN_SUCCESS) {
236 return 0;
239 /* nonce */
240 if (nonce != NULL) {
241 if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE,
242 nonce, nonce_len) != STUN_MESSAGE_RETURN_SUCCESS)
243 return 0;
246 /* realm */
247 if (realm != NULL) {
248 if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM,
249 realm, realm_len) != STUN_MESSAGE_RETURN_SUCCESS)
250 return 0;
253 /* username */
254 if (username != NULL) {
255 if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME,
256 username, username_len) != STUN_MESSAGE_RETURN_SUCCESS)
257 return 0;
260 return stun_agent_finish_message (agent, msg, password, password_len);
264 StunUsageTurnReturn stun_usage_turn_process (StunMessage *msg,
265 struct sockaddr *relay_addr, socklen_t *relay_addrlen,
266 struct sockaddr *addr, socklen_t *addrlen,
267 struct sockaddr *alternate_server, socklen_t *alternate_server_len,
268 uint32_t *bandwidth, uint32_t *lifetime,
269 StunUsageTurnCompatibility compatibility)
271 int val, code = -1;
272 StunUsageTurnReturn ret = STUN_USAGE_TURN_RETURN_RELAY_SUCCESS;
274 if (stun_message_get_method (msg) != STUN_ALLOCATE)
275 return STUN_USAGE_TURN_RETURN_INVALID;
277 switch (stun_message_get_class (msg))
279 case STUN_REQUEST:
280 case STUN_INDICATION:
281 return STUN_USAGE_TURN_RETURN_INVALID;
283 case STUN_RESPONSE:
284 break;
286 case STUN_ERROR:
287 if (stun_message_find_error (msg, &code) != STUN_MESSAGE_RETURN_SUCCESS) {
288 /* missing ERROR-CODE: ignore message */
289 return STUN_USAGE_TURN_RETURN_INVALID;
292 /* NOTE: currently we ignore unauthenticated messages if the context
293 * is authenticated, for security reasons. */
294 stun_debug (" STUN error message received (code: %d)\n", code);
296 /* ALTERNATE-SERVER mechanism */
297 if ((code / 100) == 3) {
298 if (alternate_server && alternate_server_len) {
299 if (stun_message_find_addr (msg, STUN_ATTRIBUTE_ALTERNATE_SERVER,
300 alternate_server, alternate_server_len) !=
301 STUN_MESSAGE_RETURN_SUCCESS) {
302 stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute\n");
303 return STUN_USAGE_TURN_RETURN_ERROR;
305 } else {
306 if (!stun_message_has_attribute (msg,
307 STUN_ATTRIBUTE_ALTERNATE_SERVER)) {
308 stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute\n");
309 return STUN_USAGE_TURN_RETURN_ERROR;
313 stun_debug ("Found alternate server\n");
314 return STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER;
317 return STUN_USAGE_TURN_RETURN_ERROR;
320 stun_debug ("Received %u-bytes STUN message\n", stun_message_length (msg));
322 if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 ||
323 compatibility == STUN_USAGE_TURN_COMPATIBILITY_RFC5766) {
324 val = stun_message_find_xor_addr (msg,
325 STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, addr, addrlen);
327 if (val == STUN_MESSAGE_RETURN_SUCCESS)
328 ret = STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS;
329 val = stun_message_find_xor_addr (msg,
330 STUN_ATTRIBUTE_RELAY_ADDRESS, relay_addr, relay_addrlen);
331 if (val != STUN_MESSAGE_RETURN_SUCCESS) {
332 stun_debug (" No RELAYED-ADDRESS: %d\n", val);
333 return STUN_USAGE_TURN_RETURN_ERROR;
335 } else if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_GOOGLE) {
336 val = stun_message_find_addr (msg,
337 STUN_ATTRIBUTE_MAPPED_ADDRESS, relay_addr, relay_addrlen);
338 if (val != STUN_MESSAGE_RETURN_SUCCESS) {
339 stun_debug (" No MAPPED-ADDRESS: %d\n", val);
340 return STUN_USAGE_TURN_RETURN_ERROR;
342 } else if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_MSN ||
343 compatibility == STUN_USAGE_TURN_COMPATIBILITY_OC2007) {
344 val = stun_message_find_addr (msg,
345 STUN_ATTRIBUTE_MSN_MAPPED_ADDRESS, addr, addrlen);
347 if (val == STUN_MESSAGE_RETURN_SUCCESS)
348 ret = STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS;
350 val = stun_message_find_addr (msg,
351 STUN_ATTRIBUTE_MAPPED_ADDRESS, relay_addr, relay_addrlen);
352 if (val != STUN_MESSAGE_RETURN_SUCCESS) {
353 stun_debug (" No MAPPED-ADDRESS: %d\n", val);
354 return STUN_USAGE_TURN_RETURN_ERROR;
358 stun_message_find32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime);
359 stun_message_find32 (msg, STUN_ATTRIBUTE_BANDWIDTH, bandwidth);
361 stun_debug (" Mapped address found!\n");
362 return ret;
368 StunUsageTurnReturn stun_usage_turn_refresh_process (StunMessage *msg,
369 uint32_t *lifetime, StunUsageTurnCompatibility compatibility)
371 int code = -1;
372 StunUsageTurnReturn ret = STUN_USAGE_TURN_RETURN_RELAY_SUCCESS;
374 if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 ||
375 compatibility == STUN_USAGE_TURN_COMPATIBILITY_RFC5766) {
376 if (stun_message_get_method (msg) != STUN_REFRESH)
377 return STUN_USAGE_TURN_RETURN_INVALID;
378 } else {
379 if (stun_message_get_method (msg) != STUN_ALLOCATE)
380 return STUN_USAGE_TURN_RETURN_INVALID;
383 switch (stun_message_get_class (msg))
385 case STUN_REQUEST:
386 case STUN_INDICATION:
387 return STUN_USAGE_TURN_RETURN_INVALID;
389 case STUN_RESPONSE:
390 break;
392 case STUN_ERROR:
393 if (stun_message_find_error (msg, &code) != STUN_MESSAGE_RETURN_SUCCESS) {
394 /* missing ERROR-CODE: ignore message */
395 return STUN_USAGE_TURN_RETURN_INVALID;
398 return STUN_USAGE_TURN_RETURN_ERROR;
401 stun_message_find32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime);
403 stun_debug ("TURN Refresh successful!\n");
404 return ret;