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