Esempio n. 1
0
/* 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;
}
Esempio n. 2
0
static pj_bool_t stun_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_stun_msg *req, *resp = NULL;
    pj_pool_t *pool;
    pj_ssize_t len;

    if (status != PJ_SUCCESS)
	return PJ_TRUE;

    test_srv = (test_server*) pj_activesock_get_user_data(asock);
    pool = pj_pool_create(test_srv->stun_cfg->pf, NULL, 512, 512, NULL);

    status = pj_stun_msg_decode(pool, (pj_uint8_t*)data, size, 
				PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, 
				&req, NULL, NULL);
    if (status != PJ_SUCCESS)
	goto on_return;

    if (req->hdr.type != PJ_STUN_BINDING_REQUEST) {
	pj_stun_msg_create_response(pool, req, PJ_STUN_SC_BAD_REQUEST, 
				    NULL, &resp);
	goto send_pkt;
    }

    status = pj_stun_msg_create_response(pool, req, 0, NULL, &resp);
    if (status != PJ_SUCCESS)
	goto on_return;

    pj_stun_msg_add_sockaddr_attr(pool, resp, PJ_STUN_ATTR_XOR_MAPPED_ADDR,
				  PJ_TRUE, src_addr, addr_len);

send_pkt:
    status = pj_stun_msg_encode(resp, (pj_uint8_t*)data, MAX_STUN_PKT, 
				0, NULL, &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;
}
Esempio n. 3
0
/* Handle STUN Binding request */
static void handle_binding_request(pj_turn_pkt *pkt,
				   unsigned options)
{
    pj_stun_msg *request, *response;
    pj_uint8_t pdu[200];
    pj_size_t len;
    pj_status_t status;

    /* Decode request */
    status = pj_stun_msg_decode(pkt->pool, pkt->pkt, pkt->len, options,
				&request, NULL, NULL);
    if (status != PJ_SUCCESS)
	return;

    /* Create response */
    status = pj_stun_msg_create_response(pkt->pool, request, 0, NULL, 
					 &response);
    if (status != PJ_SUCCESS)
	return;

    /* Add XOR-MAPPED-ADDRESS */
    pj_stun_msg_add_sockaddr_attr(pkt->pool, response, 
				  PJ_STUN_ATTR_XOR_MAPPED_ADDR,
				  PJ_TRUE,
				  &pkt->src.clt_addr,
				  pkt->src_addr_len);

    /* Encode */
    status = pj_stun_msg_encode(response, pdu, sizeof(pdu), 0, NULL, &len);
    if (status != PJ_SUCCESS)
	return;

    /* Send response */
    pkt->transport->sendto(pkt->transport, pdu, len, 0, 
			   &pkt->src.clt_addr, pkt->src_addr_len);
}
static int fingerprint_test_vector()
{
    pj_pool_t *pool;
    pj_status_t status;
    unsigned i;
    int rc = 0;

    /* To avoid function not referenced warnings */
    (void)create_msgint2;
    (void)create_msgint3;

    PJ_LOG(3,(THIS_FILE, "  draft-denis-behave-rfc3489bis-test-vectors-02"));

    pool = pj_pool_create(mem, "fingerprint", 1024, 1024, NULL);

    for (i=0; i<PJ_ARRAY_SIZE(test_vectors); ++i) {
	struct test_vector *v;
	pj_stun_msg *ref_msg, *msg;
	pj_size_t parsed_len;
	pj_size_t len;
	unsigned pos;
	pj_uint8_t buf[1500];
	char print[1500];
	pj_str_t key;

	PJ_LOG(3,(THIS_FILE, "    Running test %d/%d", i, 
	          PJ_ARRAY_SIZE(test_vectors)));

	v = &test_vectors[i];

	/* Print reference message */
	PJ_LOG(4,(THIS_FILE, "Reference message PDU:\n%s",
	          print_binary((pj_uint8_t*)v->pdu, v->pdu_len)));

	/* Try to parse the reference message first */
	status = pj_stun_msg_decode(pool, (pj_uint8_t*)v->pdu, v->pdu_len,
				    PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, 
				    &ref_msg, &parsed_len, NULL);
	if (status != PJ_SUCCESS) {
	    PJ_LOG(1,(THIS_FILE, "    Error decoding reference message"));
	    rc = -1010;
	    goto on_return;
	}

	if (parsed_len != v->pdu_len) {
	    PJ_LOG(1,(THIS_FILE, "    Parsed len error"));
	    rc = -1020;
	    goto on_return;
	}

	/* Print the reference message */
	pj_stun_msg_dump(ref_msg, print, sizeof(print), NULL);
	PJ_LOG(4,(THIS_FILE, "Reference message:\n%s", print));

	/* Create our message */
	msg = v->create(pool, v);
	if (msg == NULL) {
	    PJ_LOG(1,(THIS_FILE, "    Error creating stun message"));
	    rc = -1030;
	    goto on_return;
	}

	/* Encode message */
	if (v->options & USE_MESSAGE_INTEGRITY) {
	    pj_str_t s1, s2, r;

	    pj_stun_create_key(pool, &key, pj_cstr(&r, v->realm), 
			       pj_cstr(&s1, v->username), 
			       PJ_STUN_PASSWD_PLAIN, 
			       pj_cstr(&s2, v->password));
	    pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);

	} else {
	    pj_stun_msg_encode(msg, buf, sizeof(buf), 0, NULL, &len);
	}

	/* Print our raw message */
	PJ_LOG(4,(THIS_FILE, "Message PDU:\n%s",
	          print_binary((pj_uint8_t*)buf, len)));

	/* Print our message */
	pj_stun_msg_dump(msg, print, sizeof(print), NULL);
	PJ_LOG(4,(THIS_FILE, "Message is:\n%s", print));

	/* Compare message length */
	if (len != v->pdu_len) {
	    PJ_LOG(1,(THIS_FILE, "    Message length mismatch"));
	    rc = -1050;
	    goto on_return;
	}

	pos = cmp_buf(buf, (const pj_uint8_t*)v->pdu, len);
	if (pos != (unsigned)-1) {
	    PJ_LOG(1,(THIS_FILE, "    Message mismatch at byte %d", pos));
	    rc = -1060;
	    goto on_return;
	}

	/* Authenticate the request/response */
	if (v->options & USE_MESSAGE_INTEGRITY) {
	    if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
		pj_stun_auth_cred cred;
		pj_status_t status;

		pj_bzero(&cred, sizeof(cred));
		cred.type = PJ_STUN_AUTH_CRED_STATIC;
		cred.data.static_cred.realm = pj_str(v->realm);
		cred.data.static_cred.username = pj_str(v->username);
		cred.data.static_cred.data = pj_str(v->password);
		cred.data.static_cred.nonce = pj_str(v->nonce);

		status = pj_stun_authenticate_request(buf, len, msg, 
						      &cred, pool, NULL, NULL);
		if (status != PJ_SUCCESS) {
		    char errmsg[PJ_ERR_MSG_SIZE];
		    pj_strerror(status, errmsg, sizeof(errmsg));
		    PJ_LOG(1,(THIS_FILE, 
			      "    Request authentication failed: %s",
			      errmsg));
		    rc = -1070;
		    goto on_return;
		}

	    } else if (PJ_STUN_IS_RESPONSE(msg->hdr.type)) {
		pj_status_t status;
		status = pj_stun_authenticate_response(buf, len, msg, &key);
		if (status != PJ_SUCCESS) {
		    char errmsg[PJ_ERR_MSG_SIZE];
		    pj_strerror(status, errmsg, sizeof(errmsg));
		    PJ_LOG(1,(THIS_FILE, 
			      "    Response authentication failed: %s",
			      errmsg));
		    rc = -1080;
		    goto on_return;
		}
	    }
	}	
    }


