working towards new NAT client library implementation
[oweals/gnunet.git] / src / nat / nat_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2007-2016 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    * 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   if (NULL != nh->mq)
134   {
135     GNUNET_MQ_destroy (nh->mq);
136     nh->mq = NULL;
137   }
138   nh->reconnect_delay
139     = GNUNET_TIME_STD_BACKOFF (nh->reconnect_delay);
140   nh->reconnect_task
141     = GNUNET_SCHEDULER_add_delayed (nh->reconnect_delay,
142                                     &do_connect,
143                                     nh);
144 }
145
146
147 /**
148  * Check connection reversal request.
149  *
150  * @param cls our `struct GNUNET_NAT_Handle`
151  * @param crm the message
152  * @return #GNUNET_OK if @a crm is well-formed
153  */
154 static int
155 check_connection_reversal_request (void *cls,
156                                    const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
157 {
158   GNUNET_break (0);
159   return GNUNET_SYSERR;
160 }
161
162   
163 /**
164  * Handle connection reversal request.
165  *
166  * @param cls our `struct GNUNET_NAT_Handle`
167  * @param crm the message
168  */
169 static void
170 handle_connection_reversal_request (void *cls,
171                                     const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
172 {
173   // FIXME: parse
174   // FIXME: call callback!
175   GNUNET_break (0);
176 }
177
178
179 /**
180  * Check address change notification.
181  *
182  * @param cls our `struct GNUNET_NAT_Handle`
183  * @param acn the message
184  * @return #GNUNET_OK if @a crm is well-formed
185  */
186 static int
187 check_address_change_notification (void *cls,
188                                    const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
189 {
190   GNUNET_break (0);
191   return GNUNET_SYSERR;
192 }
193
194   
195 /**
196  * Handle connection reversal request.
197  *
198  * @param cls our `struct GNUNET_NAT_Handle`
199  * @param acn the message
200  */
201 static void
202 handle_address_change_notification (void *cls,
203                                     const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
204 {
205   // FIXME: parse
206   // FIXME: update ae-DLL
207   // FIXME: call callback!
208   GNUNET_break (0);
209 }
210
211
212 /**
213  * Handle queue errors by reconnecting to NAT.
214  *
215  * @param cls the `struct GNUNET_NAT_Handle *`
216  * @param error details about the error
217  */
218 static void
219 mq_error_handler (void *cls,
220                   enum GNUNET_MQ_Error error)
221 {
222   struct GNUNET_NAT_Handle *nh = cls;
223
224   reconnect (nh);
225 }
226
227
228 /**
229  * Task to connect to the NAT service.
230  *
231  * @param cls our `struct GNUNET_NAT_Handle *`
232  */
233 static void
234 do_connect (void *cls)
235 {
236   struct GNUNET_NAT_Handle *nh = cls;
237   struct GNUNET_MQ_MessageHandler handlers[] = {
238     GNUNET_MQ_hd_var_size (connection_reversal_request,
239                            GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED,
240                            struct GNUNET_NAT_ConnectionReversalRequestedMessage,
241                            nh),
242     GNUNET_MQ_hd_var_size (address_change_notification,
243                            GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE,
244                            struct GNUNET_NAT_AddressChangeNotificationMessage,
245                            nh),
246     GNUNET_MQ_handler_end ()
247   };
248
249   nh->reconnect_task = NULL;
250   nh->mq = GNUNET_CLIENT_connecT (nh->cfg,
251                                   "nat",
252                                   handlers,
253                                   &mq_error_handler,
254                                   nh);
255   if (NULL == nh->mq)
256     reconnect (nh);
257 }
258
259
260 /**
261  * Attempt to enable port redirection and detect public IP address
262  * contacting UPnP or NAT-PMP routers on the local network. Use @a
263  * addr to specify to which of the local host's addresses should the
264  * external port be mapped. The port is taken from the corresponding
265  * sockaddr_in[6] field.  The NAT module should call the given @a
266  * address_callback for any 'plausible' external address.
267  *
268  * @param cfg configuration to use
269  * @param proto protocol this is about, IPPROTO_TCP or IPPROTO_UDP
270  * @param adv_port advertised port (port we are either bound to or that our OS
271  *                 locally performs redirection from to our bound port).
272  * @param num_addrs number of addresses in @a addrs
273  * @param addrs list of local addresses packets should be redirected to
274  * @param addrlens actual lengths of the addresses in @a addrs
275  * @param address_callback function to call everytime the public IP address changes
276  * @param reversal_callback function to call if someone wants connection reversal from us,
277  *        NULL if connection reversal is not supported
278  * @param callback_cls closure for callbacks
279  * @return NULL on error, otherwise handle that can be used to unregister
280  */
281 struct GNUNET_NAT_Handle *
282 GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
283                      uint8_t proto,
284                      uint16_t adv_port,
285                      unsigned int num_addrs,
286                      const struct sockaddr **addrs,
287                      const socklen_t *addrlens,
288                      GNUNET_NAT_AddressCallback address_callback,
289                      GNUNET_NAT_ReversalCallback reversal_callback,
290                      void *callback_cls)
291 {
292   struct GNUNET_NAT_Handle *nh;
293   struct GNUNET_NAT_RegisterMessage *rm;
294   size_t len;
295   char *off;
296   
297   len = 0;
298   for (unsigned int i=0;i<num_addrs;i++)
299     len += addrlens[i];
300   if ( (len > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*rm)) ||
301        (num_addrs > UINT16_MAX) )
302   {
303     GNUNET_break (0);
304     return NULL;
305   }
306   rm = GNUNET_malloc (sizeof (*rm) + len);
307   rm->header.size = htons (sizeof (*rm) + len);
308   rm->header.type = htons (GNUNET_MESSAGE_TYPE_NAT_REGISTER);
309   rm->flags = GNUNET_NAT_RF_NONE;
310   if (NULL != address_callback)
311     rm->flags |= GNUNET_NAT_RF_ADDRESSES;
312   if (NULL != reversal_callback)
313     rm->flags |= GNUNET_NAT_RF_REVERSAL;
314   rm->proto = proto;
315   rm->adv_port = htons (adv_port);
316   rm->num_addrs = htons ((uint16_t) num_addrs);
317   off = (char *) &rm[1];
318   for (unsigned int i=0;i<num_addrs;i++)
319   {
320     GNUNET_memcpy (off,
321                    addrs[i],
322                    addrlens[i]);
323     off += addrlens[i];
324   }
325
326   nh = GNUNET_new (struct GNUNET_NAT_Handle);
327   nh->reg = &rm->header;
328   nh->cfg = cfg;
329   nh->address_callback = address_callback;
330   nh->reversal_callback = reversal_callback;
331   nh->callback_cls = callback_cls;
332   do_connect (nh);
333   GNUNET_break (0);
334   return nh;
335 }
336
337
338 /**
339  * Check if an incoming message is a STUN message.
340  *
341  * @param data the packet
342  * @param len the length of the packet in @a data
343  * @return #GNUNET_YES if @a data is a STUN packet,
344  *         #GNUNET_NO if the packet is invalid (not a stun packet)
345  */
346 static int
347 test_stun_packet (const void *data,
348                   size_t len)
349 {
350   const struct stun_header *hdr;
351   const struct stun_attr *attr;
352   uint32_t advertised_message_size;
353   uint32_t message_magic_cookie;
354
355   /* On entry, 'len' is the length of the UDP payload. After the
356    * initial checks it becomes the size of unprocessed options,
357    * while 'data' is advanced accordingly.
358    */
359   if (len < sizeof(struct stun_header))
360   {
361     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
362                 "STUN packet too short (only %d, wanting at least %d)\n",
363                 (int) len,
364                 (int) sizeof (struct stun_header));
365     return GNUNET_NO;
366   }
367   hdr = (const struct stun_header *) data;
368   /* Skip header as it is already in hdr */
369   len -= sizeof (struct stun_header);
370   data += sizeof (struct stun_header);
371
372   /* len as advertised in the message */
373   advertised_message_size = ntohs (hdr->msglen);
374
375   message_magic_cookie = ntohl (hdr->magic);
376   /* Compare if the cookie match */
377   if (STUN_MAGIC_COOKIE != message_magic_cookie)
378   {
379     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
380                 "Invalid magic cookie for STUN\n");
381     return GNUNET_NO;
382   }
383
384   if (advertised_message_size > len)
385   {
386     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
387                 "Scrambled STUN packet length (got %d, expecting %d)\n",
388                 advertised_message_size,
389                 (int)len);
390     return GNUNET_NO;
391   }
392   len = advertised_message_size;
393   while (len > 0)
394   {
395     if (len < sizeof (struct stun_attr))
396     {
397       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
398                   "Attribute too short in STUN packet (got %d, expecting %d)\n",
399                   (int) len,
400                   (int) sizeof(struct stun_attr));
401       return GNUNET_NO;
402     }
403     attr = (const struct stun_attr *) data;
404
405     /* compute total attribute length */
406     advertised_message_size = ntohs (attr->len) + sizeof(struct stun_attr);
407
408     /* Check if we still have space in our buffer */
409     if (advertised_message_size > len)
410     {
411       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412                   "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n",
413                   advertised_message_size,
414                   (int) len);
415       return GNUNET_NO;
416     }
417     data += advertised_message_size;
418     len -= advertised_message_size;
419   }
420   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421               "STUN Packet, msg %04x, length: %d\n",
422               ntohs (hdr->msgtype),
423               advertised_message_size);
424   return GNUNET_OK;
425 }
426
427
428 /**
429  * Handle an incoming STUN message.  This function is useful as
430  * some GNUnet service may be listening on a UDP port and might
431  * thus receive STUN messages while trying to receive other data.
432  * In this case, this function can be used to act as a proper
433  * STUN server (if desired).
434  *
435  * The function does some basic sanity checks on packet size and
436  * content, try to extract a bit of information, and possibly replies
437  * if this is an actual STUN message.
438  * 
439  * At the moment this only processes BIND requests, and returns the
440  * externally visible address of the request. 
441  *
442  * @param nh handle to the NAT service
443  * @param sender_addr address from which we got @a data
444  * @param sender_addr_len number of bytes in @a sender_addr
445  * @param data the packet
446  * @param data_size number of bytes in @a data
447  * @return #GNUNET_OK on success
448  *         #GNUNET_NO if the packet is not a STUN packet
449  *         #GNUNET_SYSERR on internal error handling the packet
450  */
451 int
452 GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
453                                const struct sockaddr *sender_addr,
454                                size_t sender_addr_len,
455                                const void *data,
456                                size_t data_size)
457 {
458   struct GNUNET_MQ_Envelope *env;
459   struct GNUNET_NAT_HandleStunMessage *hsn;
460   char *buf;
461
462   if (GNUNET_YES !=
463       test_stun_packet (data,
464                         data_size))
465     return GNUNET_NO;
466   if (NULL == nh->mq)
467     return GNUNET_SYSERR;
468   env = GNUNET_MQ_msg_extra (hsn,
469                              data_size + sender_addr_len,
470                              GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN);
471   hsn->sender_addr_size = htons ((uint16_t) sender_addr_len);
472   hsn->payload_size = htons ((uint16_t) data_size);
473   buf = (char *) &hsn[1];
474   GNUNET_memcpy (buf,
475                  sender_addr,
476                  sender_addr_len);
477   buf += sender_addr_len;
478   GNUNET_memcpy (buf,
479                  data,
480                  data_size);
481   GNUNET_MQ_send (nh->mq,
482                   env);
483   return GNUNET_OK;
484 }
485
486
487 /**
488  * Test if the given address is (currently) a plausible IP address for
489  * this peer.  Mostly a convenience function so that clients do not
490  * have to explicitly track all IPs that the #GNUNET_NAT_AddressCallback
491  * has returned so far.
492  *
493  * @param nh the handle returned by register
494  * @param addr IP address to test (IPv4 or IPv6)
495  * @param addrlen number of bytes in @a addr
496  * @return #GNUNET_YES if the address is plausible,
497  *         #GNUNET_NO if the address is not plausible,
498  *         #GNUNET_SYSERR if the address is malformed
499  */
500 int
501 GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *nh,
502                          const void *addr,
503                          socklen_t addrlen)
504 {
505   struct AddrEntry *ae;
506
507   if ( (addrlen != sizeof (struct sockaddr_in)) &&
508        (addrlen != sizeof (struct sockaddr_in6)) )
509   {
510     GNUNET_break (0);
511     return GNUNET_SYSERR;
512   }
513   for (ae = nh->ae_head; NULL != ae; ae = ae->next)
514     if ( (addrlen == ae->addrlen) &&
515          (0 == memcmp (addr,
516                        &ae[1],
517                        addrlen)) )
518       return GNUNET_YES;
519   return GNUNET_NO;
520 }
521
522
523 /**
524  * We learned about a peer (possibly behind NAT) so run the
525  * gnunet-nat-client to send dummy ICMP responses to cause
526  * that peer to connect to us (connection reversal).
527  *
528  * @param nh handle (used for configuration)
529  * @param local_sa our local address of the peer (IPv4-only)
530  * @param remote_sa the remote address of the peer (IPv4-only)
531  * @return #GNUNET_SYSERR on error, 
532  *         #GNUNET_NO if connection reversal is unavailable,
533  *         #GNUNET_OK otherwise (presumably in progress)
534  */
535 int
536 GNUNET_NAT_request_reversal (struct GNUNET_NAT_Handle *nh,
537                              const struct sockaddr_in *local_sa,
538                              const struct sockaddr_in *remote_sa)
539 {
540   struct GNUNET_MQ_Envelope *env;
541   struct GNUNET_NAT_RequestConnectionReversalMessage *req;
542   char *buf;
543
544   if (NULL == nh->mq)
545     return GNUNET_SYSERR;
546   env = GNUNET_MQ_msg_extra (req,
547                              2 * sizeof (struct sockaddr_in),
548                              GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL);
549   req->local_addr_size = htons (sizeof (struct sockaddr_in));
550   req->remote_addr_size = htons (sizeof (struct sockaddr_in));
551   buf = (char *) &req[1];
552   GNUNET_memcpy (buf,
553                  local_sa,
554                  sizeof (struct sockaddr_in));
555   buf += sizeof (struct sockaddr_in);
556   GNUNET_memcpy (buf,
557                  remote_sa,
558                  sizeof (struct sockaddr_in));
559   GNUNET_MQ_send (nh->mq,
560                   env);
561   return GNUNET_OK;
562 }
563
564
565 /**
566  * Stop port redirection and public IP address detection for the given
567  * handle.  This frees the handle, after having sent the needed
568  * commands to close open ports.
569  *
570  * @param nh the handle to stop
571  */
572 void
573 GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *nh)
574 {
575   GNUNET_MQ_destroy (nh->mq);
576   GNUNET_free (nh->reg);
577   GNUNET_free (nh);
578 }
579
580
581 /**
582  * Handle to a NAT test.
583  */
584 struct GNUNET_NAT_Test
585 {
586
587   /**
588    * Configuration we use.
589    */
590   const struct GNUNET_CONFIGURATION_Handle *cfg;
591   
592   /**
593    * Message queue for communicating with the NAT service.
594    */
595   struct GNUNET_MQ_Handle *mq;
596
597   /**
598    * Function called to report success or failure for
599    * NAT configuration test.
600    */
601   GNUNET_NAT_TestCallback cb;
602
603   /**
604    * Closure for @e cb.
605    */
606   void *cb_cls;
607
608 };
609
610
611 /**
612  * Handle result for a NAT test from the service.
613  *
614  * @param cls our `struct GNUNET_NAT_Test *`
615  * @param rm message with the result of the test
616  */
617 static void
618 handle_test_result (void *cls,
619                     const struct GNUNET_NAT_TestResultMessage *rm)
620 {
621   struct GNUNET_NAT_Test *tst = cls;
622   enum GNUNET_NAT_StatusCode sc;
623
624   sc = (enum GNUNET_NAT_StatusCode) ntohl (rm->status_code);
625   tst->cb (tst->cb_cls,
626            sc);
627   GNUNET_NAT_test_stop (tst);  
628 }
629                     
630
631 /**
632  * Handle queue errors by reconnecting to NAT.
633  *
634  * @param cls the `struct GNUNET_NAT_Test *`
635  * @param error details about the error
636  */
637 static void
638 tst_error_handler (void *cls,
639                   enum GNUNET_MQ_Error error)
640 {
641   struct GNUNET_NAT_Test *tst = cls;
642
643   tst->cb (tst->cb_cls,
644            GNUNET_NAT_ERROR_IPC_FAILURE);
645   GNUNET_NAT_test_stop (tst);
646 }
647
648
649 /**
650  * Start testing if NAT traversal works using the given configuration
651  * (IPv4-only).  The transport adapters should be down while using
652  * this function.
653  *
654  * @param cfg configuration for the NAT traversal
655  * @param proto protocol to test, i.e. IPPROTO_TCP or IPPROTO_UDP
656  * @param bind_ip IPv4 address to bind to
657  * @param bnd_port port to bind to, 0 to test connection reversal
658  * @param extern_ip IPv4 address to externally advertise
659  * @param extern_port externally advertised port to use
660  * @param report function to call with the result of the test
661  * @param report_cls closure for @a report
662  * @return handle to cancel NAT test
663  */
664 struct GNUNET_NAT_Test *
665 GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
666                        uint8_t proto,
667                        struct in_addr bind_ip,
668                        uint16_t bnd_port,
669                        struct in_addr extern_ip,
670                        uint16_t extern_port,
671                        GNUNET_NAT_TestCallback report,
672                        void *report_cls)
673 {
674   struct GNUNET_NAT_Test *tst = GNUNET_new (struct GNUNET_NAT_Test);
675   struct GNUNET_MQ_MessageHandler handlers[] = {
676     GNUNET_MQ_hd_fixed_size (test_result,
677                              GNUNET_MESSAGE_TYPE_NAT_TEST_RESULT,
678                              struct GNUNET_NAT_TestResultMessage,
679                              tst),
680     GNUNET_MQ_handler_end ()
681   };
682   struct GNUNET_MQ_Envelope *env;
683   struct GNUNET_NAT_RequestTestMessage *req;
684
685   tst->cb = report;
686   tst->cb_cls = report_cls;
687   tst->mq = GNUNET_CLIENT_connecT (cfg,
688                                    "nat",
689                                    handlers,
690                                    &tst_error_handler,
691                                    tst);
692   if (NULL == tst->mq)
693   {
694     GNUNET_break (0);
695     GNUNET_free (tst);
696     return NULL;
697   }
698   env = GNUNET_MQ_msg (req,
699                        GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST);
700   req->bind_port = htons (bnd_port);
701   req->extern_port = htons (extern_port);
702   req->bind_ip = bind_ip;
703   req->extern_ip = extern_ip;
704   req->proto = proto;
705   GNUNET_MQ_send (tst->mq,
706                   env);
707   return tst;
708 }
709
710
711 /**
712  * Stop an active NAT test.
713  *
714  * @param tst test to stop.
715  */
716 void
717 GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst)
718 {
719   GNUNET_MQ_destroy (tst->mq);
720   GNUNET_free (tst);
721 }
722
723
724 /**
725  * Handle to auto-configuration in progress.
726  */
727 struct GNUNET_NAT_AutoHandle
728 {
729
730   /**
731    * Configuration we use.
732    */
733   const struct GNUNET_CONFIGURATION_Handle *cfg;
734   
735   /**
736    * Message queue for communicating with the NAT service.
737    */
738   struct GNUNET_MQ_Handle *mq;
739
740   /**
741    * Function called with the result from the autoconfiguration.
742    */
743   GNUNET_NAT_AutoResultCallback arc;
744
745   /**
746    * Closure for @e arc.
747    */
748   void *arc_cls;
749
750 };
751
752
753 /**
754  * Converts `enum GNUNET_NAT_StatusCode` to string
755  *
756  * @param err error code to resolve to a string
757  * @return point to a static string containing the error code
758  */
759 const char *
760 GNUNET_NAT_status2string (enum GNUNET_NAT_StatusCode err)
761 {
762   GNUNET_break (0);
763   return NULL;
764 }
765
766
767 /**
768  * Start auto-configuration routine.  The transport adapters should
769  * be stopped while this function is called.
770  *
771  * @param cfg initial configuration
772  * @param cb function to call with autoconfiguration result
773  * @param cb_cls closure for @a cb
774  * @return handle to cancel operation
775  */
776 struct GNUNET_NAT_AutoHandle *
777 GNUNET_NAT_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
778                              GNUNET_NAT_AutoResultCallback cb,
779                              void *cb_cls)
780 {
781   struct GNUNET_NAT_AutoHandle *ah = GNUNET_new (struct GNUNET_NAT_AutoHandle);
782
783   ah->cfg = cfg;
784   ah->arc = cb;
785   ah->arc_cls = cb_cls;
786   GNUNET_break (0);
787   return ah;
788 }
789
790
791 /**
792  * Abort autoconfiguration.
793  *
794  * @param ah handle for operation to abort
795  */
796 void
797 GNUNET_NAT_autoconfig_cancel (struct GNUNET_NAT_AutoHandle *ah)
798 {
799   GNUNET_break (0);
800   GNUNET_MQ_destroy (ah->mq);
801   GNUNET_free (ah);
802 }
803
804 /* end of nat_api.c */