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 | }; |