on_return:
    pj_pool_release(pool);
    return rc;
}
static int decode_test(void)
{
    unsigned i;
    pj_pool_t *pool;
    int rc = 0;
    
    pool = pj_pool_create(mem, "decode_test", 1024, 1024, NULL);

    PJ_LOG(3,(THIS_FILE, "  STUN decode test"));

    for (i=0; i<PJ_ARRAY_SIZE(tests); ++i) {
	struct test *t = &tests[i];
	pj_stun_msg *msg, *msg2;
	pj_uint8_t buf[1500];
	pj_str_t key;
	pj_size_t len;
	pj_status_t status;

	PJ_LOG(3,(THIS_FILE, "   %s", t->title));

	if (t->pdu) {
	    status = pj_stun_msg_decode(pool, (pj_uint8_t*)t->pdu, t->pdu_len,
				        PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, 
					&msg, NULL, NULL);

	    /* Check expected decode result */
	    if (t->expected_status != status) {
		PJ_LOG(1,(THIS_FILE, "    expecting status %d, got %d",
		          t->expected_status, status));
		rc = -10;
		goto on_return;
	    }

	} else {
	    msg = t->create(pool);
	    status = PJ_SUCCESS;
	}

	if (status != PJ_SUCCESS)
	    continue;

	/* Try to encode message */
	pj_stun_create_key(pool, &key, NULL, &USERNAME, PJ_STUN_PASSWD_PLAIN, &PASSWORD);
	status = pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);
	if (status != PJ_SUCCESS) {
	    PJ_LOG(1,(THIS_FILE, "    encode error: %s", err(status)));
	    rc = -40;
	    goto on_return;
	}

	/* Try to decode it once more */
	status = pj_stun_msg_decode(pool, buf, len, 
				    PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, 
				    &msg2, NULL, NULL);
	if (status != PJ_SUCCESS) {
	    PJ_LOG(1,(THIS_FILE, "    subsequent decoding failed: %s", err(status)));
	    rc = -50;
	    goto on_return;
	}

	/* Verify */
	if (t->verify) {
	    rc = t->verify(msg);
	    if (rc != 0) {
		goto on_return;
	    }
	}
    }

