ftbfs
[oweals/gnunet.git] / src / nat / nat_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2007-2017 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @author Christian Grothoff
23  * @author Milan Bouchet-Valat
24  *
25  * @file nat/nat_api.c
26  * Service for handling UPnP and NAT-PMP port forwarding
27  * and external IP address retrieval
28  */
29 #include "platform.h"
30 #include "gnunet_nat_service.h"
31 #include "nat.h"
32 #include "nat_stun.h"
33
34
35 /**
36  * Entry in DLL of addresses of this peer.
37  */
38 struct AddrEntry
39 {
40   /**
41    * DLL.
42    */
43   struct AddrEntry *next;
44
45   /**
46    * DLL.
47    */
48   struct AddrEntry *prev;
49
50   /**
51    * Place where the application can store data (on add,
52    * and retrieve on remove).
53    */
54   void *app_ctx;
55
56   /**
57    * Address class of the address.
58    */
59   enum GNUNET_NAT_AddressClass ac;
60
61   /**
62    * Number of bytes that follow.
63    */
64   socklen_t addrlen;
65 };
66
67
68 /**
69  * Handle for active NAT registrations.
70  */
71 struct GNUNET_NAT_Handle
72 {
73   /**
74    * Configuration we use.
75    */
76   const struct GNUNET_CONFIGURATION_Handle *cfg;
77
78   /**
79    * Message queue for communicating with the NAT service.
80    */
81   struct GNUNET_MQ_Handle *mq;
82
83   /**
84    * Our registration message.
85    */
86   struct GNUNET_MessageHeader *reg;
87
88   /**
89    * Head of address DLL.
90    */
91   struct AddrEntry *ae_head;
92
93   /**
94    * Tail of address DLL.
95    */
96   struct AddrEntry *ae_tail;
97
98   /**
99    * Function to call when our addresses change.
100    */
101   GNUNET_NAT_AddressCallback address_callback;
102
103   /**
104    * Function to call when another peer requests connection reversal.
105    */
106   GNUNET_NAT_ReversalCallback reversal_callback;
107
108   /**
109    * Closure for the various callbacks.
110    */
111   void *callback_cls;
112
113   /**
114    * Task scheduled to reconnect to the service.
115    */
116   struct GNUNET_SCHEDULER_Task *reconnect_task;
117
118   /**
119    * How long to wait until we reconnect.
120    */
121   struct GNUNET_TIME_Relative reconnect_delay;
122 };
123
124
125 /**
126  * Task to connect to the NAT service.
127  *
128  * @param cls our `struct GNUNET_NAT_Handle *`
129  */
130 static void
131 do_connect (void *cls);
132
133
134 /**
135  * Task to connect to the NAT service.
136  *
137  * @param nh handle to reconnect
138  */
139 static void
140 reconnect (struct GNUNET_NAT_Handle *nh)
141 {
142   struct AddrEntry *ae;
143
144   if (NULL != nh->mq)
145   {
146     GNUNET_MQ_destroy (nh->mq);
147     nh->mq = NULL;
148   }
149   while (NULL != (ae = nh->ae_head))
150   {
151     GNUNET_CONTAINER_DLL_remove (nh->ae_head, nh->ae_tail, ae);
152     nh->address_callback (nh->callback_cls,
153                           &ae->app_ctx,
154                           GNUNET_NO,
155                           ae->ac,
156                           (const struct sockaddr *) &ae[1],
157                           ae->addrlen);
158     GNUNET_free (ae);
159   }
160   nh->reconnect_delay = GNUNET_TIME_STD_BACKOFF (nh->reconnect_delay);
161   nh->reconnect_task =
162     GNUNET_SCHEDULER_add_delayed (nh->reconnect_delay, &do_connect, nh);
163 }
164
165
166 /**
167  * Check connection reversal request.
168  *
169  * @param cls our `struct GNUNET_NAT_Handle`
170  * @param crm the message
171  * @return #GNUNET_OK if @a crm is well-formed
172  */
173 static int
174 check_connection_reversal_request (
175   void *cls,
176   const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
177 {
178   if (ntohs (crm->header.size) != sizeof(*crm) + sizeof(struct sockaddr_in))
179   {
180     GNUNET_break (0);
181     return GNUNET_SYSERR;
182   }
183   return GNUNET_OK;
184 }
185
186
187 /**
188  * Handle connection reversal request.
189  *
190  * @param cls our `struct GNUNET_NAT_Handle`
191  * @param crm the message
192  */
193 static void
194 handle_connection_reversal_request (
195   void *cls,
196   const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
197 {
198   struct GNUNET_NAT_Handle *nh = cls;
199
200   nh->reversal_callback (nh->callback_cls,
201                          (const struct sockaddr *) &crm[1],
202                          sizeof(struct sockaddr_in));
203 }
204
205
206 /**
207  * Check address change notification.
208  *
209  * @param cls our `struct GNUNET_NAT_Handle`
210  * @param acn the message
211  * @return #GNUNET_OK if @a crm is well-formed
212  */
213 static int
214 check_address_change_notification (
215   void *cls,
216   const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
217 {
218   size_t alen = ntohs (acn->header.size) - sizeof(*acn);
219
220   switch (alen)
221   {
222   case sizeof(struct sockaddr_in): {
223       const struct sockaddr_in *s4 = (const struct sockaddr_in *) &acn[1];
224       if (AF_INET != s4->sin_family)
225       {
226         GNUNET_break (0);
227         return GNUNET_SYSERR;
228       }
229     }
230     break;
231
232   case sizeof(struct sockaddr_in6): {
233       const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) &acn[1];
234       if (AF_INET6 != s6->sin6_family)
235       {
236         GNUNET_break (0);
237         return GNUNET_SYSERR;
238       }
239     }
240     break;
241
242   default:
243     GNUNET_break (0);
244     return GNUNET_SYSERR;
245   }
246   return GNUNET_OK;
247 }
248
249
250 /**
251  * Handle connection reversal request.
252  *
253  * @param cls our `struct GNUNET_NAT_Handle`
254  * @param acn the message
255  */
256 static void
257 handle_address_change_notification (
258   void *cls,
259   const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
260 {
261   struct GNUNET_NAT_Handle *nh = cls;
262   size_t alen = ntohs (acn->header.size) - sizeof(*acn);
263   const struct sockaddr *sa = (const struct sockaddr *) &acn[1];
264   enum GNUNET_NAT_AddressClass ac;
265   struct AddrEntry *ae;
266
267   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
268               "Received address change notification\n");
269   ac = (enum GNUNET_NAT_AddressClass) ntohl (acn->addr_class);
270   if (GNUNET_YES == ntohl (acn->add_remove))
271   {
272     ae = GNUNET_malloc (sizeof(*ae) + alen);
273     ae->ac = ac;
274     ae->addrlen = alen;
275     GNUNET_memcpy (&ae[1], sa, alen);
276     GNUNET_CONTAINER_DLL_insert (nh->ae_head, nh->ae_tail, ae);
277     nh->address_callback (nh->callback_cls,
278                           &ae->app_ctx,
279                           ntohl (acn->add_remove),
280                           ac,
281                           sa,
282                           alen);
283   }
284   else
285   {
286     for (ae = nh->ae_head; NULL != ae; ae = ae->next)
287       if ((ae->addrlen == alen) && (0 == memcmp (&ae[1], sa, alen)))
288         break;
289     if (NULL == ae)
290     {
291       GNUNET_break (0);
292       reconnect (nh);
293       return;
294     }
295     GNUNET_CONTAINER_DLL_remove (nh->ae_head, nh->ae_tail, ae);
296     nh->address_callback (nh->callback_cls,
297                           &ae->app_ctx,
298                           ntohl (acn->add_remove),
299                           ac,
300                           sa,
301                           alen);
302     GNUNET_free (ae);
303   }
304 }
305
306
307 /**
308  * Handle queue errors by reconnecting to NAT.
309  *
310  * @param cls the `struct GNUNET_NAT_Handle *`
311  * @param error details about the error
312  */
313 static void
314 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
315 {
316   struct GNUNET_NAT_Handle *nh = cls;
317
318   reconnect (nh);
319 }
320
321
322 /**
323  * Task to connect to the NAT service.
324  *
325  * @param cls our `struct GNUNET_NAT_Handle *`
326  */
327 static void
328 do_connect (void *cls)
329 {
330   struct GNUNET_NAT_Handle *nh = cls;
331   struct GNUNET_MQ_MessageHandler handlers[] =
332   { GNUNET_MQ_hd_var_size (connection_reversal_request,
333                            GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED,
334                            struct
335                            GNUNET_NAT_ConnectionReversalRequestedMessage,
336                            nh),
337     GNUNET_MQ_hd_var_size (address_change_notification,
338                            GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE,
339                            struct GNUNET_NAT_AddressChangeNotificationMessage,
340                            nh),
341     GNUNET_MQ_handler_end () };
342   struct GNUNET_MQ_Envelope *env;
343
344   nh->reconnect_task = NULL;
345   nh->mq =
346     GNUNET_CLIENT_connect (nh->cfg, "nat", handlers, &mq_error_handler, nh);
347   if (NULL == nh->mq)
348   {
349     reconnect (nh);
350     return;
351   }
352   env = GNUNET_MQ_msg_copy (nh->reg);
353   GNUNET_MQ_send (nh->mq, env);
354 }
355
356
357 /**
358  * Attempt to enable port redirection and detect public IP address
359  * contacting UPnP or NAT-PMP routers on the local network. Use @a
360  * addr to specify to which of the local host's addresses should the
361  * external port be mapped. The port is taken from the corresponding
362  * sockaddr_in[6] field.  The NAT module should call the given @a
363  * address_callback for any 'plausible' external address.
364  *
365  * @param cfg configuration to use
366  * @param config_section name of the configuration section for optionsx
367  * @param proto protocol this is about, IPPROTO_TCP or IPPROTO_UDP
368  * @param num_addrs number of addresses in @a addrs
369  * @param addrs list of local addresses packets should be redirected to
370  * @param addrlens actual lengths of the addresses in @a addrs
371  * @param address_callback function to call everytime the public IP address changes
372  * @param reversal_callback function to call if someone wants connection reversal from us,
373  *        NULL if connection reversal is not supported
374  * @param callback_cls closure for callbacks
375  * @return NULL on error, otherwise handle that can be used to unregister
376  */
377 struct GNUNET_NAT_Handle *
378 GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
379                      const char *config_section,
380                      uint8_t proto,
381                      unsigned int num_addrs,
382                      const struct sockaddr **addrs,
383                      const socklen_t *addrlens,
384                      GNUNET_NAT_AddressCallback address_callback,
385                      GNUNET_NAT_ReversalCallback reversal_callback,
386                      void *callback_cls)
387 {
388   struct GNUNET_NAT_Handle *nh;
389   struct GNUNET_NAT_RegisterMessage *rm;
390   size_t len;
391   size_t str_len;
392   char *off;
393
394   len = 0;
395   for (unsigned int i = 0; i < num_addrs; i++)
396     len += addrlens[i];
397   str_len = strlen (config_section) + 1;
398   len += str_len;
399   if ((len > GNUNET_MAX_MESSAGE_SIZE - sizeof(*rm)) ||
400       (num_addrs > UINT16_MAX))
401   {
402     GNUNET_break (0);
403     return NULL;
404   }
405   rm = GNUNET_malloc (sizeof(*rm) + len);
406   rm->header.size = htons (sizeof(*rm) + len);
407   rm->header.type = htons (GNUNET_MESSAGE_TYPE_NAT_REGISTER);
408   rm->flags = GNUNET_NAT_RF_NONE;
409   if (NULL != address_callback)
410     rm->flags |= GNUNET_NAT_RF_ADDRESSES;
411   if (NULL != reversal_callback)
412     rm->flags |= GNUNET_NAT_RF_REVERSAL;
413   rm->proto = proto;
414   rm->str_len = htons (str_len);
415   rm->num_addrs = htons ((uint16_t) num_addrs);
416   off = (char *) &rm[1];
417   for (unsigned int i = 0; i < num_addrs; i++)
418   {
419     switch (addrs[i]->sa_family)
420     {
421     case AF_INET:
422       if (sizeof(struct sockaddr_in) != addrlens[i])
423       {
424         GNUNET_break (0);
425         GNUNET_free (rm);
426         return NULL;
427       }
428       break;
429
430     case AF_INET6:
431       if (sizeof(struct sockaddr_in6) != addrlens[i])
432       {
433         GNUNET_break (0);
434         GNUNET_free (rm);
435         return NULL;
436       }
437       break;
438
439 #if AF_UNIX
440     case AF_UNIX:
441       if (sizeof(struct sockaddr_un) != addrlens[i])
442       {
443         GNUNET_break (0);
444         GNUNET_free (rm);
445         return NULL;
446       }
447       break;
448 #endif
449     default:
450       GNUNET_break (0);
451       GNUNET_free (rm);
452       return NULL;
453     }
454     GNUNET_memcpy (off, addrs[i], addrlens[i]);
455     off += addrlens[i];
456   }
457   GNUNET_memcpy (off, config_section, str_len);
458
459   nh = GNUNET_new (struct GNUNET_NAT_Handle);
460   nh->reg = &rm->header;
461   nh->cfg = cfg;
462   nh->address_callback = address_callback;
463   nh->reversal_callback = reversal_callback;
464   nh->callback_cls = callback_cls;
465   do_connect (nh);
466   return nh;
467 }
468
469
470 /**
471  * Check if an incoming message is a STUN message.
472  *
473  * @param data the packet
474  * @param len the length of the packet in @a data
475  * @return #GNUNET_YES if @a data is a STUN packet,
476  *         #GNUNET_NO if the packet is invalid (not a stun packet)
477  */
478 static int
479 test_stun_packet (const void *data, size_t len)
480 {
481   const struct stun_header *hdr;
482   const struct stun_attr *attr;
483   uint32_t advertised_message_size;
484   uint32_t message_magic_cookie;
485
486   /* On entry, 'len' is the length of the UDP payload. After the
487    * initial checks it becomes the size of unprocessed options,
488    * while 'data' is advanced accordingly.
489    */
490   if (len < sizeof(struct stun_header))
491   {
492     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
493                 "STUN packet too short (only %d, wanting at least %d)\n",
494                 (int) len,
495                 (int) sizeof(struct stun_header));
496     return GNUNET_NO;
497   }
498   hdr = (const struct stun_header *) data;
499   /* Skip header as it is already in hdr */
500   len -= sizeof(struct stun_header);
501   data += sizeof(struct stun_header);
502
503   /* len as advertised in the message */
504   advertised_message_size = ntohs (hdr->msglen);
505
506   message_magic_cookie = ntohl (hdr->magic);
507   /* Compare if the cookie match */
508   if (STUN_MAGIC_COOKIE != message_magic_cookie)
509   {
510     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Invalid magic cookie for STUN\n");
511     return GNUNET_NO;
512   }
513
514   if (advertised_message_size > len)
515   {
516     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
517                 "Scrambled STUN packet length (got %d, expecting %d)\n",
518                 advertised_message_size,
519                 (int) len);
520     return GNUNET_NO;
521   }
522   len = advertised_message_size;
523   while (len > 0)
524   {
525     if (len < sizeof(struct stun_attr))
526     {
527       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
528                   "Attribute too short in STUN packet (got %d, expecting %d)\n",
529                   (int) len,
530                   (int) sizeof(struct stun_attr));
531       return GNUNET_NO;
532     }
533     attr = (const struct stun_attr *) data;
534
535     /* compute total attribute length */
536     advertised_message_size = ntohs (attr->len) + sizeof(struct stun_attr);
537
538     /* Check if we still have space in our buffer */
539     if (advertised_message_size > len)
540     {
541       GNUNET_log (
542         GNUNET_ERROR_TYPE_DEBUG,
543         "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n",
544         advertised_message_size,
545         (int) len);
546       return GNUNET_NO;
547     }
548     data += advertised_message_size;
549     len -= advertised_message_size;
550   }
551   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552               "STUN Packet, msg %04x, length: %d\n",
553               ntohs (hdr->msgtype),
554               advertised_message_size);
555   return GNUNET_OK;
556 }
557
558
559 /**
560  * Handle an incoming STUN message.  This function is useful as
561  * some GNUnet service may be listening on a UDP port and might
562  * thus receive STUN messages while trying to receive other data.
563  * In this case, this function can be used to process replies
564  * to STUN requests.
565  *
566  * The function does some basic sanity checks on packet size and
567  * content, try to extract a bit of information.
568  *
569  * At the moment this only processes BIND requests, and returns the
570  * externally visible address of the request to the rest of the
571  * NAT logic.
572  *
573  * @param nh handle to the NAT service
574  * @param sender_addr address from which we got @a data
575  * @param sender_addr_len number of bytes in @a sender_addr
576  * @param data the packet
577  * @param data_size number of bytes in @a data
578  * @return #GNUNET_OK on success
579  *         #GNUNET_NO if the packet is not a STUN packet
580  *         #GNUNET_SYSERR on internal error handling the packet
581  */
582 int
583 GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
584                                const struct sockaddr *sender_addr,
585                                size_t sender_addr_len,
586                                const void *data,
587                                size_t data_size)
588 {
589   struct GNUNET_MQ_Envelope *env;
590   struct GNUNET_NAT_HandleStunMessage *hsn;
591   char *buf;
592
593   if (GNUNET_YES != test_stun_packet (data, data_size))
594     return GNUNET_NO;
595   if (NULL == nh->mq)
596     return GNUNET_SYSERR;
597   env = GNUNET_MQ_msg_extra (hsn,
598                              data_size + sender_addr_len,
599                              GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN);
600   hsn->sender_addr_size = htons ((uint16_t) sender_addr_len);
601   hsn->payload_size = htons ((uint16_t) data_size);
602   buf = (char *) &hsn[1];
603   GNUNET_memcpy (buf, sender_addr, sender_addr_len);
604   buf += sender_addr_len;
605   GNUNET_memcpy (buf, data, data_size);
606   GNUNET_MQ_send (nh->mq, env);
607   return GNUNET_OK;
608 }
609
610
611 /**
612  * Test if the given address is (currently) a plausible IP address for
613  * this peer.  Mostly a convenience function so that clients do not
614  * have to explicitly track all IPs that the #GNUNET_NAT_AddressCallback
615  * has returned so far.
616  *
617  * @param nh the handle returned by register
618  * @param addr IP address to test (IPv4 or IPv6)
619  * @param addrlen number of bytes in @a addr
620  * @return #GNUNET_YES if the address is plausible,
621  *         #GNUNET_NO if the address is not plausible,
622  *         #GNUNET_SYSERR if the address is malformed
623  */
624 int
625 GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *nh,
626                          const void *addr,
627                          socklen_t addrlen)
628 {
629   struct AddrEntry *ae;
630
631   if ((addrlen != sizeof(struct sockaddr_in)) &&
632       (addrlen != sizeof(struct sockaddr_in6)))
633   {
634     GNUNET_break (0);
635     return GNUNET_SYSERR;
636   }
637   for (ae = nh->ae_head; NULL != ae; ae = ae->next)
638     if ((addrlen == ae->addrlen) && (0 == memcmp (addr, &ae[1], addrlen)))
639       return GNUNET_YES;
640   return GNUNET_NO;
641 }
642
643
644 /**
645  * We learned about a peer (possibly behind NAT) so run the
646  * gnunet-nat-client to send dummy ICMP responses to cause
647  * that peer to connect to us (connection reversal).
648  *
649  * @param nh handle (used for configuration)
650  * @param local_sa our local address of the peer (IPv4-only)
651  * @param remote_sa the remote address of the peer (IPv4-only)
652  * @return #GNUNET_SYSERR on error,
653  *         #GNUNET_NO if connection reversal is unavailable,
654  *         #GNUNET_OK otherwise (presumably in progress)
655  */
656 int
657 GNUNET_NAT_request_reversal (struct GNUNET_NAT_Handle *nh,
658                              const struct sockaddr_in *local_sa,
659                              const struct sockaddr_in *remote_sa)
660 {
661   struct GNUNET_MQ_Envelope *env;
662   struct GNUNET_NAT_RequestConnectionReversalMessage *req;
663   char *buf;
664
665   if (NULL == nh->mq)
666     return GNUNET_SYSERR;
667   GNUNET_break (AF_INET == local_sa->sin_family);
668   GNUNET_break (AF_INET == remote_sa->sin_family);
669   env =
670     GNUNET_MQ_msg_extra (req,
671                          2 * sizeof(struct sockaddr_in),
672                          GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL);
673   req->local_addr_size = htons (sizeof(struct sockaddr_in));
674   req->remote_addr_size = htons (sizeof(struct sockaddr_in));
675   buf = (char *) &req[1];
676   GNUNET_memcpy (buf, local_sa, sizeof(struct sockaddr_in));
677   buf += sizeof(struct sockaddr_in);
678   GNUNET_memcpy (buf, remote_sa, sizeof(struct sockaddr_in));
679   GNUNET_MQ_send (nh->mq, env);
680   return GNUNET_OK;
681 }
682
683
684 /**
685  * Stop port redirection and public IP address detection for the given
686  * handle.  This frees the handle, after having sent the needed
687  * commands to close open ports.
688  *
689  * @param nh the handle to stop
690  */
691 void
692 GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *nh)
693 {
694   if (NULL != nh->mq)
695   {
696     GNUNET_MQ_destroy (nh->mq);
697     nh->mq = NULL;
698   }
699   if (NULL != nh->reconnect_task)
700   {
701     GNUNET_SCHEDULER_cancel (nh->reconnect_task);
702     nh->reconnect_task = NULL;
703   }
704   GNUNET_free (nh->reg);
705   GNUNET_free (nh);
706 }
707
708
709 /* end of nat_api.c */