aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/_updown/_updown.in39
-rw-r--r--src/libcharon/plugins/updown/updown_listener.c25
-rw-r--r--src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c24
-rw-r--r--src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c71
-rw-r--r--src/libstrongswan/library.h3
-rw-r--r--src/libstrongswan/selectors/traffic_selector.c47
-rw-r--r--src/libstrongswan/selectors/traffic_selector.h72
7 files changed, 237 insertions, 44 deletions
diff --git a/src/_updown/_updown.in b/src/_updown/_updown.in
index ca0398ab7..c68c23d8a 100644
--- a/src/_updown/_updown.in
+++ b/src/_updown/_updown.in
@@ -78,7 +78,8 @@
#
# PLUTO_MY_PORT
# is the UDP/TCP port to which the IPsec SA is
-# restricted on our side.
+# restricted on our side. For ICMP/ICMPv6 this contains the
+# message type, and PLUTO_PEER_PORT the message code.
#
# PLUTO_PEER
# is the IP address of our peer.
@@ -97,7 +98,8 @@
#
# PLUTO_PEER_PORT
# is the UDP/TCP port to which the IPsec SA is
-# restricted on the peer side.
+# restricted on the peer side. For ICMP/ICMPv6 this contains the
+# message code, and PLUTO_MY_PORT the message type.
#
# PLUTO_XAUTH_ID
# is an optional user ID employed by the XAUTH protocol
@@ -288,16 +290,41 @@ else
IPSEC_POLICY_OUT="$IPSEC_POLICY --dir out"
fi
+# use protocol specific options to set ports
+case "$PLUTO_MY_PROTOCOL" in
+1) # ICMP
+ ICMP_TYPE_OPTION="--icmp-type"
+ ;;
+58) # ICMPv6
+ ICMP_TYPE_OPTION="--icmpv6-type"
+ ;;
+*)
+ ;;
+esac
+
# are there port numbers?
if [ "$PLUTO_MY_PORT" != 0 ]
then
- S_MY_PORT="--sport $PLUTO_MY_PORT"
- D_MY_PORT="--dport $PLUTO_MY_PORT"
+ if [ -n "$ICMP_TYPE_OPTION" ]
+ then
+ S_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT"
+ D_MY_PORT="$ICMP_TYPE_OPTION $PLUTO_MY_PORT"
+ else
+ S_MY_PORT="--sport $PLUTO_MY_PORT"
+ D_MY_PORT="--dport $PLUTO_MY_PORT"
+ fi
fi
if [ "$PLUTO_PEER_PORT" != 0 ]
then
- S_PEER_PORT="--sport $PLUTO_PEER_PORT"
- D_PEER_PORT="--dport $PLUTO_PEER_PORT"
+ if [ -n "$ICMP_TYPE_OPTION" ]
+ then
+ # the syntax is --icmp[v6]-type type[/code], so add it to the existing option
+ S_MY_PORT="$S_MY_PORT/$PLUTO_PEER_PORT"
+ D_MY_PORT="$D_MY_PORT/$PLUTO_PEER_PORT"
+ else
+ S_PEER_PORT="--sport $PLUTO_PEER_PORT"
+ D_PEER_PORT="--dport $PLUTO_PEER_PORT"
+ fi
fi
# resolve octal escape sequences
diff --git a/src/libcharon/plugins/updown/updown_listener.c b/src/libcharon/plugins/updown/updown_listener.c
index 3c3994b81..12dbc88a0 100644
--- a/src/libcharon/plugins/updown/updown_listener.c
+++ b/src/libcharon/plugins/updown/updown_listener.c
@@ -174,6 +174,27 @@ static char *make_vip_vars(private_updown_listener_t *this, ike_sa_t *ike_sa)
return strdup(total);
}
+/**
+ * Determine proper values for port env variable
+ */
+static u_int16_t get_port(traffic_selector_t *me,
+ traffic_selector_t *other, bool local)
+{
+ switch (max(me->get_protocol(me), other->get_protocol(other)))
+ {
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ {
+ u_int16_t port = me->get_from_port(me);
+
+ port = max(port, other->get_from_port(other));
+ return local ? traffic_selector_icmp_type(port)
+ : traffic_selector_icmp_code(port);
+ }
+ }
+ return local ? me->get_from_port(me) : other->get_from_port(other);
+}
+
METHOD(listener_t, child_updown, bool,
private_updown_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
bool up)
@@ -341,11 +362,11 @@ METHOD(listener_t, child_updown, bool,
ike_sa->get_unique_id(ike_sa),
me, ike_sa->get_my_id(ike_sa),
my_client, my_client_mask,
- my_ts->get_from_port(my_ts),
+ get_port(my_ts, other_ts, TRUE),
my_ts->get_protocol(my_ts),
other, ike_sa->get_other_id(ike_sa),
other_client, other_client_mask,
- other_ts->get_from_port(other_ts),
+ get_port(my_ts, other_ts, FALSE),
other_ts->get_protocol(other_ts),
xauth,
virtual_ip,
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
index e23f22023..8352b9311 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2012 Tobias Brunner
+ * Copyright (C) 2006-2013 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2008 Andreas Steffen
* Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
@@ -744,6 +744,17 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src,
ts2subnet(src, &sel.saddr, &sel.prefixlen_s);
ts2ports(dst, &sel.dport, &sel.dport_mask);
ts2ports(src, &sel.sport, &sel.sport_mask);
+ if ((sel.proto == IPPROTO_ICMP || sel.proto == IPPROTO_ICMPV6) &&
+ (sel.dport || sel.sport))
+ {
+ /* the ICMP type is encoded in the most significant 8 bits and the ICMP
+ * code in the least significant 8 bits of the port. via XFRM we have
+ * to pass the ICMP type and code in the source and destination port
+ * fields, respectively. the port is in network byte order. */
+ u_int16_t port = max(sel.dport, sel.sport);
+ sel.sport = htons(port & 0xff);
+ sel.dport = htons(port >> 8);
+ }
sel.ifindex = 0;
sel.user = 0;
@@ -766,7 +777,7 @@ static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src)
prefixlen = sel->prefixlen_s;
if (sel->sport_mask)
{
- port = htons(sel->sport);
+ port = ntohs(sel->sport);
}
}
else
@@ -775,10 +786,15 @@ static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src)
prefixlen = sel->prefixlen_d;
if (sel->dport_mask)
{
- port = htons(sel->dport);
+ port = ntohs(sel->dport);
}
}
-
+ if (sel->proto == IPPROTO_ICMP || sel->proto == IPPROTO_ICMPV6)
+ { /* convert ICMP[v6] message type and code as supplied by the kernel in
+ * source and destination ports (both in network order) */
+ port = (sel->sport >> 8) | (sel->dport & 0xff00);
+ port = ntohs(port);
+ }
/* The Linux 2.6 kernel does not set the selector's family field,
* so as a kludge we additionally test the prefix length.
*/
diff --git a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
index feff3a753..98a6f81d5 100644
--- a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
+++ b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
@@ -871,6 +871,28 @@ static int lookup_algorithm(transform_type_t type, int ikev2)
}
/**
+ * Helper to set a port in a sockaddr_t, the port has to be in host order
+ */
+static void set_port(sockaddr_t *addr, u_int16_t port)
+{
+ switch (addr->sa_family)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in*)addr;
+ sin->sin_port = htons(port);
+ break;
+ }
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr;
+ sin6->sin6_port = htons(port);
+ break;
+ }
+ }
+}
+
+/**
* Copy a host_t as sockaddr_t to the given memory location.
* @return the number of bytes copied
*/
@@ -878,37 +900,38 @@ static size_t hostcpy(void *dest, host_t *host, bool include_port)
{
sockaddr_t *addr = host->get_sockaddr(host), *dest_addr = dest;
socklen_t *len = host->get_sockaddr_len(host);
- u_int16_t port = htons(host->get_port(host));
memcpy(dest, addr, *len);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
dest_addr->sa_len = *len;
#endif
- switch (dest_addr->sa_family)
+ if (!include_port)
{
- case AF_INET:
- {
- struct sockaddr_in *sin = dest;
- sin->sin_port = include_port ? port : 0;
- break;
- }
- case AF_INET6:
- {
- struct sockaddr_in6 *sin6 = dest;
- sin6->sin6_port = include_port ? port : 0;
- break;
- }
+ set_port(dest_addr, 0);
}
return *len;
}
/**
- * add a host behind an sadb_address extension
+ * Copy a host_t as sockaddr_t to the given memory location and map the port to
+ * ICMP/ICMPv6 message type/code as the Linux kernel expects it, that is, the
+ * type in the source and the code in the destination address.
+ * @return the number of bytes copied
*/
-static void host2ext(host_t *host, struct sadb_address *ext, bool include_port)
+static size_t hostcpy_icmp(void *dest, host_t *host, u_int16_t type)
{
- size_t len = hostcpy(ext + 1, host, include_port);
- ext->sadb_address_len = PFKEY_LEN(sizeof(*ext) + len);
+ size_t len;
+
+ len = hostcpy(dest, host, TRUE);
+ if (type == SADB_EXT_ADDRESS_SRC)
+ {
+ set_port(dest, traffic_selector_icmp_type(host->get_port(host)));
+ }
+ else
+ {
+ set_port(dest, traffic_selector_icmp_code(host->get_port(host)));
+ }
+ return len;
}
/**
@@ -918,10 +941,20 @@ static void add_addr_ext(struct sadb_msg *msg, host_t *host, u_int16_t type,
u_int8_t proto, u_int8_t prefixlen, bool include_port)
{
struct sadb_address *addr = (struct sadb_address*)PFKEY_EXT_ADD_NEXT(msg);
+ size_t len;
+
addr->sadb_address_exttype = type;
addr->sadb_address_proto = proto;
addr->sadb_address_prefixlen = prefixlen;
- host2ext(host, addr, include_port);
+ if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6)
+ {
+ len = hostcpy_icmp(addr + 1, host, type);
+ }
+ else
+ {
+ len = hostcpy(addr + 1, host, include_port);
+ }
+ addr->sadb_address_len = PFKEY_LEN(sizeof(*addr) + len);
PFKEY_EXT_ADD(msg, addr);
}
diff --git a/src/libstrongswan/library.h b/src/libstrongswan/library.h
index da2798014..e53cf09e2 100644
--- a/src/libstrongswan/library.h
+++ b/src/libstrongswan/library.h
@@ -70,6 +70,9 @@
* @defgroup jobs jobs
* @ingroup processing
*
+ * @defgroup selectors selectors
+ * @ingroup libstrongswan
+ *
* @defgroup threading threading
* @ingroup libstrongswan
*
diff --git a/src/libstrongswan/selectors/traffic_selector.c b/src/libstrongswan/selectors/traffic_selector.c
index 75a8717dd..b9d9b6556 100644
--- a/src/libstrongswan/selectors/traffic_selector.c
+++ b/src/libstrongswan/selectors/traffic_selector.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007-2009 Tobias Brunner
+ * Copyright (C) 2007-2013 Tobias Brunner
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -194,6 +194,22 @@ static bool is_any(private_traffic_selector_t *this)
}
/**
+ * Print ICMP/ICMPv6 type and code
+ */
+static int print_icmp(printf_hook_data_t *data, u_int16_t port)
+{
+ u_int8_t type, code;
+
+ type = traffic_selector_icmp_type(port);
+ code = traffic_selector_icmp_code(port);
+ if (code)
+ {
+ return print_in_hook(data, "%d(%d)", type, code);
+ }
+ return print_in_hook(data, "%d", type);
+}
+
+/**
* Described in header.
*/
int traffic_selector_printf_hook(printf_hook_data_t *data,
@@ -302,20 +318,35 @@ int traffic_selector_printf_hook(printf_hook_data_t *data,
{
struct servent *serv;
- serv = getservbyport(htons(this->from_port), serv_proto);
- if (serv)
+ if (this->protocol == IPPROTO_ICMP ||
+ this->protocol == IPPROTO_ICMPV6)
{
- written += print_in_hook(data, "%s", serv->s_name);
+ written += print_icmp(data, this->from_port);
}
else
{
- written += print_in_hook(data, "%d", this->from_port);
+ serv = getservbyport(htons(this->from_port), serv_proto);
+ if (serv)
+ {
+ written += print_in_hook(data, "%s", serv->s_name);
+ }
+ else
+ {
+ written += print_in_hook(data, "%d", this->from_port);
+ }
}
}
else if (is_opaque(this))
{
written += print_in_hook(data, "OPAQUE");
}
+ else if (this->protocol == IPPROTO_ICMP ||
+ this->protocol == IPPROTO_ICMPV6)
+ {
+ written += print_icmp(data, this->from_port);
+ written += print_in_hook(data, "-");
+ written += print_icmp(data, this->to_port);
+ }
else
{
written += print_in_hook(data, "%d-%d",
@@ -910,6 +941,10 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol,
.protocol = protocol,
.type = type,
);
-
+ if (protocol == IPPROTO_ICMP || protocol == IPPROTO_ICMPV6)
+ {
+ this->from_port = from_port < 256 ? from_port << 8 : from_port;
+ this->to_port = to_port < 256 ? to_port << 8 : to_port;
+ }
return this;
}
diff --git a/src/libstrongswan/selectors/traffic_selector.h b/src/libstrongswan/selectors/traffic_selector.h
index 0de358b99..ab6813acc 100644
--- a/src/libstrongswan/selectors/traffic_selector.h
+++ b/src/libstrongswan/selectors/traffic_selector.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Tobias Brunner
+ * Copyright (C) 2007-2013 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -17,7 +17,7 @@
/**
* @defgroup traffic_selector traffic_selector
- * @{ @ingroup config
+ * @{ @ingroup selectors
*/
#ifndef TRAFFIC_SELECTOR_H_
@@ -62,7 +62,12 @@ extern enum_name_t *ts_type_name;
* Object representing a traffic selector entry.
*
* A traffic selector defines an range of addresses
- * and a range of ports. IPv6 is not fully supported yet.
+ * and a range of ports.
+ *
+ * If the protocol is ICMP or ICMPv6 the ICMP type and code are stored in the
+ * port field as follows: The message type is placed in the most significant
+ * 8 bits and the code in the least significant 8 bits. Utility functions are
+ * provided to extract the individual values.
*/
struct traffic_selector_t {
@@ -109,7 +114,11 @@ struct traffic_selector_t {
* Get starting port of this ts.
*
* Port is in host order, since the parser converts it.
- * Size depends on protocol.
+ *
+ * If the protocol is ICMP/ICMPv6 the ICMP type and code are stored in this
+ * field as follows: The message type is placed in the most significant
+ * 8 bits and the code in the least significant 8 bits. Use the utility
+ * functions to extract them.
*
* @return port
*/
@@ -119,7 +128,11 @@ struct traffic_selector_t {
* Get ending port of this ts.
*
* Port is in host order, since the parser converts it.
- * Size depends on protocol.
+ *
+ * If the protocol is ICMP/ICMPv6 the ICMP type and code are stored in this
+ * field as follows: The message type is placed in the most significant
+ * 8 bits and the code in the least significant 8 bits. Use the utility
+ * functions to extract them.
*
* @return port
*/
@@ -214,8 +227,35 @@ struct traffic_selector_t {
};
/**
+ * Extract the ICMP/ICMPv6 message type from a port in host order
+ *
+ * @param port port number in host order
+ * @return ICMP/ICMPv6 message type
+ */
+static inline u_int8_t traffic_selector_icmp_type(u_int16_t port)
+{
+ return port >> 8;
+}
+
+/**
+ * Extract the ICMP/ICMPv6 message code from a port in host order
+ *
+ * @param port port number in host order
+ * @return ICMP/ICMPv6 message code
+ */
+static inline u_int8_t traffic_selector_icmp_code(u_int16_t port)
+{
+ return port & 0xff;
+}
+
+/**
* Create a new traffic selector using human readable params.
*
+ * If protocol is ICMP or ICMPv6 the ports are interpreted as follows: If they
+ * are less than 256 the value is assumed to be a message type, if they are
+ * greater or equal to 256 they are assumed to be type and code as defined
+ * for traffic_selector_t.
+ *
* @param protocol protocol for this ts, such as TCP or UDP
* @param type type of following addresses, such as TS_IPV4_ADDR_RANGE
* @param from_addr start of address range as string
@@ -236,6 +276,11 @@ traffic_selector_t *traffic_selector_create_from_string(
/**
* Create a traffic selector from a CIDR string.
*
+ * If protocol is ICMP or ICMPv6 the ports are interpreted as follows: If they
+ * are less than 256 the value is assumed to be a message type, if they are
+ * greater or equal to 256 they are assumed to be type and code as defined
+ * for traffic_selector_t.
+ *
* @param string CIDR string, such as 10.1.0.0/16
* @param protocol protocol for this ts, such as TCP or UDP
* @param from_port start of allowed port range
@@ -253,6 +298,11 @@ traffic_selector_t *traffic_selector_create_from_cidr(
* But the parser gives us this data in this format, so we
* don't have to convert twice.
*
+ * If protocol is ICMP or ICMPv6 the ports are interpreted as follows: If they
+ * are less than 256 the value is assumed to be a message type, if they are
+ * greater or equal to 256 they are assumed to be type and code as defined
+ * for traffic_selector_t.
+ *
* @param protocol protocol for this ts, such as TCP or UDP
* @param type type of following addresses, such as TS_IPV4_ADDR_RANGE
* @param from_address start of address range, network order
@@ -284,8 +334,12 @@ traffic_selector_t *traffic_selector_create_from_rfc3779_format(ts_type_t type,
* is sufficient. This constructor creates a traffic selector for
* all protocols, all ports and the address range specified by the
* subnet.
- * Additionally, a protocol and a port may be specified. Port ranges
- * are not supported via this constructor.
+ * Additionally, a protocol and ports may be specified.
+ *
+ * If protocol is ICMP or ICMPv6 the ports are interpreted as follows: If they
+ * are less than 256 the value is assumed to be a message type, if they are
+ * greater or equal to 256 they are assumed to be type and code as defined
+ * for traffic_selector_t.
*
* @param net subnet to use
* @param netbits size of the subnet, as used in e.g. 192.168.0.0/24 notation
@@ -307,6 +361,10 @@ traffic_selector_t *traffic_selector_create_from_subnet(
* created at runtime using the external/virtual IP. Using this constructor,
* a call to set_address() sets this traffic selector to the supplied host.
*
+ * If protocol is ICMP or ICMPv6 the ports are interpreted as follows: If they
+ * are less than 256 the value is assumed to be a message type, if they are
+ * greater or equal to 256 they are assumed to be type and code as defined
+ * for traffic_selector_t.
*
* @param protocol upper layer protocl to allow
* @param from_port start of allowed port range