aboutsummaryrefslogtreecommitdiff
path: root/src/dns
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-01-18 20:43:25 +0000
committerChristian Grothoff <christian@grothoff.org>2012-01-18 20:43:25 +0000
commitc37fba0bd9febb11297ebca62a58935276130244 (patch)
tree45cf17c2f0f4ffd0daa2b77181f8cc63a3445ffa /src/dns
parent6b2fb63de633b086a91e7733ca0dd5591198c20c (diff)
downloadgnunet-c37fba0bd9febb11297ebca62a58935276130244.tar.gz
gnunet-c37fba0bd9febb11297ebca62a58935276130244.zip
-adding DNS exit-from-mesh functionality to gnunet-service-dns
Diffstat (limited to 'src/dns')
-rw-r--r--src/dns/Makefile.am1
-rw-r--r--src/dns/dns.conf.in25
-rw-r--r--src/dns/dns.h2
-rw-r--r--src/dns/gnunet-service-dns.c325
4 files changed, 344 insertions, 9 deletions
diff --git a/src/dns/Makefile.am b/src/dns/Makefile.am
index d8c2cd1c1..a9b1d652e 100644
--- a/src/dns/Makefile.am
+++ b/src/dns/Makefile.am
@@ -74,6 +74,7 @@ gnunet_service_dns_SOURCES = \
74 gnunet-service-dns.c 74 gnunet-service-dns.c
75gnunet_service_dns_LDADD = \ 75gnunet_service_dns_LDADD = \
76 $(top_builddir)/src/tun/libgnunettun.la \ 76 $(top_builddir)/src/tun/libgnunettun.la \
77 $(top_builddir)/src/mesh/libgnunetmesh.la \
77 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 78 $(top_builddir)/src/statistics/libgnunetstatistics.la \
78 $(top_builddir)/src/util/libgnunetutil.la \ 79 $(top_builddir)/src/util/libgnunetutil.la \
79 $(GN_LIBINTL) 80 $(GN_LIBINTL)
diff --git a/src/dns/dns.conf.in b/src/dns/dns.conf.in
index a99f7fec3..d2c67958a 100644
--- a/src/dns/dns.conf.in
+++ b/src/dns/dns.conf.in
@@ -1,17 +1,34 @@
1[dns] 1[dns]
2AUTOSTART = YES 2AUTOSTART = YES
3@UNIXONLY@ PORT = 0
4HOSTNAME = localhost 3HOSTNAME = localhost
5HOME = $SERVICEHOME 4HOME = $SERVICEHOME
6CONFIG = $DEFAULTCONFIG 5CONFIG = $DEFAULTCONFIG
7BINARY = gnunet-service-dns 6BINARY = gnunet-service-dns
8UNIXPATH = /tmp/gnunet-service-dns.sock 7UNIXPATH = /tmp/gnunet-service-dns.sock
8
9# Access to this service can compromise all DNS queries in this
10# system. Thus access should be restricted to the same UID.
11# (see https://gnunet.org/gnunet-access-control-model)
9UNIX_MATCH_UID = YES 12UNIX_MATCH_UID = YES
10UNIX_MATCH_GID = YES 13UNIX_MATCH_GID = YES
14
15# As there is no sufficiently restrictive access control for TCP,
16# we never use it, even if @UNIXONLY@ is not set (just to be safe)
17@UNIXONLY@ PORT = 0
18
19# This option should be set to YES to allow the DNS service to
20# perform lookups against the locally configured DNS resolver.
21# (set to "NO" if no normal ISP is locally available and thus
22# requests for normal ".com"/".org"/etc. must be routed via
23# the GNUnet VPN (the GNUNET PT daemon then needs to be configured
24# to intercept and route DNS queries via mesh).
11PROVIDE_EXIT = YES 25PROVIDE_EXIT = YES
26
27# Name of the virtual interface we use to intercept DNS traffic.
12IFNAME = gnunet-dns 28IFNAME = gnunet-dns
13 29
14# Use RFC 3849-style documentation IPv6 address (RFC 4773 might provide an alternative in the future) 30# Use RFC 3849-style documentation IPv6 address (RFC 4773 might provide an alternative in the future)
31# FIXME: or just default to a site-local address scope as we do for VPN!?
15IPV6ADDR = 2001:DB8::1 32IPV6ADDR = 2001:DB8::1
16IPV6PREFIX = 126 33IPV6PREFIX = 126
17 34
@@ -19,3 +36,9 @@ IPV6PREFIX = 126
19IPV4ADDR = 169.254.1.1 36IPV4ADDR = 169.254.1.1
20IPV4MASK = 255.255.0.0 37IPV4MASK = 255.255.0.0
21 38
39# Enable GNUnet-wide DNS-EXIT service by setting this value to the IP address (IPv4 or IPv6)
40# of a DNS resolver to use. Only works if "PROVIDE_EXIT" is also set to YES. Must absolutely
41# NOT be an address of any of GNUnet's virtual tunnel interfaces. Use a well-known
42# public DNS resolver or your ISP's resolver from /etc/resolv.conf.
43# DNS_EXIT = 8.8.8.8
44
diff --git a/src/dns/dns.h b/src/dns/dns.h
index 29a9f937b..2b0ad0376 100644
--- a/src/dns/dns.h
+++ b/src/dns/dns.h
@@ -19,7 +19,7 @@
19 */ 19 */
20 20
21/** 21/**
22 * @file dns/dns_new.h 22 * @file dns/dns.h
23 * @brief IPC messages between DNS API and DNS service 23 * @brief IPC messages between DNS API and DNS service
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 */ 25 */
diff --git a/src/dns/gnunet-service-dns.c b/src/dns/gnunet-service-dns.c
index 690b4887e..9f3a64334 100644
--- a/src/dns/gnunet-service-dns.c
+++ b/src/dns/gnunet-service-dns.c
@@ -25,11 +25,13 @@
25 */ 25 */
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28#include "gnunet_applications.h"
28#include "gnunet_constants.h" 29#include "gnunet_constants.h"
29#include "gnunet_protocols.h" 30#include "gnunet_protocols.h"
30#include "gnunet_signatures.h" 31#include "gnunet_signatures.h"
31#include "dns.h" 32#include "dns.h"
32#include "gnunet_dns_service.h" 33#include "gnunet_dns_service.h"
34#include "gnunet_mesh_service.h"
33#include "gnunet_statistics_service.h" 35#include "gnunet_statistics_service.h"
34#include "gnunet_tun_lib.h" 36#include "gnunet_tun_lib.h"
35 37
@@ -162,6 +164,55 @@ struct RequestRecord
162}; 164};
163 165
164 166
167
168/**
169 * State we keep for each DNS tunnel that terminates at this node.
170 */
171struct TunnelState
172{
173
174 /**
175 * Associated MESH tunnel.
176 */
177 struct GNUNET_MESH_Tunnel *tunnel;
178
179 /**
180 * Active request for sending a reply.
181 */
182 struct GNUNET_MESH_TransmitHandle *th;
183
184 /**
185 * DNS reply ready for transmission.
186 */
187 char *reply;
188
189 /**
190 * Address we sent the DNS request to.
191 */
192 struct sockaddr_storage addr;
193
194 /**
195 * Number of bytes in 'addr'.
196 */
197 socklen_t addrlen;
198
199 /**
200 * Number of bytes in 'reply'.
201 */
202 size_t reply_length;
203
204 /**
205 * Original DNS request ID as used by the client.
206 */
207 uint16_t original_id;
208
209 /**
210 * DNS request ID that we used for forwarding.
211 */
212 uint16_t my_id;
213};
214
215
165/** 216/**
166 * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be 217 * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be
167 * sent through gnunet. The port of this socket will not be hijacked. 218 * sent through gnunet. The port of this socket will not be hijacked.
@@ -231,10 +282,27 @@ static struct GNUNET_SERVER_NotificationContext *nc;
231static struct RequestRecord requests[UINT16_MAX + 1]; 282static struct RequestRecord requests[UINT16_MAX + 1];
232 283
233/** 284/**
285 * Array of all open requests from tunnels.
286 */
287static struct TunnelState *tunnels[UINT16_MAX + 1];
288
289/**
234 * Generator for unique request IDs. 290 * Generator for unique request IDs.
235 */ 291 */
236static uint64_t request_id_gen; 292static uint64_t request_id_gen;
237 293
294/**
295 * IP address to use for the DNS server if we are a DNS exit service
296 * (for VPN via mesh); otherwise NULL.
297 */
298static char *dns_exit;
299
300/**
301 * Handle to the MESH service (for receiving DNS queries), or NULL
302 * if we are not a DNS exit.
303 */
304static struct GNUNET_MESH_Handle *mesh;
305
238 306
239/** 307/**
240 * We're done processing a DNS request, free associated memory. 308 * We're done processing a DNS request, free associated memory.
@@ -298,6 +366,11 @@ cleanup_task (void *cls GNUNET_UNUSED,
298 GNUNET_STATISTICS_destroy (stats, GNUNET_YES); 366 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
299 stats = NULL; 367 stats = NULL;
300 } 368 }
369 if (NULL != dns_exit)
370 {
371 GNUNET_free (dns_exit);
372 dns_exit = NULL;
373 }
301} 374}
302 375
303 376
@@ -657,6 +730,52 @@ client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
657 730
658 731
659/** 732/**
733 * We got a reply from DNS for a request of a MESH tunnel. Send it
734 * via the tunnel (after changing the request ID back).
735 *
736 * @param cls the 'struct TunnelState'
737 * @param size number of bytes available in buf
738 * @param buf where to copy the reply
739 * @return number of bytes written to buf
740 */
741static size_t
742transmit_reply_to_mesh (void *cls,
743 size_t size,
744 void *buf)
745{
746 struct TunnelState *ts = cls;
747 size_t off;
748 size_t ret;
749 char *cbuf = buf;
750 struct GNUNET_MessageHeader hdr;
751 struct GNUNET_TUN_DnsHeader dns;
752
753 ts->th = NULL;
754 GNUNET_assert (ts->reply != NULL);
755 if (size == 0)
756 return 0;
757 ret = sizeof (struct GNUNET_MessageHeader) + ts->reply_length;
758 GNUNET_assert (ret <= size);
759 hdr.size = htons (ret);
760 hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET);
761 memcpy (&dns, ts->reply, sizeof (dns));
762 dns.id = ts->original_id;
763 off = 0;
764 memcpy (&cbuf[off], &hdr, sizeof (hdr));
765 off += sizeof (hdr);
766 memcpy (&cbuf[off], &dns, sizeof (dns));
767 off += sizeof (dns);
768 memcpy (&cbuf[off], &ts->reply[sizeof (dns)], ts->reply_length - sizeof (dns));
769 off += ts->reply_length - sizeof (dns);
770 GNUNET_free (ts->reply);
771 ts->reply = NULL;
772 ts->reply_length = 0;
773 GNUNET_assert (ret == off);
774 return ret;
775}
776
777
778/**
660 * Read a DNS response from the (unhindered) UDP-Socket 779 * Read a DNS response from the (unhindered) UDP-Socket
661 * 780 *
662 * @param cls socket to read from 781 * @param cls socket to read from
@@ -673,6 +792,7 @@ read_response (void *cls,
673 struct GNUNET_TUN_DnsHeader *dns; 792 struct GNUNET_TUN_DnsHeader *dns;
674 socklen_t addrlen; 793 socklen_t addrlen;
675 struct RequestRecord *rr; 794 struct RequestRecord *rr;
795 struct TunnelState *ts;
676 ssize_t r; 796 ssize_t r;
677 int len; 797 int len;
678 798
@@ -728,19 +848,48 @@ read_response (void *cls,
728 return; 848 return;
729 } 849 }
730 dns = (struct GNUNET_TUN_DnsHeader *) buf; 850 dns = (struct GNUNET_TUN_DnsHeader *) buf;
851 /* Handle case that this is a reply to a request from a MESH DNS tunnel */
852 ts = tunnels[dns->id];
853 if ( (NULL == ts) ||
854 (addrlen != ts->addrlen) ||
855 (0 != memcmp (&ts->addr,
856 addr,
857 addrlen)) )
858 ts = NULL; /* DNS responder address missmatch */
859 if (NULL != ts)
860 {
861 tunnels[dns->id] = NULL;
862 GNUNET_free_non_null (ts->reply);
863 ts->reply = GNUNET_malloc (r);
864 ts->reply_length = r;
865 memcpy (ts->reply, dns, r);
866 if (ts->th != NULL)
867 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
868 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
869 GNUNET_NO, 0,
870 GNUNET_TIME_UNIT_FOREVER_REL,
871 NULL,
872 sizeof (struct GNUNET_MessageHeader) + r,
873 &transmit_reply_to_mesh,
874 ts);
875 }
876 /* Handle case that this is a reply to a local request (intercepted from TUN interface) */
731 rr = &requests[dns->id]; 877 rr = &requests[dns->id];
732 if (rr->phase != RP_INTERNET_DNS) 878 if (rr->phase != RP_INTERNET_DNS)
733 { 879 {
734 /* unexpected / bogus reply */ 880 if (NULL == ts)
735 GNUNET_STATISTICS_update (stats, 881 {
736 gettext_noop ("# External DNS response discarded (no matching request)"), 882 /* unexpected / bogus reply */
737 1, GNUNET_NO); 883 GNUNET_STATISTICS_update (stats,
884 gettext_noop ("# External DNS response discarded (no matching request)"),
885 1, GNUNET_NO);
886 }
738 return; 887 return;
739 } 888 }
740 GNUNET_free_non_null (rr->payload); 889 GNUNET_free_non_null (rr->payload);
741 rr->payload = GNUNET_malloc (len); 890 rr->payload = GNUNET_malloc (r);
742 memcpy (rr->payload, buf, len); 891 memcpy (rr->payload, buf, r);
743 rr->payload_length = len; 892 rr->payload_length = r;
744 next_phase (rr); 893 next_phase (rr);
745 } 894 }
746} 895}
@@ -1123,6 +1272,147 @@ process_helper_messages (void *cls GNUNET_UNUSED, void *client,
1123 1272
1124 1273
1125/** 1274/**
1275 * Process a request via mesh to perform a DNS query.
1276 *
1277 * @param cls closure, NULL
1278 * @param tunnel connection to the other end
1279 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1280 * @param sender who sent the message
1281 * @param message the actual message
1282 * @param atsi performance data for the connection
1283 * @return GNUNET_OK to keep the connection open,
1284 * GNUNET_SYSERR to close it (signal serious error)
1285 */
1286static int
1287receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1288 void **tunnel_ctx,
1289 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
1290 const struct GNUNET_MessageHeader *message,
1291 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1292{
1293 struct TunnelState *ts = *tunnel_ctx;
1294 const struct GNUNET_TUN_DnsHeader *dns;
1295 size_t mlen = ntohs (message->size);
1296 size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader);
1297 char buf[dlen];
1298 struct GNUNET_TUN_DnsHeader *dout;
1299 struct sockaddr_in v4;
1300 struct sockaddr_in6 v6;
1301 struct sockaddr *so;
1302 socklen_t salen;
1303 struct GNUNET_NETWORK_Handle *dnsout;
1304
1305 if (dlen < sizeof (struct GNUNET_TUN_DnsHeader))
1306 {
1307 GNUNET_break_op (0);
1308 return GNUNET_SYSERR;
1309 }
1310 dns = (const struct GNUNET_TUN_DnsHeader *) &message[1];
1311 ts->original_id = dns->id;
1312 if (tunnels[ts->my_id] == ts)
1313 tunnels[ts->my_id] = NULL;
1314 ts->my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1315 65536);
1316 tunnels[ts->my_id] = ts;
1317 memcpy (buf, dns, dlen);
1318 dout = (struct GNUNET_TUN_DnsHeader*) buf;
1319 dout->id = ts->my_id;
1320
1321 memset (&v4, 0, sizeof (v4));
1322 memset (&v6, 0, sizeof (v6));
1323 dnsout = NULL;
1324 if (1 == inet_pton (AF_INET, dns_exit, &v4.sin_addr))
1325 {
1326 salen = sizeof (v4);
1327 v4.sin_family = AF_INET;
1328 v4.sin_port = htons (53);
1329#if HAVE_SOCKADDR_IN_SIN_LEN
1330 v4.sin_len = (u_char) salen;
1331#endif
1332 so = (struct sockaddr *) &v4;
1333 dnsout = dnsout4;
1334 }
1335 if (1 == inet_pton (AF_INET6, dns_exit, &v6.sin6_addr))
1336 {
1337 salen = sizeof (v6);
1338 v6.sin6_family = AF_INET6;
1339 v6.sin6_port = htons (53);
1340#if HAVE_SOCKADDR_IN_SIN_LEN
1341 v6.sin6_len = (u_char) salen;
1342#endif
1343 so = (struct sockaddr *) &v6;
1344 dnsout = dnsout6;
1345 }
1346 if (NULL == dnsout)
1347 {
1348 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1349 _("Configured DNS exit `%s' is not working / valid.\n"),
1350 dns_exit);
1351 return GNUNET_SYSERR;
1352 }
1353 memcpy (&ts->addr,
1354 so,
1355 salen);
1356 ts->addrlen = salen;
1357 GNUNET_NETWORK_socket_sendto (dnsout,
1358 buf, dlen, so, salen);
1359 return GNUNET_OK;
1360}
1361
1362
1363/**
1364 * Callback from GNUNET_MESH for new tunnels.
1365 *
1366 * @param cls closure
1367 * @param tunnel new handle to the tunnel
1368 * @param initiator peer that started the tunnel
1369 * @param atsi performance information for the tunnel
1370 * @return initial tunnel context for the tunnel
1371 */
1372static void *
1373accept_dns_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1374 const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED,
1375 const struct GNUNET_ATS_Information *ats GNUNET_UNUSED)
1376{
1377 struct TunnelState *ts = GNUNET_malloc (sizeof (struct TunnelState));
1378
1379 GNUNET_STATISTICS_update (stats,
1380 gettext_noop ("# Inbound MESH tunnels created"),
1381 1, GNUNET_NO);
1382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1383 "Received inbound tunnel from `%s'\n",
1384 GNUNET_i2s (initiator));
1385 ts->tunnel = tunnel;
1386 return ts;
1387}
1388
1389
1390/**
1391 * Function called by mesh whenever an inbound tunnel is destroyed.
1392 * Should clean up any associated state.
1393 *
1394 * @param cls closure (set from GNUNET_MESH_connect)
1395 * @param tunnel connection to the other end (henceforth invalid)
1396 * @param tunnel_ctx place where local state associated
1397 * with the tunnel is stored
1398 */
1399static void
1400destroy_dns_tunnel (void *cls GNUNET_UNUSED,
1401 const struct GNUNET_MESH_Tunnel *tunnel,
1402 void *tunnel_ctx)
1403{
1404 struct TunnelState *ts = tunnel_ctx;
1405
1406 if (tunnels[ts->my_id] == ts)
1407 tunnels[ts->my_id] = NULL;
1408 if (NULL != ts->th)
1409 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
1410 GNUNET_free_non_null (ts->reply);
1411 GNUNET_free (ts);
1412}
1413
1414
1415/**
1126 * @param cls closure 1416 * @param cls closure
1127 * @param server the initialized server 1417 * @param server the initialized server
1128 * @param cfg_ configuration to use 1418 * @param cfg_ configuration to use
@@ -1150,6 +1440,9 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
1150 nc = GNUNET_SERVER_notification_context_create (server, 1); 1440 nc = GNUNET_SERVER_notification_context_create (server, 1);
1151 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, 1441 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1152 cls); 1442 cls);
1443 (void) GNUNET_CONFIGURATION_get_value_string (cfg, "dns",
1444 "DNS_EXIT",
1445 &dns_exit);
1153 if (GNUNET_YES == 1446 if (GNUNET_YES ==
1154 GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) 1447 GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT"))
1155 { 1448 {
@@ -1220,6 +1513,24 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
1220 (unsigned int) dnsoutport); 1513 (unsigned int) dnsoutport);
1221 helper_argv[6] = GNUNET_strdup (port_s); 1514 helper_argv[6] = GNUNET_strdup (port_s);
1222 helper_argv[7] = NULL; 1515 helper_argv[7] = NULL;
1516
1517 if (NULL != dns_exit)
1518 {
1519 static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1520 {&receive_dns_request, GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET, 0},
1521 {NULL, 0, 0}
1522 };
1523 static GNUNET_MESH_ApplicationType mesh_types[] = {
1524 GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER,
1525 GNUNET_APPLICATION_TYPE_END
1526 };
1527 mesh = GNUNET_MESH_connect (cfg,
1528 1, NULL,
1529 &accept_dns_tunnel,
1530 &destroy_dns_tunnel,
1531 mesh_handlers,
1532 mesh_types);
1533 }
1223 hijacker = GNUNET_HELPER_start ("gnunet-helper-dns", 1534 hijacker = GNUNET_HELPER_start ("gnunet-helper-dns",
1224 helper_argv, 1535 helper_argv,
1225 &process_helper_messages, 1536 &process_helper_messages,