summaryrefslogtreecommitdiff
path: root/src/libstrongswan/utils
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2016-03-24 11:59:32 +0100
committerYves-Alexis Perez <corsac@debian.org>2016-03-24 11:59:32 +0100
commit518dd33c94e041db0444c7d1f33da363bb8e3faf (patch)
treee8d1665ffadff7ec40228dda47e81f8f4691cd07 /src/libstrongswan/utils
parentf42f239a632306ed082f6fde878977248eea85cf (diff)
downloadvyos-strongswan-518dd33c94e041db0444c7d1f33da363bb8e3faf.tar.gz
vyos-strongswan-518dd33c94e041db0444c7d1f33da363bb8e3faf.zip
Imported Upstream version 5.4.0
Diffstat (limited to 'src/libstrongswan/utils')
-rw-r--r--src/libstrongswan/utils/compat/windows.c1
-rw-r--r--src/libstrongswan/utils/debug.c6
-rw-r--r--src/libstrongswan/utils/identification.c389
-rw-r--r--src/libstrongswan/utils/identification.h2
-rw-r--r--src/libstrongswan/utils/utils/byteorder.h78
5 files changed, 418 insertions, 58 deletions
diff --git a/src/libstrongswan/utils/compat/windows.c b/src/libstrongswan/utils/compat/windows.c
index 1f22ffa02..12ee59916 100644
--- a/src/libstrongswan/utils/compat/windows.c
+++ b/src/libstrongswan/utils/compat/windows.c
@@ -82,7 +82,6 @@ static void* dlsym_default(const char *name)
{
const char *dlls[] = {
"libstrongswan-0.dll",
- "libhydra-0.dll",
"libcharon-0.dll",
"libtnccs-0.dll",
NULL /* .exe */
diff --git a/src/libstrongswan/utils/debug.c b/src/libstrongswan/utils/debug.c
index e8c9e6b98..8a80b81a2 100644
--- a/src/libstrongswan/utils/debug.c
+++ b/src/libstrongswan/utils/debug.c
@@ -17,7 +17,7 @@
#include "debug.h"
-ENUM(debug_names, DBG_DMN, DBG_LIB,
+ENUM(debug_names, DBG_DMN, DBG_ANY,
"DMN",
"MGR",
"IKE",
@@ -36,9 +36,10 @@ ENUM(debug_names, DBG_DMN, DBG_LIB,
"APP",
"ESP",
"LIB",
+ "ANY",
);
-ENUM(debug_lower_names, DBG_DMN, DBG_LIB,
+ENUM(debug_lower_names, DBG_DMN, DBG_ANY,
"dmn",
"mgr",
"ike",
@@ -57,6 +58,7 @@ ENUM(debug_lower_names, DBG_DMN, DBG_LIB,
"app",
"esp",
"lib",
+ "any",
);
/**
diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c
index da23d143c..2b2e907f0 100644
--- a/src/libstrongswan/utils/identification.c
+++ b/src/libstrongswan/utils/identification.c
@@ -1,8 +1,9 @@
/*
+ * Copyright (C) 2016 Andreas Steffen
* Copyright (C) 2009-2015 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
+ * HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -79,6 +80,7 @@ static const x501rdn_t x501rdns[] = {
{"G", OID_GIVEN_NAME, ASN1_PRINTABLESTRING},
{"I", OID_INITIALS, ASN1_PRINTABLESTRING},
{"dnQualifier", OID_DN_QUALIFIER, ASN1_PRINTABLESTRING},
+ {"pseudonym", OID_PSEUDONYM, ASN1_PRINTABLESTRING},
{"ID", OID_UNIQUE_IDENTIFIER, ASN1_PRINTABLESTRING},
{"EN", OID_EMPLOYEE_NUMBER, ASN1_PRINTABLESTRING},
{"employeeNumber", OID_EMPLOYEE_NUMBER, ASN1_PRINTABLESTRING},
@@ -218,6 +220,7 @@ METHOD(enumerator_t, rdn_part_enumerate, bool,
{OID_GIVEN_NAME, ID_PART_RDN_G},
{OID_INITIALS, ID_PART_RDN_I},
{OID_DN_QUALIFIER, ID_PART_RDN_DNQ},
+ {OID_PSEUDONYM, ID_PART_RDN_PN},
{OID_UNIQUE_IDENTIFIER, ID_PART_RDN_ID},
{OID_EMAIL_ADDRESS, ID_PART_RDN_E},
{OID_EMPLOYEE_NUMBER, ID_PART_RDN_EN},
@@ -822,6 +825,154 @@ METHOD(identification_t, matches_dn, id_match_t,
}
/**
+ * Transform netmask to CIDR bits
+ */
+static int netmask_to_cidr(char *netmask, size_t address_size)
+{
+ uint8_t byte;
+ int i, netbits = 0;
+
+ for (i = 0; i < address_size; i++)
+ {
+ byte = netmask[i];
+
+ if (byte == 0x00)
+ {
+ break;
+ }
+ if (byte == 0xff)
+ {
+ netbits += 8;
+ }
+ else
+ {
+ while (byte & 0x80)
+ {
+ netbits++;
+ byte <<= 1;
+ }
+ }
+ }
+ return netbits;
+}
+
+METHOD(identification_t, matches_range, id_match_t,
+ private_identification_t *this, identification_t *other)
+{
+ chunk_t other_encoding;
+ uint8_t *address, *from, *to, *network, *netmask;
+ size_t address_size = 0;
+ int netbits, range_sign, i;
+
+ if (other->get_type(other) == ID_ANY)
+ {
+ return ID_MATCH_ANY;
+ }
+ if (this->type == other->get_type(other) &&
+ chunk_equals(this->encoded, other->get_encoding(other)))
+ {
+ return ID_MATCH_PERFECT;
+ }
+ if ((this->type == ID_IPV4_ADDR &&
+ other->get_type(other) == ID_IPV4_ADDR_SUBNET))
+ {
+ address_size = sizeof(struct in_addr);
+ }
+ else if ((this->type == ID_IPV6_ADDR &&
+ other->get_type(other) == ID_IPV6_ADDR_SUBNET))
+ {
+ address_size = sizeof(struct in6_addr);
+ }
+ if (address_size)
+ {
+ other_encoding = other->get_encoding(other);
+ if (this->encoded.len != address_size ||
+ other_encoding.len != 2 * address_size)
+ {
+ return ID_MATCH_NONE;
+ }
+ address = this->encoded.ptr;
+ network = other_encoding.ptr;
+ netmask = other_encoding.ptr + address_size;
+ netbits = netmask_to_cidr(netmask, address_size);
+
+ if (netbits == 0)
+ {
+ return ID_MATCH_MAX_WILDCARDS;
+ }
+ if (netbits == 8 * address_size)
+ {
+ return memeq(address, network, address_size) ?
+ ID_MATCH_PERFECT : ID_MATCH_NONE;
+ }
+ for (i = 0; i < (netbits + 7)/8; i++)
+ {
+ if ((address[i] ^ network[i]) & netmask[i])
+ {
+ return ID_MATCH_NONE;
+ }
+ }
+ return ID_MATCH_ONE_WILDCARD;
+ }
+ if ((this->type == ID_IPV4_ADDR &&
+ other->get_type(other) == ID_IPV4_ADDR_RANGE))
+ {
+ address_size = sizeof(struct in_addr);
+ }
+ else if ((this->type == ID_IPV6_ADDR &&
+ other->get_type(other) == ID_IPV6_ADDR_RANGE))
+ {
+ address_size = sizeof(struct in6_addr);
+ }
+ if (address_size)
+ {
+ other_encoding = other->get_encoding(other);
+ if (this->encoded.len != address_size ||
+ other_encoding.len != 2 * address_size)
+ {
+ return ID_MATCH_NONE;
+ }
+ address = this->encoded.ptr;
+ from = other_encoding.ptr;
+ to = other_encoding.ptr + address_size;
+
+ range_sign = memcmp(to, from, address_size);
+ if (range_sign < 0)
+ { /* to is smaller than from */
+ return ID_MATCH_NONE;
+ }
+
+ /* check lower bound */
+ for (i = 0; i < address_size; i++)
+ {
+ if (address[i] != from[i])
+ {
+ if (address[i] < from[i])
+ {
+ return ID_MATCH_NONE;
+ }
+ break;
+ }
+ }
+
+ /* check upper bound */
+ for (i = 0; i < address_size; i++)
+ {
+ if (address[i] != to[i])
+ {
+ if (address[i] > to[i])
+ {
+ return ID_MATCH_NONE;
+ }
+ break;
+ }
+ }
+ return range_sign ? ID_MATCH_ONE_WILDCARD : ID_MATCH_PERFECT;
+ }
+ return ID_MATCH_NONE;
+}
+
+/**
* Described in header.
*/
int identification_printf_hook(printf_hook_data_t *data,
@@ -829,7 +980,9 @@ int identification_printf_hook(printf_hook_data_t *data,
{
private_identification_t *this = *((private_identification_t**)(args[0]));
chunk_t proper;
- char buf[512];
+ char buf[BUF_LEN], *pos;
+ size_t len, address_size;
+ int written;
if (this == NULL)
{
@@ -839,49 +992,115 @@ int identification_printf_hook(printf_hook_data_t *data,
switch (this->type)
{
case ID_ANY:
- snprintf(buf, sizeof(buf), "%%any");
+ snprintf(buf, BUF_LEN, "%%any");
break;
case ID_IPV4_ADDR:
if (this->encoded.len < sizeof(struct in_addr) ||
- inet_ntop(AF_INET, this->encoded.ptr, buf, sizeof(buf)) == NULL)
+ inet_ntop(AF_INET, this->encoded.ptr, buf, BUF_LEN) == NULL)
{
- snprintf(buf, sizeof(buf), "(invalid ID_IPV4_ADDR)");
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR)");
+ }
+ break;
+ case ID_IPV4_ADDR_SUBNET:
+ address_size = sizeof(struct in_addr);
+ if (this->encoded.len < 2 * address_size ||
+ inet_ntop(AF_INET, this->encoded.ptr, buf, BUF_LEN) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR_SUBNET)");
+ break;
+ }
+ written = strlen(buf);
+ snprintf(buf + written, BUF_LEN - written, "/%d",
+ netmask_to_cidr(this->encoded.ptr + address_size,
+ address_size));
+ break;
+ case ID_IPV4_ADDR_RANGE:
+ address_size = sizeof(struct in_addr);
+ if (this->encoded.len < 2 * address_size ||
+ inet_ntop(AF_INET, this->encoded.ptr, buf, BUF_LEN) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR_RANGE)");
+ break;
+ }
+ written = strlen(buf);
+ pos = buf + written;
+ len = BUF_LEN - written;
+ written = snprintf(pos, len, "-");
+ if (written < 0 || written >= len ||
+ inet_ntop(AF_INET, this->encoded.ptr + address_size,
+ pos + written, len - written) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR_RANGE)");
}
break;
case ID_IPV6_ADDR:
if (this->encoded.len < sizeof(struct in6_addr) ||
- inet_ntop(AF_INET6, this->encoded.ptr, buf, INET6_ADDRSTRLEN) == NULL)
+ inet_ntop(AF_INET6, this->encoded.ptr, buf, BUF_LEN) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR)");
+ }
+ break;
+ case ID_IPV6_ADDR_SUBNET:
+ address_size = sizeof(struct in6_addr);
+ if (this->encoded.len < 2 * address_size ||
+ inet_ntop(AF_INET6, this->encoded.ptr, buf, BUF_LEN) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR_SUBNET)");
+ }
+ else
{
- snprintf(buf, sizeof(buf), "(invalid ID_IPV6_ADDR)");
+ written = strlen(buf);
+ snprintf(buf + written, BUF_LEN - written, "/%d",
+ netmask_to_cidr(this->encoded.ptr + address_size,
+ address_size));
+ }
+ break;
+ case ID_IPV6_ADDR_RANGE:
+ address_size = sizeof(struct in6_addr);
+ if (this->encoded.len < 2 * address_size ||
+ inet_ntop(AF_INET6, this->encoded.ptr, buf, BUF_LEN) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR_RANGE)");
+ break;
+ }
+ written = strlen(buf);
+ pos = buf + written;
+ len = BUF_LEN - written;
+ written = snprintf(pos, len, "-");
+ if (written < 0 || written >= len ||
+ inet_ntop(AF_INET6, this->encoded.ptr + address_size,
+ pos + written, len - written) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR_RANGE)");
}
break;
case ID_FQDN:
case ID_RFC822_ADDR:
case ID_DER_ASN1_GN_URI:
chunk_printable(this->encoded, &proper, '?');
- snprintf(buf, sizeof(buf), "%.*s", (int)proper.len, proper.ptr);
+ snprintf(buf, BUF_LEN, "%.*s", (int)proper.len, proper.ptr);
chunk_free(&proper);
break;
case ID_DER_ASN1_DN:
- dntoa(this->encoded, buf, sizeof(buf));
+ dntoa(this->encoded, buf, BUF_LEN);
break;
case ID_DER_ASN1_GN:
- snprintf(buf, sizeof(buf), "(ASN.1 general name)");
+ snprintf(buf, BUF_LEN, "(ASN.1 general name)");
break;
case ID_KEY_ID:
if (chunk_printable(this->encoded, NULL, '?') &&
this->encoded.len != HASH_SIZE_SHA1)
{ /* fully printable, use ascii version */
- snprintf(buf, sizeof(buf), "%.*s", (int)this->encoded.len,
+ snprintf(buf, BUF_LEN, "%.*s", (int)this->encoded.len,
this->encoded.ptr);
}
else
{ /* not printable, hex dump */
- snprintf(buf, sizeof(buf), "%#B", &this->encoded);
+ snprintf(buf, BUF_LEN, "%#B", &this->encoded);
}
break;
default:
- snprintf(buf, sizeof(buf), "(unknown ID type: %d)", this->type);
+ snprintf(buf, BUF_LEN, "(unknown ID type: %d)", this->type);
break;
}
if (spec->minus)
@@ -950,6 +1169,13 @@ static private_identification_t *identification_create(id_type_t type)
this->public.matches = _matches_dn;
this->public.contains_wildcards = _contains_wildcards_dn;
break;
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ this->public.hash = _hash_binary;
+ this->public.equals = _equals_binary;
+ this->public.matches = _matches_range;
+ this->public.contains_wildcards = return_false;
+ break;
default:
this->public.hash = _hash_binary;
this->public.equals = _equals_binary;
@@ -971,6 +1197,10 @@ static private_identification_t* create_from_string_with_prefix_type(char *str)
} prefixes[] = {
{ "ipv4:", ID_IPV4_ADDR },
{ "ipv6:", ID_IPV6_ADDR },
+ { "ipv4net:", ID_IPV4_ADDR_SUBNET },
+ { "ipv6net:", ID_IPV6_ADDR_SUBNET },
+ { "ipv4range:", ID_IPV4_ADDR_RANGE },
+ { "ipv6range:", ID_IPV6_ADDR_RANGE },
{ "rfc822:", ID_RFC822_ADDR },
{ "email:", ID_RFC822_ADDR },
{ "userfqdn:", ID_USER_FQDN },
@@ -1036,6 +1266,115 @@ static private_identification_t* create_from_string_with_num_type(char *str)
return this;
}
+/**
+ * Convert to an IPv4/IPv6 host address, subnet or address range
+ */
+static private_identification_t* create_ip_address_from_string(char *string,
+ bool is_ipv4)
+{
+ private_identification_t *this;
+ uint8_t encoding[32];
+ uint8_t *str, *pos, *address, *to_address, *netmask;
+ size_t address_size;
+ int bits, bytes, i;
+ bool has_subnet = FALSE, has_range = FALSE;
+
+ address = encoding;
+ address_size = is_ipv4 ? sizeof(struct in_addr) : sizeof(struct in6_addr);
+
+ str = strdup(string);
+ pos = strchr(str, '/');
+ if (pos)
+ { /* separate IP address from optional netmask */
+
+ *pos = '\0';
+ has_subnet = TRUE;
+ }
+ else
+ {
+ pos = strchr(str, '-');
+ if (pos)
+ { /* separate lower address from upper address of IP range */
+ *pos = '\0';
+ has_range = TRUE;
+ }
+ }
+
+ if (inet_pton(is_ipv4 ? AF_INET : AF_INET6, str, address) != 1)
+ {
+ free(str);
+ return NULL;
+ }
+
+ if (has_subnet)
+ { /* is IP subnet */
+ bits = atoi(pos + 1);
+ if (bits > 8 * address_size)
+ {
+ free(str);
+ return NULL;
+ }
+ bytes = bits / 8;
+ bits -= 8 * bytes;
+ netmask = encoding + address_size;
+
+ for (i = 0; i < address_size; i++)
+ {
+ if (bytes)
+ {
+ *netmask = 0xff;
+ bytes--;
+ }
+ else if (bits)
+ {
+ *netmask = 0xff << (8 - bits);
+ bits = 0;
+ }
+ else
+ {
+ *netmask = 0x00;
+ }
+ *address++ &= *netmask++;
+ }
+ this = identification_create(is_ipv4 ? ID_IPV4_ADDR_SUBNET :
+ ID_IPV6_ADDR_SUBNET);
+ this->encoded = chunk_clone(chunk_create(encoding, 2 * address_size));
+ }
+ else if (has_range)
+ { /* is IP range */
+ to_address = encoding + address_size;
+
+ if (inet_pton(is_ipv4 ? AF_INET : AF_INET6, pos + 1, to_address) != 1)
+ {
+ free(str);
+ return NULL;
+ }
+ for (i = 0; i < address_size; i++)
+ {
+ if (address[i] != to_address[i])
+ {
+ if (address[i] > to_address[i])
+ {
+ free(str);
+ return NULL;
+ }
+ break;
+ }
+ }
+ this = identification_create(is_ipv4 ? ID_IPV4_ADDR_RANGE :
+ ID_IPV6_ADDR_RANGE);
+ this->encoded = chunk_clone(chunk_create(encoding, 2 * address_size));
+ }
+ else
+ { /* is IP host address */
+ this = identification_create(is_ipv4 ? ID_IPV4_ADDR : ID_IPV6_ADDR);
+ this->encoded = chunk_clone(chunk_create(encoding, address_size));
+ }
+ free(str);
+
+ return this;
+}
+
/*
* Described in header.
*/
@@ -1093,15 +1432,9 @@ identification_t *identification_create_from_string(char *string)
{
if (strchr(string, ':') == NULL)
{
- struct in_addr address;
- chunk_t chunk = {(void*)&address, sizeof(address)};
-
- if (inet_pton(AF_INET, string, &address) > 0)
- { /* is IPv4 */
- this = identification_create(ID_IPV4_ADDR);
- this->encoded = chunk_clone(chunk);
- }
- else
+ /* IPv4 address or subnet */
+ this = create_ip_address_from_string(string, TRUE);
+ if (!this)
{ /* not IPv4, mostly FQDN */
this = identification_create(ID_FQDN);
this->encoded = chunk_from_str(strdup(string));
@@ -1110,15 +1443,9 @@ identification_t *identification_create_from_string(char *string)
}
else
{
- struct in6_addr address;
- chunk_t chunk = {(void*)&address, sizeof(address)};
-
- if (inet_pton(AF_INET6, string, &address) > 0)
- { /* is IPv6 */
- this = identification_create(ID_IPV6_ADDR);
- this->encoded = chunk_clone(chunk);
- }
- else
+ /* IPv6 address or subnet */
+ this = create_ip_address_from_string(string, FALSE);
+ if (!this)
{ /* not IPv4/6 fallback to KEY_ID */
this = identification_create(ID_KEY_ID);
this->encoded = chunk_from_str(strdup(string));
diff --git a/src/libstrongswan/utils/identification.h b/src/libstrongswan/utils/identification.h
index 5f27ba112..51d132491 100644
--- a/src/libstrongswan/utils/identification.h
+++ b/src/libstrongswan/utils/identification.h
@@ -168,6 +168,8 @@ enum id_part_t {
ID_PART_RDN_I,
/** DN Qualifier RDN of a DN */
ID_PART_RDN_DNQ,
+ /** Pseudonym RDN of a DN */
+ ID_PART_RDN_PN,
/** UniqueIdentifier RDN of a DN */
ID_PART_RDN_ID,
/** Locality RDN of a DN */
diff --git a/src/libstrongswan/utils/utils/byteorder.h b/src/libstrongswan/utils/utils/byteorder.h
index 48cf1d526..3ccbad5f1 100644
--- a/src/libstrongswan/utils/utils/byteorder.h
+++ b/src/libstrongswan/utils/utils/byteorder.h
@@ -44,6 +44,36 @@
#define BITFIELD5(t, a, b, c, d, e,...) struct { t e; t d; t c; t b; t a; __VA_ARGS__}
#endif
+#ifndef le32toh
+# if BYTE_ORDER == BIG_ENDIAN
+# define le32toh(x) __builtin_bswap32(x)
+# define htole32(x) __builtin_bswap32(x)
+# else
+# define le32toh(x) (x)
+# define htole32(x) (x)
+# endif
+#endif
+
+#ifndef le64toh
+# if BYTE_ORDER == BIG_ENDIAN
+# define le64toh(x) __builtin_bswap64(x)
+# define htole64(x) __builtin_bswap64(x)
+# else
+# define le64toh(x) (x)
+# define htole64(x) (x)
+# endif
+#endif
+
+#ifndef be64toh
+# if BYTE_ORDER == BIG_ENDIAN
+# define be64toh(x) (x)
+# define htobe64(x) (x)
+# else
+# define be64toh(x) __builtin_bswap64(x)
+# define htobe64(x) __builtin_bswap64(x)
+# endif
+#endif
+
/**
* Write a 16-bit host order value in network order to an unaligned address.
*
@@ -82,21 +112,8 @@ static inline void htoun64(void *network, u_int64_t host)
{
char *unaligned = (char*)network;
-#ifdef be64toh
host = htobe64(host);
memcpy((char*)unaligned, &host, sizeof(host));
-#else
- u_int32_t high_part, low_part;
-
- high_part = host >> 32;
- high_part = htonl(high_part);
- low_part = host & 0xFFFFFFFFLL;
- low_part = htonl(low_part);
-
- memcpy(unaligned, &high_part, sizeof(high_part));
- unaligned += sizeof(high_part);
- memcpy(unaligned, &low_part, sizeof(low_part));
-#endif
}
/**
@@ -138,24 +155,37 @@ static inline u_int32_t untoh32(void *network)
static inline u_int64_t untoh64(void *network)
{
char *unaligned = (char*)network;
-
-#ifdef be64toh
u_int64_t tmp;
memcpy(&tmp, unaligned, sizeof(tmp));
return be64toh(tmp);
-#else
- u_int32_t high_part, low_part;
+}
- memcpy(&high_part, unaligned, sizeof(high_part));
- unaligned += sizeof(high_part);
- memcpy(&low_part, unaligned, sizeof(low_part));
+/**
+ * Read a 32-bit value in little-endian order from unaligned address.
+ *
+ * @param p unaligned address to read little endian value from
+ * @return host order value
+ */
+static inline u_int32_t uletoh32(void *p)
+{
+ u_int32_t ret;
- high_part = ntohl(high_part);
- low_part = ntohl(low_part);
+ memcpy(&ret, p, sizeof(ret));
+ ret = le32toh(ret);
+ return ret;
+}
- return (((u_int64_t)high_part) << 32) + low_part;
-#endif
+/**
+ * Write a 32-bit value in little-endian to an unaligned address.
+ *
+ * @param p host order 32-bit value
+ * @param v unaligned address to write little endian value to
+ */
+static inline void htoule32(void *p, u_int32_t v)
+{
+ v = htole32(v);
+ memcpy(p, &v, sizeof(v));
}
#endif /** BYTEORDER_H_ @} */