aboutsummaryrefslogtreecommitdiff
path: root/src/nat/gnunet-service-nat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nat/gnunet-service-nat.c')
-rw-r--r--src/nat/gnunet-service-nat.c899
1 files changed, 625 insertions, 274 deletions
diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c
index 4ad6c8d2c..af1219dc0 100644
--- a/src/nat/gnunet-service-nat.c
+++ b/src/nat/gnunet-service-nat.c
@@ -40,6 +40,7 @@
40#include "gnunet_statistics_service.h" 40#include "gnunet_statistics_service.h"
41#include "gnunet_nat_service.h" 41#include "gnunet_nat_service.h"
42#include "gnunet-service-nat_stun.h" 42#include "gnunet-service-nat_stun.h"
43#include "gnunet-service-nat_mini.h"
43#include "gnunet-service-nat_helper.h" 44#include "gnunet-service-nat_helper.h"
44#include "nat.h" 45#include "nat.h"
45#include <gcrypt.h> 46#include <gcrypt.h>
@@ -51,6 +52,11 @@
51 */ 52 */
52#define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) 53#define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
53 54
55/**
56 * How long do we wait until we forcefully terminate autoconfiguration?
57 */
58#define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
59
54 60
55/** 61/**
56 * Internal data structure we track for each of our clients. 62 * Internal data structure we track for each of our clients.
@@ -187,6 +193,75 @@ struct StunExternalIP
187 193
188 194
189/** 195/**
196 * Context for autoconfiguration operations.
197 */
198struct AutoconfigContext
199{
200 /**
201 * Kept in a DLL.
202 */
203 struct AutoconfigContext *prev;
204
205 /**
206 * Kept in a DLL.
207 */
208 struct AutoconfigContext *next;
209
210 /**
211 * Which client asked the question.
212 */
213 struct ClientHandle *ch;
214
215 /**
216 * Configuration we are creating.
217 */
218 struct GNUNET_CONFIGURATION_Handle *c;
219
220 /**
221 * Timeout task to force termination.
222 */
223 struct GNUNET_SCHEDULER_Task *timeout_task;
224
225 /**
226 * What type of system are we on?
227 */
228 char *system_type;
229
230 /**
231 * Handle to activity to probe for our external IP.
232 */
233 struct GNUNET_NAT_ExternalHandle *probe_external;
234
235 /**
236 * #GNUNET_YES if upnpc should be used,
237 * #GNUNET_NO if upnpc should not be used,
238 * #GNUNET_SYSERR if we should simply not change the option.
239 */
240 int enable_upnpc;
241
242 /**
243 * Status code to return to the client.
244 */
245 enum GNUNET_NAT_StatusCode status_code;
246
247 /**
248 * NAT type to return to the client.
249 */
250 enum GNUNET_NAT_Type type;
251};
252
253
254/**
255 * DLL of our autoconfiguration operations.
256 */
257static struct AutoconfigContext *ac_head;
258
259/**
260 * DLL of our autoconfiguration operations.
261 */
262static struct AutoconfigContext *ac_tail;
263
264/**
190 * Timeout to use when STUN data is considered stale. 265 * Timeout to use when STUN data is considered stale.
191 */ 266 */
192static struct GNUNET_TIME_Relative stun_stale_timeout; 267static struct GNUNET_TIME_Relative stun_stale_timeout;
@@ -236,6 +311,12 @@ static struct StunExternalIP *se_head;
236 */ 311 */
237static struct StunExternalIP *se_tail; 312static struct StunExternalIP *se_tail;
238 313
314/**
315 * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
316 * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
317 */
318static int enable_upnp;
319
239 320
240/** 321/**
241 * Free the DLL starting at #lal_head. 322 * Free the DLL starting at #lal_head.
@@ -322,7 +403,9 @@ match_ipv4 (const char *network,
322 uint8_t bits) 403 uint8_t bits)
323{ 404{
324 struct in_addr net; 405 struct in_addr net;
325 406
407 if (0 == ip->s_addr)
408 return GNUNET_YES;
326 if (0 == bits) 409 if (0 == bits)
327 return GNUNET_YES; 410 return GNUNET_YES;
328 GNUNET_assert (1 == inet_pton (AF_INET, 411 GNUNET_assert (1 == inet_pton (AF_INET,
@@ -355,6 +438,10 @@ match_ipv6 (const char *network,
355 network, 438 network,
356 &net)); 439 &net));
357 memset (&mask, 0, sizeof (mask)); 440 memset (&mask, 0, sizeof (mask));
441 if (0 == memcmp (&mask,
442 ip,
443 sizeof (mask)))
444 return GNUNET_YES;
358 off = 0; 445 off = 0;
359 while (bits > 8) 446 while (bits > 8)
360 { 447 {
@@ -411,6 +498,296 @@ is_nat_v6 (const struct in6_addr *ip)
411 498
412 499
413/** 500/**
501 * Closure for #ifc_proc.
502 */
503struct IfcProcContext
504{
505
506 /**
507 * Head of DLL of local addresses.
508 */
509 struct LocalAddressList *lal_head;
510
511 /**
512 * Tail of DLL of local addresses.
513 */
514 struct LocalAddressList *lal_tail;
515
516};
517
518
519/**
520 * Callback function invoked for each interface found. Adds them
521 * to our new address list.
522 *
523 * @param cls a `struct IfcProcContext *`
524 * @param name name of the interface (can be NULL for unknown)
525 * @param isDefault is this presumably the default interface
526 * @param addr address of this interface (can be NULL for unknown or unassigned)
527 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
528 * @param netmask the network mask (can be NULL for unknown or unassigned)
529 * @param addrlen length of the address
530 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
531 */
532static int
533ifc_proc (void *cls,
534 const char *name,
535 int isDefault,
536 const struct sockaddr *addr,
537 const struct sockaddr *broadcast_addr,
538 const struct sockaddr *netmask,
539 socklen_t addrlen)
540{
541 struct IfcProcContext *ifc_ctx = cls;
542 struct LocalAddressList *lal;
543 size_t alen;
544 const struct in_addr *ip4;
545 const struct in6_addr *ip6;
546 enum GNUNET_NAT_AddressClass ac;
547
548 switch (addr->sa_family)
549 {
550 case AF_INET:
551 alen = sizeof (struct sockaddr_in);
552 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
553 if (match_ipv4 ("127.0.0.0", ip4, 8))
554 ac = GNUNET_NAT_AC_LOOPBACK;
555 else if (is_nat_v4 (ip4))
556 ac = GNUNET_NAT_AC_LAN;
557 else
558 ac = GNUNET_NAT_AC_GLOBAL;
559 break;
560 case AF_INET6:
561 alen = sizeof (struct sockaddr_in6);
562 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
563 if (match_ipv6 ("::1", ip6, 128))
564 ac = GNUNET_NAT_AC_LOOPBACK;
565 else if (is_nat_v6 (ip6))
566 ac = GNUNET_NAT_AC_LAN;
567 else
568 ac = GNUNET_NAT_AC_GLOBAL;
569 if ( (ip6->s6_addr[11] == 0xFF) &&
570 (ip6->s6_addr[12] == 0xFE) )
571 {
572 /* contains a MAC, be extra careful! */
573 ac |= GNUNET_NAT_AC_PRIVATE;
574 }
575 break;
576#if AF_UNIX
577 case AF_UNIX:
578 GNUNET_break (0);
579 return GNUNET_OK;
580#endif
581 default:
582 GNUNET_break (0);
583 return GNUNET_OK;
584 }
585 lal = GNUNET_malloc (sizeof (*lal));
586 lal->af = addr->sa_family;
587 lal->ac = ac;
588 GNUNET_memcpy (&lal->addr,
589 addr,
590 alen);
591 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
592 ifc_ctx->lal_tail,
593 lal);
594 return GNUNET_OK;
595}
596
597
598/**
599 * Notify client about a change in the list of addresses this peer
600 * has.
601 *
602 * @param delta the entry in the list that changed
603 * @param ch client to contact
604 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
605 * @param addr the address that changed
606 * @param addr_len number of bytes in @a addr
607 */
608static void
609notify_client (struct LocalAddressList *delta,
610 struct ClientHandle *ch,
611 int add,
612 const void *addr,
613 size_t addr_len)
614{
615 struct GNUNET_MQ_Envelope *env;
616 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
617
618 env = GNUNET_MQ_msg_extra (msg,
619 addr_len,
620 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
621 msg->add_remove = htonl (add);
622 msg->addr_class = htonl (delta->ac);
623 GNUNET_memcpy (&msg[1],
624 addr,
625 addr_len);
626 GNUNET_MQ_send (ch->mq,
627 env);
628}
629
630
631/**
632 * Check if we should bother to notify this client about this
633 * address change, and if so, do it.
634 *
635 * @param delta the entry in the list that changed
636 * @param ch client to check
637 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
638 */
639static void
640check_notify_client (struct LocalAddressList *delta,
641 struct ClientHandle *ch,
642 int add)
643{
644 size_t alen;
645 struct sockaddr_in v4;
646 struct sockaddr_in6 v6;
647
648 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
649 return;
650 switch (delta->af)
651 {
652 case AF_INET:
653 alen = sizeof (struct sockaddr_in);
654 GNUNET_memcpy (&v4,
655 &delta->addr,
656 alen);
657 for (unsigned int i=0;i<ch->num_addrs;i++)
658 {
659 const struct sockaddr_in *c4;
660
661 if (AF_INET != ch->addrs[i]->sa_family)
662 return; /* IPv4 not relevant */
663 c4 = (const struct sockaddr_in *) ch->addrs[i];
664 v4.sin_port = c4->sin_port;
665 notify_client (delta,
666 ch,
667 add,
668 &v4,
669 alen);
670 }
671 break;
672 case AF_INET6:
673 alen = sizeof (struct sockaddr_in6);
674 GNUNET_memcpy (&v6,
675 &delta->addr,
676 alen);
677 for (unsigned int i=0;i<ch->num_addrs;i++)
678 {
679 const struct sockaddr_in6 *c6;
680
681 if (AF_INET6 != ch->addrs[i]->sa_family)
682 return; /* IPv4 not relevant */
683 c6 = (const struct sockaddr_in6 *) ch->addrs[i];
684 v6.sin6_port = c6->sin6_port;
685 notify_client (delta,
686 ch,
687 add,
688 &v6,
689 alen);
690 }
691 break;
692 default:
693 GNUNET_break (0);
694 return;
695 }
696}
697
698
699/**
700 * Notify all clients about a change in the list
701 * of addresses this peer has.
702 *
703 * @param delta the entry in the list that changed
704 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
705 */
706static void
707notify_clients (struct LocalAddressList *delta,
708 int add)
709{
710 for (struct ClientHandle *ch = ch_head;
711 NULL != ch;
712 ch = ch->next)
713 check_notify_client (delta,
714 ch,
715 add);
716}
717
718
719/**
720 * Task we run periodically to scan for network interfaces.
721 *
722 * @param cls NULL
723 */
724static void
725run_scan (void *cls)
726{
727 struct IfcProcContext ifc_ctx;
728 int found;
729
730 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
731 &run_scan,
732 NULL);
733 memset (&ifc_ctx,
734 0,
735 sizeof (ifc_ctx));
736 GNUNET_OS_network_interfaces_list (&ifc_proc,
737 &ifc_ctx);
738 /* remove addresses that disappeared */
739 for (struct LocalAddressList *lal = lal_head;
740 NULL != lal;
741 lal = lal->next)
742 {
743 found = GNUNET_NO;
744 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
745 NULL != pos;
746 pos = pos->next)
747 {
748 if ( (pos->af == lal->af) &&
749 (0 == memcmp (&lal->addr,
750 &pos->addr,
751 (AF_INET == lal->af)
752 ? sizeof (struct sockaddr_in)
753 : sizeof (struct sockaddr_in6))) )
754 found = GNUNET_YES;
755 }
756 if (GNUNET_NO == found)
757 notify_clients (lal,
758 GNUNET_NO);
759 }
760
761 /* add addresses that appeared */
762 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
763 NULL != pos;
764 pos = pos->next)
765 {
766 found = GNUNET_NO;
767 for (struct LocalAddressList *lal = lal_head;
768 NULL != lal;
769 lal = lal->next)
770 {
771 if ( (pos->af == lal->af) &&
772 (0 == memcmp (&lal->addr,
773 &pos->addr,
774 (AF_INET == lal->af)
775 ? sizeof (struct sockaddr_in)
776 : sizeof (struct sockaddr_in6))) )
777 found = GNUNET_YES;
778 }
779 if (GNUNET_NO == found)
780 notify_clients (pos,
781 GNUNET_YES);
782 }
783
784 destroy_lal ();
785 lal_head = ifc_ctx.lal_head;
786 lal_tail = ifc_ctx.lal_tail;
787}
788
789
790/**
414 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client. 791 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
415 * We remember the client for updates upon future NAT events. 792 * We remember the client for updates upon future NAT events.
416 * 793 *
@@ -438,7 +815,7 @@ handle_register (void *cls,
438 ch->flags = message->flags; 815 ch->flags = message->flags;
439 ch->proto = message->proto; 816 ch->proto = message->proto;
440 ch->adv_port = ntohs (message->adv_port); 817 ch->adv_port = ntohs (message->adv_port);
441 ch->num_addrs = ntohs (message->adv_port); 818 ch->num_addrs = ntohs (message->num_addrs);
442 ch->addrs = GNUNET_new_array (ch->num_addrs, 819 ch->addrs = GNUNET_new_array (ch->num_addrs,
443 struct sockaddr *); 820 struct sockaddr *);
444 left = ntohs (message->header.size) - sizeof (*message); 821 left = ntohs (message->header.size) - sizeof (*message);
@@ -490,7 +867,16 @@ handle_register (void *cls,
490 sa, 867 sa,
491 alen); 868 alen);
492 off += alen; 869 off += alen;
493 } 870 }
871 /* Actually send IP address list to client */
872 for (struct LocalAddressList *lal = lal_head;
873 NULL != lal;
874 lal = lal->next)
875 {
876 check_notify_client (lal,
877 ch,
878 GNUNET_YES);
879 }
494 GNUNET_SERVICE_client_continue (ch->client); 880 GNUNET_SERVICE_client_continue (ch->client);
495} 881}
496 882
@@ -826,344 +1212,289 @@ check_autoconfig_request (void *cls,
826 1212
827 1213
828/** 1214/**
829 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from 1215 * Stop all pending activities with respect to the @a ac
830 * client.
831 * 1216 *
832 * @param cls client who sent the message 1217 * @param ac autoconfiguration to terminate activities for
833 * @param message the message received
834 */ 1218 */
835static void 1219static void
836handle_autoconfig_request (void *cls, 1220terminate_ac_activities (struct AutoconfigContext *ac)
837 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
838{ 1221{
839 struct ClientHandle *ch = cls; 1222 if (NULL != ac->probe_external)
840 size_t left = ntohs (message->header.size) - sizeof (*message);
841 struct GNUNET_CONFIGURATION_Handle *c;
842
843 c = GNUNET_CONFIGURATION_create ();
844 if (GNUNET_OK !=
845 GNUNET_CONFIGURATION_deserialize (c,
846 (const char *) &message[1],
847 left,
848 GNUNET_NO))
849 { 1223 {
850 GNUNET_break (0); 1224 GNUNET_NAT_mini_get_external_ipv4_cancel_ (ac->probe_external);
851 GNUNET_SERVICE_client_drop (ch->client); 1225 ac->probe_external = NULL;
852 return; 1226 }
1227 if (NULL != ac->timeout_task)
1228 {
1229 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1230 ac->timeout_task = NULL;
853 } 1231 }
854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
855 "Received REQUEST_AUTO_CONFIG message from client\n");
856 // FIXME: actually handle request...
857 GNUNET_CONFIGURATION_destroy (c);
858 GNUNET_SERVICE_client_continue (ch->client);
859} 1232}
860 1233
861 1234
862/** 1235/**
863 * Task run during shutdown. 1236 * Finish handling the autoconfiguration request and send
1237 * the response to the client.
864 * 1238 *
865 * @param cls unused 1239 * @param cls the `struct AutoconfigContext` to conclude
866 */ 1240 */
867static void 1241static void
868shutdown_task (void *cls) 1242conclude_autoconfig_request (void *cls)
869{ 1243{
870 struct StunExternalIP *se; 1244 struct AutoconfigContext *ac = cls;
1245 struct ClientHandle *ch = ac->ch;
1246 struct GNUNET_NAT_AutoconfigResultMessage *arm;
1247 struct GNUNET_MQ_Envelope *env;
1248 size_t c_size;
1249 char *buf;
1250
1251 ac->timeout_task = NULL;
1252 terminate_ac_activities (ac);
1253
1254 /* Send back response */
1255 buf = GNUNET_CONFIGURATION_serialize (ac->c,
1256 &c_size);
1257 env = GNUNET_MQ_msg_extra (arm,
1258 c_size,
1259 GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT);
1260 arm->status_code = htonl ((uint32_t) ac->status_code);
1261 arm->type = htonl ((uint32_t) ac->type);
1262 GNUNET_memcpy (&arm[1],
1263 buf,
1264 c_size);
1265 GNUNET_free (buf);
1266 GNUNET_MQ_send (ch->mq,
1267 env);
871 1268
872 while (NULL != (se = se_head)) 1269 /* clean up */
873 { 1270 GNUNET_free (ac->system_type);
874 GNUNET_CONTAINER_DLL_remove (se_head, 1271 GNUNET_CONFIGURATION_destroy (ac->c);
875 se_tail, 1272 GNUNET_CONTAINER_DLL_remove (ac_head,
876 se); 1273 ac_tail,
877 GNUNET_SCHEDULER_cancel (se->timeout_task); 1274 ac);
878 GNUNET_free (se); 1275 GNUNET_free (ac);
879 } 1276 GNUNET_SERVICE_client_continue (ch->client);
880 if (NULL != scan_task)
881 {
882 GNUNET_SCHEDULER_cancel (scan_task);
883 scan_task = NULL;
884 }
885 if (NULL != stats)
886 {
887 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
888 stats = NULL;
889 }
890 destroy_lal ();
891} 1277}
892 1278
893 1279
894/** 1280/**
895 * Closure for #ifc_proc. 1281 * Check if all autoconfiguration operations have concluded,
1282 * and if they have, send the result back to the client.
1283 *
1284 * @param ac autoconfiguation context to check
896 */ 1285 */
897struct IfcProcContext 1286static void
1287check_autoconfig_finished (struct AutoconfigContext *ac)
898{ 1288{
899 1289 if (NULL != ac->probe_external)
900 /** 1290 return;
901 * Head of DLL of local addresses. 1291 GNUNET_SCHEDULER_cancel (ac->timeout_task);
902 */ 1292 ac->timeout_task
903 struct LocalAddressList *lal_head; 1293 = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request,
904 1294 ac);
905 /** 1295}
906 * Tail of DLL of local addresses.
907 */
908 struct LocalAddressList *lal_tail;
909
910};
911 1296
912 1297
913/** 1298/**
914 * Callback function invoked for each interface found. Adds them 1299 * Update ENABLE_UPNPC configuration option.
915 * to our new address list.
916 * 1300 *
917 * @param cls a `struct IfcProcContext *` 1301 * @param ac autoconfiguration to update
918 * @param name name of the interface (can be NULL for unknown)
919 * @param isDefault is this presumably the default interface
920 * @param addr address of this interface (can be NULL for unknown or unassigned)
921 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
922 * @param netmask the network mask (can be NULL for unknown or unassigned)
923 * @param addrlen length of the address
924 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
925 */ 1302 */
926static int 1303static void
927ifc_proc (void *cls, 1304update_enable_upnpc_option (struct AutoconfigContext *ac)
928 const char *name,
929 int isDefault,
930 const struct sockaddr *addr,
931 const struct sockaddr *broadcast_addr,
932 const struct sockaddr *netmask,
933 socklen_t addrlen)
934{ 1305{
935 struct IfcProcContext *ifc_ctx = cls; 1306 switch (ac->enable_upnpc)
936 struct LocalAddressList *lal;
937 size_t alen;
938 const struct in_addr *ip4;
939 const struct in6_addr *ip6;
940 enum GNUNET_NAT_AddressClass ac;
941
942 switch (addr->sa_family)
943 { 1307 {
944 case AF_INET: 1308 case GNUNET_YES:
945 alen = sizeof (struct sockaddr_in); 1309 GNUNET_CONFIGURATION_set_value_string (ac->c,
946 ip4 = &((const struct sockaddr_in *) addr)->sin_addr; 1310 "NAT",
947 if (match_ipv4 ("127.0.0.0", ip4, 8)) 1311 "ENABLE_UPNPC",
948 ac = GNUNET_NAT_AC_LOOPBACK; 1312 "YES");
949 else if (is_nat_v4 (ip4))
950 ac = GNUNET_NAT_AC_LAN;
951 else
952 ac = GNUNET_NAT_AC_GLOBAL;
953 break; 1313 break;
954 case AF_INET6: 1314 case GNUNET_NO:
955 alen = sizeof (struct sockaddr_in6); 1315 GNUNET_CONFIGURATION_set_value_string (ac->c,
956 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr; 1316 "NAT",
957 if (match_ipv6 ("::1", ip6, 128)) 1317 "ENABLE_UPNPC",
958 ac = GNUNET_NAT_AC_LOOPBACK; 1318 "NO");
959 else if (is_nat_v6 (ip6)) 1319 break;
960 ac = GNUNET_NAT_AC_LAN; 1320 case GNUNET_SYSERR:
961 else 1321 /* We are unsure, do not change option */
962 ac = GNUNET_NAT_AC_GLOBAL;
963 if ( (ip6->s6_addr[11] == 0xFF) &&
964 (ip6->s6_addr[12] == 0xFE) )
965 {
966 /* contains a MAC, be extra careful! */
967 ac |= GNUNET_NAT_AC_PRIVATE;
968 }
969 break; 1322 break;
970#if AF_UNIX
971 case AF_UNIX:
972 GNUNET_break (0);
973 return GNUNET_OK;
974#endif
975 default:
976 GNUNET_break (0);
977 return GNUNET_OK;
978 } 1323 }
979 lal = GNUNET_malloc (sizeof (*lal));
980 lal->af = addr->sa_family;
981 lal->ac = ac;
982 GNUNET_memcpy (&lal->addr,
983 addr,
984 alen);
985 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
986 ifc_ctx->lal_tail,
987 lal);
988 return GNUNET_OK;
989} 1324}
990 1325
991 1326
992/** 1327/**
993 * Notify client about a change in the list 1328 * Handle result from external IP address probe during
994 * of addresses this peer has. 1329 * autoconfiguration.
995 * 1330 *
996 * @param delta the entry in the list that changed 1331 * @param cls our `struct AutoconfigContext`
997 * @param ch client to contact 1332 * @param addr the address, NULL on errors
998 * @param add #GNUNET_YES to add, #GNUNET_NO to remove 1333 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
999 * @param addr the address that changed
1000 * @param addr_len number of bytes in @a addr
1001 */ 1334 */
1002static void 1335static void
1003notify_client (struct LocalAddressList *delta, 1336auto_external_result_cb (void *cls,
1004 struct ClientHandle *ch, 1337 const struct in_addr *addr,
1005 int add, 1338 enum GNUNET_NAT_StatusCode result)
1006 const void *addr,
1007 size_t addr_len)
1008{ 1339{
1009 struct GNUNET_MQ_Envelope *env; 1340 struct AutoconfigContext *ac = cls;
1010 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1011 1341
1012 env = GNUNET_MQ_msg_extra (msg, 1342 ac->probe_external = NULL;
1013 addr_len, 1343 switch (result)
1014 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE); 1344 {
1015 msg->add_remove = htonl (add); 1345 case GNUNET_NAT_ERROR_SUCCESS:
1016 msg->addr_class = htonl (delta->ac); 1346 ac->enable_upnpc = GNUNET_YES;
1017 GNUNET_memcpy (&msg[1], 1347 break;
1018 addr, 1348 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1019 addr_len); 1349 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1020 GNUNET_MQ_send (ch->mq, 1350 case GNUNET_NAT_ERROR_IPC_FAILURE:
1021 env); 1351 ac->enable_upnpc = GNUNET_NO; /* did not work */
1022} 1352 break;
1353 default:
1354 GNUNET_break (0); /* unexpected */
1355 ac->enable_upnpc = GNUNET_SYSERR;
1356 break;
1357 }
1358 update_enable_upnpc_option (ac);
1359 check_autoconfig_finished (ac);
1360}
1023 1361
1024 1362
1025/** 1363/**
1026 * Notify all clients about a change in the list 1364 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
1027 * of addresses this peer has. 1365 * client.
1028 * 1366 *
1029 * @param delta the entry in the list that changed 1367 * @param cls client who sent the message
1030 * @param add #GNUNET_YES to add, #GNUNET_NO to remove 1368 * @param message the message received
1031 */ 1369 */
1032static void 1370static void
1033notify_clients (struct LocalAddressList *delta, 1371handle_autoconfig_request (void *cls,
1034 int add) 1372 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1035{ 1373{
1036 for (struct ClientHandle *ch = ch_head; 1374 struct ClientHandle *ch = cls;
1037 NULL != ch; 1375 size_t left = ntohs (message->header.size) - sizeof (*message);
1038 ch = ch->next) 1376 struct LocalAddressList *lal;
1377 struct AutoconfigContext *ac;
1378
1379 ac = GNUNET_new (struct AutoconfigContext);
1380 ac->c = GNUNET_CONFIGURATION_create ();
1381 if (GNUNET_OK !=
1382 GNUNET_CONFIGURATION_deserialize (ac->c,
1383 (const char *) &message[1],
1384 left,
1385 GNUNET_NO))
1039 { 1386 {
1040 size_t alen; 1387 GNUNET_break (0);
1041 struct sockaddr_in v4; 1388 GNUNET_SERVICE_client_drop (ch->client);
1042 struct sockaddr_in6 v6; 1389 GNUNET_CONFIGURATION_destroy (ac->c);
1043 1390 GNUNET_free (ac);
1044 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES)) 1391 return;
1045 continue; 1392 }
1046 switch (delta->af) 1393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1394 "Received REQUEST_AUTO_CONFIG message from client\n");
1395
1396 if (GNUNET_OK !=
1397 GNUNET_CONFIGURATION_get_value_string (ac->c,
1398 "PEER",
1399 "SYSTEM_TYPE",
1400 &ac->system_type))
1401 ac->system_type = "UNKNOWN";
1402
1403 GNUNET_CONTAINER_DLL_insert (ac_head,
1404 ac_tail,
1405 ac);
1406 ac->timeout_task
1407 = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT,
1408 &conclude_autoconfig_request,
1409 ac);
1410 ac->enable_upnpc = GNUNET_SYSERR; /* undecided */
1411
1412 /* Probe for upnpc */
1413 if (GNUNET_SYSERR ==
1414 GNUNET_OS_check_helper_binary ("upnpc",
1415 GNUNET_NO,
1416 NULL))
1417 {
1418 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1419 _("UPnP client `upnpc` command not found, disabling UPnP\n"));
1420 ac->enable_upnpc = GNUNET_NO;
1421 }
1422 else
1423 {
1424 for (lal = lal_head; NULL != lal; lal = lal->next)
1425 if (GNUNET_NAT_AC_LAN == (lal->ac & GNUNET_NAT_AC_LAN))
1426 /* we are behind NAT, useful to try upnpc */
1427 ac->enable_upnpc = GNUNET_YES;
1428 }
1429 if (GNUNET_YES == ac->enable_upnpc)
1430 {
1431 /* If we are a mobile device, always leave it on as the network
1432 may change to one that supports UPnP anytime. If we are
1433 stationary, check if our network actually supports UPnP, and if
1434 not, disable it. */
1435 if ( (0 == strcasecmp (ac->system_type,
1436 "INFRASTRUCTURE")) ||
1437 (0 == strcasecmp (ac->system_type,
1438 "DESKTOP")) )
1047 { 1439 {
1048 case AF_INET: 1440 /* Check if upnpc gives us an external IP */
1049 alen = sizeof (struct sockaddr_in); 1441 ac->probe_external
1050 GNUNET_memcpy (&v4, 1442 = GNUNET_NAT_mini_get_external_ipv4_ (&auto_external_result_cb,
1051 &delta->addr, 1443 ac);
1052 alen);
1053 for (unsigned int i=0;i<ch->num_addrs;i++)
1054 {
1055 const struct sockaddr_in *c4;
1056
1057 if (AF_INET != ch->addrs[i]->sa_family)
1058 continue; /* IPv4 not relevant */
1059 c4 = (const struct sockaddr_in *) ch->addrs[i];
1060 v4.sin_port = c4->sin_port;
1061 notify_client (delta,
1062 ch,
1063 add,
1064 &v4,
1065 alen);
1066 }
1067 break;
1068 case AF_INET6:
1069 alen = sizeof (struct sockaddr_in6);
1070 GNUNET_memcpy (&v6,
1071 &delta->addr,
1072 alen);
1073 for (unsigned int i=0;i<ch->num_addrs;i++)
1074 {
1075 const struct sockaddr_in6 *c6;
1076
1077 if (AF_INET6 != ch->addrs[i]->sa_family)
1078 continue; /* IPv4 not relevant */
1079 c6 = (const struct sockaddr_in6 *) ch->addrs[i];
1080 v6.sin6_port = c6->sin6_port;
1081 notify_client (delta,
1082 ch,
1083 add,
1084 &v6,
1085 alen);
1086 }
1087 break;
1088 default:
1089 GNUNET_break (0);
1090 continue;
1091 } 1444 }
1092 } 1445 }
1446 if (NULL == ac->probe_external)
1447 update_enable_upnpc_option (ac);
1448
1449 /* Finally, check if we are already done */
1450 check_autoconfig_finished (ac);
1093} 1451}
1094 1452
1095 1453
1096/** 1454/**
1097 * Task we run periodically to scan for network interfaces. 1455 * Task run during shutdown.
1098 * 1456 *
1099 * @param cls NULL 1457 * @param cls unused
1100 */ 1458 */
1101static void 1459static void
1102run_scan (void *cls) 1460shutdown_task (void *cls)
1103{ 1461{
1104 struct IfcProcContext ifc_ctx; 1462 struct StunExternalIP *se;
1105 int found; 1463 struct AutoconfigContext *ac;
1106 1464
1107 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ, 1465 while (NULL != (ac = ac_head))
1108 &run_scan,
1109 NULL);
1110 memset (&ifc_ctx,
1111 0,
1112 sizeof (ifc_ctx));
1113 GNUNET_OS_network_interfaces_list (&ifc_proc,
1114 &ifc_ctx);
1115 for (struct LocalAddressList *lal = lal_head;
1116 NULL != lal;
1117 lal = lal->next)
1118 { 1466 {
1119 found = GNUNET_NO; 1467 GNUNET_CONTAINER_DLL_remove (ac_head,
1120 for (struct LocalAddressList *pos = ifc_ctx.lal_head; 1468 ac_tail,
1121 NULL != pos; 1469 ac);
1122 pos = pos->next) 1470 terminate_ac_activities (ac);
1123 { 1471 GNUNET_free (ac);
1124 if ( (pos->af == lal->af) &&
1125 (0 == memcmp (&lal->addr,
1126 &pos->addr,
1127 (AF_INET == lal->af)
1128 ? sizeof (struct sockaddr_in)
1129 : sizeof (struct sockaddr_in6))) )
1130 found = GNUNET_YES;
1131 }
1132 if (GNUNET_NO == found)
1133 notify_clients (lal,
1134 GNUNET_NO);
1135 } 1472 }
1136 1473 while (NULL != (se = se_head))
1137 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1138 NULL != pos;
1139 pos = pos->next)
1140 { 1474 {
1141 found = GNUNET_NO; 1475 GNUNET_CONTAINER_DLL_remove (se_head,
1142 for (struct LocalAddressList *lal = lal_head; 1476 se_tail,
1143 NULL != lal; 1477 se);
1144 lal = lal->next) 1478 GNUNET_SCHEDULER_cancel (se->timeout_task);
1145 { 1479 GNUNET_free (se);
1146 if ( (pos->af == lal->af) && 1480 }
1147 (0 == memcmp (&lal->addr, 1481 if (NULL != scan_task)
1148 &pos->addr, 1482 {
1149 (AF_INET == lal->af) 1483 GNUNET_SCHEDULER_cancel (scan_task);
1150 ? sizeof (struct sockaddr_in) 1484 scan_task = NULL;
1151 : sizeof (struct sockaddr_in6))) ) 1485 }
1152 found = GNUNET_YES; 1486 if (NULL != stats)
1153 } 1487 {
1154 if (GNUNET_NO == found) 1488 GNUNET_STATISTICS_destroy (stats,
1155 notify_clients (pos, 1489 GNUNET_NO);
1156 GNUNET_YES); 1490 stats = NULL;
1157 } 1491 }
1158
1159 destroy_lal (); 1492 destroy_lal ();
1160 lal_head = ifc_ctx.lal_head;
1161 lal_tail = ifc_ctx.lal_tail;
1162} 1493}
1163 1494
1164 1495
1165/** 1496/**
1166 * Handle network size estimate clients. 1497 * Setup NAT service.
1167 * 1498 *
1168 * @param cls closure 1499 * @param cls closure
1169 * @param c configuration to use 1500 * @param c configuration to use
@@ -1181,6 +1512,26 @@ run (void *cls,
1181 "STUN_STALE", 1512 "STUN_STALE",
1182 &stun_stale_timeout)) 1513 &stun_stale_timeout))
1183 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS; 1514 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1515
1516 /* Check for UPnP */
1517 enable_upnp
1518 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1519 "NAT",
1520 "ENABLE_UPNP");
1521 if (GNUNET_YES == enable_upnp)
1522 {
1523 /* check if it works */
1524 if (GNUNET_SYSERR ==
1525 GNUNET_OS_check_helper_binary ("upnpc",
1526 GNUNET_NO,
1527 NULL))
1528 {
1529 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1530 _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1531 enable_upnp = GNUNET_SYSERR;
1532 }
1533 }
1534
1184 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1535 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1185 NULL); 1536 NULL);
1186 stats = GNUNET_STATISTICS_create ("nat", 1537 stats = GNUNET_STATISTICS_create ("nat",