File: | src/usr.sbin/bgpd/pfkey.c |
Warning: | line 466, column 25 The left operand of '!=' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: pfkey.c,v 1.61 2020/04/23 16:13:11 claudio Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> | |||
5 | * Copyright (c) 2003, 2004 Markus Friedl <markus@openbsd.org> | |||
6 | * | |||
7 | * Permission to use, copy, modify, and distribute this software for any | |||
8 | * purpose with or without fee is hereby granted, provided that the above | |||
9 | * copyright notice and this permission notice appear in all copies. | |||
10 | * | |||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
18 | */ | |||
19 | ||||
20 | #include <sys/types.h> | |||
21 | #include <sys/socket.h> | |||
22 | #include <sys/uio.h> | |||
23 | #include <net/pfkeyv2.h> | |||
24 | #include <netinet/ip_ipsp.h> | |||
25 | #include <netinet/in.h> | |||
26 | #include <netinet/tcp.h> | |||
27 | #include <ctype.h> | |||
28 | #include <errno(*__errno()).h> | |||
29 | #include <limits.h> | |||
30 | #include <stdlib.h> | |||
31 | #include <string.h> | |||
32 | #include <unistd.h> | |||
33 | ||||
34 | #include "bgpd.h" | |||
35 | #include "session.h" | |||
36 | #include "log.h" | |||
37 | ||||
38 | extern struct bgpd_sysdep sysdep; | |||
39 | ||||
40 | #define PFKEY2_CHUNKsizeof(u_int64_t) sizeof(u_int64_t) | |||
41 | #define ROUNDUP(x)(((x) + (sizeof(u_int64_t) - 1)) & ~(sizeof(u_int64_t) - 1 )) (((x) + (PFKEY2_CHUNKsizeof(u_int64_t) - 1)) & ~(PFKEY2_CHUNKsizeof(u_int64_t) - 1)) | |||
42 | #define IOV_CNT20 20 | |||
43 | ||||
44 | static u_int32_t sadb_msg_seq = 0; | |||
45 | static u_int32_t pid = 0; /* should pid_t but pfkey needs u_int32_t */ | |||
46 | static int pfkey_fd; | |||
47 | ||||
48 | int pfkey_reply(int, u_int32_t *); | |||
49 | int pfkey_send(int, uint8_t, uint8_t, uint8_t, | |||
50 | struct bgpd_addr *, struct bgpd_addr *, | |||
51 | u_int32_t, uint8_t, int, char *, uint8_t, int, char *, | |||
52 | uint16_t, uint16_t); | |||
53 | ||||
54 | #define pfkey_flow(fd, satype, cmd, dir, from, to, sport, dport)pfkey_send(fd, satype, cmd, dir, from, to, 0, 0, 0, ((void *) 0), 0, 0, ((void *)0), sport, dport) \ | |||
55 | pfkey_send(fd, satype, cmd, dir, from, to, \ | |||
56 | 0, 0, 0, NULL((void *)0), 0, 0, NULL((void *)0), sport, dport) | |||
57 | ||||
58 | static struct bgpd_addr * | |||
59 | pfkey_localaddr(struct peer *p) | |||
60 | { | |||
61 | switch (p->conf.remote_addr.aid) { | |||
62 | case AID_INET1: | |||
63 | return &p->conf.local_addr_v4; | |||
64 | case AID_INET62: | |||
65 | return &p->conf.local_addr_v6; | |||
66 | } | |||
67 | fatalx("Unknown AID in pfkey_localaddr"); | |||
68 | } | |||
69 | ||||
70 | int | |||
71 | pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir, | |||
72 | struct bgpd_addr *src, struct bgpd_addr *dst, u_int32_t spi, | |||
73 | uint8_t aalg, int alen, char *akey, uint8_t ealg, int elen, char *ekey, | |||
74 | uint16_t sport, uint16_t dport) | |||
75 | { | |||
76 | struct sadb_msg smsg; | |||
77 | struct sadb_sa sa; | |||
78 | struct sadb_address sa_src, sa_dst, sa_peer, sa_smask, sa_dmask; | |||
79 | struct sadb_key sa_akey, sa_ekey; | |||
80 | struct sadb_spirange sa_spirange; | |||
81 | struct sadb_protocol sa_flowtype, sa_protocol; | |||
82 | struct iovec iov[IOV_CNT20]; | |||
83 | ssize_t n; | |||
84 | int len = 0; | |||
85 | int iov_cnt; | |||
86 | struct sockaddr_storage ssrc, sdst, speer, smask, dmask; | |||
87 | struct sockaddr *saptr; | |||
88 | socklen_t salen; | |||
89 | ||||
90 | if (!pid) | |||
91 | pid = getpid(); | |||
92 | ||||
93 | /* we need clean sockaddr... no ports set */ | |||
94 | bzero(&ssrc, sizeof(ssrc)); | |||
95 | bzero(&smask, sizeof(smask)); | |||
96 | if ((saptr = addr2sa(src, 0, &salen))) { | |||
97 | memcpy(&ssrc, saptr, salen); | |||
98 | ssrc.ss_len = salen; | |||
99 | } | |||
100 | switch (src->aid) { | |||
101 | case AID_INET1: | |||
102 | memset(&((struct sockaddr_in *)&smask)->sin_addr, 0xff, 32/8); | |||
103 | break; | |||
104 | case AID_INET62: | |||
105 | memset(&((struct sockaddr_in6 *)&smask)->sin6_addr, 0xff, | |||
106 | 128/8); | |||
107 | break; | |||
108 | case AID_UNSPEC0: | |||
109 | ssrc.ss_len = sizeof(struct sockaddr); | |||
110 | break; | |||
111 | default: | |||
112 | return (-1); | |||
113 | } | |||
114 | smask.ss_family = ssrc.ss_family; | |||
115 | smask.ss_len = ssrc.ss_len; | |||
116 | ||||
117 | bzero(&sdst, sizeof(sdst)); | |||
118 | bzero(&dmask, sizeof(dmask)); | |||
119 | if ((saptr = addr2sa(dst, 0, &salen))) { | |||
120 | memcpy(&sdst, saptr, salen); | |||
121 | sdst.ss_len = salen; | |||
122 | } | |||
123 | switch (dst->aid) { | |||
124 | case AID_INET1: | |||
125 | memset(&((struct sockaddr_in *)&dmask)->sin_addr, 0xff, 32/8); | |||
126 | break; | |||
127 | case AID_INET62: | |||
128 | memset(&((struct sockaddr_in6 *)&dmask)->sin6_addr, 0xff, | |||
129 | 128/8); | |||
130 | break; | |||
131 | case AID_UNSPEC0: | |||
132 | sdst.ss_len = sizeof(struct sockaddr); | |||
133 | break; | |||
134 | default: | |||
135 | return (-1); | |||
136 | } | |||
137 | dmask.ss_family = sdst.ss_family; | |||
138 | dmask.ss_len = sdst.ss_len; | |||
139 | ||||
140 | bzero(&smsg, sizeof(smsg)); | |||
141 | smsg.sadb_msg_version = PF_KEY_V22; | |||
142 | smsg.sadb_msg_seq = ++sadb_msg_seq; | |||
143 | smsg.sadb_msg_pid = pid; | |||
144 | smsg.sadb_msg_len = sizeof(smsg) / 8; | |||
145 | smsg.sadb_msg_type = mtype; | |||
146 | smsg.sadb_msg_satype = satype; | |||
147 | ||||
148 | switch (mtype) { | |||
149 | case SADB_GETSPI1: | |||
150 | bzero(&sa_spirange, sizeof(sa_spirange)); | |||
151 | sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE16; | |||
152 | sa_spirange.sadb_spirange_len = sizeof(sa_spirange) / 8; | |||
153 | sa_spirange.sadb_spirange_min = 0x100; | |||
154 | sa_spirange.sadb_spirange_max = 0xffffffff; | |||
155 | sa_spirange.sadb_spirange_reserved = 0; | |||
156 | break; | |||
157 | case SADB_ADD3: | |||
158 | case SADB_UPDATE2: | |||
159 | case SADB_DELETE4: | |||
160 | bzero(&sa, sizeof(sa)); | |||
161 | sa.sadb_sa_exttype = SADB_EXT_SA1; | |||
162 | sa.sadb_sa_len = sizeof(sa) / 8; | |||
163 | sa.sadb_sa_replay = 0; | |||
164 | sa.sadb_sa_spi = htonl(spi)(__uint32_t)(__builtin_constant_p(spi) ? (__uint32_t)(((__uint32_t )(spi) & 0xff) << 24 | ((__uint32_t)(spi) & 0xff00 ) << 8 | ((__uint32_t)(spi) & 0xff0000) >> 8 | ((__uint32_t)(spi) & 0xff000000) >> 24) : __swap32md (spi)); | |||
165 | sa.sadb_sa_state = SADB_SASTATE_MATURE1; | |||
166 | break; | |||
167 | case SADB_X_ADDFLOW12: | |||
168 | case SADB_X_DELFLOW13: | |||
169 | bzero(&sa_flowtype, sizeof(sa_flowtype)); | |||
170 | sa_flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE20; | |||
171 | sa_flowtype.sadb_protocol_len = sizeof(sa_flowtype) / 8; | |||
172 | sa_flowtype.sadb_protocol_direction = dir; | |||
173 | sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_REQUIRE3; | |||
174 | ||||
175 | bzero(&sa_protocol, sizeof(sa_protocol)); | |||
176 | sa_protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL19; | |||
177 | sa_protocol.sadb_protocol_len = sizeof(sa_protocol) / 8; | |||
178 | sa_protocol.sadb_protocol_direction = 0; | |||
179 | sa_protocol.sadb_protocol_proto = 6; | |||
180 | break; | |||
181 | } | |||
182 | ||||
183 | bzero(&sa_src, sizeof(sa_src)); | |||
184 | sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC5; | |||
185 | sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)(((ssrc.ss_len) + (sizeof(u_int64_t) - 1)) & ~(sizeof(u_int64_t ) - 1))) / 8; | |||
186 | ||||
187 | bzero(&sa_dst, sizeof(sa_dst)); | |||
188 | sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST6; | |||
189 | sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)(((sdst.ss_len) + (sizeof(u_int64_t) - 1)) & ~(sizeof(u_int64_t ) - 1))) / 8; | |||
190 | ||||
191 | sa.sadb_sa_auth = aalg; | |||
192 | sa.sadb_sa_encrypt = SADB_X_EALG_AES12; /* XXX */ | |||
193 | ||||
194 | switch (mtype) { | |||
195 | case SADB_ADD3: | |||
196 | case SADB_UPDATE2: | |||
197 | bzero(&sa_akey, sizeof(sa_akey)); | |||
198 | sa_akey.sadb_key_exttype = SADB_EXT_KEY_AUTH8; | |||
199 | sa_akey.sadb_key_len = (sizeof(sa_akey) + | |||
200 | ((alen + 7) / 8) * 8) / 8; | |||
201 | sa_akey.sadb_key_bits = 8 * alen; | |||
202 | ||||
203 | bzero(&sa_ekey, sizeof(sa_ekey)); | |||
204 | sa_ekey.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT9; | |||
205 | sa_ekey.sadb_key_len = (sizeof(sa_ekey) + | |||
206 | ((elen + 7) / 8) * 8) / 8; | |||
207 | sa_ekey.sadb_key_bits = 8 * elen; | |||
208 | ||||
209 | break; | |||
210 | case SADB_X_ADDFLOW12: | |||
211 | case SADB_X_DELFLOW13: | |||
212 | /* sa_peer always points to the remote machine */ | |||
213 | if (dir == IPSP_DIRECTION_IN0x1) { | |||
214 | speer = ssrc; | |||
215 | sa_peer = sa_src; | |||
216 | } else { | |||
217 | speer = sdst; | |||
218 | sa_peer = sa_dst; | |||
219 | } | |||
220 | sa_peer.sadb_address_exttype = SADB_EXT_ADDRESS_DST6; | |||
221 | sa_peer.sadb_address_len = | |||
222 | (sizeof(sa_peer) + ROUNDUP(speer.ss_len)(((speer.ss_len) + (sizeof(u_int64_t) - 1)) & ~(sizeof(u_int64_t ) - 1))) / 8; | |||
223 | ||||
224 | /* for addflow we also use src/dst as the flow destination */ | |||
225 | sa_src.sadb_address_exttype = SADB_X_EXT_SRC_FLOW21; | |||
226 | sa_dst.sadb_address_exttype = SADB_X_EXT_DST_FLOW22; | |||
227 | ||||
228 | bzero(&smask, sizeof(smask)); | |||
229 | switch (src->aid) { | |||
230 | case AID_INET1: | |||
231 | smask.ss_len = sizeof(struct sockaddr_in); | |||
232 | smask.ss_family = AF_INET2; | |||
233 | memset(&((struct sockaddr_in *)&smask)->sin_addr, | |||
234 | 0xff, 32/8); | |||
235 | if (sport) { | |||
236 | ((struct sockaddr_in *)&ssrc)->sin_port = | |||
237 | htons(sport)(__uint16_t)(__builtin_constant_p(sport) ? (__uint16_t)(((__uint16_t )(sport) & 0xffU) << 8 | ((__uint16_t)(sport) & 0xff00U) >> 8) : __swap16md(sport)); | |||
238 | ((struct sockaddr_in *)&smask)->sin_port = | |||
239 | htons(0xffff)(__uint16_t)(__builtin_constant_p(0xffff) ? (__uint16_t)(((__uint16_t )(0xffff) & 0xffU) << 8 | ((__uint16_t)(0xffff) & 0xff00U) >> 8) : __swap16md(0xffff)); | |||
240 | } | |||
241 | break; | |||
242 | case AID_INET62: | |||
243 | smask.ss_len = sizeof(struct sockaddr_in6); | |||
244 | smask.ss_family = AF_INET624; | |||
245 | memset(&((struct sockaddr_in6 *)&smask)->sin6_addr, | |||
246 | 0xff, 128/8); | |||
247 | if (sport) { | |||
248 | ((struct sockaddr_in6 *)&ssrc)->sin6_port = | |||
249 | htons(sport)(__uint16_t)(__builtin_constant_p(sport) ? (__uint16_t)(((__uint16_t )(sport) & 0xffU) << 8 | ((__uint16_t)(sport) & 0xff00U) >> 8) : __swap16md(sport)); | |||
250 | ((struct sockaddr_in6 *)&smask)->sin6_port = | |||
251 | htons(0xffff)(__uint16_t)(__builtin_constant_p(0xffff) ? (__uint16_t)(((__uint16_t )(0xffff) & 0xffU) << 8 | ((__uint16_t)(0xffff) & 0xff00U) >> 8) : __swap16md(0xffff)); | |||
252 | } | |||
253 | break; | |||
254 | } | |||
255 | bzero(&dmask, sizeof(dmask)); | |||
256 | switch (dst->aid) { | |||
257 | case AID_INET1: | |||
258 | dmask.ss_len = sizeof(struct sockaddr_in); | |||
259 | dmask.ss_family = AF_INET2; | |||
260 | memset(&((struct sockaddr_in *)&dmask)->sin_addr, | |||
261 | 0xff, 32/8); | |||
262 | if (dport) { | |||
263 | ((struct sockaddr_in *)&sdst)->sin_port = | |||
264 | htons(dport)(__uint16_t)(__builtin_constant_p(dport) ? (__uint16_t)(((__uint16_t )(dport) & 0xffU) << 8 | ((__uint16_t)(dport) & 0xff00U) >> 8) : __swap16md(dport)); | |||
265 | ((struct sockaddr_in *)&dmask)->sin_port = | |||
266 | htons(0xffff)(__uint16_t)(__builtin_constant_p(0xffff) ? (__uint16_t)(((__uint16_t )(0xffff) & 0xffU) << 8 | ((__uint16_t)(0xffff) & 0xff00U) >> 8) : __swap16md(0xffff)); | |||
267 | } | |||
268 | break; | |||
269 | case AID_INET62: | |||
270 | dmask.ss_len = sizeof(struct sockaddr_in6); | |||
271 | dmask.ss_family = AF_INET624; | |||
272 | memset(&((struct sockaddr_in6 *)&dmask)->sin6_addr, | |||
273 | 0xff, 128/8); | |||
274 | if (dport) { | |||
275 | ((struct sockaddr_in6 *)&sdst)->sin6_port = | |||
276 | htons(dport)(__uint16_t)(__builtin_constant_p(dport) ? (__uint16_t)(((__uint16_t )(dport) & 0xffU) << 8 | ((__uint16_t)(dport) & 0xff00U) >> 8) : __swap16md(dport)); | |||
277 | ((struct sockaddr_in6 *)&dmask)->sin6_port = | |||
278 | htons(0xffff)(__uint16_t)(__builtin_constant_p(0xffff) ? (__uint16_t)(((__uint16_t )(0xffff) & 0xffU) << 8 | ((__uint16_t)(0xffff) & 0xff00U) >> 8) : __swap16md(0xffff)); | |||
279 | } | |||
280 | break; | |||
281 | } | |||
282 | ||||
283 | bzero(&sa_smask, sizeof(sa_smask)); | |||
284 | sa_smask.sadb_address_exttype = SADB_X_EXT_SRC_MASK17; | |||
285 | sa_smask.sadb_address_len = | |||
286 | (sizeof(sa_smask) + ROUNDUP(smask.ss_len)(((smask.ss_len) + (sizeof(u_int64_t) - 1)) & ~(sizeof(u_int64_t ) - 1))) / 8; | |||
287 | ||||
288 | bzero(&sa_dmask, sizeof(sa_dmask)); | |||
289 | sa_dmask.sadb_address_exttype = SADB_X_EXT_DST_MASK18; | |||
290 | sa_dmask.sadb_address_len = | |||
291 | (sizeof(sa_dmask) + ROUNDUP(dmask.ss_len)(((dmask.ss_len) + (sizeof(u_int64_t) - 1)) & ~(sizeof(u_int64_t ) - 1))) / 8; | |||
292 | break; | |||
293 | } | |||
294 | ||||
295 | iov_cnt = 0; | |||
296 | ||||
297 | /* msghdr */ | |||
298 | iov[iov_cnt].iov_base = &smsg; | |||
299 | iov[iov_cnt].iov_len = sizeof(smsg); | |||
300 | iov_cnt++; | |||
301 | ||||
302 | switch (mtype) { | |||
303 | case SADB_ADD3: | |||
304 | case SADB_UPDATE2: | |||
305 | case SADB_DELETE4: | |||
306 | /* SA hdr */ | |||
307 | iov[iov_cnt].iov_base = &sa; | |||
308 | iov[iov_cnt].iov_len = sizeof(sa); | |||
309 | smsg.sadb_msg_len += sa.sadb_sa_len; | |||
310 | iov_cnt++; | |||
311 | break; | |||
312 | case SADB_GETSPI1: | |||
313 | /* SPI range */ | |||
314 | iov[iov_cnt].iov_base = &sa_spirange; | |||
315 | iov[iov_cnt].iov_len = sizeof(sa_spirange); | |||
316 | smsg.sadb_msg_len += sa_spirange.sadb_spirange_len; | |||
317 | iov_cnt++; | |||
318 | break; | |||
319 | case SADB_X_ADDFLOW12: | |||
320 | /* sa_peer always points to the remote machine */ | |||
321 | iov[iov_cnt].iov_base = &sa_peer; | |||
322 | iov[iov_cnt].iov_len = sizeof(sa_peer); | |||
323 | iov_cnt++; | |||
324 | iov[iov_cnt].iov_base = &speer; | |||
325 | iov[iov_cnt].iov_len = ROUNDUP(speer.ss_len)(((speer.ss_len) + (sizeof(u_int64_t) - 1)) & ~(sizeof(u_int64_t ) - 1)); | |||
326 | smsg.sadb_msg_len += sa_peer.sadb_address_len; | |||
327 | iov_cnt++; | |||
328 | ||||
329 | /* FALLTHROUGH */ | |||
330 | case SADB_X_DELFLOW13: | |||
331 | /* add flow type */ | |||
332 | iov[iov_cnt].iov_base = &sa_flowtype; | |||
333 | iov[iov_cnt].iov_len = sizeof(sa_flowtype); | |||
334 | smsg.sadb_msg_len += sa_flowtype.sadb_protocol_len; | |||
335 | iov_cnt++; | |||
336 | ||||
337 | /* add protocol */ | |||
338 | iov[iov_cnt].iov_base = &sa_protocol; | |||
339 | iov[iov_cnt].iov_len = sizeof(sa_protocol); | |||
340 | smsg.sadb_msg_len += sa_protocol.sadb_protocol_len; | |||
341 | iov_cnt++; | |||
342 | ||||
343 | /* add flow masks */ | |||
344 | iov[iov_cnt].iov_base = &sa_smask; | |||
345 | iov[iov_cnt].iov_len = sizeof(sa_smask); | |||
346 | iov_cnt++; | |||
347 | iov[iov_cnt].iov_base = &smask; | |||
348 | iov[iov_cnt].iov_len = ROUNDUP(smask.ss_len)(((smask.ss_len) + (sizeof(u_int64_t) - 1)) & ~(sizeof(u_int64_t ) - 1)); | |||
349 | smsg.sadb_msg_len += sa_smask.sadb_address_len; | |||
350 | iov_cnt++; | |||
351 | ||||
352 | iov[iov_cnt].iov_base = &sa_dmask; | |||
353 | iov[iov_cnt].iov_len = sizeof(sa_dmask); | |||
354 | iov_cnt++; | |||
355 | iov[iov_cnt].iov_base = &dmask; | |||
356 | iov[iov_cnt].iov_len = ROUNDUP(dmask.ss_len)(((dmask.ss_len) + (sizeof(u_int64_t) - 1)) & ~(sizeof(u_int64_t ) - 1)); | |||
357 | smsg.sadb_msg_len += sa_dmask.sadb_address_len; | |||
358 | iov_cnt++; | |||
359 | break; | |||
360 | } | |||
361 | ||||
362 | /* dest addr */ | |||
363 | iov[iov_cnt].iov_base = &sa_dst; | |||
364 | iov[iov_cnt].iov_len = sizeof(sa_dst); | |||
365 | iov_cnt++; | |||
366 | iov[iov_cnt].iov_base = &sdst; | |||
367 | iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len)(((sdst.ss_len) + (sizeof(u_int64_t) - 1)) & ~(sizeof(u_int64_t ) - 1)); | |||
368 | smsg.sadb_msg_len += sa_dst.sadb_address_len; | |||
369 | iov_cnt++; | |||
370 | ||||
371 | /* src addr */ | |||
372 | iov[iov_cnt].iov_base = &sa_src; | |||
373 | iov[iov_cnt].iov_len = sizeof(sa_src); | |||
374 | iov_cnt++; | |||
375 | iov[iov_cnt].iov_base = &ssrc; | |||
376 | iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len)(((ssrc.ss_len) + (sizeof(u_int64_t) - 1)) & ~(sizeof(u_int64_t ) - 1)); | |||
377 | smsg.sadb_msg_len += sa_src.sadb_address_len; | |||
378 | iov_cnt++; | |||
379 | ||||
380 | switch (mtype) { | |||
381 | case SADB_ADD3: | |||
382 | case SADB_UPDATE2: | |||
383 | if (alen) { | |||
384 | /* auth key */ | |||
385 | iov[iov_cnt].iov_base = &sa_akey; | |||
386 | iov[iov_cnt].iov_len = sizeof(sa_akey); | |||
387 | iov_cnt++; | |||
388 | iov[iov_cnt].iov_base = akey; | |||
389 | iov[iov_cnt].iov_len = ((alen + 7) / 8) * 8; | |||
390 | smsg.sadb_msg_len += sa_akey.sadb_key_len; | |||
391 | iov_cnt++; | |||
392 | } | |||
393 | if (elen) { | |||
394 | /* encryption key */ | |||
395 | iov[iov_cnt].iov_base = &sa_ekey; | |||
396 | iov[iov_cnt].iov_len = sizeof(sa_ekey); | |||
397 | iov_cnt++; | |||
398 | iov[iov_cnt].iov_base = ekey; | |||
399 | iov[iov_cnt].iov_len = ((elen + 7) / 8) * 8; | |||
400 | smsg.sadb_msg_len += sa_ekey.sadb_key_len; | |||
401 | iov_cnt++; | |||
402 | } | |||
403 | break; | |||
404 | } | |||
405 | ||||
406 | len = smsg.sadb_msg_len * 8; | |||
407 | do { | |||
408 | n = writev(sd, iov, iov_cnt); | |||
409 | } while (n == -1 && (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)); | |||
410 | ||||
411 | if (n == -1) { | |||
412 | log_warn("%s: writev (%d/%d)", __func__, iov_cnt, len); | |||
413 | return (-1); | |||
414 | } | |||
415 | ||||
416 | return (0); | |||
417 | } | |||
418 | ||||
419 | int | |||
420 | pfkey_read(int sd, struct sadb_msg *h) | |||
421 | { | |||
422 | struct sadb_msg hdr; | |||
423 | ||||
424 | if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK0x2) != sizeof(hdr)) { | |||
425 | if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4) | |||
426 | return (0); | |||
427 | log_warn("pfkey peek"); | |||
428 | return (-1); | |||
429 | } | |||
430 | ||||
431 | /* XXX: Only one message can be outstanding. */ | |||
432 | if (hdr.sadb_msg_seq == sadb_msg_seq && | |||
433 | hdr.sadb_msg_pid == pid) { | |||
434 | if (h) | |||
435 | bcopy(&hdr, h, sizeof(hdr)); | |||
436 | return (0); | |||
437 | } | |||
438 | ||||
439 | /* not ours, discard */ | |||
440 | if (read(sd, &hdr, sizeof(hdr)) == -1) { | |||
441 | if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4) | |||
442 | return (0); | |||
443 | log_warn("pfkey read"); | |||
444 | return (-1); | |||
445 | } | |||
446 | ||||
447 | return (1); | |||
448 | } | |||
449 | ||||
450 | int | |||
451 | pfkey_reply(int sd, u_int32_t *spi) | |||
452 | { | |||
453 | struct sadb_msg hdr, *msg; | |||
454 | struct sadb_ext *ext; | |||
455 | struct sadb_sa *sa; | |||
456 | u_int8_t *data; | |||
457 | ssize_t len; | |||
458 | int rv; | |||
459 | ||||
460 | do { | |||
461 | rv = pfkey_read(sd, &hdr); | |||
462 | if (rv == -1) | |||
463 | return (-1); | |||
464 | } while (rv); | |||
465 | ||||
466 | if (hdr.sadb_msg_errno != 0) { | |||
| ||||
467 | errno(*__errno()) = hdr.sadb_msg_errno; | |||
468 | if (errno(*__errno()) == ESRCH3) | |||
469 | return (0); | |||
470 | else { | |||
471 | log_warn("pfkey"); | |||
472 | return (-1); | |||
473 | } | |||
474 | } | |||
475 | if ((data = reallocarray(NULL((void *)0), hdr.sadb_msg_len, PFKEY2_CHUNKsizeof(u_int64_t))) | |||
476 | == NULL((void *)0)) { | |||
477 | log_warn("pfkey malloc"); | |||
478 | return (-1); | |||
479 | } | |||
480 | len = hdr.sadb_msg_len * PFKEY2_CHUNKsizeof(u_int64_t); | |||
481 | if (read(sd, data, len) != len) { | |||
482 | log_warn("pfkey read"); | |||
483 | freezero(data, len); | |||
484 | return (-1); | |||
485 | } | |||
486 | ||||
487 | if (hdr.sadb_msg_type == SADB_GETSPI1) { | |||
488 | if (spi == NULL((void *)0)) { | |||
489 | freezero(data, len); | |||
490 | return (0); | |||
491 | } | |||
492 | ||||
493 | msg = (struct sadb_msg *)data; | |||
494 | for (ext = (struct sadb_ext *)(msg + 1); | |||
495 | (size_t)((u_int8_t *)ext - (u_int8_t *)msg) < | |||
496 | msg->sadb_msg_len * PFKEY2_CHUNKsizeof(u_int64_t); | |||
497 | ext = (struct sadb_ext *)((u_int8_t *)ext + | |||
498 | ext->sadb_ext_len * PFKEY2_CHUNKsizeof(u_int64_t))) { | |||
499 | if (ext->sadb_ext_type == SADB_EXT_SA1) { | |||
500 | sa = (struct sadb_sa *) ext; | |||
501 | *spi = ntohl(sa->sadb_sa_spi)(__uint32_t)(__builtin_constant_p(sa->sadb_sa_spi) ? (__uint32_t )(((__uint32_t)(sa->sadb_sa_spi) & 0xff) << 24 | ((__uint32_t)(sa->sadb_sa_spi) & 0xff00) << 8 | ((__uint32_t)(sa->sadb_sa_spi) & 0xff0000) >> 8 | ((__uint32_t)(sa->sadb_sa_spi) & 0xff000000) >> 24) : __swap32md(sa->sadb_sa_spi)); | |||
502 | break; | |||
503 | } | |||
504 | } | |||
505 | } | |||
506 | freezero(data, len); | |||
507 | return (0); | |||
508 | } | |||
509 | ||||
510 | static int | |||
511 | pfkey_sa_add(struct bgpd_addr *src, struct bgpd_addr *dst, u_int8_t keylen, | |||
512 | char *key, u_int32_t *spi) | |||
513 | { | |||
514 | if (pfkey_send(pfkey_fd, SADB_X_SATYPE_TCPSIGNATURE8, SADB_GETSPI1, 0, | |||
515 | src, dst, 0, 0, 0, NULL((void *)0), 0, 0, NULL((void *)0), 0, 0) == -1) | |||
516 | return (-1); | |||
517 | if (pfkey_reply(pfkey_fd, spi) == -1) | |||
518 | return (-1); | |||
519 | if (pfkey_send(pfkey_fd, SADB_X_SATYPE_TCPSIGNATURE8, SADB_UPDATE2, 0, | |||
520 | src, dst, *spi, 0, keylen, key, 0, 0, NULL((void *)0), 0, 0) == -1) | |||
521 | return (-1); | |||
522 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
523 | return (-1); | |||
524 | return (0); | |||
525 | } | |||
526 | ||||
527 | static int | |||
528 | pfkey_sa_remove(struct bgpd_addr *src, struct bgpd_addr *dst, u_int32_t *spi) | |||
529 | { | |||
530 | if (pfkey_send(pfkey_fd, SADB_X_SATYPE_TCPSIGNATURE8, SADB_DELETE4, 0, | |||
531 | src, dst, *spi, 0, 0, NULL((void *)0), 0, 0, NULL((void *)0), 0, 0) == -1) | |||
532 | return (-1); | |||
533 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
534 | return (-1); | |||
535 | *spi = 0; | |||
536 | return (0); | |||
537 | } | |||
538 | ||||
539 | static int | |||
540 | pfkey_md5sig_establish(struct peer *p) | |||
541 | { | |||
542 | u_int32_t spi_out = 0; | |||
543 | u_int32_t spi_in = 0; | |||
544 | ||||
545 | if (pfkey_sa_add(pfkey_localaddr(p), &p->conf.remote_addr, | |||
546 | p->conf.auth.md5key_len, p->conf.auth.md5key, | |||
547 | &spi_out) == -1) | |||
548 | goto fail; | |||
549 | ||||
550 | if (pfkey_sa_add(&p->conf.remote_addr, pfkey_localaddr(p), | |||
551 | p->conf.auth.md5key_len, p->conf.auth.md5key, | |||
552 | &spi_in) == -1) | |||
553 | goto fail; | |||
554 | ||||
555 | /* cleanup old flow if one was present */ | |||
556 | if (p->auth.established) { | |||
557 | if (pfkey_remove(p) == -1) | |||
558 | return (-1); | |||
559 | } | |||
560 | ||||
561 | p->auth.established = 1; | |||
562 | p->auth.spi_out = spi_out; | |||
563 | p->auth.spi_in = spi_in; | |||
564 | return (0); | |||
565 | ||||
566 | fail: | |||
567 | log_peer_warn(&p->conf, "%s: failed to insert md5sig", __func__); | |||
568 | return (-1); | |||
569 | } | |||
570 | ||||
571 | static int | |||
572 | pfkey_md5sig_remove(struct peer *p) | |||
573 | { | |||
574 | if (p->auth.spi_out) | |||
575 | if (pfkey_sa_remove(&p->auth.local_addr, &p->conf.remote_addr, | |||
576 | &p->auth.spi_out) == -1) | |||
577 | goto fail; | |||
578 | if (p->auth.spi_in) | |||
579 | if (pfkey_sa_remove(&p->conf.remote_addr, &p->auth.local_addr, | |||
580 | &p->auth.spi_in) == -1) | |||
581 | goto fail; | |||
582 | ||||
583 | p->auth.established = 0; | |||
584 | p->auth.spi_out = 0; | |||
585 | p->auth.spi_in = 0; | |||
586 | return (0); | |||
587 | ||||
588 | fail: | |||
589 | log_peer_warn(&p->conf, "%s: failed to remove md5sig", __func__); | |||
590 | return (-1); | |||
591 | } | |||
592 | ||||
593 | static int | |||
594 | pfkey_ipsec_establish(struct peer *p) | |||
595 | { | |||
596 | uint8_t satype = SADB_SATYPE_ESP2; | |||
597 | struct bgpd_addr *local_addr = pfkey_localaddr(p); | |||
598 | ||||
599 | /* cleanup first, unlike in the TCP MD5 case */ | |||
600 | if (p->auth.established) { | |||
601 | if (pfkey_remove(p) == -1) | |||
602 | return (-1); | |||
603 | } | |||
604 | ||||
605 | switch (p->auth.method) { | |||
606 | case AUTH_IPSEC_IKE_ESP: | |||
607 | satype = SADB_SATYPE_ESP2; | |||
608 | break; | |||
609 | case AUTH_IPSEC_IKE_AH: | |||
610 | satype = SADB_SATYPE_AH1; | |||
611 | break; | |||
612 | case AUTH_IPSEC_MANUAL_ESP: | |||
613 | case AUTH_IPSEC_MANUAL_AH: | |||
614 | satype = p->auth.method == AUTH_IPSEC_MANUAL_ESP ? | |||
615 | SADB_SATYPE_ESP2 : SADB_SATYPE_AH1; | |||
616 | if (pfkey_send(pfkey_fd, satype, SADB_ADD3, 0, | |||
617 | local_addr, &p->conf.remote_addr, | |||
618 | p->conf.auth.spi_out, | |||
619 | p->conf.auth.auth_alg_out, | |||
620 | p->conf.auth.auth_keylen_out, | |||
621 | p->conf.auth.auth_key_out, | |||
622 | p->conf.auth.enc_alg_out, | |||
623 | p->conf.auth.enc_keylen_out, | |||
624 | p->conf.auth.enc_key_out, | |||
625 | 0, 0) == -1) | |||
626 | goto fail_key; | |||
627 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
628 | goto fail_key; | |||
629 | if (pfkey_send(pfkey_fd, satype, SADB_ADD3, 0, | |||
630 | &p->conf.remote_addr, local_addr, | |||
631 | p->conf.auth.spi_in, | |||
632 | p->conf.auth.auth_alg_in, | |||
633 | p->conf.auth.auth_keylen_in, | |||
634 | p->conf.auth.auth_key_in, | |||
635 | p->conf.auth.enc_alg_in, | |||
636 | p->conf.auth.enc_keylen_in, | |||
637 | p->conf.auth.enc_key_in, | |||
638 | 0, 0) == -1) | |||
639 | goto fail_key; | |||
640 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
641 | goto fail_key; | |||
642 | break; | |||
643 | default: | |||
644 | return (-1); | |||
645 | } | |||
646 | ||||
647 | if (pfkey_flow(pfkey_fd, satype, SADB_X_ADDFLOW, IPSP_DIRECTION_OUT,pfkey_send(pfkey_fd, satype, 12, 0x2, local_addr, &p-> conf.remote_addr, 0, 0, 0, ((void *)0), 0, 0, ((void *)0), 0, 179) | |||
648 | local_addr, &p->conf.remote_addr, 0, BGP_PORT)pfkey_send(pfkey_fd, satype, 12, 0x2, local_addr, &p-> conf.remote_addr, 0, 0, 0, ((void *)0), 0, 0, ((void *)0), 0, 179) == -1) | |||
649 | goto fail_flow; | |||
650 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
651 | goto fail_flow; | |||
652 | ||||
653 | if (pfkey_flow(pfkey_fd, satype, SADB_X_ADDFLOW, IPSP_DIRECTION_OUT,pfkey_send(pfkey_fd, satype, 12, 0x2, local_addr, &p-> conf.remote_addr, 0, 0, 0, ((void *)0), 0, 0, ((void *)0), 179 , 0) | |||
654 | local_addr, &p->conf.remote_addr, BGP_PORT, 0)pfkey_send(pfkey_fd, satype, 12, 0x2, local_addr, &p-> conf.remote_addr, 0, 0, 0, ((void *)0), 0, 0, ((void *)0), 179 , 0) == -1) | |||
655 | goto fail_flow; | |||
656 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
657 | goto fail_flow; | |||
658 | ||||
659 | if (pfkey_flow(pfkey_fd, satype, SADB_X_ADDFLOW, IPSP_DIRECTION_IN,pfkey_send(pfkey_fd, satype, 12, 0x1, &p->conf.remote_addr , local_addr, 0, 0, 0, ((void *)0), 0, 0, ((void *)0), 0, 179 ) | |||
660 | &p->conf.remote_addr, local_addr, 0, BGP_PORT)pfkey_send(pfkey_fd, satype, 12, 0x1, &p->conf.remote_addr , local_addr, 0, 0, 0, ((void *)0), 0, 0, ((void *)0), 0, 179 ) == -1) | |||
661 | goto fail_flow; | |||
662 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
663 | goto fail_flow; | |||
664 | ||||
665 | if (pfkey_flow(pfkey_fd, satype, SADB_X_ADDFLOW, IPSP_DIRECTION_IN,pfkey_send(pfkey_fd, satype, 12, 0x1, &p->conf.remote_addr , local_addr, 0, 0, 0, ((void *)0), 0, 0, ((void *)0), 179, 0 ) | |||
666 | &p->conf.remote_addr, local_addr, BGP_PORT, 0)pfkey_send(pfkey_fd, satype, 12, 0x1, &p->conf.remote_addr , local_addr, 0, 0, 0, ((void *)0), 0, 0, ((void *)0), 179, 0 ) == -1) | |||
667 | goto fail_flow; | |||
668 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
669 | goto fail_flow; | |||
670 | ||||
671 | /* save SPI so that they can be removed later on */ | |||
672 | p->auth.spi_in = p->conf.auth.spi_in; | |||
673 | p->auth.spi_out = p->conf.auth.spi_out; | |||
674 | p->auth.established = 1; | |||
675 | return (0); | |||
676 | ||||
677 | fail_key: | |||
678 | log_peer_warn(&p->conf, "%s: failed to insert ipsec key", __func__); | |||
679 | return (-1); | |||
680 | fail_flow: | |||
681 | log_peer_warn(&p->conf, "%s: failed to insert flow", __func__); | |||
682 | return (-1); | |||
683 | } | |||
684 | ||||
685 | static int | |||
686 | pfkey_ipsec_remove(struct peer *p) | |||
687 | { | |||
688 | uint8_t satype; | |||
689 | ||||
690 | switch (p->auth.method) { | |||
691 | case AUTH_IPSEC_IKE_ESP: | |||
692 | satype = SADB_SATYPE_ESP2; | |||
693 | break; | |||
694 | case AUTH_IPSEC_IKE_AH: | |||
695 | satype = SADB_SATYPE_AH1; | |||
696 | break; | |||
697 | case AUTH_IPSEC_MANUAL_ESP: | |||
698 | case AUTH_IPSEC_MANUAL_AH: | |||
699 | satype = p->auth.method == AUTH_IPSEC_MANUAL_ESP ? | |||
700 | SADB_SATYPE_ESP2 : SADB_SATYPE_AH1; | |||
701 | if (pfkey_send(pfkey_fd, satype, SADB_DELETE4, 0, | |||
702 | &p->auth.local_addr, &p->conf.remote_addr, | |||
703 | p->auth.spi_out, 0, 0, NULL((void *)0), 0, 0, NULL((void *)0), | |||
704 | 0, 0) == -1) | |||
705 | goto fail_key; | |||
706 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
707 | goto fail_key; | |||
708 | ||||
709 | if (pfkey_send(pfkey_fd, satype, SADB_DELETE4, 0, | |||
710 | &p->conf.remote_addr, &p->auth.local_addr, | |||
711 | p->auth.spi_in, 0, 0, NULL((void *)0), 0, 0, NULL((void *)0), | |||
712 | 0, 0) == -1) | |||
713 | goto fail_key; | |||
714 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
715 | goto fail_key; | |||
716 | break; | |||
717 | default: | |||
718 | return (-1); | |||
719 | } | |||
720 | ||||
721 | if (pfkey_flow(pfkey_fd, satype, SADB_X_DELFLOW, IPSP_DIRECTION_OUT,pfkey_send(pfkey_fd, satype, 13, 0x2, &p->auth.local_addr , &p->conf.remote_addr, 0, 0, 0, ((void *)0), 0, 0, (( void *)0), 0, 179) | |||
722 | &p->auth.local_addr, &p->conf.remote_addr, 0, BGP_PORT)pfkey_send(pfkey_fd, satype, 13, 0x2, &p->auth.local_addr , &p->conf.remote_addr, 0, 0, 0, ((void *)0), 0, 0, (( void *)0), 0, 179) == -1) | |||
723 | goto fail_flow; | |||
724 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
725 | goto fail_flow; | |||
726 | ||||
727 | if (pfkey_flow(pfkey_fd, satype, SADB_X_DELFLOW, IPSP_DIRECTION_OUT,pfkey_send(pfkey_fd, satype, 13, 0x2, &p->auth.local_addr , &p->conf.remote_addr, 0, 0, 0, ((void *)0), 0, 0, (( void *)0), 179, 0) | |||
728 | &p->auth.local_addr, &p->conf.remote_addr, BGP_PORT, 0)pfkey_send(pfkey_fd, satype, 13, 0x2, &p->auth.local_addr , &p->conf.remote_addr, 0, 0, 0, ((void *)0), 0, 0, (( void *)0), 179, 0) == -1) | |||
729 | goto fail_flow; | |||
730 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
731 | goto fail_flow; | |||
732 | ||||
733 | if (pfkey_flow(pfkey_fd, satype, SADB_X_DELFLOW, IPSP_DIRECTION_IN,pfkey_send(pfkey_fd, satype, 13, 0x1, &p->conf.remote_addr , &p->auth.local_addr, 0, 0, 0, ((void *)0), 0, 0, ((void *)0), 0, 179) | |||
734 | &p->conf.remote_addr, &p->auth.local_addr, 0, BGP_PORT)pfkey_send(pfkey_fd, satype, 13, 0x1, &p->conf.remote_addr , &p->auth.local_addr, 0, 0, 0, ((void *)0), 0, 0, ((void *)0), 0, 179) == -1) | |||
735 | goto fail_flow; | |||
736 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
737 | goto fail_flow; | |||
738 | ||||
739 | if (pfkey_flow(pfkey_fd, satype, SADB_X_DELFLOW, IPSP_DIRECTION_IN,pfkey_send(pfkey_fd, satype, 13, 0x1, &p->conf.remote_addr , &p->auth.local_addr, 0, 0, 0, ((void *)0), 0, 0, ((void *)0), 179, 0) | |||
740 | &p->conf.remote_addr, &p->auth.local_addr, BGP_PORT, 0)pfkey_send(pfkey_fd, satype, 13, 0x1, &p->conf.remote_addr , &p->auth.local_addr, 0, 0, 0, ((void *)0), 0, 0, ((void *)0), 179, 0) == -1) | |||
741 | goto fail_flow; | |||
742 | if (pfkey_reply(pfkey_fd, NULL((void *)0)) == -1) | |||
743 | goto fail_flow; | |||
744 | ||||
745 | p->auth.established = 0; | |||
746 | p->auth.spi_out = 0; | |||
747 | p->auth.spi_in = 0; | |||
748 | return (0); | |||
749 | ||||
750 | fail_key: | |||
751 | log_peer_warn(&p->conf, "%s: failed to remove ipsec key", __func__); | |||
752 | return (-1); | |||
753 | fail_flow: | |||
754 | log_peer_warn(&p->conf, "%s: failed to remove flow", __func__); | |||
755 | return (-1); | |||
756 | } | |||
757 | ||||
758 | int | |||
759 | pfkey_establish(struct peer *p) | |||
760 | { | |||
761 | int rv; | |||
762 | ||||
763 | switch (p->conf.auth.method) { | |||
| ||||
764 | case AUTH_NONE: | |||
765 | rv = 0; | |||
766 | if (p->auth.established) | |||
767 | rv = pfkey_remove(p); | |||
768 | break; | |||
769 | case AUTH_MD5SIG: | |||
770 | rv = pfkey_md5sig_establish(p); | |||
771 | break; | |||
772 | default: | |||
773 | rv = pfkey_ipsec_establish(p); | |||
774 | break; | |||
775 | } | |||
776 | /* | |||
777 | * make sure we keep copies of everything we need to | |||
778 | * remove SAs and flows later again, even if the | |||
779 | * info in p->conf changed due to reload. | |||
780 | * We need: SPIs, method, local_addr, remote_addr. | |||
781 | * remote_addr cannot change, so no copy, SPI are | |||
782 | * handled by the method specific functions. | |||
783 | */ | |||
784 | memcpy(&p->auth.local_addr, pfkey_localaddr(p), | |||
785 | sizeof(p->auth.local_addr)); | |||
786 | p->auth.method = p->conf.auth.method; | |||
787 | ||||
788 | return (rv); | |||
789 | } | |||
790 | ||||
791 | int | |||
792 | pfkey_remove(struct peer *p) | |||
793 | { | |||
794 | if (p->auth.established == 0) | |||
795 | return (0); | |||
796 | ||||
797 | switch (p->auth.method) { | |||
798 | case AUTH_NONE: | |||
799 | return (0); | |||
800 | case AUTH_MD5SIG: | |||
801 | return (pfkey_md5sig_remove(p)); | |||
802 | default: | |||
803 | return (pfkey_ipsec_remove(p)); | |||
804 | } | |||
805 | } | |||
806 | ||||
807 | int | |||
808 | pfkey_init(void) | |||
809 | { | |||
810 | if ((pfkey_fd = socket(PF_KEY30, SOCK_RAW3 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, | |||
811 | PF_KEY_V22)) == -1) { | |||
812 | if (errno(*__errno()) == EPROTONOSUPPORT43) { | |||
813 | log_warnx("PF_KEY not available, disabling ipsec"); | |||
814 | return (-1); | |||
815 | } else | |||
816 | fatal("pfkey setup failed"); | |||
817 | } | |||
818 | return (pfkey_fd); | |||
819 | } | |||
820 | ||||
821 | /* verify that connection is using TCP MD5UM if required by config */ | |||
822 | int | |||
823 | tcp_md5_check(int fd, struct peer *p) | |||
824 | { | |||
825 | socklen_t len; | |||
826 | int opt; | |||
827 | ||||
828 | if (p->conf.auth.method == AUTH_MD5SIG) { | |||
829 | if (sysdep.no_md5sig) { | |||
830 | log_peer_warnx(&p->conf, | |||
831 | "md5sig configured but not available"); | |||
832 | return -1; | |||
833 | } | |||
834 | len = sizeof(opt); | |||
835 | if (getsockopt(fd, IPPROTO_TCP6, TCP_MD5SIG0x04, | |||
836 | &opt, &len) == -1) | |||
837 | fatal("getsockopt TCP_MD5SIG"); | |||
838 | if (!opt) { /* non-md5'd connection! */ | |||
839 | log_peer_warnx(&p->conf, | |||
840 | "connection attempt without md5 signature"); | |||
841 | return -1; | |||
842 | } | |||
843 | } | |||
844 | return 0; | |||
845 | } | |||
846 | ||||
847 | /* enable or set TCP MD5SIG on a new client connection */ | |||
848 | int | |||
849 | tcp_md5_set(int fd, struct peer *p) | |||
850 | { | |||
851 | int opt = 1; | |||
852 | ||||
853 | if (p->conf.auth.method == AUTH_MD5SIG) { | |||
854 | if (sysdep.no_md5sig) { | |||
855 | log_peer_warnx(&p->conf, | |||
856 | "md5sig configured but not available"); | |||
857 | return -1; | |||
858 | } | |||
859 | if (setsockopt(fd, IPPROTO_TCP6, TCP_MD5SIG0x04, | |||
860 | &opt, sizeof(opt)) == -1) { | |||
861 | log_peer_warn(&p->conf, "setsockopt md5sig"); | |||
862 | return -1; | |||
863 | } | |||
864 | } | |||
865 | return 0; | |||
866 | } | |||
867 | ||||
868 | /* enable or prepare a new listening socket for TCP MD5SIG usage */ | |||
869 | int | |||
870 | tcp_md5_prep_listener(struct listen_addr *la, struct peer_head *p) | |||
871 | { | |||
872 | int opt = 1; | |||
873 | ||||
874 | if (setsockopt(la->fd, IPPROTO_TCP6, TCP_MD5SIG0x04, | |||
875 | &opt, sizeof(opt)) == -1) { | |||
876 | if (errno(*__errno()) == ENOPROTOOPT42) { /* system w/o md5sig */ | |||
877 | log_warnx("md5sig not available, disabling"); | |||
878 | sysdep.no_md5sig = 1; | |||
879 | return 0; | |||
880 | } | |||
881 | return -1; | |||
882 | } | |||
883 | return 0; | |||
884 | } | |||
885 | ||||
886 | /* add md5 key to all listening sockets, dummy function for portable */ | |||
887 | void | |||
888 | tcp_md5_add_listener(struct bgpd_config *conf, struct peer *p) | |||
889 | { | |||
890 | } | |||
891 | ||||
892 | /* delete md5 key form all listening sockets, dummy function for portable */ | |||
893 | void | |||
894 | tcp_md5_del_listener(struct bgpd_config *conf, struct peer *p) | |||
895 | { | |||
896 | } |