/* Decode and authenticate message with unknown non-mandatory attribute */ static int handle_unknown_non_mandatory(void) { pj_pool_t *pool = pj_pool_create(mem, NULL, 1000, 1000, NULL); pj_stun_msg *msg0, *msg1, *msg2; pj_uint8_t data[] = { 1, 2, 3, 4, 5, 6}; pj_uint8_t packet[500]; pj_stun_auth_cred cred; pj_size_t len; pj_status_t rc; PJ_LOG(3,(THIS_FILE, " handling unknown non-mandatory attr")); PJ_LOG(3,(THIS_FILE, " encoding")); rc = pj_stun_msg_create(pool, PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC, NULL, &msg0); rc += pj_stun_msg_add_string_attr(pool, msg0, PJ_STUN_ATTR_USERNAME, &USERNAME); rc += pj_stun_msg_add_binary_attr(pool, msg0, 0x80ff, data, sizeof(data)); rc += pj_stun_msg_add_msgint_attr(pool, msg0); rc += pj_stun_msg_encode(msg0, packet, sizeof(packet), 0, &PASSWORD, &len); #if 0 if (1) { unsigned i; puts(""); printf("{ "); for (i=0; i<len; ++i) printf("0x%02x, ", packet[i]); puts(" }"); } #endif PJ_LOG(3,(THIS_FILE, " decoding")); rc += pj_stun_msg_decode(pool, packet, len, PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, &msg1, NULL, NULL); rc += cmp_msg(msg0, msg1); pj_bzero(&cred, sizeof(cred)); cred.type = PJ_STUN_AUTH_CRED_STATIC; cred.data.static_cred.username = USERNAME; cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN; cred.data.static_cred.data = PASSWORD; PJ_LOG(3,(THIS_FILE, " authenticating")); rc += pj_stun_authenticate_request(packet, (unsigned)len, msg1, &cred, pool, NULL, NULL); PJ_LOG(3,(THIS_FILE, " clone")); msg2 = pj_stun_msg_clone(pool, msg1); rc += cmp_msg(msg0, msg2); pj_pool_release(pool); return rc==0 ? 0 : -4410; }
static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v) { pj_stun_msg *msg; pj_sockaddr mapped_addr; pj_str_t s1; pj_status_t status; status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC, (pj_uint8_t*)v->tsx_id, &msg); if (status != PJ_SUCCESS) goto on_error; status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE, pj_cstr(&s1, "test vector")); if (status != PJ_SUCCESS) goto on_error; status = pj_sockaddr_init(pj_AF_INET6(), &mapped_addr, pj_cstr(&s1, "2001:db8:1234:5678:11:2233:4455:6677"), 32853); if (status != PJ_SUCCESS) goto on_error; status = pj_stun_msg_add_sockaddr_attr(pool, msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR, PJ_TRUE, &mapped_addr, sizeof(pj_sockaddr)); if (status != PJ_SUCCESS) goto on_error; status = pj_stun_msg_add_msgint_attr(pool, msg); if (status != PJ_SUCCESS) goto on_error; status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0); if (status != PJ_SUCCESS) goto on_error; return msg; on_error: app_perror(" error: create_msgint3()", status); return NULL; }
static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v) { pj_stun_msg *msg; pj_timestamp u64; pj_str_t s1; pj_status_t status; status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC, (pj_uint8_t*)v->tsx_id, &msg); if (status != PJ_SUCCESS) goto on_error; status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_PRIORITY, 0x6e0001ff); if (status != PJ_SUCCESS) goto on_error; u64.u32.hi = 0x932ff9b1; u64.u32.lo = 0x51263b36; status = pj_stun_msg_add_uint64_attr(pool, msg, PJ_STUN_ATTR_ICE_CONTROLLED, &u64); if (status != PJ_SUCCESS) goto on_error; status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_USERNAME, pj_cstr(&s1, v->username)); if (status != PJ_SUCCESS) goto on_error; status = pj_stun_msg_add_msgint_attr(pool, msg); if (status != PJ_SUCCESS) goto on_error; status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0); if (status != PJ_SUCCESS) goto on_error; return msg; on_error: app_perror(" error: create_msgint1()", status); return NULL; }
static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v) { pj_stun_msg *msg; pj_sockaddr_in mapped_addr; pj_str_t s1; pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC, (pj_uint8_t*)v->tsx_id, &msg); pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE, pj_cstr(&s1, "test vector")); pj_sockaddr_in_init(&mapped_addr, pj_cstr(&s1, "127.0.0.1"), 32853); pj_stun_msg_add_sockaddr_attr(pool, msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR, PJ_TRUE, &mapped_addr, sizeof(pj_sockaddr_in)); pj_stun_msg_add_msgint_attr(pool, msg); pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0); return msg; }
static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v) { pj_stun_msg *msg; pj_timestamp u64; pj_str_t s1; pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC, (pj_uint8_t*)v->tsx_id, &msg); pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_PRIORITY, 0x6e0001ff); u64.u32.hi = 0x932ff9b1; u64.u32.lo = 0x51263b36; pj_stun_msg_add_uint64_attr(pool, msg, PJ_STUN_ATTR_ICE_CONTROLLED, &u64); pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_USERNAME, pj_cstr(&s1, v->username)); pj_stun_msg_add_msgint_attr(pool, msg); pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0); return msg; }
static pj_bool_t turn_on_data_recvfrom(pj_activesock_t *asock, void *data, pj_size_t size, const pj_sockaddr_t *src_addr, int addr_len, pj_status_t status) { test_server *test_srv; pj_pool_t *pool; turn_allocation *alloc; pj_stun_msg *req, *resp = NULL; pj_str_t auth_key = { NULL, 0 }; char client_info[PJ_INET6_ADDRSTRLEN+10]; unsigned i; pj_ssize_t len; if (status != PJ_SUCCESS) return PJ_TRUE; pj_sockaddr_print(src_addr, client_info, sizeof(client_info), 3); test_srv = (test_server*) pj_activesock_get_user_data(asock); pool = pj_pool_create(test_srv->stun_cfg->pf, NULL, 512, 512, NULL); /* Find the client */ for (i=0; i<test_srv->turn_alloc_cnt; i++) { if (pj_sockaddr_cmp(&test_srv->turn_alloc[i].client_addr, src_addr)==0) break; } if (pj_stun_msg_check((pj_uint8_t*)data, size, PJ_STUN_NO_FINGERPRINT_CHECK)!=PJ_SUCCESS) { /* Not STUN message, this probably is a ChannelData */ pj_turn_channel_data cd; const pj_turn_channel_data *pcd = (const pj_turn_channel_data*)data; pj_ssize_t sent; if (i==test_srv->turn_alloc_cnt) { /* Invalid data */ PJ_LOG(1,(THIS_FILE, "TURN Server received strayed data")); goto on_return; } alloc = &test_srv->turn_alloc[i]; cd.ch_number = pj_ntohs(pcd->ch_number); cd.length = pj_ntohs(pcd->length); /* For UDP check the packet length */ if (size < cd.length+sizeof(cd)) { PJ_LOG(1,(THIS_FILE, "TURN Server: ChannelData discarded: UDP size error")); goto on_return; } /* Lookup peer */ for (i=0; i<alloc->perm_cnt; ++i) { if (alloc->chnum[i] == cd.ch_number) break; } if (i==alloc->perm_cnt) { PJ_LOG(1,(THIS_FILE, "TURN Server: ChannelData discarded: invalid channel number")); goto on_return; } /* Relay the data to peer */ sent = cd.length; pj_activesock_sendto(alloc->sock, &alloc->send_key, pcd+1, &sent, 0, &alloc->perm[i], pj_sockaddr_get_len(&alloc->perm[i])); /* Done */ goto on_return; } status = pj_stun_msg_decode(pool, (pj_uint8_t*)data, size, PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK, &req, NULL, NULL); if (status != PJ_SUCCESS) { char errmsg[PJ_ERR_MSG_SIZE]; pj_strerror(status, errmsg, sizeof(errmsg)); PJ_LOG(1,("", "STUN message decode error from client %s: %s", client_info, errmsg)); goto on_return; } if (i==test_srv->turn_alloc_cnt) { /* New client */ //pj_str_t ip_addr; pj_stun_username_attr *uname; pj_activesock_cb alloc_sock_cb; turn_allocation *alloc; /* Must be Allocate request */ if (req->hdr.type != PJ_STUN_ALLOCATE_REQUEST) { PJ_LOG(1,(THIS_FILE, "Invalid %s %s from client %s", pj_stun_get_method_name(req->hdr.type), pj_stun_get_class_name(req->hdr.type), client_info)); if (PJ_STUN_IS_REQUEST(req->hdr.type)) pj_stun_msg_create_response(pool, req, PJ_STUN_SC_BAD_REQUEST, NULL, &resp); goto send_pkt; } test_srv->turn_stat.rx_allocate_cnt++; /* Skip if we're not responding to Allocate request */ if (!test_srv->turn_respond_allocate) return PJ_TRUE; /* Check if we have too many clients */ if (test_srv->turn_alloc_cnt == MAX_TURN_ALLOC) { pj_stun_msg_create_response(pool, req, PJ_STUN_SC_INSUFFICIENT_CAPACITY, NULL, &resp); goto send_pkt; } /* Get USERNAME attribute */ uname = (pj_stun_username_attr*) pj_stun_msg_find_attr(req, PJ_STUN_ATTR_USERNAME, 0); /* Reject if it doesn't have MESSAGE-INTEGRITY or USERNAME attributes or * the user is incorrect */ if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0) == NULL || uname==NULL || pj_stricmp2(&uname->value, TURN_USERNAME) != 0) { pj_str_t tmp; pj_stun_msg_create_response(pool, req, PJ_STUN_SC_UNAUTHORIZED, NULL, &resp); pj_stun_msg_add_string_attr(pool, resp, PJ_STUN_ATTR_REALM, &test_srv->domain); pj_stun_msg_add_string_attr(pool, resp, PJ_STUN_ATTR_NONCE, pj_cstr(&tmp, TURN_NONCE)); goto send_pkt; } pj_bzero(&alloc_sock_cb, sizeof(alloc_sock_cb)); alloc_sock_cb.on_data_recvfrom = &alloc_on_data_recvfrom; /* Create allocation */ alloc = &test_srv->turn_alloc[test_srv->turn_alloc_cnt]; alloc->perm_cnt = 0; alloc->test_srv = test_srv; pj_memcpy(&alloc->client_addr, src_addr, addr_len); pj_ioqueue_op_key_init(&alloc->send_key, sizeof(alloc->send_key)); alloc->pool = pj_pool_create(test_srv->stun_cfg->pf, "alloc", 512, 512, NULL); /* Create relay socket */ pj_sockaddr_in_init(&alloc->alloc_addr.ipv4, NULL, 0); pj_gethostip(pj_AF_INET(), &alloc->alloc_addr); status = pj_activesock_create_udp(alloc->pool, &alloc->alloc_addr, NULL, test_srv->stun_cfg->ioqueue, &alloc_sock_cb, alloc, &alloc->sock, &alloc->alloc_addr); if (status != PJ_SUCCESS) { pj_pool_release(alloc->pool); pj_stun_msg_create_response(pool, req, PJ_STUN_SC_SERVER_ERROR, NULL, &resp); goto send_pkt; } //pj_sockaddr_set_str_addr(pj_AF_INET(), &alloc->alloc_addr, &ip_addr); pj_activesock_set_user_data(alloc->sock, alloc); status = pj_activesock_start_recvfrom(alloc->sock, alloc->pool, 1500, 0); if (status != PJ_SUCCESS) { pj_activesock_close(alloc->sock); pj_pool_release(alloc->pool); pj_stun_msg_create_response(pool, req, PJ_STUN_SC_SERVER_ERROR, NULL, &resp); goto send_pkt; } /* Create Data indication */ status = pj_stun_msg_create(alloc->pool, PJ_STUN_DATA_INDICATION, PJ_STUN_MAGIC, NULL, &alloc->data_ind); if (status != PJ_SUCCESS) { pj_activesock_close(alloc->sock); pj_pool_release(alloc->pool); pj_stun_msg_create_response(pool, req, PJ_STUN_SC_SERVER_ERROR, NULL, &resp); goto send_pkt; } pj_stun_msg_add_sockaddr_attr(alloc->pool, alloc->data_ind, PJ_STUN_ATTR_XOR_PEER_ADDR, PJ_TRUE, &alloc->alloc_addr, pj_sockaddr_get_len(&alloc->alloc_addr)); pj_stun_msg_add_binary_attr(alloc->pool, alloc->data_ind, PJ_STUN_ATTR_DATA, (pj_uint8_t*)"", 1); /* Create response */ resp = create_success_response(test_srv, alloc, req, pool, 600, &auth_key); if (resp == NULL) { pj_activesock_close(alloc->sock); pj_pool_release(alloc->pool); pj_stun_msg_create_response(pool, req, PJ_STUN_SC_SERVER_ERROR, NULL, &resp); goto send_pkt; } ++test_srv->turn_alloc_cnt; } else { alloc = &test_srv->turn_alloc[i]; if (req->hdr.type == PJ_STUN_ALLOCATE_REQUEST) { test_srv->turn_stat.rx_allocate_cnt++; /* Skip if we're not responding to Allocate request */ if (!test_srv->turn_respond_allocate) return PJ_TRUE; resp = create_success_response(test_srv, alloc, req, pool, 0, &auth_key); } else if (req->hdr.type == PJ_STUN_REFRESH_REQUEST) { pj_stun_lifetime_attr *lf_attr; test_srv->turn_stat.rx_refresh_cnt++; /* Skip if we're not responding to Refresh request */ if (!test_srv->turn_respond_refresh) return PJ_TRUE; lf_attr = (pj_stun_lifetime_attr*) pj_stun_msg_find_attr(req, PJ_STUN_ATTR_LIFETIME, 0); if (lf_attr && lf_attr->value != 0) { resp = create_success_response(test_srv, alloc, req, pool, 600, &auth_key); pj_array_erase(test_srv->turn_alloc, sizeof(test_srv->turn_alloc[0]), test_srv->turn_alloc_cnt, i); --test_srv->turn_alloc_cnt; } else resp = create_success_response(test_srv, alloc, req, pool, 0, &auth_key); } else if (req->hdr.type == PJ_STUN_CREATE_PERM_REQUEST) { for (i=0; i<req->attr_count; ++i) { if (req->attr[i]->type == PJ_STUN_ATTR_XOR_PEER_ADDR) { pj_stun_xor_peer_addr_attr *pa = (pj_stun_xor_peer_addr_attr*)req->attr[i]; unsigned j; for (j=0; j<alloc->perm_cnt; ++j) { if (pj_sockaddr_cmp(&alloc->perm[j], &pa->sockaddr)==0) break; } if (j==alloc->perm_cnt && alloc->perm_cnt < MAX_TURN_PERM) { char peer_info[PJ_INET6_ADDRSTRLEN]; pj_sockaddr_print(&pa->sockaddr, peer_info, sizeof(peer_info), 3); pj_sockaddr_cp(&alloc->perm[alloc->perm_cnt], &pa->sockaddr); ++alloc->perm_cnt; PJ_LOG(5,("", "Permission %s added to client %s, perm_cnt=%d", peer_info, client_info, alloc->perm_cnt)); } } } resp = create_success_response(test_srv, alloc, req, pool, 0, &auth_key); } else if (req->hdr.type == PJ_STUN_SEND_INDICATION) { pj_stun_xor_peer_addr_attr *pa; pj_stun_data_attr *da; test_srv->turn_stat.rx_send_ind_cnt++; pa = (pj_stun_xor_peer_addr_attr*) pj_stun_msg_find_attr(req, PJ_STUN_ATTR_XOR_PEER_ADDR, 0); da = (pj_stun_data_attr*) pj_stun_msg_find_attr(req, PJ_STUN_ATTR_DATA, 0); if (pa && da) { unsigned j; char peer_info[PJ_INET6_ADDRSTRLEN]; pj_ssize_t sent; pj_sockaddr_print(&pa->sockaddr, peer_info, sizeof(peer_info), 3); for (j=0; j<alloc->perm_cnt; ++j) { if (pj_sockaddr_cmp(&alloc->perm[j], &pa->sockaddr)==0) break; } if (j==alloc->perm_cnt) { PJ_LOG(5,("", "SendIndication to %s is rejected (no permission)", peer_info, client_info, alloc->perm_cnt)); } else { PJ_LOG(5,(THIS_FILE, "Relaying %d bytes data from client %s to peer %s, " "perm_cnt=%d", da->length, client_info, peer_info, alloc->perm_cnt)); sent = da->length; pj_activesock_sendto(alloc->sock, &alloc->send_key, da->data, &sent, 0, &pa->sockaddr, pj_sockaddr_get_len(&pa->sockaddr)); } } else { PJ_LOG(1,(THIS_FILE, "Invalid Send Indication from %s", client_info)); } } else if (req->hdr.type == PJ_STUN_CHANNEL_BIND_REQUEST) { pj_stun_xor_peer_addr_attr *pa; pj_stun_channel_number_attr *cna; unsigned j, cn; pa = (pj_stun_xor_peer_addr_attr*) pj_stun_msg_find_attr(req, PJ_STUN_ATTR_XOR_PEER_ADDR, 0); cna = (pj_stun_channel_number_attr*) pj_stun_msg_find_attr(req, PJ_STUN_ATTR_CHANNEL_NUMBER, 0); cn = PJ_STUN_GET_CH_NB(cna->value); resp = create_success_response(test_srv, alloc, req, pool, 0, &auth_key); for (j=0; j<alloc->perm_cnt; ++j) { if (pj_sockaddr_cmp(&alloc->perm[j], &pa->sockaddr)==0) break; } if (i==alloc->perm_cnt) { if (alloc->perm_cnt==MAX_TURN_PERM) { pj_stun_msg_create_response(pool, req, PJ_STUN_SC_INSUFFICIENT_CAPACITY, NULL, &resp); goto send_pkt; } pj_sockaddr_cp(&alloc->perm[i], &pa->sockaddr); ++alloc->perm_cnt; } alloc->chnum[i] = cn; resp = create_success_response(test_srv, alloc, req, pool, 0, &auth_key); } else if (PJ_STUN_IS_REQUEST(req->hdr.type)) { pj_stun_msg_create_response(pool, req, PJ_STUN_SC_BAD_REQUEST, NULL, &resp); } } send_pkt: if (resp) { status = pj_stun_msg_encode(resp, (pj_uint8_t*)data, MAX_STUN_PKT, 0, &auth_key, &size); if (status != PJ_SUCCESS) goto on_return; len = size; status = pj_activesock_sendto(asock, &test_srv->send_key, data, &len, 0, src_addr, addr_len); } on_return: pj_pool_release(pool); return PJ_TRUE; }
static pj_bool_t srv_on_data_recvfrom(pj_activesock_t *asock, void *data, pj_size_t size, const pj_sockaddr_t *src_addr, int addr_len, pj_status_t status) { struct stun_srv *srv; pj_ssize_t sent; srv = (struct stun_srv*) pj_activesock_get_user_data(asock); /* Ignore error */ if (status != PJ_SUCCESS) return PJ_TRUE; ++srv->rx_cnt; /* Ignore if we're not responding */ if (srv->flag & RESPOND_STUN) { pj_pool_t *pool; pj_stun_msg *req_msg, *res_msg; pool = pj_pool_create(mem, "stunsrv", 512, 512, NULL); /* Parse request */ status = pj_stun_msg_decode(pool, (pj_uint8_t*)data, size, PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, &req_msg, NULL, NULL); if (status != PJ_SUCCESS) { app_perror(" pj_stun_msg_decode()", status); pj_pool_release(pool); return PJ_TRUE; } /* Create response */ status = pj_stun_msg_create(pool, PJ_STUN_BINDING_RESPONSE, PJ_STUN_MAGIC, req_msg->hdr.tsx_id, &res_msg); if (status != PJ_SUCCESS) { app_perror(" pj_stun_msg_create()", status); pj_pool_release(pool); return PJ_TRUE; } /* Add MAPPED-ADDRESS or XOR-MAPPED-ADDRESS (or don't add) */ if (srv->flag & WITH_MAPPED) { pj_sockaddr_in addr; pj_sockaddr_in_init(&addr, &srv->ip_to_send, srv->port_to_send); pj_stun_msg_add_sockaddr_attr(pool, res_msg, PJ_STUN_ATTR_MAPPED_ADDR, PJ_FALSE, &addr, sizeof(addr)); } else if (srv->flag & WITH_XOR_MAPPED) { pj_sockaddr_in addr; pj_sockaddr_in_init(&addr, &srv->ip_to_send, srv->port_to_send); pj_stun_msg_add_sockaddr_attr(pool, res_msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR, PJ_TRUE, &addr, sizeof(addr)); } /* Encode */ status = pj_stun_msg_encode(res_msg, (pj_uint8_t*)data, 100, 0, NULL, &size); if (status != PJ_SUCCESS) { app_perror(" pj_stun_msg_encode()", status); pj_pool_release(pool); return PJ_TRUE; } /* Send back */ sent = size; pj_activesock_sendto(asock, &srv->send_key, data, &sent, 0, src_addr, addr_len); pj_pool_release(pool); } else if (srv->flag & ECHO) { /* Send back */ sent = size; pj_activesock_sendto(asock, &srv->send_key, data, &sent, 0, src_addr, addr_len); } return PJ_TRUE; }