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.
50 #include <sys/types.h>
51 #include <sys/socket.h>
52 #include <arpa/inet.h>
56 #include "stunagent.h"
58 /** ICE connectivity checks **/
63 stun_usage_ice_conncheck_create (StunAgent *agent, StunMessage *msg,
64 uint8_t *buffer, size_t buffer_len,
65 const uint8_t *username, const size_t username_len,
66 const uint8_t *password, const size_t password_len,
67 bool cand_use, bool controlling, uint32_t priority,
68 uint64_t tie, const char *candidate_identifier,
69 StunUsageIceCompatibility compatibility)
71 StunMessageReturn val;
73 stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_BINDING);
75 if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_RFC5245 ||
76 compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2) {
79 val = stun_message_append_flag (msg, STUN_ATTRIBUTE_USE_CANDIDATE);
80 if (val != STUN_MESSAGE_RETURN_SUCCESS)
84 val = stun_message_append32 (msg, STUN_ATTRIBUTE_PRIORITY, priority);
85 if (val != STUN_MESSAGE_RETURN_SUCCESS)
89 val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLING, tie);
91 val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLED, tie);
92 if (val != STUN_MESSAGE_RETURN_SUCCESS)
96 if (username && username_len > 0) {
97 val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME,
98 username, username_len);
99 if (val != STUN_MESSAGE_RETURN_SUCCESS)
103 if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2 &&
104 candidate_identifier) {
105 size_t identifier_len = strlen(candidate_identifier);
106 size_t attribute_len = identifier_len;
107 int modulo4 = identifier_len % 4;
111 attribute_len += 4 - modulo4;
113 // Avoid a coverify false positive
114 assert (attribute_len >= identifier_len);
115 buf = malloc(attribute_len);
116 memset(buf, 0, attribute_len);
117 memcpy(buf, candidate_identifier, identifier_len);
119 val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_CANDIDATE_IDENTIFIER,
124 if (val != STUN_MESSAGE_RETURN_SUCCESS)
127 val = stun_message_append32 (msg,
128 STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION, 2);
130 if (val != STUN_MESSAGE_RETURN_SUCCESS)
134 return stun_agent_finish_message (agent, msg, password, password_len);
139 StunUsageIceReturn stun_usage_ice_conncheck_process (StunMessage *msg,
140 struct sockaddr_storage *addr, socklen_t *addrlen,
141 StunUsageIceCompatibility compatibility)
144 StunMessageReturn val;
146 if (stun_message_get_method (msg) != STUN_BINDING)
147 return STUN_USAGE_ICE_RETURN_INVALID;
149 switch (stun_message_get_class (msg))
152 case STUN_INDICATION:
153 return STUN_USAGE_ICE_RETURN_INVALID;
160 if (stun_message_find_error (msg, &code) != STUN_MESSAGE_RETURN_SUCCESS) {
161 /* missing ERROR-CODE: ignore message */
162 return STUN_USAGE_ICE_RETURN_INVALID;
165 if (code == STUN_ERROR_ROLE_CONFLICT)
166 return STUN_USAGE_ICE_RETURN_ROLE_CONFLICT;
168 /* NOTE: currently we ignore unauthenticated messages if the context
169 * is authenticated, for security reasons. */
170 stun_debug (" STUN error message received (code: %d)", code);
172 return STUN_USAGE_ICE_RETURN_ERROR;
175 stun_debug ("Received %u-bytes STUN message", stun_message_length (msg));
177 if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSN) {
179 StunTransactionId u8;
180 uint32_t u32[STUN_MESSAGE_TRANS_ID_LEN / 4];
182 uint32_t magic_cookie;
183 stun_message_id (msg, transid.u8);
184 magic_cookie = *(transid.u32);
186 val = stun_message_find_xor_addr_full (msg,
187 STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, addr, addrlen, htonl (magic_cookie));
189 val = stun_message_find_xor_addr (msg,
190 STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, addr, addrlen);
192 if (val != STUN_MESSAGE_RETURN_SUCCESS)
194 stun_debug (" No XOR-MAPPED-ADDRESS: %d", val);
195 val = stun_message_find_addr (msg,
196 STUN_ATTRIBUTE_MAPPED_ADDRESS, addr, addrlen);
197 if (val != STUN_MESSAGE_RETURN_SUCCESS)
199 stun_debug (" No MAPPED-ADDRESS: %d", val);
200 return STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS;
204 stun_debug ("Mapped address found!");
205 return STUN_USAGE_ICE_RETURN_SUCCESS;
209 stun_bind_error (StunAgent *agent, StunMessage *msg,
210 uint8_t *buf, size_t *plen, const StunMessage *req,
217 stun_debug ("STUN Error Reply (buffer size: %u)...", (unsigned)len);
219 val = stun_agent_init_error (agent, msg, buf, len, req, code);
223 len = stun_agent_finish_message (agent, msg, NULL, 0);
228 stun_debug (" Error response (%u) of %u bytes", (unsigned)code,
234 stun_usage_ice_conncheck_create_reply (StunAgent *agent, StunMessage *req,
235 StunMessage *msg, uint8_t *buf, size_t *plen,
236 const struct sockaddr_storage *src, socklen_t srclen,
237 bool *control, uint64_t tie,
238 StunUsageIceCompatibility compatibility)
240 const char *username = NULL;
241 uint16_t username_len;
244 StunMessageReturn val = STUN_MESSAGE_RETURN_SUCCESS;
245 StunUsageIceReturn ret = STUN_USAGE_ICE_RETURN_SUCCESS;
248 #define err( code ) \
249 stun_bind_error (agent, msg, buf, &len, req, code); \
253 stun_debug ("STUN Reply (buffer size = %u)...", (unsigned)len);
255 if (stun_message_get_class (req) != STUN_REQUEST)
257 stun_debug (" Unhandled non-request (class %u) message.",
258 stun_message_get_class (req));
259 return STUN_USAGE_ICE_RETURN_INVALID_REQUEST;
262 if (stun_message_get_method (req) != STUN_BINDING)
264 stun_debug (" Bad request (method %u) message.",
265 stun_message_get_method (req));
266 err (STUN_ERROR_BAD_REQUEST);
267 return STUN_USAGE_ICE_RETURN_INVALID_METHOD;
270 /* Role conflict handling */
271 assert (control != NULL);
272 if (stun_message_find64 (req, *control ? STUN_ATTRIBUTE_ICE_CONTROLLING
273 : STUN_ATTRIBUTE_ICE_CONTROLLED, &q) == STUN_MESSAGE_RETURN_SUCCESS)
275 /* we have the ice-controlling/controlled attribute,
276 * and there's a role conflict
278 stun_debug ("STUN Role Conflict detected:");
280 /* According to ICE RFC 5245, section 7.2.1.1, we consider the four
281 * possible cases when a role conflict is detected: two cases are
282 * resolved by switching role locally, and the two other cases are
283 * handled by responding with a STUN error.
285 if ((tie < q && *control) || (tie >= q && !*control))
287 stun_debug (" switching role from \"controll%s\" to \"controll%s\"",
288 *control ? "ing" : "ed", *control ? "ed" : "ing");
289 *control = !*control;
290 ret = STUN_USAGE_ICE_RETURN_ROLE_CONFLICT;
294 stun_debug (" staying \"controll%s\" (sending error)",
295 *control ? "ing" : "ed");
296 err (STUN_ERROR_ROLE_CONFLICT);
297 return STUN_USAGE_ICE_RETURN_ROLE_CONFLICT;
300 if (stun_message_find64 (req, *control ? STUN_ATTRIBUTE_ICE_CONTROLLED
301 : STUN_ATTRIBUTE_ICE_CONTROLLING, &q) != STUN_MESSAGE_RETURN_SUCCESS)
303 /* we don't have the expected ice-controlling/controlled
306 if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_RFC5245 ||
307 compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2)
309 stun_debug ("STUN Role not specified by peer!");
314 if (stun_agent_init_response (agent, msg, buf, len, req) == FALSE) {
315 stun_debug ("Unable to create response");
318 if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSN) {
320 StunTransactionId transid;
321 uint32_t magic_cookie;
324 stun_message_id (msg, conv.transid);
326 val = stun_message_append_xor_addr_full (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS,
327 src, srclen, htonl (conv.magic_cookie));
328 } else if (stun_message_has_cookie (msg) &&
329 compatibility != STUN_USAGE_ICE_COMPATIBILITY_GOOGLE) {
330 val = stun_message_append_xor_addr (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS,
333 val = stun_message_append_addr (msg, STUN_ATTRIBUTE_MAPPED_ADDRESS,
334 (struct sockaddr *) src, srclen);
337 if (val != STUN_MESSAGE_RETURN_SUCCESS) {
338 stun_debug (" Mapped address problem: %d", val);
342 username = (const char *)stun_message_find (req,
343 STUN_ATTRIBUTE_USERNAME, &username_len);
345 val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME,
346 username, username_len);
349 if (val != STUN_MESSAGE_RETURN_SUCCESS) {
350 stun_debug ("Error appending username: %d", val);
354 if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2) {
355 val = stun_message_append32 (msg,
356 STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION, 2);
358 if (val != STUN_MESSAGE_RETURN_SUCCESS) {
359 stun_debug ("Error appending implementation version: %d", val);
364 /* the stun agent will automatically use the password of the request */
365 len = stun_agent_finish_message (agent, msg, NULL, 0);
370 stun_debug (" All done (response size: %u)", (unsigned)len);
375 stun_debug (" Fatal error formatting Response: %d", val);
379 case STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE:
380 return STUN_USAGE_ICE_RETURN_MEMORY_ERROR;
381 case STUN_MESSAGE_RETURN_INVALID:
382 case STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS:
383 return STUN_USAGE_ICE_RETURN_INVALID_ADDRESS;
384 case STUN_MESSAGE_RETURN_SUCCESS:
385 assert (0); /* shouldn’t be reached */
386 case STUN_MESSAGE_RETURN_NOT_FOUND:
388 return STUN_USAGE_ICE_RETURN_ERROR;
394 uint32_t stun_usage_ice_conncheck_priority (const StunMessage *msg)
398 if (stun_message_find32 (msg, STUN_ATTRIBUTE_PRIORITY, &value)
399 != STUN_MESSAGE_RETURN_SUCCESS)
405 bool stun_usage_ice_conncheck_use_candidate (const StunMessage *msg)
407 return (stun_message_find_flag (msg,
408 STUN_ATTRIBUTE_USE_CANDIDATE) == STUN_MESSAGE_RETURN_SUCCESS);