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