chiark / gitweb /
Support expiry of other peers' public keys.
[tripe] / peer.c
1 /* -*-c-*-
2  *
3  * $Id: peer.c,v 1.6 2001/06/19 22:07:59 mdw Exp $
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
29 /*----- Revision history --------------------------------------------------* 
30  *
31  * $Log: peer.c,v $
32  * Revision 1.6  2001/06/19 22:07:59  mdw
33  * Use magic number for packet size.
34  *
35  * Revision 1.5  2001/03/03 11:15:19  mdw
36  * Set the socket send and receive buffers to maximum.  At least this way,
37  * we won't drop large packets on the floor.  If the administrator wants to
38  * prevent fragmentation of TrIPE messages, he can lower the MTU on the
39  * tunnel interface.  Getting path-MTU stuff out of the kernel is too much
40  * system-specific hard work for this program.
41  *
42  * Revision 1.4  2001/02/16 21:40:24  mdw
43  * Change key exchange message interface.  Maintain statistics.
44  *
45  * Revision 1.3  2001/02/04 17:10:58  mdw
46  * Make file descriptors be nonblocking and close-on-exec.
47  *
48  * Revision 1.2  2001/02/03 22:40:29  mdw
49  * Put timer information into the entropy pool when packets are received
50  * and on similar events.  Reseed the generator on the interval timer.
51  *
52  * Revision 1.1  2001/02/03 20:26:37  mdw
53  * Initial checkin.
54  *
55  */
56
57 /*----- Header files ------------------------------------------------------*/
58
59 #include "tripe.h"
60
61 /*----- Static variables --------------------------------------------------*/
62
63 static peer *peers = 0;
64 static sel_file sock;
65
66 /*----- Main code ---------------------------------------------------------*/
67
68 /* --- @p_read@ --- *
69  *
70  * Arguments:   @int fd@ = file descriptor to read from
71  *              @unsigned mode@ = what happened
72  *              @void *v@ = an uninteresting pointer
73  *
74  * Returns:     ---
75  *
76  * Use:         Reads a packet from somewhere.
77  */
78
79 static void p_read(int fd, unsigned mode, void *v)
80 {
81   peer *p;
82   addr a;
83   size_t sz;
84   ssize_t n;
85   int ch;
86   buf b, bb;
87
88   /* --- Read the data --- */
89
90   TIMER;
91   sz = sizeof(addr);
92   n = recvfrom(fd, buf_i, sizeof(buf_i), 0, &a.sa, &sz);
93   if (n < 0) {
94     a_warn("error reading socket: %s", strerror(errno));
95     return;
96   }
97
98   /* --- Find the appropriate peer --- */
99
100   assert(a.sa.sa_family == AF_INET);
101   for (p = peers; p; p = p->next) {
102     if (p->peer.sin.sin_addr.s_addr == a.sin.sin_addr.s_addr &&
103         p->peer.sin.sin_port == a.sin.sin_port)
104       goto found;
105   }
106   a_warn("packet from unexpected peer: %s:%u",
107        inet_ntoa(a.sin.sin_addr), (unsigned)ntohs(a.sin.sin_port));
108   return;
109
110 found:
111   T( trace(T_PEER, "peer: packet received from `%s'", p->name);
112      trace_block(T_PACKET, "peer: packet contents", buf_i, n); )
113
114   /* --- Pick the packet apart --- */
115
116   p->st.t_last = time(0);
117   p->st.n_in++;
118   p->st.sz_in += n;
119   buf_init(&b, buf_i, n);
120   if ((ch = buf_getbyte(&b)) < 0) {
121     a_warn("bad packet from `%s': no type byte", p->name);
122     return;
123   }
124   switch (ch & MSG_CATMASK) {
125     case MSG_PACKET:
126       if (ch & MSG_TYPEMASK) {
127         a_warn("unknown packet type from `%s'", p->name);
128         p->st.n_reject++;
129         return;
130       }
131       buf_init(&bb, buf_o, sizeof(buf_o));
132       if (ksl_decrypt(&p->ks, &b, &bb)) {
133         p->st.n_reject++;
134         a_warn("couldn't decrypt inbound packet from `%s'", p->name);
135         return;
136       }
137       if (BOK(&bb)) {
138         p->st.n_ipin++;
139         p->st.sz_ipin += BSZ(&b);
140         tun_inject(&p->t, &bb);
141       } else {
142         p->st.n_reject++;
143         a_warn("packet build failed");
144       }
145       break;
146     case MSG_KEYEXCH:
147       kx_message(&p->kx, ch & MSG_TYPEMASK, &b);
148       break;
149     default:
150       p->st.n_reject++;
151       a_warn("bad packet from `%s': unknown packet type", p->name);
152       break;
153   }
154 }
155
156 /* --- @p_txstart@ --- *
157  *
158  * Arguments:   @peer *p@ = pointer to peer block
159  *              @unsigned msg@ = message type code
160  *
161  * Returns:     A pointer to a buffer to write to.
162  *
163  * Use:         Starts sending to a peer.  Only one send can happen at a
164  *              time.
165  */
166
167 buf *p_txstart(peer *p, unsigned msg)
168 {
169   buf_init(&p->b, buf_o, sizeof(buf_o));
170   buf_putbyte(&p->b, msg);
171   return (&p->b);
172 }
173
174 /* --- @p_txend@ --- *
175  *
176  * Arguments:   @peer *p@ = pointer to peer block
177  *
178  * Returns:     ---
179  *
180  * Use:         Sends a packet to the peer.
181  */
182
183 void p_txend(peer *p)
184 {
185   if (!BOK(&p->b)) {
186     a_warn("packet build failed");
187     return;
188   }
189   IF_TRACING(T_PEER, trace_block(T_PACKET, "peer: sending packet",
190                                  BBASE(&p->b), BLEN(&p->b)); )
191   if (sendto(sock.fd, BBASE(&p->b), BLEN(&p->b),
192              0, &p->peer.sa, p->sasz) < 0)
193     a_warn("packet send to `%s' failed: %s", p->name, strerror(errno));
194   else {
195     p->st.n_out++;
196     p->st.sz_out += BLEN(&p->b);
197   }
198 }
199
200 /* --- @p_tun@ --- *
201  *
202  * Arguments:   @peer *p@ = pointer to peer block
203  *              @buf *b@ = buffer containing incoming packet
204  *
205  * Returns:     ---
206  *
207  * Use:         Handles a packet which needs to be sent to a peer.
208  */
209
210 void p_tun(peer *p, buf *b)
211 {
212   buf *bb = p_txstart(p, MSG_PACKET);
213   TIMER;
214   if (ksl_encrypt(&p->ks, b, bb))
215     kx_start(&p->kx);
216   if (BOK(bb) && BLEN(bb)) {
217     p->st.n_ipout++;
218     p->st.sz_ipout += BLEN(bb);
219     p_txend(p);
220   }
221 }
222
223 /* --- @p_interval@ --- *
224  *
225  * Arguments:   ---
226  *
227  * Returns:     ---
228  *
229  * Use:         Called periodically to do tidying.
230  */
231
232 void p_interval(void)
233 {
234   peer *p, *pp;
235   int reload;
236
237   reload = km_interval();
238   for (p = peers; p; p = pp) {
239     pp = p->next;
240     if (reload)
241       kx_newkeys(&p->kx);
242     ksl_prune(&p->ks);
243   }
244 }
245
246 /* --- @p_stats@ --- *
247  *
248  * Arguments:   @peer *p@ = pointer to a peer block
249  *
250  * Returns:     A pointer to the peer's statistics.
251  */
252
253 stats *p_stats(peer *p) { return (&p->st); }
254
255 /* --- @p_ifname@ --- *
256  *
257  * Arguments:   @peer *p@ = pointer to a peer block
258  *
259  * Returns:     A pointer to the peer's interface name.
260  */
261
262 const char *p_ifname(peer *p) { return (tun_ifname(&p->t)); }
263
264 /* --- @p_addr@ --- *
265  *
266  * Arguments:   @peer *p@ = pointer to a peer block
267  *
268  * Returns:     A pointer to the peer's address.
269  */
270
271 const addr *p_addr(peer *p) { return (&p->peer); }
272
273 /* --- @p_init@ --- *
274  *
275  * Arguments:   @unsigned port@ = port number to listen to
276  *
277  * Returns:     ---
278  *
279  * Use:         Initializes the peer system; creates the socket.
280  */
281
282 void p_init(unsigned port)
283 {
284   int fd;
285   struct sockaddr_in sin;
286   int len = PKBUFSZ;
287
288   /* --- Note on socket buffer sizes --- *
289    *
290    * For some bizarre reason, Linux 2.2 (at least) doubles the socket buffer
291    * sizes I pass to @setsockopt@.  I'm not putting special-case code here
292    * for Linux: BSD (at least TCPv2) does what I tell it rather than second-
293    * guessing me.
294    */
295
296   if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
297     die(EXIT_FAILURE, "socket creation failed: %s", strerror(errno));
298   BURN(sin);
299   sin.sin_family = AF_INET;
300   sin.sin_addr.s_addr = INADDR_ANY;
301   sin.sin_port = htons(port);
302   if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)))
303     die(EXIT_FAILURE, "bind failed: %s", strerror(errno));
304   if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) ||
305       setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &len, sizeof(len))) {
306     die(EXIT_FAILURE, "failed to set socket buffer sizes: %s",
307         strerror(errno));
308   }
309   fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
310   sel_initfile(&sel, &sock, fd, SEL_READ, p_read, 0);
311   sel_addfile(&sock);
312   T( trace(T_PEER, "peer: created socket"); )
313 }
314
315 /* --- @p_port@ --- *
316  *
317  * Arguments:   ---
318  *
319  * Returns:     Port number used for socket.
320  */
321
322 unsigned p_port(void)
323 {
324   addr a;
325   size_t sz = sizeof(addr);
326
327   if (getsockname(sock.fd, &a.sa, &sz))
328     die(EXIT_FAILURE, "couldn't read port number: %s", strerror(errno));
329   assert(a.sa.sa_family == AF_INET);
330   return (ntohs(a.sin.sin_port));
331 }
332
333 /* --- @p_create@ --- *
334  *
335  * Arguments:   @const char *name@ = name for this peer
336  *              @struct sockaddr *sa@ = socket address of peer
337  *              @size_t sz@ = size of socket address
338  *
339  * Returns:     Pointer to the peer block, or null if it failed.
340  *
341  * Use:         Creates a new named peer block.  No peer is actually attached
342  *              by this point.
343  */
344
345 peer *p_create(const char *name, struct sockaddr *sa, size_t sz)
346 {
347   peer *p = CREATE(peer);
348   T( trace(T_PEER, "peer: creating new peer `%s'", name); )
349   p->name = xstrdup(name);
350   p->ks = 0;
351   p->prev = 0;
352   memcpy(&p->peer.sa, sa, sz);
353   p->sasz = sz;
354   memset(&p->st, 0, sizeof(stats));
355   p->st.t_start = time(0);
356   if (kx_init(&p->kx, p, &p->ks))
357     goto tidy_0;
358   if (tun_create(&p->t, p))
359     goto tidy_1;
360   p->next = peers;
361   if (peers)
362     peers->prev = p;
363   peers = p;
364   return (p);
365
366 tidy_1:
367   kx_free(&p->kx);
368 tidy_0:
369   xfree(p->name);
370   DESTROY(p);
371   return (0);
372 }
373
374 /* --- @p_name@ --- *
375  *
376  * Arguments:   @peer *p@ = pointer to a peer block
377  *
378  * Returns:     A pointer to the peer's name.
379  */
380
381 const char *p_name(peer *p) { return (p->name); }
382
383 /* --- @p_find@ --- *
384  *
385  * Arguments:   @const char *name@ = name to look up
386  *
387  * Returns:     Pointer to the peer block, or null if not found.
388  *
389  * Use:         Finds a peer by name.
390  */
391
392 peer *p_find(const char *name)
393 {
394   peer *p;
395   for (p = peers; p; p = p->next) {
396     if (strcmp(name, p->name) == 0)
397       return (p);
398   }
399   return (0);  
400 }
401
402 /* --- @p_destroy@ --- *
403  *
404  * Arguments:   @peer *p@ = pointer to a peer
405  *
406  * Returns:     ---
407  *
408  * Use:         Destroys a peer.
409  */
410
411 void p_destroy(peer *p)
412 {
413   T( trace(T_PEER, "peer: destroying peer `%s'", p->name); )
414   ksl_free(&p->ks);
415   kx_free(&p->kx);
416   tun_destroy(&p->t);
417   xfree(p->name);
418   if (p->next)
419     p->next->prev = p->prev;
420   if (p->prev)
421     p->prev->next = p->next;
422   else
423     peers = p->next;
424   DESTROY(p);
425 }
426
427 /* --- @p_first@, @p_next@ --- *
428  *
429  * Arguments:   @peer *p@ = a peer block
430  *
431  * Returns:     @peer_first@ returns the first peer in some ordering;
432  *              @peer_next@ returns the peer following a given one in the
433  *              same ordering.  Null is returned for the end of the list.
434  */
435
436 peer *p_first(void) { return (peers); }
437 peer *p_next(peer *p) { return (p->next); }
438
439 /*----- That's all, folks -------------------------------------------------*/