chiark / gitweb /
Fix segfault on failure to add peer specified by IP address.
[tripe] / peer.c
CommitLineData
410c8acf 1/* -*-c-*-
2 *
3cdc3f3a 3 * $Id$
410c8acf 4 *
5 * Communication with the peer
6 *
7 * (c) 2001 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Trivial IP Encryption (TrIPE).
13 *
14 * TrIPE is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * TrIPE is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with TrIPE; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
410c8acf 29/*----- Header files ------------------------------------------------------*/
30
31#include "tripe.h"
32
33/*----- Static variables --------------------------------------------------*/
34
35static peer *peers = 0;
36static sel_file sock;
37
42da2a58 38/*----- Tunnel table ------------------------------------------------------*/
39
40const 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
56/* --- @p_read@ --- *
57 *
58 * Arguments: @int fd@ = file descriptor to read from
59 * @unsigned mode@ = what happened
60 * @void *v@ = an uninteresting pointer
61 *
62 * Returns: ---
63 *
64 * Use: Reads a packet from somewhere.
65 */
66
67static void p_read(int fd, unsigned mode, void *v)
68{
69 peer *p;
70 addr a;
71 size_t sz;
72 ssize_t n;
73 int ch;
74 buf b, bb;
75
76 /* --- Read the data --- */
77
8d0c7a83 78 TIMER;
410c8acf 79 sz = sizeof(addr);
80 n = recvfrom(fd, buf_i, sizeof(buf_i), 0, &a.sa, &sz);
81 if (n < 0) {
3cdc3f3a 82 a_warn("PEER - socket-read-error -- %s", strerror(errno));
410c8acf 83 return;
84 }
85
86 /* --- Find the appropriate peer --- */
87
88 assert(a.sa.sa_family == AF_INET);
410c8acf 89 for (p = peers; p; p = p->next) {
410c8acf 90 if (p->peer.sin.sin_addr.s_addr == a.sin.sin_addr.s_addr &&
91 p->peer.sin.sin_port == a.sin.sin_port)
92 goto found;
93 }
3cdc3f3a 94 a_warn("PEER - unexpected-source INET %s %u",
95 inet_ntoa(a.sin.sin_addr), (unsigned)ntohs(a.sin.sin_port));
410c8acf 96 return;
97
98found:
b9066fbb 99 IF_TRACING(T_PEER, {
100 trace(T_PEER, "peer: packet received from `%s'", p->name);
101 trace_block(T_PACKET, "peer: packet contents", buf_i, n);
102 })
410c8acf 103
104 /* --- Pick the packet apart --- */
105
5bb41301 106 p->st.t_last = time(0);
107 p->st.n_in++;
108 p->st.sz_in += n;
410c8acf 109 buf_init(&b, buf_i, n);
110 if ((ch = buf_getbyte(&b)) < 0) {
3cdc3f3a 111 a_warn("PEER %s bad-packet no-type", p->name);
410c8acf 112 return;
113 }
5bb41301 114 switch (ch & MSG_CATMASK) {
410c8acf 115 case MSG_PACKET:
5bb41301 116 if (ch & MSG_TYPEMASK) {
3cdc3f3a 117 a_warn("PEER %s bad-packet unknown-type 0x%02x", p->name, ch);
5bb41301 118 p->st.n_reject++;
119 return;
120 }
410c8acf 121 buf_init(&bb, buf_o, sizeof(buf_o));
7ed14135 122 if (ksl_decrypt(&p->ks, MSG_PACKET, &b, &bb)) {
5bb41301 123 p->st.n_reject++;
3cdc3f3a 124 a_warn("PEER %s decrypt-failed", p->name);
410c8acf 125 return;
126 }
5bb41301 127 if (BOK(&bb)) {
128 p->st.n_ipin++;
129 p->st.sz_ipin += BSZ(&b);
42da2a58 130 p->t->ops->inject(p->t, &bb);
5bb41301 131 } else {
132 p->st.n_reject++;
3cdc3f3a 133 a_warn("PEER %s packet-build-failed", p->name);
5bb41301 134 }
410c8acf 135 break;
5bb41301 136 case MSG_KEYEXCH:
137 kx_message(&p->kx, ch & MSG_TYPEMASK, &b);
410c8acf 138 break;
139 default:
5bb41301 140 p->st.n_reject++;
3cdc3f3a 141 a_warn("PEER %s bad-packet unknown-category 0x%02x", p->name, ch);
410c8acf 142 break;
143 }
144}
145
146/* --- @p_txstart@ --- *
147 *
148 * Arguments: @peer *p@ = pointer to peer block
149 * @unsigned msg@ = message type code
150 *
151 * Returns: A pointer to a buffer to write to.
152 *
153 * Use: Starts sending to a peer. Only one send can happen at a
154 * time.
155 */
156
157buf *p_txstart(peer *p, unsigned msg)
158{
159 buf_init(&p->b, buf_o, sizeof(buf_o));
160 buf_putbyte(&p->b, msg);
161 return (&p->b);
162}
163
164/* --- @p_txend@ --- *
165 *
166 * Arguments: @peer *p@ = pointer to peer block
167 *
168 * Returns: ---
169 *
170 * Use: Sends a packet to the peer.
171 */
172
173void p_txend(peer *p)
174{
175 if (!BOK(&p->b)) {
3cdc3f3a 176 a_warn("PEER %s packet-build-failed", p->name);
410c8acf 177 return;
178 }
179 IF_TRACING(T_PEER, trace_block(T_PACKET, "peer: sending packet",
180 BBASE(&p->b), BLEN(&p->b)); )
181 if (sendto(sock.fd, BBASE(&p->b), BLEN(&p->b),
182 0, &p->peer.sa, p->sasz) < 0)
3cdc3f3a 183 a_warn("PEER %s socket-write-error -- %s", p->name, strerror(errno));
5bb41301 184 else {
185 p->st.n_out++;
186 p->st.sz_out += BLEN(&p->b);
187 }
410c8acf 188}
189
190/* --- @p_tun@ --- *
191 *
192 * Arguments: @peer *p@ = pointer to peer block
193 * @buf *b@ = buffer containing incoming packet
194 *
195 * Returns: ---
196 *
197 * Use: Handles a packet which needs to be sent to a peer.
198 */
199
200void p_tun(peer *p, buf *b)
201{
202 buf *bb = p_txstart(p, MSG_PACKET);
7b052fe6 203
8d0c7a83 204 TIMER;
7ed14135 205 if (ksl_encrypt(&p->ks, MSG_PACKET, b, bb))
410c8acf 206 kx_start(&p->kx);
5bb41301 207 if (BOK(bb) && BLEN(bb)) {
208 p->st.n_ipout++;
209 p->st.sz_ipout += BLEN(bb);
410c8acf 210 p_txend(p);
5bb41301 211 }
410c8acf 212}
213
214/* --- @p_interval@ --- *
215 *
216 * Arguments: ---
217 *
218 * Returns: ---
219 *
220 * Use: Called periodically to do tidying.
221 */
222
223void p_interval(void)
224{
225 peer *p, *pp;
226 int reload;
227
228 reload = km_interval();
229 for (p = peers; p; p = pp) {
230 pp = p->next;
231 if (reload)
232 kx_newkeys(&p->kx);
5bb41301 233 ksl_prune(&p->ks);
410c8acf 234 }
235}
236
5bb41301 237/* --- @p_stats@ --- *
238 *
239 * Arguments: @peer *p@ = pointer to a peer block
240 *
241 * Returns: A pointer to the peer's statistics.
242 */
243
244stats *p_stats(peer *p) { return (&p->st); }
245
410c8acf 246/* --- @p_ifname@ --- *
247 *
248 * Arguments: @peer *p@ = pointer to a peer block
249 *
250 * Returns: A pointer to the peer's interface name.
251 */
252
42da2a58 253const char *p_ifname(peer *p) { return (p->t->ops->ifname(p->t)); }
410c8acf 254
255/* --- @p_addr@ --- *
256 *
257 * Arguments: @peer *p@ = pointer to a peer block
258 *
259 * Returns: A pointer to the peer's address.
260 */
261
262const addr *p_addr(peer *p) { return (&p->peer); }
263
264/* --- @p_init@ --- *
265 *
767b36e2 266 * Arguments: @struct in_addr addr@ = address to bind to
267 * @unsigned port@ = port number to listen to
410c8acf 268 *
269 * Returns: ---
270 *
271 * Use: Initializes the peer system; creates the socket.
272 */
273
767b36e2 274void p_init(struct in_addr addr, unsigned port)
410c8acf 275{
276 int fd;
277 struct sockaddr_in sin;
df9dfccf 278 int len = PKBUFSZ;
0a9920e2 279
280 /* --- Note on socket buffer sizes --- *
281 *
282 * For some bizarre reason, Linux 2.2 (at least) doubles the socket buffer
283 * sizes I pass to @setsockopt@. I'm not putting special-case code here
284 * for Linux: BSD (at least TCPv2) does what I tell it rather than second-
285 * guessing me.
286 */
410c8acf 287
288 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
289 die(EXIT_FAILURE, "socket creation failed: %s", strerror(errno));
290 BURN(sin);
291 sin.sin_family = AF_INET;
767b36e2 292 sin.sin_addr = addr;
410c8acf 293 sin.sin_port = htons(port);
294 if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)))
295 die(EXIT_FAILURE, "bind failed: %s", strerror(errno));
0a9920e2 296 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) ||
297 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &len, sizeof(len))) {
298 die(EXIT_FAILURE, "failed to set socket buffer sizes: %s",
299 strerror(errno));
300 }
650a6624 301 fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
410c8acf 302 sel_initfile(&sel, &sock, fd, SEL_READ, p_read, 0);
303 sel_addfile(&sock);
304 T( trace(T_PEER, "peer: created socket"); )
305}
306
307/* --- @p_port@ --- *
308 *
309 * Arguments: ---
310 *
311 * Returns: Port number used for socket.
312 */
313
314unsigned p_port(void)
315{
316 addr a;
317 size_t sz = sizeof(addr);
318
319 if (getsockname(sock.fd, &a.sa, &sz))
320 die(EXIT_FAILURE, "couldn't read port number: %s", strerror(errno));
321 assert(a.sa.sa_family == AF_INET);
322 return (ntohs(a.sin.sin_port));
323}
324
325/* --- @p_create@ --- *
326 *
327 * Arguments: @const char *name@ = name for this peer
42da2a58 328 * @const tunnel_ops *tops@ = tunnel to use
410c8acf 329 * @struct sockaddr *sa@ = socket address of peer
330 * @size_t sz@ = size of socket address
331 *
332 * Returns: Pointer to the peer block, or null if it failed.
333 *
334 * Use: Creates a new named peer block. No peer is actually attached
335 * by this point.
336 */
337
42da2a58 338peer *p_create(const char *name, const tunnel_ops *tops,
339 struct sockaddr *sa, size_t sz)
410c8acf 340{
341 peer *p = CREATE(peer);
42da2a58 342
410c8acf 343 T( trace(T_PEER, "peer: creating new peer `%s'", name); )
344 p->name = xstrdup(name);
345 p->ks = 0;
346 p->prev = 0;
347 memcpy(&p->peer.sa, sa, sz);
348 p->sasz = sz;
5bb41301 349 memset(&p->st, 0, sizeof(stats));
350 p->st.t_start = time(0);
410c8acf 351 if (kx_init(&p->kx, p, &p->ks))
352 goto tidy_0;
42da2a58 353 if ((p->t = tops->create(p)) == 0)
410c8acf 354 goto tidy_1;
355 p->next = peers;
356 if (peers)
357 peers->prev = p;
358 peers = p;
3cdc3f3a 359 switch (p->peer.sa.sa_family) {
360 case AF_INET:
42da2a58 361 a_notify("ADD %s %s INET %s %u",
3cdc3f3a 362 name,
42da2a58 363 p->t->ops->ifname(p->t),
3cdc3f3a 364 inet_ntoa(p->peer.sin.sin_addr),
365 (unsigned)ntohs(p->peer.sin.sin_port));
366 break;
367 default:
42da2a58 368 a_notify("ADD %s %s UNKNOWN", name, p->t->ops->ifname(p->t));
3cdc3f3a 369 break;
370 }
11c0039e 371 a_notify("KXSTART %s", name); /* Couldn't tell anyone before */
410c8acf 372 return (p);
373
374tidy_1:
375 kx_free(&p->kx);
376tidy_0:
377 xfree(p->name);
378 DESTROY(p);
379 return (0);
380}
381
382/* --- @p_name@ --- *
383 *
384 * Arguments: @peer *p@ = pointer to a peer block
385 *
386 * Returns: A pointer to the peer's name.
387 */
388
389const char *p_name(peer *p) { return (p->name); }
390
391/* --- @p_find@ --- *
392 *
393 * Arguments: @const char *name@ = name to look up
394 *
395 * Returns: Pointer to the peer block, or null if not found.
396 *
397 * Use: Finds a peer by name.
398 */
399
400peer *p_find(const char *name)
401{
402 peer *p;
403 for (p = peers; p; p = p->next) {
404 if (strcmp(name, p->name) == 0)
405 return (p);
406 }
407 return (0);
408}
409
410/* --- @p_destroy@ --- *
411 *
412 * Arguments: @peer *p@ = pointer to a peer
413 *
414 * Returns: ---
415 *
416 * Use: Destroys a peer.
417 */
418
419void p_destroy(peer *p)
420{
421 T( trace(T_PEER, "peer: destroying peer `%s'", p->name); )
3cdc3f3a 422 a_notify("KILL %s", p->name);
5bb41301 423 ksl_free(&p->ks);
410c8acf 424 kx_free(&p->kx);
42da2a58 425 p->t->ops->destroy(p->t);
410c8acf 426 xfree(p->name);
427 if (p->next)
428 p->next->prev = p->prev;
429 if (p->prev)
430 p->prev->next = p->next;
431 else
432 peers = p->next;
433 DESTROY(p);
434}
435
436/* --- @p_first@, @p_next@ --- *
437 *
438 * Arguments: @peer *p@ = a peer block
439 *
440 * Returns: @peer_first@ returns the first peer in some ordering;
441 * @peer_next@ returns the peer following a given one in the
442 * same ordering. Null is returned for the end of the list.
443 */
444
445peer *p_first(void) { return (peers); }
446peer *p_next(peer *p) { return (p->next); }
447
448/*----- That's all, folks -------------------------------------------------*/