Beispiel #1
0
/**
 * Deserialization routine for keydata.
 */
static void
deserialize_keydata(bstr_t *bs, void *valptr, size_t len)
{
	struct keydata *kd = valptr;
	int i;
	uint8 version;

	g_assert(sizeof *kd == len);

	/*
	 * Early returns will cause DBMW to complain that the value could not
	 * be deserialized properly.  We do not log anything here.
	 */

	if (!bstr_read_u8(bs, &version))
		return;

	if (!bstr_read_u8(bs, &kd->values))
		return;

	if (kd->values > G_N_ELEMENTS(kd->creators))
		return;

	STATIC_ASSERT(G_N_ELEMENTS(kd->creators) == G_N_ELEMENTS(kd->dbkeys));
	STATIC_ASSERT(G_N_ELEMENTS(kd->creators) == G_N_ELEMENTS(kd->expire));

	for (i = 0; i < kd->values; i++) {
		bstr_read(bs, &kd->creators[i], sizeof(kd->creators[i]));
		bstr_read(bs, &kd->dbkeys[i], sizeof(kd->dbkeys[i]));
		bstr_read_time(bs, &kd->expire[i]);
	}
}
Beispiel #2
0
/**
 * Deserialization routine for pubdata.
 */
static void
deserialize_pubdata(bstr_t *bs, void *valptr, size_t len)
{
	struct pubdata *pd = valptr;

	g_assert(sizeof *pd == len);

	bstr_read_time(bs, &pd->next_enqueue);
	bstr_read_time(bs, &pd->expiration);

	/*
	 * Temporary, until 0.96.7 is out: we cannot blindly read the version
	 * since it was lacking in previous experimental versions.  Therefore
	 * only do it if we have unread data.
	 *
	 * The test will be removed in versions after 0.96.7, when we can be
	 * certain that the new data format was serialized.
	 *		--RAM, 2009-10-18
	 */

	if (bstr_unread_size(bs))
		bstr_read_u8(bs, &pd->version);
	else
		pd->version = 0;
}
Beispiel #3
0
/**
 * Deserialization routine for lifedata.
 */
static void
deserialize_lifedata(bstr_t *bs, gpointer valptr, size_t len)
{
    struct lifedata *ld = valptr;

    g_assert(sizeof *ld == len);

    bstr_read_u8(bs, &ld->version);
    bstr_read_time(bs, &ld->first_seen);
    bstr_read_time(bs, &ld->last_seen);
}
Beispiel #4
0
/**
 * Deserialization routine for guiddata.
 */
static void
deserialize_guiddata(bstr_t *bs, void *valptr, size_t len)
{
	struct guiddata *gd = valptr;
	uint8 version;

	g_assert(sizeof *gd == len);

	bstr_read_u8(bs, &version);
	bstr_read_time(bs, &gd->create_time);
	bstr_read_time(bs, &gd->last_time);
}
Beispiel #5
0
/**
 * Deserialization routine for tokdata.
 */
static void
deserialize_tokdata(bstr_t *bs, void *valptr, size_t len)
{
	struct tokdata *td = valptr;

	g_assert(sizeof *td == len);

	bstr_read_time(bs, &td->last_update);
	bstr_read_u8(bs, &td->length);

	if (td->length != 0) {
		td->token = walloc(td->length);
		bstr_read(bs, td->token, td->length);
	} else {
		td->token = NULL;
	}
}
Beispiel #6
0
/**
 * Handle reply to a mapping request.
 *
 * @param payload		the received reply
 * @param len			length of reply
 * @param rd			the RPC request descriptor
 *
 * @return TRUE if we successfully processed the reply and notified the
 * user code about the outcome of the request, FALSE if we need to resend
 * the request.
 */
