Commit | Line | Data |
---|---|---|
410c8acf | 1 | /* -*-c-*- |
2 | * | |
410c8acf | 3 | * Communication with the peer |
4 | * | |
5 | * (c) 2001 Straylight/Edgeware | |
6 | */ | |
7 | ||
e04c2d50 | 8 | /*----- Licensing notice --------------------------------------------------* |
410c8acf | 9 | * |
10 | * This file is part of Trivial IP Encryption (TrIPE). | |
11 | * | |
11ad66c2 MW |
12 | * TrIPE is free software: you can redistribute it and/or modify it under |
13 | * the terms of the GNU General Public License as published by the Free | |
14 | * Software Foundation; either version 3 of the License, or (at your | |
15 | * option) any later version. | |
e04c2d50 | 16 | * |
11ad66c2 MW |
17 | * TrIPE is distributed in the hope that it will be useful, but WITHOUT |
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
20 | * for more details. | |
e04c2d50 | 21 | * |
410c8acf | 22 | * You should have received a copy of the GNU General Public License |
11ad66c2 | 23 | * along with TrIPE. If not, see <https://www.gnu.org/licenses/>. |
410c8acf | 24 | */ |
25 | ||
410c8acf | 26 | /*----- Header files ------------------------------------------------------*/ |
27 | ||
28 | #include "tripe.h" | |
29 | ||
5d06f63e MW |
30 | /*----- Global state ------------------------------------------------------*/ |
31 | ||
063c9648 | 32 | udpsocket udpsock[NADDRFAM]; |
5d06f63e | 33 | |
410c8acf | 34 | /*----- Static variables --------------------------------------------------*/ |
35 | ||
c8e02c8a MW |
36 | static sym_table byname; |
37 | static addrmap byaddr; | |
6411163d | 38 | static unsigned nmobile; |
24898e7e MW |
39 | static struct tunnel_node { |
40 | struct tunnel_node *next; | |
41 | const tunnel_ops *tops; | |
42 | } *tunnels, **tunnels_tail = &tunnels; | |
693588c0 | 43 | static ratelim wgt_limit; |
24898e7e | 44 | const tunnel_ops *dflttun; |
42da2a58 | 45 | |
410c8acf | 46 | /*----- Main code ---------------------------------------------------------*/ |
47 | ||
0ba8de86 | 48 | /* --- @p_pingtype@ --- * |
49 | * | |
50 | * Arguments: @unsigned msg@ = message type | |
51 | * | |
52 | * Returns: String to describe the message. | |
53 | */ | |
54 | ||
55 | static const char *p_pingtype(unsigned msg) | |
56 | { | |
57 | switch (msg & MSG_TYPEMASK) { | |
58 | case MISC_PING: | |
59 | case MISC_PONG: | |
60 | return "transport-ping"; | |
61 | case MISC_EPING: | |
62 | case MISC_EPONG: | |
63 | return "encrypted-ping"; | |
64 | default: | |
65 | abort(); | |
66 | } | |
67 | } | |
68 | ||
69 | /* --- @p_ponged@ --- * | |
70 | * | |
71 | * Arguments: @peer *p@ = peer packet arrived from | |
72 | * @unsigned msg@ = message type | |
73 | * @buf *b@ = buffer containing payload | |
74 | * | |
75 | * Returns: --- | |
76 | * | |
77 | * Use: Processes a ping response. | |
78 | */ | |
79 | ||
80 | static void p_ponged(peer *p, unsigned msg, buf *b) | |
81 | { | |
82 | uint32 id; | |
83 | const octet *magic; | |
84 | ping *pg; | |
e04c2d50 | 85 | |
0ba8de86 | 86 | IF_TRACING(T_PEER, { |
87 | trace(T_PEER, "peer: received %s reply from %s", | |
88 | p_pingtype(msg), p->spec.name); | |
89 | trace_block(T_PACKET, "peer: ping contents", BBASE(b), BSZ(b)); | |
90 | }) | |
91 | ||
92 | if (buf_getu32(b, &id) || | |
93 | (magic = buf_get(b, sizeof(pg->magic))) == 0 || | |
94 | BLEFT(b)) { | |
f43df819 | 95 | a_warn("PEER", "?PEER", p, "malformed-%s", p_pingtype(msg), A_END); |
0ba8de86 | 96 | return; |
97 | } | |
98 | ||
99 | for (pg = p->pings; pg; pg = pg->next) { | |
100 | if (pg->id == id) | |
101 | goto found; | |
102 | } | |
f43df819 MW |
103 | a_warn("PEER", |
104 | "?PEER", p, | |
105 | "unexpected-%s", p_pingtype(msg), | |
106 | "0x%08lx", (unsigned long)id, | |
107 | A_END); | |
0ba8de86 | 108 | return; |
109 | ||
110 | found: | |
111 | if (memcmp(magic, pg->magic, sizeof(pg->magic)) != 0) { | |
f43df819 | 112 | a_warn("PEER", "?PEER", p, "corrupt-%s", p_pingtype(msg), A_END); |
0ba8de86 | 113 | return; |
114 | } | |
115 | p_pingdone(pg, PING_OK); | |
116 | } | |
117 | ||
6411163d MW |
118 | /* --- @p_rxupdstats@ --- * |
119 | * | |
120 | * Arguments: @peer *p@ = peer to update | |
121 | * @size_t n@ = size of incoming packet | |
122 | * | |
123 | * Returns: --- | |
124 | * | |
125 | * Use: Updates the peer's incoming packet statistics. | |
126 | */ | |
127 | ||
128 | static void p_rxupdstats(peer *p, size_t n) | |
129 | { | |
130 | p->st.t_last = time(0); | |
131 | p->st.n_in++; | |
132 | p->st.sz_in += n; | |
133 | } | |
134 | ||
a50f9a0e MW |
135 | /* --- @p_encrypt@ --- * |
136 | * | |
137 | * Arguments: @peer *p@ = peer to encrypt message to | |
138 | * @int ty@ message type to send | |
139 | * @buf *bin, *bout@ = input and output buffers | |
140 | * | |
141 | * Returns: --- | |
142 | * | |
143 | * Use: Convenience function for packet encryption. Forces | |
144 | * renegotiation when necessary. Check for the output buffer | |
145 | * being broken to find out whether the encryption was | |
146 | * successful. | |
147 | */ | |
148 | ||
149 | static int p_encrypt(peer *p, int ty, buf *bin, buf *bout) | |
150 | { | |
151 | int err = ksl_encrypt(&p->ks, ty, bin, bout); | |
152 | ||
153 | if (err == KSERR_REGEN) { | |
154 | kx_start(&p->kx, 1); | |
155 | err = 0; | |
156 | } | |
157 | if (!BOK(bout)) | |
158 | err = -1; | |
159 | return (err); | |
160 | } | |
161 | ||
23bbe601 MW |
162 | /* --- @p_updateaddr@ --- * |
163 | * | |
164 | * Arguments: @peer *p@ = pointer to peer block | |
165 | * @const addr *a@ = address to associate with this peer | |
166 | * | |
167 | * Returns: Zero if the address was changed; @+1@ if it was already | |
168 | * right. | |
169 | * | |
170 | * Use: Updates our idea of @p@'s address. | |
171 | */ | |
172 | ||
173 | int p_updateaddr(peer *p, const addr *a) | |
174 | { | |
175 | peer *q; | |
176 | peer_byaddr *pa, *qa; | |
5d06f63e | 177 | int ix; |
23bbe601 MW |
178 | unsigned f; |
179 | ||
180 | /* --- Figure out how to proceed --- * | |
181 | * | |
182 | * If this address already belongs to a different peer, then swap the | |
183 | * addresses over. This doesn't leave the displaced peer in an especially | |
184 | * good state, but it ought to get sorted out soon enough. | |
185 | */ | |
186 | ||
187 | pa = am_find(&byaddr, a, sizeof(peer_byaddr), &f); | |
188 | if (f && pa->p == p) | |
189 | return (+1); | |
190 | else if (!f) { | |
191 | T( trace(T_PEER, "peer: updating address for `%s'", p_name(p)); ) | |
192 | am_remove(&byaddr, p->byaddr); | |
193 | p->byaddr = pa; p->spec.sa = *a; pa->p = p; | |
5d06f63e | 194 | p->afix = afix(p->spec.sa.sa.sa_family); assert(p->afix >= 0); |
23bbe601 MW |
195 | a_notify("NEWADDR", "?PEER", p, "?ADDR", a, A_END); |
196 | return (0); | |
197 | } else { | |
198 | q = pa->p; qa = p->byaddr; | |
199 | T( trace(T_PEER, "peer: swapping addresses for `%s' and `%s'", | |
200 | p_name(p), p_name(q)); ) | |
201 | q->byaddr = qa; qa->p = q; q->spec.sa = p->spec.sa; | |
202 | p->byaddr = pa; pa->p = p; p->spec.sa = *a; | |
5d06f63e | 203 | ix = p->afix; p->afix = q->afix; q->afix = ix; |
23bbe601 MW |
204 | a_notify("NEWADDR", "?PEER", p, "?ADDR", a, A_END); |
205 | a_notify("NEWADDR", "?PEER", q, "?ADDR", &q->spec.sa, A_END); | |
206 | return (0); | |
207 | } | |
208 | } | |
209 | ||
a50f9a0e MW |
210 | /* --- @p_decrypt@ --- * |
211 | * | |
6411163d MW |
212 | * Arguments: @peer **pp@ = pointer to peer to decrypt message from |
213 | * @addr *a@ = address the packet arrived on | |
214 | * @size_t n@ = size of original incoming packet | |
a50f9a0e MW |
215 | * @int ty@ = message type to expect |
216 | * @buf *bin, *bout@ = input and output buffers | |
217 | * | |
218 | * Returns: Zero on success; nonzero on error. | |
219 | * | |
220 | * Use: Convenience function for packet decryption. Reports errors | |
221 | * and updates statistics appropriately. | |
6411163d MW |
222 | * |
223 | * If @*pp@ is null on entry and there are mobile peers then we | |
224 | * see if any of them can decrypt the packet. If so, we record | |
225 | * @*a@ as the peer's new address and send a notification. | |
a50f9a0e MW |
226 | */ |
227 | ||
6411163d MW |
228 | static int p_decrypt(peer **pp, addr *a, size_t n, |
229 | int ty, buf *bin, buf *bout) | |
a50f9a0e | 230 | { |
c71be758 | 231 | peer *p, *q; |
6411163d | 232 | int err = KSERR_DECRYPT; |
693588c0 | 233 | buf b; |
6411163d | 234 | |
c71be758 MW |
235 | /* --- If we have a match on the source address then try that first --- */ |
236 | ||
237 | q = *pp; | |
238 | if (q) { | |
6411163d | 239 | T( trace(T_PEER, "peer: decrypting packet from known peer `%s'", |
c71be758 MW |
240 | p_name(q)); ) |
241 | if ((err = ksl_decrypt(&q->ks, ty, bin, bout)) != KSERR_DECRYPT || | |
242 | !(q->spec.f & PSF_MOBILE) || nmobile == 1) { | |
243 | p = q; | |
244 | goto match; | |
245 | } | |
73174919 | 246 | T( trace(T_PEER, "peer: failed to decrypt: try other mobile peers..."); ) |
c71be758 | 247 | } else if (nmobile) |
8ed35e02 | 248 | T( trace(T_PEER, "peer: unknown source: trying mobile peers...") ); |
c71be758 | 249 | else { |
6411163d | 250 | p = 0; |
c71be758 MW |
251 | goto searched; |
252 | } | |
253 | ||
254 | /* --- See whether any mobile peer is interested --- */ | |
255 | ||
01c21903 MW |
256 | p = 0; |
257 | FOREACH_PEER(qq, { | |
258 | if (qq == q || !(qq->spec.f & PSF_MOBILE)) continue; | |
259 | if ((err = ksl_decrypt(&qq->ks, ty, bin, bout)) == KSERR_DECRYPT) { | |
c71be758 | 260 | T( trace(T_PEER, "peer: peer `%s' failed to decrypt", |
01c21903 | 261 | p_name(qq)); ) |
c71be758 MW |
262 | continue; |
263 | } else { | |
01c21903 | 264 | p = qq; |
c71be758 MW |
265 | IF_TRACING(T_PEER, { |
266 | if (!err) | |
01c21903 | 267 | trace(T_PEER, "peer: peer `%s' reports success", p_name(qq)); |
c71be758 MW |
268 | else { |
269 | trace(T_PEER, "peer: peer `%s' reports decryption error %d", | |
01c21903 | 270 | p_name(qq), err); |
6411163d | 271 | } |
c71be758 MW |
272 | }) |
273 | break; | |
6411163d | 274 | } |
c71be758 MW |
275 | }); |
276 | ||
277 | /* --- We've searched the mobile peers --- */ | |
278 | ||
279 | searched: | |
280 | if (!p) { | |
693588c0 | 281 | if (!q) { |
01c21903 | 282 | a_warn("PEER", "-", "unexpected-source", "?ADDR", a, A_END); |
693588c0 MW |
283 | if (!ratelim_withdraw(&wgt_limit, 1)) { |
284 | buf_init(&b, buf_t, sizeof(buf_t)); | |
285 | buf_putbyte(&b, MSG_MISC | MISC_WGT); | |
286 | if (n > WGTLEN) n = WGTLEN; | |
287 | buf_put(&b, buf_i, n); | |
288 | T( trace(T_PEER, "peer: sending who-goes-there message"); ) | |
289 | assert(BOK(&b)); p_txaddr(a, BBASE(&b), BLEN(&b)); | |
290 | } | |
291 | } else { | |
01c21903 MW |
292 | a_warn("PEER", "?PEER", p, "decrypt-failed", |
293 | "error-code", "%d", err, A_END); | |
294 | p_rxupdstats(q, n); | |
295 | } | |
c71be758 MW |
296 | return (-1); |
297 | } | |
298 | ||
23bbe601 | 299 | /* --- We found one that accepted, so update the peer's address --- */ |
c71be758 MW |
300 | |
301 | if (!err) { | |
01c21903 | 302 | *pp = p; |
23bbe601 | 303 | p_updateaddr(p, a); |
6411163d | 304 | } |
c71be758 MW |
305 | |
306 | match: | |
88622d1d | 307 | p_rxupdstats(p, n); |
6411163d MW |
308 | if (err) { |
309 | if (p) p->st.n_reject++; | |
310 | a_warn("PEER", "?PEER", p, "decrypt-failed", | |
311 | "error-code", "%d", err, A_END); | |
a50f9a0e MW |
312 | return (-1); |
313 | } | |
314 | if (!BOK(bout)) | |
315 | return (-1); | |
316 | return (0); | |
317 | } | |
318 | ||
410c8acf | 319 | /* --- @p_read@ --- * |
320 | * | |
321 | * Arguments: @int fd@ = file descriptor to read from | |
322 | * @unsigned mode@ = what happened | |
323 | * @void *v@ = an uninteresting pointer | |
324 | * | |
325 | * Returns: --- | |
326 | * | |
327 | * Use: Reads a packet from somewhere. | |
328 | */ | |
329 | ||
330 | static void p_read(int fd, unsigned mode, void *v) | |
331 | { | |
37941236 | 332 | peer *p = 0; |
410c8acf | 333 | addr a; |
cb160b86 | 334 | socklen_t sz; |
410c8acf | 335 | ssize_t n; |
336 | int ch; | |
337 | buf b, bb; | |
693588c0 MW |
338 | const octet *q; |
339 | unsigned i; | |
340 | time_t now; | |
89640f3f MW |
341 | #ifndef NTRACE |
342 | int ix = -1; | |
343 | char name[NI_MAXHOST], svc[NI_MAXSERV]; | |
344 | #endif | |
410c8acf | 345 | |
346 | /* --- Read the data --- */ | |
347 | ||
f4c9c08f | 348 | QUICKRAND; |
410c8acf | 349 | sz = sizeof(addr); |
350 | n = recvfrom(fd, buf_i, sizeof(buf_i), 0, &a.sa, &sz); | |
351 | if (n < 0) { | |
f43df819 | 352 | a_warn("PEER", "-", "socket-read-error", "?ERRNO", A_END); |
410c8acf | 353 | return; |
354 | } | |
89640f3f MW |
355 | IF_TRACING(T_PEER, { |
356 | ix = afix(a.sa.sa_family); | |
357 | getnameinfo(&a.sa, sz, name, sizeof(name), svc, sizeof(svc), | |
358 | NI_NUMERICHOST | NI_NUMERICSERV); | |
359 | }) | |
410c8acf | 360 | |
37941236 | 361 | /* --- If the packet is a greeting, don't check peers --- */ |
362 | ||
363 | if (n && buf_i[0] == (MSG_MISC | MISC_GREET)) { | |
364 | IF_TRACING(T_PEER, { | |
89640f3f MW |
365 | trace(T_PEER, "peer: greeting received from %s %s %s", |
366 | aftab[ix].name, name, svc); | |
37941236 | 367 | trace_block(T_PACKET, "peer: greeting contents", buf_i, n); |
368 | }) | |
369 | buf_init(&b, buf_i, n); | |
370 | buf_getbyte(&b); | |
3deadf73 | 371 | if (c_check(0, 0, &b) || BLEFT(&b)) { |
f43df819 | 372 | a_warn("PEER", "-", "invalid-greeting", A_END); |
37941236 | 373 | return; |
374 | } | |
f43df819 MW |
375 | a_notify("GREET", |
376 | "?B64", buf_i + 1, (size_t)(n - 1), | |
377 | "?ADDR", &a, | |
378 | A_END); | |
37941236 | 379 | return; |
380 | } | |
381 | ||
6411163d MW |
382 | /* --- Find the appropriate peer --- * |
383 | * | |
384 | * At this stage, don't worry too much about whether we actually found it. | |
385 | */ | |
410c8acf | 386 | |
6411163d | 387 | p = p_findbyaddr(&a); |
410c8acf | 388 | |
b9066fbb | 389 | IF_TRACING(T_PEER, { |
6411163d MW |
390 | if (p) { |
391 | trace(T_PEER, | |
89640f3f MW |
392 | "peer: packet received from `%s' from address %s %s %s", |
393 | p_name(p), aftab[ix].name, name, svc); | |
6411163d | 394 | } else { |
89640f3f MW |
395 | trace(T_PEER, "peer: packet received from unknown address %s %s %s", |
396 | aftab[ix].name, name, svc); | |
6411163d | 397 | } |
b9066fbb | 398 | trace_block(T_PACKET, "peer: packet contents", buf_i, n); |
399 | }) | |
410c8acf | 400 | |
401 | /* --- Pick the packet apart --- */ | |
402 | ||
403 | buf_init(&b, buf_i, n); | |
404 | if ((ch = buf_getbyte(&b)) < 0) { | |
f43df819 | 405 | a_warn("PEER", "?PEER", p, "bad-packet", "no-type", A_END); |
410c8acf | 406 | return; |
407 | } | |
5bb41301 | 408 | switch (ch & MSG_CATMASK) { |
410c8acf | 409 | case MSG_PACKET: |
5bb41301 | 410 | if (ch & MSG_TYPEMASK) { |
f43df819 MW |
411 | a_warn("PEER", |
412 | "?PEER", p, | |
413 | "bad-packet", | |
414 | "unknown-type", "0x%02x", ch, | |
415 | A_END); | |
6411163d | 416 | if (p) p->st.n_reject++; |
5bb41301 | 417 | return; |
418 | } | |
410c8acf | 419 | buf_init(&bb, buf_o, sizeof(buf_o)); |
6411163d | 420 | if (p_decrypt(&p, &a, n, MSG_PACKET, &b, &bb)) |
410c8acf | 421 | return; |
5bb41301 | 422 | if (BOK(&bb)) { |
423 | p->st.n_ipin++; | |
424 | p->st.sz_ipin += BSZ(&b); | |
42da2a58 | 425 | p->t->ops->inject(p->t, &bb); |
5bb41301 | 426 | } else { |
427 | p->st.n_reject++; | |
f43df819 | 428 | a_warn("PEER", "?PEER", p, "packet-build-failed", A_END); |
5bb41301 | 429 | } |
410c8acf | 430 | break; |
5bb41301 | 431 | case MSG_KEYEXCH: |
f6994bd0 MW |
432 | if (p) p_rxupdstats(p, n); |
433 | if (kx_message(p ? &p->kx : 0, &a, ch & MSG_TYPEMASK, &b)) goto unexp; | |
410c8acf | 434 | break; |
0ba8de86 | 435 | case MSG_MISC: |
436 | switch (ch & MSG_TYPEMASK) { | |
437 | case MISC_NOP: | |
6411163d | 438 | if (!p) goto unexp; |
88622d1d | 439 | p_rxupdstats(p, n); |
0ba8de86 | 440 | T( trace(T_PEER, "peer: received NOP packet"); ) |
441 | break; | |
442 | case MISC_PING: | |
6411163d | 443 | if (!p) goto unexp; |
88622d1d | 444 | p_rxupdstats(p, n); |
0ba8de86 | 445 | buf_put(p_txstart(p, MSG_MISC | MISC_PONG), BCUR(&b), BLEFT(&b)); |
aa1a0211 | 446 | p_txend(p, 0); |
e04c2d50 | 447 | break; |
0ba8de86 | 448 | case MISC_PONG: |
6411163d | 449 | if (!p) goto unexp; |
88622d1d | 450 | p_rxupdstats(p, n); |
0ba8de86 | 451 | p_ponged(p, MISC_PONG, &b); |
452 | break; | |
453 | case MISC_EPING: | |
454 | buf_init(&bb, buf_t, sizeof(buf_t)); | |
6411163d | 455 | if (p_decrypt(&p, &a, n, ch, &b, &bb)) |
0ba8de86 | 456 | return; |
0ba8de86 | 457 | if (BOK(&bb)) { |
458 | buf_flip(&bb); | |
a50f9a0e MW |
459 | p_encrypt(p, MSG_MISC | MISC_EPONG, &bb, |
460 | p_txstart(p, MSG_MISC | MISC_EPONG)); | |
693588c0 | 461 | p_txend(p, TXF_WGT); |
0ba8de86 | 462 | } |
463 | break; | |
464 | case MISC_EPONG: | |
465 | buf_init(&bb, buf_t, sizeof(buf_t)); | |
6411163d | 466 | if (p_decrypt(&p, &a, n, ch, &b, &bb)) |
0ba8de86 | 467 | return; |
0ba8de86 | 468 | if (BOK(&bb)) { |
469 | buf_flip(&bb); | |
470 | p_ponged(p, MISC_EPONG, &bb); | |
471 | } | |
472 | break; | |
067aa5f0 MW |
473 | case MISC_BYE: |
474 | buf_init(&bb, buf_t, sizeof(buf_t)); | |
475 | if (p_decrypt(&p, &a, n, ch, &b, &bb)) return; | |
476 | if (!(p->spec.f&PSF_EPHEM)) return; | |
477 | if (BOK(&bb)) { | |
478 | buf_flip(&bb); | |
479 | if (BSZ(&bb)) return; | |
480 | p_destroy(p, 0); | |
481 | } | |
482 | break; | |
693588c0 MW |
483 | case MISC_WGT: |
484 | if (!p) goto unexp; | |
485 | if (!(p->spec.f&PSF_EPHEM)) | |
486 | { a_warn("PEER", "?PEER", p, "unexpected-wgt", A_END); break; } | |
487 | n = BLEFT(&b); if (n > WGTLEN) n = WGTLEN; | |
488 | now = time(0); | |
489 | q = buf_get(&b, n); assert(q); | |
490 | for (i = 0; i < NWGT; i++) { | |
491 | if (p->wgt[i].when != (time_t)-1 && | |
492 | now - p->wgt[i].when <= T_WGT && | |
493 | p->wgt[i].sz == n && | |
494 | MEMCMP(p->wgt[i].msg, ==, q, n)) | |
495 | goto found_wgt; | |
496 | } | |
497 | a_warn("PEER", "?PEER", p, "unrecognized-wgt", A_END); | |
498 | break; | |
499 | found_wgt: | |
500 | if (p->spec.knock) { | |
501 | T( trace(T_PEER, "peer: who-goes-there from peer: knocking"); ) | |
502 | kx_start(&p->kx, 0); | |
503 | } else { | |
504 | T( trace(T_PEER, "peer: who-goes-there from peer: notifying"); ) | |
505 | a_notify("WGT", "?PEER", p, A_END); | |
506 | } | |
507 | break; | |
0ba8de86 | 508 | } |
509 | break; | |
410c8acf | 510 | default: |
6411163d | 511 | if (p) p->st.n_reject++; |
f43df819 MW |
512 | a_warn("PEER", |
513 | "?PEER", p, | |
514 | "bad-packet", | |
a68280fc | 515 | "unknown-category", "0x%02x", ch, |
f43df819 | 516 | A_END); |
410c8acf | 517 | break; |
6411163d MW |
518 | unexp: |
519 | a_warn("PEER", "-", "unexpected-source", "?ADDR", &a, A_END); | |
520 | break; | |
410c8acf | 521 | } |
522 | } | |
523 | ||
524 | /* --- @p_txstart@ --- * | |
525 | * | |
526 | * Arguments: @peer *p@ = pointer to peer block | |
527 | * @unsigned msg@ = message type code | |
528 | * | |
529 | * Returns: A pointer to a buffer to write to. | |
530 | * | |
531 | * Use: Starts sending to a peer. Only one send can happen at a | |
532 | * time. | |
533 | */ | |
534 | ||
535 | buf *p_txstart(peer *p, unsigned msg) | |
536 | { | |
537 | buf_init(&p->b, buf_o, sizeof(buf_o)); | |
538 | buf_putbyte(&p->b, msg); | |
539 | return (&p->b); | |
540 | } | |
541 | ||
8362ac1c MW |
542 | /* --- @p_txaddr@ --- * |
543 | * | |
544 | * Arguments: @const addr *a@ = recipient address | |
545 | * @const void *p@ = pointer to packet to send | |
546 | * @size_t sz@ = length of packet | |
547 | * | |
548 | * Returns: Zero if successful, nonzero on error. | |
549 | * | |
550 | * Use: Sends a packet to an address which (possibly) isn't a current | |
551 | * peer. | |
552 | */ | |
553 | ||
554 | int p_txaddr(const addr *a, const void *p, size_t sz) | |
555 | { | |
556 | socklen_t sasz = addrsz(a); | |
56c76774 | 557 | int i; |
8362ac1c | 558 | |
56c76774 MW |
559 | if ((i = afix(a->sa.sa_family)) < 0) { |
560 | a_warn("PEER", "?ADDR", a, "disabled-address-family", A_END); | |
561 | return (-1); | |
562 | } | |
8362ac1c | 563 | IF_TRACING(T_PEER, trace_block(T_PACKET, "peer: sending packet", p, sz); ) |
063c9648 | 564 | if (sendto(udpsock[i].sf.fd, p, sz, 0, &a->sa, sasz) < 0) { |
8362ac1c MW |
565 | a_warn("PEER", "?ADDR", a, "socket-write-error", "?ERRNO", A_END); |
566 | return (-1); | |
567 | } | |
568 | return (0); | |
569 | } | |
570 | ||
410c8acf | 571 | /* --- @p_txend@ --- * |
572 | * | |
573 | * Arguments: @peer *p@ = pointer to peer block | |
aa1a0211 | 574 | * @unsigned f@ = flags |
410c8acf | 575 | * |
576 | * Returns: --- | |
577 | * | |
578 | * Use: Sends a packet to the peer. | |
579 | */ | |
580 | ||
0ba8de86 | 581 | static void p_setkatimer(peer *); |
582 | ||
583 | static int p_dotxend(peer *p) | |
410c8acf | 584 | { |
cb2c2bfc MW |
585 | socklen_t sasz = addrsz(&p->spec.sa); |
586 | ||
410c8acf | 587 | if (!BOK(&p->b)) { |
f43df819 | 588 | a_warn("PEER", "?PEER", p, "packet-build-failed", A_END); |
0ba8de86 | 589 | return (0); |
410c8acf | 590 | } |
591 | IF_TRACING(T_PEER, trace_block(T_PACKET, "peer: sending packet", | |
592 | BBASE(&p->b), BLEN(&p->b)); ) | |
063c9648 | 593 | if (sendto(udpsock[p->afix].sf.fd, BBASE(&p->b), BLEN(&p->b), |
cb2c2bfc | 594 | 0, &p->spec.sa.sa, sasz) < 0) { |
f43df819 | 595 | a_warn("PEER", "?PEER", p, "socket-write-error", "?ERRNO", A_END); |
0ba8de86 | 596 | return (0); |
597 | } else { | |
5bb41301 | 598 | p->st.n_out++; |
599 | p->st.sz_out += BLEN(&p->b); | |
0ba8de86 | 600 | return (1); |
5bb41301 | 601 | } |
410c8acf | 602 | } |
603 | ||
aa1a0211 | 604 | void p_txend(peer *p, unsigned f) |
0ba8de86 | 605 | { |
693588c0 MW |
606 | size_t n; |
607 | ||
5164c6f7 | 608 | if (p_dotxend(p)) { |
693588c0 MW |
609 | if ((f&TXF_WGT) && (p->spec.f&PSF_EPHEM)) { |
610 | n = BLEN(&p->b); if (n > WGTLEN) n = WGTLEN; | |
611 | memcpy(p->wgt[p->wgtix].msg, BBASE(&p->b), n); | |
612 | p->wgt[p->wgtix].sz = n; | |
613 | p->wgt[p->wgtix].when = time(0); | |
614 | p->wgtix++; if (p->wgtix >= NWGT) p->wgtix = 0; | |
615 | } | |
5164c6f7 MW |
616 | if (p->spec.t_ka) { |
617 | sel_rmtimer(&p->tka); | |
618 | p_setkatimer(p); | |
619 | } | |
0ba8de86 | 620 | } |
621 | } | |
622 | ||
623 | /* --- @p_pingwrite@ --- * | |
624 | * | |
625 | * Arguments: @ping *p@ = ping structure | |
626 | * @buf *b@ = buffer to write in | |
627 | * | |
628 | * Returns: --- | |
629 | * | |
630 | * Use: Fills in a ping structure and writes the packet payload. | |
631 | */ | |
632 | ||
633 | static void p_pingwrite(ping *p, buf *b) | |
634 | { | |
635 | static uint32 seq = 0; | |
636 | ||
637 | p->id = U32(seq++); | |
638 | GR_FILL(&rand_global, p->magic, sizeof(p->magic)); | |
639 | buf_putu32(b, p->id); | |
640 | buf_put(b, p->magic, sizeof(p->magic)); | |
641 | } | |
642 | ||
643 | /* --- @p_pingdone@ --- * | |
644 | * | |
645 | * Arguments: @ping *p@ = ping structure | |
646 | * @int rc@ = return code to pass on | |
647 | * | |
648 | * Returns: --- | |
649 | * | |
650 | * Use: Disposes of a ping structure, maybe sending a notification. | |
651 | */ | |
652 | ||
653 | void p_pingdone(ping *p, int rc) | |
654 | { | |
0ba8de86 | 655 | if (p->prev) p->prev->next = p->next; |
656 | else p->p->pings = p->next; | |
657 | if (p->next) p->next->prev = p->prev; | |
658 | if (rc != PING_TIMEOUT) sel_rmtimer(&p->t); | |
060ca767 | 659 | T( trace(T_PEER, "peer: ping 0x%08lx done (rc = %d)", |
660 | (unsigned long)p->id, rc); ) | |
0ba8de86 | 661 | if (rc >= 0) p->func(rc, p->arg); |
662 | } | |
663 | ||
664 | /* --- @p_pingtimeout@ --- * | |
665 | * | |
666 | * Arguments: @struct timeval *now@ = the time now | |
667 | * @void *pv@ = pointer to ping block | |
668 | * | |
669 | * Returns: --- | |
670 | * | |
671 | * Use: Called when a ping times out. | |
672 | */ | |
673 | ||
674 | static void p_pingtimeout(struct timeval *now, void *pv) | |
675 | { | |
676 | ping *p = pv; | |
677 | ||
678 | T( trace(T_PEER, "peer: ping 0x%08lx timed out", (unsigned long)p->id); ) | |
679 | p_pingdone(p, PING_TIMEOUT); | |
680 | } | |
681 | ||
682 | /* --- @p_pingsend@ --- * | |
683 | * | |
684 | * Arguments: @peer *p@ = destination peer | |
685 | * @ping *pg@ = structure to fill in | |
686 | * @unsigned type@ = message type | |
687 | * @unsigned long timeout@ = how long to wait before giving up | |
688 | * @void (*func)(int, void *)@ = callback function | |
689 | * @void *arg@ = argument for callback | |
690 | * | |
691 | * Returns: Zero if successful, nonzero if it failed. | |
692 | * | |
693 | * Use: Sends a ping to a peer. Call @func@ with a nonzero argument | |
694 | * if we get an answer within the timeout, or zero if no answer. | |
695 | */ | |
696 | ||
697 | int p_pingsend(peer *p, ping *pg, unsigned type, | |
698 | unsigned long timeout, | |
699 | void (*func)(int, void *), void *arg) | |
700 | { | |
701 | buf *b, bb; | |
702 | struct timeval tv; | |
703 | ||
0ba8de86 | 704 | switch (type) { |
705 | case MISC_PING: | |
706 | pg->msg = MISC_PONG; | |
707 | b = p_txstart(p, MSG_MISC | MISC_PING); | |
708 | p_pingwrite(pg, b); | |
aa1a0211 | 709 | p_txend(p, 0); |
0ba8de86 | 710 | break; |
711 | case MISC_EPING: | |
712 | pg->msg = MISC_EPONG; | |
713 | b = p_txstart(p, MSG_MISC | MISC_EPING); | |
714 | buf_init(&bb, buf_t, sizeof(buf_t)); | |
715 | p_pingwrite(pg, &bb); | |
716 | buf_flip(&bb); | |
a50f9a0e | 717 | p_encrypt(p, MSG_MISC | MISC_EPING, &bb, b); |
0ba8de86 | 718 | if (!BOK(b)) |
719 | return (-1); | |
693588c0 | 720 | p_txend(p, TXF_WGT); |
0ba8de86 | 721 | break; |
722 | default: | |
723 | abort(); | |
724 | break; | |
725 | } | |
726 | ||
727 | pg->next = p->pings; | |
728 | pg->prev = 0; | |
729 | pg->p = p; | |
730 | pg->func = func; | |
731 | pg->arg = arg; | |
060ca767 | 732 | if (p->pings) p->pings->prev = pg; |
0ba8de86 | 733 | p->pings = pg; |
734 | gettimeofday(&tv, 0); | |
735 | tv.tv_sec += timeout; | |
736 | sel_addtimer(&sel, &pg->t, &tv, p_pingtimeout, pg); | |
737 | T( trace(T_PEER, "peer: send %s 0x%08lx to %s", | |
738 | p_pingtype(type), (unsigned long)pg->id, p->spec.name); ) | |
739 | return (0); | |
740 | } | |
741 | ||
37941236 | 742 | /* --- @p_greet@ --- * |
743 | * | |
744 | * Arguments: @peer *p@ = peer to send to | |
745 | * @const void *c@ = pointer to challenge | |
746 | * @size_t sz@ = size of challenge | |
747 | * | |
748 | * Returns: --- | |
749 | * | |
750 | * Use: Sends a greeting packet. | |
751 | */ | |
752 | ||
753 | void p_greet(peer *p, const void *c, size_t sz) | |
754 | { | |
755 | buf *b = p_txstart(p, MSG_MISC | MISC_GREET); | |
756 | buf_put(b, c, sz); | |
aa1a0211 | 757 | p_txend(p, 0); |
37941236 | 758 | } |
759 | ||
410c8acf | 760 | /* --- @p_tun@ --- * |
761 | * | |
762 | * Arguments: @peer *p@ = pointer to peer block | |
763 | * @buf *b@ = buffer containing incoming packet | |
764 | * | |
765 | * Returns: --- | |
766 | * | |
767 | * Use: Handles a packet which needs to be sent to a peer. | |
768 | */ | |
769 | ||
770 | void p_tun(peer *p, buf *b) | |
771 | { | |
772 | buf *bb = p_txstart(p, MSG_PACKET); | |
7b052fe6 | 773 | |
f4c9c08f | 774 | QUICKRAND; |
a50f9a0e | 775 | p_encrypt(p, MSG_PACKET, b, bb); |
5bb41301 | 776 | if (BOK(bb) && BLEN(bb)) { |
777 | p->st.n_ipout++; | |
778 | p->st.sz_ipout += BLEN(bb); | |
693588c0 | 779 | p_txend(p, TXF_WGT); |
5bb41301 | 780 | } |
410c8acf | 781 | } |
782 | ||
de014da6 | 783 | /* --- @p_keyreload@ --- * |
784 | * | |
785 | * Arguments: --- | |
786 | * | |
787 | * Returns: --- | |
788 | * | |
789 | * Use: Forces a check of the daemon's keyring files. | |
790 | */ | |
791 | ||
792 | void p_keyreload(void) | |
793 | { | |
c8e02c8a MW |
794 | if (km_reload()) |
795 | FOREACH_PEER(p, { kx_newkeys(&p->kx); }); | |
de014da6 | 796 | } |
797 | ||
410c8acf | 798 | /* --- @p_interval@ --- * |
799 | * | |
800 | * Arguments: --- | |
801 | * | |
802 | * Returns: --- | |
803 | * | |
804 | * Use: Called periodically to do tidying. | |
805 | */ | |
806 | ||
807 | void p_interval(void) | |
808 | { | |
de014da6 | 809 | p_keyreload(); |
c8e02c8a | 810 | FOREACH_PEER(p, { ksl_prune(&p->ks); }); |
410c8acf | 811 | } |
812 | ||
5bb41301 | 813 | /* --- @p_stats@ --- * |
814 | * | |
815 | * Arguments: @peer *p@ = pointer to a peer block | |
816 | * | |
817 | * Returns: A pointer to the peer's statistics. | |
818 | */ | |
819 | ||
820 | stats *p_stats(peer *p) { return (&p->st); } | |
821 | ||
410c8acf | 822 | /* --- @p_ifname@ --- * |
823 | * | |
824 | * Arguments: @peer *p@ = pointer to a peer block | |
825 | * | |
826 | * Returns: A pointer to the peer's interface name. | |
827 | */ | |
828 | ||
64cf2223 MW |
829 | const char *p_ifname(peer *p) { return (p->ifname); } |
830 | ||
831 | /* --- @p_setifname@ --- * | |
832 | * | |
833 | * Arguments: @peer *p@ = pointer to a peer block | |
834 | * @const char *name@ = pointer to the new name | |
835 | * | |
836 | * Returns: --- | |
837 | * | |
838 | * Use: Changes the name held for a peer's interface. | |
839 | */ | |
840 | ||
841 | void p_setifname(peer *p, const char *name) | |
72917fe7 MW |
842 | { |
843 | xfree(p->ifname); | |
844 | p->ifname = xstrdup(name); | |
845 | if (p->spec.tops->setifname) | |
846 | p->spec.tops->setifname(p->t, name); | |
847 | } | |
410c8acf | 848 | |
849 | /* --- @p_addr@ --- * | |
850 | * | |
851 | * Arguments: @peer *p@ = pointer to a peer block | |
852 | * | |
853 | * Returns: A pointer to the peer's address. | |
854 | */ | |
855 | ||
0ba8de86 | 856 | const addr *p_addr(peer *p) { return (&p->spec.sa); } |
410c8acf | 857 | |
7737eb87 | 858 | /* --- @p_bind@ --- * |
410c8acf | 859 | * |
89640f3f | 860 | * Arguments: @struct addrinfo *ailist@ = addresses to bind to |
410c8acf | 861 | * |
9d966eb7 | 862 | * Returns: Zero on success, @-1@ on failure. |
410c8acf | 863 | * |
9d966eb7 | 864 | * Use: Binds to the main UDP sockets. |
410c8acf | 865 | */ |
866 | ||
9d966eb7 | 867 | int p_bind(struct addrinfo *ailist) |
410c8acf | 868 | { |
9d966eb7 | 869 | int fd = -1; |
df9dfccf | 870 | int len = PKBUFSZ; |
47828bd9 | 871 | int yes = 1; |
89640f3f MW |
872 | int i; |
873 | struct addrinfo *ai; | |
874 | unsigned port, lastport = 0; | |
875 | addr a; | |
876 | socklen_t sz; | |
0a9920e2 | 877 | |
063c9648 | 878 | for (i = 0; i < NADDRFAM; i++) udpsock[i].sf.fd = -1; |
89640f3f MW |
879 | |
880 | for (ai = ailist; ai; ai = ai->ai_next) { | |
881 | if ((i = afix(ai->ai_family)) < 0) continue; | |
063c9648 | 882 | if (udpsock[i].sf.fd != -1) continue; |
89640f3f MW |
883 | |
884 | /* --- Note on socket buffer sizes --- * | |
885 | * | |
886 | * For some bizarre reason, Linux 2.2 (at least) doubles the socket | |
887 | * buffer sizes I pass to @setsockopt@. I'm not putting special-case | |
888 | * code here for Linux: BSD (at least TCPv2) does what I tell it rather | |
889 | * than second-guessing me. | |
890 | */ | |
891 | ||
5ae728a6 MW |
892 | if ((fd = socket(ai->ai_family, SOCK_DGRAM, 0)) < 0) { |
893 | a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, | |
894 | "create-failed", "?ERRNO", A_END); | |
9d966eb7 | 895 | goto fail; |
5ae728a6 | 896 | } |
47828bd9 MW |
897 | if (i == AFIX_INET6 && |
898 | setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes))) { | |
5ae728a6 MW |
899 | a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, |
900 | "set-v6only-failed", "?ERRNO", A_END); | |
9d966eb7 | 901 | goto fail; |
47828bd9 | 902 | } |
89640f3f MW |
903 | assert(ai->ai_addrlen <= sizeof(a)); |
904 | memcpy(&a, ai->ai_addr, ai->ai_addrlen); | |
905 | if ((port = getport(&a)) == 0 && lastport) setport(&a, lastport); | |
5ae728a6 MW |
906 | if (bind(fd, &a.sa, addrsz(&a))) { |
907 | a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, | |
908 | "bind-failed", "?ERRNO", A_END); | |
9d966eb7 | 909 | goto fail; |
5ae728a6 | 910 | } |
89640f3f MW |
911 | if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) || |
912 | setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &len, sizeof(len))) { | |
5ae728a6 MW |
913 | a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, |
914 | "set-buffers-failed", "?ERRNO", A_END); | |
9d966eb7 | 915 | goto fail; |
89640f3f MW |
916 | } |
917 | fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); | |
8d4c29d2 MW |
918 | if (port) |
919 | udpsock[i].port = port; | |
920 | else { | |
89640f3f MW |
921 | sz = sizeof(a); |
922 | if (getsockname(fd, &a.sa, &sz)) { | |
5ae728a6 MW |
923 | a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, |
924 | "read-local-address-failed", "?ERRNO", A_END); | |
9d966eb7 | 925 | goto fail; |
89640f3f | 926 | } |
8d4c29d2 | 927 | udpsock[i].port = lastport = getport(&a); |
89640f3f | 928 | } |
c6fb2bee MW |
929 | T( trace(T_PEER, "peer: created %s socket", aftab[i].name); ) |
930 | sel_initfile(&sel, &udpsock[i].sf, fd, SEL_READ, p_read, 0); | |
931 | sel_addfile(&udpsock[i].sf); | |
9d966eb7 | 932 | fd = -1; |
0a9920e2 | 933 | } |
c8e02c8a | 934 | |
9d966eb7 MW |
935 | return (0); |
936 | ||
937 | fail: | |
938 | if (fd != -1) close(fd); | |
939 | p_unbind(); | |
940 | return (-1); | |
7737eb87 MW |
941 | } |
942 | ||
bf302d90 MW |
943 | /* --- @p_unbind@ --- * |
944 | * | |
945 | * Arguments: --- | |
946 | * | |
947 | * Returns: --- | |
948 | * | |
949 | * Use: Unbinds the UDP sockets. There must not be any active peers, | |
950 | * and none can be created until the sockets are rebound. | |
951 | */ | |
952 | ||
953 | void p_unbind(void) | |
954 | { | |
955 | int i; | |
956 | ||
957 | #ifndef NDEBUG | |
958 | { peer_iter it; p_mkiter(&it); assert(!p_next(&it)); } | |
959 | #endif | |
960 | ||
961 | for (i = 0; i < NADDRFAM; i++) { | |
962 | if (udpsock[i].sf.fd == -1) continue; | |
963 | sel_rmfile(&udpsock[i].sf); | |
964 | close(udpsock[i].sf.fd); | |
965 | udpsock[i].sf.fd = -1; | |
966 | } | |
967 | } | |
968 | ||
7737eb87 MW |
969 | /* --- @p_init@ --- * |
970 | * | |
971 | * Arguments: --- | |
972 | * | |
973 | * Returns: --- | |
974 | * | |
975 | * Use: Initializes the peer system. | |
976 | */ | |
977 | ||
978 | void p_init(void) | |
979 | { | |
c8e02c8a MW |
980 | sym_create(&byname); |
981 | am_create(&byaddr); | |
693588c0 | 982 | ratelim_init(&wgt_limit, 5, 100); |
410c8acf | 983 | } |
984 | ||
24898e7e MW |
985 | /* --- @p_addtun@ --- * |
986 | * | |
987 | * Arguments: @const tunnel_ops *tops@ = tunnel ops to add | |
988 | * | |
9d966eb7 | 989 | * Returns: Zero on success, @-1@ on failure. |
24898e7e | 990 | * |
9d966eb7 MW |
991 | * Use: Adds a tunnel class to the list of known classes, if it |
992 | * initializes properly. If there is no current default tunnel, | |
993 | * then this one is made the default. | |
24898e7e MW |
994 | * |
995 | * Does nothing if the tunnel class is already known. So adding | |
996 | * a bunch of tunnels takes quadratic time, but there will be | |
997 | * too few to care about. | |
998 | */ | |
999 | ||
9d966eb7 | 1000 | int p_addtun(const tunnel_ops *tops) |
24898e7e MW |
1001 | { |
1002 | struct tunnel_node *tn; | |
1003 | ||
1004 | for (tn = tunnels; tn; tn = tn->next) | |
9d966eb7 MW |
1005 | if (tn->tops == tops) return (0); |
1006 | if (tops->init()) return (-1); | |
24898e7e MW |
1007 | tn = CREATE(struct tunnel_node); |
1008 | tn->next = 0; tn->tops = tops; | |
1009 | *tunnels_tail = tn; tunnels_tail = &tn->next; | |
1010 | if (!dflttun) dflttun = tops; | |
9d966eb7 | 1011 | return (0); |
24898e7e MW |
1012 | } |
1013 | ||
1014 | /* --- @p_setdflttun@ --- * | |
1015 | * | |
1016 | * Arguments: @const tunnel_ops *tops@ = tunnel ops to set | |
1017 | * | |
1018 | * Returns: --- | |
1019 | * | |
1020 | * Use: Sets the default tunnel. It must already be registered. The | |
1021 | * old default is forgotten. | |
1022 | */ | |
1023 | ||
1024 | void p_setdflttun(const tunnel_ops *tops) | |
1025 | { dflttun = tops; } | |
1026 | ||
1027 | /* --- @p_dflttun@ --- * | |
1028 | * | |
1029 | * Arguments: --- | |
1030 | * | |
1031 | * Returns: A pointer to the current default tunnel operations, or null | |
1032 | * if no tunnels are defined. | |
1033 | */ | |
1034 | ||
1035 | const tunnel_ops *p_dflttun(void) { return (dflttun); } | |
1036 | ||
1037 | /* --- @p_findtun@ --- * | |
1038 | * | |
1039 | * Arguments: @const char *name@ = tunnel name | |
1040 | * | |
1041 | * Returns: Pointer to the tunnel operations, or null. | |
1042 | * | |
1043 | * Use: Finds the operations for a named tunnel class. | |
1044 | */ | |
1045 | ||
1046 | const tunnel_ops *p_findtun(const char *name) | |
1047 | { | |
1048 | const struct tunnel_node *tn; | |
1049 | ||
1050 | for (tn = tunnels; tn; tn = tn->next) | |
1051 | if (mystrieq(tn->tops->name, name) == 0) return (tn->tops); | |
1052 | return (0); | |
1053 | } | |
1054 | ||
1055 | /* --- @p_mktuniter@ --- * | |
1056 | * | |
1057 | * Arguments: @tuniter *i@ = pointer to iterator to initialize | |
1058 | * | |
1059 | * Returns: --- | |
1060 | * | |
1061 | * Use: Initializes a tunnel iterator. | |
1062 | */ | |
1063 | ||
1064 | void p_mktuniter(tun_iter *i) { i->next = tunnels; } | |
1065 | ||
1066 | /* --- @p_nexttun@ --- * | |
1067 | * | |
1068 | * Arguments: @tuniter *i@ = pointer to iterator | |
1069 | * | |
1070 | * Returns: Pointer to the next tunnel's operations, or null. | |
1071 | */ | |
1072 | ||
1073 | const tunnel_ops *p_nexttun(tun_iter *i) | |
1074 | { | |
1075 | const struct tunnel_node *tn = i->next; | |
1076 | ||
1077 | if (!tn) return (0); | |
1078 | else { i->next = tn->next; return (tn->tops); } | |
1079 | } | |
1080 | ||
0ba8de86 | 1081 | /* --- @p_keepalive@ --- * |
1082 | * | |
1083 | * Arguments: @struct timeval *now@ = the current time | |
1084 | * @void *pv@ = peer to wake up | |
1085 | * | |
1086 | * Returns: --- | |
1087 | * | |
1088 | * Use: Sends a keepalive ping message to its peer. | |
1089 | */ | |
1090 | ||
1091 | static void p_keepalive(struct timeval *now, void *pv) | |
1092 | { | |
1093 | peer *p = pv; | |
fe2a5dcf | 1094 | |
0ba8de86 | 1095 | p_txstart(p, MSG_MISC | MISC_NOP); p_dotxend(p); |
1096 | T( trace(T_PEER, "peer: sent keepalive to %s", p->spec.name); ) | |
1097 | p_setkatimer(p); | |
1098 | } | |
1099 | ||
1100 | /* --- @p_setkatimer@ --- * | |
1101 | * | |
1102 | * Arguments: @peer *p@ = peer to set | |
1103 | * | |
1104 | * Returns: --- | |
1105 | * | |
1106 | * Use: Resets the keepalive timer thing. | |
1107 | */ | |
1108 | ||
1109 | static void p_setkatimer(peer *p) | |
1110 | { | |
1111 | struct timeval tv; | |
1112 | ||
1113 | if (!p->spec.t_ka) | |
1114 | return; | |
1115 | gettimeofday(&tv, 0); | |
1116 | tv.tv_sec += p->spec.t_ka; | |
1117 | sel_addtimer(&sel, &p->tka, &tv, p_keepalive, p); | |
1118 | } | |
1119 | ||
410c8acf | 1120 | /* --- @p_create@ --- * |
1121 | * | |
0ba8de86 | 1122 | * Arguments: @peerspec *spec@ = information about this peer |
410c8acf | 1123 | * |
1124 | * Returns: Pointer to the peer block, or null if it failed. | |
1125 | * | |
1126 | * Use: Creates a new named peer block. No peer is actually attached | |
1127 | * by this point. | |
1128 | */ | |
1129 | ||
0ba8de86 | 1130 | peer *p_create(peerspec *spec) |
410c8acf | 1131 | { |
1132 | peer *p = CREATE(peer); | |
eb5f3fea MW |
1133 | const tunnel_ops *tops = spec->tops; |
1134 | int fd; | |
693588c0 | 1135 | unsigned f, i; |
c8e02c8a MW |
1136 | |
1137 | p->byname = sym_find(&byname, spec->name, -1, sizeof(peer_byname), &f); | |
1138 | if (f) goto tidy_0; | |
1139 | p->byaddr = am_find(&byaddr, &spec->sa, sizeof(peer_byaddr), &f); | |
1140 | if (f) goto tidy_1; | |
1141 | p->byname->p = p->byaddr->p = p; | |
42da2a58 | 1142 | |
0ba8de86 | 1143 | T( trace(T_PEER, "peer: creating new peer `%s'", spec->name); ) |
1144 | p->spec = *spec; | |
c8e02c8a | 1145 | p->spec.name = (/*unconst*/ char *)SYM_NAME(p->byname); |
fe2a5dcf MW |
1146 | if (spec->tag) p->spec.tag = xstrdup(spec->tag); |
1147 | if (spec->privtag) p->spec.privtag = xstrdup(spec->privtag); | |
8362ac1c | 1148 | if (spec->knock) p->spec.knock = xstrdup(spec->knock); |
410c8acf | 1149 | p->ks = 0; |
629842d8 | 1150 | p->pings = 0; |
64cf2223 | 1151 | p->ifname = 0; |
5d06f63e | 1152 | p->afix = afix(p->spec.sa.sa.sa_family); assert(p->afix >= 0); |
5bb41301 | 1153 | memset(&p->st, 0, sizeof(stats)); |
1154 | p->st.t_start = time(0); | |
388e0319 | 1155 | if (!(tops->flags & TUNF_PRIVOPEN)) |
eb5f3fea | 1156 | fd = -1; |
388e0319 | 1157 | else if ((fd = ps_tunfd(tops, &p->ifname)) < 0) |
c8e02c8a | 1158 | goto tidy_2; |
eb5f3fea MW |
1159 | if ((p->t = tops->create(p, fd, &p->ifname)) == 0) |
1160 | goto tidy_3; | |
1161 | T( trace(T_TUNNEL, "peer: attached interface %s to peer `%s'", | |
1162 | p->ifname, p_name(p)); ) | |
0ba8de86 | 1163 | p_setkatimer(p); |
024d189a | 1164 | iv_addreason(); |
0510f262 | 1165 | if (kx_setup(&p->kx, p, &p->ks, p->spec.f & PSF_KXMASK)) |
eb5f3fea | 1166 | goto tidy_4; |
f43df819 | 1167 | a_notify("ADD", |
6047fbac MW |
1168 | "?PEER", p, |
1169 | "%s", p->ifname, | |
1170 | "?ADDR", &p->spec.sa, | |
1171 | A_END); | |
8743c776 | 1172 | if (!(p->spec.f & KXF_CORK)) { |
010e6f63 | 1173 | a_notify("KXSTART", "?PEER", p, A_END); |
f43df819 | 1174 | /* Couldn't tell anyone before */ |
010e6f63 | 1175 | } |
6411163d | 1176 | if (p->spec.f & PSF_MOBILE) nmobile++; |
693588c0 MW |
1177 | for (i = 0; i < NWGT; i++) { |
1178 | p->wgt[i].sz = 0; | |
1179 | p->wgt[i].when = (time_t)-1; | |
1180 | } | |
1181 | p->wgtix = 0; | |
410c8acf | 1182 | return (p); |
1183 | ||
eb5f3fea | 1184 | tidy_4: |
fe2a5dcf | 1185 | if (spec->t_ka) sel_rmtimer(&p->tka); |
72917fe7 | 1186 | xfree(p->ifname); |
0ba8de86 | 1187 | p->t->ops->destroy(p->t); |
024d189a | 1188 | iv_rmreason(); |
eb5f3fea MW |
1189 | tidy_3: |
1190 | if (fd >= 0) close(fd); | |
c8e02c8a MW |
1191 | tidy_2: |
1192 | am_remove(&byaddr, p->byaddr); | |
48b84569 | 1193 | if (p->spec.tag) xfree(p->spec.tag); |
fe2a5dcf | 1194 | if (p->spec.privtag) xfree(p->spec.privtag); |
c8e02c8a MW |
1195 | tidy_1: |
1196 | sym_remove(&byname, p->byname); | |
410c8acf | 1197 | tidy_0: |
410c8acf | 1198 | DESTROY(p); |
1199 | return (0); | |
1200 | } | |
1201 | ||
1202 | /* --- @p_name@ --- * | |
1203 | * | |
1204 | * Arguments: @peer *p@ = pointer to a peer block | |
1205 | * | |
1206 | * Returns: A pointer to the peer's name. | |
1207 | */ | |
1208 | ||
6411163d MW |
1209 | const char *p_name(peer *p) |
1210 | { if (p) return (p->spec.name); else return ("-"); } | |
410c8acf | 1211 | |
48b84569 MW |
1212 | /* --- @p_tag@ --- * |
1213 | * | |
1214 | * Arguments: @peer *p@ = pointer to a peer block | |
1215 | * | |
1216 | * Returns: A pointer to the peer's public key tag. | |
1217 | */ | |
1218 | ||
1219 | const char *p_tag(peer *p) | |
1220 | { return (p->spec.tag ? p->spec.tag : p->spec.name); } | |
1221 | ||
fe2a5dcf MW |
1222 | /* --- @p_privtag@ --- * |
1223 | * | |
1224 | * Arguments: @peer *p@ = pointer to a peer block | |
1225 | * | |
1226 | * Returns: A pointer to the peer's private key tag. | |
1227 | */ | |
1228 | ||
1229 | const char *p_privtag(peer *p) | |
1230 | { return (p->spec.privtag ? p->spec.privtag : tag_priv); } | |
1231 | ||
060ca767 | 1232 | /* --- @p_spec@ --- * |
1233 | * | |
1234 | * Arguments: @peer *p@ = pointer to a peer block | |
1235 | * | |
1236 | * Returns: Pointer to the peer's specification | |
1237 | */ | |
1238 | ||
1239 | const peerspec *p_spec(peer *p) { return (&p->spec); } | |
1240 | ||
c8e02c8a MW |
1241 | /* --- @p_findbyaddr@ --- * |
1242 | * | |
1243 | * Arguments: @const addr *a@ = address to look up | |
1244 | * | |
1245 | * Returns: Pointer to the peer block, or null if not found. | |
1246 | * | |
1247 | * Use: Finds a peer by address. | |
1248 | */ | |
1249 | ||
1250 | peer *p_findbyaddr(const addr *a) | |
1251 | { | |
1252 | peer_byaddr *pa; | |
1253 | ||
6411163d MW |
1254 | if ((pa = am_find(&byaddr, a, 0, 0)) != 0) { |
1255 | assert(pa->p); | |
c8e02c8a | 1256 | return (pa->p); |
6411163d | 1257 | } |
c8e02c8a MW |
1258 | return (0); |
1259 | } | |
1260 | ||
410c8acf | 1261 | /* --- @p_find@ --- * |
1262 | * | |
1263 | * Arguments: @const char *name@ = name to look up | |
1264 | * | |
1265 | * Returns: Pointer to the peer block, or null if not found. | |
1266 | * | |
1267 | * Use: Finds a peer by name. | |
1268 | */ | |
1269 | ||
1270 | peer *p_find(const char *name) | |
1271 | { | |
c8e02c8a MW |
1272 | peer_byname *pn; |
1273 | ||
1274 | if ((pn = sym_find(&byname, name, -1, 0, 0)) != 0) | |
1275 | return (pn->p); | |
e04c2d50 | 1276 | return (0); |
410c8acf | 1277 | } |
1278 | ||
1279 | /* --- @p_destroy@ --- * | |
1280 | * | |
1281 | * Arguments: @peer *p@ = pointer to a peer | |
067aa5f0 | 1282 | * @int bye@ = say goodbye to the peer? |
410c8acf | 1283 | * |
1284 | * Returns: --- | |
1285 | * | |
1286 | * Use: Destroys a peer. | |
1287 | */ | |
1288 | ||
067aa5f0 | 1289 | void p_destroy(peer *p, int bye) |
410c8acf | 1290 | { |
0ba8de86 | 1291 | ping *pg, *ppg; |
067aa5f0 | 1292 | buf *b, bb; |
0ba8de86 | 1293 | |
1294 | T( trace(T_PEER, "peer: destroying peer `%s'", p->spec.name); ) | |
067aa5f0 | 1295 | |
136f3f44 | 1296 | if (bye) { |
067aa5f0 MW |
1297 | b = p_txstart(p, MSG_MISC | MISC_BYE); |
1298 | buf_init(&bb, buf_t, sizeof(buf_t)); | |
1299 | assert(BOK(&bb)); buf_flip(&bb); | |
1300 | p_encrypt(p, MSG_MISC | MISC_BYE, &bb, b); | |
aa1a0211 | 1301 | p_txend(p, 0); |
067aa5f0 MW |
1302 | } |
1303 | ||
f43df819 | 1304 | a_notify("KILL", "%s", p->spec.name, A_END); |
5bb41301 | 1305 | ksl_free(&p->ks); |
410c8acf | 1306 | kx_free(&p->kx); |
fe2a5dcf MW |
1307 | if (p->spec.f & PSF_MOBILE) nmobile--; |
1308 | if (p->ifname) xfree(p->ifname); | |
1309 | if (p->spec.tag) xfree(p->spec.tag); | |
1310 | if (p->spec.privtag) xfree(p->spec.privtag); | |
8362ac1c | 1311 | if (p->spec.knock) xfree(p->spec.knock); |
42da2a58 | 1312 | p->t->ops->destroy(p->t); |
fe2a5dcf | 1313 | if (p->spec.t_ka) sel_rmtimer(&p->tka); |
0ba8de86 | 1314 | for (pg = p->pings; pg; pg = ppg) { |
1315 | ppg = pg->next; | |
1316 | p_pingdone(pg, PING_PEERDIED); | |
1317 | } | |
c8e02c8a MW |
1318 | sym_remove(&byname, p->byname); |
1319 | am_remove(&byaddr, p->byaddr); | |
024d189a | 1320 | iv_rmreason(); |
410c8acf | 1321 | DESTROY(p); |
1322 | } | |
1323 | ||
78e45b53 MW |
1324 | /* --- @p_destroyall@ --- * |
1325 | * | |
1326 | * Arguments: --- | |
1327 | * | |
1328 | * Returns: --- | |
1329 | * | |
1330 | * Use: Destroys all of the peers, saying goodbye. | |
1331 | */ | |
1332 | ||
1333 | void p_destroyall(void) { FOREACH_PEER(p, { p_destroy(p, 1); }); } | |
1334 | ||
c8e02c8a MW |
1335 | /* --- @p_mkiter@ --- * |
1336 | * | |
1337 | * Arguments: @peer_iter *i@ = pointer to an iterator | |
1338 | * | |
1339 | * Returns: --- | |
1340 | * | |
1341 | * Use: Initializes the iterator. | |
1342 | */ | |
1343 | ||
1344 | void p_mkiter(peer_iter *i) { sym_mkiter(&i->i, &byname); } | |
1345 | ||
1346 | /* --- @p_next@ --- * | |
1347 | * | |
1348 | * Arguments: @peer_iter *i@ = pointer to an iterator | |
410c8acf | 1349 | * |
c8e02c8a | 1350 | * Returns: Next peer, or null if at the end. |
410c8acf | 1351 | * |
c8e02c8a | 1352 | * Use: Returns the next peer. |
410c8acf | 1353 | */ |
1354 | ||
c8e02c8a MW |
1355 | peer *p_next(peer_iter *i) |
1356 | { | |
1357 | peer_byname *pn; | |
1358 | ||
1359 | if ((pn = sym_next(&i->i)) == 0) | |
1360 | return (0); | |
1361 | return (pn->p); | |
1362 | } | |
410c8acf | 1363 | |
1364 | /*----- That's all, folks -------------------------------------------------*/ |