Commit | Line | Data |
---|---|---|
410c8acf | 1 | /* -*-c-*- |
410c8acf | 2 | * |
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 | ||
33 | static peer *peers = 0; | |
34 | static sel_file sock; | |
35 | ||
42da2a58 | 36 | /*----- Tunnel table ------------------------------------------------------*/ |
37 | ||
38 | const tunnel_ops *tunnels[] = { | |
39 | #ifdef TUN_LINUX | |
40 | &tun_linux, | |
41 | #endif | |
42 | #ifdef TUN_BSD | |
43 | &tun_bsd, | |
44 | #endif | |
45 | #ifdef TUN_UNET | |
46 | &tun_unet, | |
47 | #endif | |
48 | &tun_slip, | |
49 | 0 | |
50 | }, *tun_default; | |
51 | ||
410c8acf | 52 | /*----- Main code ---------------------------------------------------------*/ |
53 | ||
0ba8de86 | 54 | /* --- @p_pingtype@ --- * |
55 | * | |
56 | * Arguments: @unsigned msg@ = message type | |
57 | * | |
58 | * Returns: String to describe the message. | |
59 | */ | |
60 | ||
61 | static const char *p_pingtype(unsigned msg) | |
62 | { | |
63 | switch (msg & MSG_TYPEMASK) { | |
64 | case MISC_PING: | |
65 | case MISC_PONG: | |
66 | return "transport-ping"; | |
67 | case MISC_EPING: | |
68 | case MISC_EPONG: | |
69 | return "encrypted-ping"; | |
70 | default: | |
71 | abort(); | |
72 | } | |
73 | } | |
74 | ||
75 | /* --- @p_ponged@ --- * | |
76 | * | |
77 | * Arguments: @peer *p@ = peer packet arrived from | |
78 | * @unsigned msg@ = message type | |
79 | * @buf *b@ = buffer containing payload | |
80 | * | |
81 | * Returns: --- | |
82 | * | |
83 | * Use: Processes a ping response. | |
84 | */ | |
85 | ||
86 | static void p_ponged(peer *p, unsigned msg, buf *b) | |
87 | { | |
88 | uint32 id; | |
89 | const octet *magic; | |
90 | ping *pg; | |
e04c2d50 | 91 | |
0ba8de86 | 92 | IF_TRACING(T_PEER, { |
93 | trace(T_PEER, "peer: received %s reply from %s", | |
94 | p_pingtype(msg), p->spec.name); | |
95 | trace_block(T_PACKET, "peer: ping contents", BBASE(b), BSZ(b)); | |
96 | }) | |
97 | ||
98 | if (buf_getu32(b, &id) || | |
99 | (magic = buf_get(b, sizeof(pg->magic))) == 0 || | |
100 | BLEFT(b)) { | |
f43df819 | 101 | a_warn("PEER", "?PEER", p, "malformed-%s", p_pingtype(msg), A_END); |
0ba8de86 | 102 | return; |
103 | } | |
104 | ||
105 | for (pg = p->pings; pg; pg = pg->next) { | |
106 | if (pg->id == id) | |
107 | goto found; | |
108 | } | |
f43df819 MW |
109 | a_warn("PEER", |
110 | "?PEER", p, | |
111 | "unexpected-%s", p_pingtype(msg), | |
112 | "0x%08lx", (unsigned long)id, | |
113 | A_END); | |
0ba8de86 | 114 | return; |
115 | ||
116 | found: | |
117 | if (memcmp(magic, pg->magic, sizeof(pg->magic)) != 0) { | |
f43df819 | 118 | a_warn("PEER", "?PEER", p, "corrupt-%s", p_pingtype(msg), A_END); |
0ba8de86 | 119 | return; |
120 | } | |
121 | p_pingdone(pg, PING_OK); | |
122 | } | |
123 | ||
410c8acf | 124 | /* --- @p_read@ --- * |
125 | * | |
126 | * Arguments: @int fd@ = file descriptor to read from | |
127 | * @unsigned mode@ = what happened | |
128 | * @void *v@ = an uninteresting pointer | |
129 | * | |
130 | * Returns: --- | |
131 | * | |
132 | * Use: Reads a packet from somewhere. | |
133 | */ | |
134 | ||
135 | static void p_read(int fd, unsigned mode, void *v) | |
136 | { | |
37941236 | 137 | peer *p = 0; |
410c8acf | 138 | addr a; |
139 | size_t sz; | |
140 | ssize_t n; | |
141 | int ch; | |
142 | buf b, bb; | |
143 | ||
144 | /* --- Read the data --- */ | |
145 | ||
8d0c7a83 | 146 | TIMER; |
410c8acf | 147 | sz = sizeof(addr); |
148 | n = recvfrom(fd, buf_i, sizeof(buf_i), 0, &a.sa, &sz); | |
149 | if (n < 0) { | |
f43df819 | 150 | a_warn("PEER", "-", "socket-read-error", "?ERRNO", A_END); |
410c8acf | 151 | return; |
152 | } | |
153 | ||
37941236 | 154 | /* --- If the packet is a greeting, don't check peers --- */ |
155 | ||
156 | if (n && buf_i[0] == (MSG_MISC | MISC_GREET)) { | |
157 | IF_TRACING(T_PEER, { | |
158 | trace(T_PEER, "peer: greeting received from INET %s %u", | |
159 | inet_ntoa(a.sin.sin_addr), | |
160 | (unsigned)ntohs(a.sin.sin_port)); | |
161 | trace_block(T_PACKET, "peer: greeting contents", buf_i, n); | |
162 | }) | |
163 | buf_init(&b, buf_i, n); | |
164 | buf_getbyte(&b); | |
165 | if (c_check(&b) || BLEFT(&b)) { | |
f43df819 | 166 | a_warn("PEER", "-", "invalid-greeting", A_END); |
37941236 | 167 | return; |
168 | } | |
f43df819 MW |
169 | a_notify("GREET", |
170 | "?B64", buf_i + 1, (size_t)(n - 1), | |
171 | "?ADDR", &a, | |
172 | A_END); | |
37941236 | 173 | return; |
174 | } | |
175 | ||
410c8acf | 176 | /* --- Find the appropriate peer --- */ |
177 | ||
178 | assert(a.sa.sa_family == AF_INET); | |
410c8acf | 179 | for (p = peers; p; p = p->next) { |
0ba8de86 | 180 | if (p->spec.sa.sin.sin_addr.s_addr == a.sin.sin_addr.s_addr && |
181 | p->spec.sa.sin.sin_port == a.sin.sin_port) | |
410c8acf | 182 | goto found; |
183 | } | |
f43df819 | 184 | a_warn("PEER", "-", "unexpected-source", "?ADDR", &a, A_END); |
410c8acf | 185 | return; |
186 | ||
187 | found: | |
b9066fbb | 188 | IF_TRACING(T_PEER, { |
0ba8de86 | 189 | trace(T_PEER, "peer: packet received from `%s'", p->spec.name); |
b9066fbb | 190 | trace_block(T_PACKET, "peer: packet contents", buf_i, n); |
191 | }) | |
410c8acf | 192 | |
193 | /* --- Pick the packet apart --- */ | |
194 | ||
5bb41301 | 195 | p->st.t_last = time(0); |
196 | p->st.n_in++; | |
197 | p->st.sz_in += n; | |
410c8acf | 198 | buf_init(&b, buf_i, n); |
199 | if ((ch = buf_getbyte(&b)) < 0) { | |
f43df819 | 200 | a_warn("PEER", "?PEER", p, "bad-packet", "no-type", A_END); |
410c8acf | 201 | return; |
202 | } | |
5bb41301 | 203 | switch (ch & MSG_CATMASK) { |
410c8acf | 204 | case MSG_PACKET: |
5bb41301 | 205 | if (ch & MSG_TYPEMASK) { |
f43df819 MW |
206 | a_warn("PEER", |
207 | "?PEER", p, | |
208 | "bad-packet", | |
209 | "unknown-type", "0x%02x", ch, | |
210 | A_END); | |
5bb41301 | 211 | p->st.n_reject++; |
212 | return; | |
213 | } | |
410c8acf | 214 | buf_init(&bb, buf_o, sizeof(buf_o)); |
7ed14135 | 215 | if (ksl_decrypt(&p->ks, MSG_PACKET, &b, &bb)) { |
5bb41301 | 216 | p->st.n_reject++; |
f43df819 | 217 | a_warn("PEER", "?PEER", p, "decrypt-failed", A_END); |
410c8acf | 218 | return; |
219 | } | |
5bb41301 | 220 | if (BOK(&bb)) { |
221 | p->st.n_ipin++; | |
222 | p->st.sz_ipin += BSZ(&b); | |
42da2a58 | 223 | p->t->ops->inject(p->t, &bb); |
5bb41301 | 224 | } else { |
225 | p->st.n_reject++; | |
f43df819 | 226 | a_warn("PEER", "?PEER", p, "packet-build-failed", A_END); |
5bb41301 | 227 | } |
410c8acf | 228 | break; |
5bb41301 | 229 | case MSG_KEYEXCH: |
230 | kx_message(&p->kx, ch & MSG_TYPEMASK, &b); | |
410c8acf | 231 | break; |
0ba8de86 | 232 | case MSG_MISC: |
233 | switch (ch & MSG_TYPEMASK) { | |
234 | case MISC_NOP: | |
235 | T( trace(T_PEER, "peer: received NOP packet"); ) | |
236 | break; | |
237 | case MISC_PING: | |
238 | buf_put(p_txstart(p, MSG_MISC | MISC_PONG), BCUR(&b), BLEFT(&b)); | |
239 | p_txend(p); | |
e04c2d50 | 240 | break; |
0ba8de86 | 241 | case MISC_PONG: |
242 | p_ponged(p, MISC_PONG, &b); | |
243 | break; | |
244 | case MISC_EPING: | |
245 | buf_init(&bb, buf_t, sizeof(buf_t)); | |
246 | if (ksl_decrypt(&p->ks, ch, &b, &bb)) { | |
247 | p->st.n_reject++; | |
5ac9463b | 248 | a_warn("PEER", "?PEER", p, "decrypt-failed", A_END); |
0ba8de86 | 249 | return; |
250 | } | |
251 | if (BOK(&bb)) { | |
252 | buf_flip(&bb); | |
253 | if (ksl_encrypt(&p->ks, MSG_MISC | MISC_EPONG, &bb, | |
254 | p_txstart(p, MSG_MISC | MISC_EPONG))) | |
de014da6 | 255 | kx_start(&p->kx, 0); |
0ba8de86 | 256 | p_txend(p); |
257 | } | |
258 | break; | |
259 | case MISC_EPONG: | |
260 | buf_init(&bb, buf_t, sizeof(buf_t)); | |
261 | if (ksl_decrypt(&p->ks, ch, &b, &bb)) { | |
262 | p->st.n_reject++; | |
f43df819 | 263 | a_warn("PEER", "?PEER", p, "decrypt-failed", A_END); |
0ba8de86 | 264 | return; |
265 | } | |
266 | if (BOK(&bb)) { | |
267 | buf_flip(&bb); | |
268 | p_ponged(p, MISC_EPONG, &bb); | |
269 | } | |
270 | break; | |
271 | } | |
272 | break; | |
410c8acf | 273 | default: |
5bb41301 | 274 | p->st.n_reject++; |
f43df819 MW |
275 | a_warn("PEER", |
276 | "?PEER", p, | |
277 | "bad-packet", | |
278 | "unknown-category" "0x%02x", ch, | |
279 | A_END); | |
410c8acf | 280 | break; |
281 | } | |
282 | } | |
283 | ||
284 | /* --- @p_txstart@ --- * | |
285 | * | |
286 | * Arguments: @peer *p@ = pointer to peer block | |
287 | * @unsigned msg@ = message type code | |
288 | * | |
289 | * Returns: A pointer to a buffer to write to. | |
290 | * | |
291 | * Use: Starts sending to a peer. Only one send can happen at a | |
292 | * time. | |
293 | */ | |
294 | ||
295 | buf *p_txstart(peer *p, unsigned msg) | |
296 | { | |
297 | buf_init(&p->b, buf_o, sizeof(buf_o)); | |
298 | buf_putbyte(&p->b, msg); | |
299 | return (&p->b); | |
300 | } | |
301 | ||
302 | /* --- @p_txend@ --- * | |
303 | * | |
304 | * Arguments: @peer *p@ = pointer to peer block | |
305 | * | |
306 | * Returns: --- | |
307 | * | |
308 | * Use: Sends a packet to the peer. | |
309 | */ | |
310 | ||
0ba8de86 | 311 | static void p_setkatimer(peer *); |
312 | ||
313 | static int p_dotxend(peer *p) | |
410c8acf | 314 | { |
315 | if (!BOK(&p->b)) { | |
f43df819 | 316 | a_warn("PEER", "?PEER", p, "packet-build-failed", A_END); |
0ba8de86 | 317 | return (0); |
410c8acf | 318 | } |
319 | IF_TRACING(T_PEER, trace_block(T_PACKET, "peer: sending packet", | |
320 | BBASE(&p->b), BLEN(&p->b)); ) | |
321 | if (sendto(sock.fd, BBASE(&p->b), BLEN(&p->b), | |
0ba8de86 | 322 | 0, &p->spec.sa.sa, p->spec.sasz) < 0) { |
f43df819 | 323 | a_warn("PEER", "?PEER", p, "socket-write-error", "?ERRNO", A_END); |
0ba8de86 | 324 | return (0); |
325 | } else { | |
5bb41301 | 326 | p->st.n_out++; |
327 | p->st.sz_out += BLEN(&p->b); | |
0ba8de86 | 328 | return (1); |
5bb41301 | 329 | } |
410c8acf | 330 | } |
331 | ||
0ba8de86 | 332 | void p_txend(peer *p) |
333 | { | |
334 | if (p_dotxend(p) && p->spec.t_ka) { | |
335 | sel_rmtimer(&p->tka); | |
336 | p_setkatimer(p); | |
337 | } | |
338 | } | |
339 | ||
340 | /* --- @p_pingwrite@ --- * | |
341 | * | |
342 | * Arguments: @ping *p@ = ping structure | |
343 | * @buf *b@ = buffer to write in | |
344 | * | |
345 | * Returns: --- | |
346 | * | |
347 | * Use: Fills in a ping structure and writes the packet payload. | |
348 | */ | |
349 | ||
350 | static void p_pingwrite(ping *p, buf *b) | |
351 | { | |
352 | static uint32 seq = 0; | |
353 | ||
354 | p->id = U32(seq++); | |
355 | GR_FILL(&rand_global, p->magic, sizeof(p->magic)); | |
356 | buf_putu32(b, p->id); | |
357 | buf_put(b, p->magic, sizeof(p->magic)); | |
358 | } | |
359 | ||
360 | /* --- @p_pingdone@ --- * | |
361 | * | |
362 | * Arguments: @ping *p@ = ping structure | |
363 | * @int rc@ = return code to pass on | |
364 | * | |
365 | * Returns: --- | |
366 | * | |
367 | * Use: Disposes of a ping structure, maybe sending a notification. | |
368 | */ | |
369 | ||
370 | void p_pingdone(ping *p, int rc) | |
371 | { | |
0ba8de86 | 372 | if (p->prev) p->prev->next = p->next; |
373 | else p->p->pings = p->next; | |
374 | if (p->next) p->next->prev = p->prev; | |
375 | if (rc != PING_TIMEOUT) sel_rmtimer(&p->t); | |
060ca767 | 376 | T( trace(T_PEER, "peer: ping 0x%08lx done (rc = %d)", |
377 | (unsigned long)p->id, rc); ) | |
0ba8de86 | 378 | if (rc >= 0) p->func(rc, p->arg); |
379 | } | |
380 | ||
381 | /* --- @p_pingtimeout@ --- * | |
382 | * | |
383 | * Arguments: @struct timeval *now@ = the time now | |
384 | * @void *pv@ = pointer to ping block | |
385 | * | |
386 | * Returns: --- | |
387 | * | |
388 | * Use: Called when a ping times out. | |
389 | */ | |
390 | ||
391 | static void p_pingtimeout(struct timeval *now, void *pv) | |
392 | { | |
393 | ping *p = pv; | |
394 | ||
395 | T( trace(T_PEER, "peer: ping 0x%08lx timed out", (unsigned long)p->id); ) | |
396 | p_pingdone(p, PING_TIMEOUT); | |
397 | } | |
398 | ||
399 | /* --- @p_pingsend@ --- * | |
400 | * | |
401 | * Arguments: @peer *p@ = destination peer | |
402 | * @ping *pg@ = structure to fill in | |
403 | * @unsigned type@ = message type | |
404 | * @unsigned long timeout@ = how long to wait before giving up | |
405 | * @void (*func)(int, void *)@ = callback function | |
406 | * @void *arg@ = argument for callback | |
407 | * | |
408 | * Returns: Zero if successful, nonzero if it failed. | |
409 | * | |
410 | * Use: Sends a ping to a peer. Call @func@ with a nonzero argument | |
411 | * if we get an answer within the timeout, or zero if no answer. | |
412 | */ | |
413 | ||
414 | int p_pingsend(peer *p, ping *pg, unsigned type, | |
415 | unsigned long timeout, | |
416 | void (*func)(int, void *), void *arg) | |
417 | { | |
418 | buf *b, bb; | |
419 | struct timeval tv; | |
420 | ||
0ba8de86 | 421 | switch (type) { |
422 | case MISC_PING: | |
423 | pg->msg = MISC_PONG; | |
424 | b = p_txstart(p, MSG_MISC | MISC_PING); | |
425 | p_pingwrite(pg, b); | |
426 | p_txend(p); | |
427 | break; | |
428 | case MISC_EPING: | |
429 | pg->msg = MISC_EPONG; | |
430 | b = p_txstart(p, MSG_MISC | MISC_EPING); | |
431 | buf_init(&bb, buf_t, sizeof(buf_t)); | |
432 | p_pingwrite(pg, &bb); | |
433 | buf_flip(&bb); | |
434 | if (ksl_encrypt(&p->ks, MSG_MISC | MISC_EPING, &bb, b)) | |
de014da6 | 435 | kx_start(&p->kx, 0); |
0ba8de86 | 436 | if (!BOK(b)) |
437 | return (-1); | |
438 | p_txend(p); | |
439 | break; | |
440 | default: | |
441 | abort(); | |
442 | break; | |
443 | } | |
444 | ||
445 | pg->next = p->pings; | |
446 | pg->prev = 0; | |
447 | pg->p = p; | |
448 | pg->func = func; | |
449 | pg->arg = arg; | |
060ca767 | 450 | if (p->pings) p->pings->prev = pg; |
0ba8de86 | 451 | p->pings = pg; |
452 | gettimeofday(&tv, 0); | |
453 | tv.tv_sec += timeout; | |
454 | sel_addtimer(&sel, &pg->t, &tv, p_pingtimeout, pg); | |
455 | T( trace(T_PEER, "peer: send %s 0x%08lx to %s", | |
456 | p_pingtype(type), (unsigned long)pg->id, p->spec.name); ) | |
457 | return (0); | |
458 | } | |
459 | ||
37941236 | 460 | /* --- @p_greet@ --- * |
461 | * | |
462 | * Arguments: @peer *p@ = peer to send to | |
463 | * @const void *c@ = pointer to challenge | |
464 | * @size_t sz@ = size of challenge | |
465 | * | |
466 | * Returns: --- | |
467 | * | |
468 | * Use: Sends a greeting packet. | |
469 | */ | |
470 | ||
471 | void p_greet(peer *p, const void *c, size_t sz) | |
472 | { | |
473 | buf *b = p_txstart(p, MSG_MISC | MISC_GREET); | |
474 | buf_put(b, c, sz); | |
475 | p_txend(p); | |
476 | } | |
477 | ||
410c8acf | 478 | /* --- @p_tun@ --- * |
479 | * | |
480 | * Arguments: @peer *p@ = pointer to peer block | |
481 | * @buf *b@ = buffer containing incoming packet | |
482 | * | |
483 | * Returns: --- | |
484 | * | |
485 | * Use: Handles a packet which needs to be sent to a peer. | |
486 | */ | |
487 | ||
488 | void p_tun(peer *p, buf *b) | |
489 | { | |
490 | buf *bb = p_txstart(p, MSG_PACKET); | |
7b052fe6 | 491 | |
8d0c7a83 | 492 | TIMER; |
7ed14135 | 493 | if (ksl_encrypt(&p->ks, MSG_PACKET, b, bb)) |
de014da6 | 494 | kx_start(&p->kx, 0); |
5bb41301 | 495 | if (BOK(bb) && BLEN(bb)) { |
496 | p->st.n_ipout++; | |
497 | p->st.sz_ipout += BLEN(bb); | |
410c8acf | 498 | p_txend(p); |
5bb41301 | 499 | } |
410c8acf | 500 | } |
501 | ||
de014da6 | 502 | /* --- @p_keyreload@ --- * |
503 | * | |
504 | * Arguments: --- | |
505 | * | |
506 | * Returns: --- | |
507 | * | |
508 | * Use: Forces a check of the daemon's keyring files. | |
509 | */ | |
510 | ||
511 | void p_keyreload(void) | |
512 | { | |
513 | peer *p; | |
514 | ||
515 | if (km_reload()) { | |
516 | for (p = peers; p; p = p->next) | |
517 | kx_newkeys(&p->kx); | |
518 | } | |
519 | } | |
520 | ||
410c8acf | 521 | /* --- @p_interval@ --- * |
522 | * | |
523 | * Arguments: --- | |
524 | * | |
525 | * Returns: --- | |
526 | * | |
527 | * Use: Called periodically to do tidying. | |
528 | */ | |
529 | ||
530 | void p_interval(void) | |
531 | { | |
de014da6 | 532 | peer *p; |
410c8acf | 533 | |
de014da6 | 534 | p_keyreload(); |
535 | for (p = peers; p; p = p->next) | |
5bb41301 | 536 | ksl_prune(&p->ks); |
410c8acf | 537 | } |
538 | ||
5bb41301 | 539 | /* --- @p_stats@ --- * |
540 | * | |
541 | * Arguments: @peer *p@ = pointer to a peer block | |
542 | * | |
543 | * Returns: A pointer to the peer's statistics. | |
544 | */ | |
545 | ||
546 | stats *p_stats(peer *p) { return (&p->st); } | |
547 | ||
410c8acf | 548 | /* --- @p_ifname@ --- * |
549 | * | |
550 | * Arguments: @peer *p@ = pointer to a peer block | |
551 | * | |
552 | * Returns: A pointer to the peer's interface name. | |
553 | */ | |
554 | ||
64cf2223 MW |
555 | const char *p_ifname(peer *p) { return (p->ifname); } |
556 | ||
557 | /* --- @p_setifname@ --- * | |
558 | * | |
559 | * Arguments: @peer *p@ = pointer to a peer block | |
560 | * @const char *name@ = pointer to the new name | |
561 | * | |
562 | * Returns: --- | |
563 | * | |
564 | * Use: Changes the name held for a peer's interface. | |
565 | */ | |
566 | ||
567 | void p_setifname(peer *p, const char *name) | |
72917fe7 MW |
568 | { |
569 | xfree(p->ifname); | |
570 | p->ifname = xstrdup(name); | |
571 | if (p->spec.tops->setifname) | |
572 | p->spec.tops->setifname(p->t, name); | |
573 | } | |
410c8acf | 574 | |
575 | /* --- @p_addr@ --- * | |
576 | * | |
577 | * Arguments: @peer *p@ = pointer to a peer block | |
578 | * | |
579 | * Returns: A pointer to the peer's address. | |
580 | */ | |
581 | ||
0ba8de86 | 582 | const addr *p_addr(peer *p) { return (&p->spec.sa); } |
410c8acf | 583 | |
584 | /* --- @p_init@ --- * | |
585 | * | |
767b36e2 | 586 | * Arguments: @struct in_addr addr@ = address to bind to |
587 | * @unsigned port@ = port number to listen to | |
410c8acf | 588 | * |
589 | * Returns: --- | |
590 | * | |
591 | * Use: Initializes the peer system; creates the socket. | |
592 | */ | |
593 | ||
767b36e2 | 594 | void p_init(struct in_addr addr, unsigned port) |
410c8acf | 595 | { |
596 | int fd; | |
597 | struct sockaddr_in sin; | |
df9dfccf | 598 | int len = PKBUFSZ; |
0a9920e2 | 599 | |
600 | /* --- Note on socket buffer sizes --- * | |
601 | * | |
602 | * For some bizarre reason, Linux 2.2 (at least) doubles the socket buffer | |
603 | * sizes I pass to @setsockopt@. I'm not putting special-case code here | |
604 | * for Linux: BSD (at least TCPv2) does what I tell it rather than second- | |
605 | * guessing me. | |
606 | */ | |
410c8acf | 607 | |
608 | if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) | |
609 | die(EXIT_FAILURE, "socket creation failed: %s", strerror(errno)); | |
610 | BURN(sin); | |
611 | sin.sin_family = AF_INET; | |
767b36e2 | 612 | sin.sin_addr = addr; |
410c8acf | 613 | sin.sin_port = htons(port); |
614 | if (bind(fd, (struct sockaddr *)&sin, sizeof(sin))) | |
615 | die(EXIT_FAILURE, "bind failed: %s", strerror(errno)); | |
0a9920e2 | 616 | if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) || |
617 | setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &len, sizeof(len))) { | |
618 | die(EXIT_FAILURE, "failed to set socket buffer sizes: %s", | |
619 | strerror(errno)); | |
620 | } | |
650a6624 | 621 | fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); |
410c8acf | 622 | sel_initfile(&sel, &sock, fd, SEL_READ, p_read, 0); |
623 | sel_addfile(&sock); | |
624 | T( trace(T_PEER, "peer: created socket"); ) | |
625 | } | |
626 | ||
627 | /* --- @p_port@ --- * | |
628 | * | |
629 | * Arguments: --- | |
630 | * | |
631 | * Returns: Port number used for socket. | |
632 | */ | |
633 | ||
634 | unsigned p_port(void) | |
635 | { | |
636 | addr a; | |
637 | size_t sz = sizeof(addr); | |
638 | ||
639 | if (getsockname(sock.fd, &a.sa, &sz)) | |
640 | die(EXIT_FAILURE, "couldn't read port number: %s", strerror(errno)); | |
641 | assert(a.sa.sa_family == AF_INET); | |
642 | return (ntohs(a.sin.sin_port)); | |
643 | } | |
644 | ||
0ba8de86 | 645 | /* --- @p_keepalive@ --- * |
646 | * | |
647 | * Arguments: @struct timeval *now@ = the current time | |
648 | * @void *pv@ = peer to wake up | |
649 | * | |
650 | * Returns: --- | |
651 | * | |
652 | * Use: Sends a keepalive ping message to its peer. | |
653 | */ | |
654 | ||
655 | static void p_keepalive(struct timeval *now, void *pv) | |
656 | { | |
657 | peer *p = pv; | |
658 | p_txstart(p, MSG_MISC | MISC_NOP); p_dotxend(p); | |
659 | T( trace(T_PEER, "peer: sent keepalive to %s", p->spec.name); ) | |
660 | p_setkatimer(p); | |
661 | } | |
662 | ||
663 | /* --- @p_setkatimer@ --- * | |
664 | * | |
665 | * Arguments: @peer *p@ = peer to set | |
666 | * | |
667 | * Returns: --- | |
668 | * | |
669 | * Use: Resets the keepalive timer thing. | |
670 | */ | |
671 | ||
672 | static void p_setkatimer(peer *p) | |
673 | { | |
674 | struct timeval tv; | |
675 | ||
676 | if (!p->spec.t_ka) | |
677 | return; | |
678 | gettimeofday(&tv, 0); | |
679 | tv.tv_sec += p->spec.t_ka; | |
680 | sel_addtimer(&sel, &p->tka, &tv, p_keepalive, p); | |
681 | } | |
682 | ||
410c8acf | 683 | /* --- @p_create@ --- * |
684 | * | |
0ba8de86 | 685 | * Arguments: @peerspec *spec@ = information about this peer |
410c8acf | 686 | * |
687 | * Returns: Pointer to the peer block, or null if it failed. | |
688 | * | |
689 | * Use: Creates a new named peer block. No peer is actually attached | |
690 | * by this point. | |
691 | */ | |
692 | ||
0ba8de86 | 693 | peer *p_create(peerspec *spec) |
410c8acf | 694 | { |
695 | peer *p = CREATE(peer); | |
42da2a58 | 696 | |
0ba8de86 | 697 | T( trace(T_PEER, "peer: creating new peer `%s'", spec->name); ) |
698 | p->spec = *spec; | |
699 | p->spec.name = xstrdup(spec->name); | |
410c8acf | 700 | p->ks = 0; |
701 | p->prev = 0; | |
629842d8 | 702 | p->pings = 0; |
64cf2223 | 703 | p->ifname = 0; |
5bb41301 | 704 | memset(&p->st, 0, sizeof(stats)); |
705 | p->st.t_start = time(0); | |
72917fe7 | 706 | if ((p->t = spec->tops->create(p, &p->ifname)) == 0) |
410c8acf | 707 | goto tidy_0; |
0ba8de86 | 708 | p_setkatimer(p); |
709 | if (kx_init(&p->kx, p, &p->ks)) | |
410c8acf | 710 | goto tidy_1; |
711 | p->next = peers; | |
712 | if (peers) | |
713 | peers->prev = p; | |
714 | peers = p; | |
f43df819 MW |
715 | a_notify("ADD", |
716 | "?PEER", p, | |
64cf2223 | 717 | "%s", p->ifname, |
f43df819 MW |
718 | "?ADDR", &p->spec.sa, |
719 | A_END); | |
720 | a_notify("KXSTART", "?PEER", p, A_END); | |
721 | /* Couldn't tell anyone before */ | |
410c8acf | 722 | return (p); |
723 | ||
724 | tidy_1: | |
0ba8de86 | 725 | if (spec->t_ka) |
726 | sel_rmtimer(&p->tka); | |
72917fe7 | 727 | xfree(p->ifname); |
0ba8de86 | 728 | p->t->ops->destroy(p->t); |
410c8acf | 729 | tidy_0: |
0ba8de86 | 730 | xfree(p->spec.name); |
410c8acf | 731 | DESTROY(p); |
732 | return (0); | |
733 | } | |
734 | ||
735 | /* --- @p_name@ --- * | |
736 | * | |
737 | * Arguments: @peer *p@ = pointer to a peer block | |
738 | * | |
739 | * Returns: A pointer to the peer's name. | |
740 | */ | |
741 | ||
0ba8de86 | 742 | const char *p_name(peer *p) { return (p->spec.name); } |
410c8acf | 743 | |
060ca767 | 744 | /* --- @p_spec@ --- * |
745 | * | |
746 | * Arguments: @peer *p@ = pointer to a peer block | |
747 | * | |
748 | * Returns: Pointer to the peer's specification | |
749 | */ | |
750 | ||
751 | const peerspec *p_spec(peer *p) { return (&p->spec); } | |
752 | ||
410c8acf | 753 | /* --- @p_find@ --- * |
754 | * | |
755 | * Arguments: @const char *name@ = name to look up | |
756 | * | |
757 | * Returns: Pointer to the peer block, or null if not found. | |
758 | * | |
759 | * Use: Finds a peer by name. | |
760 | */ | |
761 | ||
762 | peer *p_find(const char *name) | |
763 | { | |
764 | peer *p; | |
765 | for (p = peers; p; p = p->next) { | |
0ba8de86 | 766 | if (strcmp(name, p->spec.name) == 0) |
410c8acf | 767 | return (p); |
768 | } | |
e04c2d50 | 769 | return (0); |
410c8acf | 770 | } |
771 | ||
772 | /* --- @p_destroy@ --- * | |
773 | * | |
774 | * Arguments: @peer *p@ = pointer to a peer | |
775 | * | |
776 | * Returns: --- | |
777 | * | |
778 | * Use: Destroys a peer. | |
779 | */ | |
780 | ||
781 | void p_destroy(peer *p) | |
782 | { | |
0ba8de86 | 783 | ping *pg, *ppg; |
784 | ||
785 | T( trace(T_PEER, "peer: destroying peer `%s'", p->spec.name); ) | |
f43df819 | 786 | a_notify("KILL", "%s", p->spec.name, A_END); |
5bb41301 | 787 | ksl_free(&p->ks); |
410c8acf | 788 | kx_free(&p->kx); |
64cf2223 MW |
789 | if (p->ifname) |
790 | xfree(p->ifname); | |
42da2a58 | 791 | p->t->ops->destroy(p->t); |
0ba8de86 | 792 | if (p->spec.t_ka) |
793 | sel_rmtimer(&p->tka); | |
0ba8de86 | 794 | for (pg = p->pings; pg; pg = ppg) { |
795 | ppg = pg->next; | |
796 | p_pingdone(pg, PING_PEERDIED); | |
797 | } | |
410c8acf | 798 | if (p->next) |
799 | p->next->prev = p->prev; | |
800 | if (p->prev) | |
801 | p->prev->next = p->next; | |
802 | else | |
803 | peers = p->next; | |
804 | DESTROY(p); | |
805 | } | |
806 | ||
807 | /* --- @p_first@, @p_next@ --- * | |
808 | * | |
809 | * Arguments: @peer *p@ = a peer block | |
810 | * | |
811 | * Returns: @peer_first@ returns the first peer in some ordering; | |
812 | * @peer_next@ returns the peer following a given one in the | |
813 | * same ordering. Null is returned for the end of the list. | |
814 | */ | |
815 | ||
816 | peer *p_first(void) { return (peers); } | |
817 | peer *p_next(peer *p) { return (p->next); } | |
818 | ||
819 | /*----- That's all, folks -------------------------------------------------*/ |