static bool
natpmp_handle_mapping_reply(
	const void *payload, size_t len, struct natpmp_rpc *rd)
{
	bstr_t *bs;
	uint8 version;
	uint8 code;
	uint16 result = 0;
	uint16 port;
	uint32 lifetime;

	natpmp_rpc_check(rd);

	/*
	 * We expect the following reply to a mapping request:
	 *
     *    0                   1                   2                   3
     *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *   | Vers = 0      | OP = 128 + x  | Result Code                   |
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *   | Seconds Since Start of Epoch                                  |
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *   | Internal Port                 | Mapped External Port          |
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *   | Port Mapping Lifetime in Seconds                              |
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 */

	bs = bstr_open(payload, len,
			GNET_PROPERTY(natpmp_debug) ? BSTR_F_ERROR : 0);

	/*
	 * Make sure we got a valid reply.
	 */

	bstr_read_u8(bs, &version);
	bstr_read_u8(bs, &code);
	bstr_read_be16(bs, &result);

	if (bstr_has_error(bs))
		goto error;

	if (GNET_PROPERTY(natpmp_debug) > 5) {
		g_debug("NATPMP version=%u, code=%u, result_code=%u (%s)",
			version, code, result, natpmp_strerror(result));
	}

	if (version != NATPMP_VERSION || code != NATPMP_REPLY_OFF + rd->op)
		goto error;

	if (NATPMP_E_OK != result)
		goto failed;

	/*
	 * We're allowed to parse the remaining of the packet.
	 */

	bstr_read_be32(bs, &rd->sssoe);
	bstr_read_be16(bs, &port);			/* Internal port */
	if (port != rd->iport)
		goto error;
	bstr_read_be16(bs, &port);			/* External port */
	bstr_read_be32(bs, &lifetime);		/* Lease time */

	/*
	 * Signal success, if needed.
	 */

	if (GNET_PROPERTY(natpmp_debug) > 1) {
		g_debug("NATPMP %spublished NAT-PMP mapping for %s port %u",
			0 == lifetime ? "un-" : "",
			NATPMP_OP_MAP_TCP == rd->op ? "TCP" : "UDP", rd->iport);
	}

	if (rd->cb.map != NULL)
		(*rd->cb.map)(result, port, lifetime, rd->arg);

	bstr_free(&bs);
	return TRUE;		/* OK */

failed:
	if (GNET_PROPERTY(natpmp_debug))
		g_warning("NATPMP unable to publish NAT-PMP mapping: %s",
			natpmp_strerror(result));

	if (rd->cb.map != NULL)
		(*rd->cb.map)(result, 0, 0, rd->arg);

	return TRUE;		/* We're done for now */

error:
	if (GNET_PROPERTY(natpmp_debug)) {
		if (bstr_has_error(bs)) {
			g_warning("NATPMP parsing error while processing discovery reply "
				"(%zu byte%s): %s",
				len, 1 == len ? "" : "s", bstr_error(bs));
		} else {
			g_warning("NATPMP inconsistent discovery reply (%zu byte%s)",
				len, 1 == len ? "" : "s");
		}
	}
	bstr_free(&bs);
	return FALSE;
}
Beispiel #7
0
/**
 * Handle reply to a discovery request.
 *
 * @param payload		the received reply
 * @param len			length of reply
 * @param rd			the RPC request descriptor
 *
 * @return TRUE if we successfully processed the reply and notified the
 * user code about the outcome of the request, FALSE if we need to resend
 * the request.
 */
static bool
natpmp_handle_discovery_reply(
	const void *payload, size_t len, struct natpmp_rpc *rd)
{
	bstr_t *bs;
	uint8 version;
	uint8 code;
	uint16 result;
	uint32 ip;
	host_addr_t wan_ip;
	natpmp_t *np;

	natpmp_rpc_check(rd);

	/**
	 * A NAT gateway will reply with the following message:
	 *
     *    0                   1                   2                   3
     *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *   | Vers = 0      | OP = 128 + 0  | Result Code                   |
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *   | Seconds Since Start of Epoch                                  |
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *   | External IP Address (a.b.c.d)                                 |
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 *
	 * The first 32-bits are always present, the remaining of the packet
	 * may or may not be there depending on the result code.
	 */

	bs = bstr_open(payload, len,
			GNET_PROPERTY(natpmp_debug) ? BSTR_F_ERROR : 0);

	/*
	 * Make sure we got a valid reply.
	 */

	bstr_read_u8(bs, &version);
	bstr_read_u8(bs, &code);
	bstr_read_be16(bs, &result);

	if (bstr_has_error(bs))
		goto error;

	if (GNET_PROPERTY(natpmp_debug) > 5) {
		g_debug("NATPMP version=%u, code=%u, result_code=%u (%s)",
			version, code, result, natpmp_strerror(result));
	}

	if (version != NATPMP_VERSION || code != NATPMP_REPLY_OFF + rd->op)
		goto error;

	if (NATPMP_E_OK != result)
		goto failed;

	bstr_read_be32(bs, &rd->sssoe);
	bstr_read_be32(bs, &ip);

	if (bstr_has_error(bs))
		goto error;

	wan_ip = host_addr_get_ipv4(ip);

	if (GNET_PROPERTY(natpmp_debug) > 5) {
		g_debug("NATPMP SSSOE=%u, WAN IP is %s",
			rd->sssoe, host_addr_to_string(wan_ip));
	}

	if (!host_addr_is_routable(wan_ip))
		goto failed;

	/*
	 * Good, we got a valid reply from the gateway, with a routable WAN IP.
	 */

	if (rd->np != NULL) {
		natpmp_check(rd->np);
		np = rd->np;
		natpmp_update(np, rd->sssoe);
		np->wan_ip = wan_ip;
	} else {
		np = natpmp_alloc(rd->gateway, rd->sssoe, wan_ip);
	}

	(*rd->cb.discovery)(TRUE, np, rd->arg);

	bstr_free(&bs);
	return TRUE;		/* OK */

failed:
	if (GNET_PROPERTY(natpmp_debug))
		g_warning("NATPMP did not find any suitable NAT-PMP gateway");

	(*rd->cb.discovery)(FALSE, rd->np, rd->arg);
	return TRUE;		/* We're done for now */

error:
	if (GNET_PROPERTY(natpmp_debug)) {
		if (bstr_has_error(bs)) {
			g_warning("NATPMP parsing error while processing discovery reply "
				"(%zu byte%s): %s",
				len, 1 == len ? "" : "s", bstr_error(bs));
		} else {
			g_warning("NATPMP inconsistent discovery reply (%zu byte%s)",
				len, 1 == len ? "" : "s");
		}
	}
	bstr_free(&bs);
	return FALSE;
}