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