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
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.
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.
46 #include <sys/types.h>
47 #include <sys/socket.h>
50 #include "stun/stunagent.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
)
88 if (stun_message_append32 (msg
, STUN_ATTRIBUTE_BANDWIDTH
, bandwidth
) !=
89 STUN_MESSAGE_RETURN_SUCCESS
)
93 if (stun_message_append32 (msg
, STUN_ATTRIBUTE_MAGIC_COOKIE
,
94 TURN_MAGIC_COOKIE
) != STUN_MESSAGE_RETURN_SUCCESS
)
98 if (compatibility
== STUN_USAGE_TURN_COMPATIBILITY_OC2007
) {
99 stun_message_append32(msg
, STUN_ATTRIBUTE_MS_VERSION
, 1);
103 if (stun_message_append32 (msg
, STUN_ATTRIBUTE_LIFETIME
, lifetime
) !=
104 STUN_MESSAGE_RETURN_SUCCESS
)
108 if ((compatibility
== STUN_USAGE_TURN_COMPATIBILITY_DRAFT9
||
109 compatibility
== STUN_USAGE_TURN_COMPATIBILITY_RFC5766
) &&
110 request_props
!= STUN_USAGE_TURN_REQUEST_PORT_NORMAL
) {
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
)
126 if (previous_response
) {
129 uint64_t reservation
;
132 realm
= (uint8_t *) stun_message_find (previous_response
,
133 STUN_ATTRIBUTE_REALM
, &len
);
135 if (stun_message_append_bytes (msg
, STUN_ATTRIBUTE_REALM
, realm
, len
) !=
136 STUN_MESSAGE_RETURN_SUCCESS
)
139 nonce
= (uint8_t *) stun_message_find (previous_response
,
140 STUN_ATTRIBUTE_NONCE
, &len
);
142 if (stun_message_append_bytes (msg
, STUN_ATTRIBUTE_NONCE
, nonce
, len
) !=
143 STUN_MESSAGE_RETURN_SUCCESS
)
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
)
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
)
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
);
181 if (stun_message_append32 (msg
, STUN_ATTRIBUTE_LIFETIME
, lifetime
) !=
182 STUN_MESSAGE_RETURN_SUCCESS
)
186 if (previous_response
) {
191 realm
= (uint8_t *) stun_message_find (previous_response
,
192 STUN_ATTRIBUTE_REALM
, &len
);
194 if (stun_message_append_bytes (msg
, STUN_ATTRIBUTE_REALM
, realm
, len
) !=
195 STUN_MESSAGE_RETURN_SUCCESS
)
198 nonce
= (uint8_t *) stun_message_find (previous_response
,
199 STUN_ATTRIBUTE_NONCE
, &len
);
201 if (stun_message_append_bytes (msg
, STUN_ATTRIBUTE_NONCE
, nonce
, len
) !=
202 STUN_MESSAGE_RETURN_SUCCESS
)
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
)
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
)
230 stun_agent_init_request (agent
, msg
, buffer
, buffer_len
,
231 STUN_CREATEPERMISSION
);
234 if (stun_message_append_xor_addr (msg
, STUN_ATTRIBUTE_XOR_PEER_ADDRESS
,
235 peer
, sizeof(*peer
)) != STUN_MESSAGE_RETURN_SUCCESS
) {
241 if (stun_message_append_bytes (msg
, STUN_ATTRIBUTE_NONCE
,
242 nonce
, nonce_len
) != STUN_MESSAGE_RETURN_SUCCESS
)
248 if (stun_message_append_bytes (msg
, STUN_ATTRIBUTE_REALM
,
249 realm
, realm_len
) != STUN_MESSAGE_RETURN_SUCCESS
)
254 if (username
!= NULL
) {
255 if (stun_message_append_bytes (msg
, STUN_ATTRIBUTE_USERNAME
,
256 username
, username_len
) != STUN_MESSAGE_RETURN_SUCCESS
)
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
)
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
))
280 case STUN_INDICATION
:
281 return STUN_USAGE_TURN_RETURN_INVALID
;
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
;
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");
368 StunUsageTurnReturn
stun_usage_turn_refresh_process (StunMessage
*msg
,
369 uint32_t *lifetime
, StunUsageTurnCompatibility compatibility
)
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
;
379 if (stun_message_get_method (msg
) != STUN_ALLOCATE
)
380 return STUN_USAGE_TURN_RETURN_INVALID
;
383 switch (stun_message_get_class (msg
))
386 case STUN_INDICATION
:
387 return STUN_USAGE_TURN_RETURN_INVALID
;
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");