| File: | programs/pluto/kernel_xfrm.c |
| Warning: | line 1617, column 3 Value stored to 'attr' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* |
| 2 | * netlink interface to the kernel's IPsec mechanism |
| 3 | * |
| 4 | * Copyright (C) 2003-2008 Herbert Xu |
| 5 | * Copyright (C) 2006-2008 Michael Richardson <mcr@xelerance.com> |
| 6 | * Copyright (C) 2006 Ken Bantoft <ken@xelerance.com> |
| 7 | * Copyright (C) 2007 Bart Trojanowski <bart@jukie.net> |
| 8 | * Copyright (C) 2007 Ilia Sotnikov |
| 9 | * Copyright (C) 2009 Carsten Schlote <c.schlote@konzeptpark.de> |
| 10 | * Copyright (C) 2008 Andreas Steffen |
| 11 | * Copyright (C) 2008 Neil Horman <nhorman@redhat.com> |
| 12 | * Copyright (C) 2008-2010 David McCullough <david_mccullough@securecomputing.com> |
| 13 | * Copyright (C) 2006-2010 Paul Wouters <paul@xelerance.com> |
| 14 | * Copyright (C) 2010-2017 Tuomo Soini <tis@foobar.fi> |
| 15 | * Copyright (C) 2010 Mika Ilmaranta <ilmis@foobar.fi> |
| 16 | * Copyright (C) 2010 Roman Hoog Antink <rha@open.ch> |
| 17 | * Copyright (C) 2010 D. Hugh Redelmeier |
| 18 | * Copyright (C) 2012 Avesh Agarwal <avagarwa@redhat.com> |
| 19 | * Copyright (C) 2013 Kim B. Heino <b@bbbs.net> |
| 20 | * Copyright (C) 2012-2013 Paul Wouters <paul@libreswan.org> |
| 21 | * Copyright (C) 2013-2019 D. Hugh Redelmeier <hugh@mimosa.com> |
| 22 | * Copyright (C) 2017 Richard Guy Briggs <rgb@tricolour.ca> |
| 23 | * Copyright (C) 2016-2019 Andrew Cagney <cagney@gnu.org> |
| 24 | * Copyright (C) 2019 Paul Wouters <pwouters@redhat.com> |
| 25 | * Copyright (C) 2019 Antony Antony <antony@phenome.org> |
| 26 | * Copyright (C) 2017 Mayank Totale <mtotale@gmail.com> |
| 27 | * |
| 28 | * This program is free software; you can redistribute it and/or modify it |
| 29 | * under the terms of the GNU General Public License as published by the |
| 30 | * Free Software Foundation; either version 2 of the License, or (at your |
| 31 | * option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>. |
| 32 | * |
| 33 | * This program is distributed in the hope that it will be useful, but |
| 34 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| 35 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 36 | * for more details. |
| 37 | */ |
| 38 | |
| 39 | #include <errno(*__errno_location ()).h> |
| 40 | #include <fcntl.h> |
| 41 | #include <string.h> |
| 42 | |
| 43 | #include <sys/socket.h> |
| 44 | |
| 45 | #include <sys/types.h> |
| 46 | #include <sys/ioctl.h> |
| 47 | #include <stdint.h> |
| 48 | #include <linux1/ethtool.h> |
| 49 | #include <linux1/sockios.h> |
| 50 | |
| 51 | #include <linux1/udp.h> /* for TCP_ENCAP_ESPINTCP and UDP_ENCAP_ESPINUDP */ |
| 52 | #ifndef TCP_ENCAP_ESPINTCP7 |
| 53 | #define TCP_ENCAP_ESPINTCP7 7 |
| 54 | #endif |
| 55 | |
| 56 | #include <unistd.h> |
| 57 | #include <sys/stat.h> |
| 58 | |
| 59 | #include <linux1/rtnetlink.h> |
| 60 | #include <linux1/if_addr.h> |
| 61 | #include <linux1/if_link.h> |
| 62 | |
| 63 | /* work around weird combo's of glibc and kernel header conflicts */ |
| 64 | #ifndef GLIBC_KERN_FLIP_HEADERS |
| 65 | # include "linux/xfrm.h" /* local (if configured) or system copy */ |
| 66 | # include "libreswan.h" |
| 67 | #else |
| 68 | # include "libreswan.h" |
| 69 | # include "linux/xfrm.h" /* local (if configured) or system copy */ |
| 70 | #endif |
| 71 | #include "lsw-pfkeyv2.h" /* for SADB_X_CALG_DEFLATE et.al., grrr */ |
| 72 | |
| 73 | #include "sysdep.h" |
| 74 | #include "socketwrapper.h" |
| 75 | #include "constants.h" |
| 76 | #include "defs.h" |
| 77 | #include "id.h" |
| 78 | #include "state.h" |
| 79 | #include "connections.h" |
| 80 | #include "kernel.h" |
| 81 | #include "server.h" |
| 82 | #include "nat_traversal.h" |
| 83 | #include "state.h" |
| 84 | #include "kernel_xfrm.h" |
| 85 | #include "log.h" |
| 86 | #include "whack.h" /* for RC_LOG_SERIOUS */ |
| 87 | #include "kernel_alg.h" |
| 88 | #include "ike_alg.h" |
| 89 | #include "ike_alg_integ.h" |
| 90 | #include "ike_alg_encrypt.h" |
| 91 | #include "ip_address.h" |
| 92 | #include "ip_info.h" |
| 93 | # include "kernel_xfrm_interface.h" |
| 94 | #include "iface.h" |
| 95 | #include "ip_selector.h" |
| 96 | #include "ip_encap.h" |
| 97 | |
| 98 | /* required for Linux 2.6.26 kernel and later */ |
| 99 | #ifndef XFRM_STATE_AF_UNSPEC32 |
| 100 | #define XFRM_STATE_AF_UNSPEC32 32 |
| 101 | #endif |
| 102 | |
| 103 | static int nl_send_fd = NULL_FD(-1); /* to send to NETLINK_XFRM */ |
| 104 | static int nl_xfrm_fd = NULL_FD(-1); /* listen to NETLINK_XFRM broadcast */ |
| 105 | static int nl_route_fd = NULL_FD(-1); /* listen to NETLINK_ROUTE broadcast */ |
| 106 | |
| 107 | static int kernel_mobike_supprt ; /* kernel xfrm_migrate_support */ |
| 108 | |
| 109 | #define NE(x) { x, #x } /* Name Entry -- shorthand for sparse_names */ |
| 110 | |
| 111 | enum { |
| 112 | IPSEC_POLICY_DISCARD = 0, |
| 113 | IPSEC_POLICY_NONE = 1, |
| 114 | IPSEC_POLICY_IPSEC = 2, |
| 115 | IPSEC_POLICY_ENTRUST = 3, |
| 116 | IPSEC_POLICY_BYPASS = 4 |
| 117 | }; |
| 118 | |
| 119 | static sparse_names xfrm_type_names = { |
| 120 | NE(NLMSG_NOOP0x1), |
| 121 | NE(NLMSG_ERROR0x2), |
| 122 | NE(NLMSG_DONE0x3), |
| 123 | NE(NLMSG_OVERRUN0x4), |
| 124 | |
| 125 | NE(XFRM_MSG_NEWSAXFRM_MSG_NEWSA), |
| 126 | NE(XFRM_MSG_DELSAXFRM_MSG_DELSA), |
| 127 | NE(XFRM_MSG_GETSAXFRM_MSG_GETSA), |
| 128 | |
| 129 | NE(XFRM_MSG_NEWPOLICYXFRM_MSG_NEWPOLICY), |
| 130 | NE(XFRM_MSG_DELPOLICYXFRM_MSG_DELPOLICY), |
| 131 | NE(XFRM_MSG_GETPOLICYXFRM_MSG_GETPOLICY), |
| 132 | |
| 133 | NE(XFRM_MSG_ALLOCSPIXFRM_MSG_ALLOCSPI), |
| 134 | NE(XFRM_MSG_ACQUIREXFRM_MSG_ACQUIRE), |
| 135 | NE(XFRM_MSG_EXPIREXFRM_MSG_EXPIRE), |
| 136 | |
| 137 | NE(XFRM_MSG_UPDPOLICYXFRM_MSG_UPDPOLICY), |
| 138 | NE(XFRM_MSG_UPDSAXFRM_MSG_UPDSA), |
| 139 | |
| 140 | NE(XFRM_MSG_POLEXPIREXFRM_MSG_POLEXPIRE), |
| 141 | |
| 142 | NE(XFRM_MSG_MAX(__XFRM_MSG_MAX - 1)), |
| 143 | |
| 144 | { 0, sparse_end } |
| 145 | }; |
| 146 | |
| 147 | static sparse_names rtm_type_names = { |
| 148 | NE(RTM_BASERTM_BASE), |
| 149 | NE(RTM_NEWADDRRTM_NEWADDR), |
| 150 | NE(RTM_DELADDRRTM_DELADDR), |
| 151 | NE(RTM_MAX(((__RTM_MAX + 3) & ~3) - 1)), |
| 152 | { 0, sparse_end } |
| 153 | }; |
| 154 | #undef NE |
| 155 | |
| 156 | #define RTA_TAIL(rta)((struct rtattr *) (((void *) (rta)) + ( (((rta)->rta_len) +4U -1) & ~(4U -1) ))) ((struct rtattr *) (((void *) (rta)) + \ |
| 157 | RTA_ALIGN((rta)->rta_len)( (((rta)->rta_len)+4U -1) & ~(4U -1) ))) |
| 158 | |
| 159 | #define NLMSG_TAIL(nmsg)((struct rtattr *) (((void *) (nmsg)) + ( (((nmsg)->nlmsg_len )+4U -1) & ~(4U -1) ))) \ |
| 160 | ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)( (((nmsg)->nlmsg_len)+4U -1) & ~(4U -1) ))) |
| 161 | |
| 162 | /* Compress Algs */ |
| 163 | static sparse_names calg_list = { |
| 164 | { SADB_X_CALG_DEFLATE2, "deflate" }, |
| 165 | { SADB_X_CALG_LZS3, "lzs" }, |
| 166 | { SADB_X_CALG_LZJH4, "lzjh" }, |
| 167 | { 0, sparse_end } |
| 168 | }; |
| 169 | |
| 170 | /* |
| 171 | * xfrm2ip - Take an xfrm and convert to an IP address |
| 172 | * |
| 173 | * @param xaddr xfrm_address_t |
| 174 | * @param addr ip_address IPv[46] Address from addr is copied here. |
| 175 | */ |
| 176 | static void xfrm2ip(const xfrm_address_t *xaddr, ip_address *addr, const sa_family_t family) |
| 177 | { |
| 178 | shunk_t x = THING_AS_SHUNK(*xaddr)shunk2(&(*xaddr), sizeof(*xaddr)); |
| 179 | |
| 180 | const struct ip_info *afi = aftoinfo(family); |
| 181 | passert(afi != NULL){ _Bool assertion__ = afi != ((void*)0); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "kernel_xfrm.c" , . line = 181}, "%s", "afi != NULL"); } }; |
| 182 | |
| 183 | *addr = afi->any_address; /* initialize dst type and zero */ |
| 184 | chunk_t a = address_as_chunk(addr); |
| 185 | |
| 186 | /* a = x */ |
| 187 | passert(x.len >= a.len){ _Bool assertion__ = x.len >= a.len; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "kernel_xfrm.c" , . line = 187}, "%s", "x.len >= a.len"); } }; |
| 188 | memcpy(a.ptr, x.ptr, a.len); |
| 189 | } |
| 190 | |
| 191 | /* |
| 192 | * xfrm_from-address - Take an IP address and convert to an xfrm. |
| 193 | */ |
| 194 | static xfrm_address_t xfrm_from_address(const ip_address *addr) |
| 195 | { |
| 196 | xfrm_address_t xaddr; |
| 197 | zero(&xaddr)memset((&xaddr), '\0', sizeof(*(&xaddr))); |
| 198 | |
| 199 | shunk_t a = address_as_shunk(addr); |
| 200 | /* .len == ipv6 len */ |
| 201 | chunk_t x = THING_AS_CHUNK(xaddr)chunk2(&(xaddr), sizeof(xaddr)); |
| 202 | /* x = a */ |
| 203 | passert(x.len >= a.len){ _Bool assertion__ = x.len >= a.len; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "kernel_xfrm.c" , . line = 203}, "%s", "x.len >= a.len"); } }; |
| 204 | memcpy(x.ptr, a.ptr, a.len); |
| 205 | return xaddr; |
| 206 | } |
| 207 | |
| 208 | #define SELECTOR_TO_XFRM(CLIENT, REQ, L){ ip_selector client_ = *(CLIENT); ip_address address = selector_prefix (&client_); (REQ).Laddr = xfrm_from_address(&address) ; (REQ).prefixlen_L = selector_maskbits(&client_); (REQ). Lport = nport(selector_port(&client_)); } \ |
| 209 | { \ |
| 210 | ip_selector client_ = *(CLIENT); \ |
| 211 | ip_address address = selector_prefix(&client_); \ |
| 212 | (REQ).L##addr = xfrm_from_address(&address); \ |
| 213 | (REQ).prefixlen_##L = selector_maskbits(&client_); \ |
| 214 | (REQ).L##port = nport(selector_port(&client_)); \ |
| 215 | } |
| 216 | |
| 217 | static void init_netlink_route_fd(void) |
| 218 | { |
| 219 | nl_route_fd = safe_socket(AF_NETLINK16, SOCK_RAWSOCK_RAW, NETLINK_ROUTE0); |
| 220 | if (nl_route_fd < 0) { |
| 221 | FATAL_ERRNO(errno, "socket()"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "FATAL ERROR: "); jam_cur_prefix(buf ); jam(buf, "socket()"". ""Errno %d: %s", (e_), strerror(e_)) ; jambuf_to_error_stream(buf); } libreswan_exit(PLUTO_EXIT_FAIL ); }; |
| 222 | } |
| 223 | |
| 224 | if (fcntl(nl_route_fd, F_SETFD2, FD_CLOEXEC1) != 0) { |
| 225 | FATAL_ERRNO(errno, "fcntl(FD_CLOEXEC) for bcast NETLINK_ROUTE "){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "FATAL ERROR: "); jam_cur_prefix(buf ); jam(buf, "fcntl(FD_CLOEXEC) for bcast NETLINK_ROUTE "". ""Errno %d: %s" , (e_), strerror(e_)); jambuf_to_error_stream(buf); } libreswan_exit (PLUTO_EXIT_FAIL); }; |
| 226 | } |
| 227 | |
| 228 | if (fcntl(nl_route_fd, F_SETFL4, O_NONBLOCK04000) != 0) { |
| 229 | FATAL_ERRNO(errno, "fcntl(O_NONBLOCK) for bcast NETLINK_ROUTE"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "FATAL ERROR: "); jam_cur_prefix(buf ); jam(buf, "fcntl(O_NONBLOCK) for bcast NETLINK_ROUTE"". ""Errno %d: %s" , (e_), strerror(e_)); jambuf_to_error_stream(buf); } libreswan_exit (PLUTO_EXIT_FAIL); }; |
| 230 | } |
| 231 | |
| 232 | struct sockaddr_nl addr = { |
| 233 | .nl_family = AF_NETLINK16, |
| 234 | .nl_pid = getpid(), |
| 235 | .nl_groups = RTMGRP_IPV4_IFADDR0x10 | RTMGRP_IPV6_IFADDR0x100 | |
| 236 | RTMGRP_IPV4_ROUTE0x40 | RTMGRP_IPV6_ROUTE0x400 | RTMGRP_LINK1, |
| 237 | }; |
| 238 | |
| 239 | if (bind(nl_route_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { |
| 240 | FATAL_ERRNO(errno, "Failed to bind NETLINK_ROUTE bcast socket - Perhaps kernel was not compiled with CONFIG_XFRM"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "FATAL ERROR: "); jam_cur_prefix(buf ); jam(buf, "Failed to bind NETLINK_ROUTE bcast socket - Perhaps kernel was not compiled with CONFIG_XFRM" ". ""Errno %d: %s", (e_), strerror(e_)); jambuf_to_error_stream (buf); } libreswan_exit(PLUTO_EXIT_FAIL); }; |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | |
| 245 | /* |
| 246 | * init_netlink - Initialize the netlink inferface. Opens the sockets and |
| 247 | * then binds to the broadcast socket. |
| 248 | */ |
| 249 | static void init_netlink(void) |
| 250 | { |
| 251 | struct sockaddr_nl addr; |
| 252 | |
| 253 | nl_send_fd = safe_socket(AF_NETLINK16, SOCK_DGRAMSOCK_DGRAM, NETLINK_XFRM6); |
| 254 | |
| 255 | if (nl_send_fd < 0) { |
| 256 | FATAL_ERRNO(errno, "socket() in init_netlink()"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "FATAL ERROR: "); jam_cur_prefix(buf ); jam(buf, "socket() in init_netlink()"". ""Errno %d: %s", ( e_), strerror(e_)); jambuf_to_error_stream(buf); } libreswan_exit (PLUTO_EXIT_FAIL); }; |
| 257 | } |
| 258 | |
| 259 | if (fcntl(nl_send_fd, F_SETFD2, FD_CLOEXEC1) != 0) { |
| 260 | FATAL_ERRNO(errno, "fcntl(FD_CLOEXEC) in init_netlink()"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "FATAL ERROR: "); jam_cur_prefix(buf ); jam(buf, "fcntl(FD_CLOEXEC) in init_netlink()"". ""Errno %d: %s" , (e_), strerror(e_)); jambuf_to_error_stream(buf); } libreswan_exit (PLUTO_EXIT_FAIL); }; |
| 261 | } |
| 262 | |
| 263 | nl_xfrm_fd = safe_socket(AF_NETLINK16, SOCK_DGRAMSOCK_DGRAM, NETLINK_XFRM6); |
| 264 | if (nl_xfrm_fd < 0) { |
| 265 | FATAL_ERRNO(errno, "socket() for bcast in init_netlink()"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "FATAL ERROR: "); jam_cur_prefix(buf ); jam(buf, "socket() for bcast in init_netlink()"". ""Errno %d: %s" , (e_), strerror(e_)); jambuf_to_error_stream(buf); } libreswan_exit (PLUTO_EXIT_FAIL); }; |
| 266 | } |
| 267 | |
| 268 | if (fcntl(nl_xfrm_fd, F_SETFD2, FD_CLOEXEC1) != 0) { |
| 269 | FATAL_ERRNO(errno, "fcntl(FD_CLOEXEC) for bcast in init_netlink()"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "FATAL ERROR: "); jam_cur_prefix(buf ); jam(buf, "fcntl(FD_CLOEXEC) for bcast in init_netlink()"". " "Errno %d: %s", (e_), strerror(e_)); jambuf_to_error_stream(buf ); } libreswan_exit(PLUTO_EXIT_FAIL); }; |
| 270 | } |
| 271 | |
| 272 | if (fcntl(nl_xfrm_fd, F_SETFL4, O_NONBLOCK04000) != 0) { |
| 273 | FATAL_ERRNO(errno, "fcntl(O_NONBLOCK) for bcast in init_netlink()"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "FATAL ERROR: "); jam_cur_prefix(buf ); jam(buf, "fcntl(O_NONBLOCK) for bcast in init_netlink()"". " "Errno %d: %s", (e_), strerror(e_)); jambuf_to_error_stream(buf ); } libreswan_exit(PLUTO_EXIT_FAIL); }; |
| 274 | } |
| 275 | |
| 276 | addr.nl_family = AF_NETLINK16; |
| 277 | addr.nl_pid = getpid(); |
| 278 | addr.nl_pad = 0; /* make coverity happy */ |
| 279 | addr.nl_groups = XFRMGRP_ACQUIRE1 | XFRMGRP_EXPIRE2; |
| 280 | if (bind(nl_xfrm_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { |
| 281 | FATAL_ERRNO(errno, "Failed to bind bcast socket in init_netlink() - Perhaps kernel was not compiled with CONFIG_XFRM"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "FATAL ERROR: "); jam_cur_prefix(buf ); jam(buf, "Failed to bind bcast socket in init_netlink() - Perhaps kernel was not compiled with CONFIG_XFRM" ". ""Errno %d: %s", (e_), strerror(e_)); jambuf_to_error_stream (buf); } libreswan_exit(PLUTO_EXIT_FAIL); }; |
| 282 | } |
| 283 | |
| 284 | init_netlink_route_fd(); |
| 285 | |
| 286 | /* |
| 287 | * pfkey_register_response() does not register an entry for |
| 288 | * msg->sadb_msg_satype=10 to indicate IPCOMP, so we override |
| 289 | * detection here. Seems the PF_KEY API in Linux with netkey |
| 290 | * is a joke that should be abandoned for a "linux children" |
| 291 | * native netlink query/response |
| 292 | * |
| 293 | * XXX: Given KLIPS defines K_SADB_X_SATYPE_COMP=9, and |
| 294 | * IPIP=10 which conflicts with the aboe, that might be the |
| 295 | * source of the problem? |
| 296 | */ |
| 297 | can_do_IPcomp = TRUE1; |
| 298 | |
| 299 | /* |
| 300 | * Just assume any algorithm with a NETLINK_XFRM name works. |
| 301 | * |
| 302 | * Kind of lame since pluto should query the kernel for what |
| 303 | * it supports. OTOH, the query might happen before the |
| 304 | * crypto module gets loaded. |
| 305 | */ |
| 306 | dbg("Hard-wiring algorithms"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Hard-wiring algorithms"); } }; |
| 307 | for (const struct encrypt_desc **algp = next_encrypt_desc(NULL((void*)0)); |
| 308 | algp != NULL((void*)0); algp = next_encrypt_desc(algp)) { |
| 309 | const struct encrypt_desc *alg = *algp; |
| 310 | if (alg->encrypt_netlink_xfrm_name != NULL((void*)0)) { |
| 311 | kernel_encrypt_add(alg); |
| 312 | } |
| 313 | } |
| 314 | for (const struct integ_desc **algp = next_integ_desc(NULL((void*)0)); |
| 315 | algp != NULL((void*)0); algp = next_integ_desc(algp)) { |
| 316 | const struct integ_desc *alg = *algp; |
| 317 | if (alg->integ_netlink_xfrm_name != NULL((void*)0)) { |
| 318 | kernel_integ_add(alg); |
| 319 | } |
| 320 | } |
| 321 | } |
| 322 | |
| 323 | struct nlm_resp { |
| 324 | struct nlmsghdr n; |
| 325 | union { |
| 326 | struct nlmsgerr e; |
| 327 | struct xfrm_userpolicy_info pol; /* netlink_policy_expire */ |
| 328 | struct xfrm_usersa_info sa; /* netlink_get_spi */ |
| 329 | struct xfrm_usersa_info info; /* netlink_get_sa */ |
| 330 | char data[MAX_NETLINK_DATA_SIZE8192]; |
| 331 | } u; |
| 332 | }; |
| 333 | |
| 334 | /* |
| 335 | * send_netlink_msg |
| 336 | * |
| 337 | * @param hdr - Data to be sent. |
| 338 | * @param expected_resp_type - type of message expected from netlink |
| 339 | * @param rbuf - Return Buffer - contains data returned from the send. |
| 340 | * @param description - String - user friendly description of what is |
| 341 | * being attempted. Used for diagnostics |
| 342 | * @param text_said - String |
| 343 | * @return bool True if the message was successfully sent. |
| 344 | */ |
| 345 | static int netlink_errno; /* side-channel result of send_netlink_msg */ |
| 346 | |
| 347 | static bool_Bool send_netlink_msg(struct nlmsghdr *hdr, |
| 348 | unsigned expected_resp_type, struct nlm_resp *rbuf, |
| 349 | const char *description, const char *text_said) |
| 350 | { |
| 351 | struct nlm_resp rsp; |
| 352 | size_t len; |
| 353 | ssize_t r; |
| 354 | struct sockaddr_nl addr; |
| 355 | static uint32_t seq = 0; /* STATIC */ |
| 356 | |
| 357 | netlink_errno = 0; |
| 358 | |
| 359 | hdr->nlmsg_seq = ++seq; |
| 360 | len = hdr->nlmsg_len; |
| 361 | do { |
| 362 | r = write(nl_send_fd, hdr, len); |
| 363 | } while (r < 0 && errno(*__errno_location ()) == EINTR4); |
| 364 | if (r < 0) { |
| 365 | LOG_ERRNO(errno, "netlink write() of %s message for %s %s failed",{ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "netlink write() of %s message for %s %s failed", sparse_val_show (xfrm_type_names, hdr->nlmsg_type), description, text_said ); jam_string(buf, "."); jam(buf, " ""Errno %d: %s", (e_), strerror (e_)); jambuf_to_error_stream(buf); } } |
| 366 | sparse_val_show(xfrm_type_names,{ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "netlink write() of %s message for %s %s failed", sparse_val_show (xfrm_type_names, hdr->nlmsg_type), description, text_said ); jam_string(buf, "."); jam(buf, " ""Errno %d: %s", (e_), strerror (e_)); jambuf_to_error_stream(buf); } } |
| 367 | hdr->nlmsg_type),{ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "netlink write() of %s message for %s %s failed", sparse_val_show (xfrm_type_names, hdr->nlmsg_type), description, text_said ); jam_string(buf, "."); jam(buf, " ""Errno %d: %s", (e_), strerror (e_)); jambuf_to_error_stream(buf); } } |
| 368 | description, text_said){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "netlink write() of %s message for %s %s failed", sparse_val_show (xfrm_type_names, hdr->nlmsg_type), description, text_said ); jam_string(buf, "."); jam(buf, " ""Errno %d: %s", (e_), strerror (e_)); jambuf_to_error_stream(buf); } }; |
| 369 | return FALSE0; |
| 370 | } else if ((size_t)r != len) { |
| 371 | loglog(RC_LOG_SERIOUS, |
| 372 | "ERROR: netlink write() of %s message for %s %s truncated: %zd instead of %zu", |
| 373 | sparse_val_show(xfrm_type_names, hdr->nlmsg_type), |
| 374 | description, text_said, r, len); |
| 375 | return FALSE0; |
| 376 | } |
| 377 | |
| 378 | for (;;) { |
| 379 | socklen_t alen = sizeof(addr); |
| 380 | |
| 381 | r = recvfrom(nl_send_fd, &rsp, sizeof(rsp), 0, |
| 382 | (struct sockaddr *)&addr, &alen); |
| 383 | if (r < 0) { |
| 384 | if (errno(*__errno_location ()) == EINTR4) |
| 385 | continue; |
| 386 | netlink_errno = errno(*__errno_location ()); |
| 387 | LOG_ERRNO(errno,{ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "netlink recvfrom() of response to our %s message for %s %s failed" , sparse_val_show(xfrm_type_names, hdr->nlmsg_type), description , text_said); jam_string(buf, "."); jam(buf, " ""Errno %d: %s" , (e_), strerror(e_)); jambuf_to_error_stream(buf); } } |
| 388 | "netlink recvfrom() of response to our %s message for %s %s failed",{ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "netlink recvfrom() of response to our %s message for %s %s failed" , sparse_val_show(xfrm_type_names, hdr->nlmsg_type), description , text_said); jam_string(buf, "."); jam(buf, " ""Errno %d: %s" , (e_), strerror(e_)); jambuf_to_error_stream(buf); } } |
| 389 | sparse_val_show(xfrm_type_names,{ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "netlink recvfrom() of response to our %s message for %s %s failed" , sparse_val_show(xfrm_type_names, hdr->nlmsg_type), description , text_said); jam_string(buf, "."); jam(buf, " ""Errno %d: %s" , (e_), strerror(e_)); jambuf_to_error_stream(buf); } } |
| 390 | hdr->nlmsg_type),{ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "netlink recvfrom() of response to our %s message for %s %s failed" , sparse_val_show(xfrm_type_names, hdr->nlmsg_type), description , text_said); jam_string(buf, "."); jam(buf, " ""Errno %d: %s" , (e_), strerror(e_)); jambuf_to_error_stream(buf); } } |
| 391 | description, text_said){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "netlink recvfrom() of response to our %s message for %s %s failed" , sparse_val_show(xfrm_type_names, hdr->nlmsg_type), description , text_said); jam_string(buf, "."); jam(buf, " ""Errno %d: %s" , (e_), strerror(e_)); jambuf_to_error_stream(buf); } }; |
| 392 | return FALSE0; |
| 393 | } else if ((size_t) r < sizeof(rsp.n)) { |
| 394 | libreswan_log(loglog(RC_LOG, "netlink read truncated message: %zd bytes; ignore message" , r) |
| 395 | "netlink read truncated message: %zd bytes; ignore message",loglog(RC_LOG, "netlink read truncated message: %zd bytes; ignore message" , r) |
| 396 | r)loglog(RC_LOG, "netlink read truncated message: %zd bytes; ignore message" , r); |
| 397 | continue; |
| 398 | } else if (addr.nl_pid != 0) { |
| 399 | /* not for us: ignore */ |
| 400 | dbg("netlink: ignoring %s message from process %u",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: ignoring %s message from process %u" , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type), addr.nl_pid ); } } |
| 401 | sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: ignoring %s message from process %u" , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type), addr.nl_pid ); } } |
| 402 | addr.nl_pid){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: ignoring %s message from process %u" , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type), addr.nl_pid ); } }; |
| 403 | continue; |
| 404 | } else if (rsp.n.nlmsg_seq != seq) { |
| 405 | dbg("netlink: ignoring out of sequence (%u/%u) message %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: ignoring out of sequence (%u/%u) message %s" , rsp.n.nlmsg_seq, seq, sparse_val_show(xfrm_type_names, rsp. n.nlmsg_type)); } } |
| 406 | rsp.n.nlmsg_seq, seq,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: ignoring out of sequence (%u/%u) message %s" , rsp.n.nlmsg_seq, seq, sparse_val_show(xfrm_type_names, rsp. n.nlmsg_type)); } } |
| 407 | sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: ignoring out of sequence (%u/%u) message %s" , rsp.n.nlmsg_seq, seq, sparse_val_show(xfrm_type_names, rsp. n.nlmsg_type)); } }; |
| 408 | continue; |
| 409 | } |
| 410 | break; |
| 411 | } |
| 412 | |
| 413 | if (rsp.n.nlmsg_len > (size_t) r) { |
| 414 | loglog(RC_LOG_SERIOUS, |
| 415 | "netlink recvfrom() of response to our %s message for %s %s was truncated: %zd instead of %zu", |
| 416 | sparse_val_show(xfrm_type_names, hdr->nlmsg_type), |
| 417 | description, text_said, |
| 418 | len, (size_t) rsp.n.nlmsg_len); |
| 419 | return FALSE0; |
| 420 | } |
| 421 | |
| 422 | if (rsp.n.nlmsg_type != expected_resp_type && rsp.n.nlmsg_type == NLMSG_ERROR0x2) { |
| 423 | if (rsp.u.e.error != 0) { |
| 424 | loglog(RC_LOG_SERIOUS, |
| 425 | "ERROR: netlink response for %s %s included errno %d: %s", |
| 426 | description, text_said, -rsp.u.e.error, |
| 427 | strerror(-rsp.u.e.error)); |
| 428 | return FALSE0; |
| 429 | } |
| 430 | /* |
| 431 | * What the heck does a 0 error mean? |
| 432 | * Since the caller doesn't depend on the result |
| 433 | * we'll let it pass. |
| 434 | * This really happens for netlink_add_sa(). |
| 435 | */ |
| 436 | dbg("netlink response for %s %s included non-error error",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink response for %s %s included non-error error" , description, text_said); } } |
| 437 | description, text_said){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink response for %s %s included non-error error" , description, text_said); } }; |
| 438 | /* ignore */ |
| 439 | } |
| 440 | if (rbuf == NULL((void*)0)) { |
| 441 | return TRUE1; |
| 442 | } |
| 443 | if (rsp.n.nlmsg_type != expected_resp_type) { |
| 444 | loglog(RC_LOG_SERIOUS, |
| 445 | "netlink recvfrom() of response to our %s message for %s %s was of wrong type (%s)", |
| 446 | sparse_val_show(xfrm_type_names, hdr->nlmsg_type), |
| 447 | description, text_said, |
| 448 | sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)); |
| 449 | return FALSE0; |
| 450 | } |
| 451 | memcpy(rbuf, &rsp, r); |
| 452 | return TRUE1; |
| 453 | } |
| 454 | |
| 455 | /* |
| 456 | * netlink_policy - |
| 457 | * |
| 458 | * @param hdr - Data to check |
| 459 | * @param enoent_ok - Boolean - OK or not OK. |
| 460 | * @param text_said - String |
| 461 | * @return boolean |
| 462 | */ |
| 463 | static bool_Bool netlink_policy(struct nlmsghdr *hdr, bool_Bool enoent_ok, |
| 464 | const char *text_said) |
| 465 | { |
| 466 | struct nlm_resp rsp; |
| 467 | |
| 468 | if (!send_netlink_msg(hdr, NLMSG_ERROR0x2, &rsp, "policy", text_said)) |
| 469 | return FALSE0; |
| 470 | |
| 471 | /* kind of surprising: we get here by success which implies an error structure! */ |
| 472 | |
| 473 | int error = -rsp.u.e.error; |
| 474 | |
| 475 | if (error == 0 || (error == ENOENT2 && enoent_ok)) |
| 476 | return TRUE1; |
| 477 | |
| 478 | loglog(RC_LOG_SERIOUS, |
| 479 | "ERROR: netlink %s response for flow %s included errno %d: %s", |
| 480 | sparse_val_show(xfrm_type_names, hdr->nlmsg_type), |
| 481 | text_said, error, strerror(error)); |
| 482 | return FALSE0; |
| 483 | } |
| 484 | |
| 485 | /* |
| 486 | * netlink_raw_eroute |
| 487 | * |
| 488 | * @param this_host ip_address |
| 489 | * @param this_client ip_subnet |
| 490 | * @param that_host ip_address |
| 491 | * @param that_client ip_subnet |
| 492 | * @param spi |
| 493 | * @param sa_proto int (4=tunnel, 50=esp, 108=ipcomp, etc ...) |
| 494 | * @param transport_proto unsigned int Contains protocol |
| 495 | * (6=tcp, 17=udp, etc...) |
| 496 | * @param esatype int |
| 497 | * @param pfkey_proto_info proto_info |
| 498 | * @param use_lifetime monotime_t (Currently unused) |
| 499 | * @param pluto_sadb_opterations sadb_op (operation - ie: ERO_DELETE) |
| 500 | * @param text_said char |
| 501 | * @return boolean True if successful |
| 502 | */ |
| 503 | static bool_Bool netlink_raw_eroute(const ip_address *this_host, |
| 504 | const ip_subnet *this_client, |
| 505 | const ip_address *that_host, |
| 506 | const ip_subnet *that_client, |
| 507 | ipsec_spi_t cur_spi, /* current SPI */ |
| 508 | ipsec_spi_t new_spi, /* new SPI */ |
| 509 | const struct ip_protocol *sa_proto, |
| 510 | unsigned int transport_proto, |
| 511 | enum eroute_type esatype, |
| 512 | const struct pfkey_proto_info *proto_info, |
| 513 | deltatime_t use_lifetime UNUSED__attribute__ ((unused)), |
| 514 | uint32_t sa_priority, |
| 515 | const struct sa_marks *sa_marks, |
| 516 | const uint32_t xfrm_if_id, |
| 517 | enum pluto_sadb_operations sadb_op, |
| 518 | const char *text_said, |
| 519 | const char *policy_label) |
| 520 | { |
| 521 | struct { |
| 522 | struct nlmsghdr n; |
| 523 | union { |
| 524 | struct xfrm_userpolicy_info p; |
| 525 | struct xfrm_userpolicy_id id; |
| 526 | } u; |
| 527 | char data[MAX_NETLINK_DATA_SIZE8192]; |
| 528 | } req; |
| 529 | |
| 530 | int policy = IPSEC_POLICY_IPSEC; |
| 531 | |
| 532 | if (sadb_op == ERO_DELETE && proto_info[0].reqid == 0 && |
| 533 | (ntohl(new_spi) == SPI_PASS256 || ntohl(new_spi) == SPI_HOLD259) && |
| 534 | strstr("IGNORE_ON_XFRM", text_said) != NULL((void*)0)) { |
| 535 | dbg("request to delete an opportunistic bare shunt ignored - XFRM already deleted it when it installed IPsec SA, text_said:%s", text_said){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("request to delete an opportunistic bare shunt ignored - XFRM already deleted it when it installed IPsec SA, text_said:%s" , text_said); } }; |
| 536 | return TRUE1; |
| 537 | } |
| 538 | |
| 539 | switch (esatype) { |
| 540 | case ET_UNSPEC: |
| 541 | case ET_AH: |
| 542 | case ET_ESP: |
| 543 | case ET_IPCOMP: |
| 544 | case ET_IPIP: |
| 545 | |
| 546 | break; |
| 547 | |
| 548 | case ET_INT: |
| 549 | /* shunt route */ |
| 550 | switch (ntohl(new_spi)) { |
| 551 | case SPI_PASS256: |
| 552 | dbg("netlink_raw_eroute: SPI_PASS"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_raw_eroute: SPI_PASS"); } }; |
| 553 | policy = IPSEC_POLICY_NONE; |
| 554 | break; |
| 555 | case SPI_HOLD259: |
| 556 | /* |
| 557 | * We don't know how to implement %hold, but it is okay. |
| 558 | * When we need a hold, the kernel XFRM acquire state |
| 559 | * will do the job (by dropping or holding the packet) |
| 560 | * until this entry expires. See /proc/sys/net/core/xfrm_acq_expires |
| 561 | * After expiration, the underlying policy causing the original acquire |
| 562 | * will fire again, dropping further packets. |
| 563 | */ |
| 564 | dbg("netlink_raw_eroute: SPI_HOLD implemented as no-op"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_raw_eroute: SPI_HOLD implemented as no-op" ); } }; |
| 565 | return TRUE1; /* yes really */ |
| 566 | case SPI_DROP257: |
| 567 | case SPI_REJECT258: |
| 568 | case 0: /* used with type=passthrough - can it not use SPI_PASS ?? */ |
| 569 | policy = IPSEC_POLICY_DISCARD; |
| 570 | break; |
| 571 | case SPI_TRAP260: |
| 572 | if (sadb_op == ERO_ADD_INBOUND || |
| 573 | sadb_op == ERO_DEL_INBOUND) |
| 574 | return TRUE1; |
| 575 | |
| 576 | break; |
| 577 | case SPI_TRAPSUBNET261: /* unused in our code */ |
| 578 | default: |
| 579 | bad_case(ntohl(new_spi))libreswan_bad_case("ntohl(new_spi)", (ntohl(new_spi)), (where_t ) { .func = __func__, .basename = "kernel_xfrm.c" , .line = 579 }); |
| 580 | } |
| 581 | break; |
| 582 | |
| 583 | default: |
| 584 | bad_case(esatype)libreswan_bad_case("esatype", (esatype), (where_t) { .func = __func__ , .basename = "kernel_xfrm.c" , .line = 584}); |
| 585 | } |
| 586 | |
| 587 | const int dir = (sadb_op == ERO_ADD_INBOUND || sadb_op == ERO_DEL_INBOUND) ? |
| 588 | XFRM_POLICY_IN : XFRM_POLICY_OUT; |
| 589 | |
| 590 | /* |
| 591 | * Bug #1004 fix. |
| 592 | * There really isn't "client" with XFRM and transport mode |
| 593 | * so eroute must be done to natted, visible ip. If we don't hide |
| 594 | * internal IP, communication doesn't work. |
| 595 | */ |
| 596 | ip_selector local_client; |
| 597 | |
| 598 | if (esatype == ET_ESP || esatype == ET_IPCOMP || sa_proto == &ip_protocol_esp) { |
| 599 | /* |
| 600 | * Variable "that" should be remote, but here it's not. |
| 601 | * We must check "dir" to find out remote address. |
| 602 | */ |
| 603 | int local_port; |
| 604 | |
| 605 | if (dir == XFRM_POLICY_OUT) { |
| 606 | local_port = portof(&that_client->addr)nport(endpoint_port((&that_client->addr))); |
| 607 | local_client = subnet_from_address(that_host); |
| 608 | that_client = &local_client; |
| 609 | } else { |
| 610 | local_port = portof(&this_client->addr)nport(endpoint_port((&this_client->addr))); |
| 611 | local_client = subnet_from_address(this_host); |
| 612 | this_client = &local_client; |
| 613 | } |
| 614 | setportof(local_port, &local_client.addr){ *(&local_client.addr) = set_endpoint_hport((&local_client .addr), ntohs(local_port)); }; |
| 615 | dbg("%s: using host address instead of client subnet", __func__){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s: using host address instead of client subnet" , __func__); } }; |
| 616 | } |
| 617 | |
| 618 | zero(&req)memset((&req), '\0', sizeof(*(&req))); |
| 619 | req.n.nlmsg_flags = NLM_F_REQUEST0x01 | NLM_F_ACK0x04; |
| 620 | |
| 621 | const int family = subnet_type(that_client)->af; |
| 622 | |
| 623 | /* .[sd]addr, .prefixlen_[sd], .[sd]port */ |
| 624 | SELECTOR_TO_XFRM(this_client, req.u.p.sel, s){ ip_selector client_ = *(this_client); ip_address address = selector_prefix (&client_); (req.u.p.sel).saddr = xfrm_from_address(& address); (req.u.p.sel).prefixlen_s = selector_maskbits(& client_); (req.u.p.sel).sport = nport(selector_port(&client_ )); }; |
| 625 | SELECTOR_TO_XFRM(that_client, req.u.p.sel, d){ ip_selector client_ = *(that_client); ip_address address = selector_prefix (&client_); (req.u.p.sel).daddr = xfrm_from_address(& address); (req.u.p.sel).prefixlen_d = selector_maskbits(& client_); (req.u.p.sel).dport = nport(selector_port(&client_ )); }; |
| 626 | |
| 627 | /* |
| 628 | * Munge .[sd]port? |
| 629 | * |
| 630 | * As per RFC 4301/5996, icmp type is put in the most significant |
| 631 | * 8 bits and icmp code is in the least significant 8 bits of port |
| 632 | * field. |
| 633 | * Although Libreswan does not have any configuration options for |
| 634 | * icmp type/code values, it is possible to specify icmp type and code |
| 635 | * using protoport option. For example, icmp echo request |
| 636 | * (type 8/code 0) needs to be encoded as 0x0800 in the port field |
| 637 | * and can be specified as left/rightprotoport=icmp/2048. Now with |
| 638 | * XFRM, icmp type and code need to be passed as source and |
| 639 | * destination ports, respectively. Therefore, this code extracts |
| 640 | * upper 8 bits and lower 8 bits and puts into source and destination |
| 641 | * ports before passing to XFRM. |
| 642 | */ |
| 643 | if (transport_proto == IPPROTO_ICMPIPPROTO_ICMP || |
| 644 | transport_proto == IPPROTO_ICMPV658) { |
| 645 | uint16_t icmp_type; |
| 646 | uint16_t icmp_code; |
| 647 | |
| 648 | icmp_type = ntohs(req.u.p.sel.sport) >> 8; |
| 649 | icmp_code = ntohs(req.u.p.sel.sport) & 0xFF; |
| 650 | |
| 651 | req.u.p.sel.sport = htons(icmp_type); |
| 652 | req.u.p.sel.dport = htons(icmp_code); |
| 653 | } |
| 654 | |
| 655 | req.u.p.sel.sport_mask = req.u.p.sel.sport == 0 ? 0 : ~0; |
| 656 | req.u.p.sel.dport_mask = req.u.p.sel.dport == 0 ? 0 : ~0; |
| 657 | req.u.p.sel.proto = transport_proto; |
| 658 | req.u.p.sel.family = family; |
| 659 | |
| 660 | if (sadb_op == ERO_DELETE || sadb_op == ERO_DEL_INBOUND) { |
| 661 | req.u.id.dir = dir; |
| 662 | req.n.nlmsg_type = XFRM_MSG_DELPOLICYXFRM_MSG_DELPOLICY; |
| 663 | req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.id)))( ((((sizeof(req.u.id)) + ((int) ( ((sizeof(struct nlmsghdr)) +4U -1) & ~(4U -1) ))))+4U -1) & ~(4U -1) ); |
| 664 | } else { |
| 665 | req.u.p.dir = dir; |
| 666 | |
| 667 | /* The caller should have set the proper priority by now */ |
| 668 | req.u.p.priority = sa_priority; |
| 669 | dbg("IPsec SA SPD priority set to %d", req.u.p.priority){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("IPsec SA SPD priority set to %d", req.u.p.priority ); } }; |
| 670 | |
| 671 | req.u.p.action = XFRM_POLICY_ALLOW0; |
| 672 | if (policy == IPSEC_POLICY_DISCARD) |
| 673 | req.u.p.action = XFRM_POLICY_BLOCK1; |
| 674 | /* req.u.p.lft.soft_use_expires_seconds = deltasecs(use_lifetime); */ |
| 675 | req.u.p.lft.soft_byte_limit = XFRM_INF(~(__u64)0); |
| 676 | req.u.p.lft.soft_packet_limit = XFRM_INF(~(__u64)0); |
| 677 | req.u.p.lft.hard_byte_limit = XFRM_INF(~(__u64)0); |
| 678 | req.u.p.lft.hard_packet_limit = XFRM_INF(~(__u64)0); |
| 679 | |
| 680 | /* |
| 681 | * NEW will fail when an existing policy, UPD always works. |
| 682 | * This seems to happen in cases with NAT'ed XP clients, or |
| 683 | * quick recycling/resurfacing of roadwarriors on the same IP. |
| 684 | * |
| 685 | * UPD is also needed for two separate tunnels with same end |
| 686 | * subnets |
| 687 | * Like A = B = C config where both A - B and B - C have |
| 688 | * tunnel A = C configured. |
| 689 | */ |
| 690 | req.n.nlmsg_type = XFRM_MSG_UPDPOLICYXFRM_MSG_UPDPOLICY; |
| 691 | if (sadb_op == ERO_REPLACE) |
| 692 | req.n.nlmsg_type = XFRM_MSG_UPDPOLICYXFRM_MSG_UPDPOLICY; |
| 693 | req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.p)))( ((((sizeof(req.u.p)) + ((int) ( ((sizeof(struct nlmsghdr))+ 4U -1) & ~(4U -1) ))))+4U -1) & ~(4U -1) ); |
| 694 | } |
| 695 | |
| 696 | if (policy == IPSEC_POLICY_IPSEC || policy == IPSEC_POLICY_DISCARD) { |
| 697 | if (sadb_op != ERO_DELETE) { |
| 698 | struct rtattr *attr; |
| 699 | |
| 700 | struct xfrm_user_tmpl tmpl[4]; |
| 701 | int i; |
| 702 | |
| 703 | zero(&tmpl)memset((&tmpl), '\0', sizeof(*(&tmpl))); |
| 704 | for (i = 0; proto_info[i].proto; i++) { |
| 705 | tmpl[i].reqid = proto_info[i].reqid; |
| 706 | tmpl[i].id.proto = proto_info[i].proto; |
| 707 | tmpl[i].optional = proto_info[i].proto == IPPROTO_COMPIPPROTO_COMP && dir != XFRM_POLICY_OUT; |
| 708 | tmpl[i].aalgos = tmpl[i].ealgos = tmpl[i].calgos = ~0; |
| 709 | tmpl[i].family = addrtypeof(that_host); |
| 710 | tmpl[i].mode = proto_info[i].mode == ENCAPSULATION_MODE_TUNNEL1; |
| 711 | |
| 712 | if (!tmpl[i].mode) |
| 713 | continue; |
| 714 | |
| 715 | tmpl[i].saddr = xfrm_from_address(this_host); |
| 716 | tmpl[i].id.daddr = xfrm_from_address(that_host); |
| 717 | } |
| 718 | |
| 719 | attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); |
| 720 | attr->rta_type = XFRMA_TMPL; |
| 721 | attr->rta_len = i * sizeof(tmpl[0]); |
| 722 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), tmpl, attr->rta_len); |
| 723 | attr->rta_len = RTA_LENGTH(attr->rta_len)(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (attr-> rta_len)); |
| 724 | req.n.nlmsg_len += attr->rta_len; |
| 725 | } |
| 726 | |
| 727 | /* mark policy extension */ |
| 728 | { |
| 729 | struct sa_mark sa_mark = (dir == XFRM_POLICY_IN) ? sa_marks->in : sa_marks->out; |
| 730 | |
| 731 | if (sa_mark.val != 0 && sa_mark.mask != 0) { |
| 732 | struct xfrm_mark xfrm_mark; |
| 733 | struct rtattr* mark_attr; |
| 734 | |
| 735 | xfrm_mark.v = sa_mark.val; |
| 736 | xfrm_mark.m = sa_mark.mask; |
| 737 | mark_attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); |
| 738 | mark_attr->rta_type = XFRMA_MARK; |
| 739 | mark_attr->rta_len = sizeof(xfrm_mark); |
| 740 | memcpy(RTA_DATA(mark_attr)((void*)(((char*)(mark_attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &xfrm_mark, mark_attr->rta_len); |
| 741 | mark_attr->rta_len = RTA_LENGTH(mark_attr->rta_len)(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (mark_attr ->rta_len)); |
| 742 | req.n.nlmsg_len += mark_attr->rta_len; |
| 743 | } |
| 744 | } |
| 745 | if (xfrm_if_id > 0) { |
| 746 | #ifdef USE_XFRM_INTERFACE1 |
| 747 | struct rtattr *attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); |
| 748 | dbg("%s netlink: XFRMA_IF_ID %" PRIu32 " req.n.nlmsg_type=%" PRIu32,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s netlink: XFRMA_IF_ID %" "u" " req.n.nlmsg_type=%" "u", __func__, xfrm_if_id, req.n.nlmsg_type); } } |
| 749 | __func__, xfrm_if_id, req.n.nlmsg_type){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s netlink: XFRMA_IF_ID %" "u" " req.n.nlmsg_type=%" "u", __func__, xfrm_if_id, req.n.nlmsg_type); } }; |
| 750 | attr->rta_type = XFRMA_IF_ID; |
| 751 | attr->rta_len = RTA_LENGTH(sizeof(uint32_t))(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (uint32_t))); |
| 752 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &xfrm_if_id, sizeof(uint32_t)); |
| 753 | req.n.nlmsg_len += attr->rta_len; |
| 754 | |
| 755 | /* XFRMA_SET_MARK = XFRMA_IF_ID/0xffffffff */ |
| 756 | attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); |
| 757 | attr->rta_type = XFRMA_SET_MARK; |
| 758 | attr->rta_len = RTA_LENGTH(sizeof(uint32_t))(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (uint32_t))); |
| 759 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &xfrm_if_id, sizeof(uint32_t)); |
| 760 | req.n.nlmsg_len += attr->rta_len; |
| 761 | #endif |
| 762 | } |
| 763 | |
| 764 | } |
| 765 | |
| 766 | if (policy_label != NULL((void*)0)) { |
| 767 | size_t len = strlen(policy_label) + 1; |
| 768 | struct rtattr *attr = (struct rtattr *) |
| 769 | ((char *)&req + req.n.nlmsg_len); |
| 770 | struct xfrm_user_sec_ctx *uctx; |
| 771 | |
| 772 | passert(len <= MAX_SECCTX_LEN){ _Bool assertion__ = len <= 4096; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "kernel_xfrm.c" , . line = 772}, "%s", "len <= MAX_SECCTX_LEN"); } }; |
| 773 | attr->rta_type = XFRMA_SEC_CTX; |
| 774 | |
| 775 | dbg("passing security label \"%s\" to kernel", policy_label){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("passing security label \"%s\" to kernel", policy_label ); } }; |
| 776 | attr->rta_len = |
| 777 | RTA_LENGTH(sizeof(struct xfrm_user_sec_ctx) + len)(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (struct xfrm_user_sec_ctx) + len)); |
| 778 | uctx = RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))); |
| 779 | uctx->exttype = XFRMA_SEC_CTX; |
| 780 | uctx->len = sizeof(struct xfrm_user_sec_ctx) + len; |
| 781 | uctx->ctx_doi = 1; /* ??? hardwired and nameless */ |
| 782 | uctx->ctx_alg = 1; /* ??? hardwired and nameless */ |
| 783 | uctx->ctx_len = len; |
| 784 | memcpy(uctx + 1, policy_label, len); |
| 785 | req.n.nlmsg_len += attr->rta_len; |
| 786 | } |
| 787 | |
| 788 | bool_Bool enoent_ok = sadb_op == ERO_DEL_INBOUND || |
| 789 | (sadb_op == ERO_DELETE && ntohl(cur_spi) == SPI_HOLD259); |
| 790 | |
| 791 | bool_Bool ok = netlink_policy(&req.n, enoent_ok, text_said); |
| 792 | |
| 793 | /* ??? deal with any forwarding policy */ |
| 794 | switch (dir) { |
| 795 | case XFRM_POLICY_IN: |
| 796 | if (req.n.nlmsg_type == XFRM_MSG_DELPOLICYXFRM_MSG_DELPOLICY) { |
| 797 | /* ??? we will call netlink_policy even if !ok. */ |
| 798 | req.u.id.dir = XFRM_POLICY_FWD; |
| 799 | } else if (!ok) { |
| 800 | break; |
| 801 | } else if (proto_info[0].mode != ENCAPSULATION_MODE_TUNNEL1 && |
| 802 | esatype != ET_INT) { |
| 803 | break; |
| 804 | } else { |
| 805 | req.u.p.dir = XFRM_POLICY_FWD; |
| 806 | } |
| 807 | ok &= netlink_policy(&req.n, enoent_ok, text_said); |
| 808 | break; |
| 809 | } |
| 810 | |
| 811 | return ok; |
| 812 | } |
| 813 | |
| 814 | static void netlink_sa_policy_to_id(struct xfrm_userpolicy_id *id, |
| 815 | struct xfrm_userpolicy_info *pol) |
| 816 | { |
| 817 | id->sel = pol->sel; |
| 818 | id->index = pol->index; |
| 819 | id->dir = pol->dir; |
| 820 | } |
| 821 | |
| 822 | static bool_Bool netlink_get_sa_policy(const struct kernel_sa *sa, |
| 823 | struct xfrm_userpolicy_id *id) |
| 824 | { |
| 825 | struct { |
| 826 | struct nlmsghdr n; |
| 827 | struct xfrm_userpolicy_id id; |
| 828 | } req; |
| 829 | struct nlm_resp rsp; |
| 830 | |
| 831 | zero(&req)memset((&req), '\0', sizeof(*(&req))); |
| 832 | zero(&rsp)memset((&rsp), '\0', sizeof(*(&rsp))); |
| 833 | |
| 834 | req.n.nlmsg_flags = NLM_F_REQUEST0x01; |
| 835 | req.n.nlmsg_type = XFRM_MSG_GETPOLICYXFRM_MSG_GETPOLICY; |
| 836 | req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)))( ((((sizeof(req.id)) + ((int) ( ((sizeof(struct nlmsghdr))+4U -1) & ~(4U -1) ))))+4U -1) & ~(4U -1) ); |
| 837 | |
| 838 | req.id.dir = sa->nk_dir; /* clang 6.0.0 thinks RHS is garbage or undefined */ |
| 839 | req.id.sel.family = address_type(sa->src.address)->af; |
| 840 | |
| 841 | /* .[sd]addr, .prefixlen_[sd], .[sd]port */ |
| 842 | SELECTOR_TO_XFRM(sa->src.client, req.id.sel, s){ ip_selector client_ = *(sa->src.client); ip_address address = selector_prefix(&client_); (req.id.sel).saddr = xfrm_from_address (&address); (req.id.sel).prefixlen_s = selector_maskbits( &client_); (req.id.sel).sport = nport(selector_port(& client_)); }; |
| 843 | SELECTOR_TO_XFRM(sa->dst.client, req.id.sel, d){ ip_selector client_ = *(sa->dst.client); ip_address address = selector_prefix(&client_); (req.id.sel).daddr = xfrm_from_address (&address); (req.id.sel).prefixlen_d = selector_maskbits( &client_); (req.id.sel).dport = nport(selector_port(& client_)); }; |
| 844 | |
| 845 | /* |
| 846 | * XXX: the other calls to CLIENT_TO_XFRM() also munge the |
| 847 | * .[sd]port per ICMP, and set .[sd]port_mask. |
| 848 | * |
| 849 | * This code does not. |
| 850 | * |
| 851 | * Presumably this code, which is called from |
| 852 | * netlink_migrate_sa(), and is handling MOBIKE only allows |
| 853 | * addresses (no port, no rotocol). Hence the default value |
| 854 | * of .[sd]port_mask (0), is correct. |
| 855 | */ |
| 856 | |
| 857 | if (!send_netlink_msg(&req.n, XFRM_MSG_NEWPOLICYXFRM_MSG_NEWPOLICY, &rsp, "Get policy", |
| 858 | sa->text_said)) { |
| 859 | dbg(" netlink_get_sa_policy : policy died on us: %s, index=%d %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" netlink_get_sa_policy : policy died on us: %s, index=%d %s" , enum_name(&netkey_sa_dir_names, req.id.dir), req.id.index , sa->text_said); } } |
| 860 | enum_name(&netkey_sa_dir_names, req.id.dir),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" netlink_get_sa_policy : policy died on us: %s, index=%d %s" , enum_name(&netkey_sa_dir_names, req.id.dir), req.id.index , sa->text_said); } } |
| 861 | req.id.index, sa->text_said){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" netlink_get_sa_policy : policy died on us: %s, index=%d %s" , enum_name(&netkey_sa_dir_names, req.id.dir), req.id.index , sa->text_said); } }; |
| 862 | return FALSE0; |
| 863 | } else if (rsp.n.nlmsg_len < NLMSG_LENGTH(sizeof(rsp.u.pol))((sizeof(rsp.u.pol)) + ((int) ( ((sizeof(struct nlmsghdr))+4U -1) & ~(4U -1) )))) { |
| 864 | libreswan_log(" netlink_get_sa_policy: XFRM_MSG_GETPOLICY %s "loglog(RC_LOG, " netlink_get_sa_policy: XFRM_MSG_GETPOLICY %s " "returned message with length %zu < %zu " "bytes; ignore message" , enum_name(&netkey_sa_dir_names, req.id.dir), (size_t) rsp .n.nlmsg_len, sizeof(rsp.u.pol)) |
| 865 | "returned message with length %zu < %zu "loglog(RC_LOG, " netlink_get_sa_policy: XFRM_MSG_GETPOLICY %s " "returned message with length %zu < %zu " "bytes; ignore message" , enum_name(&netkey_sa_dir_names, req.id.dir), (size_t) rsp .n.nlmsg_len, sizeof(rsp.u.pol)) |
| 866 | "bytes; ignore message",loglog(RC_LOG, " netlink_get_sa_policy: XFRM_MSG_GETPOLICY %s " "returned message with length %zu < %zu " "bytes; ignore message" , enum_name(&netkey_sa_dir_names, req.id.dir), (size_t) rsp .n.nlmsg_len, sizeof(rsp.u.pol)) |
| 867 | enum_name(&netkey_sa_dir_names, req.id.dir),loglog(RC_LOG, " netlink_get_sa_policy: XFRM_MSG_GETPOLICY %s " "returned message with length %zu < %zu " "bytes; ignore message" , enum_name(&netkey_sa_dir_names, req.id.dir), (size_t) rsp .n.nlmsg_len, sizeof(rsp.u.pol)) |
| 868 | (size_t) rsp.n.nlmsg_len, sizeof(rsp.u.pol))loglog(RC_LOG, " netlink_get_sa_policy: XFRM_MSG_GETPOLICY %s " "returned message with length %zu < %zu " "bytes; ignore message" , enum_name(&netkey_sa_dir_names, req.id.dir), (size_t) rsp .n.nlmsg_len, sizeof(rsp.u.pol)); |
| 869 | return FALSE0; |
| 870 | } |
| 871 | |
| 872 | netlink_sa_policy_to_id(id, &rsp.u.pol); |
| 873 | |
| 874 | return TRUE1; |
| 875 | } |
| 876 | |
| 877 | static void set_migration_attr(const struct kernel_sa *sa, |
| 878 | struct xfrm_user_migrate *m) |
| 879 | { |
| 880 | m->old_saddr = xfrm_from_address(sa->src.address); |
| 881 | m->old_daddr = xfrm_from_address(sa->dst.address); |
| 882 | m->new_saddr = xfrm_from_address(sa->src.new_address); |
| 883 | m->new_daddr = xfrm_from_address(sa->dst.new_address); |
| 884 | |
| 885 | m->proto = sa->proto->ipproto; |
| 886 | m->mode = XFRM_MODE_TUNNEL1; /* AA_201705 hard coded how to figure this out */ |
| 887 | m->reqid = sa->reqid; |
| 888 | m->old_family = m->new_family = address_type(sa->src.address)->af; |
| 889 | } |
| 890 | |
| 891 | static bool_Bool create_xfrm_migrate_sa(struct state *st, const int dir, |
| 892 | struct kernel_sa *ret_sa, char *text_said) |
| 893 | { |
| 894 | const struct connection *const c = st->st_connection; |
| 895 | |
| 896 | const struct ip_encap *encap_type = |
| 897 | (st->st_interface->protocol == &ip_protocol_tcp) ? &ip_encap_esp_in_tcp : |
| 898 | (st->hidden_variables.st_nat_traversal & NAT_T_DETECTED( ((lset_t)1 << (NATED_HOST)) | ((lset_t)1 << (NATED_PEER )) )) ? &ip_encap_esp_in_udp : |
| 899 | NULL((void*)0); |
| 900 | dbg("TCP/NAT: encap type "PRI_IP_ENCAP, pri_ip_encap(encap_type)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("TCP/NAT: encap type ""%u(%s)", (encap_type) == ((void*)0) ? 0 : (encap_type)->encap_type, (encap_type) == ((void*)0) ? "none" : (encap_type)->name); } }; |
| 901 | |
| 902 | const struct ip_protocol *proto; |
| 903 | struct ipsec_proto_info *proto_info; |
| 904 | |
| 905 | if (st->st_esp.present) { |
| 906 | proto = &ip_protocol_esp; |
| 907 | proto_info = &st->st_esp; |
| 908 | } else if (st->st_ah.present) { |
| 909 | proto = &ip_protocol_ah; |
| 910 | proto_info = &st->st_ah; |
| 911 | } else { |
| 912 | return FALSE0; |
| 913 | } |
| 914 | |
| 915 | struct kernel_sa sa = { |
| 916 | .nk_dir = dir, |
| 917 | .proto = proto, |
| 918 | .reqid = reqid_esp(c->spd.reqid), |
| 919 | .encap_type = encap_type, |
| 920 | }; |
| 921 | |
| 922 | ip_endpoint new_endpoint; |
| 923 | uint16_t old_port; |
| 924 | uint16_t encap_sport = 0; |
| 925 | uint16_t encap_dport = 0; |
| 926 | const ip_address *src, *dst; |
| 927 | const ip_subnet *src_client, *dst_client; |
| 928 | |
| 929 | if (endpoint_type(&st->st_mobike_local_endpoint) != NULL((void*)0)) { |
| 930 | char *n = jam_str(text_said, SAMIGTOT_BUF(16 + sizeof(said_buf) + sizeof(address_reversed_buf)), "initiator migrate kernel SA "); |
| 931 | passert((SAMIGTOT_BUF - strlen(text_said)) > SATOT_BUF){ _Bool assertion__ = ((16 + sizeof(said_buf) + sizeof(address_reversed_buf )) - strlen(text_said)) > sizeof(said_buf); if (!assertion__ ) { lsw_passert_fail((where_t) { .func = __func__, .basename = "kernel_xfrm.c" , .line = 931}, "%s", "(SAMIGTOT_BUF - strlen(text_said)) > SATOT_BUF" ); } }; |
| 932 | pexpect_st_local_endpoint(st); |
| 933 | old_port = endpoint_hport(&st->st_interface->local_endpoint); |
| 934 | new_endpoint = st->st_mobike_local_endpoint; |
| 935 | |
| 936 | if (dir == XFRM_POLICY_IN || dir == XFRM_POLICY_FWD) { |
| 937 | src = &c->spd.that.host_addr; |
| 938 | dst = &c->spd.this.host_addr; |
| 939 | src_client = &c->spd.that.client; |
| 940 | dst_client = &c->spd.this.client; |
| 941 | sa.src.new_address = src; |
| 942 | sa.dst.new_address = &st->st_mobike_local_endpoint; |
| 943 | sa.spi = proto_info->our_spi; |
| 944 | set_text_said(n, dst, sa.spi, proto); |
| 945 | if (encap_type != NULL((void*)0)) { |
| 946 | encap_sport = endpoint_hport(&st->st_remote_endpoint); |
| 947 | encap_dport = endpoint_hport(&st->st_mobike_local_endpoint); |
| 948 | } |
| 949 | } else { |
| 950 | src = &c->spd.this.host_addr; |
| 951 | dst = &c->spd.that.host_addr; |
| 952 | src_client = &c->spd.this.client; |
| 953 | dst_client = &c->spd.that.client; |
| 954 | sa.src.new_address = &st->st_mobike_local_endpoint; |
| 955 | sa.dst.new_address = dst; |
| 956 | sa.spi = proto_info->attrs.spi; |
| 957 | set_text_said(n, src, sa.spi, proto); |
| 958 | if (encap_type != NULL((void*)0)) { |
| 959 | encap_sport = endpoint_hport(&st->st_mobike_local_endpoint); |
| 960 | encap_dport = endpoint_hport(&st->st_remote_endpoint); |
| 961 | } |
| 962 | } |
| 963 | } else { |
| 964 | char *n = jam_str(text_said, SAMIGTOT_BUF(16 + sizeof(said_buf) + sizeof(address_reversed_buf)), "responder migrate kernel SA "); |
| 965 | passert((SAMIGTOT_BUF - strlen(text_said)) > SATOT_BUF){ _Bool assertion__ = ((16 + sizeof(said_buf) + sizeof(address_reversed_buf )) - strlen(text_said)) > sizeof(said_buf); if (!assertion__ ) { lsw_passert_fail((where_t) { .func = __func__, .basename = "kernel_xfrm.c" , .line = 965}, "%s", "(SAMIGTOT_BUF - strlen(text_said)) > SATOT_BUF" ); } }; |
| 966 | old_port = endpoint_hport(&st->st_remote_endpoint); |
| 967 | new_endpoint = st->st_mobike_remote_endpoint; |
| 968 | |
| 969 | if (dir == XFRM_POLICY_IN || dir == XFRM_POLICY_FWD) { |
| 970 | src = &c->spd.that.host_addr; |
| 971 | dst = &c->spd.this.host_addr; |
| 972 | src_client = &c->spd.that.client; |
| 973 | dst_client = &c->spd.this.client; |
| 974 | sa.src.new_address = &st->st_mobike_remote_endpoint; |
| 975 | sa.dst.new_address = &c->spd.this.host_addr; |
| 976 | sa.spi = proto_info->our_spi; |
| 977 | set_text_said(n, src, sa.spi, proto); |
| 978 | if (encap_type != NULL((void*)0)) { |
| 979 | encap_sport = endpoint_hport(&st->st_mobike_remote_endpoint); |
| 980 | pexpect_st_local_endpoint(st); |
| 981 | encap_dport = endpoint_hport(&st->st_interface->local_endpoint); |
| 982 | } |
| 983 | } else { |
| 984 | src = &c->spd.this.host_addr; |
| 985 | dst = &c->spd.that.host_addr; |
| 986 | src_client = &c->spd.this.client; |
| 987 | dst_client = &c->spd.that.client; |
| 988 | sa.src.new_address = &c->spd.this.host_addr; |
| 989 | sa.dst.new_address = &st->st_mobike_remote_endpoint; |
| 990 | sa.spi = proto_info->attrs.spi; |
| 991 | set_text_said(n, dst, sa.spi, proto); |
| 992 | |
| 993 | if (encap_type != NULL((void*)0)) { |
| 994 | pexpect_st_local_endpoint(st); |
| 995 | encap_sport = endpoint_hport(&st->st_interface->local_endpoint); |
| 996 | encap_dport = endpoint_hport(&st->st_mobike_remote_endpoint); |
| 997 | } |
| 998 | } |
| 999 | } |
| 1000 | |
| 1001 | sa.src.address = src; |
| 1002 | sa.dst.address = dst; |
| 1003 | sa.text_said = text_said; |
| 1004 | sa.src.client = src_client; |
| 1005 | sa.dst.client = dst_client; |
| 1006 | sa.src.encap_port = encap_sport; |
| 1007 | sa.dst.encap_port = encap_dport; |
| 1008 | |
| 1009 | char reqid_buf[ULTOT_BUF(22 + 1) + 32]; |
| 1010 | endpoint_buf ra; |
| 1011 | snprintf(reqid_buf, sizeof(reqid_buf), ":%u to %s reqid=%u %s", |
| 1012 | old_port, |
| 1013 | str_endpoint(&new_endpoint, &ra), |
| 1014 | sa.reqid, |
| 1015 | enum_name(&netkey_sa_dir_names, dir)); |
| 1016 | add_str(text_said, SAMIGTOT_BUF(16 + sizeof(said_buf) + sizeof(address_reversed_buf)), text_said, reqid_buf); |
| 1017 | |
| 1018 | dbg("%s", text_said){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s", text_said); } }; |
| 1019 | |
| 1020 | *ret_sa = sa; |
| 1021 | return TRUE1; |
| 1022 | } |
| 1023 | |
| 1024 | static bool_Bool migrate_xfrm_sa(const struct kernel_sa *sa) |
| 1025 | { |
| 1026 | struct { |
| 1027 | struct nlmsghdr n; |
| 1028 | struct xfrm_userpolicy_id id; |
| 1029 | char data[MAX_NETLINK_DATA_SIZE8192]; |
| 1030 | } req; |
| 1031 | struct nlm_resp rsp; |
| 1032 | struct rtattr *attr; |
| 1033 | |
| 1034 | zero(&req)memset((&req), '\0', sizeof(*(&req))); |
| 1035 | |
| 1036 | if (!netlink_get_sa_policy(sa, &req.id)) { |
| 1037 | return FALSE0; |
| 1038 | } |
| 1039 | |
| 1040 | req.n.nlmsg_flags = NLM_F_REQUEST0x01 | NLM_F_ACK0x04; |
| 1041 | req.n.nlmsg_type = XFRM_MSG_MIGRATEXFRM_MSG_MIGRATE; |
| 1042 | req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)))( ((((sizeof(req.id)) + ((int) ( ((sizeof(struct nlmsghdr))+4U -1) & ~(4U -1) ))))+4U -1) & ~(4U -1) ); |
| 1043 | |
| 1044 | |
| 1045 | /* add attrs[XFRM_MSG_MIGRATE] */ |
| 1046 | { |
| 1047 | struct xfrm_user_migrate migrate; |
| 1048 | |
| 1049 | attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); |
| 1050 | attr->rta_type = XFRMA_MIGRATE; |
| 1051 | attr->rta_len = sizeof(migrate); |
| 1052 | |
| 1053 | set_migration_attr(sa, &migrate); |
| 1054 | |
| 1055 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &migrate, attr->rta_len); |
| 1056 | attr->rta_len = RTA_LENGTH(attr->rta_len)(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (attr-> rta_len)); |
| 1057 | req.n.nlmsg_len += attr->rta_len; |
| 1058 | } |
| 1059 | |
| 1060 | if (sa->encap_type != NULL((void*)0)) { |
| 1061 | dbg("adding xfrm_encap_templ when migrating sa encap_type="PRI_IP_ENCAP" sport=%d dport=%d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("adding xfrm_encap_templ when migrating sa encap_type=" "%u(%s)"" sport=%d dport=%d", (sa->encap_type) == ((void*) 0) ? 0 : (sa->encap_type)->encap_type, (sa->encap_type ) == ((void*)0) ? "none" : (sa->encap_type)->name, sa-> src.encap_port, sa->dst.encap_port); } } |
| 1062 | pri_ip_encap(sa->encap_type),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("adding xfrm_encap_templ when migrating sa encap_type=" "%u(%s)"" sport=%d dport=%d", (sa->encap_type) == ((void*) 0) ? 0 : (sa->encap_type)->encap_type, (sa->encap_type ) == ((void*)0) ? "none" : (sa->encap_type)->name, sa-> src.encap_port, sa->dst.encap_port); } } |
| 1063 | sa->src.encap_port, sa->dst.encap_port){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("adding xfrm_encap_templ when migrating sa encap_type=" "%u(%s)"" sport=%d dport=%d", (sa->encap_type) == ((void*) 0) ? 0 : (sa->encap_type)->encap_type, (sa->encap_type ) == ((void*)0) ? "none" : (sa->encap_type)->name, sa-> src.encap_port, sa->dst.encap_port); } }; |
| 1064 | attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); |
| 1065 | struct xfrm_encap_tmpl natt; |
| 1066 | |
| 1067 | natt.encap_type = sa->encap_type->encap_type; |
| 1068 | natt.encap_sport = ntohs(sa->src.encap_port); |
| 1069 | natt.encap_dport = ntohs(sa->dst.encap_port); |
| 1070 | zero(&natt.encap_oa)memset((&natt.encap_oa), '\0', sizeof(*(&natt.encap_oa ))); |
| 1071 | |
| 1072 | attr->rta_type = XFRMA_ENCAP; |
| 1073 | attr->rta_len = RTA_LENGTH(sizeof(natt))(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (natt))); |
| 1074 | |
| 1075 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &natt, sizeof(natt)); |
| 1076 | |
| 1077 | req.n.nlmsg_len += attr->rta_len; |
| 1078 | } |
| 1079 | |
| 1080 | bool_Bool r = send_netlink_msg(&req.n, NLMSG_ERROR0x2, &rsp, "mobike", |
| 1081 | sa->text_said); |
| 1082 | if (!r) |
| 1083 | return FALSE0; |
| 1084 | |
| 1085 | if (rsp.u.e.error < 0) { |
| 1086 | /* error is already logged */ |
| 1087 | return FALSE0; |
| 1088 | } |
| 1089 | |
| 1090 | return TRUE1; |
| 1091 | } |
| 1092 | |
| 1093 | static bool_Bool netlink_migrate_sa(struct state *st) |
| 1094 | { |
| 1095 | struct kernel_sa sa; |
| 1096 | char mig_said[SAMIGTOT_BUF(16 + sizeof(said_buf) + sizeof(address_reversed_buf))]; |
| 1097 | |
| 1098 | return |
| 1099 | create_xfrm_migrate_sa(st, XFRM_POLICY_OUT, &sa, mig_said) && |
| 1100 | migrate_xfrm_sa(&sa) && |
| 1101 | |
| 1102 | create_xfrm_migrate_sa(st, XFRM_POLICY_IN, &sa, mig_said) && |
| 1103 | migrate_xfrm_sa(&sa) && |
| 1104 | |
| 1105 | create_xfrm_migrate_sa(st, XFRM_POLICY_FWD, &sa, mig_said) && |
| 1106 | migrate_xfrm_sa(&sa); |
| 1107 | } |
| 1108 | |
| 1109 | |
| 1110 | /* see /usr/include/linux/ethtool.h */ |
| 1111 | |
| 1112 | enum nic_offload_state { |
| 1113 | NIC_OFFLOAD_UNKNOWN, |
| 1114 | NIC_OFFLOAD_UNSUPPORTED, |
| 1115 | NIC_OFFLOAD_SUPPORTED |
| 1116 | }; |
| 1117 | |
| 1118 | static struct { |
| 1119 | unsigned int bit; |
| 1120 | unsigned int total_blocks; |
| 1121 | enum nic_offload_state state; |
| 1122 | } netlink_esp_hw_offload; |
| 1123 | |
| 1124 | static bool_Bool siocethtool(const char *ifname, void *data, const char *action) |
| 1125 | { |
| 1126 | struct ifreq ifr = { .ifr_dataifr_ifru.ifru_data = data }; |
| 1127 | jam_str(ifr.ifr_nameifr_ifrn.ifrn_name, sizeof(ifr.ifr_nameifr_ifrn.ifrn_name), ifname); |
| 1128 | if (ioctl(nl_send_fd, SIOCETHTOOL0x8946, &ifr) != 0) { |
| 1129 | /* EOPNOTSUPP is expected if kernel doesn't support this */ |
| 1130 | if (errno(*__errno_location ()) == EOPNOTSUPP95) { |
| 1131 | dbg("cannot offload to %s because SIOCETHTOOL %s failed: %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("cannot offload to %s because SIOCETHTOOL %s failed: %s" , ifname, action, strerror((*__errno_location ()))); } } |
| 1132 | ifname, action, strerror(errno)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("cannot offload to %s because SIOCETHTOOL %s failed: %s" , ifname, action, strerror((*__errno_location ()))); } }; |
| 1133 | } else { |
| 1134 | LOG_ERRNO(errno, "can't offload to %s because SIOCETHTOOL %s failed",{ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "can't offload to %s because SIOCETHTOOL %s failed", ifname , action); jam_string(buf, "."); jam(buf, " ""Errno %d: %s", ( e_), strerror(e_)); jambuf_to_error_stream(buf); } } |
| 1135 | ifname, action){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "can't offload to %s because SIOCETHTOOL %s failed", ifname , action); jam_string(buf, "."); jam(buf, " ""Errno %d: %s", ( e_), strerror(e_)); jambuf_to_error_stream(buf); } }; |
| 1136 | } |
| 1137 | return false0; |
| 1138 | } else { |
| 1139 | return true1; |
| 1140 | } |
| 1141 | } |
| 1142 | |
| 1143 | static void netlink_find_offload_feature(const char *ifname) |
| 1144 | { |
| 1145 | netlink_esp_hw_offload.state = NIC_OFFLOAD_UNSUPPORTED; |
| 1146 | |
| 1147 | /* Determine number of device-features */ |
| 1148 | |
| 1149 | struct ethtool_sset_info *sset_info = alloc_bytes( |
| 1150 | sizeof(*sset_info) + sizeof(sset_info->data[0]), |
| 1151 | "ethtool_sset_info"); |
| 1152 | sset_info->cmd = ETHTOOL_GSSET_INFO0x00000037; |
| 1153 | sset_info->sset_mask = 1ULL << ETH_SS_FEATURES; |
| 1154 | |
| 1155 | if (!siocethtool(ifname, sset_info, "ETHTOOL_GSSET_INFO") || |
| 1156 | sset_info->sset_mask != 1ULL << ETH_SS_FEATURES) { |
| 1157 | pfree(sset_info); |
| 1158 | libreswan_log("Kernel does not support NIC esp-hw-offload (ETHTOOL_GSSET_INFO failed)")loglog(RC_LOG, "Kernel does not support NIC esp-hw-offload (ETHTOOL_GSSET_INFO failed)" ); |
| 1159 | return; |
| 1160 | } |
| 1161 | |
| 1162 | uint32_t sset_len = sset_info->data[0]; |
| 1163 | |
| 1164 | pfree(sset_info); |
| 1165 | |
| 1166 | /* Retrieve names of device-features */ |
| 1167 | |
| 1168 | struct ethtool_gstrings *cmd = alloc_bytes( |
| 1169 | sizeof(*cmd) + ETH_GSTRING_LEN32 * sset_len, "ethtool_gstrings"); |
| 1170 | cmd->cmd = ETHTOOL_GSTRINGS0x0000001b; |
| 1171 | cmd->string_set = ETH_SS_FEATURES; |
| 1172 | |
| 1173 | if (siocethtool(ifname, cmd, "ETHTOOL_GSTRINGS")) { |
| 1174 | /* Look for the ESP_HW feature bit */ |
| 1175 | char *str = (char *)cmd->data; |
| 1176 | for (uint32_t i = 0; i < cmd->len; i++) { |
| 1177 | if (strneq(str, "esp-hw-offload", ETH_GSTRING_LEN)(strncmp((str), ("esp-hw-offload"), (32)) == 0)) { |
| 1178 | netlink_esp_hw_offload.bit = i; |
| 1179 | netlink_esp_hw_offload.total_blocks = (sset_len + 31) / 32; |
| 1180 | netlink_esp_hw_offload.state = NIC_OFFLOAD_SUPPORTED; |
| 1181 | break; |
| 1182 | } |
| 1183 | str += ETH_GSTRING_LEN32; |
| 1184 | } |
| 1185 | } |
| 1186 | |
| 1187 | pfree(cmd); |
| 1188 | |
| 1189 | if (netlink_esp_hw_offload.state == NIC_OFFLOAD_SUPPORTED) { |
| 1190 | libreswan_log("Kernel supports NIC esp-hw-offload")loglog(RC_LOG, "Kernel supports NIC esp-hw-offload"); |
| 1191 | } else { |
| 1192 | libreswan_log("Kernel does not support NIC esp-hw-offload")loglog(RC_LOG, "Kernel does not support NIC esp-hw-offload"); |
| 1193 | } |
| 1194 | } |
| 1195 | |
| 1196 | static bool_Bool netlink_detect_offload(const struct raw_iface *ifp) |
| 1197 | { |
| 1198 | const char *ifname = ifp->name; |
| 1199 | /* |
| 1200 | * Kernel requires a real interface in order to query the kernel-wide |
| 1201 | * capability, so we do it here on first invocation. |
| 1202 | */ |
| 1203 | if (netlink_esp_hw_offload.state == NIC_OFFLOAD_UNKNOWN) |
| 1204 | netlink_find_offload_feature(ifname); |
| 1205 | |
| 1206 | if (netlink_esp_hw_offload.state == NIC_OFFLOAD_UNSUPPORTED) { |
| 1207 | return false0; |
| 1208 | } |
| 1209 | |
| 1210 | /* Feature is supported by kernel. Query device features */ |
| 1211 | |
| 1212 | struct ethtool_gfeatures *cmd = alloc_bytes( |
| 1213 | sizeof(*cmd) + sizeof(cmd->features[0]) * netlink_esp_hw_offload.total_blocks, |
| 1214 | "ethtool_gfeatures"); |
| 1215 | |
| 1216 | cmd->cmd = ETHTOOL_GFEATURES0x0000003a; |
| 1217 | cmd->size = netlink_esp_hw_offload.total_blocks; |
| 1218 | |
| 1219 | bool_Bool ret = false0; |
| 1220 | |
| 1221 | if (siocethtool(ifname, cmd, "ETHTOOL_GFEATURES")) { |
| 1222 | int block = netlink_esp_hw_offload.bit / 32; |
| 1223 | uint32_t feature_bit = 1U << (netlink_esp_hw_offload.bit % 32); |
| 1224 | if (cmd->features[block].active & feature_bit) |
| 1225 | ret = true1; |
| 1226 | } |
| 1227 | pfree(cmd); |
| 1228 | return ret; |
| 1229 | } |
| 1230 | |
| 1231 | /* |
| 1232 | * netlink_add_sa - Add an SA into the kernel SPDB via netlink |
| 1233 | * |
| 1234 | * @param sa Kernel SA to add/modify |
| 1235 | * @param replace boolean - true if this replaces an existing SA |
| 1236 | * @return bool True if successful |
| 1237 | */ |
| 1238 | static bool_Bool netlink_add_sa(const struct kernel_sa *sa, bool_Bool replace) |
| 1239 | { |
| 1240 | struct { |
| 1241 | struct nlmsghdr n; |
| 1242 | struct xfrm_usersa_info p; |
| 1243 | char data[MAX_NETLINK_DATA_SIZE8192]; |
| 1244 | } req; |
| 1245 | struct rtattr *attr; |
| 1246 | int ret; |
| 1247 | |
| 1248 | zero(&req)memset((&req), '\0', sizeof(*(&req))); |
| 1249 | req.n.nlmsg_flags = NLM_F_REQUEST0x01 | NLM_F_ACK0x04; |
| 1250 | req.n.nlmsg_type = replace ? XFRM_MSG_UPDSAXFRM_MSG_UPDSA : XFRM_MSG_NEWSAXFRM_MSG_NEWSA; |
| 1251 | |
| 1252 | req.p.saddr = xfrm_from_address(sa->src.address); |
| 1253 | req.p.id.daddr = xfrm_from_address(sa->dst.address); |
| 1254 | |
| 1255 | req.p.id.spi = sa->spi; |
| 1256 | req.p.id.proto = esatype2proto(sa->esatype)((int)(sa->esatype)); |
| 1257 | req.p.family = addrtypeof(sa->src.address); |
| 1258 | /* |
| 1259 | * This requires ipv6 modules. It is required to support 6in4 and 4in6 |
| 1260 | * tunnels in linux 2.6.25+ |
| 1261 | */ |
| 1262 | if (sa->mode == ENCAPSULATION_MODE_TUNNEL1) { |
| 1263 | dbg("netlink: enabling tunnel mode"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: enabling tunnel mode"); } }; |
| 1264 | req.p.mode = XFRM_MODE_TUNNEL1; |
| 1265 | req.p.flags |= XFRM_STATE_AF_UNSPEC32; |
| 1266 | } else { |
| 1267 | dbg("netlink: enabling transport mode"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: enabling transport mode"); } }; |
| 1268 | req.p.mode = XFRM_MODE_TRANSPORT0; |
| 1269 | } |
| 1270 | |
| 1271 | /* |
| 1272 | * We only add traffic selectors for transport mode. The problem is |
| 1273 | * that Tunnel mode ipsec with ipcomp is layered so that ipcomp |
| 1274 | * tunnel is protected with transport mode ipsec but in this case we |
| 1275 | * shouldn't any more add traffic selectors. Caller function will |
| 1276 | * inform us if we need or don't need selectors. |
| 1277 | */ |
| 1278 | if (sa->add_selector) { |
| 1279 | ip_selector src = *sa->src.client; |
| 1280 | ip_selector dst = *sa->dst.client; |
| 1281 | |
| 1282 | /* |
| 1283 | * With XFRM/NETKEY and transport mode with nat-traversal we |
| 1284 | * need to change outbound IPsec SA to point to external ip of |
| 1285 | * the peer. Here we substitute real client ip with NATD ip. |
| 1286 | * |
| 1287 | * XXX: unset_protoport is technically wrong - the |
| 1288 | * protocol is sa->transport_proto(?) and . Code |
| 1289 | * further down will fix up the .sport / .dport in the |
| 1290 | * xfrm structure. |
| 1291 | * |
| 1292 | * XXX: is .src.address / .dst.address an address or |
| 1293 | * endpoint in disguise? |
| 1294 | */ |
| 1295 | if (sa->inbound) { |
| 1296 | /* inbound; fix this end */ |
| 1297 | ip_port port = selector_port(sa->src.client); |
| 1298 | ip_protoport protoport = protoport2(sa->transport_proto, port); |
| 1299 | src = selector_from_address(sa->src.address, &protoport); |
| 1300 | } else { |
| 1301 | /* outbound; fix other end */ |
| 1302 | ip_port port = selector_port(sa->dst.client); |
| 1303 | ip_protoport protoport = protoport2(sa->transport_proto, port); |
| 1304 | dst = selector_from_address(sa->dst.address, &protoport); |
| 1305 | } |
| 1306 | |
| 1307 | /* .[sd]addr, .prefixlen_[sd], .[sd]port */ |
| 1308 | SELECTOR_TO_XFRM(&src, req.p.sel, s){ ip_selector client_ = *(&src); ip_address address = selector_prefix (&client_); (req.p.sel).saddr = xfrm_from_address(&address ); (req.p.sel).prefixlen_s = selector_maskbits(&client_); (req.p.sel).sport = nport(selector_port(&client_)); }; |
| 1309 | SELECTOR_TO_XFRM(&dst, req.p.sel, d){ ip_selector client_ = *(&dst); ip_address address = selector_prefix (&client_); (req.p.sel).daddr = xfrm_from_address(&address ); (req.p.sel).prefixlen_d = selector_maskbits(&client_); (req.p.sel).dport = nport(selector_port(&client_)); }; |
| 1310 | |
| 1311 | /* |
| 1312 | * Munge .[sd]port? |
| 1313 | * |
| 1314 | * As per RFC 4301/5996, icmp type is put in the most |
| 1315 | * significant 8 bits and icmp code is in the least |
| 1316 | * significant 8 bits of port field. Although Libreswan does |
| 1317 | * not have any configuration options for |
| 1318 | * icmp type/code values, it is possible to specify icmp type |
| 1319 | * and code using protoport option. For example, |
| 1320 | * icmp echo request (type 8/code 0) needs to be encoded as |
| 1321 | * 0x0800 in the port field and can be specified |
| 1322 | * as left/rightprotoport=icmp/2048. Now with XFRM, |
| 1323 | * icmp type and code need to be passed as source and |
| 1324 | * destination ports, respectively. Therefore, this code |
| 1325 | * extracts upper 8 bits and lower 8 bits and puts |
| 1326 | * into source and destination ports before passing to XFRM. |
| 1327 | */ |
| 1328 | if (IPPROTO_ICMPIPPROTO_ICMP == sa->transport_proto || |
| 1329 | IPPROTO_ICMPV658 == sa->transport_proto) { |
| 1330 | uint16_t icmp_type; |
| 1331 | uint16_t icmp_code; |
| 1332 | |
| 1333 | icmp_type = ntohs(req.p.sel.sport) >> 8; |
| 1334 | icmp_code = ntohs(req.p.sel.sport) & 0xFF; |
| 1335 | |
| 1336 | req.p.sel.sport = htons(icmp_type); |
| 1337 | req.p.sel.dport = htons(icmp_code); |
| 1338 | } |
| 1339 | |
| 1340 | req.p.sel.sport_mask = req.p.sel.sport == 0 ? 0 : ~0; |
| 1341 | req.p.sel.dport_mask = req.p.sel.dport == 0 ? 0 : ~0; |
| 1342 | req.p.sel.proto = sa->transport_proto; |
| 1343 | req.p.sel.family = subnet_type(&src)->af; |
| 1344 | } |
| 1345 | |
| 1346 | req.p.reqid = sa->reqid; |
| 1347 | dbg("XFRM: adding IPsec SA with reqid %d", sa->reqid){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("XFRM: adding IPsec SA with reqid %d", sa-> reqid); } }; |
| 1348 | |
| 1349 | /* TODO expose limits to kernel_sa via config */ |
| 1350 | req.p.lft.soft_byte_limit = XFRM_INF(~(__u64)0); |
| 1351 | req.p.lft.soft_packet_limit = XFRM_INF(~(__u64)0); |
| 1352 | req.p.lft.hard_byte_limit = XFRM_INF(~(__u64)0); |
| 1353 | req.p.lft.hard_packet_limit = XFRM_INF(~(__u64)0); |
| 1354 | |
| 1355 | req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.p)))( ((((sizeof(req.p)) + ((int) ( ((sizeof(struct nlmsghdr))+4U -1) & ~(4U -1) ))))+4U -1) & ~(4U -1) ); |
| 1356 | |
| 1357 | attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); |
| 1358 | |
| 1359 | /* |
| 1360 | * The Linux IPv4 AH stack aligns the AH header on a 64 bit boundary |
| 1361 | * (like in IPv6). This is not RFC compliant (see RFC4302, Section |
| 1362 | * 3.3.3.2.1), it should be aligned on 32 bits. |
| 1363 | * |
| 1364 | * For most of the authentication algorithms, the ICV size is 96 bits. |
| 1365 | * The AH header alignment on 32 or 64 bits gives the same results. |
| 1366 | * |
| 1367 | * However for SHA-256-128 for instance, the wrong 64 bit alignment results |
| 1368 | * in adding useless padding in IPv4 AH, which is forbidden by the RFC. |
| 1369 | * |
| 1370 | * To avoid breaking backward compatibility, we use a new flag |
| 1371 | * (XFRM_STATE_ALIGN4) do change original behavior. |
| 1372 | */ |
| 1373 | if (sa->esatype == ET_AH && addrtypeof(sa->src.address) == AF_INET2) { |
| 1374 | dbg("netlink: aligning IPv4 AH to 32bits as per RFC-4302, Section 3.3.3.2.1"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: aligning IPv4 AH to 32bits as per RFC-4302, Section 3.3.3.2.1" ); } }; |
| 1375 | req.p.flags |= XFRM_STATE_ALIGN464; |
| 1376 | } |
| 1377 | |
| 1378 | if (sa->esatype != ET_IPCOMP) { |
| 1379 | if (sa->esn) { |
| 1380 | dbg("netlink: enabling ESN"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: enabling ESN"); } }; |
| 1381 | req.p.flags |= XFRM_STATE_ESN128; |
| 1382 | } |
| 1383 | if (sa->decap_dscp) { |
| 1384 | dbg("netlink: enabling Decap DSCP"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: enabling Decap DSCP"); } }; |
| 1385 | req.p.flags |= XFRM_STATE_DECAP_DSCP2; |
| 1386 | } |
| 1387 | if (sa->nopmtudisc) { |
| 1388 | dbg("netlink: disabling Path MTU Discovery"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: disabling Path MTU Discovery"); } }; |
| 1389 | req.p.flags |= XFRM_STATE_NOPMTUDISC4; |
| 1390 | } |
| 1391 | |
| 1392 | if (sa->replay_window <= 32 && !sa->esn) { |
| 1393 | /* this only works up to 32, for > 32 and for ESN, we need struct xfrm_replay_state_esn */ |
| 1394 | req.p.replay_window = sa->replay_window; |
| 1395 | dbg("netlink: setting IPsec SA replay-window to %d using old-style req",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: setting IPsec SA replay-window to %d using old-style req" , req.p.replay_window); } } |
| 1396 | req.p.replay_window){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: setting IPsec SA replay-window to %d using old-style req" , req.p.replay_window); } }; |
| 1397 | } else { |
| 1398 | uint32_t bmp_size = BYTES_FOR_BITS(sa->replay_window +(((sa->replay_window + (((sizeof(uint32_t) * 8) - 1) - ((( sa->replay_window) + (sizeof(uint32_t) * 8) - 1) % (sizeof (uint32_t) * 8)))) + 8 - 1) / 8) |
| 1399 | pad_up(sa->replay_window, sizeof(uint32_t) * BITS_PER_BYTE) )(((sa->replay_window + (((sizeof(uint32_t) * 8) - 1) - ((( sa->replay_window) + (sizeof(uint32_t) * 8) - 1) % (sizeof (uint32_t) * 8)))) + 8 - 1) / 8); |
| 1400 | /* this is where we could fill in sequence numbers for this SA */ |
| 1401 | struct xfrm_replay_state_esn xre = { |
| 1402 | /* replay_window must be multiple of 8 */ |
| 1403 | .replay_window = sa->replay_window, |
| 1404 | .bmp_len = bmp_size / sizeof(uint32_t), |
| 1405 | }; |
| 1406 | dbg("netlink: setting IPsec SA replay-window to %" PRIu32 " using xfrm_replay_state_esn",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: setting IPsec SA replay-window to %" "u" " using xfrm_replay_state_esn", xre.replay_window); } } |
| 1407 | xre.replay_window){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: setting IPsec SA replay-window to %" "u" " using xfrm_replay_state_esn", xre.replay_window); } }; |
| 1408 | |
| 1409 | attr->rta_type = XFRMA_REPLAY_ESN_VAL; |
| 1410 | attr->rta_len = RTA_LENGTH(sizeof(xre) + bmp_size)(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (xre) + bmp_size)); |
| 1411 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &xre, sizeof(xre)); |
| 1412 | req.n.nlmsg_len += attr->rta_len; |
| 1413 | attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); |
| 1414 | } |
| 1415 | } |
| 1416 | |
| 1417 | if (sa->authkeylen != 0) { |
| 1418 | const char *name = sa->integ->integ_netlink_xfrm_name; |
| 1419 | if (name == NULL((void*)0)) { |
| 1420 | loglog(RC_LOG_SERIOUS, |
| 1421 | "XFRM: unknown authentication algorithm: %s", |
| 1422 | sa->integ->common.fqn); |
| 1423 | return FALSE0; |
| 1424 | } |
| 1425 | |
| 1426 | /* |
| 1427 | * According to RFC-4868 the hash should be nnn/2, so |
| 1428 | * 128 bits for SHA256 and 256 for SHA512. The XFRM |
| 1429 | * kernel uses a default of 96, which was the value in |
| 1430 | * an earlier draft. The kernel then introduced a new struct |
| 1431 | * xfrm_algo_auth to replace struct xfrm_algo to deal with |
| 1432 | * this. |
| 1433 | */ |
| 1434 | |
| 1435 | struct xfrm_algo_auth algo = { |
| 1436 | .alg_key_len = sa->integ->integ_keymat_size * BITS_PER_BYTE8, |
| 1437 | .alg_trunc_len = sa->integ->integ_output_size * BITS_PER_BYTE8, |
| 1438 | }; |
| 1439 | |
| 1440 | attr->rta_type = XFRMA_ALG_AUTH_TRUNC; |
| 1441 | attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->authkeylen)(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (algo) + sa->authkeylen)); |
| 1442 | |
| 1443 | fill_and_terminate(algo.alg_name, name, sizeof(algo.alg_name)){ strncpy((algo.alg_name), (name), (sizeof(algo.alg_name))-1) ; (algo.alg_name)[(sizeof(algo.alg_name))-1] = '\0'; }; |
| 1444 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &algo, sizeof(algo)); |
| 1445 | memcpy((char *)RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))) + sizeof(algo), |
| 1446 | sa->authkey, sa->authkeylen); |
| 1447 | |
| 1448 | req.n.nlmsg_len += attr->rta_len; |
| 1449 | attr = (struct rtattr *)((char *)attr + attr->rta_len); |
| 1450 | } |
| 1451 | |
| 1452 | /* |
| 1453 | * ??? why does IPCOMP trump aead and ESP? |
| 1454 | * Shouldn't all be bundled? |
| 1455 | */ |
| 1456 | if (sa->esatype == ET_IPCOMP) { |
| 1457 | struct xfrm_algo algo; |
| 1458 | const char *name = sparse_name(calg_list, sa->compalg); |
| 1459 | |
| 1460 | if (name == NULL((void*)0)) { |
| 1461 | loglog(RC_LOG_SERIOUS, |
| 1462 | "unknown compression algorithm: %u", |
| 1463 | sa->compalg); |
| 1464 | return FALSE0; |
| 1465 | } |
| 1466 | |
| 1467 | fill_and_terminate(algo.alg_name, name, sizeof(algo.alg_name)){ strncpy((algo.alg_name), (name), (sizeof(algo.alg_name))-1) ; (algo.alg_name)[(sizeof(algo.alg_name))-1] = '\0'; }; |
| 1468 | algo.alg_key_len = 0; |
| 1469 | |
| 1470 | attr->rta_type = XFRMA_ALG_COMP; |
| 1471 | attr->rta_len = RTA_LENGTH(sizeof(algo))(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (algo))); |
| 1472 | |
| 1473 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &algo, sizeof(algo)); |
| 1474 | |
| 1475 | req.n.nlmsg_len += attr->rta_len; |
| 1476 | attr = (struct rtattr *)((char *)attr + attr->rta_len); |
| 1477 | } else if (sa->esatype == ET_ESP) { |
| 1478 | const char *name = sa->encrypt->encrypt_netlink_xfrm_name; |
| 1479 | |
| 1480 | if (name == NULL((void*)0)) { |
| 1481 | loglog(RC_LOG_SERIOUS, |
| 1482 | "unknown encryption algorithm: %s", |
| 1483 | sa->encrypt->common.fqn); |
| 1484 | return FALSE0; |
| 1485 | } |
| 1486 | |
| 1487 | if (encrypt_desc_is_aead(sa->encrypt)) { |
| 1488 | struct xfrm_algo_aead algo; |
| 1489 | |
| 1490 | fill_and_terminate(algo.alg_name, name,{ strncpy((algo.alg_name), (name), (sizeof(algo.alg_name))-1) ; (algo.alg_name)[(sizeof(algo.alg_name))-1] = '\0'; } |
| 1491 | sizeof(algo.alg_name)){ strncpy((algo.alg_name), (name), (sizeof(algo.alg_name))-1) ; (algo.alg_name)[(sizeof(algo.alg_name))-1] = '\0'; }; |
| 1492 | algo.alg_key_len = sa->enckeylen * BITS_PER_BYTE8; |
| 1493 | algo.alg_icv_len = sa->encrypt->aead_tag_size * BITS_PER_BYTE8; |
| 1494 | |
| 1495 | attr->rta_type = XFRMA_ALG_AEAD; |
| 1496 | attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->enckeylen)(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (algo) + sa->enckeylen)); |
| 1497 | |
| 1498 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &algo, sizeof(algo)); |
| 1499 | memcpy((char *)RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))) + sizeof(algo), |
| 1500 | sa->enckey, sa->enckeylen); |
| 1501 | |
| 1502 | req.n.nlmsg_len += attr->rta_len; |
| 1503 | attr = (struct rtattr *)((char *)attr + attr->rta_len); |
| 1504 | |
| 1505 | } else { |
| 1506 | struct xfrm_algo algo; |
| 1507 | |
| 1508 | fill_and_terminate(algo.alg_name, name,{ strncpy((algo.alg_name), (name), (sizeof(algo.alg_name))-1) ; (algo.alg_name)[(sizeof(algo.alg_name))-1] = '\0'; } |
| 1509 | sizeof(algo.alg_name)){ strncpy((algo.alg_name), (name), (sizeof(algo.alg_name))-1) ; (algo.alg_name)[(sizeof(algo.alg_name))-1] = '\0'; }; |
| 1510 | algo.alg_key_len = sa->enckeylen * BITS_PER_BYTE8; |
| 1511 | |
| 1512 | attr->rta_type = XFRMA_ALG_CRYPT; |
| 1513 | attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->enckeylen)(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (algo) + sa->enckeylen)); |
| 1514 | |
| 1515 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &algo, sizeof(algo)); |
| 1516 | memcpy((char *)RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))) + sizeof(algo), |
| 1517 | sa->enckey, |
| 1518 | sa->enckeylen); |
| 1519 | |
| 1520 | req.n.nlmsg_len += attr->rta_len; |
| 1521 | attr = (struct rtattr *)((char *)attr + attr->rta_len); |
| 1522 | |
| 1523 | /* Traffic Flow Confidentiality is only for ESP tunnel mode */ |
| 1524 | if (sa->tfcpad != 0 && |
| 1525 | sa->mode == ENCAPSULATION_MODE_TUNNEL1) { |
| 1526 | dbg("netlink: setting TFC to %" PRIu32 " (up to PMTU)",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: setting TFC to %" "u" " (up to PMTU)" , sa->tfcpad); } } |
| 1527 | sa->tfcpad){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: setting TFC to %" "u" " (up to PMTU)" , sa->tfcpad); } }; |
| 1528 | |
| 1529 | attr->rta_type = XFRMA_TFCPAD; |
| 1530 | attr->rta_len = RTA_LENGTH(sizeof(sa->tfcpad))(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (sa->tfcpad))); |
| 1531 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &sa->tfcpad, sizeof(sa->tfcpad)); |
| 1532 | req.n.nlmsg_len += attr->rta_len; |
| 1533 | attr = (struct rtattr *)((char *)attr + attr->rta_len); |
| 1534 | |
| 1535 | } |
| 1536 | } |
| 1537 | } |
| 1538 | |
| 1539 | if (sa->encap_type != NULL((void*)0)) { |
| 1540 | dbg("adding xfrm-encap-tmpl when adding sa encap_type="PRI_IP_ENCAP" sport=%d dport=%d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("adding xfrm-encap-tmpl when adding sa encap_type=" "%u(%s)"" sport=%d dport=%d", (sa->encap_type) == ((void*) 0) ? 0 : (sa->encap_type)->encap_type, (sa->encap_type ) == ((void*)0) ? "none" : (sa->encap_type)->name, sa-> src.encap_port, sa->dst.encap_port); } } |
| 1541 | pri_ip_encap(sa->encap_type),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("adding xfrm-encap-tmpl when adding sa encap_type=" "%u(%s)"" sport=%d dport=%d", (sa->encap_type) == ((void*) 0) ? 0 : (sa->encap_type)->encap_type, (sa->encap_type ) == ((void*)0) ? "none" : (sa->encap_type)->name, sa-> src.encap_port, sa->dst.encap_port); } } |
| 1542 | sa->src.encap_port, sa->dst.encap_port){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("adding xfrm-encap-tmpl when adding sa encap_type=" "%u(%s)"" sport=%d dport=%d", (sa->encap_type) == ((void*) 0) ? 0 : (sa->encap_type)->encap_type, (sa->encap_type ) == ((void*)0) ? "none" : (sa->encap_type)->name, sa-> src.encap_port, sa->dst.encap_port); } }; |
| 1543 | struct xfrm_encap_tmpl natt; |
| 1544 | |
| 1545 | natt.encap_type = sa->encap_type->encap_type; |
| 1546 | natt.encap_sport = ntohs(sa->src.encap_port); |
| 1547 | natt.encap_dport = ntohs(sa->dst.encap_port); |
| 1548 | zero(&natt.encap_oa)memset((&natt.encap_oa), '\0', sizeof(*(&natt.encap_oa ))); |
| 1549 | |
| 1550 | attr->rta_type = XFRMA_ENCAP; |
| 1551 | attr->rta_len = RTA_LENGTH(sizeof(natt))(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (natt))); |
| 1552 | |
| 1553 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &natt, sizeof(natt)); |
| 1554 | |
| 1555 | req.n.nlmsg_len += attr->rta_len; |
| 1556 | attr = (struct rtattr *)((char *)attr + attr->rta_len); |
| 1557 | } |
| 1558 | |
| 1559 | if (sa->xfrm_if_id > 0) { |
| 1560 | #ifdef USE_XFRM_INTERFACE1 |
| 1561 | dbg("%s netlink: XFRMA_IF_ID %" PRIu32 " req.n.nlmsg_type=%" PRIu32,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s netlink: XFRMA_IF_ID %" "u" " req.n.nlmsg_type=%" "u", __func__, sa->xfrm_if_id, req.n.nlmsg_type); } } |
| 1562 | __func__, sa->xfrm_if_id, req.n.nlmsg_type){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s netlink: XFRMA_IF_ID %" "u" " req.n.nlmsg_type=%" "u", __func__, sa->xfrm_if_id, req.n.nlmsg_type); } }; |
| 1563 | attr->rta_type = XFRMA_IF_ID; |
| 1564 | attr->rta_len = RTA_LENGTH(sizeof(uint32_t))(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (uint32_t))); |
| 1565 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &sa->xfrm_if_id, sizeof(uint32_t)); |
| 1566 | req.n.nlmsg_len += attr->rta_len; |
| 1567 | attr = (struct rtattr *)((char *)attr + attr->rta_len); |
| 1568 | |
| 1569 | /* XFRMA_SET_MARK = XFRMA_IF_ID/0xffffffff */ |
| 1570 | attr->rta_type = XFRMA_SET_MARK; |
| 1571 | attr->rta_len = RTA_LENGTH(sizeof(uint32_t))(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (uint32_t))); |
| 1572 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &sa->xfrm_if_id, sizeof(uint32_t)); |
| 1573 | req.n.nlmsg_len += attr->rta_len; |
| 1574 | attr = (struct rtattr *)((char *)attr + attr->rta_len); |
| 1575 | #endif |
| 1576 | } |
| 1577 | |
| 1578 | if (sa->nic_offload_dev) { |
| 1579 | struct xfrm_user_offload xuo = { |
| 1580 | .flags = (sa->inbound ? XFRM_OFFLOAD_INBOUND2 : 0) | |
| 1581 | (addrtypeof(sa->src.address) == AF_INET610 ? XFRM_OFFLOAD_IPV61 : 0), |
| 1582 | .ifindex = if_nametoindex(sa->nic_offload_dev), |
| 1583 | }; |
| 1584 | |
| 1585 | attr->rta_type = XFRMA_OFFLOAD_DEV; |
| 1586 | attr->rta_len = RTA_LENGTH(sizeof(xuo))(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (sizeof (xuo))); |
| 1587 | |
| 1588 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &xuo, sizeof(xuo)); |
| 1589 | |
| 1590 | req.n.nlmsg_len += attr->rta_len; |
| 1591 | attr = (struct rtattr *)((char *)attr + attr->rta_len); |
| 1592 | dbg("netlink: esp-hw-offload set via interface %s for IPsec SA", sa->nic_offload_dev){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: esp-hw-offload set via interface %s for IPsec SA" , sa->nic_offload_dev); } }; |
| 1593 | } else { |
| 1594 | dbg("netlink: esp-hw-offload not set for IPsec SA"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink: esp-hw-offload not set for IPsec SA" ); } }; |
| 1595 | } |
| 1596 | |
| 1597 | if (sa->sec_ctx != NULL((void*)0)) { |
| 1598 | size_t len = sa->sec_ctx->ctx.ctx_len; |
| 1599 | struct xfrm_user_sec_ctx xuctx; |
| 1600 | |
| 1601 | xuctx.len = sizeof(struct xfrm_user_sec_ctx) + len; |
| 1602 | xuctx.exttype = XFRMA_SEC_CTX; |
| 1603 | xuctx.ctx_alg = 1; /* ??? sa->sec_ctx.ctx_alg? */ |
| 1604 | xuctx.ctx_doi = 1; /* ??? sa->sec_ctx.ctx_doi? */ |
| 1605 | xuctx.ctx_len = len; |
| 1606 | |
| 1607 | attr->rta_type = XFRMA_SEC_CTX; |
| 1608 | attr->rta_len = RTA_LENGTH(xuctx.len)(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (xuctx. len)); |
| 1609 | |
| 1610 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &xuctx, sizeof(xuctx)); |
| 1611 | memcpy((char *)RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))) + sizeof(xuctx), |
| 1612 | sa->sec_ctx->sec_ctx_value, len); |
| 1613 | |
| 1614 | req.n.nlmsg_len += attr->rta_len; |
| 1615 | |
| 1616 | /* attr not subsequently used */ |
| 1617 | attr = (struct rtattr *)((char *)attr + attr->rta_len); |
Value stored to 'attr' is never read | |
| 1618 | } |
| 1619 | |
| 1620 | ret = send_netlink_msg(&req.n, NLMSG_NOOP0x1, NULL((void*)0), "Add SA", sa->text_said); |
| 1621 | if (!ret && netlink_errno == ESRCH3 && |
| 1622 | req.n.nlmsg_type == XFRM_MSG_UPDSAXFRM_MSG_UPDSA) { |
| 1623 | loglog(RC_LOG_SERIOUS, |
| 1624 | "Warning: kernel expired our reserved IPsec SA SPI - negotiation took too long? Try increasing /proc/sys/net/core/xfrm_acq_expires"); |
| 1625 | } |
| 1626 | return ret; |
| 1627 | } |
| 1628 | |
| 1629 | /* |
| 1630 | * netlink_del_sa - Delete an SA from the Kernel |
| 1631 | * |
| 1632 | * @param sa Kernel SA to be deleted |
| 1633 | * @return bool True if successful |
| 1634 | */ |
| 1635 | static bool_Bool netlink_del_sa(const struct kernel_sa *sa) |
| 1636 | { |
| 1637 | struct { |
| 1638 | struct nlmsghdr n; |
| 1639 | struct xfrm_usersa_id id; |
| 1640 | char data[MAX_NETLINK_DATA_SIZE8192]; |
| 1641 | } req; |
| 1642 | |
| 1643 | zero(&req)memset((&req), '\0', sizeof(*(&req))); |
| 1644 | req.n.nlmsg_flags = NLM_F_REQUEST0x01 | NLM_F_ACK0x04; |
| 1645 | req.n.nlmsg_type = XFRM_MSG_DELSAXFRM_MSG_DELSA; |
| 1646 | |
| 1647 | req.id.daddr = xfrm_from_address(sa->dst.address); |
| 1648 | |
| 1649 | req.id.spi = sa->spi; |
| 1650 | req.id.family = addrtypeof(sa->src.address); |
| 1651 | req.id.proto = sa->proto->ipproto; |
| 1652 | |
| 1653 | req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)))( ((((sizeof(req.id)) + ((int) ( ((sizeof(struct nlmsghdr))+4U -1) & ~(4U -1) ))))+4U -1) & ~(4U -1) ); |
| 1654 | |
| 1655 | dbg("XFRM: deleting IPsec SA with reqid %d", sa->reqid){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("XFRM: deleting IPsec SA with reqid %d", sa-> reqid); } }; |
| 1656 | |
| 1657 | return send_netlink_msg(&req.n, NLMSG_NOOP0x1, NULL((void*)0), "Del SA", sa->text_said); |
| 1658 | } |
| 1659 | |
| 1660 | /* |
| 1661 | * Create ip_address out of xfrm_address_t. |
| 1662 | * |
| 1663 | * @param family |
| 1664 | * @param src xfrm formatted IP address |
| 1665 | * @param dst ip_address formatted destination |
| 1666 | * @return err_t NULL if okay, otherwise an error |
| 1667 | */ |
| 1668 | static ip_address address_from_xfrm(const struct ip_info *afi, |
| 1669 | const xfrm_address_t *xaddr) |
| 1670 | { |
| 1671 | /* .len == ipv6 size */ |
| 1672 | shunk_t x = THING_AS_SHUNK(*xaddr)shunk2(&(*xaddr), sizeof(*xaddr)); |
| 1673 | |
| 1674 | ip_address addr = afi->any_address; /* "zero" it & set type */ |
| 1675 | chunk_t a = address_as_chunk(&addr); |
| 1676 | |
| 1677 | /* a = x */ |
| 1678 | passert(a.len <= x.len){ _Bool assertion__ = a.len <= x.len; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "kernel_xfrm.c" , . line = 1678}, "%s", "a.len <= x.len"); } }; |
| 1679 | memcpy(a.ptr, x.ptr, a.len); |
| 1680 | |
| 1681 | return addr; |
| 1682 | } |
| 1683 | |
| 1684 | /* |
| 1685 | * Create ip_selector / ip_client out of xfrm_address_t:NPORT. |
| 1686 | */ |
| 1687 | |
| 1688 | static ip_selector selector_from_xfrm(const struct ip_info *afi, unsigned ipproto, |
| 1689 | const xfrm_address_t *src, uint16_t nport) |
| 1690 | { |
| 1691 | ip_address address = address_from_xfrm(afi, src); |
| 1692 | ip_protoport protoport = protoport2(ipproto, ip_nport(nport)); |
| 1693 | return selector_from_address(&address, &protoport); |
| 1694 | } |
| 1695 | |
| 1696 | static void netlink_acquire(struct nlmsghdr *n) |
| 1697 | { |
| 1698 | struct xfrm_user_acquire *acquire; |
| 1699 | struct xfrm_user_sec_ctx_ike *uctx = NULL((void*)0); |
| 1700 | struct xfrm_user_sec_ctx_ike uctx_space; |
| 1701 | |
| 1702 | dbg("xfrm netlink msg len %zu", (size_t) n->nlmsg_len){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("xfrm netlink msg len %zu", (size_t) n->nlmsg_len ); } }; |
| 1703 | |
| 1704 | if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*acquire))((sizeof(*acquire)) + ((int) ( ((sizeof(struct nlmsghdr))+4U - 1) & ~(4U -1) )))) { |
| 1705 | libreswan_log(loglog(RC_LOG, "netlink_acquire got message with length %zu < %zu bytes; ignore message" , (size_t) n->nlmsg_len, sizeof(*acquire)) |
| 1706 | "netlink_acquire got message with length %zu < %zu bytes; ignore message",loglog(RC_LOG, "netlink_acquire got message with length %zu < %zu bytes; ignore message" , (size_t) n->nlmsg_len, sizeof(*acquire)) |
| 1707 | (size_t) n->nlmsg_len,loglog(RC_LOG, "netlink_acquire got message with length %zu < %zu bytes; ignore message" , (size_t) n->nlmsg_len, sizeof(*acquire)) |
| 1708 | sizeof(*acquire))loglog(RC_LOG, "netlink_acquire got message with length %zu < %zu bytes; ignore message" , (size_t) n->nlmsg_len, sizeof(*acquire)); |
| 1709 | return; |
| 1710 | } |
| 1711 | |
| 1712 | /* |
| 1713 | * WARNING: netlink only guarantees 32-bit alignment. |
| 1714 | * See NLMSG_ALIGNTO in the kernel's include/uapi/linux/netlink.h. |
| 1715 | * BUT some fields in struct xfrm_user_acquire are 64-bit and so access |
| 1716 | * may be improperly aligned. This will fail on a few strict |
| 1717 | * architectures (it does break C rules). |
| 1718 | * |
| 1719 | * WARNING: this code's understanding to the XFRM netlink |
| 1720 | * messages is from programs/pluto/linux26/xfrm.h. |
| 1721 | * There is no guarantee that this matches the kernel's |
| 1722 | * understanding. |
| 1723 | * |
| 1724 | * Many things are defined to be int or unsigned int. |
| 1725 | * This isn't safe when the kernel and userland may |
| 1726 | * be compiled with different models. |
| 1727 | */ |
| 1728 | acquire = NLMSG_DATA(n)((void*)(((char*)n) + ((0) + ((int) ( ((sizeof(struct nlmsghdr ))+4U -1) & ~(4U -1) ))))); /* insufficiently aligned */ |
| 1729 | |
| 1730 | const struct ip_info *afi = aftoinfo(acquire->policy.sel.family); |
| 1731 | if (afi == NULL((void*)0)) { |
| 1732 | libreswan_log("XFRM_MSG_ACQUIRE message from kernel malformed: family %u unknown",loglog(RC_LOG, "XFRM_MSG_ACQUIRE message from kernel malformed: family %u unknown" , acquire->policy.sel.family) |
| 1733 | acquire->policy.sel.family)loglog(RC_LOG, "XFRM_MSG_ACQUIRE message from kernel malformed: family %u unknown" , acquire->policy.sel.family); |
| 1734 | return; |
| 1735 | } |
| 1736 | ip_selector ours = selector_from_xfrm(afi, acquire->sel.proto, |
| 1737 | &acquire->sel.saddr, |
| 1738 | acquire->sel.sport); |
| 1739 | ip_selector theirs = selector_from_xfrm(afi, acquire->sel.proto, |
| 1740 | &acquire->sel.daddr, |
| 1741 | acquire->sel.dport); |
| 1742 | |
| 1743 | /* |
| 1744 | * Run through rtattributes looking for XFRMA_SEC_CTX |
| 1745 | * Instead, it should loop through all (known rtattributes |
| 1746 | * and use/log them. |
| 1747 | */ |
| 1748 | struct rtattr *attr = (struct rtattr *) |
| 1749 | ((char*) NLMSG_DATA(n)((void*)(((char*)n) + ((0) + ((int) ( ((sizeof(struct nlmsghdr ))+4U -1) & ~(4U -1) ))))) + |
| 1750 | NLMSG_ALIGN(sizeof(struct xfrm_user_acquire))( ((sizeof(struct xfrm_user_acquire))+4U -1) & ~(4U -1) )); |
| 1751 | size_t remaining = n->nlmsg_len - |
| 1752 | NLMSG_SPACE(sizeof(struct xfrm_user_acquire))( ((((sizeof(struct xfrm_user_acquire)) + ((int) ( ((sizeof(struct nlmsghdr))+4U -1) & ~(4U -1) ))))+4U -1) & ~(4U -1) ); |
| 1753 | |
| 1754 | while (remaining > 0) { |
| 1755 | dbg("xfrm acquire rtattribute type %u ...", attr->rta_type){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("xfrm acquire rtattribute type %u ...", attr-> rta_type); } }; |
| 1756 | switch (attr->rta_type) { |
| 1757 | case XFRMA_TMPL: |
| 1758 | { |
| 1759 | struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl *) RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))); |
| 1760 | dbg("... xfrm template attribute with reqid:%d, spi:%d, proto:%d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("... xfrm template attribute with reqid:%d, spi:%d, proto:%d" , tmpl->reqid, tmpl->id.spi, tmpl->id.proto); } } |
| 1761 | tmpl->reqid, tmpl->id.spi, tmpl->id.proto){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("... xfrm template attribute with reqid:%d, spi:%d, proto:%d" , tmpl->reqid, tmpl->id.spi, tmpl->id.proto); } }; |
| 1762 | break; |
| 1763 | } |
| 1764 | case XFRMA_POLICY_TYPE: |
| 1765 | /* discard */ |
| 1766 | dbg("... xfrm policy type ignored"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("... xfrm policy type ignored"); } }; |
| 1767 | break; |
| 1768 | case XFRMA_SEC_CTX: |
| 1769 | { |
| 1770 | struct xfrm_user_sec_ctx *xuctx = (struct xfrm_user_sec_ctx *) RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))); |
| 1771 | /* length of text of label */ |
| 1772 | size_t len = xuctx->ctx_len; |
| 1773 | |
| 1774 | dbg("... xfrm xuctx: exttype=%d, len=%d, ctx_doi=%d, ctx_alg=%d, ctx_len=%zu",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("... xfrm xuctx: exttype=%d, len=%d, ctx_doi=%d, ctx_alg=%d, ctx_len=%zu" , xuctx->exttype, xuctx->len, xuctx->ctx_doi, xuctx-> ctx_alg, len); } } |
| 1775 | xuctx->exttype, xuctx->len,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("... xfrm xuctx: exttype=%d, len=%d, ctx_doi=%d, ctx_alg=%d, ctx_len=%zu" , xuctx->exttype, xuctx->len, xuctx->ctx_doi, xuctx-> ctx_alg, len); } } |
| 1776 | xuctx->ctx_doi, xuctx->ctx_alg,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("... xfrm xuctx: exttype=%d, len=%d, ctx_doi=%d, ctx_alg=%d, ctx_len=%zu" , xuctx->exttype, xuctx->len, xuctx->ctx_doi, xuctx-> ctx_alg, len); } } |
| 1777 | len){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("... xfrm xuctx: exttype=%d, len=%d, ctx_doi=%d, ctx_alg=%d, ctx_len=%zu" , xuctx->exttype, xuctx->len, xuctx->ctx_doi, xuctx-> ctx_alg, len); } }; |
| 1778 | |
| 1779 | if (uctx != NULL((void*)0)) { |
| 1780 | libreswan_log("Second Sec Ctx label in a single Acquire message; ignoring Acquire message")loglog(RC_LOG, "Second Sec Ctx label in a single Acquire message; ignoring Acquire message" ); |
| 1781 | return; |
| 1782 | } |
| 1783 | |
| 1784 | if (len > MAX_SECCTX_LEN4096) { |
| 1785 | libreswan_log("Sec Ctx label of length %zu, longer than MAX_SECCTX_LEN; ignoring Acquire message",loglog(RC_LOG, "Sec Ctx label of length %zu, longer than MAX_SECCTX_LEN; ignoring Acquire message" , len) |
| 1786 | len)loglog(RC_LOG, "Sec Ctx label of length %zu, longer than MAX_SECCTX_LEN; ignoring Acquire message" , len); |
| 1787 | return; |
| 1788 | } |
| 1789 | |
| 1790 | /* |
| 1791 | * note: xuctx + 1 is tricky: |
| 1792 | * first byte after header |
| 1793 | */ |
| 1794 | dbg("xfrm: xuctx security context value: %.*s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("xfrm: xuctx security context value: %.*s", xuctx ->ctx_len, (const char *) (xuctx + 1)); } } |
| 1795 | xuctx->ctx_len,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("xfrm: xuctx security context value: %.*s", xuctx ->ctx_len, (const char *) (xuctx + 1)); } } |
| 1796 | (const char *) (xuctx + 1)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("xfrm: xuctx security context value: %.*s", xuctx ->ctx_len, (const char *) (xuctx + 1)); } }; |
| 1797 | |
| 1798 | zero(&uctx_space)memset((&uctx_space), '\0', sizeof(*(&uctx_space))); |
| 1799 | uctx = &uctx_space; |
| 1800 | |
| 1801 | memcpy(uctx->sec_ctx_value, (xuctx + 1), |
| 1802 | xuctx->ctx_len); |
| 1803 | |
| 1804 | if (len == 0 || uctx->sec_ctx_value[len-1] != '\0') { |
| 1805 | if (len == MAX_SECCTX_LEN4096) { |
| 1806 | libreswan_log("Sec Ctx label missing final NUL and too long to add; ignoring Acquire message")loglog(RC_LOG, "Sec Ctx label missing final NUL and too long to add; ignoring Acquire message" ); |
| 1807 | return; |
| 1808 | } |
| 1809 | libreswan_log("Sec Ctx label missing final NUL; we're adding it")loglog(RC_LOG, "Sec Ctx label missing final NUL; we're adding it" ); |
| 1810 | uctx->sec_ctx_value[len] = '\0'; |
| 1811 | len++; |
| 1812 | } |
| 1813 | |
| 1814 | if (strlen(uctx->sec_ctx_value) + 1 != len) { |
| 1815 | libreswan_log("Sec Ctx label contains embedded NUL; ignoring Acquire message")loglog(RC_LOG, "Sec Ctx label contains embedded NUL; ignoring Acquire message" ); |
| 1816 | return; |
| 1817 | } |
| 1818 | |
| 1819 | uctx->ctx.ctx_alg = xuctx->ctx_alg; |
| 1820 | uctx->ctx.ctx_doi = xuctx->ctx_doi; |
| 1821 | /* Length includes '\0'*/ |
| 1822 | uctx->ctx.ctx_len = len; |
| 1823 | |
| 1824 | break; |
| 1825 | } |
| 1826 | default: |
| 1827 | dbg("... ignoring unknown xfrm acquire payload type %u",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("... ignoring unknown xfrm acquire payload type %u" , attr->rta_type); } } |
| 1828 | attr->rta_type){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("... ignoring unknown xfrm acquire payload type %u" , attr->rta_type); } }; |
| 1829 | break; |
| 1830 | } |
| 1831 | /* updates remaining too */ |
| 1832 | attr = RTA_NEXT(attr, remaining)((remaining) -= ( (((attr)->rta_len)+4U -1) & ~(4U -1) ), (struct rtattr*)(((char*)(attr)) + ( (((attr)->rta_len )+4U -1) & ~(4U -1) ))); |
| 1833 | } |
| 1834 | |
| 1835 | /* |
| 1836 | * XXX also the type of src/dst should be checked to make sure |
| 1837 | * that they aren't v4 to v6 or something goofy |
| 1838 | */ |
| 1839 | record_and_initiate_opportunistic(&ours, &theirs, |
| 1840 | acquire->sel.proto, uctx, |
| 1841 | "%acquire-netlink"); |
| 1842 | } |
| 1843 | |
| 1844 | static void netlink_shunt_expire(struct xfrm_userpolicy_info *pol) |
| 1845 | { |
| 1846 | const xfrm_address_t *srcx = &pol->sel.saddr; |
| 1847 | const xfrm_address_t *dstx = &pol->sel.daddr; |
| 1848 | unsigned transport_proto = pol->sel.proto; |
| 1849 | |
| 1850 | const struct ip_info *afi = aftoinfo(pol->sel.family); |
| 1851 | if (afi == NULL((void*)0)) { |
| 1852 | libreswan_log("XFRM_MSG_POLEXPIRE message from kernel malformed: address family %u unknown",loglog(RC_LOG, "XFRM_MSG_POLEXPIRE message from kernel malformed: address family %u unknown" , pol->sel.family) |
| 1853 | pol->sel.family)loglog(RC_LOG, "XFRM_MSG_POLEXPIRE message from kernel malformed: address family %u unknown" , pol->sel.family); |
| 1854 | return; |
| 1855 | } |
| 1856 | |
| 1857 | ip_address src = address_from_xfrm(afi, srcx); |
| 1858 | ip_address dst = address_from_xfrm(afi, dstx); |
| 1859 | |
| 1860 | if (delete_bare_shunt(&src, &dst, |
| 1861 | transport_proto, SPI_HOLD259 /* why spi to use? */, |
| 1862 | "delete expired bare shunt")) { |
| 1863 | dbg("netlink_shunt_expire() called delete_bare_shunt() with success"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_shunt_expire() called delete_bare_shunt() with success" ); } }; |
| 1864 | } else { |
| 1865 | libreswan_log("netlink_shunt_expire() called delete_bare_shunt() which failed!")loglog(RC_LOG, "netlink_shunt_expire() called delete_bare_shunt() which failed!" ); |
| 1866 | } |
| 1867 | } |
| 1868 | |
| 1869 | static void process_addr_chage(struct nlmsghdr *n) |
| 1870 | { |
| 1871 | struct ifaddrmsg *nl_msg = NLMSG_DATA(n)((void*)(((char*)n) + ((0) + ((int) ( ((sizeof(struct nlmsghdr ))+4U -1) & ~(4U -1) ))))); |
| 1872 | struct rtattr *rta = IFLA_RTA(nl_msg)((struct rtattr*)(((char*)(nl_msg)) + ( ((sizeof(struct ifinfomsg ))+4U -1) & ~(4U -1) ))); |
| 1873 | size_t msg_size = IFA_PAYLOAD (n)((n)->nlmsg_len - ( (((((sizeof(struct ifaddrmsg))) + ((int ) ( ((sizeof(struct nlmsghdr))+4U -1) & ~(4U -1) ))))+4U - 1) & ~(4U -1) )); |
| 1874 | ip_address ip; |
| 1875 | |
| 1876 | dbg("xfrm netlink address change %s msg len %zu",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("xfrm netlink address change %s msg len %zu", sparse_val_show (rtm_type_names, n->nlmsg_type), (size_t) n->nlmsg_len) ; } } |
| 1877 | sparse_val_show(rtm_type_names, n->nlmsg_type),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("xfrm netlink address change %s msg len %zu", sparse_val_show (rtm_type_names, n->nlmsg_type), (size_t) n->nlmsg_len) ; } } |
| 1878 | (size_t) n->nlmsg_len){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("xfrm netlink address change %s msg len %zu", sparse_val_show (rtm_type_names, n->nlmsg_type), (size_t) n->nlmsg_len) ; } }; |
| 1879 | |
| 1880 | while (RTA_OK(rta, msg_size)((msg_size) >= (int)sizeof(struct rtattr) && (rta) ->rta_len >= sizeof(struct rtattr) && (rta)-> rta_len <= (msg_size))) { |
| 1881 | err_t ugh; |
| 1882 | |
| 1883 | switch (rta->rta_type) { |
| 1884 | case IFA_LOCAL: |
| 1885 | ugh = data_to_address(RTA_DATA(rta)((void*)(((char*)(rta)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), RTA_PAYLOAD(rta)((int)((rta)->rta_len) - (( ((sizeof(struct rtattr))+4U -1 ) & ~(4U -1) ) + (0)))/*size*/, |
| 1886 | aftoinfo(nl_msg->ifa_family), &ip); |
| 1887 | if (ugh != NULL((void*)0)) { |
| 1888 | libreswan_log("ERROR IFA_LOCAL invalid %s", ugh)loglog(RC_LOG, "ERROR IFA_LOCAL invalid %s", ugh); |
| 1889 | } else { |
| 1890 | if (n->nlmsg_type == RTM_DELADDRRTM_DELADDR) |
| 1891 | record_deladdr(&ip, "IFA_LOCAL"); |
| 1892 | else if (n->nlmsg_type == RTM_NEWADDRRTM_NEWADDR) |
| 1893 | record_newaddr(&ip, "IFA_LOCAL"); |
| 1894 | } |
| 1895 | break; |
| 1896 | |
| 1897 | case IFA_ADDRESS: |
| 1898 | ugh = data_to_address(RTA_DATA(rta)((void*)(((char*)(rta)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), RTA_PAYLOAD(rta)((int)((rta)->rta_len) - (( ((sizeof(struct rtattr))+4U -1 ) & ~(4U -1) ) + (0)))/*size*/, |
| 1899 | aftoinfo(nl_msg->ifa_family), &ip); |
| 1900 | if (ugh != NULL((void*)0)) { |
| 1901 | libreswan_log("ERROR IFA_ADDRESS invalid %s", ugh)loglog(RC_LOG, "ERROR IFA_ADDRESS invalid %s", ugh); |
| 1902 | } else { |
| 1903 | address_buf ip_str; |
| 1904 | dbg("XFRM IFA_ADDRESS %s IFA_ADDRESS is this PPP?",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("XFRM IFA_ADDRESS %s IFA_ADDRESS is this PPP?" , str_address(&ip, &ip_str)); } } |
| 1905 | str_address(&ip, &ip_str)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("XFRM IFA_ADDRESS %s IFA_ADDRESS is this PPP?" , str_address(&ip, &ip_str)); } }; |
| 1906 | } |
| 1907 | break; |
| 1908 | |
| 1909 | default: |
| 1910 | dbg("IKEv2 received address %s type %u",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("IKEv2 received address %s type %u", sparse_val_show (rtm_type_names, n->nlmsg_type), rta->rta_type); } } |
| 1911 | sparse_val_show(rtm_type_names, n->nlmsg_type),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("IKEv2 received address %s type %u", sparse_val_show (rtm_type_names, n->nlmsg_type), rta->rta_type); } } |
| 1912 | rta->rta_type){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("IKEv2 received address %s type %u", sparse_val_show (rtm_type_names, n->nlmsg_type), rta->rta_type); } }; |
| 1913 | break; |
| 1914 | } |
| 1915 | |
| 1916 | rta = RTA_NEXT(rta, msg_size)((msg_size) -= ( (((rta)->rta_len)+4U -1) & ~(4U -1) ) , (struct rtattr*)(((char*)(rta)) + ( (((rta)->rta_len)+4U -1) & ~(4U -1) ))); |
| 1917 | } |
| 1918 | } |
| 1919 | |
| 1920 | static void netlink_policy_expire(struct nlmsghdr *n) |
| 1921 | { |
| 1922 | struct xfrm_user_polexpire *upe; |
| 1923 | ip_address src, dst; |
| 1924 | |
| 1925 | struct { |
| 1926 | struct nlmsghdr n; |
| 1927 | struct xfrm_userpolicy_id id; |
| 1928 | } req; |
| 1929 | struct nlm_resp rsp; |
| 1930 | |
| 1931 | if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*upe))((sizeof(*upe)) + ((int) ( ((sizeof(struct nlmsghdr))+4U -1) & ~(4U -1) )))) { |
| 1932 | libreswan_log(loglog(RC_LOG, "netlink_policy_expire got message with length %zu < %zu bytes; ignore message" , (size_t) n->nlmsg_len, sizeof(*upe)) |
| 1933 | "netlink_policy_expire got message with length %zu < %zu bytes; ignore message",loglog(RC_LOG, "netlink_policy_expire got message with length %zu < %zu bytes; ignore message" , (size_t) n->nlmsg_len, sizeof(*upe)) |
| 1934 | (size_t) n->nlmsg_len,loglog(RC_LOG, "netlink_policy_expire got message with length %zu < %zu bytes; ignore message" , (size_t) n->nlmsg_len, sizeof(*upe)) |
| 1935 | sizeof(*upe))loglog(RC_LOG, "netlink_policy_expire got message with length %zu < %zu bytes; ignore message" , (size_t) n->nlmsg_len, sizeof(*upe)); |
| 1936 | return; |
| 1937 | } |
| 1938 | |
| 1939 | upe = NLMSG_DATA(n)((void*)(((char*)n) + ((0) + ((int) ( ((sizeof(struct nlmsghdr ))+4U -1) & ~(4U -1) ))))); |
| 1940 | xfrm2ip(&upe->pol.sel.saddr, &src, upe->pol.sel.family); |
| 1941 | xfrm2ip(&upe->pol.sel.daddr, &dst, upe->pol.sel.family); |
| 1942 | address_buf a; |
| 1943 | address_buf b; |
| 1944 | dbg("%s src %s/%u dst %s/%u dir %d index %d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s src %s/%u dst %s/%u dir %d index %d", __func__ , str_address(&src, &a), upe->pol.sel.prefixlen_s, str_address(&dst, &b), upe->pol.sel.prefixlen_d, upe ->pol.dir, upe->pol.index); } } |
| 1945 | __func__,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s src %s/%u dst %s/%u dir %d index %d", __func__ , str_address(&src, &a), upe->pol.sel.prefixlen_s, str_address(&dst, &b), upe->pol.sel.prefixlen_d, upe ->pol.dir, upe->pol.index); } } |
| 1946 | str_address(&src, &a), upe->pol.sel.prefixlen_s,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s src %s/%u dst %s/%u dir %d index %d", __func__ , str_address(&src, &a), upe->pol.sel.prefixlen_s, str_address(&dst, &b), upe->pol.sel.prefixlen_d, upe ->pol.dir, upe->pol.index); } } |
| 1947 | str_address(&dst, &b), upe->pol.sel.prefixlen_d,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s src %s/%u dst %s/%u dir %d index %d", __func__ , str_address(&src, &a), upe->pol.sel.prefixlen_s, str_address(&dst, &b), upe->pol.sel.prefixlen_d, upe ->pol.dir, upe->pol.index); } } |
| 1948 | upe->pol.dir, upe->pol.index){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s src %s/%u dst %s/%u dir %d index %d", __func__ , str_address(&src, &a), upe->pol.sel.prefixlen_s, str_address(&dst, &b), upe->pol.sel.prefixlen_d, upe ->pol.dir, upe->pol.index); } }; |
| 1949 | |
| 1950 | req.id.dir = upe->pol.dir; |
| 1951 | req.id.index = upe->pol.index; |
| 1952 | req.n.nlmsg_flags = NLM_F_REQUEST0x01; |
| 1953 | req.n.nlmsg_type = XFRM_MSG_GETPOLICYXFRM_MSG_GETPOLICY; |
| 1954 | req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)))( ((((sizeof(req.id)) + ((int) ( ((sizeof(struct nlmsghdr))+4U -1) & ~(4U -1) ))))+4U -1) & ~(4U -1) ); |
| 1955 | |
| 1956 | if (!send_netlink_msg(&req.n, XFRM_MSG_NEWPOLICYXFRM_MSG_NEWPOLICY, &rsp, "Get policy", "?")) { |
| 1957 | dbg("netlink_policy_expire: policy died on us: dir=%d, index=%d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_policy_expire: policy died on us: dir=%d, index=%d" , req.id.dir, req.id.index); } } |
| 1958 | req.id.dir, req.id.index){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_policy_expire: policy died on us: dir=%d, index=%d" , req.id.dir, req.id.index); } }; |
| 1959 | } else if (rsp.n.nlmsg_len < NLMSG_LENGTH(sizeof(rsp.u.pol))((sizeof(rsp.u.pol)) + ((int) ( ((sizeof(struct nlmsghdr))+4U -1) & ~(4U -1) )))) { |
| 1960 | libreswan_log(loglog(RC_LOG, "netlink_policy_expire: XFRM_MSG_GETPOLICY returned message with length %zu < %zu bytes; ignore message" , (size_t) rsp.n.nlmsg_len, sizeof(rsp.u.pol)) |
| 1961 | "netlink_policy_expire: XFRM_MSG_GETPOLICY returned message with length %zu < %zu bytes; ignore message",loglog(RC_LOG, "netlink_policy_expire: XFRM_MSG_GETPOLICY returned message with length %zu < %zu bytes; ignore message" , (size_t) rsp.n.nlmsg_len, sizeof(rsp.u.pol)) |
| 1962 | (size_t) rsp.n.nlmsg_len,loglog(RC_LOG, "netlink_policy_expire: XFRM_MSG_GETPOLICY returned message with length %zu < %zu bytes; ignore message" , (size_t) rsp.n.nlmsg_len, sizeof(rsp.u.pol)) |
| 1963 | sizeof(rsp.u.pol))loglog(RC_LOG, "netlink_policy_expire: XFRM_MSG_GETPOLICY returned message with length %zu < %zu bytes; ignore message" , (size_t) rsp.n.nlmsg_len, sizeof(rsp.u.pol)); |
| 1964 | } else if (req.id.index != rsp.u.pol.index) { |
| 1965 | dbg("netlink_policy_expire: policy was replaced: dir=%d, oldindex=%d, newindex=%d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_policy_expire: policy was replaced: dir=%d, oldindex=%d, newindex=%d" , req.id.dir, req.id.index, rsp.u.pol.index); } } |
| 1966 | req.id.dir, req.id.index, rsp.u.pol.index){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_policy_expire: policy was replaced: dir=%d, oldindex=%d, newindex=%d" , req.id.dir, req.id.index, rsp.u.pol.index); } }; |
| 1967 | } else if (upe->pol.curlft.add_time != rsp.u.pol.curlft.add_time) { |
| 1968 | dbg("netlink_policy_expire: policy was replaced and you have won the lottery: dir=%d, index=%d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_policy_expire: policy was replaced and you have won the lottery: dir=%d, index=%d" , req.id.dir, req.id.index); } } |
| 1969 | req.id.dir, req.id.index){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_policy_expire: policy was replaced and you have won the lottery: dir=%d, index=%d" , req.id.dir, req.id.index); } }; |
| 1970 | } else { |
| 1971 | switch (upe->pol.dir) { |
| 1972 | case XFRM_POLICY_OUT: |
| 1973 | netlink_shunt_expire(&rsp.u.pol); |
| 1974 | break; |
| 1975 | } |
| 1976 | } |
| 1977 | } |
| 1978 | |
| 1979 | /* returns FALSE iff EAGAIN */ |
| 1980 | static bool_Bool netlink_get(int fd) |
| 1981 | { |
| 1982 | struct nlm_resp rsp; |
| 1983 | struct sockaddr_nl addr; |
| 1984 | socklen_t alen = sizeof(addr); |
| 1985 | ssize_t r = recvfrom(fd, &rsp, sizeof(rsp), 0, |
| 1986 | (struct sockaddr *)&addr, &alen); |
| 1987 | |
| 1988 | if (r < 0) { |
| 1989 | if (errno(*__errno_location ()) == EAGAIN11) |
| 1990 | return FALSE0; |
| 1991 | |
| 1992 | if (errno(*__errno_location ()) != EINTR4) { |
| 1993 | LOG_ERRNO(errno, "recvfrom() failed in netlink_get: errno(%d): %s",{ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "recvfrom() failed in netlink_get: errno(%d): %s", (*__errno_location ()), strerror((*__errno_location ()))); jam_string(buf, ".") ; jam(buf, " ""Errno %d: %s", (e_), strerror(e_)); jambuf_to_error_stream (buf); } } |
| 1994 | errno, strerror(errno)){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "recvfrom() failed in netlink_get: errno(%d): %s", (*__errno_location ()), strerror((*__errno_location ()))); jam_string(buf, ".") ; jam(buf, " ""Errno %d: %s", (e_), strerror(e_)); jambuf_to_error_stream (buf); } }; |
| 1995 | } |
| 1996 | return TRUE1; |
| 1997 | } else if ((size_t)r < sizeof(rsp.n)) { |
| 1998 | libreswan_log(loglog(RC_LOG, "netlink_get read truncated message: %zd bytes; ignore message" , r) |
| 1999 | "netlink_get read truncated message: %zd bytes; ignore message",loglog(RC_LOG, "netlink_get read truncated message: %zd bytes; ignore message" , r) |
| 2000 | r)loglog(RC_LOG, "netlink_get read truncated message: %zd bytes; ignore message" , r); |
| 2001 | return TRUE1; |
| 2002 | } else if (addr.nl_pid != 0) { |
| 2003 | /* not for us: ignore */ |
| 2004 | dbg("netlink_get: ignoring %s message from process %u",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_get: ignoring %s message from process %u" , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type), addr.nl_pid ); } } |
| 2005 | sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_get: ignoring %s message from process %u" , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type), addr.nl_pid ); } } |
| 2006 | addr.nl_pid){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_get: ignoring %s message from process %u" , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type), addr.nl_pid ); } }; |
| 2007 | return TRUE1; |
| 2008 | } else if ((size_t)r != rsp.n.nlmsg_len) { |
| 2009 | libreswan_log(loglog(RC_LOG, "netlink_get read message with length %zd that doesn't equal nlmsg_len %zu bytes; ignore message" , r, (size_t) rsp.n.nlmsg_len) |
| 2010 | "netlink_get read message with length %zd that doesn't equal nlmsg_len %zu bytes; ignore message",loglog(RC_LOG, "netlink_get read message with length %zd that doesn't equal nlmsg_len %zu bytes; ignore message" , r, (size_t) rsp.n.nlmsg_len) |
| 2011 | r, (size_t) rsp.n.nlmsg_len)loglog(RC_LOG, "netlink_get read message with length %zd that doesn't equal nlmsg_len %zu bytes; ignore message" , r, (size_t) rsp.n.nlmsg_len); |
| 2012 | return TRUE1; |
| 2013 | } |
| 2014 | |
| 2015 | dbg("netlink_get: %s message",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_get: %s message", sparse_val_show(xfrm_type_names , rsp.n.nlmsg_type)); } } |
| 2016 | sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_get: %s message", sparse_val_show(xfrm_type_names , rsp.n.nlmsg_type)); } }; |
| 2017 | |
| 2018 | switch (rsp.n.nlmsg_type) { |
| 2019 | case XFRM_MSG_ACQUIREXFRM_MSG_ACQUIRE: |
| 2020 | netlink_acquire(&rsp.n); |
| 2021 | break; |
| 2022 | case XFRM_MSG_POLEXPIREXFRM_MSG_POLEXPIRE: |
| 2023 | netlink_policy_expire(&rsp.n); |
| 2024 | break; |
| 2025 | |
| 2026 | case RTM_NEWADDRRTM_NEWADDR: |
| 2027 | process_addr_chage(&rsp.n); |
| 2028 | break; |
| 2029 | |
| 2030 | case RTM_DELADDRRTM_DELADDR: |
| 2031 | process_addr_chage(&rsp.n); |
| 2032 | break; |
| 2033 | |
| 2034 | default: |
| 2035 | /* ignored */ |
| 2036 | break; |
| 2037 | } |
| 2038 | |
| 2039 | return TRUE1; |
| 2040 | } |
| 2041 | |
| 2042 | static void netlink_process_msg(int fd) |
| 2043 | { |
| 2044 | do {} while (netlink_get(fd)); |
| 2045 | } |
| 2046 | |
| 2047 | static ipsec_spi_t netlink_get_spi(const ip_address *src, |
| 2048 | const ip_address *dst, |
| 2049 | const struct ip_protocol *proto, |
| 2050 | bool_Bool tunnel_mode, |
| 2051 | reqid_t reqid, |
| 2052 | ipsec_spi_t min, |
| 2053 | ipsec_spi_t max, |
| 2054 | const char *text_said) |
| 2055 | { |
| 2056 | struct { |
| 2057 | struct nlmsghdr n; |
| 2058 | struct xfrm_userspi_info spi; |
| 2059 | } req; |
| 2060 | struct nlm_resp rsp; |
| 2061 | |
| 2062 | zero(&req)memset((&req), '\0', sizeof(*(&req))); |
| 2063 | req.n.nlmsg_flags = NLM_F_REQUEST0x01; |
| 2064 | req.n.nlmsg_type = XFRM_MSG_ALLOCSPIXFRM_MSG_ALLOCSPI; |
| 2065 | |
| 2066 | req.spi.info.saddr = xfrm_from_address(src); |
| 2067 | req.spi.info.id.daddr = xfrm_from_address(dst); |
| 2068 | req.spi.info.mode = tunnel_mode; |
| 2069 | req.spi.info.reqid = reqid; |
| 2070 | req.spi.info.id.proto = proto->ipproto; |
| 2071 | req.spi.info.family = addrtypeof(src); |
| 2072 | |
| 2073 | req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.spi)))( ((((sizeof(req.spi)) + ((int) ( ((sizeof(struct nlmsghdr))+ 4U -1) & ~(4U -1) ))))+4U -1) & ~(4U -1) ); |
| 2074 | |
| 2075 | req.spi.min = min; |
| 2076 | req.spi.max = max; |
| 2077 | |
| 2078 | if (!send_netlink_msg(&req.n, XFRM_MSG_NEWSAXFRM_MSG_NEWSA, &rsp, "Get SPI", |
| 2079 | text_said)) { |
| 2080 | return 0; |
| 2081 | } |
| 2082 | |
| 2083 | if (rsp.n.nlmsg_len < NLMSG_LENGTH(sizeof(rsp.u.sa))((sizeof(rsp.u.sa)) + ((int) ( ((sizeof(struct nlmsghdr))+4U - 1) & ~(4U -1) )))) { |
| 2084 | libreswan_log(loglog(RC_LOG, "netlink_get_spi: XFRM_MSG_ALLOCSPI returned message with length %zu < %zu bytes; ignore message" , (size_t) rsp.n.nlmsg_len, sizeof(rsp.u.sa)) |
| 2085 | "netlink_get_spi: XFRM_MSG_ALLOCSPI returned message with length %zu < %zu bytes; ignore message",loglog(RC_LOG, "netlink_get_spi: XFRM_MSG_ALLOCSPI returned message with length %zu < %zu bytes; ignore message" , (size_t) rsp.n.nlmsg_len, sizeof(rsp.u.sa)) |
| 2086 | (size_t) rsp.n.nlmsg_len,loglog(RC_LOG, "netlink_get_spi: XFRM_MSG_ALLOCSPI returned message with length %zu < %zu bytes; ignore message" , (size_t) rsp.n.nlmsg_len, sizeof(rsp.u.sa)) |
| 2087 | sizeof(rsp.u.sa))loglog(RC_LOG, "netlink_get_spi: XFRM_MSG_ALLOCSPI returned message with length %zu < %zu bytes; ignore message" , (size_t) rsp.n.nlmsg_len, sizeof(rsp.u.sa)); |
| 2088 | return 0; |
| 2089 | } |
| 2090 | |
| 2091 | dbg("netlink_get_spi: allocated 0x%x for %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_get_spi: allocated 0x%x for %s", ntohl (rsp.u.sa.id.spi), text_said); } } |
| 2092 | ntohl(rsp.u.sa.id.spi), text_said){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("netlink_get_spi: allocated 0x%x for %s", ntohl (rsp.u.sa.id.spi), text_said); } }; |
| 2093 | return rsp.u.sa.id.spi; |
| 2094 | } |
| 2095 | |
| 2096 | /* |
| 2097 | * install or remove eroute for SA Group |
| 2098 | * |
| 2099 | * (identical to KLIPS version, but refactoring isn't waranteed yet |
| 2100 | */ |
| 2101 | static bool_Bool netlink_sag_eroute(const struct state *st, const struct spd_route *sr, |
| 2102 | unsigned op, const char *opname) |
| 2103 | { |
| 2104 | struct connection *c = st->st_connection; |
| 2105 | enum eroute_type inner_esatype; |
| 2106 | ipsec_spi_t inner_spi; |
| 2107 | struct pfkey_proto_info proto_info[4]; |
| 2108 | int i; |
| 2109 | bool_Bool tunnel; |
| 2110 | |
| 2111 | /* |
| 2112 | * figure out the SPI and protocol (in two forms) |
| 2113 | * for the innermost transformation. |
| 2114 | */ |
| 2115 | i = elemsof(proto_info)(sizeof(proto_info) / sizeof(*(proto_info))) - 1; |
| 2116 | proto_info[i].proto = 0; |
| 2117 | tunnel = FALSE0; |
| 2118 | |
| 2119 | const struct ip_protocol *inner_proto = NULL((void*)0); |
| 2120 | inner_esatype = ET_UNSPEC; |
| 2121 | inner_spi = 0; |
| 2122 | |
| 2123 | if (st->st_ah.present) { |
| 2124 | inner_spi = st->st_ah.attrs.spi; |
| 2125 | inner_proto = &ip_protocol_ah; |
| 2126 | inner_esatype = ET_AH; |
| 2127 | |
| 2128 | i--; |
| 2129 | proto_info[i].proto = IPPROTO_AHIPPROTO_AH; |
| 2130 | proto_info[i].mode = st->st_ah.attrs.mode; |
| 2131 | tunnel |= proto_info[i].mode == |
| 2132 | ENCAPSULATION_MODE_TUNNEL1; |
| 2133 | proto_info[i].reqid = reqid_ah(sr->reqid); |
| 2134 | } |
| 2135 | |
| 2136 | if (st->st_esp.present) { |
| 2137 | inner_spi = st->st_esp.attrs.spi; |
| 2138 | inner_proto = &ip_protocol_esp; |
| 2139 | inner_esatype = ET_ESP; |
| 2140 | |
| 2141 | i--; |
| 2142 | proto_info[i].proto = IPPROTO_ESPIPPROTO_ESP; |
| 2143 | proto_info[i].mode = st->st_esp.attrs.mode; |
| 2144 | tunnel |= proto_info[i].mode == |
| 2145 | ENCAPSULATION_MODE_TUNNEL1; |
| 2146 | proto_info[i].reqid = reqid_esp(sr->reqid); |
| 2147 | } |
| 2148 | |
| 2149 | if (st->st_ipcomp.present) { |
| 2150 | inner_spi = st->st_ipcomp.attrs.spi; |
| 2151 | inner_proto = &ip_protocol_comp; |
| 2152 | inner_esatype = ET_IPCOMP; |
| 2153 | |
| 2154 | i--; |
| 2155 | proto_info[i].proto = IPPROTO_COMPIPPROTO_COMP; |
| 2156 | proto_info[i].mode = |
| 2157 | st->st_ipcomp.attrs.mode; |
| 2158 | tunnel |= proto_info[i].mode == |
| 2159 | ENCAPSULATION_MODE_TUNNEL1; |
| 2160 | proto_info[i].reqid = reqid_ipcomp(sr->reqid); |
| 2161 | } |
| 2162 | |
| 2163 | /* check for no transform at all */ |
| 2164 | passert(st->st_ipcomp.present || st->st_esp.present ||{ _Bool assertion__ = st->st_ipcomp.present || st->st_esp .present || st->st_ah.present; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "kernel_xfrm.c" , . line = 2165}, "%s", "st->st_ipcomp.present || st->st_esp.present || st->st_ah.present" ); } } |
| 2165 | st->st_ah.present){ _Bool assertion__ = st->st_ipcomp.present || st->st_esp .present || st->st_ah.present; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "kernel_xfrm.c" , . line = 2165}, "%s", "st->st_ipcomp.present || st->st_esp.present || st->st_ah.present" ); } }; |
| 2166 | |
| 2167 | if (tunnel) { |
| 2168 | int j; |
| 2169 | |
| 2170 | inner_spi = st->st_tunnel_out_spi; |
| 2171 | inner_proto = &ip_protocol_ipip; |
| 2172 | inner_esatype = ET_IPIP; |
| 2173 | |
| 2174 | proto_info[i].mode = ENCAPSULATION_MODE_TUNNEL1; |
| 2175 | for (j = i + 1; proto_info[j].proto; j++) |
| 2176 | proto_info[j].mode = |
| 2177 | ENCAPSULATION_MODE_TRANSPORT2; |
| 2178 | } |
| 2179 | |
| 2180 | uint32_t xfrm_if_id = c->xfrmi != NULL((void*)0) ? c->xfrmi->if_id : 0; |
| 2181 | |
| 2182 | return eroute_connection(sr, inner_spi, inner_spi, inner_proto, |
| 2183 | inner_esatype, proto_info + i, |
| 2184 | calculate_sa_prio(c, FALSE0), &c->sa_marks, |
| 2185 | xfrm_if_id, op, opname, |
| 2186 | st->st_connection->policy_label); |
| 2187 | } |
| 2188 | |
| 2189 | /* Check if there was traffic on given SA during the last idle_max |
| 2190 | * seconds. If TRUE, the SA was idle and DPD exchange should be performed. |
| 2191 | * If FALSE, DPD is not necessary. We also return TRUE for errors, as they |
| 2192 | * could mean that the SA is broken and needs to be replace anyway. |
| 2193 | * |
| 2194 | * note: this mutates *st by calling get_sa_info |
| 2195 | */ |
| 2196 | static bool_Bool netlink_eroute_idle(struct state *st, deltatime_t idle_max) |
| 2197 | { |
| 2198 | deltatime_t idle_time; |
| 2199 | |
| 2200 | passert(st != NULL){ _Bool assertion__ = st != ((void*)0); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "kernel_xfrm.c" , . line = 2200}, "%s", "st != NULL"); } }; |
| 2201 | return !get_sa_info(st, TRUE1, &idle_time) || |
| 2202 | deltatime_cmp(idle_time, >=, idle_max)(deltatime_cmp_sign(idle_time, idle_max) >= 0); |
| 2203 | } |
| 2204 | |
| 2205 | static bool_Bool netlink_shunt_eroute(const struct connection *c, |
| 2206 | const struct spd_route *sr, |
| 2207 | enum routing_t rt_kind, |
| 2208 | enum pluto_sadb_operations op, |
| 2209 | const char *opname) |
| 2210 | { |
| 2211 | ipsec_spi_t spi; |
| 2212 | |
| 2213 | /* |
| 2214 | * We are constructing a special SAID for the eroute. |
| 2215 | * The destination doesn't seem to matter, but the family does. |
| 2216 | * The protocol is &ip_protocol_internal -- mark this as shunt. |
| 2217 | * The satype has no meaning, but is required for PF_KEY header! |
| 2218 | * The SPI signifies the kind of shunt. |
| 2219 | */ |
| 2220 | spi = shunt_policy_spi(c, rt_kind == RT_ROUTED_PROSPECTIVE); |
| 2221 | |
| 2222 | if (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { |
| 2223 | selector_buf this_buf, that_buf; |
| 2224 | DBG_log("netlink_shunt_eroute for proto %d, and source %s dest %s", |
| 2225 | sr->this.protocol, |
| 2226 | str_selector(&sr->this.client, &this_buf), |
| 2227 | str_selector(&sr->that.client, &that_buf)); |
| 2228 | } |
| 2229 | |
| 2230 | if (spi == 0) { |
| 2231 | /* |
| 2232 | * we're supposed to end up with no eroute: rejig op and |
| 2233 | * opname |
| 2234 | */ |
| 2235 | switch (op) { |
| 2236 | case ERO_REPLACE: |
| 2237 | /* replace with nothing == delete */ |
| 2238 | op = ERO_DELETE; |
| 2239 | opname = "delete"; |
| 2240 | break; |
| 2241 | case ERO_ADD: |
| 2242 | /* add nothing == do nothing */ |
| 2243 | return TRUE1; |
| 2244 | |
| 2245 | case ERO_DELETE: |
| 2246 | /* delete remains delete */ |
| 2247 | break; |
| 2248 | |
| 2249 | case ERO_ADD_INBOUND: |
| 2250 | break; |
| 2251 | |
| 2252 | case ERO_DEL_INBOUND: |
| 2253 | break; |
| 2254 | |
| 2255 | default: |
| 2256 | bad_case(op)libreswan_bad_case("op", (op), (where_t) { .func = __func__, . basename = "kernel_xfrm.c" , .line = 2256}); |
| 2257 | } |
| 2258 | } |
| 2259 | |
| 2260 | if (sr->routing == RT_ROUTED_ECLIPSED && c->kind == CK_TEMPLATE) { |
| 2261 | /* |
| 2262 | * We think that we have an eroute, but we don't. |
| 2263 | * Adjust the request and account for eclipses. |
| 2264 | */ |
| 2265 | passert(eclipsable(sr)){ _Bool assertion__ = (subnetishost(&(sr)->this.client ) && subnetishost(&(sr)->that.client)); if (!assertion__ ) { lsw_passert_fail((where_t) { .func = __func__, .basename = "kernel_xfrm.c" , .line = 2265}, "%s", "eclipsable(sr)"); } }; |
| 2266 | switch (op) { |
| 2267 | case ERO_REPLACE: |
| 2268 | /* really an add */ |
| 2269 | op = ERO_ADD; |
| 2270 | opname = "replace eclipsed"; |
| 2271 | eclipse_count--; |
| 2272 | break; |
| 2273 | case ERO_DELETE: |
| 2274 | /* |
| 2275 | * delete unnecessary: |
| 2276 | * we don't actually have an eroute |
| 2277 | */ |
| 2278 | eclipse_count--; |
| 2279 | return TRUE1; |
| 2280 | |
| 2281 | case ERO_ADD: |
| 2282 | default: |
| 2283 | bad_case(op)libreswan_bad_case("op", (op), (where_t) { .func = __func__, . basename = "kernel_xfrm.c" , .line = 2283}); |
| 2284 | } |
| 2285 | } else if (eclipse_count > 0 && op == ERO_DELETE && eclipsable(sr)(subnetishost(&(sr)->this.client) && subnetishost (&(sr)->that.client))) { |
| 2286 | /* maybe we are uneclipsing something */ |
| 2287 | struct spd_route *esr; |
| 2288 | struct connection *ue = eclipsed(c, &esr); |
| 2289 | |
| 2290 | if (ue != NULL((void*)0)) { |
| 2291 | esr->routing = RT_ROUTED_PROSPECTIVE; |
| 2292 | return netlink_shunt_eroute(ue, esr, |
| 2293 | RT_ROUTED_PROSPECTIVE, |
| 2294 | ERO_REPLACE, |
| 2295 | "restoring eclipsed"); |
| 2296 | } |
| 2297 | } |
| 2298 | |
| 2299 | char buf2[256]; |
| 2300 | |
| 2301 | snprintf(buf2, sizeof(buf2), "eroute_connection %s", opname); |
| 2302 | |
| 2303 | /* |
| 2304 | * XXX: the two calls below to netlink_raw_eroute() (not |
| 2305 | * raw_eroute()) seems to be the only place where SA_PROTO and |
| 2306 | * ESATYPE disagree - when ENCAPSULATION_MODE_TRANSPORT |
| 2307 | * SA_PROTO==&ip_protocol_esp and ESATYPE==ET_INT!?! Looking in the |
| 2308 | * function there's a weird test involving both SA_PROTO and |
| 2309 | * ESATYPE. |
| 2310 | */ |
| 2311 | const struct ip_protocol *sa_proto = c->ipsec_mode == ENCAPSULATION_MODE_TRANSPORT2 ? |
| 2312 | &ip_protocol_esp : &ip_protocol_internal; |
| 2313 | |
| 2314 | if (!netlink_raw_eroute(&sr->this.host_addr, &sr->this.client, |
| 2315 | &sr->that.host_addr, &sr->that.client, |
| 2316 | htonl(spi), htonl(spi), |
| 2317 | sa_proto, |
| 2318 | sr->this.protocol, |
| 2319 | ET_INT, |
| 2320 | null_proto_info, |
| 2321 | deltatime(0), |
| 2322 | calculate_sa_prio(c, FALSE0), |
| 2323 | &c->sa_marks, |
| 2324 | 0 /* xfrm_if_id needed for shunt? */, |
| 2325 | op, buf2, |
| 2326 | c->policy_label)) |
| 2327 | return FALSE0; |
| 2328 | |
| 2329 | switch (op) { |
| 2330 | case ERO_ADD: |
| 2331 | op = ERO_ADD_INBOUND; |
| 2332 | break; |
| 2333 | case ERO_DELETE: |
| 2334 | op = ERO_DEL_INBOUND; |
| 2335 | break; |
| 2336 | default: |
| 2337 | return TRUE1; |
| 2338 | } |
| 2339 | |
| 2340 | snprintf(buf2, sizeof(buf2), "eroute_connection %s inbound", opname); |
| 2341 | |
| 2342 | return netlink_raw_eroute(&sr->that.host_addr, &sr->that.client, |
| 2343 | &sr->this.host_addr, &sr->this.client, |
| 2344 | htonl(spi), htonl(spi), |
| 2345 | sa_proto, |
| 2346 | sr->this.protocol, |
| 2347 | ET_INT, |
| 2348 | null_proto_info, |
| 2349 | deltatime(0), |
| 2350 | calculate_sa_prio(c, FALSE0), |
| 2351 | &c->sa_marks, |
| 2352 | 0, /* xfrm_if_id needed for shunt? */ |
| 2353 | op, buf2, |
| 2354 | c->policy_label); |
| 2355 | } |
| 2356 | |
| 2357 | static void netlink_process_raw_ifaces(struct raw_iface *rifaces) |
| 2358 | { |
| 2359 | struct raw_iface *ifp; |
| 2360 | ip_address lip; /* --listen filter option */ |
| 2361 | |
| 2362 | if (pluto_listen) { |
| 2363 | err_t e = ttoaddr_num(pluto_listen, 0, AF_UNSPEC0, &lip); |
| 2364 | |
| 2365 | if (e != NULL((void*)0)) { |
| 2366 | DBG_log("invalid listen= option ignored: %s", e); |
| 2367 | pluto_listen = NULL((void*)0); |
| 2368 | } |
| 2369 | address_buf b; |
| 2370 | dbg("Only looking to listen on %s", str_address(&lip, &b)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Only looking to listen on %s", str_address(& lip, &b)); } }; |
| 2371 | } |
| 2372 | |
| 2373 | /* |
| 2374 | * Find all virtual/real interface pairs. |
| 2375 | * For each real interface... |
| 2376 | */ |
| 2377 | for (ifp = rifaces; ifp != NULL((void*)0); ifp = ifp->next) { |
| 2378 | struct raw_iface *v = NULL((void*)0); /* matching ipsecX interface */ |
| 2379 | bool_Bool after = FALSE0; /* has vfp passed ifp on the list? */ |
| 2380 | bool_Bool bad = FALSE0; |
| 2381 | struct raw_iface *vfp; |
| 2382 | |
| 2383 | /* ignore if virtual (ipsec*) interface */ |
| 2384 | if (startswith(ifp->name, IPSECDEVPREFIX)(strncmp(((ifp->name)), (("ipsec")), (strlen("ipsec"))) == 0)) |
| 2385 | continue; |
| 2386 | |
| 2387 | /* ignore if virtual (mast*) interface */ |
| 2388 | if (startswith(ifp->name, MASTDEVPREFIX)(strncmp(((ifp->name)), (("mast")), (strlen("mast"))) == 0 )) |
| 2389 | continue; |
| 2390 | |
| 2391 | for (vfp = rifaces; vfp != NULL((void*)0); vfp = vfp->next) { |
| 2392 | if (vfp == ifp) { |
| 2393 | after = true1; |
| 2394 | } else if (sameaddr(&ifp->addr, &vfp->addr)) { |
| 2395 | /* |
| 2396 | * Different entries with matching IP |
| 2397 | * addresses. |
| 2398 | * |
| 2399 | * Many interesting cases. |
| 2400 | */ |
| 2401 | if (startswith(vfp->name, IPSECDEVPREFIX)(strncmp(((vfp->name)), (("ipsec")), (strlen("ipsec"))) == 0)) { |
| 2402 | if (v != NULL((void*)0)) { |
| 2403 | ipstr_buf b; |
| 2404 | |
| 2405 | loglog(RC_LOG_SERIOUS, |
| 2406 | "ipsec interfaces %s and %s share same address %s", |
| 2407 | v->name, vfp->name, |
| 2408 | ipstr(&ifp->addr, &b)); |
| 2409 | bad = TRUE1; |
| 2410 | } else { |
| 2411 | /* current winner */ |
| 2412 | v = vfp; |
| 2413 | } |
| 2414 | } else { |
| 2415 | /* |
| 2416 | * ugh: a second real interface with |
| 2417 | * the same IP address "after" allows |
| 2418 | * us to avoid double reporting. |
| 2419 | */ |
| 2420 | /* XXX: isn't this always true? */ |
| 2421 | if (kernel_ops->type == USE_XFRM) { |
| 2422 | if (after) { |
| 2423 | bad = TRUE1; |
| 2424 | break; |
| 2425 | } |
| 2426 | continue; |
| 2427 | } |
| 2428 | if (after) { |
| 2429 | ipstr_buf b; |
| 2430 | |
| 2431 | loglog(RC_LOG_SERIOUS, |
| 2432 | "IP interfaces %s and %s share address %s!", |
| 2433 | ifp->name, vfp->name, |
| 2434 | ipstr(&ifp->addr, &b)); |
| 2435 | } |
| 2436 | bad = TRUE1; |
| 2437 | } |
| 2438 | } |
| 2439 | } |
| 2440 | |
| 2441 | if (bad) |
| 2442 | continue; |
| 2443 | |
| 2444 | /* XXX: isn't this always true? */ |
| 2445 | if (kernel_ops->type == USE_XFRM) { |
| 2446 | v = ifp; |
| 2447 | } |
| 2448 | |
| 2449 | /* what if we didn't find a virtual interface? */ |
| 2450 | if (v == NULL((void*)0)) { |
| 2451 | address_buf b; |
| 2452 | dbg("IP interface %s %s has no matching ipsec* interface -- ignored",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("IP interface %s %s has no matching ipsec* interface -- ignored" , ifp->name, str_address(&ifp->addr, &b)); } } |
| 2453 | ifp->name, str_address(&ifp->addr, &b)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("IP interface %s %s has no matching ipsec* interface -- ignored" , ifp->name, str_address(&ifp->addr, &b)); } }; |
| 2454 | continue; |
| 2455 | } |
| 2456 | |
| 2457 | /* |
| 2458 | * We've got all we need; see if this is a new thing: |
| 2459 | * search old interfaces list. |
| 2460 | */ |
| 2461 | |
| 2462 | /* |
| 2463 | * last check before we actually add the entry. |
| 2464 | * |
| 2465 | * ignore if --listen is specified and we do not match |
| 2466 | */ |
| 2467 | if (pluto_listen != NULL((void*)0) && !sameaddr(&lip, &ifp->addr)) { |
| 2468 | ipstr_buf b; |
| 2469 | |
| 2470 | libreswan_log("skipping interface %s with %s",loglog(RC_LOG, "skipping interface %s with %s", ifp->name, ipstr(&ifp->addr, &b)) |
| 2471 | ifp->name, ipstr(&ifp->addr, &b))loglog(RC_LOG, "skipping interface %s with %s", ifp->name, ipstr(&ifp->addr, &b)); |
| 2472 | continue; |
| 2473 | } |
| 2474 | |
| 2475 | add_or_keep_iface_dev(ifp); |
| 2476 | } |
| 2477 | |
| 2478 | /* delete the raw interfaces list */ |
| 2479 | while (rifaces != NULL((void*)0)) { |
| 2480 | struct raw_iface *t = rifaces; |
| 2481 | |
| 2482 | rifaces = t->next; |
| 2483 | pfree(t); |
| 2484 | } |
| 2485 | } |
| 2486 | |
| 2487 | /* |
| 2488 | * netlink_get_sa - Get SA information from the kernel |
| 2489 | * |
| 2490 | * @param sa Kernel SA to be queried |
| 2491 | * @param bytes octets processed by IPsec SA |
| 2492 | * @param add_time timestamp when IPsec SA added |
| 2493 | * @return bool True if successful |
| 2494 | */ |
| 2495 | static bool_Bool netlink_get_sa(const struct kernel_sa *sa, uint64_t *bytes, |
| 2496 | uint64_t *add_time) |
| 2497 | { |
| 2498 | struct { |
| 2499 | struct nlmsghdr n; |
| 2500 | struct xfrm_usersa_id id; |
| 2501 | } req; |
| 2502 | |
| 2503 | struct nlm_resp rsp; |
| 2504 | |
| 2505 | zero(&req)memset((&req), '\0', sizeof(*(&req))); |
| 2506 | req.n.nlmsg_flags = NLM_F_REQUEST0x01; |
| 2507 | req.n.nlmsg_type = XFRM_MSG_GETSAXFRM_MSG_GETSA; |
| 2508 | |
| 2509 | req.id.daddr = xfrm_from_address(sa->dst.address); |
| 2510 | |
| 2511 | req.id.spi = sa->spi; |
| 2512 | req.id.family = addrtypeof(sa->src.address); |
| 2513 | req.id.proto = sa->proto->ipproto; |
| 2514 | |
| 2515 | req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)))( ((((sizeof(req.id)) + ((int) ( ((sizeof(struct nlmsghdr))+4U -1) & ~(4U -1) ))))+4U -1) & ~(4U -1) ); |
| 2516 | |
| 2517 | if (!send_netlink_msg(&req.n, XFRM_MSG_NEWSAXFRM_MSG_NEWSA, &rsp, "Get SA", sa->text_said)) |
| 2518 | return FALSE0; |
| 2519 | |
| 2520 | *bytes = rsp.u.info.curlft.bytes; |
| 2521 | *add_time = rsp.u.info.curlft.add_time; |
| 2522 | return TRUE1; |
| 2523 | } |
| 2524 | |
| 2525 | static bool_Bool netkey_do_command(const struct connection *c, const struct spd_route *sr, |
| 2526 | const char *verb, const char *verb_suffix, struct state *st) |
| 2527 | { |
| 2528 | char cmd[2048]; /* arbitrary limit on shell command length */ |
| 2529 | char common_shell_out_str[2048]; |
| 2530 | |
| 2531 | if (!fmt_common_shell_out(common_shell_out_str, |
| 2532 | sizeof(common_shell_out_str), |
| 2533 | c, sr, st)) { |
| 2534 | loglog(RC_LOG_SERIOUS, "%s%s command too long!", verb, |
| 2535 | verb_suffix); |
| 2536 | return FALSE0; |
| 2537 | } |
| 2538 | |
| 2539 | if (-1 == snprintf(cmd, sizeof(cmd), |
| 2540 | "PLUTO_VERB='%s%s' %s%s 2>&1", |
| 2541 | verb, verb_suffix, |
| 2542 | common_shell_out_str, |
| 2543 | sr->this.updown)) { |
| 2544 | loglog(RC_LOG_SERIOUS, "%s%s command too long!", verb, |
| 2545 | verb_suffix); |
| 2546 | return FALSE0; |
| 2547 | } |
| 2548 | |
| 2549 | return invoke_command(verb, verb_suffix, cmd); |
| 2550 | } |
| 2551 | |
| 2552 | /* add bypass policies/holes icmp */ |
| 2553 | static bool_Bool netlink_bypass_policy(int family, int proto, int port) |
| 2554 | { |
| 2555 | struct { |
| 2556 | struct nlmsghdr n; |
| 2557 | union { |
| 2558 | struct xfrm_userpolicy_info p; |
| 2559 | struct xfrm_userpolicy_id id; |
| 2560 | } u; |
| 2561 | char data[MAX_NETLINK_DATA_SIZE8192]; |
| 2562 | } req; |
| 2563 | |
| 2564 | zero(&req)memset((&req), '\0', sizeof(*(&req))); |
| 2565 | |
| 2566 | req.n.nlmsg_flags = NLM_F_REQUEST0x01 | NLM_F_ACK0x04; |
| 2567 | |
| 2568 | req.n.nlmsg_type = XFRM_MSG_UPDPOLICYXFRM_MSG_UPDPOLICY; |
| 2569 | req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.p)))( ((((sizeof(req.u.p)) + ((int) ( ((sizeof(struct nlmsghdr))+ 4U -1) & ~(4U -1) ))))+4U -1) & ~(4U -1) ); |
| 2570 | |
| 2571 | req.u.p.dir = XFRM_POLICY_IN; |
| 2572 | req.u.p.priority = 1; /* give admin prio 0 as override */ |
| 2573 | req.u.p.action = XFRM_POLICY_ALLOW0; |
| 2574 | req.u.p.share = XFRM_SHARE_ANY; |
| 2575 | |
| 2576 | req.u.p.lft.soft_byte_limit = XFRM_INF(~(__u64)0); |
| 2577 | req.u.p.lft.soft_packet_limit = XFRM_INF(~(__u64)0); |
| 2578 | req.u.p.lft.hard_byte_limit = XFRM_INF(~(__u64)0); |
| 2579 | req.u.p.lft.hard_packet_limit = XFRM_INF(~(__u64)0); |
| 2580 | |
| 2581 | req.u.p.sel.proto = proto; |
| 2582 | req.u.p.sel.family = family; |
| 2583 | |
| 2584 | const char* text = "add port bypass"; |
| 2585 | |
| 2586 | if (proto == IPPROTO_ICMPV658) { |
| 2587 | uint16_t icmp_type; |
| 2588 | uint16_t icmp_code; |
| 2589 | |
| 2590 | icmp_type = port >> 8; |
| 2591 | icmp_code = port & 0xFF; |
| 2592 | req.u.p.sel.sport = htons(icmp_type); |
| 2593 | req.u.p.sel.dport = htons(icmp_code); |
| 2594 | req.u.p.sel.sport_mask = 0xffff; |
| 2595 | |
| 2596 | if (!netlink_policy(&req.n, 1, text)) |
| 2597 | return FALSE0; |
| 2598 | |
| 2599 | req.u.p.dir = XFRM_POLICY_FWD; |
| 2600 | |
| 2601 | if (!netlink_policy(&req.n, 1, text)) |
| 2602 | return FALSE0; |
| 2603 | |
| 2604 | req.u.p.dir = XFRM_POLICY_OUT; |
| 2605 | |
| 2606 | if (!netlink_policy(&req.n, 1, text)) |
| 2607 | return FALSE0; |
| 2608 | } else { |
| 2609 | req.u.p.sel.dport = htons(port); |
| 2610 | req.u.p.sel.dport_mask = 0xffff; |
| 2611 | |
| 2612 | if (!netlink_policy(&req.n, 1, text)) |
| 2613 | return FALSE0; |
| 2614 | |
| 2615 | req.u.p.dir = XFRM_POLICY_OUT; |
| 2616 | |
| 2617 | req.u.p.sel.sport = htons(port); |
| 2618 | req.u.p.sel.sport_mask = 0xffff; |
| 2619 | req.u.p.sel.dport = 0; |
| 2620 | req.u.p.sel.dport_mask = 0; |
| 2621 | |
| 2622 | if (!netlink_policy(&req.n, 1, text)) |
| 2623 | return FALSE0; |
| 2624 | } |
| 2625 | |
| 2626 | return TRUE1; |
| 2627 | } |
| 2628 | |
| 2629 | static bool_Bool netlink_v6holes(void) |
| 2630 | { |
| 2631 | /* this could be per interface specific too */ |
| 2632 | char proc_f[] = "/proc/sys/net/ipv6/conf/all/disable_ipv6"; |
| 2633 | int disable_ipv6 = -1; |
| 2634 | bool_Bool ret = FALSE0; |
| 2635 | struct stat sts; |
| 2636 | |
| 2637 | if (stat(proc_f, &sts) == 0) { |
| 2638 | FILE *f = fopen(proc_f, "r"); |
| 2639 | if (f != NULL((void*)0)) { |
| 2640 | char buf[64]; |
| 2641 | if (fgets(buf, sizeof(buf), f) != NULL((void*)0)) { |
| 2642 | disable_ipv6 = atoi(buf); |
| 2643 | } |
| 2644 | (void) fclose(f); |
| 2645 | } else { |
| 2646 | LOG_ERRNO(errno, "\"%s\"", proc_f){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "\"%s\"", proc_f); jam_string(buf, "."); jam(buf, " ""Errno %d: %s" , (e_), strerror(e_)); jambuf_to_error_stream(buf); } }; |
| 2647 | } |
| 2648 | } else { |
| 2649 | dbg("starting without ipv6 support! could not stat \"%s\"" PRI_ERRNO,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("starting without ipv6 support! could not stat \"%s\"" "Errno %d: %s", proc_f, ((*__errno_location ())), strerror(( *__errno_location ()))); } } |
| 2650 | proc_f, pri_errno(errno)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("starting without ipv6 support! could not stat \"%s\"" "Errno %d: %s", proc_f, ((*__errno_location ())), strerror(( *__errno_location ()))); } }; |
| 2651 | /* |
| 2652 | * pretend success, do not exit pluto, |
| 2653 | * likely IPv6 is disabled in kernel at compile time. e.g. OpenWRT. |
| 2654 | */ |
| 2655 | ret = TRUE1; |
| 2656 | } |
| 2657 | |
| 2658 | if (disable_ipv6 == 1) { |
| 2659 | dbg("net.ipv6.conf.all.disable_ipv6=1 ignore ipv6 holes"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("net.ipv6.conf.all.disable_ipv6=1 ignore ipv6 holes" ); } }; |
| 2660 | ret = TRUE1; /* pretend success, do not exit pluto */ |
| 2661 | } else if (disable_ipv6 == 0) { |
| 2662 | ret = netlink_bypass_policy(AF_INET610, IPPROTO_ICMPV658, |
| 2663 | ICMP_NEIGHBOR_DISCOVERY34816); |
| 2664 | ret &= netlink_bypass_policy(AF_INET610, IPPROTO_ICMPV658, |
| 2665 | ICMP_NEIGHBOR_SOLICITATION34560); |
| 2666 | } |
| 2667 | |
| 2668 | return ret; |
| 2669 | } |
| 2670 | |
| 2671 | static bool_Bool qry_xfrm_mirgrate_support(struct nlmsghdr *hdr) |
| 2672 | { |
| 2673 | struct nlm_resp rsp; |
| 2674 | size_t len; |
| 2675 | ssize_t r; |
| 2676 | struct sockaddr_nl addr; |
| 2677 | int nl_fd = socket(AF_NETLINK16, SOCK_DGRAMSOCK_DGRAM, NETLINK_XFRM6); |
| 2678 | |
| 2679 | if (nl_fd < 0) { |
| 2680 | LOG_ERRNO(errno, "socket() in qry_xfrm_mirgrate_support()"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "socket() in qry_xfrm_mirgrate_support()"); jam_string( buf, "."); jam(buf, " ""Errno %d: %s", (e_), strerror(e_)); jambuf_to_error_stream (buf); } }; |
| 2681 | return FALSE0; |
| 2682 | } |
| 2683 | |
| 2684 | if (fcntl(nl_fd, F_SETFL4, O_NONBLOCK04000) != 0) { |
| 2685 | LOG_ERRNO(errno, "fcntl(O_NONBLOCK in qry_xfrm_mirgrate_support()"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "fcntl(O_NONBLOCK in qry_xfrm_mirgrate_support()"); jam_string (buf, "."); jam(buf, " ""Errno %d: %s", (e_), strerror(e_)); jambuf_to_error_stream (buf); } }; |
| 2686 | close(nl_fd); |
| 2687 | |
| 2688 | return FALSE0; |
| 2689 | } |
| 2690 | |
| 2691 | /* hdr->nlmsg_seq = ++seq; */ |
| 2692 | len = hdr->nlmsg_len; |
| 2693 | do { |
| 2694 | r = write(nl_fd, hdr, len); |
| 2695 | } while (r < 0 && errno(*__errno_location ()) == EINTR4); |
| 2696 | if (r < 0) { |
| 2697 | LOG_ERRNO(errno, "netlink write() xfrm_migrate_support lookup"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "netlink write() xfrm_migrate_support lookup"); jam_string (buf, "."); jam(buf, " ""Errno %d: %s", (e_), strerror(e_)); jambuf_to_error_stream (buf); } }; |
| 2698 | close(nl_fd); |
| 2699 | return FALSE0; |
| 2700 | } else if ((size_t)r != len) { |
| 2701 | loglog(RC_LOG_SERIOUS, |
| 2702 | "ERROR: netlink write() xfrm_migrate_support message truncated: %zd instead of %zu", |
| 2703 | r, len); |
| 2704 | close(nl_fd); |
| 2705 | return FALSE0; |
| 2706 | } |
| 2707 | |
| 2708 | for (;;) { |
| 2709 | socklen_t alen = sizeof(addr); |
| 2710 | |
| 2711 | r = recvfrom(nl_fd, &rsp, sizeof(rsp), 0, |
| 2712 | (struct sockaddr *)&addr, &alen); |
| 2713 | if (r < 0) { |
| 2714 | if (errno(*__errno_location ()) == EINTR4) { |
| 2715 | continue; |
| 2716 | } else if (errno(*__errno_location ()) == EAGAIN11) { |
| 2717 | /* old kernel F22 - dos not return proper error ??? */ |
| 2718 | dbg("ignore EAGAIN in %s assume MOBIKE migration is supported", __func__){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ignore EAGAIN in %s assume MOBIKE migration is supported" , __func__); } }; |
| 2719 | break; |
| 2720 | } |
| 2721 | } |
| 2722 | break; |
| 2723 | } |
| 2724 | |
| 2725 | close(nl_fd); |
| 2726 | |
| 2727 | if (rsp.n.nlmsg_type == NLMSG_ERROR0x2 && rsp.u.e.error == -ENOPROTOOPT92) { |
| 2728 | dbg("MOBIKE will fail got ENOPROTOOPT"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("MOBIKE will fail got ENOPROTOOPT"); } }; |
| 2729 | return FALSE0; |
| 2730 | } |
| 2731 | |
| 2732 | return TRUE1; |
| 2733 | } |
| 2734 | |
| 2735 | static err_t netlink_migrate_sa_check(void) |
| 2736 | { |
| 2737 | if (kernel_mobike_supprt == 0) { |
| 2738 | /* check the kernel */ |
| 2739 | |
| 2740 | struct { |
| 2741 | struct nlmsghdr n; |
| 2742 | struct xfrm_userpolicy_id id; |
| 2743 | char data[MAX_NETLINK_DATA_SIZE8192]; |
| 2744 | } req; |
| 2745 | |
| 2746 | zero(&req)memset((&req), '\0', sizeof(*(&req))); |
| 2747 | req.n.nlmsg_flags = NLM_F_REQUEST0x01; |
| 2748 | req.n.nlmsg_type = XFRM_MSG_MIGRATEXFRM_MSG_MIGRATE; |
| 2749 | req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)))( ((((sizeof(req.id)) + ((int) ( ((sizeof(struct nlmsghdr))+4U -1) & ~(4U -1) ))))+4U -1) & ~(4U -1) ); |
| 2750 | |
| 2751 | /* add attrs[XFRM_MSG_MIGRATE] */ |
| 2752 | struct rtattr *attr; |
| 2753 | struct xfrm_user_migrate migrate; |
| 2754 | |
| 2755 | zero(&migrate)memset((&migrate), '\0', sizeof(*(&migrate))); |
| 2756 | attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); |
| 2757 | attr->rta_type = XFRMA_MIGRATE; |
| 2758 | attr->rta_len = sizeof(migrate); |
| 2759 | |
| 2760 | memcpy(RTA_DATA(attr)((void*)(((char*)(attr)) + (( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (0)))), &migrate, attr->rta_len); |
| 2761 | attr->rta_len = RTA_LENGTH(attr->rta_len)(( ((sizeof(struct rtattr))+4U -1) & ~(4U -1) ) + (attr-> rta_len)); |
| 2762 | req.n.nlmsg_len += attr->rta_len; |
| 2763 | |
| 2764 | bool_Bool ret = qry_xfrm_mirgrate_support(&req.n); |
| 2765 | kernel_mobike_supprt = ret ? 1 : -1; |
| 2766 | } |
| 2767 | |
| 2768 | if (kernel_mobike_supprt > 0) { |
| 2769 | return NULL((void*)0); |
| 2770 | } else { |
| 2771 | return "CONFIG_XFRM_MIGRATE"; |
| 2772 | } |
| 2773 | } |
| 2774 | |
| 2775 | static bool_Bool netlink_poke_ipsec_policy_hole(const struct iface_dev *ifd, int fd) |
| 2776 | { |
| 2777 | const struct ip_info *type = address_type(&ifd->id_address); |
| 2778 | struct xfrm_userpolicy_info policy = { |
| 2779 | .action = XFRM_POLICY_ALLOW0, |
| 2780 | .sel = { |
| 2781 | .family = type->af, |
| 2782 | } |
| 2783 | }; |
| 2784 | |
| 2785 | int opt, sol; |
| 2786 | |
| 2787 | if (type == &ipv6_info) { |
| 2788 | sol = IPPROTO_IPV6IPPROTO_IPV6; |
| 2789 | opt = IPV6_XFRM_POLICY35; |
| 2790 | } else { |
| 2791 | sol = SOL_IP0; |
| 2792 | opt = IP_XFRM_POLICY17; |
| 2793 | } |
| 2794 | |
| 2795 | policy.dir = XFRM_POLICY_IN; |
| 2796 | if (setsockopt(fd, sol, opt, &policy, sizeof(policy)) < 0) { |
| 2797 | LOG_ERRNO(errno, "setsockopt IP_XFRM_POLICY XFRM_POLICY_IN in process_raw_ifaces()"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "setsockopt IP_XFRM_POLICY XFRM_POLICY_IN in process_raw_ifaces()" ); jam_string(buf, "."); jam(buf, " ""Errno %d: %s", (e_), strerror (e_)); jambuf_to_error_stream(buf); } }; |
| 2798 | return false0; |
| 2799 | } |
| 2800 | |
| 2801 | policy.dir = XFRM_POLICY_OUT; |
| 2802 | if (setsockopt(fd, sol, opt, &policy, sizeof(policy)) < 0) { |
| 2803 | LOG_ERRNO(errno, "setsockopt IP_XFRM_POLICY XFRM_POLICY_OUT in process_raw_ifaces()"){ int e_ = (*__errno_location ()); for (char lswbuf[((size_t) 1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ( (void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) { jam(buf, "ERROR: "); jam_cur_prefix(buf); jam (buf, "setsockopt IP_XFRM_POLICY XFRM_POLICY_OUT in process_raw_ifaces()" ); jam_string(buf, "."); jam(buf, " ""Errno %d: %s", (e_), strerror (e_)); jambuf_to_error_stream(buf); } }; |
| 2804 | return false0; |
| 2805 | } |
| 2806 | |
| 2807 | return true1; |
| 2808 | } |
| 2809 | |
| 2810 | const struct kernel_ops xfrm_kernel_ops = { |
| 2811 | .kern_name = "xfrm", |
| 2812 | .type = USE_XFRM, |
| 2813 | .scan_shunts = expire_bare_shunts, |
| 2814 | .async_fdp = &nl_xfrm_fd, |
| 2815 | .route_fdp = &nl_route_fd, |
| 2816 | .replay_window = IPSEC_SA_DEFAULT_REPLAY_WINDOW32, |
| 2817 | |
| 2818 | .init = init_netlink, |
| 2819 | #ifdef USE_XFRM_INTERFACE1 |
| 2820 | .shutdown = free_xfrmi_ipsec1, |
| 2821 | #else |
| 2822 | .shutdown = NULL((void*)0), |
| 2823 | #endif |
| 2824 | .process_msg = netlink_process_msg, |
| 2825 | .raw_eroute = netlink_raw_eroute, |
| 2826 | .add_sa = netlink_add_sa, |
| 2827 | .del_sa = netlink_del_sa, |
| 2828 | .get_sa = netlink_get_sa, |
| 2829 | .process_queue = NULL((void*)0), |
| 2830 | .grp_sa = NULL((void*)0), |
| 2831 | .get_spi = netlink_get_spi, |
| 2832 | .exceptsocket = NULL((void*)0), |
| 2833 | .docommand = netkey_do_command, |
| 2834 | .process_raw_ifaces = netlink_process_raw_ifaces, |
| 2835 | .shunt_eroute = netlink_shunt_eroute, |
| 2836 | .sag_eroute = netlink_sag_eroute, |
| 2837 | .eroute_idle = netlink_eroute_idle, |
| 2838 | .migrate_sa_check = netlink_migrate_sa_check, |
| 2839 | .migrate_sa = netlink_migrate_sa, |
| 2840 | /* |
| 2841 | * We should implement netlink_remove_orphaned_holds |
| 2842 | * if netlink specific changes are needed. |
| 2843 | */ |
| 2844 | .remove_orphaned_holds = NULL((void*)0), /* only used for klips /proc scanner */ |
| 2845 | .overlap_supported = FALSE0, |
| 2846 | .sha2_truncbug_support = TRUE1, |
| 2847 | .v6holes = netlink_v6holes, |
| 2848 | .poke_ipsec_policy_hole = netlink_poke_ipsec_policy_hole, |
| 2849 | .detect_offload = netlink_detect_offload, |
| 2850 | }; |