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 | * | |
12 | * TrIPE is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU General Public License as published by | |
14 | * the Free Software Foundation; either version 2 of the License, or | |
15 | * (at your option) any later version. | |
e04c2d50 | 16 | * |
410c8acf | 17 | * TrIPE is distributed in the hope that it will be useful, |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU General Public License for more details. | |
e04c2d50 | 21 | * |
410c8acf | 22 | * You should have received a copy of the GNU General Public License |
23 | * along with TrIPE; if not, write to the Free Software Foundation, | |
24 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
25 | */ | |
26 | ||
410c8acf | 27 | /*----- Header files ------------------------------------------------------*/ |
28 | ||
29 | #include "tripe.h" | |
30 | ||
31 | /*----- Static variables --------------------------------------------------*/ | |
32 | ||
c8e02c8a MW |
33 | static sym_table byname; |
34 | static addrmap byaddr; | |
410c8acf | 35 | static sel_file sock; |
6411163d | 36 | static unsigned nmobile; |
410c8acf | 37 | |
42da2a58 | 38 | /*----- Tunnel table ------------------------------------------------------*/ |
39 | ||
40 | const tunnel_ops *tunnels[] = { | |
41 | #ifdef TUN_LINUX | |
42 | &tun_linux, | |
43 | #endif | |
44 | #ifdef TUN_BSD | |
45 | &tun_bsd, | |
46 | #endif | |
47 | #ifdef TUN_UNET | |
48 | &tun_unet, | |
49 | #endif | |
50 | &tun_slip, | |
51 | 0 | |
52 | }, *tun_default; | |
53 | ||
410c8acf | 54 | /*----- Main code ---------------------------------------------------------*/ |
55 | ||
0ba8de86 | 56 | /* --- @p_pingtype@ --- * |
57 | * | |
58 | * Arguments: @unsigned msg@ = message type | |
59 | * | |
60 | * Returns: String to describe the message. | |
61 | */ | |
62 | ||
63 | static const char *p_pingtype(unsigned msg) | |
64 | { | |
65 | switch (msg & MSG_TYPEMASK) { | |
66 | case MISC_PING: | |
67 | case MISC_PONG: | |
68 | return "transport-ping"; | |
69 | case MISC_EPING: | |
70 | case MISC_EPONG: | |
71 | return "encrypted-ping"; | |
72 | default: | |
73 | abort(); | |
74 | } | |
75 | } | |
76 | ||
77 | /* --- @p_ponged@ --- * | |
78 | * | |
79 | * Arguments: @peer *p@ = peer packet arrived from | |
80 | * @unsigned msg@ = message type | |
81 | * @buf *b@ = buffer containing payload | |
82 | * | |
83 | * Returns: --- | |
84 | * | |
85 | * Use: Processes a ping response. | |
86 | */ | |
87 | ||
88 | static void p_ponged(peer *p, unsigned msg, buf *b) | |
89 | { | |
90 | uint32 id; | |
91 | const octet *magic; | |
92 | ping *pg; | |
e04c2d50 | 93 | |
0ba8de86 | 94 | IF_TRACING(T_PEER, { |
95 | trace(T_PEER, "peer: received %s reply from %s", | |
96 | p_pingtype(msg), p->spec.name); | |
97 | trace_block(T_PACKET, "peer: ping contents", BBASE(b), BSZ(b)); | |
98 | }) | |
99 | ||
100 | if (buf_getu32(b, &id) || | |
101 | (magic = buf_get(b, sizeof(pg->magic))) == 0 || | |
102 | BLEFT(b)) { | |
f43df819 | 103 | a_warn("PEER", "?PEER", p, "malformed-%s", p_pingtype(msg), A_END); |
0ba8de86 | 104 | return; |
105 | } | |
106 | ||
107 | for (pg = p->pings; pg; pg = pg->next) { | |
108 | if (pg->id == id) | |
109 | goto found; | |
110 | } | |
f43df819 MW |
111 | a_warn("PEER", |
112 | "?PEER", p, | |
113 | "unexpected-%s", p_pingtype(msg), | |
114 | "0x%08lx", (unsigned long)id, | |
115 | A_END); | |
0ba8de86 | 116 | return; |
117 | ||
118 | found: | |
119 | if (memcmp(magic, pg->magic, sizeof(pg->magic)) != 0) { | |
f43df819 | 120 | a_warn("PEER", "?PEER", p, "corrupt-%s", p_pingtype(msg), A_END); |
0ba8de86 | 121 | return; |
122 | } | |
123 | p_pingdone(pg, PING_OK); | |
124 | } | |
125 | ||
6411163d MW |
126 | /* --- @p_rxupdstats@ --- * |
127 | * | |
128 | * Arguments: @peer *p@ = peer to update | |
129 | * @size_t n@ = size of incoming packet | |
130 | * | |
131 | * Returns: --- | |
132 | * | |
133 | * Use: Updates the peer's incoming packet statistics. | |
134 | */ | |
135 | ||
136 | static void p_rxupdstats(peer *p, size_t n) | |
137 | { | |
138 | p->st.t_last = time(0); | |
139 | p->st.n_in++; | |
140 | p->st.sz_in += n; | |
141 | } | |
142 | ||
a50f9a0e MW |
143 | /* --- @p_encrypt@ --- * |
144 | * | |
145 | * Arguments: @peer *p@ = peer to encrypt message to | |
146 | * @int ty@ message type to send | |
147 | * @buf *bin, *bout@ = input and output buffers | |
148 | * | |
149 | * Returns: --- | |
150 | * | |
151 | * Use: Convenience function for packet encryption. Forces | |
152 | * renegotiation when necessary. Check for the output buffer | |
153 | * being broken to find out whether the encryption was | |
154 | * successful. | |
155 | */ | |
156 | ||
157 | static int p_encrypt(peer *p, int ty, buf *bin, buf *bout) | |
158 | { | |
159 | int err = ksl_encrypt(&p->ks, ty, bin, bout); | |
160 | ||
161 | if (err == KSERR_REGEN) { | |
162 | kx_start(&p->kx, 1); | |
163 | err = 0; | |
164 | } | |
165 | if (!BOK(bout)) | |
166 | err = -1; | |
167 | return (err); | |
168 | } | |
169 | ||
170 | /* --- @p_decrypt@ --- * | |
171 | * | |
6411163d MW |
172 | * Arguments: @peer **pp@ = pointer to peer to decrypt message from |
173 | * @addr *a@ = address the packet arrived on | |
174 | * @size_t n@ = size of original incoming packet | |
a50f9a0e MW |
175 | * @int ty@ = message type to expect |
176 | * @buf *bin, *bout@ = input and output buffers | |
177 | * | |
178 | * Returns: Zero on success; nonzero on error. | |
179 | * | |
180 | * Use: Convenience function for packet decryption. Reports errors | |
181 | * and updates statistics appropriately. | |
6411163d MW |
182 | * |
183 | * If @*pp@ is null on entry and there are mobile peers then we | |
184 | * see if any of them can decrypt the packet. If so, we record | |
185 | * @*a@ as the peer's new address and send a notification. | |
a50f9a0e MW |
186 | */ |
187 | ||
6411163d MW |
188 | static int p_decrypt(peer **pp, addr *a, size_t n, |
189 | int ty, buf *bin, buf *bout) | |
a50f9a0e | 190 | { |
c71be758 MW |
191 | peer *p, *q; |
192 | peer_byaddr *pa, *qa; | |
6411163d MW |
193 | int err = KSERR_DECRYPT; |
194 | unsigned f; | |
195 | ||
c71be758 MW |
196 | /* --- If we have a match on the source address then try that first --- */ |
197 | ||
198 | q = *pp; | |
199 | if (q) { | |
6411163d | 200 | T( trace(T_PEER, "peer: decrypting packet from known peer `%s'", |
c71be758 MW |
201 | p_name(q)); ) |
202 | if ((err = ksl_decrypt(&q->ks, ty, bin, bout)) != KSERR_DECRYPT || | |
203 | !(q->spec.f & PSF_MOBILE) || nmobile == 1) { | |
204 | p = q; | |
205 | goto match; | |
206 | } | |
73174919 | 207 | T( trace(T_PEER, "peer: failed to decrypt: try other mobile peers..."); ) |
c71be758 | 208 | } else if (nmobile) |
8ed35e02 | 209 | T( trace(T_PEER, "peer: unknown source: trying mobile peers...") ); |
c71be758 | 210 | else { |
6411163d | 211 | p = 0; |
c71be758 MW |
212 | goto searched; |
213 | } | |
214 | ||
215 | /* --- See whether any mobile peer is interested --- */ | |
216 | ||
01c21903 MW |
217 | p = 0; |
218 | FOREACH_PEER(qq, { | |
219 | if (qq == q || !(qq->spec.f & PSF_MOBILE)) continue; | |
220 | if ((err = ksl_decrypt(&qq->ks, ty, bin, bout)) == KSERR_DECRYPT) { | |
c71be758 | 221 | T( trace(T_PEER, "peer: peer `%s' failed to decrypt", |
01c21903 | 222 | p_name(qq)); ) |
c71be758 MW |
223 | continue; |
224 | } else { | |
01c21903 | 225 | p = qq; |
c71be758 MW |
226 | IF_TRACING(T_PEER, { |
227 | if (!err) | |
01c21903 | 228 | trace(T_PEER, "peer: peer `%s' reports success", p_name(qq)); |
c71be758 MW |
229 | else { |
230 | trace(T_PEER, "peer: peer `%s' reports decryption error %d", | |
01c21903 | 231 | p_name(qq), err); |
6411163d | 232 | } |
c71be758 MW |
233 | }) |
234 | break; | |
6411163d | 235 | } |
c71be758 MW |
236 | }); |
237 | ||
238 | /* --- We've searched the mobile peers --- */ | |
239 | ||
240 | searched: | |
241 | if (!p) { | |
01c21903 MW |
242 | if (!q) |
243 | a_warn("PEER", "-", "unexpected-source", "?ADDR", a, A_END); | |
244 | else { | |
245 | a_warn("PEER", "?PEER", p, "decrypt-failed", | |
246 | "error-code", "%d", err, A_END); | |
247 | p_rxupdstats(q, n); | |
248 | } | |
c71be758 MW |
249 | return (-1); |
250 | } | |
251 | ||
252 | /* --- We found one that accepted, so update the peer's address --- * | |
253 | * | |
254 | * If we had an initial guess of which peer this packet came from -- i.e., | |
255 | * @q@ is not null -- then swap the addresses over. This doesn't leave the | |
256 | * evicted peer in an especially good state, but it ought to get sorted out | |
257 | * soon enough. | |
258 | */ | |
259 | ||
260 | if (!err) { | |
01c21903 | 261 | *pp = p; |
c71be758 | 262 | if (!q) { |
6411163d | 263 | T( trace(T_PEER, "peer: updating address for `%s'", p_name(p)); ) |
6411163d MW |
264 | pa = am_find(&byaddr, a, sizeof(peer_byaddr), &f); assert(!f); |
265 | am_remove(&byaddr, p->byaddr); | |
266 | p->byaddr = pa; | |
267 | pa->p = p; | |
268 | p->spec.sa = *a; | |
269 | a_notify("NEWADDR", "?PEER", p, "?ADDR", a, A_END); | |
c71be758 MW |
270 | } else { |
271 | T( trace(T_PEER, "peer: swapping addresses for `%s' and `%s'", | |
272 | p_name(p), p_name(q)); ) | |
273 | pa = p->byaddr; qa = q->byaddr; | |
274 | pa->p = q; q->byaddr = pa; q->spec.sa = p->spec.sa; | |
275 | qa->p = p; p->byaddr = qa; p->spec.sa = *a; | |
276 | a_notify("NEWADDR", "?PEER", p, "?ADDR", a, A_END); | |
277 | a_notify("NEWADDR", "?PEER", q, "?ADDR", &q->spec.sa, A_END); | |
6411163d MW |
278 | } |
279 | } | |
c71be758 MW |
280 | |
281 | match: | |
88622d1d | 282 | p_rxupdstats(p, n); |
6411163d MW |
283 | if (err) { |
284 | if (p) p->st.n_reject++; | |
285 | a_warn("PEER", "?PEER", p, "decrypt-failed", | |
286 | "error-code", "%d", err, A_END); | |
a50f9a0e MW |
287 | return (-1); |
288 | } | |
289 | if (!BOK(bout)) | |
290 | return (-1); | |
291 | return (0); | |
292 | } | |
293 | ||
410c8acf | 294 | /* --- @p_read@ --- * |
295 | * | |
296 | * Arguments: @int fd@ = file descriptor to read from | |
297 | * @unsigned mode@ = what happened | |
298 | * @void *v@ = an uninteresting pointer | |
299 | * | |
300 | * Returns: --- | |
301 | * | |
302 | * Use: Reads a packet from somewhere. | |
303 | */ | |
304 | ||
305 | static void p_read(int fd, unsigned mode, void *v) | |
306 | { | |
37941236 | 307 | peer *p = 0; |
410c8acf | 308 | addr a; |
cb160b86 | 309 | socklen_t sz; |
410c8acf | 310 | ssize_t n; |
311 | int ch; | |
312 | buf b, bb; | |
313 | ||
314 | /* --- Read the data --- */ | |
315 | ||
f4c9c08f | 316 | QUICKRAND; |
410c8acf | 317 | sz = sizeof(addr); |
318 | n = recvfrom(fd, buf_i, sizeof(buf_i), 0, &a.sa, &sz); | |
319 | if (n < 0) { | |
f43df819 | 320 | a_warn("PEER", "-", "socket-read-error", "?ERRNO", A_END); |
410c8acf | 321 | return; |
322 | } | |
323 | ||
37941236 | 324 | /* --- If the packet is a greeting, don't check peers --- */ |
325 | ||
326 | if (n && buf_i[0] == (MSG_MISC | MISC_GREET)) { | |
327 | IF_TRACING(T_PEER, { | |
328 | trace(T_PEER, "peer: greeting received from INET %s %u", | |
329 | inet_ntoa(a.sin.sin_addr), | |
330 | (unsigned)ntohs(a.sin.sin_port)); | |
331 | trace_block(T_PACKET, "peer: greeting contents", buf_i, n); | |
332 | }) | |
333 | buf_init(&b, buf_i, n); | |
334 | buf_getbyte(&b); | |
335 | if (c_check(&b) || BLEFT(&b)) { | |
f43df819 | 336 | a_warn("PEER", "-", "invalid-greeting", A_END); |
37941236 | 337 | return; |
338 | } | |
f43df819 MW |
339 | a_notify("GREET", |
340 | "?B64", buf_i + 1, (size_t)(n - 1), | |
341 | "?ADDR", &a, | |
342 | A_END); | |
37941236 | 343 | return; |
344 | } | |
345 | ||
6411163d MW |
346 | /* --- Find the appropriate peer --- * |
347 | * | |
348 | * At this stage, don't worry too much about whether we actually found it. | |
349 | */ | |
410c8acf | 350 | |
6411163d | 351 | p = p_findbyaddr(&a); |
410c8acf | 352 | |
b9066fbb | 353 | IF_TRACING(T_PEER, { |
6411163d MW |
354 | if (p) { |
355 | trace(T_PEER, | |
356 | "peer: packet received from `%s' from address INET %s %d", | |
357 | p_name(p), inet_ntoa(a.sin.sin_addr), ntohs(a.sin.sin_port)); | |
358 | } else { | |
359 | trace(T_PEER, "peer: packet received from unknown address INET %s %d", | |
360 | inet_ntoa(a.sin.sin_addr), ntohs(a.sin.sin_port)); | |
361 | } | |
b9066fbb | 362 | trace_block(T_PACKET, "peer: packet contents", buf_i, n); |
363 | }) | |
410c8acf | 364 | |
365 | /* --- Pick the packet apart --- */ | |
366 | ||
367 | buf_init(&b, buf_i, n); | |
368 | if ((ch = buf_getbyte(&b)) < 0) { | |
f43df819 | 369 | a_warn("PEER", "?PEER", p, "bad-packet", "no-type", A_END); |
410c8acf | 370 | return; |
371 | } | |
5bb41301 | 372 | switch (ch & MSG_CATMASK) { |
410c8acf | 373 | case MSG_PACKET: |
5bb41301 | 374 | if (ch & MSG_TYPEMASK) { |
f43df819 MW |
375 | a_warn("PEER", |
376 | "?PEER", p, | |
377 | "bad-packet", | |
378 | "unknown-type", "0x%02x", ch, | |
379 | A_END); | |
6411163d | 380 | if (p) p->st.n_reject++; |
5bb41301 | 381 | return; |
382 | } | |
410c8acf | 383 | buf_init(&bb, buf_o, sizeof(buf_o)); |
6411163d | 384 | if (p_decrypt(&p, &a, n, MSG_PACKET, &b, &bb)) |
410c8acf | 385 | return; |
5bb41301 | 386 | if (BOK(&bb)) { |
387 | p->st.n_ipin++; | |
388 | p->st.sz_ipin += BSZ(&b); | |
42da2a58 | 389 | p->t->ops->inject(p->t, &bb); |
5bb41301 | 390 | } else { |
391 | p->st.n_reject++; | |
f43df819 | 392 | a_warn("PEER", "?PEER", p, "packet-build-failed", A_END); |
5bb41301 | 393 | } |
410c8acf | 394 | break; |
5bb41301 | 395 | case MSG_KEYEXCH: |
6411163d | 396 | if (!p) goto unexp; |
88622d1d | 397 | p_rxupdstats(p, n); |
5bb41301 | 398 | kx_message(&p->kx, ch & MSG_TYPEMASK, &b); |
410c8acf | 399 | break; |
0ba8de86 | 400 | case MSG_MISC: |
401 | switch (ch & MSG_TYPEMASK) { | |
402 | case MISC_NOP: | |
6411163d | 403 | if (!p) goto unexp; |
88622d1d | 404 | p_rxupdstats(p, n); |
0ba8de86 | 405 | T( trace(T_PEER, "peer: received NOP packet"); ) |
406 | break; | |
407 | case MISC_PING: | |
6411163d | 408 | if (!p) goto unexp; |
88622d1d | 409 | p_rxupdstats(p, n); |
0ba8de86 | 410 | buf_put(p_txstart(p, MSG_MISC | MISC_PONG), BCUR(&b), BLEFT(&b)); |
411 | p_txend(p); | |
e04c2d50 | 412 | break; |
0ba8de86 | 413 | case MISC_PONG: |
6411163d | 414 | if (!p) goto unexp; |
88622d1d | 415 | p_rxupdstats(p, n); |
0ba8de86 | 416 | p_ponged(p, MISC_PONG, &b); |
417 | break; | |
418 | case MISC_EPING: | |
419 | buf_init(&bb, buf_t, sizeof(buf_t)); | |
6411163d | 420 | if (p_decrypt(&p, &a, n, ch, &b, &bb)) |
0ba8de86 | 421 | return; |
0ba8de86 | 422 | if (BOK(&bb)) { |
423 | buf_flip(&bb); | |
a50f9a0e MW |
424 | p_encrypt(p, MSG_MISC | MISC_EPONG, &bb, |
425 | p_txstart(p, MSG_MISC | MISC_EPONG)); | |
0ba8de86 | 426 | p_txend(p); |
427 | } | |
428 | break; | |
429 | case MISC_EPONG: | |
430 | buf_init(&bb, buf_t, sizeof(buf_t)); | |
6411163d | 431 | if (p_decrypt(&p, &a, n, ch, &b, &bb)) |
0ba8de86 | 432 | return; |
0ba8de86 | 433 | if (BOK(&bb)) { |
434 | buf_flip(&bb); | |
435 | p_ponged(p, MISC_EPONG, &bb); | |
436 | } | |
437 | break; | |
438 | } | |
439 | break; | |
410c8acf | 440 | default: |
6411163d | 441 | if (p) p->st.n_reject++; |
f43df819 MW |
442 | a_warn("PEER", |
443 | "?PEER", p, | |
444 | "bad-packet", | |
a68280fc | 445 | "unknown-category", "0x%02x", ch, |
f43df819 | 446 | A_END); |
410c8acf | 447 | break; |
6411163d MW |
448 | unexp: |
449 | a_warn("PEER", "-", "unexpected-source", "?ADDR", &a, A_END); | |
450 | break; | |
410c8acf | 451 | } |
452 | } | |
453 | ||
454 | /* --- @p_txstart@ --- * | |
455 | * | |
456 | * Arguments: @peer *p@ = pointer to peer block | |
457 | * @unsigned msg@ = message type code | |
458 | * | |
459 | * Returns: A pointer to a buffer to write to. | |
460 | * | |
461 | * Use: Starts sending to a peer. Only one send can happen at a | |
462 | * time. | |
463 | */ | |
464 | ||
465 | buf *p_txstart(peer *p, unsigned msg) | |
466 | { | |
467 | buf_init(&p->b, buf_o, sizeof(buf_o)); | |
468 | buf_putbyte(&p->b, msg); | |
469 | return (&p->b); | |
470 | } | |
471 | ||
472 | /* --- @p_txend@ --- * | |
473 | * | |
474 | * Arguments: @peer *p@ = pointer to peer block | |
475 | * | |
476 | * Returns: --- | |
477 | * | |
478 | * Use: Sends a packet to the peer. | |
479 | */ | |
480 | ||
0ba8de86 | 481 | static void p_setkatimer(peer *); |
482 | ||
483 | static int p_dotxend(peer *p) | |
410c8acf | 484 | { |
485 | if (!BOK(&p->b)) { | |
f43df819 | 486 | a_warn("PEER", "?PEER", p, "packet-build-failed", A_END); |
0ba8de86 | 487 | return (0); |
410c8acf | 488 | } |
489 | IF_TRACING(T_PEER, trace_block(T_PACKET, "peer: sending packet", | |
490 | BBASE(&p->b), BLEN(&p->b)); ) | |
491 | if (sendto(sock.fd, BBASE(&p->b), BLEN(&p->b), | |
0ba8de86 | 492 | 0, &p->spec.sa.sa, p->spec.sasz) < 0) { |
f43df819 | 493 | a_warn("PEER", "?PEER", p, "socket-write-error", "?ERRNO", A_END); |
0ba8de86 | 494 | return (0); |
495 | } else { | |
5bb41301 | 496 | p->st.n_out++; |
497 | p->st.sz_out += BLEN(&p->b); | |
0ba8de86 | 498 | return (1); |
5bb41301 | 499 | } |
410c8acf | 500 | } |
501 | ||
0ba8de86 | 502 | void p_txend(peer *p) |
503 | { | |
504 | if (p_dotxend(p) && p->spec.t_ka) { | |
505 | sel_rmtimer(&p->tka); | |
506 | p_setkatimer(p); | |
507 | } | |
508 | } | |
509 | ||
510 | /* --- @p_pingwrite@ --- * | |
511 | * | |
512 | * Arguments: @ping *p@ = ping structure | |
513 | * @buf *b@ = buffer to write in | |
514 | * | |
515 | * Returns: --- | |
516 | * | |
517 | * Use: Fills in a ping structure and writes the packet payload. | |
518 | */ | |
519 | ||
520 | static void p_pingwrite(ping *p, buf *b) | |
521 | { | |
522 | static uint32 seq = 0; | |
523 | ||
524 | p->id = U32(seq++); | |
525 | GR_FILL(&rand_global, p->magic, sizeof(p->magic)); | |
526 | buf_putu32(b, p->id); | |
527 | buf_put(b, p->magic, sizeof(p->magic)); | |
528 | } | |
529 | ||
530 | /* --- @p_pingdone@ --- * | |
531 | * | |
532 | * Arguments: @ping *p@ = ping structure | |
533 | * @int rc@ = return code to pass on | |
534 | * | |
535 | * Returns: --- | |
536 | * | |
537 | * Use: Disposes of a ping structure, maybe sending a notification. | |
538 | */ | |
539 | ||
540 | void p_pingdone(ping *p, int rc) | |
541 | { | |
0ba8de86 | 542 | if (p->prev) p->prev->next = p->next; |
543 | else p->p->pings = p->next; | |
544 | if (p->next) p->next->prev = p->prev; | |
545 | if (rc != PING_TIMEOUT) sel_rmtimer(&p->t); | |
060ca767 | 546 | T( trace(T_PEER, "peer: ping 0x%08lx done (rc = %d)", |
547 | (unsigned long)p->id, rc); ) | |
0ba8de86 | 548 | if (rc >= 0) p->func(rc, p->arg); |
549 | } | |
550 | ||
551 | /* --- @p_pingtimeout@ --- * | |
552 | * | |
553 | * Arguments: @struct timeval *now@ = the time now | |
554 | * @void *pv@ = pointer to ping block | |
555 | * | |
556 | * Returns: --- | |
557 | * | |
558 | * Use: Called when a ping times out. | |
559 | */ | |
560 | ||
561 | static void p_pingtimeout(struct timeval *now, void *pv) | |
562 | { | |
563 | ping *p = pv; | |
564 | ||
565 | T( trace(T_PEER, "peer: ping 0x%08lx timed out", (unsigned long)p->id); ) | |
566 | p_pingdone(p, PING_TIMEOUT); | |
567 | } | |
568 | ||
569 | /* --- @p_pingsend@ --- * | |
570 | * | |
571 | * Arguments: @peer *p@ = destination peer | |
572 | * @ping *pg@ = structure to fill in | |
573 | * @unsigned type@ = message type | |
574 | * @unsigned long timeout@ = how long to wait before giving up | |
575 | * @void (*func)(int, void *)@ = callback function | |
576 | * @void *arg@ = argument for callback | |
577 | * | |
578 | * Returns: Zero if successful, nonzero if it failed. | |
579 | * | |
580 | * Use: Sends a ping to a peer. Call @func@ with a nonzero argument | |
581 | * if we get an answer within the timeout, or zero if no answer. | |
582 | */ | |
583 | ||
584 | int p_pingsend(peer *p, ping *pg, unsigned type, | |
585 | unsigned long timeout, | |
586 | void (*func)(int, void *), void *arg) | |
587 | { | |
588 | buf *b, bb; | |
589 | struct timeval tv; | |
590 | ||
0ba8de86 | 591 | switch (type) { |
592 | case MISC_PING: | |
593 | pg->msg = MISC_PONG; | |
594 | b = p_txstart(p, MSG_MISC | MISC_PING); | |
595 | p_pingwrite(pg, b); | |
596 | p_txend(p); | |
597 | break; | |
598 | case MISC_EPING: | |
599 | pg->msg = MISC_EPONG; | |
600 | b = p_txstart(p, MSG_MISC | MISC_EPING); | |
601 | buf_init(&bb, buf_t, sizeof(buf_t)); | |
602 | p_pingwrite(pg, &bb); | |
603 | buf_flip(&bb); | |
a50f9a0e | 604 | p_encrypt(p, MSG_MISC | MISC_EPING, &bb, b); |
0ba8de86 | 605 | if (!BOK(b)) |
606 | return (-1); | |
607 | p_txend(p); | |
608 | break; | |
609 | default: | |
610 | abort(); | |
611 | break; | |
612 | } | |
613 | ||
614 | pg->next = p->pings; | |
615 | pg->prev = 0; | |
616 | pg->p = p; | |
617 | pg->func = func; | |
618 | pg->arg = arg; | |
060ca767 | 619 | if (p->pings) p->pings->prev = pg; |
0ba8de86 | 620 | p->pings = pg; |
621 | gettimeofday(&tv, 0); | |
622 | tv.tv_sec += timeout; | |
623 | sel_addtimer(&sel, &pg->t, &tv, p_pingtimeout, pg); | |
624 | T( trace(T_PEER, "peer: send %s 0x%08lx to %s", | |
625 | p_pingtype(type), (unsigned long)pg->id, p->spec.name); ) | |
626 | return (0); | |
627 | } | |
628 | ||
37941236 | 629 | /* --- @p_greet@ --- * |
630 | * | |
631 | * Arguments: @peer *p@ = peer to send to | |
632 | * @const void *c@ = pointer to challenge | |
633 | * @size_t sz@ = size of challenge | |
634 | * | |
635 | * Returns: --- | |
636 | * | |
637 | * Use: Sends a greeting packet. | |
638 | */ | |
639 | ||
640 | void p_greet(peer *p, const void *c, size_t sz) | |
641 | { | |
642 | buf *b = p_txstart(p, MSG_MISC | MISC_GREET); | |
643 | buf_put(b, c, sz); | |
644 | p_txend(p); | |
645 | } | |
646 | ||
410c8acf | 647 | /* --- @p_tun@ --- * |
648 | * | |
649 | * Arguments: @peer *p@ = pointer to peer block | |
650 | * @buf *b@ = buffer containing incoming packet | |
651 | * | |
652 | * Returns: --- | |
653 | * | |
654 | * Use: Handles a packet which needs to be sent to a peer. | |
655 | */ | |
656 | ||
657 | void p_tun(peer *p, buf *b) | |
658 | { | |
659 | buf *bb = p_txstart(p, MSG_PACKET); | |
7b052fe6 | 660 | |
f4c9c08f | 661 | QUICKRAND; |
a50f9a0e | 662 | p_encrypt(p, MSG_PACKET, b, bb); |
5bb41301 | 663 | if (BOK(bb) && BLEN(bb)) { |
664 | p->st.n_ipout++; | |
665 | p->st.sz_ipout += BLEN(bb); | |
410c8acf | 666 | p_txend(p); |
5bb41301 | 667 | } |
410c8acf | 668 | } |
669 | ||
de014da6 | 670 | /* --- @p_keyreload@ --- * |
671 | * | |
672 | * Arguments: --- | |
673 | * | |
674 | * Returns: --- | |
675 | * | |
676 | * Use: Forces a check of the daemon's keyring files. | |
677 | */ | |
678 | ||
679 | void p_keyreload(void) | |
680 | { | |
c8e02c8a MW |
681 | if (km_reload()) |
682 | FOREACH_PEER(p, { kx_newkeys(&p->kx); }); | |
de014da6 | 683 | } |
684 | ||
410c8acf | 685 | /* --- @p_interval@ --- * |
686 | * | |
687 | * Arguments: --- | |
688 | * | |
689 | * Returns: --- | |
690 | * | |
691 | * Use: Called periodically to do tidying. | |
692 | */ | |
693 | ||
694 | void p_interval(void) | |
695 | { | |
de014da6 | 696 | p_keyreload(); |
c8e02c8a | 697 | FOREACH_PEER(p, { ksl_prune(&p->ks); }); |
410c8acf | 698 | } |
699 | ||
5bb41301 | 700 | /* --- @p_stats@ --- * |
701 | * | |
702 | * Arguments: @peer *p@ = pointer to a peer block | |
703 | * | |
704 | * Returns: A pointer to the peer's statistics. | |
705 | */ | |
706 | ||
707 | stats *p_stats(peer *p) { return (&p->st); } | |
708 | ||
410c8acf | 709 | /* --- @p_ifname@ --- * |
710 | * | |
711 | * Arguments: @peer *p@ = pointer to a peer block | |
712 | * | |
713 | * Returns: A pointer to the peer's interface name. | |
714 | */ | |
715 | ||
64cf2223 MW |
716 | const char *p_ifname(peer *p) { return (p->ifname); } |
717 | ||
718 | /* --- @p_setifname@ --- * | |
719 | * | |
720 | * Arguments: @peer *p@ = pointer to a peer block | |
721 | * @const char *name@ = pointer to the new name | |
722 | * | |
723 | * Returns: --- | |
724 | * | |
725 | * Use: Changes the name held for a peer's interface. | |
726 | */ | |
727 | ||
728 | void p_setifname(peer *p, const char *name) | |
72917fe7 MW |
729 | { |
730 | xfree(p->ifname); | |
731 | p->ifname = xstrdup(name); | |
732 | if (p->spec.tops->setifname) | |
733 | p->spec.tops->setifname(p->t, name); | |
734 | } | |
410c8acf | 735 | |
736 | /* --- @p_addr@ --- * | |
737 | * | |
738 | * Arguments: @peer *p@ = pointer to a peer block | |
739 | * | |
740 | * Returns: A pointer to the peer's address. | |
741 | */ | |
742 | ||
0ba8de86 | 743 | const addr *p_addr(peer *p) { return (&p->spec.sa); } |
410c8acf | 744 | |
745 | /* --- @p_init@ --- * | |
746 | * | |
767b36e2 | 747 | * Arguments: @struct in_addr addr@ = address to bind to |
748 | * @unsigned port@ = port number to listen to | |
410c8acf | 749 | * |
750 | * Returns: --- | |
751 | * | |
752 | * Use: Initializes the peer system; creates the socket. | |
753 | */ | |
754 | ||
767b36e2 | 755 | void p_init(struct in_addr addr, unsigned port) |
410c8acf | 756 | { |
757 | int fd; | |
758 | struct sockaddr_in sin; | |
df9dfccf | 759 | int len = PKBUFSZ; |
0a9920e2 | 760 | |
761 | /* --- Note on socket buffer sizes --- * | |
762 | * | |
763 | * For some bizarre reason, Linux 2.2 (at least) doubles the socket buffer | |
764 | * sizes I pass to @setsockopt@. I'm not putting special-case code here | |
765 | * for Linux: BSD (at least TCPv2) does what I tell it rather than second- | |
766 | * guessing me. | |
767 | */ | |
410c8acf | 768 | |
769 | if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) | |
770 | die(EXIT_FAILURE, "socket creation failed: %s", strerror(errno)); | |
771 | BURN(sin); | |
772 | sin.sin_family = AF_INET; | |
767b36e2 | 773 | sin.sin_addr = addr; |
410c8acf | 774 | sin.sin_port = htons(port); |
775 | if (bind(fd, (struct sockaddr *)&sin, sizeof(sin))) | |
776 | die(EXIT_FAILURE, "bind failed: %s", strerror(errno)); | |
0a9920e2 | 777 | if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) || |
778 | setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &len, sizeof(len))) { | |
779 | die(EXIT_FAILURE, "failed to set socket buffer sizes: %s", | |
780 | strerror(errno)); | |
781 | } | |
650a6624 | 782 | fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); |
410c8acf | 783 | sel_initfile(&sel, &sock, fd, SEL_READ, p_read, 0); |
784 | sel_addfile(&sock); | |
785 | T( trace(T_PEER, "peer: created socket"); ) | |
c8e02c8a MW |
786 | |
787 | sym_create(&byname); | |
788 | am_create(&byaddr); | |
410c8acf | 789 | } |
790 | ||
791 | /* --- @p_port@ --- * | |
792 | * | |
793 | * Arguments: --- | |
794 | * | |
795 | * Returns: Port number used for socket. | |
796 | */ | |
797 | ||
798 | unsigned p_port(void) | |
799 | { | |
800 | addr a; | |
cb160b86 | 801 | socklen_t sz = sizeof(addr); |
410c8acf | 802 | |
803 | if (getsockname(sock.fd, &a.sa, &sz)) | |
804 | die(EXIT_FAILURE, "couldn't read port number: %s", strerror(errno)); | |
805 | assert(a.sa.sa_family == AF_INET); | |
806 | return (ntohs(a.sin.sin_port)); | |
807 | } | |
808 | ||
0ba8de86 | 809 | /* --- @p_keepalive@ --- * |
810 | * | |
811 | * Arguments: @struct timeval *now@ = the current time | |
812 | * @void *pv@ = peer to wake up | |
813 | * | |
814 | * Returns: --- | |
815 | * | |
816 | * Use: Sends a keepalive ping message to its peer. | |
817 | */ | |
818 | ||
819 | static void p_keepalive(struct timeval *now, void *pv) | |
820 | { | |
821 | peer *p = pv; | |
fe2a5dcf | 822 | |
0ba8de86 | 823 | p_txstart(p, MSG_MISC | MISC_NOP); p_dotxend(p); |
824 | T( trace(T_PEER, "peer: sent keepalive to %s", p->spec.name); ) | |
825 | p_setkatimer(p); | |
826 | } | |
827 | ||
828 | /* --- @p_setkatimer@ --- * | |
829 | * | |
830 | * Arguments: @peer *p@ = peer to set | |
831 | * | |
832 | * Returns: --- | |
833 | * | |
834 | * Use: Resets the keepalive timer thing. | |
835 | */ | |
836 | ||
837 | static void p_setkatimer(peer *p) | |
838 | { | |
839 | struct timeval tv; | |
840 | ||
841 | if (!p->spec.t_ka) | |
842 | return; | |
843 | gettimeofday(&tv, 0); | |
844 | tv.tv_sec += p->spec.t_ka; | |
845 | sel_addtimer(&sel, &p->tka, &tv, p_keepalive, p); | |
846 | } | |
847 | ||
410c8acf | 848 | /* --- @p_create@ --- * |
849 | * | |
0ba8de86 | 850 | * Arguments: @peerspec *spec@ = information about this peer |
410c8acf | 851 | * |
852 | * Returns: Pointer to the peer block, or null if it failed. | |
853 | * | |
854 | * Use: Creates a new named peer block. No peer is actually attached | |
855 | * by this point. | |
856 | */ | |
857 | ||
0ba8de86 | 858 | peer *p_create(peerspec *spec) |
410c8acf | 859 | { |
860 | peer *p = CREATE(peer); | |
eb5f3fea MW |
861 | const tunnel_ops *tops = spec->tops; |
862 | int fd; | |
c8e02c8a MW |
863 | unsigned f; |
864 | ||
865 | p->byname = sym_find(&byname, spec->name, -1, sizeof(peer_byname), &f); | |
866 | if (f) goto tidy_0; | |
867 | p->byaddr = am_find(&byaddr, &spec->sa, sizeof(peer_byaddr), &f); | |
868 | if (f) goto tidy_1; | |
869 | p->byname->p = p->byaddr->p = p; | |
42da2a58 | 870 | |
0ba8de86 | 871 | T( trace(T_PEER, "peer: creating new peer `%s'", spec->name); ) |
872 | p->spec = *spec; | |
c8e02c8a | 873 | p->spec.name = (/*unconst*/ char *)SYM_NAME(p->byname); |
fe2a5dcf MW |
874 | if (spec->tag) p->spec.tag = xstrdup(spec->tag); |
875 | if (spec->privtag) p->spec.privtag = xstrdup(spec->privtag); | |
410c8acf | 876 | p->ks = 0; |
629842d8 | 877 | p->pings = 0; |
64cf2223 | 878 | p->ifname = 0; |
5bb41301 | 879 | memset(&p->st, 0, sizeof(stats)); |
880 | p->st.t_start = time(0); | |
388e0319 | 881 | if (!(tops->flags & TUNF_PRIVOPEN)) |
eb5f3fea | 882 | fd = -1; |
388e0319 | 883 | else if ((fd = ps_tunfd(tops, &p->ifname)) < 0) |
c8e02c8a | 884 | goto tidy_2; |
eb5f3fea MW |
885 | if ((p->t = tops->create(p, fd, &p->ifname)) == 0) |
886 | goto tidy_3; | |
887 | T( trace(T_TUNNEL, "peer: attached interface %s to peer `%s'", | |
888 | p->ifname, p_name(p)); ) | |
0ba8de86 | 889 | p_setkatimer(p); |
8743c776 | 890 | if (kx_init(&p->kx, p, &p->ks, p->spec.f & PSF_KXMASK)) |
eb5f3fea | 891 | goto tidy_4; |
f43df819 | 892 | a_notify("ADD", |
6047fbac MW |
893 | "?PEER", p, |
894 | "%s", p->ifname, | |
895 | "?ADDR", &p->spec.sa, | |
896 | A_END); | |
8743c776 | 897 | if (!(p->spec.f & KXF_CORK)) { |
010e6f63 | 898 | a_notify("KXSTART", "?PEER", p, A_END); |
f43df819 | 899 | /* Couldn't tell anyone before */ |
010e6f63 | 900 | } |
6411163d | 901 | if (p->spec.f & PSF_MOBILE) nmobile++; |
410c8acf | 902 | return (p); |
903 | ||
eb5f3fea | 904 | tidy_4: |
fe2a5dcf | 905 | if (spec->t_ka) sel_rmtimer(&p->tka); |
72917fe7 | 906 | xfree(p->ifname); |
0ba8de86 | 907 | p->t->ops->destroy(p->t); |
eb5f3fea MW |
908 | tidy_3: |
909 | if (fd >= 0) close(fd); | |
c8e02c8a MW |
910 | tidy_2: |
911 | am_remove(&byaddr, p->byaddr); | |
48b84569 | 912 | if (p->spec.tag) xfree(p->spec.tag); |
fe2a5dcf | 913 | if (p->spec.privtag) xfree(p->spec.privtag); |
c8e02c8a MW |
914 | tidy_1: |
915 | sym_remove(&byname, p->byname); | |
410c8acf | 916 | tidy_0: |
410c8acf | 917 | DESTROY(p); |
918 | return (0); | |
919 | } | |
920 | ||
921 | /* --- @p_name@ --- * | |
922 | * | |
923 | * Arguments: @peer *p@ = pointer to a peer block | |
924 | * | |
925 | * Returns: A pointer to the peer's name. | |
926 | */ | |
927 | ||
6411163d MW |
928 | const char *p_name(peer *p) |
929 | { if (p) return (p->spec.name); else return ("-"); } | |
410c8acf | 930 | |
48b84569 MW |
931 | /* --- @p_tag@ --- * |
932 | * | |
933 | * Arguments: @peer *p@ = pointer to a peer block | |
934 | * | |
935 | * Returns: A pointer to the peer's public key tag. | |
936 | */ | |
937 | ||
938 | const char *p_tag(peer *p) | |
939 | { return (p->spec.tag ? p->spec.tag : p->spec.name); } | |
940 | ||
fe2a5dcf MW |
941 | /* --- @p_privtag@ --- * |
942 | * | |
943 | * Arguments: @peer *p@ = pointer to a peer block | |
944 | * | |
945 | * Returns: A pointer to the peer's private key tag. | |
946 | */ | |
947 | ||
948 | const char *p_privtag(peer *p) | |
949 | { return (p->spec.privtag ? p->spec.privtag : tag_priv); } | |
950 | ||
060ca767 | 951 | /* --- @p_spec@ --- * |
952 | * | |
953 | * Arguments: @peer *p@ = pointer to a peer block | |
954 | * | |
955 | * Returns: Pointer to the peer's specification | |
956 | */ | |
957 | ||
958 | const peerspec *p_spec(peer *p) { return (&p->spec); } | |
959 | ||
c8e02c8a MW |
960 | /* --- @p_findbyaddr@ --- * |
961 | * | |
962 | * Arguments: @const addr *a@ = address to look up | |
963 | * | |
964 | * Returns: Pointer to the peer block, or null if not found. | |
965 | * | |
966 | * Use: Finds a peer by address. | |
967 | */ | |
968 | ||
969 | peer *p_findbyaddr(const addr *a) | |
970 | { | |
971 | peer_byaddr *pa; | |
972 | ||
6411163d MW |
973 | if ((pa = am_find(&byaddr, a, 0, 0)) != 0) { |
974 | assert(pa->p); | |
c8e02c8a | 975 | return (pa->p); |
6411163d | 976 | } |
c8e02c8a MW |
977 | return (0); |
978 | } | |
979 | ||
410c8acf | 980 | /* --- @p_find@ --- * |
981 | * | |
982 | * Arguments: @const char *name@ = name to look up | |
983 | * | |
984 | * Returns: Pointer to the peer block, or null if not found. | |
985 | * | |
986 | * Use: Finds a peer by name. | |
987 | */ | |
988 | ||
989 | peer *p_find(const char *name) | |
990 | { | |
c8e02c8a MW |
991 | peer_byname *pn; |
992 | ||
993 | if ((pn = sym_find(&byname, name, -1, 0, 0)) != 0) | |
994 | return (pn->p); | |
e04c2d50 | 995 | return (0); |
410c8acf | 996 | } |
997 | ||
998 | /* --- @p_destroy@ --- * | |
999 | * | |
1000 | * Arguments: @peer *p@ = pointer to a peer | |
1001 | * | |
1002 | * Returns: --- | |
1003 | * | |
1004 | * Use: Destroys a peer. | |
1005 | */ | |
1006 | ||
1007 | void p_destroy(peer *p) | |
1008 | { | |
0ba8de86 | 1009 | ping *pg, *ppg; |
1010 | ||
1011 | T( trace(T_PEER, "peer: destroying peer `%s'", p->spec.name); ) | |
f43df819 | 1012 | a_notify("KILL", "%s", p->spec.name, A_END); |
5bb41301 | 1013 | ksl_free(&p->ks); |
410c8acf | 1014 | kx_free(&p->kx); |
fe2a5dcf MW |
1015 | if (p->spec.f & PSF_MOBILE) nmobile--; |
1016 | if (p->ifname) xfree(p->ifname); | |
1017 | if (p->spec.tag) xfree(p->spec.tag); | |
1018 | if (p->spec.privtag) xfree(p->spec.privtag); | |
42da2a58 | 1019 | p->t->ops->destroy(p->t); |
fe2a5dcf | 1020 | if (p->spec.t_ka) sel_rmtimer(&p->tka); |
0ba8de86 | 1021 | for (pg = p->pings; pg; pg = ppg) { |
1022 | ppg = pg->next; | |
1023 | p_pingdone(pg, PING_PEERDIED); | |
1024 | } | |
c8e02c8a MW |
1025 | sym_remove(&byname, p->byname); |
1026 | am_remove(&byaddr, p->byaddr); | |
410c8acf | 1027 | DESTROY(p); |
1028 | } | |
1029 | ||
c8e02c8a MW |
1030 | /* --- @p_mkiter@ --- * |
1031 | * | |
1032 | * Arguments: @peer_iter *i@ = pointer to an iterator | |
1033 | * | |
1034 | * Returns: --- | |
1035 | * | |
1036 | * Use: Initializes the iterator. | |
1037 | */ | |
1038 | ||
1039 | void p_mkiter(peer_iter *i) { sym_mkiter(&i->i, &byname); } | |
1040 | ||
1041 | /* --- @p_next@ --- * | |
1042 | * | |
1043 | * Arguments: @peer_iter *i@ = pointer to an iterator | |
410c8acf | 1044 | * |
c8e02c8a | 1045 | * Returns: Next peer, or null if at the end. |
410c8acf | 1046 | * |
c8e02c8a | 1047 | * Use: Returns the next peer. |
410c8acf | 1048 | */ |
1049 | ||
c8e02c8a MW |
1050 | peer *p_next(peer_iter *i) |
1051 | { | |
1052 | peer_byname *pn; | |
1053 | ||
1054 | if ((pn = sym_next(&i->i)) == 0) | |
1055 | return (0); | |
1056 | return (pn->p); | |
1057 | } | |
410c8acf | 1058 | |
1059 | /*----- That's all, folks -------------------------------------------------*/ |