on_return:
    pj_pool_release(pool);
    if (rc == 0)
	PJ_LOG(3,(THIS_FILE, "...success!"));
    return rc;
}
Esempio n. 6
0
static int server_thread_proc(void *p)
{
    struct stun_test_session *test_sess = (struct stun_test_session*)p;
    pj_pool_t *pool;
    pj_status_t status;

    PJ_LOG(4,(THIS_FILE, "Server thread running"));

    pool = pj_pool_create(test_sess->stun_cfg.pf, "server", 512, 512, NULL);

    while (!test_sess->thread_quit_flag) {
	pj_time_val timeout = {0, 10};
	pj_fd_set_t rdset;
	int n;

	/* Serve client */
	PJ_FD_ZERO(&rdset);
	PJ_FD_SET(test_sess->server_sock, &rdset);
	n = pj_sock_select(test_sess->server_sock+1, &rdset,
	                   NULL, NULL, &timeout);
	if (n==1 && PJ_FD_ISSET(test_sess->server_sock, &rdset)) {
	    pj_uint8_t pkt[512];
	    pj_ssize_t pkt_len;
	    pj_size_t res_len;
	    pj_sockaddr client_addr;
	    int addr_len;

	    pj_stun_msg	*stun_req, *stun_res;

	    pj_pool_reset(pool);

	    /* Got query */
	    pkt_len = sizeof(pkt);
	    addr_len = sizeof(client_addr);
	    status = pj_sock_recvfrom(test_sess->server_sock, pkt, &pkt_len,
	                              0, &client_addr, &addr_len);
	    if (status != PJ_SUCCESS) {
		continue;
	    }

	    status = pj_stun_msg_decode(pool, pkt, pkt_len,
	                                PJ_STUN_IS_DATAGRAM,
	                                &stun_req, NULL, NULL);
	    if (status != PJ_SUCCESS) {
		PJ_PERROR(1,(THIS_FILE, status, "STUN request decode error"));
		continue;
	    }

	    status = pj_stun_msg_create_response(pool, stun_req,
	                                         PJ_STUN_SC_BAD_REQUEST, NULL,
	                                         &stun_res);
	    if (status != PJ_SUCCESS) {
		PJ_PERROR(1,(THIS_FILE, status, "STUN create response error"));
		continue;
	    }

	    status = pj_stun_msg_encode(stun_res, pkt, sizeof(pkt), 0,
	                                NULL, &res_len);
	    if (status != PJ_SUCCESS) {
		PJ_PERROR(1,(THIS_FILE, status, "STUN encode error"));
		continue;
	    }

	    /* Ignore request */
	    if (test_sess->param.server_drop_request)
		continue;

	    /* Wait for signal to continue */
	    if (test_sess->param.server_wait_for_event)
		pj_event_wait(test_sess->server_event);

	    pkt_len = res_len;
	    pj_sock_sendto(test_sess->server_sock, pkt, &pkt_len, 0,
	                   &client_addr, pj_sockaddr_get_len(&client_addr));
	}
    }

    pj_pool_release(pool);

    PJ_LOG(4,(THIS_FILE, "Server thread quitting"));
    return 0;
}
Esempio n. 7
0
/* On received data from peer */
static pj_bool_t alloc_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)
{
    turn_allocation *alloc;
    pj_stun_xor_peer_addr_attr *pa;
    pj_stun_data_attr *da;
    char peer_info[PJ_INET6_ADDRSTRLEN+10];
    char client_info[PJ_INET6_ADDRSTRLEN+10];
    pj_uint8_t buffer[1500];
    pj_ssize_t sent;
    unsigned i;

    if (status != PJ_SUCCESS)
	return PJ_TRUE;

    alloc = (turn_allocation*) pj_activesock_get_user_data(asock);

    pj_sockaddr_print(&alloc->client_addr, client_info, sizeof(client_info), 3);
    pj_sockaddr_print(src_addr, peer_info, sizeof(peer_info), 3);

    /* Check that this peer has a permission */
    for (i=0; i<alloc->perm_cnt; ++i) {
	if (pj_sockaddr_get_len(&alloc->perm[i]) == (unsigned)addr_len &&
	    pj_memcmp(pj_sockaddr_get_addr(&alloc->perm[i]),
		      pj_sockaddr_get_addr(src_addr),
		      addr_len) == 0)
	{
	    break;
	}
    }
    if (i==alloc->perm_cnt) {
	PJ_LOG(5,("", "Client %s received %d bytes unauthorized data from peer %s", 
		      client_info, size, peer_info));
	if (alloc->perm_cnt == 0)
	    PJ_LOG(5,("", "Client %s has no permission", client_info));
	return PJ_TRUE;
    }

    /* Format a Data indication */
    pa = (pj_stun_xor_peer_addr_attr*)
	 pj_stun_msg_find_attr(alloc->data_ind, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
    da = (pj_stun_data_attr*)
	 pj_stun_msg_find_attr(alloc->data_ind, PJ_STUN_ATTR_DATA, 0);
    pj_assert(pa && da);

    pj_sockaddr_cp(&pa->sockaddr, src_addr);
    da->data = (pj_uint8_t*)data;
    da->length = size;

    /* Encode Data indication */
    status = pj_stun_msg_encode(alloc->data_ind, buffer, sizeof(buffer), 0,
				NULL, &size);
    if (status != PJ_SUCCESS)
	return PJ_TRUE;

    /* Send */
    sent = size;
    PJ_LOG(5,("", "Forwarding %d bytes data from peer %s to client %s", 
		   sent, peer_info, client_info));

    pj_activesock_sendto(alloc->test_srv->turn_sock, &alloc->send_key, buffer,
			 &sent, 0, &alloc->client_addr,
			 pj_sockaddr_get_len(&alloc->client_addr));

    return PJ_TRUE;
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
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;
}