Merge branch 'icmp'
Improves handling of ICMP[v6] traffic selectors that specify message type and code. Fixes #421.
This commit is contained in:
commit
3ea7165a27
|
@ -858,6 +858,14 @@ Instead of omitting either value
|
|||
can be used to the same effect, e.g.
|
||||
.BR leftsubnet=fec1::1[udp/%any],10.0.0.0/16[%any/53] .
|
||||
|
||||
If the protocol is
|
||||
.B icmp
|
||||
or
|
||||
.B ipv6-icmp
|
||||
the port is interpreted as ICMP message type if it is less than 256 or as type
|
||||
and code if it is greater or equal to 256, with the type in the most significant
|
||||
8 bits and the code in the least significant 8 bits.
|
||||
|
||||
The port value can alternatively take the value
|
||||
.B %opaque
|
||||
for RFC 4301 OPAQUE selectors, or a numerical range in the form
|
||||
|
|
|
@ -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,17 +290,42 @@ 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
|
||||
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
|
||||
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
|
||||
PLUTO_MY_ID=`printf "$PLUTO_MY_ID"`
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -870,6 +870,28 @@ static int lookup_algorithm(transform_type_t type, int ikev2)
|
|||
return alg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,9 @@
|
|||
* @defgroup jobs jobs
|
||||
* @ingroup processing
|
||||
*
|
||||
* @defgroup selectors selectors
|
||||
* @ingroup libstrongswan
|
||||
*
|
||||
* @defgroup threading threading
|
||||
* @ingroup libstrongswan
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
@ -193,6 +193,22 @@ static bool is_any(private_traffic_selector_t *this)
|
|||
return this->from_port == 0 && this->to_port == 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
@ -302,6 +318,13 @@ int traffic_selector_printf_hook(printf_hook_data_t *data,
|
|||
{
|
||||
struct servent *serv;
|
||||
|
||||
if (this->protocol == IPPROTO_ICMP ||
|
||||
this->protocol == IPPROTO_ICMPV6)
|
||||
{
|
||||
written += print_icmp(data, this->from_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
serv = getservbyport(htons(this->from_port), serv_proto);
|
||||
if (serv)
|
||||
{
|
||||
|
@ -312,10 +335,18 @@ int traffic_selector_printf_hook(printf_hook_data_t *data,
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
@ -213,9 +226,36 @@ struct traffic_selector_t {
|
|||
void (*destroy) (traffic_selector_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
Loading…
Reference in New Issue