size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg, uint8_t *buffer, size_t buffer_len, StunMessage *previous_response, int32_t lifetime, uint8_t *username, size_t username_len, uint8_t *password, size_t password_len, StunUsageTurnCompatibility compatibility) { if (compatibility != STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 && compatibility != STUN_USAGE_TURN_COMPATIBILITY_RFC5766) { return stun_usage_turn_create (agent, msg, buffer, buffer_len, previous_response, STUN_USAGE_TURN_REQUEST_PORT_NORMAL, 0, lifetime, username, username_len, password, password_len, compatibility); } stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_REFRESH); if (lifetime >= 0) { if (stun_message_append32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (previous_response) { uint8_t *realm; uint8_t *nonce; uint16_t len; realm = (uint8_t *) stun_message_find (previous_response, STUN_ATTRIBUTE_REALM, &len); if (realm != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM, realm, len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } nonce = (uint8_t *) stun_message_find (previous_response, STUN_ATTRIBUTE_NONCE, &len); if (nonce != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE, nonce, len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } } if (username != NULL && username_len > 0) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, username, username_len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } return stun_agent_finish_message (agent, msg, password, password_len); }
size_t stun_agent_build_unknown_attributes_error (StunAgent *agent, StunMessage *msg, uint8_t *buffer, size_t buffer_len, const StunMessage *request) { unsigned counter; uint16_t ids[STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES]; counter = stun_agent_find_unknowns (agent, request, ids, STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES); if (stun_agent_init_error (agent, msg, buffer, buffer_len, request, STUN_ERROR_UNKNOWN_ATTRIBUTE) == FALSE) { return 0; } /* NOTE: Old RFC3489 compatibility: * When counter is odd, duplicate one value for 32-bits padding. */ if (!stun_message_has_cookie (request) && (counter & 1)) ids[counter++] = ids[0]; if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES, ids, counter * 2) == STUN_MESSAGE_RETURN_SUCCESS) { return stun_agent_finish_message (agent, msg, request->key, request->key_len); } return 0; }
size_t stun_usage_turn_create_permission (StunAgent *agent, StunMessage *msg, uint8_t *buffer, size_t buffer_len, uint8_t *username, size_t username_len, uint8_t *password, size_t password_len, uint8_t *realm, size_t realm_len, uint8_t *nonce, size_t nonce_len, struct sockaddr *peer, StunUsageTurnCompatibility compatibility) { if (!peer) return 0; stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_CREATEPERMISSION); /* PEER address */ if (stun_message_append_xor_addr (msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, peer, sizeof(*peer)) != STUN_MESSAGE_RETURN_SUCCESS) { return 0; } /* nonce */ if (nonce != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE, nonce, nonce_len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } /* realm */ if (realm != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM, realm, realm_len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } /* username */ if (username != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, username, username_len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } return stun_agent_finish_message (agent, msg, password, password_len); }
size_t stun_usage_ice_conncheck_create (StunAgent *agent, StunMessage *msg, uint8_t *buffer, size_t buffer_len, const uint8_t *username, const size_t username_len, const uint8_t *password, const size_t password_len, bool cand_use, bool controlling, uint32_t priority, uint64_t tie, StunUsageIceCompatibility compatibility) { StunMessageReturn val; stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_BINDING); if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_RFC5245) { if (cand_use) { val = stun_message_append_flag (msg, STUN_ATTRIBUTE_USE_CANDIDATE); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } val = stun_message_append32 (msg, STUN_ATTRIBUTE_PRIORITY, priority); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; if (controlling) val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLING, tie); else val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLED, tie); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (username && username_len > 0) { val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, username, username_len); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } return stun_agent_finish_message (agent, msg, password, password_len); }
size_t stun_usage_turn_create (StunAgent *agent, StunMessage *msg, uint8_t *buffer, size_t buffer_len, StunMessage *previous_response, StunUsageTurnRequestPorts request_props, int32_t bandwidth, int32_t lifetime, uint8_t *username, size_t username_len, uint8_t *password, size_t password_len, StunUsageTurnCompatibility compatibility) { stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_ALLOCATE); if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9) { if (stun_message_append32 (msg, STUN_ATTRIBUTE_REQUESTED_TRANSPORT, TURN_REQUESTED_TRANSPORT_UDP) != STUN_MESSAGE_RETURN_SUCCESS) return 0; if (bandwidth >= 0) { if (stun_message_append32 (msg, STUN_ATTRIBUTE_BANDWIDTH, bandwidth) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } } else { if (stun_message_append32 (msg, STUN_ATTRIBUTE_MAGIC_COOKIE, TURN_MAGIC_COOKIE) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (lifetime >= 0) { if (stun_message_append32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 && request_props != STUN_USAGE_TURN_REQUEST_PORT_NORMAL) { uint32_t req = 0; if (request_props & STUN_USAGE_TURN_REQUEST_PORT_EVEN_AND_RESERVE) { req |= REQUESTED_PROPS_R; req |= REQUESTED_PROPS_E; } else if (request_props & STUN_USAGE_TURN_REQUEST_PORT_EVEN) { req |= REQUESTED_PROPS_E; } if (stun_message_append32 (msg, STUN_ATTRIBUTE_REQUESTED_PORT_PROPS, req) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (previous_response) { uint8_t *realm; uint8_t *nonce; uint64_t reservation; uint16_t len; realm = (uint8_t *) stun_message_find (previous_response, STUN_ATTRIBUTE_REALM, &len); if (realm != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM, realm, len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } nonce = (uint8_t *) stun_message_find (previous_response, STUN_ATTRIBUTE_NONCE, &len); if (nonce != NULL) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE, nonce, len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (stun_message_find64 (previous_response, STUN_ATTRIBUTE_RESERVATION_TOKEN, &reservation) == STUN_MESSAGE_RETURN_SUCCESS) { if (stun_message_append64 (msg, STUN_ATTRIBUTE_RESERVATION_TOKEN, reservation) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } } if (username != NULL && username_len > 0) { if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, username, username_len) != STUN_MESSAGE_RETURN_SUCCESS) return 0; } return stun_agent_finish_message (agent, msg, password, password_len); }
StunUsageIceReturn stun_usage_ice_conncheck_create_reply (StunAgent *agent, StunMessage *req, StunMessage *msg, uint8_t *buf, size_t *plen, const struct sockaddr *src, socklen_t srclen, bool *control, uint64_t tie, StunUsageIceCompatibility compatibility) { const char *username = NULL; uint16_t username_len; size_t len = *plen; uint64_t q; StunMessageReturn val = STUN_MESSAGE_RETURN_SUCCESS; StunUsageIceReturn ret = STUN_USAGE_ICE_RETURN_SUCCESS; #define err( code ) \ stun_bind_error (agent, msg, buf, &len, req, code); \ *plen = len *plen = 0; stun_debug ("STUN Reply (buffer size = %u)...\n", (unsigned)len); if (stun_message_get_class (req) != STUN_REQUEST) { stun_debug (" Unhandled non-request (class %u) message.\n", stun_message_get_class (req)); return STUN_USAGE_ICE_RETURN_INVALID_REQUEST; } if (stun_message_get_method (req) != STUN_BINDING) { stun_debug (" Bad request (method %u) message.\n", stun_message_get_method (req)); err (STUN_ERROR_BAD_REQUEST); return STUN_USAGE_ICE_RETURN_INVALID_METHOD; } /* Role conflict handling */ assert (control != NULL); if (stun_message_find64 (req, *control ? STUN_ATTRIBUTE_ICE_CONTROLLING : STUN_ATTRIBUTE_ICE_CONTROLLED, &q) == STUN_MESSAGE_RETURN_SUCCESS) { stun_debug ("STUN Role Conflict detected:\n"); if (tie < q) { stun_debug (" switching role from \"controll%s\" to \"controll%s\"\n", *control ? "ing" : "ed", *control ? "ed" : "ing"); *control = !*control; ret = STUN_USAGE_ICE_RETURN_ROLE_CONFLICT; } else { stun_debug (" staying \"controll%s\" (sending error)\n", *control ? "ing" : "ed"); err (STUN_ERROR_ROLE_CONFLICT); return STUN_USAGE_ICE_RETURN_SUCCESS; } } else { stun_debug ("STUN Role not specified by peer!\n"); } if (stun_agent_init_response (agent, msg, buf, len, req) == FALSE) { stun_debug ("Unable to create response\n"); goto failure; } if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSN) { StunTransactionId transid; uint32_t magic_cookie; stun_message_id (msg, transid); magic_cookie = *((uint32_t *) transid); val = stun_message_append_xor_addr_full (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, src, srclen, htonl (magic_cookie)); } else if (stun_message_has_cookie (msg)) { val = stun_message_append_xor_addr (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, src, srclen); } else { val = stun_message_append_addr (msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, src, srclen); } if (val != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug (" Mapped address problem: %d\n", val); goto failure; } username = (const char *)stun_message_find (req, STUN_ATTRIBUTE_USERNAME, &username_len); if (username) { val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, username, username_len); } if (val != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug ("Error appending username: %d\n", val); goto failure; } /* the stun agent will automatically use the password of the request */ len = stun_agent_finish_message (agent, msg, NULL, 0); if (len == 0) goto failure; *plen = len; stun_debug (" All done (response size: %u)\n", (unsigned)len); return ret; failure: assert (*plen == 0); stun_debug (" Fatal error formatting Response: %d\n", val); switch (val) { case STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE: return STUN_USAGE_ICE_RETURN_MEMORY_ERROR; case STUN_MESSAGE_RETURN_INVALID: case STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS: return STUN_USAGE_ICE_RETURN_INVALID_ADDRESS; default: return STUN_USAGE_ICE_RETURN_ERROR; } }
size_t stun_usage_ice_conncheck_create (StunAgent *agent, StunMessage *msg, uint8_t *buffer, size_t buffer_len, const uint8_t *username, const size_t username_len, const uint8_t *password, const size_t password_len, bool cand_use, bool controlling, uint32_t priority, uint64_t tie, const char *candidate_identifier, StunUsageIceCompatibility compatibility) { StunMessageReturn val; stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_BINDING); if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_RFC5245 || compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2) { if (cand_use) { val = stun_message_append_flag (msg, STUN_ATTRIBUTE_USE_CANDIDATE); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } val = stun_message_append32 (msg, STUN_ATTRIBUTE_PRIORITY, priority); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; if (controlling) val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLING, tie); else val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLED, tie); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (username && username_len > 0) { val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, username, username_len); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2 && candidate_identifier) { size_t identifier_len = strlen(candidate_identifier); size_t attribute_len = identifier_len; int modulo4 = identifier_len % 4; uint8_t* buf; if (modulo4) attribute_len += 4 - modulo4; // Avoid a coverify false positive assert (attribute_len >= identifier_len); buf = malloc(attribute_len); memset(buf, 0, attribute_len); memcpy(buf, candidate_identifier, identifier_len); val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_CANDIDATE_IDENTIFIER, buf, attribute_len); free(buf); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; val = stun_message_append32 (msg, STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION, 2); if (val != STUN_MESSAGE_RETURN_SUCCESS) return 0; } return stun_agent_finish_message (agent, msg, password, password_len); }
StunUsageIceReturn stun_usage_ice_conncheck_create_reply (StunAgent *agent, StunMessage *req, StunMessage *msg, uint8_t *buf, size_t *plen, const struct sockaddr_storage *src, socklen_t srclen, bool *control, uint64_t tie, StunUsageIceCompatibility compatibility) { const char *username = NULL; uint16_t username_len; size_t len = *plen; uint64_t q; StunMessageReturn val = STUN_MESSAGE_RETURN_SUCCESS; StunUsageIceReturn ret = STUN_USAGE_ICE_RETURN_SUCCESS; #define err( code ) \ stun_bind_error (agent, msg, buf, &len, req, code); \ *plen = len *plen = 0; stun_debug ("STUN Reply (buffer size = %u)...", (unsigned)len); if (stun_message_get_class (req) != STUN_REQUEST) { stun_debug (" Unhandled non-request (class %u) message.", stun_message_get_class (req)); return STUN_USAGE_ICE_RETURN_INVALID_REQUEST; } if (stun_message_get_method (req) != STUN_BINDING) { stun_debug (" Bad request (method %u) message.", stun_message_get_method (req)); err (STUN_ERROR_BAD_REQUEST); return STUN_USAGE_ICE_RETURN_INVALID_METHOD; } /* Role conflict handling */ assert (control != NULL); if (stun_message_find64 (req, *control ? STUN_ATTRIBUTE_ICE_CONTROLLING : STUN_ATTRIBUTE_ICE_CONTROLLED, &q) == STUN_MESSAGE_RETURN_SUCCESS) { /* we have the ice-controlling/controlled attribute, * and there's a role conflict */ stun_debug ("STUN Role Conflict detected:"); /* According to ICE RFC 5245, section 7.2.1.1, we consider the four * possible cases when a role conflict is detected: two cases are * resolved by switching role locally, and the two other cases are * handled by responding with a STUN error. */ if ((tie < q && *control) || (tie >= q && !*control)) { stun_debug (" switching role from \"controll%s\" to \"controll%s\"", *control ? "ing" : "ed", *control ? "ed" : "ing"); *control = !*control; ret = STUN_USAGE_ICE_RETURN_ROLE_CONFLICT; } else { stun_debug (" staying \"controll%s\" (sending error)", *control ? "ing" : "ed"); err (STUN_ERROR_ROLE_CONFLICT); return STUN_USAGE_ICE_RETURN_ROLE_CONFLICT; } } else { if (stun_message_find64 (req, *control ? STUN_ATTRIBUTE_ICE_CONTROLLED : STUN_ATTRIBUTE_ICE_CONTROLLING, &q) != STUN_MESSAGE_RETURN_SUCCESS) { /* we don't have the expected ice-controlling/controlled * attribute */ if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_RFC5245 || compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2) { stun_debug ("STUN Role not specified by peer!"); } } } if (stun_agent_init_response (agent, msg, buf, len, req) == FALSE) { stun_debug ("Unable to create response"); goto failure; } if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSN) { union { StunTransactionId transid; uint32_t magic_cookie; } conv; stun_message_id (msg, conv.transid); val = stun_message_append_xor_addr_full (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, src, srclen, htonl (conv.magic_cookie)); } else if (stun_message_has_cookie (msg) && compatibility != STUN_USAGE_ICE_COMPATIBILITY_GOOGLE) { val = stun_message_append_xor_addr (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, src, srclen); } else { val = stun_message_append_addr (msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, (struct sockaddr *) src, srclen); } if (val != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug (" Mapped address problem: %d", val); goto failure; } username = (const char *)stun_message_find (req, STUN_ATTRIBUTE_USERNAME, &username_len); if (username) { val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, username, username_len); } if (val != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug ("Error appending username: %d", val); goto failure; } if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2) { val = stun_message_append32 (msg, STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION, 2); if (val != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug ("Error appending implementation version: %d", val); goto failure; } } /* the stun agent will automatically use the password of the request */ len = stun_agent_finish_message (agent, msg, NULL, 0); if (len == 0) goto failure; *plen = len; stun_debug (" All done (response size: %u)", (unsigned)len); return ret; failure: assert (*plen == 0); stun_debug (" Fatal error formatting Response: %d", val); switch (val) { case STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE: return STUN_USAGE_ICE_RETURN_MEMORY_ERROR; case STUN_MESSAGE_RETURN_INVALID: case STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS: return STUN_USAGE_ICE_RETURN_INVALID_ADDRESS; case STUN_MESSAGE_RETURN_SUCCESS: assert (0); /* shouldn’t be reached */ case STUN_MESSAGE_RETURN_NOT_FOUND: default: return STUN_USAGE_ICE_RETURN_ERROR; } }
int handle_stun(udp_conn* c, uint8_t *packet, size_t len) { StunAgent agent; StunValidationStatus status; StunAgentUsageFlags flags; StunMessage request; StunMessage response; int ret; size_t output_size; uint8_t output[1024]; flags = STUN_AGENT_USAGE_IGNORE_CREDENTIALS; // | STUN_AGENT_USAGE_USE_FINGERPRINT; static const uint16_t attr[] = { STUN_ATTRIBUTE_MAPPED_ADDRESS, STUN_ATTRIBUTE_RESPONSE_ADDRESS, STUN_ATTRIBUTE_CHANGE_REQUEST, STUN_ATTRIBUTE_SOURCE_ADDRESS, STUN_ATTRIBUTE_CHANGED_ADDRESS, STUN_ATTRIBUTE_USERNAME, STUN_ATTRIBUTE_PASSWORD, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, STUN_ATTRIBUTE_ERROR_CODE, STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES, STUN_ATTRIBUTE_REFLECTED_FROM, STUN_ATTRIBUTE_CHANNEL_NUMBER, STUN_ATTRIBUTE_LIFETIME, STUN_ATTRIBUTE_MS_ALTERNATE_SERVER, STUN_ATTRIBUTE_MAGIC_COOKIE, STUN_ATTRIBUTE_BANDWIDTH, STUN_ATTRIBUTE_DESTINATION_ADDRESS, STUN_ATTRIBUTE_REMOTE_ADDRESS, STUN_ATTRIBUTE_PEER_ADDRESS, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, STUN_ATTRIBUTE_DATA, STUN_ATTRIBUTE_REALM, STUN_ATTRIBUTE_NONCE, STUN_ATTRIBUTE_RELAY_ADDRESS, STUN_ATTRIBUTE_RELAYED_ADDRESS, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, STUN_ATTRIBUTE_REQUESTED_ADDRESS_TYPE, STUN_ATTRIBUTE_REQUESTED_PORT_PROPS, STUN_ATTRIBUTE_REQUESTED_PROPS, STUN_ATTRIBUTE_EVEN_PORT, STUN_ATTRIBUTE_REQUESTED_TRANSPORT, STUN_ATTRIBUTE_DONT_FRAGMENT, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, STUN_ATTRIBUTE_TIMER_VAL, STUN_ATTRIBUTE_REQUESTED_IP, STUN_ATTRIBUTE_RESERVATION_TOKEN, STUN_ATTRIBUTE_CONNECT_STAT, STUN_ATTRIBUTE_PRIORITY, STUN_ATTRIBUTE_USE_CANDIDATE, STUN_ATTRIBUTE_OPTIONS, STUN_ATTRIBUTE_MS_VERSION, STUN_ATTRIBUTE_SOFTWARE, STUN_ATTRIBUTE_ALTERNATE_SERVER, STUN_ATTRIBUTE_FINGERPRINT, STUN_ATTRIBUTE_ICE_CONTROLLED, STUN_ATTRIBUTE_ICE_CONTROLLING, STUN_ATTRIBUTE_MS_SEQUENCE_NUMBER, STUN_ATTRIBUTE_CANDIDATE_IDENTIFIER }; /* initialize our agent to be compatible with RFC5389 (= with TLS support) */ output_size = 0; memset(output, 0, sizeof(output)); stun_agent_init(&agent, attr, STUN_COMPATIBILITY_RFC5389, flags); /* validate the request */ status = stun_agent_validate(&agent, &request, packet, len, NULL, NULL); print_stun_validation_status(status); /* check the class */ StunClass request_class = stun_message_get_class(&request); print_stun_class(request_class); if(request_class == STUN_ERROR) { printf("Error: request stun class failed.\n"); exit(0); } /* what stun method? */ StunMethod request_method = stun_message_get_method(&request); print_stun_method(request_method); /* initialize the response */ ret = stun_agent_init_response(&agent, &response, output, 1024, &request); printf("Stun agent_init_response ret: %d\n", ret); /* add xor-mapped-address */ uint32_t magic_cookie = 0; uint8_t* cookie_ptr = NULL; StunTransactionId transid; socklen_t sock_len = 0; char client_ip[16] = { 0 } ; StunMessageReturn stun_ret = STUN_MESSAGE_RETURN_INVALID; stun_message_id(&response, transid); magic_cookie = *((uint32_t*)transid); sock_len = sizeof(c->client); cookie_ptr = (uint8_t*) &magic_cookie; inet_ntop(AF_INET, &c->client.sin_addr.s_addr, client_ip, sizeof(client_ip)); stun_ret = stun_message_append_xor_addr(&response, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, (const struct sockaddr*)&c->client, sock_len); print_stun_message_return(stun_ret); printf("Received data from: %s\n", client_ip); printf("Magic cookie: %02X %02X %02X %02X\n", cookie_ptr[0], cookie_ptr[1], cookie_ptr[2], cookie_ptr[3]); // username // -------- const char* username = NULL; uint16_t username_len = 0; username = (const char*)stun_message_find(&request, STUN_ATTRIBUTE_USERNAME, &username_len); printf("Username: %s, len: %d\n", username, (int)username_len); #if 0 if(username) { StunMessageReturn username_res = stun_message_append_bytes(&response, STUN_ATTRIBUTE_USERNAME, username, username_len); print_stun_message_return(username_res); } uint32_t fingerprint = 0; if(stun_message_find32(&request, STUN_ATTRIBUTE_FINGERPRINT, &fingerprint) == STUN_MESSAGE_RETURN_SUCCESS) { printf("Got fingerprint: %d\n", fingerprint); if(stun_message_append32(&response, STUN_ATTRIBUTE_FINGERPRINT, fingerprint) != STUN_MESSAGE_RETURN_SUCCESS) { printf("Error while adding the fingerprint.\n"); } } #endif // password const char* password = ucon_ptr->stun_pw; // "94ccca06d14fb48c135bdaff30560c4d"; uint16_t password_len = strlen(password) + 1; output_size = stun_agent_finish_message(&agent, &response, (const uint8_t*) password, password_len); // answer to the connection krx_udp_send(c, output, output_size); print_buffer(output, output_size); return 0; }