Some random changes.
[oweals/tinc.git] / tnl / tnl.c
1 /*
2     tnl.c -- tunnels
3
4     Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id$
21 */
22
23 #include "system.h"
24
25 #include <gnutls/gnutls.h>
26
27 #include "support/avl.h"
28 #include "support/sockaddr.h"
29 #include "support/xalloc.h"
30 #include "tnl/tnl.h"
31
32 static avl_tree_t *tnls, *listeners;
33
34 bool tnl_init(void) {
35         tnls = avl_tree_new(NULL, (avl_action_t)free);
36         listeners = avl_tree_new(NULL, (avl_action_t)free);
37
38         return true;
39 }
40
41 bool tnl_exit(void) {
42         avl_tree_del(listeners);
43         avl_tree_del(tnls);
44
45         return true;
46 }
47
48 #define tnl_add(t) avl_add(tnls, t)
49 #define tnl_del(t) avl_del(tnls, t)
50 #define tnl_listen_add(l) avl_add(listeners, l)
51 #define tnl_listen_del(l) avl_del(listeners, l)
52
53 static bool tnl_send(tnl_t *tnl, const char *buf, int len) {
54         int result;
55
56         while(len) {
57                 result = gnutls_record_send(tnl->session, buf, len);
58                 if(result <= 0) {
59                         if(result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN)
60                                 continue;
61
62                         if(result)
63                                 logger(LOG_ERR, _("tnl: error while sending: %s"), gnutls_strerror(result));
64                         else
65                                 logger(LOG_INFO, _("tnl: connection closed by peer"));
66
67                         tnl->error(tnl, result);
68                         tnl->close(tnl);
69                         return !result;
70                 }
71
72                 buf += result;
73                 len -= result;
74         }
75
76         return true;
77 }
78
79 static bool tnl_recv(tnl_t *tnl) {
80         int result;
81         tnl_record_t *record = (tnl_record_t *)tnl->buf;
82
83         result = gnutls_record_recv(tnl->session, tnl->buf + tnl->bufread, sizeof tnl->buf - tnl->bufread);
84         if(result <= 0) {
85                 if(result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN)
86                         return true;
87
88                 if(result)
89                         logger(LOG_ERR, _("tnl: error while receiving: %s"), gnutls_strerror(result));
90                 else
91                         logger(LOG_INFO, _("tnl: connection closed by peer"));
92
93                 tnl->error(tnl, result);
94                 tnl->close(tnl);
95                 return !result;
96         }
97
98         tnl->bufread += result;
99
100         while(tnl->bufread >= sizeof *record && tnl->bufread - sizeof *record >= record->len) {
101                 switch(record->type) {
102                         case TNL_RECORD_META:
103                                 tnl->recv_meta(tnl, record->data, record->len);
104                                 break;
105
106                         case TNL_RECORD_PACKET:
107                                 tnl->recv_packet(tnl, record->data, record->len);
108                                 break;
109                                 
110                         default:
111                                 logger(LOG_ERR, _("tnl: error while receiving: %s"), _("unknown record type"));
112                                 tnl->error(tnl, EINVAL);
113                                 tnl->close(tnl);
114                                 return false;
115                 }
116
117                 tnl->bufread -= sizeof *record + record->len;
118                 memmove(tnl->buf, record->data + record->len, tnl->bufread);
119         }
120 }
121
122 static bool tnl_recv_handler(fd_t *fd) {
123         tnl_t *tnl = fd->data;
124         int result;
125
126         result = gnutls_record_recv(tnl->session, tnl->buf + tnl->bufread, sizeof(tnl->buf) - tnl->bufread);
127         if(result < 0) {
128                 if(gnutls_error_is_fatal(result)) {
129                         logger(LOG_DEBUG, _("tnl: reception failed: %s\n"), gnutls_strerror(result));
130                         tnl->error(tnl, result);
131                         tnl->close(tnl);
132                         return false;
133                 }
134
135                 return true;
136         }
137
138         tnl->bufread += result;
139         return tnl_recv(tnl);
140 }
141
142 static bool tnl_authenticate(tnl_t *tnl) {
143         gnutls_x509_crt cert;
144         const gnutls_datum *certs;
145         int ncerts = 0, result;
146         char buf[1024], *name, *p;
147         int len;
148
149         certs = gnutls_certificate_get_peers(tnl->session, &ncerts);
150
151         if (!certs || !ncerts) {
152                 logger(LOG_ERR, _("tnl: no certificates from %s"), tnl->remote.hostname);
153                 return false;
154         }
155
156         len = sizeof buf;
157         gnutls_x509_crt_init(&cert);
158         result = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_DER) ?: gnutls_x509_crt_get_dn(cert, buf, &len);
159
160         if(result) {
161                 logger(LOG_ERR, _("tnl: error importing certificate from %s: %s"), tnl->remote.hostname, gnutls_strerror(errno));
162                 gnutls_x509_crt_deinit(cert);
163                 return false;
164         }
165
166         name = strstr(buf, "CN=");
167         if(!name) {
168                 logger(LOG_ERR, _("tnl: no name in certificate from %s"), tnl->remote.hostname);
169                 gnutls_x509_crt_deinit(cert);
170                 return false;
171         }
172
173         name += 3;
174         for(p = name; *p && *p != ','; p++);
175         *p = '\0';
176
177         if(tnl->remote.id && strcmp(tnl->remote.id, name)) {
178                 logger(LOG_ERR, _("tnl: peer %s is %s instead of %s"), tnl->remote.hostname, name, tnl->remote.id);
179                 return false;
180         }
181
182         replace(tnl->remote.id, name);
183
184         result = gnutls_certificate_verify_peers(tnl->session);
185
186         if(result < 0) {
187                 logger(LOG_ERR, "tnl: error verifying certificate from %s (%s): %s\n", tnl->remote.id, tnl->remote.hostname, gnutls_strerror(result));
188                 return false;
189         }
190
191         if(result) {
192                 logger(LOG_ERR, "tnl: certificate from %s (%s) not good, verification result %x", tnl->remote.id, tnl->remote.hostname, result);
193                 return false;
194         }
195 }
196
197         
198
199 static bool tnl_handshake_handler(fd_t *fd) {
200         char id[1024];
201         tnl_t *tnl = fd->data;
202         int result;
203
204         result = gnutls_handshake(tnl->session);
205         if(result < 0) {
206                 if(gnutls_error_is_fatal(result)) {
207                         logger(LOG_ERR, "tnl: handshake error: %s\n", gnutls_strerror(result));
208                         tnl->close(tnl);
209                         return false;
210                 }
211
212                 /* check other stuff? */
213                 return true;
214         }
215         
216         logger(LOG_DEBUG, _("tnl: handshake finished"));
217
218         if(!tnl_authenticate(tnl))
219                 return false;
220
221         tnl->status == TNL_STATUS_UP;
222         tnl->fd.read = tnl_recv_handler;
223         tnl->accept(tnl);
224         return true;
225 }
226
227 static bool tnl_send_meta(tnl_t *tnl, const char *buf, int len) {
228         tnl_record_t record = {
229                 .type = TNL_RECORD_META,
230                 .len = len,
231         };
232
233         return tnl_send(tnl, (char *)&record, sizeof(record)) && tnl_send(tnl, buf, len);
234 }
235
236 static bool tnl_send_packet(tnl_t *tnl, const char *buf, int len) {
237         tnl_record_t record = {
238                 .type = TNL_RECORD_PACKET,
239                 .len = len,
240         };
241
242         return tnl_send(tnl, (char *)&record, sizeof(record)) && tnl_send(tnl, buf, len);
243 }
244
245 static bool tnl_close(tnl_t *tnl) {
246         if(tnl->session) {
247                 gnutls_bye(tnl->session, GNUTLS_SHUT_RDWR);
248                 gnutls_deinit(tnl->session);
249         }
250                 
251         fd_del(&tnl->fd);
252         close(tnl->fd.fd);
253         
254         tnl_del(tnl);
255
256         return true;
257 }
258
259 static bool tnl_accept_error(tnl_t *tnl, int errnum) {
260         logger(LOG_ERR, _("tnl: error %d on accepted tunnel"));
261         return true;
262 }
263
264 static bool tnl_accept_handler(fd_t *fd) {
265         tnl_listen_t *listener = fd->data;
266         tnl_t *tnl;
267         struct sockaddr_storage ss;
268         socklen_t len = sizeof ss;
269         int sock;       
270         
271         sock = accept(fd->fd, sa(&ss), &len);
272
273         if(sock == -1) {
274                 logger(LOG_ERR, _("tnl: could not accept incoming connection: %s"), strerror(errno));
275                 return false;
276         }
277
278         logger(LOG_DEBUG, _("tnl: accepted incoming connection"));
279
280         sa_unmap(&ss);
281
282         clear(new(tnl));
283         tnl->local = listener->local;
284         tnl->remote.address = ss;
285         len = sizeof tnl->local.address;
286         getsockname(sock, sa(&tnl->local.address), &len);
287         sa_unmap(&tnl->local.address);
288         tnl->type = listener->type;
289         tnl->protocol = listener->protocol;
290         tnl->status = TNL_STATUS_CONNECTING;
291         tnl->error = tnl_accept_error;
292         tnl->close = tnl_close;
293
294         tnl->fd.fd = sock;
295         tnl->fd.read = tnl_handshake_handler;
296         tnl->fd.data = tnl;
297
298         fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
299
300         tnl_add(tnl);
301
302         gnutls_init(&tnl->session, GNUTLS_SERVER);
303         //gnutls_handshake_set_private_extensions(tnl->session, 1);
304         gnutls_set_default_priority(tnl->session);
305         gnutls_credentials_set(tnl->session, GNUTLS_CRD_CERTIFICATE, tnl->local.cred);
306         gnutls_certificate_server_set_request(tnl->session, GNUTLS_CERT_REQUEST);
307         gnutls_transport_set_ptr(tnl->session, (gnutls_transport_ptr)sock);
308         gnutls_handshake(tnl->session);
309
310         tnl->accept = listener->accept;
311         
312         fd_add(&tnl->fd);
313         
314         return true;
315 }       
316
317 static bool tnl_connect_handler(fd_t *fd) {
318         tnl_t *tnl = fd->data;
319         int result;
320         socklen_t len;
321
322         len = sizeof result;
323         getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &result, &len);
324         if(result) {
325                 logger(LOG_ERR, "tnl: error while connecting: %s", strerror(result));
326                 tnl->error(tnl, result);
327                 tnl->close(tnl);
328                 return false;
329         }
330         
331         fcntl(tnl->fd.fd, F_SETFL, fcntl(tnl->fd.fd, F_GETFL) | O_NONBLOCK);
332
333         tnl->status = TNL_STATUS_HANDSHAKE;
334         gnutls_init(&tnl->session, GNUTLS_CLIENT);
335         //gnutls_handshake_set_private_extensions(tnl->session, 1);
336         gnutls_set_default_priority(tnl->session);
337         gnutls_credentials_set(tnl->session, GNUTLS_CRD_CERTIFICATE, tnl->local.cred);
338         gnutls_certificate_server_set_request(tnl->session, GNUTLS_CERT_REQUEST);
339         gnutls_transport_set_ptr(tnl->session, (gnutls_transport_ptr)fd->fd);
340         gnutls_handshake(tnl->session);
341
342         tnl->fd.write = NULL;
343         tnl->fd.read = tnl_handshake_handler;
344         fd_mod(&tnl->fd);
345
346         logger(LOG_DEBUG, _("tnl: connected"));
347         
348         return true;
349 }
350
351 bool tnl_connect(tnl_t *tnl) {
352         int sock;
353
354         sock = socket(sa_family(&tnl->remote.address), tnl->type, tnl->protocol);
355
356         if(sock == -1) {
357                 logger(LOG_ERR, _("tnl: could not create socket: %s"), strerror(errno));
358                 return false;
359         }
360         
361 #if 0
362         if(sa_nonzero(&tnl->local.address) && bind(sock, sa(&tnl->local.address), sa_len(&tnl->local.address)) == -1) {
363                 logger(LOG_ERR, _("tnl: could not bind socket: %s"), strerror(errno));
364                 close(sock);
365                 return false;
366         }
367 #endif
368
369         if(connect(sock, sa(&tnl->remote.address), sa_len(&tnl->remote.address)) == -1) {
370                 logger(LOG_ERR, _("tnl: could not connect: %s"), strerror(errno));
371                 close(sock);
372                 return false;
373         }
374
375         tnl->status = TNL_STATUS_CONNECTING;
376
377         tnl->fd.fd = sock;
378         tnl->fd.write = tnl_connect_handler;
379         tnl->fd.data = tnl;
380
381         tnl->send_packet = tnl_send_packet;
382         tnl->send_meta = tnl_send_meta;
383         tnl->close = tnl_close;
384         
385         tnl_add(tnl);
386
387         fd_add(&tnl->fd);
388
389         return true;
390 }
391
392 static bool tnl_listen_close(tnl_listen_t *listener) {
393         fd_del(&listener->fd);
394         close(listener->fd.fd);
395         tnl_listen_del(listener);
396         return true;
397 }
398
399 bool tnl_listen(tnl_listen_t *listener) {
400         int sock;
401
402         sock = socket(sa_family(&listener->local.address), listener->type, listener->protocol);
403
404         if(sock == -1) {
405                 logger(LOG_ERR, _("tnl: could not create listener socket: %s"), strerror(errno));
406                 return false;
407         }
408         
409         if(bind(sock, sa(&listener->local.address), sa_len(&listener->local.address)) == -1) {
410                 logger(LOG_ERR, _("tnl: could not bind listener socket: %s"), strerror(errno));
411                 return false;
412         }
413         
414         if(listen(sock, 10) == -1) {
415                 logger(LOG_ERR, _("tnl: could not listen on listener socket: %s"), strerror(errno));
416                 return false;
417         }
418
419         listener->fd.fd = sock;
420         listener->fd.read = tnl_accept_handler;
421         listener->fd.data = listener;
422         listener->close = tnl_listen_close;
423
424         tnl_listen_add(listener);
425         fd_add(&listener->fd);
426
427         return true;
428 }