Update documents.
[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 #include <gnutls/x509.h>
27
28 #include "logger/logger.h"
29 #include "support/avl.h"
30 #include "support/sockaddr.h"
31 #include "support/xalloc.h"
32 #include "tnl/tnl.h"
33
34 static bool tnl_send(tnl_t *tnl, const void *buf, int len) {
35         int result;
36
37         while(len) {
38                 result = gnutls_record_send(tnl->session, buf, len);
39                 if(result <= 0) {
40                         if(result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN)
41                                 continue;
42
43                         if(result)
44                                 logger(LOG_ERR, _("tnl: error while sending: %s"), gnutls_strerror(result));
45                         else
46                                 logger(LOG_INFO, _("tnl: connection closed by peer"));
47
48                         if(tnl->error)
49                                 tnl->error(tnl, result);
50                         tnl->close(tnl);
51                         return !result;
52                 }
53
54                 buf += result;
55                 len -= result;
56         }
57
58         return true;
59 }
60
61 static bool tnl_recv(tnl_t *tnl) {
62         tnl_record_t *record = (tnl_record_t *)tnl->buf;
63
64 #if 0
65         int result = gnutls_record_recv(tnl->session, tnl->buf + tnl->bufread, sizeof tnl->buf - tnl->bufread);
66         if(result <= 0) {
67                 if(result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN)
68                         return true;
69
70                 if(result)
71                         logger(LOG_ERR, _("tnl: error while receiving: %s"), gnutls_strerror(result));
72                 else
73                         logger(LOG_INFO, _("tnl: connection closed by peer"));
74
75                 if(tnl->error)
76                         tnl->error(tnl, result);
77                 tnl->close(tnl);
78                 return !result;
79         }
80
81         tnl->bufread += result;
82 #endif
83
84         while(tnl->bufread >= sizeof *record && tnl->bufread - sizeof *record >= record->len) {
85                 switch(record->type) {
86                         case TNL_RECORD_META:
87                                 if(tnl->recv_meta)
88                                         tnl->recv_meta(tnl, record->data, record->len);
89                                 break;
90
91                         case TNL_RECORD_PACKET:
92                                 if(tnl->recv_packet)
93                                         tnl->recv_packet(tnl, record->data, record->len);
94                                 break;
95                                 
96                         default:
97                                 logger(LOG_ERR, _("tnl: error while receiving: %s"), _("unknown record type"));
98                                 if(tnl->error)
99                                         tnl->error(tnl, EINVAL);
100                                 tnl->close(tnl);
101                                 return false;
102                 }
103
104                 tnl->bufread -= sizeof *record + record->len;
105                 memmove(tnl->buf, record->data + record->len, tnl->bufread);
106         }
107
108         return true;
109 }
110
111 static bool tnl_recv_handler(fd_t *fd) {
112         if(!fd)
113                 abort();
114
115         tnl_t *tnl = fd->data;
116         int result;
117
118         result = gnutls_record_recv(tnl->session, tnl->buf + tnl->bufread, sizeof(tnl->buf) - tnl->bufread);
119         if(result <= 0) {
120                 if(!result) {
121                         logger(LOG_DEBUG, _("tnl: connection closed by peer %s (%s)"), tnl->remote.id, tnl->remote.hostname);
122                         if(tnl->error)
123                                 tnl->error(tnl, 0);
124                         tnl->close(tnl);
125                         return false;
126                 }       
127                                         
128                 if(gnutls_error_is_fatal(result)) {
129                         logger(LOG_DEBUG, _("tnl: reception failed: %s"), gnutls_strerror(result));
130                         if(tnl->error)
131                                 tnl->error(tnl, result);
132                         tnl->close(tnl);
133                         return false;
134                 }
135
136                 return true;
137         }
138
139         tnl->bufread += result;
140         return tnl_recv(tnl);
141 }
142
143 bool tnl_ep_set_x509_credentials(tnl_ep_t *tnl_ep, const char *privkey, const char *certificate, const char *trust, const char *crl) {
144         int err;
145
146         if(tnl_ep->cred.certificate) {
147                 gnutls_certificate_free_credentials(tnl_ep->cred.certificate);
148                 tnl_ep->cred.certificate = NULL;
149         }
150         
151         if((err = gnutls_certificate_allocate_credentials(&tnl_ep->cred.certificate)) < 0) {
152                 logger(LOG_ERR, _("Failed to allocate certificate credentials: %s"), gnutls_strerror(err));
153                 return false;
154         }
155
156         if((err = gnutls_certificate_set_x509_key_file(tnl_ep->cred.certificate, certificate, privkey, GNUTLS_X509_FMT_PEM)) < 0) {
157                 logger(LOG_ERR, _("Failed to load X.509 key and/or certificate: %s"), gnutls_strerror(err));
158                 return false;
159         }
160
161         tnl_ep->cred.type = GNUTLS_CRD_CERTIFICATE;
162
163         if(trust && (err = gnutls_certificate_set_x509_trust_file(tnl_ep->cred.certificate, trust, GNUTLS_X509_FMT_PEM)) < 0) {
164                 logger(LOG_ERR, _("Failed to set X.509 trust file: %s"), gnutls_strerror(err));
165                 return false;
166         }
167         
168         if(crl && (err = gnutls_certificate_set_x509_crl_file(tnl_ep->cred.certificate, crl, GNUTLS_X509_FMT_PEM)) < 0) {
169                 logger(LOG_ERR, _("Failed to set X.509 CRL file: %s"), gnutls_strerror(err));
170                 return false;
171         }
172
173         //gnutls_certificate_set_verify_flags(tnl_ep->cred.certificate, GNUTLS_VERIFY_DISABLE_CA_SIGN);
174
175         return true;
176 }       
177
178 bool tnl_ep_set_openpgp_credentials(tnl_ep_t *tnl_ep, const char *privkey, const char *pubkey, const char *keyring, const char *trustdb) {
179         int err;
180
181         if(tnl_ep->cred.certificate) {
182                 gnutls_certificate_free_credentials(tnl_ep->cred.certificate);
183                 tnl_ep->cred.certificate = NULL;
184         }
185         
186         if((err = gnutls_certificate_allocate_credentials(&tnl_ep->cred.certificate)) < 0) {
187                 logger(LOG_ERR, _("Failed to allocate certificate credentials: %s"), gnutls_strerror(err));
188                 return false;
189         }
190
191         if((err = gnutls_certificate_set_openpgp_key_file(tnl_ep->cred.certificate, pubkey, privkey)) < 0) {
192                 logger(LOG_ERR, _("Failed to load public and/or private OpenPGP key: %s"), gnutls_strerror(err));
193                 return false;
194         }
195
196         tnl_ep->cred.type = GNUTLS_CRD_CERTIFICATE;
197
198         if(keyring && (err = gnutls_certificate_set_openpgp_keyring_file(tnl_ep->cred.certificate, keyring)) < 0) {
199                 logger(LOG_ERR, _("Failed to set OpenPGP keyring file: %s"), gnutls_strerror(err));
200                 return false;
201         }
202         
203         if(trustdb && (err = gnutls_certificate_set_openpgp_trustdb(tnl_ep->cred.certificate, trustdb)) < 0) {
204                 logger(LOG_ERR, _("Failed to set OpenPGP trustdb file: %s"), gnutls_strerror(err));
205                 return false;
206         }
207
208         //gnutls_certificate_set_verify_flags(tnl_ep->cred.certificate, GNUTLS_VERIFY_DISABLE_CA_SIGN);
209
210         return true;
211 }               
212
213 static bool tnl_authenticate_x509(tnl_t *tnl) {
214         gnutls_x509_crt cert;
215         const gnutls_datum *certs;
216         int ncerts = 0, result;
217         char name[1024];
218         int len;
219
220         certs = gnutls_certificate_get_peers(tnl->session, &ncerts);
221
222         if (!certs || !ncerts) {
223                 logger(LOG_ERR, _("tnl: no certificates from %s"), tnl->remote.hostname);
224                 return false;
225         }
226
227         gnutls_x509_crt_init(&cert);
228         result = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_DER);
229
230         if(result) {
231                 logger(LOG_ERR, _("tnl: error importing certificate from %s: %s"), tnl->remote.hostname, gnutls_strerror(result));
232                 gnutls_x509_crt_deinit(cert);
233                 return false;
234         }
235
236         len = sizeof name;
237         result = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, name, &len);
238         gnutls_x509_crt_deinit(cert);
239         
240         if(result) {
241                 logger(LOG_ERR, _("tnl: could not extract common name from certificate from %s: %s"), tnl->remote.hostname, gnutls_strerror(result));
242                 return false;
243         }
244
245         if(len > sizeof name) {
246                 logger(LOG_ERR, _("tnl: common name from certificate from %s too long"), tnl->remote.hostname);
247                 return false;
248         }
249
250         if(tnl->remote.id && strcmp(tnl->remote.id, name)) {
251                 logger(LOG_ERR, _("tnl: peer %s is %s instead of %s"), tnl->remote.hostname, name, tnl->remote.id);
252                 return false;
253         }
254
255         replace(tnl->remote.id, xstrdup(name));
256
257         result = gnutls_certificate_verify_peers(tnl->session);
258
259         if(result < 0) {
260                 logger(LOG_ERR, "tnl: error verifying certificate from %s (%s): %s", tnl->remote.id, tnl->remote.hostname, gnutls_strerror(result));
261                 return false;
262         }
263
264         if(result) {
265                 logger(LOG_ERR, "tnl: certificate from %s (%s) not good, verification result %x", tnl->remote.id, tnl->remote.hostname, result);
266                 return false;
267         }
268
269         return true;
270 }
271
272 static bool tnl_authenticate(tnl_t *tnl) {
273         switch(tnl->local.cred.type) {
274                 case GNUTLS_CRD_CERTIFICATE:
275                         switch(gnutls_certificate_type_get(tnl->session)) {
276                                 case GNUTLS_CRT_X509:
277                                         return tnl_authenticate_x509(tnl);
278                                 case GNUTLS_CRT_OPENPGP:
279                                         //return tnl_authenticate_openpgp(tnl);
280                                 default:
281                                         logger(LOG_ERR, "tnl: unknown certificate type for session with %s (%s)", tnl->remote.id, tnl->remote.hostname);
282                                         return false;
283                         }
284
285                 case GNUTLS_CRD_ANON:
286                         logger(LOG_ERR, "tnl: anonymous authentication not yet supported");
287                         return false;
288
289                 case GNUTLS_CRD_SRP:
290                         logger(LOG_ERR, "tnl: SRP authentication not yet supported");
291                         return false;
292                                 
293                 default:
294                         logger(LOG_ERR, "tnl: unknown authentication type for session with %s (%s)", tnl->remote.id, tnl->remote.hostname);
295                         return false;
296         }
297 }
298
299 static bool tnl_handshake_handler(fd_t *fd) {
300         //char id[1024];
301         tnl_t *tnl = fd->data;
302         int result;
303
304         result = gnutls_handshake(tnl->session);
305         if(result < 0) {
306                 if(gnutls_error_is_fatal(result)) {
307                         logger(LOG_ERR, "tnl: handshake error: %s", gnutls_strerror(result));
308                         tnl->close(tnl);
309                         return false;
310                 }
311
312                 /* check other stuff? */
313                 return true;
314         }
315         
316         logger(LOG_DEBUG, _("tnl: handshake finished"));
317
318         if(!tnl_authenticate(tnl))
319                 return false;
320
321         tnl->status = TNL_STATUS_UP;
322         tnl->fd.read = tnl_recv_handler;
323         if(tnl->accept)
324                 tnl->accept(tnl);
325
326         return true;
327 }
328
329 static bool tnl_send_meta(tnl_t *tnl, const void *buf, int len) {
330         tnl_record_t record = {
331                 .type = TNL_RECORD_META,
332                 .len = len,
333         };
334
335         return tnl_send(tnl, &record, sizeof record) && tnl_send(tnl, buf, len);
336 }
337
338 static bool tnl_send_packet(tnl_t *tnl, const void *buf, int len) {
339         tnl_record_t record = {
340                 .type = TNL_RECORD_PACKET,
341                 .len = len,
342         };
343
344         return tnl_send(tnl, &record, sizeof record) && tnl_send(tnl, buf, len);
345 }
346
347 static bool tnl_close(tnl_t *tnl) {
348         if(tnl->session) {
349                 gnutls_bye(tnl->session, GNUTLS_SHUT_RDWR);
350                 gnutls_deinit(tnl->session);
351         }
352                 
353         fd_del(&tnl->fd);
354         close(tnl->fd.fd);
355         
356         return true;
357 }
358
359 static bool tnl_accept_handler(fd_t *fd) {
360         tnl_listen_t *listener = fd->data;
361         tnl_t *tnl;
362         struct sockaddr_storage ss;
363         socklen_t len = sizeof ss;
364         int sock;       
365         
366         sock = accept(fd->fd, sa(&ss), &len);
367
368         if(sock == -1) {
369                 logger(LOG_ERR, _("tnl: could not accept incoming connection: %s"), strerror(errno));
370                 return false;
371         }
372
373         sa_unmap(&ss);
374         
375         logger(LOG_DEBUG, _("tnl: accepted incoming connection"));
376
377         clear(new(tnl));
378         tnl->local = listener->local;
379         tnl->remote.address = ss;
380         len = sizeof tnl->local.address;
381         getsockname(sock, sa(&tnl->local.address), &len);
382         sa_unmap(&tnl->local.address);
383         tnl->type = listener->type;
384         tnl->protocol = listener->protocol;
385         tnl->send_packet = tnl_send_packet;
386         tnl->send_meta = tnl_send_meta;
387         tnl->close = tnl_close;
388
389         tnl->fd.fd = sock;
390         tnl->fd.read = tnl_handshake_handler;
391         tnl->fd.data = tnl;
392
393         fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
394
395         tnl->status = TNL_STATUS_HANDSHAKE;
396         gnutls_init(&tnl->session, GNUTLS_SERVER);
397         //gnutls_handshake_set_private_extensions(tnl->session, 1);
398         gnutls_set_default_priority(tnl->session);
399         gnutls_credentials_set(tnl->session, tnl->local.cred.type, tnl->local.cred.certificate);
400         gnutls_certificate_server_set_request(tnl->session, GNUTLS_CERT_REQUEST);
401         gnutls_transport_set_ptr(tnl->session, (gnutls_transport_ptr)sock);
402
403         tnl->accept = listener->accept;
404         
405         fd_add(&tnl->fd);
406
407         tnl_handshake_handler(&tnl->fd);
408         
409         return true;
410 }       
411
412 static bool tnl_connect_handler(fd_t *fd) {
413         tnl_t *tnl = fd->data;
414         int result;
415         socklen_t len;
416
417         len = sizeof result;
418         getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &result, &len);
419         if(result) {
420                 logger(LOG_ERR, "tnl: error while connecting: %s", strerror(result));
421                 if(tnl->error)
422                         tnl->error(tnl, result);
423                 tnl->close(tnl);
424                 return false;
425         }
426         
427         logger(LOG_DEBUG, _("tnl: connected"));
428         
429         fcntl(tnl->fd.fd, F_SETFL, fcntl(tnl->fd.fd, F_GETFL) | O_NONBLOCK);
430
431         tnl->status = TNL_STATUS_HANDSHAKE;
432         gnutls_init(&tnl->session, GNUTLS_CLIENT);
433         //gnutls_handshake_set_private_extensions(tnl->session, 1);
434         gnutls_set_default_priority(tnl->session);
435         gnutls_credentials_set(tnl->session, tnl->local.cred.type, tnl->local.cred.certificate);
436         gnutls_certificate_server_set_request(tnl->session, GNUTLS_CERT_REQUEST);
437         gnutls_transport_set_ptr(tnl->session, (gnutls_transport_ptr)fd->fd);
438
439         tnl->fd.write = NULL;
440         tnl->fd.read = tnl_handshake_handler;
441         fd_mod(&tnl->fd);
442
443         tnl_handshake_handler(&tnl->fd);
444
445         return true;
446 }
447
448 bool tnl_connect(tnl_t *tnl) {
449         int sock;
450
451         sock = socket(sa_family(&tnl->remote.address), tnl->type, tnl->protocol);
452
453         if(sock == -1) {
454                 logger(LOG_ERR, _("tnl: could not create socket: %s"), strerror(errno));
455                 return false;
456         }
457         
458 #if 0
459         if(sa_nonzero(&tnl->local.address) && bind(sock, sa(&tnl->local.address), sa_len(&tnl->local.address)) == -1) {
460                 logger(LOG_ERR, _("tnl: could not bind socket: %s"), strerror(errno));
461                 close(sock);
462                 return false;
463         }
464 #endif
465
466         if(connect(sock, sa(&tnl->remote.address), sa_len(&tnl->remote.address)) == -1) {
467                 logger(LOG_ERR, _("tnl: could not connect: %s"), strerror(errno));
468                 close(sock);
469                 return false;
470         }
471
472         tnl->status = TNL_STATUS_CONNECTING;
473
474         tnl->fd.fd = sock;
475         tnl->fd.write = tnl_connect_handler;
476         tnl->fd.data = tnl;
477
478         tnl->send_packet = tnl_send_packet;
479         tnl->send_meta = tnl_send_meta;
480         tnl->close = tnl_close;
481         
482         fd_add(&tnl->fd);
483
484         return true;
485 }
486
487 static bool tnl_listen_close(tnl_listen_t *listener) {
488         fd_del(&listener->fd);
489         close(listener->fd.fd);
490         return true;
491 }
492
493 bool tnl_listen(tnl_listen_t *listener) {
494         int sock;
495
496         sock = socket(sa_family(&listener->local.address), listener->type, listener->protocol);
497
498         if(sock == -1) {
499                 logger(LOG_ERR, _("tnl: could not create listener socket: %s"), strerror(errno));
500                 return false;
501         }
502         
503         if(bind(sock, sa(&listener->local.address), sa_len(&listener->local.address)) == -1) {
504                 logger(LOG_ERR, _("tnl: could not bind listener socket: %s"), strerror(errno));
505                 return false;
506         }
507         
508         if(listen(sock, 10) == -1) {
509                 logger(LOG_ERR, _("tnl: could not listen on listener socket: %s"), strerror(errno));
510                 return false;
511         }
512
513         listener->fd.fd = sock;
514         listener->fd.read = tnl_accept_handler;
515         listener->fd.data = listener;
516         listener->close = tnl_listen_close;
517
518         fd_add(&listener->fd);
519
520         return true;
521 }