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