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