diff options
Diffstat (limited to 'src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c')
-rw-r--r-- | src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 275aa6cb2..6d9d63a98 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2006-2015 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi - * Copyright (C) 2008 Andreas Steffen + * Copyright (C) 2008-2016 Andreas Steffen * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -702,15 +702,13 @@ static void ts2subnet(traffic_selector_t* ts, static void ts2ports(traffic_selector_t* ts, u_int16_t *port, u_int16_t *mask) { - /* Linux does not seem to accept complex portmasks. Only - * any or a specific port is allowed. We set to any, if we have - * a port range, or to a specific, if we have one port only. - */ - u_int16_t from, to; + uint16_t from, to, bitmask; + int bit; from = ts->get_from_port(ts); to = ts->get_to_port(ts); + /* Quick check for a single port */ if (from == to) { *port = htons(from); @@ -718,9 +716,23 @@ static void ts2ports(traffic_selector_t* ts, } else { - *port = 0; + /* Compute the port mask for port ranges */ *mask = 0; + + for (bit = 15; bit >= 0; bit--) + { + bitmask = 1 << bit; + + if ((bitmask & from) != (bitmask & to)) + { + *port = htons(from & *mask); + *mask = htons(*mask); + return; + } + *mask |= bitmask; + } } + return; } /** |