aboutsummaryrefslogtreecommitdiff
path: root/src/transport
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2014-11-02 20:54:51 +0000
committerChristian Grothoff <christian@grothoff.org>2014-11-02 20:54:51 +0000
commitff2354195a8ed1ea2e9c781d7c4421742b0df4d0 (patch)
tree2cb08c47004138f88f49850b0af2e9185acb4e82 /src/transport
parent75b02f33ec88d5b2db25d31a1b6fffc82290f38c (diff)
downloadgnunet-ff2354195a8ed1ea2e9c781d7c4421742b0df4d0.tar.gz
gnunet-ff2354195a8ed1ea2e9c781d7c4421742b0df4d0.zip
adding TCP_STEALTH support to TCP plugin
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/plugin_transport_http_common.h15
-rw-r--r--src/transport/plugin_transport_tcp.c181
2 files changed, 163 insertions, 33 deletions
diff --git a/src/transport/plugin_transport_http_common.h b/src/transport/plugin_transport_http_common.h
index 1fb1bd1ed..79c671862 100644
--- a/src/transport/plugin_transport_http_common.h
+++ b/src/transport/plugin_transport_http_common.h
@@ -57,9 +57,21 @@
57#define HTTP_DEFAULT_PORT 80 57#define HTTP_DEFAULT_PORT 80
58#define HTTPS_DEFAULT_PORT 443 58#define HTTPS_DEFAULT_PORT 443
59 59
60enum HTTP_ADDRESS_OPTIONS 60/**
61 * Bits in the `options` field of HTTP addresses.
62 */
63enum HttpAddressOptions
61{ 64{
65 /**
66 * No bits set.
67 */
62 HTTP_OPTIONS_NONE = 0, 68 HTTP_OPTIONS_NONE = 0,
69
70 /**
71 * Verify X509 server certificate, it should be valid.
72 * (if this bit is not set, it is probably just self-
73 * signed and not expected to be verified).
74 */
63 HTTP_OPTIONS_VERIFY_CERTIFICATE = 1 75 HTTP_OPTIONS_VERIFY_CERTIFICATE = 1
64}; 76};
65 77
@@ -73,6 +85,7 @@ struct HttpAddress
73{ 85{
74 /** 86 /**
75 * Address options 87 * Address options
88 * see `enum HttpAddressOptions`
76 */ 89 */
77 uint32_t options; 90 uint32_t options;
78 91
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c
index 3e82465a7..77997b5ef 100644
--- a/src/transport/plugin_transport_tcp.c
+++ b/src/transport/plugin_transport_tcp.c
@@ -121,6 +121,28 @@ struct TCPProbeContext
121 struct Plugin *plugin; 121 struct Plugin *plugin;
122}; 122};
123 123
124/**
125 * Bits in the `options` field of TCP addresses.
126 */
127enum TcpAddressOptions
128{
129
130 /**
131 * No bits set.
132 */
133 TCP_OPTIONS_NONE = 0,
134
135 /**
136 * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
137 */
138 TCP_OPTIONS_RESERVED = 1,
139
140 /**
141 * Enable TCP Stealth-style port knocking.
142 */
143 TCP_OPTIONS_TCP_STEALTH = 2
144};
145
124GNUNET_NETWORK_STRUCT_BEGIN 146GNUNET_NETWORK_STRUCT_BEGIN
125 147
126/** 148/**
@@ -129,7 +151,8 @@ GNUNET_NETWORK_STRUCT_BEGIN
129struct IPv4TcpAddress 151struct IPv4TcpAddress
130{ 152{
131 /** 153 /**
132 * Optional options and flags for this address 154 * Optional options and flags for this address,
155 * see `enum TcpAddressOptions`
133 */ 156 */
134 uint32_t options; 157 uint32_t options;
135 158
@@ -152,6 +175,7 @@ struct IPv6TcpAddress
152{ 175{
153 /** 176 /**
154 * Optional flags for this address 177 * Optional flags for this address
178 * see `enum TcpAddressOptions`
155 */ 179 */
156 uint32_t options; 180 uint32_t options;
157 181
@@ -1488,9 +1512,13 @@ tcp_plugin_get_session (void *cls,
1488 struct sockaddr_in6 a6; 1512 struct sockaddr_in6 a6;
1489 const struct IPv4TcpAddress *t4; 1513 const struct IPv4TcpAddress *t4;
1490 const struct IPv6TcpAddress *t6; 1514 const struct IPv6TcpAddress *t6;
1515 unsigned int options;
1491 struct GNUNET_ATS_Information ats; 1516 struct GNUNET_ATS_Information ats;
1492 unsigned int is_natd = GNUNET_NO; 1517 unsigned int is_natd = GNUNET_NO;
1493 size_t addrlen; 1518 size_t addrlen;
1519#ifdef SO_TCPSTEALTH
1520 struct GNUNET_NETWORK_Handle *s;
1521#endif
1494 1522
1495 addrlen = address->address_length; 1523 addrlen = address->address_length;
1496 LOG(GNUNET_ERROR_TYPE_DEBUG, 1524 LOG(GNUNET_ERROR_TYPE_DEBUG,
@@ -1537,6 +1565,7 @@ tcp_plugin_get_session (void *cls,
1537 { 1565 {
1538 GNUNET_assert(NULL != address->address); /* make static analysis happy */ 1566 GNUNET_assert(NULL != address->address); /* make static analysis happy */
1539 t6 = address->address; 1567 t6 = address->address;
1568 options = t6->options;
1540 af = AF_INET6; 1569 af = AF_INET6;
1541 memset (&a6, 0, sizeof(a6)); 1570 memset (&a6, 0, sizeof(a6));
1542#if HAVE_SOCKADDR_IN_SIN_LEN 1571#if HAVE_SOCKADDR_IN_SIN_LEN
@@ -1554,6 +1583,7 @@ tcp_plugin_get_session (void *cls,
1554 { 1583 {
1555 GNUNET_assert(NULL != address->address); /* make static analysis happy */ 1584 GNUNET_assert(NULL != address->address); /* make static analysis happy */
1556 t4 = address->address; 1585 t4 = address->address;
1586 options = t4->options;
1557 af = AF_INET; 1587 af = AF_INET;
1558 memset (&a4, 0, sizeof(a4)); 1588 memset (&a4, 0, sizeof(a4));
1559#if HAVE_SOCKADDR_IN_SIN_LEN 1589#if HAVE_SOCKADDR_IN_SIN_LEN
@@ -1571,7 +1601,7 @@ tcp_plugin_get_session (void *cls,
1571 { 1601 {
1572 GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop 1602 GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop
1573 ("# requests to create session with invalid address"), 1, GNUNET_NO); 1603 ("# requests to create session with invalid address"), 1, GNUNET_NO);
1574 return NULL ; 1604 return NULL;
1575 } 1605 }
1576 1606
1577 ats = plugin->env->get_address_type (plugin->env->cls, sb, sbs); 1607 ats = plugin->env->get_address_type (plugin->env->cls, sb, sbs);
@@ -1579,13 +1609,13 @@ tcp_plugin_get_session (void *cls,
1579 if ((is_natd == GNUNET_YES) && (addrlen == sizeof(struct IPv6TcpAddress))) 1609 if ((is_natd == GNUNET_YES) && (addrlen == sizeof(struct IPv6TcpAddress)))
1580 { 1610 {
1581 /* NAT client only works with IPv4 addresses */ 1611 /* NAT client only works with IPv4 addresses */
1582 return NULL ; 1612 return NULL;
1583 } 1613 }
1584 1614
1585 if (plugin->cur_connections >= plugin->max_connections) 1615 if (plugin->cur_connections >= plugin->max_connections)
1586 { 1616 {
1587 /* saturated */ 1617 /* saturated */
1588 return NULL ; 1618 return NULL;
1589 } 1619 }
1590 1620
1591 if ((is_natd == GNUNET_YES) 1621 if ((is_natd == GNUNET_YES)
@@ -1594,7 +1624,7 @@ tcp_plugin_get_session (void *cls,
1594 &address->peer))) 1624 &address->peer)))
1595 { 1625 {
1596 /* Only do one NAT punch attempt per peer identity */ 1626 /* Only do one NAT punch attempt per peer identity */
1597 return NULL ; 1627 return NULL;
1598 } 1628 }
1599 1629
1600 if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) && 1630 if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) &&
@@ -1634,13 +1664,51 @@ tcp_plugin_get_session (void *cls,
1634 1664
1635 /* create new outbound session */ 1665 /* create new outbound session */
1636 GNUNET_assert(plugin->cur_connections <= plugin->max_connections); 1666 GNUNET_assert(plugin->cur_connections <= plugin->max_connections);
1637 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs); 1667
1668 if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
1669 {
1670#ifdef SO_TCPSTEALTH
1671 s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
1672 if (NULL == s)
1673 {
1674 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
1675 "socket");
1676 sa = NULL;
1677 }
1678 else
1679 {
1680 if (GNUNET_OK !=
1681 GNUNET_NETWORK_socket_setsockopt (s,
1682 IPPROTO_TCP,
1683 SO_TCPSTEALTH,
1684 &session->target,
1685 sizeof (struct GNUNET_PeerIdentity)))
1686 {
1687 /* TCP STEALTH not supported by kernel */
1688 GNUNET_break (GNUNET_OK ==
1689 GNUNET_NETWORK_socket_close (s));
1690 sa = NULL;
1691 }
1692 else
1693 {
1694 sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
1695 }
1696 }
1697#else
1698 sa = NULL;
1699#endif
1700 }
1701 else
1702 {
1703 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
1704 }
1638 if (NULL == sa) 1705 if (NULL == sa)
1639 { 1706 {
1640 LOG(GNUNET_ERROR_TYPE_DEBUG, 1707 LOG (GNUNET_ERROR_TYPE_DEBUG,
1641 "Failed to create connection to `%4s' at `%s'\n", 1708 "Failed to create connection to `%4s' at `%s'\n",
1642 GNUNET_i2s (&address->peer), GNUNET_a2s (sb, sbs)); 1709 GNUNET_i2s (&address->peer),
1643 return NULL ; 1710 GNUNET_a2s (sb, sbs));
1711 return NULL;
1644 } 1712 }
1645 plugin->cur_connections++; 1713 plugin->cur_connections++;
1646 if (plugin->cur_connections == plugin->max_connections) 1714 if (plugin->cur_connections == plugin->max_connections)
@@ -1651,7 +1719,8 @@ tcp_plugin_get_session (void *cls,
1651 GNUNET_i2s (&address->peer), GNUNET_a2s (sb, sbs)); 1719 GNUNET_i2s (&address->peer), GNUNET_a2s (sb, sbs));
1652 1720
1653 session = create_session (plugin, address, 1721 session = create_session (plugin, address,
1654 GNUNET_SERVER_connect_socket (plugin->server, sa), GNUNET_NO); 1722 GNUNET_SERVER_connect_socket (plugin->server, sa),
1723 GNUNET_NO);
1655 session->ats_address_network_type = (enum GNUNET_ATS_Network_Type) ntohl ( 1724 session->ats_address_network_type = (enum GNUNET_ATS_Network_Type) ntohl (
1656 ats.value); 1725 ats.value);
1657 GNUNET_break(session->ats_address_network_type != GNUNET_ATS_NET_UNSPECIFIED); 1726 GNUNET_break(session->ats_address_network_type != GNUNET_ATS_NET_UNSPECIFIED);
@@ -2100,7 +2169,7 @@ handle_tcp_nat_probe (void *cls,
2100 case AF_INET: 2169 case AF_INET:
2101 s4 = vaddr; 2170 s4 = vaddr;
2102 t4 = GNUNET_new (struct IPv4TcpAddress); 2171 t4 = GNUNET_new (struct IPv4TcpAddress);
2103 t4->options = htonl(0); 2172 t4->options = htonl (TCP_OPTIONS_NONE);
2104 t4->t4_port = s4->sin_port; 2173 t4->t4_port = s4->sin_port;
2105 t4->ipv4_addr = s4->sin_addr.s_addr; 2174 t4->ipv4_addr = s4->sin_addr.s_addr;
2106 session->address = GNUNET_HELLO_address_allocate ( 2175 session->address = GNUNET_HELLO_address_allocate (
@@ -2111,7 +2180,7 @@ handle_tcp_nat_probe (void *cls,
2111 case AF_INET6: 2180 case AF_INET6:
2112 s6 = vaddr; 2181 s6 = vaddr;
2113 t6 = GNUNET_new (struct IPv6TcpAddress); 2182 t6 = GNUNET_new (struct IPv6TcpAddress);
2114 t6->options = htonl(0); 2183 t6->options = htonl (TCP_OPTIONS_NONE);
2115 t6->t6_port = s6->sin6_port; 2184 t6->t6_port = s6->sin6_port;
2116 memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr)); 2185 memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2117 session->address = GNUNET_HELLO_address_allocate ( 2186 session->address = GNUNET_HELLO_address_allocate (
@@ -2209,7 +2278,7 @@ handle_tcp_welcome (void *cls,
2209 { 2278 {
2210 s4 = vaddr; 2279 s4 = vaddr;
2211 memset (&t4, '\0', sizeof (t4)); 2280 memset (&t4, '\0', sizeof (t4));
2212 t4.options = htonl (0); 2281 t4.options = htonl (TCP_OPTIONS_NONE);
2213 t4.t4_port = s4->sin_port; 2282 t4.t4_port = s4->sin_port;
2214 t4.ipv4_addr = s4->sin_addr.s_addr; 2283 t4.ipv4_addr = s4->sin_addr.s_addr;
2215 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity, 2284 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
@@ -2220,7 +2289,7 @@ handle_tcp_welcome (void *cls,
2220 { 2289 {
2221 s6 = vaddr; 2290 s6 = vaddr;
2222 memset (&t6, '\0', sizeof (t6)); 2291 memset (&t6, '\0', sizeof (t6));
2223 t6.options = htonl (0); 2292 t6.options = htonl (TCP_OPTIONS_NONE);
2224 t6.t6_port = s6->sin6_port; 2293 t6.t6_port = s6->sin6_port;
2225 memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr)); 2294 memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
2226 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity, 2295 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
@@ -2609,6 +2678,9 @@ libgnunet_plugin_transport_tcp_init (void *cls)
2609 unsigned long long max_connections; 2678 unsigned long long max_connections;
2610 unsigned int i; 2679 unsigned int i;
2611 struct GNUNET_TIME_Relative idle_timeout; 2680 struct GNUNET_TIME_Relative idle_timeout;
2681#ifdef SO_TCPSTEALTH
2682 struct GNUNET_NETWORK_Handle **lsocks;
2683#endif
2612 int ret; 2684 int ret;
2613 int ret_s; 2685 int ret_s;
2614 struct sockaddr **addrs; 2686 struct sockaddr **addrs;
@@ -2635,28 +2707,30 @@ libgnunet_plugin_transport_tcp_init (void *cls)
2635 max_connections = 128; 2707 max_connections = 128;
2636 2708
2637 aport = 0; 2709 aport = 0;
2638 if ((GNUNET_OK 2710 if ((GNUNET_OK !=
2639 != GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", 2711 GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
2640 "PORT", &bport)) || (bport > 65535) 2712 "PORT", &bport)) ||
2641 || ((GNUNET_OK 2713 (bport > 65535) ||
2642 == GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", 2714 ((GNUNET_OK ==
2643 "ADVERTISED-PORT", &aport)) && (aport > 65535))) 2715 GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
2716 "ADVERTISED-PORT", &aport)) &&
2717 (aport > 65535) ))
2644 { 2718 {
2645 LOG(GNUNET_ERROR_TYPE_ERROR, 2719 LOG(GNUNET_ERROR_TYPE_ERROR,
2646 _("Require valid port number for service `%s' in configuration!\n"), 2720 _("Require valid port number for service `%s' in configuration!\n"),
2647 "transport-tcp"); 2721 "transport-tcp");
2648 return NULL ; 2722 return NULL ;
2649 } 2723 }
2650 if (aport == 0) 2724 if (0 == aport)
2651 aport = bport; 2725 aport = bport;
2652 if (bport == 0) 2726 if (0 == bport)
2653 aport = 0; 2727 aport = 0;
2654 if (bport != 0) 2728 if (0 != bport)
2655 { 2729 {
2656 service = GNUNET_SERVICE_start ("transport-tcp", 2730 service = GNUNET_SERVICE_start ("transport-tcp",
2657 env->cfg, 2731 env->cfg,
2658 GNUNET_SERVICE_OPTION_NONE); 2732 GNUNET_SERVICE_OPTION_NONE);
2659 if (service == NULL) 2733 if (NULL == service)
2660 { 2734 {
2661 LOG (GNUNET_ERROR_TYPE_WARNING, 2735 LOG (GNUNET_ERROR_TYPE_WARNING,
2662 _("Failed to start service.\n")); 2736 _("Failed to start service.\n"));
@@ -2666,14 +2740,51 @@ libgnunet_plugin_transport_tcp_init (void *cls)
2666 else 2740 else
2667 service = NULL; 2741 service = NULL;
2668 2742
2743 api = NULL;
2669 plugin = GNUNET_new (struct Plugin); 2744 plugin = GNUNET_new (struct Plugin);
2670 plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections, 2745 plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
2671 GNUNET_YES); 2746 GNUNET_YES);
2672 plugin->max_connections = max_connections; 2747 plugin->max_connections = max_connections;
2673 plugin->open_port = bport; 2748 plugin->open_port = bport;
2674 plugin->adv_port = aport; 2749 plugin->adv_port = aport;
2675 plugin->env = env; 2750 plugin->env = env;
2676 if ( (service != NULL) && 2751
2752 if ( (NULL != service) &&
2753 (GNUNET_YES ==
2754 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2755 "transport-tcp",
2756 "TCP_STEALTH")) )
2757 {
2758#ifdef SO_TCPSTEALTH
2759 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
2760 lsocks = GNUNET_SERVICE_get_listen_sockets (service);
2761 if (NULL != lsocks)
2762 {
2763 for (i=0;NULL!=lsocks[i];i++)
2764 {
2765 if (GNUNET_OK !=
2766 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
2767 IPPROTO_TCP,
2768 SO_TCPSTEALTH,
2769 env->my_identity,
2770 sizeof (struct GNUNET_PeerIdentity)))
2771 {
2772 /* TCP STEALTH not supported by kernel */
2773 GNUNET_assert (0 == i);
2774 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2775 _("TCP_STEALTH not supported on this platform.\n"));
2776 goto die;
2777 }
2778 }
2779 }
2780#else
2781 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2782 _("TCP_STEALTH not supported on this platform.\n"));
2783 goto die;
2784#endif
2785 }
2786
2787 if ( (NULL != service) &&
2677 (GNUNET_SYSERR != 2788 (GNUNET_SYSERR !=
2678 (ret_s = 2789 (ret_s =
2679 GNUNET_SERVICE_get_server_addresses ("transport-tcp", 2790 GNUNET_SERVICE_get_server_addresses ("transport-tcp",
@@ -2736,11 +2847,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
2736 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2847 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2737 "transport-tcp", 2848 "transport-tcp",
2738 "TIMEOUT"); 2849 "TIMEOUT");
2739 if (NULL != plugin->nat) 2850 goto die;
2740 GNUNET_NAT_unregister (plugin->nat);
2741 GNUNET_free(plugin);
2742 GNUNET_free(api);
2743 return NULL;
2744 } 2851 }
2745 plugin->server 2852 plugin->server
2746 = GNUNET_SERVER_create_with_sockets (&plugin_tcp_access_check, 2853 = GNUNET_SERVER_create_with_sockets (&plugin_tcp_access_check,
@@ -2775,6 +2882,16 @@ libgnunet_plugin_transport_tcp_init (void *cls)
2775 0, 2882 0,
2776 GNUNET_NO); 2883 GNUNET_NO);
2777 return api; 2884 return api;
2885
2886 die:
2887 if (NULL != plugin->nat)
2888 GNUNET_NAT_unregister (plugin->nat);
2889 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
2890 if (NULL != service)
2891 GNUNET_SERVICE_stop (service);
2892 GNUNET_free (plugin);
2893 GNUNET_free_non_null (api);
2894 return NULL;
2778} 2895}
2779 2896
2780 2897