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