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