diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-01-15 20:41:40 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-01-15 20:41:40 +0000 |
commit | 1574e0f8c2a55363c024a95f440ba7be647efbe1 (patch) | |
tree | 5e4507d9aa404ac983c5774b71b25ec6174ee7cc /src | |
parent | 5ec7048ed9ffeddbe06e34a31d388080fae143e5 (diff) | |
download | gnunet-1574e0f8c2a55363c024a95f440ba7be647efbe1.tar.gz gnunet-1574e0f8c2a55363c024a95f440ba7be647efbe1.zip |
-removing legacy dns/vpn/exit code and renaming -new versions to current
Diffstat (limited to 'src')
-rw-r--r-- | src/dns/Makefile.am | 47 | ||||
-rw-r--r-- | src/dns/dns.h | 93 | ||||
-rw-r--r-- | src/dns/dns_api.c | 664 | ||||
-rw-r--r-- | src/dns/dns_api_new.c | 522 | ||||
-rw-r--r-- | src/dns/dns_new.h | 101 | ||||
-rw-r--r-- | src/dns/dnsparser.c | 329 | ||||
-rw-r--r-- | src/dns/gnunet-dns-monitor.c | 2 | ||||
-rw-r--r-- | src/dns/gnunet-dns-redirector.c | 2 | ||||
-rw-r--r-- | src/dns/gnunet-helper-hijack-dns.c | 328 | ||||
-rw-r--r-- | src/dns/gnunet-service-dns.c | 2445 | ||||
-rw-r--r-- | src/dns/gnunet-service-dns_new.c | 1293 | ||||
-rw-r--r-- | src/include/Makefile.am | 1 | ||||
-rw-r--r-- | src/include/gnunet_dns_service-new.h | 186 | ||||
-rw-r--r-- | src/include/gnunet_dns_service.h | 236 | ||||
-rw-r--r-- | src/include/gnunet_dnsparser_lib.h | 93 | ||||
-rw-r--r-- | src/vpn/Makefile.am | 25 | ||||
-rw-r--r-- | src/vpn/gnunet-daemon-exit.c | 1501 | ||||
-rw-r--r-- | src/vpn/gnunet-daemon-vpn.c | 1808 | ||||
-rw-r--r-- | src/vpn/test-conf.conf | 276 |
19 files changed, 1611 insertions, 8341 deletions
diff --git a/src/dns/Makefile.am b/src/dns/Makefile.am index 99e78d7d6..f8bdae94e 100644 --- a/src/dns/Makefile.am +++ b/src/dns/Makefile.am | |||
@@ -16,26 +16,23 @@ pkgcfg_DATA = \ | |||
16 | dns.conf | 16 | dns.conf |
17 | 17 | ||
18 | if LINUX | 18 | if LINUX |
19 | HIJACKBIN = gnunet-helper-hijack-dns gnunet-helper-dns | 19 | HIJACKBIN = gnunet-helper-dns |
20 | install-exec-hook: | 20 | install-exec-hook: |
21 | $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-hijack-dns || true | ||
22 | $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-hijack-dns || true | ||
23 | $(SUDO_BINARY) chown root $(bindir)/gnunet-helper-dns || true | 21 | $(SUDO_BINARY) chown root $(bindir)/gnunet-helper-dns || true |
24 | $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-helper-dns || true | 22 | $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-helper-dns || true |
25 | $(SUDO_BINARY) chmod 4750 $(bindir)/gnunet-helper-dns || true | 23 | $(SUDO_BINARY) chmod 4750 $(bindir)/gnunet-helper-dns || true |
26 | $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-service-dns-new || true | 24 | $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-service-dns || true |
27 | $(SUDO_BINARY) chmod 2755 $(bindir)/gnunet-helper-dns || true | 25 | $(SUDO_BINARY) chmod 2755 $(bindir)/gnunet-service-dns || true |
28 | else | 26 | else |
29 | install-exec-hook: | 27 | install-exec-hook: |
30 | endif | 28 | endif |
31 | 29 | ||
32 | lib_LTLIBRARIES = \ | 30 | lib_LTLIBRARIES = \ |
33 | libgnunetdnsparser.la \ | 31 | libgnunetdnsparser.la \ |
34 | libgnunetdnsnew.la \ | ||
35 | libgnunetdns.la | 32 | libgnunetdns.la |
36 | 33 | ||
37 | bin_PROGRAMS = \ | 34 | bin_PROGRAMS = \ |
38 | gnunet-service-dns gnunet-service-dns-new $(HIJACKBIN) | 35 | gnunet-service-dns $(HIJACKBIN) |
39 | 36 | ||
40 | noinst_PROGRAMS = \ | 37 | noinst_PROGRAMS = \ |
41 | gnunet-dns-monitor gnunet-dns-redirector | 38 | gnunet-dns-monitor gnunet-dns-redirector |
@@ -44,50 +41,35 @@ plugin_LTLIBRARIES = \ | |||
44 | libgnunet_plugin_block_dns.la | 41 | libgnunet_plugin_block_dns.la |
45 | 42 | ||
46 | 43 | ||
47 | gnunet_helper_hijack_dns_SOURCES = \ | ||
48 | gnunet-helper-hijack-dns.c | ||
49 | |||
50 | gnunet_helper_dns_SOURCES = \ | 44 | gnunet_helper_dns_SOURCES = \ |
51 | gnunet-helper-dns.c | 45 | gnunet-helper-dns.c |
52 | 46 | ||
53 | gnunet_service_dns_SOURCES = \ | ||
54 | gnunet-service-dns.c | ||
55 | gnunet_service_dns_LDADD = \ | ||
56 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
57 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
58 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
59 | $(top_builddir)/src/dht/libgnunetdht.la \ | ||
60 | $(top_builddir)/src/mesh/libgnunetmesh.la \ | ||
61 | $(top_builddir)/src/dns/libgnunetdnsparser.la \ | ||
62 | $(GN_LIBINTL) | ||
63 | gnunet_service_dns_DEPENDENCIES = \ | ||
64 | libgnunetdnsparser.la | ||
65 | 47 | ||
66 | gnunet_dns_monitor_SOURCES = \ | 48 | gnunet_dns_monitor_SOURCES = \ |
67 | gnunet-dns-monitor.c | 49 | gnunet-dns-monitor.c |
68 | gnunet_dns_monitor_LDADD = \ | 50 | gnunet_dns_monitor_LDADD = \ |
69 | $(top_builddir)/src/dns/libgnunetdnsparser.la \ | 51 | $(top_builddir)/src/dns/libgnunetdnsparser.la \ |
70 | $(top_builddir)/src/dns/libgnunetdnsnew.la \ | 52 | $(top_builddir)/src/dns/libgnunetdns.la \ |
71 | $(top_builddir)/src/util/libgnunetutil.la \ | 53 | $(top_builddir)/src/util/libgnunetutil.la \ |
72 | $(GN_LIBINTL) | 54 | $(GN_LIBINTL) |
73 | gnunet_dns_monitor_DEPENDENCIES = \ | 55 | gnunet_dns_monitor_DEPENDENCIES = \ |
74 | libgnunetdnsparser.la \ | 56 | libgnunetdnsparser.la \ |
75 | libgnunetdnsnew.la | 57 | libgnunetdns.la |
76 | 58 | ||
77 | gnunet_dns_redirector_SOURCES = \ | 59 | gnunet_dns_redirector_SOURCES = \ |
78 | gnunet-dns-redirector.c | 60 | gnunet-dns-redirector.c |
79 | gnunet_dns_redirector_LDADD = \ | 61 | gnunet_dns_redirector_LDADD = \ |
80 | $(top_builddir)/src/dns/libgnunetdnsparser.la \ | 62 | $(top_builddir)/src/dns/libgnunetdnsparser.la \ |
81 | $(top_builddir)/src/dns/libgnunetdnsnew.la \ | 63 | $(top_builddir)/src/dns/libgnunetdns.la \ |
82 | $(top_builddir)/src/util/libgnunetutil.la \ | 64 | $(top_builddir)/src/util/libgnunetutil.la \ |
83 | $(GN_LIBINTL) | 65 | $(GN_LIBINTL) |
84 | gnunet_dns_redirector_DEPENDENCIES = \ | 66 | gnunet_dns_redirector_DEPENDENCIES = \ |
85 | libgnunetdnsparser.la \ | 67 | libgnunetdnsparser.la \ |
86 | libgnunetdnsnew.la | 68 | libgnunetdns.la |
87 | 69 | ||
88 | gnunet_service_dns_new_SOURCES = \ | 70 | gnunet_service_dns_SOURCES = \ |
89 | gnunet-service-dns_new.c | 71 | gnunet-service-dns.c |
90 | gnunet_service_dns_new_LDADD = \ | 72 | gnunet_service_dns_LDADD = \ |
91 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | 73 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ |
92 | $(top_builddir)/src/util/libgnunetutil.la \ | 74 | $(top_builddir)/src/util/libgnunetutil.la \ |
93 | $(GN_LIBINTL) | 75 | $(GN_LIBINTL) |
@@ -106,13 +88,6 @@ libgnunetdns_la_LIBADD = \ | |||
106 | libgnunetdns_la_LDFLAGS = \ | 88 | libgnunetdns_la_LDFLAGS = \ |
107 | $(GN_LIB_LDFLAGS) | 89 | $(GN_LIB_LDFLAGS) |
108 | 90 | ||
109 | libgnunetdnsnew_la_SOURCES = \ | ||
110 | dns_api_new.c dns_new.h | ||
111 | libgnunetdnsnew_la_LIBADD = \ | ||
112 | $(top_builddir)/src/util/libgnunetutil.la $(XLIB) | ||
113 | libgnunetdnsnew_la_LDFLAGS = \ | ||
114 | $(GN_LIB_LDFLAGS) | ||
115 | |||
116 | libgnunet_plugin_block_dns_la_SOURCES = \ | 91 | libgnunet_plugin_block_dns_la_SOURCES = \ |
117 | plugin_block_dns.c | 92 | plugin_block_dns.c |
118 | libgnunet_plugin_block_dns_la_LIBADD = \ | 93 | libgnunet_plugin_block_dns_la_LIBADD = \ |
diff --git a/src/dns/dns.h b/src/dns/dns.h index dd0f55e16..29a9f937b 100644 --- a/src/dns/dns.h +++ b/src/dns/dns.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors) | 3 | (C) 2012 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -19,36 +19,83 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file dns/dns.h | 22 | * @file dns/dns_new.h |
23 | * @brief IPC messages between DNS API and DNS service | 23 | * @brief IPC messages between DNS API and DNS service |
24 | * @author Philipp Toelke | ||
25 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
26 | */ | 25 | */ |
27 | #ifndef DNS_H | 26 | #ifndef DNS_NEW_H |
28 | #define DNS_H | 27 | #define DNS_NEW_H |
29 | 28 | ||
30 | GNUNET_NETWORK_STRUCT_BEGIN | 29 | GNUNET_NETWORK_STRUCT_BEGIN |
31 | 30 | ||
32 | struct query_packet | 31 | |
32 | /** | ||
33 | * Message from client to DNS service to register itself. | ||
34 | */ | ||
35 | struct GNUNET_DNS_Register | ||
36 | { | ||
37 | /** | ||
38 | * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT | ||
39 | */ | ||
40 | struct GNUNET_MessageHeader header; | ||
41 | |||
42 | /** | ||
43 | * NBO encoding of 'enum GNUNET_DNS_Flags' for the client. | ||
44 | */ | ||
45 | uint32_t flags; | ||
46 | }; | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Message from DNS service to client: please handle a request. | ||
51 | */ | ||
52 | struct GNUNET_DNS_Request | ||
53 | { | ||
54 | /** | ||
55 | * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST | ||
56 | */ | ||
57 | struct GNUNET_MessageHeader header; | ||
58 | |||
59 | /** | ||
60 | * Always zero. | ||
61 | */ | ||
62 | uint32_t reserved GNUNET_PACKED; | ||
63 | |||
64 | /** | ||
65 | * Unique request ID. | ||
66 | */ | ||
67 | uint64_t request_id GNUNET_PACKED; | ||
68 | |||
69 | /* followed by original DNS request (without UDP header) */ | ||
70 | |||
71 | }; | ||
72 | |||
73 | |||
74 | /** | ||
75 | * Message from client to DNS service: here is my reply. | ||
76 | */ | ||
77 | struct GNUNET_DNS_Response | ||
33 | { | 78 | { |
34 | struct GNUNET_MessageHeader hdr; | 79 | /** |
35 | 80 | * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE | |
36 | /** | 81 | */ |
37 | * The IP-Address this query was originally sent to | 82 | struct GNUNET_MessageHeader header; |
38 | */ | 83 | |
39 | char orig_to[16]; | 84 | /** |
40 | /** | 85 | * Zero to drop, 1 for no change (no payload), 2 for update (message has payload). |
41 | * The IP-Address this query was originally sent from | 86 | */ |
42 | */ | 87 | uint32_t drop_flag GNUNET_PACKED; |
43 | char orig_from[16]; | 88 | |
44 | char addrlen; | 89 | /** |
45 | /** | 90 | * Unique request ID. |
46 | * The UDP-Port this query was originally sent from | 91 | */ |
47 | */ | 92 | uint64_t request_id GNUNET_PACKED; |
48 | uint16_t src_port GNUNET_PACKED; | 93 | |
49 | 94 | /* followed by original DNS request (without UDP header) */ | |
50 | unsigned char data[1]; /* The DNS-Packet */ | 95 | |
51 | }; | 96 | }; |
97 | |||
98 | |||
52 | GNUNET_NETWORK_STRUCT_END | 99 | GNUNET_NETWORK_STRUCT_END |
53 | 100 | ||
54 | #endif | 101 | #endif |
diff --git a/src/dns/dns_api.c b/src/dns/dns_api.c index b434fc1e7..dfce0af1b 100644 --- a/src/dns/dns_api.c +++ b/src/dns/dns_api.c | |||
@@ -1,342 +1,522 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet |
3 | (C) 2010 Christian Grothoff | 3 | (C) 2012 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 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 | 7 | by the Free Software Foundation; either version 2, or (at your |
8 | option) any later version. | 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., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
9 | 20 | ||
10 | GNUnet is distributed in the hope that it will be useful, but | 21 | /** |
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | 22 | * @file dns/dns_api_new.c |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 23 | * @brief API to access the DNS service. |
13 | General Public License for more details. | 24 | * @author Christian Grothoff |
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_dns_service.h" | ||
28 | #include "dns.h" | ||
14 | 29 | ||
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., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | 30 | ||
21 | /** | 31 | /** |
22 | * @file dns/dns_api.c | 32 | * Reply to send to service. |
23 | * @brief | ||
24 | * @author Philipp Toelke | ||
25 | */ | 33 | */ |
26 | #include <platform.h> | 34 | struct ReplyQueueEntry |
27 | #include <gnunet_common.h> | 35 | { |
28 | #include <gnunet_client_lib.h> | 36 | /** |
29 | #include <gnunet_os_lib.h> | 37 | * Kept in DLL. |
30 | #include <gnunet_mesh_service.h> | 38 | */ |
31 | #include <gnunet_protocols.h> | 39 | struct ReplyQueueEntry *next; |
32 | #include <gnunet_server_lib.h> | ||
33 | #include <gnunet_container_lib.h> | ||
34 | #include <block_dns.h> | ||
35 | 40 | ||
36 | #include "gnunet_dns_service.h" | 41 | /** |
37 | #include "dns.h" | 42 | * Kept in DLL. |
43 | */ | ||
44 | struct ReplyQueueEntry *prev; | ||
45 | |||
46 | /** | ||
47 | * Message to transmit, allocated at the end of this struct. | ||
48 | */ | ||
49 | const struct GNUNET_MessageHeader *msg; | ||
38 | 50 | ||
39 | struct query_packet_list | 51 | }; |
52 | |||
53 | |||
54 | /** | ||
55 | * Handle to identify an individual DNS request. | ||
56 | */ | ||
57 | struct GNUNET_DNS_RequestHandle | ||
40 | { | 58 | { |
41 | struct query_packet_list *next; | 59 | |
42 | struct query_packet_list *prev; | 60 | /** |
43 | struct query_packet pkt; | 61 | * Handle to DNS API. |
62 | */ | ||
63 | struct GNUNET_DNS_Handle *dh; | ||
64 | |||
65 | /** | ||
66 | * Stored in network byte order (as for us, it is just a random number). | ||
67 | */ | ||
68 | uint64_t request_id; | ||
69 | |||
70 | /** | ||
71 | * Re-connect counter, to make sure we did not reconnect in the meantime. | ||
72 | */ | ||
73 | uint32_t generation; | ||
74 | |||
44 | }; | 75 | }; |
45 | 76 | ||
46 | 77 | ||
78 | /** | ||
79 | * DNS handle | ||
80 | */ | ||
47 | struct GNUNET_DNS_Handle | 81 | struct GNUNET_DNS_Handle |
48 | { | 82 | { |
49 | struct query_packet_list *head; | 83 | |
50 | struct query_packet_list *tail; | 84 | /** |
85 | * Connection to DNS service, or NULL. | ||
86 | */ | ||
51 | struct GNUNET_CLIENT_Connection *dns_connection; | 87 | struct GNUNET_CLIENT_Connection *dns_connection; |
52 | unsigned char restart_hijack; | ||
53 | 88 | ||
89 | /** | ||
90 | * Handle to active transmission request, or NULL. | ||
91 | */ | ||
54 | struct GNUNET_CLIENT_TransmitHandle *dns_transmit_handle; | 92 | struct GNUNET_CLIENT_TransmitHandle *dns_transmit_handle; |
55 | 93 | ||
94 | /** | ||
95 | * Configuration to use. | ||
96 | */ | ||
56 | const struct GNUNET_CONFIGURATION_Handle *cfg; | 97 | const struct GNUNET_CONFIGURATION_Handle *cfg; |
57 | 98 | ||
58 | GNUNET_DNS_ResponseCallback process_answer_cb; | 99 | /** |
100 | * Function to call to get replies. | ||
101 | */ | ||
102 | GNUNET_DNS_RequestHandler rh; | ||
59 | 103 | ||
60 | void *process_answer_cb_cls; | 104 | /** |
61 | }; | 105 | * Closure for 'rh'. |
106 | */ | ||
107 | void *rh_cls; | ||
62 | 108 | ||
109 | /** | ||
110 | * Head of replies to transmit. | ||
111 | */ | ||
112 | struct ReplyQueueEntry *rq_head; | ||
63 | 113 | ||
64 | /** | 114 | /** |
65 | * Callback called by notify_transmit_ready; sends dns-queries or rehijack-messages | 115 | * Tail of replies to transmit. |
66 | * to the service-dns | 116 | */ |
67 | * {{{ | 117 | struct ReplyQueueEntry *rq_tail; |
68 | */ | ||
69 | size_t | ||
70 | send_query (void *cls GNUNET_UNUSED, size_t size, void *buf) | ||
71 | { | ||
72 | struct GNUNET_DNS_Handle *h = cls; | ||
73 | 118 | ||
74 | size_t len; | 119 | /** |
120 | * Task to reconnect to the service. | ||
121 | */ | ||
122 | GNUNET_SCHEDULER_TaskIdentifier reconnect_task; | ||
75 | 123 | ||
76 | h->dns_transmit_handle = NULL; | 124 | /** |
125 | * Re-connect counter, to make sure we did not reconnect in the meantime. | ||
126 | */ | ||
127 | uint32_t generation; | ||
128 | |||
129 | /** | ||
130 | * Flags for events we care about. | ||
131 | */ | ||
132 | enum GNUNET_DNS_Flags flags; | ||
77 | 133 | ||
78 | /* | 134 | /** |
79 | * Send the rehijack-message | 135 | * Did we start the receive loop yet? |
80 | */ | 136 | */ |
81 | if (h->restart_hijack == 1) | 137 | int in_receive; |
82 | { | 138 | |
83 | h->restart_hijack = 0; | 139 | /** |
84 | /* | 140 | * Number of GNUNET_DNS_RequestHandles we have outstanding. Must be 0 before |
85 | * The message is just a header | 141 | * we can be disconnected. |
86 | */ | 142 | */ |
87 | GNUNET_assert (sizeof (struct GNUNET_MessageHeader) <= size); | 143 | unsigned int pending_requests; |
88 | struct GNUNET_MessageHeader *hdr = buf; | 144 | }; |
89 | 145 | ||
90 | len = sizeof (struct GNUNET_MessageHeader); | ||
91 | hdr->size = htons (len); | ||
92 | hdr->type = htons (GNUNET_MESSAGE_TYPE_REHIJACK); | ||
93 | } | ||
94 | else if (h->head != NULL) | ||
95 | { | ||
96 | struct query_packet_list *query = h->head; | ||
97 | 146 | ||
98 | len = ntohs (query->pkt.hdr.size); | 147 | /** |
148 | * Add the given reply to our transmission queue and trigger sending if needed. | ||
149 | * | ||
150 | * @param dh handle with the connection | ||
151 | * @param qe reply to queue | ||
152 | */ | ||
153 | static void | ||
154 | queue_reply (struct GNUNET_DNS_Handle *dh, | ||
155 | struct ReplyQueueEntry *qe); | ||
99 | 156 | ||
100 | GNUNET_assert (len <= size); | ||
101 | 157 | ||
102 | memcpy (buf, &query->pkt.hdr, len); | 158 | /** |
159 | * Reconnect to the DNS service. | ||
160 | * | ||
161 | * @param cls handle with the connection to connect | ||
162 | * @param tc scheduler context (unused) | ||
163 | */ | ||
164 | static void | ||
165 | reconnect (void *cls, | ||
166 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
167 | { | ||
168 | struct GNUNET_DNS_Handle *dh = cls; | ||
169 | struct ReplyQueueEntry *qe; | ||
170 | struct GNUNET_DNS_Register *msg; | ||
103 | 171 | ||
104 | GNUNET_CONTAINER_DLL_remove (h->head, h->tail, query); | 172 | dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; |
173 | dh->dns_connection = GNUNET_CLIENT_connect ("dns", dh->cfg); | ||
174 | if (NULL == dh->dns_connection) | ||
175 | return; | ||
176 | dh->generation++; | ||
177 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
178 | sizeof (struct GNUNET_DNS_Register)); | ||
179 | msg = (struct GNUNET_DNS_Register*) &qe[1]; | ||
180 | qe->msg = &msg->header; | ||
181 | msg->header.size = htons (sizeof (struct GNUNET_DNS_Register)); | ||
182 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT); | ||
183 | msg->flags = htonl (dh->flags); | ||
184 | queue_reply (dh, qe); | ||
185 | } | ||
105 | 186 | ||
106 | GNUNET_free (query); | 187 | |
107 | } | 188 | /** |
108 | else | 189 | * Disconnect from the DNS service. |
190 | * | ||
191 | * @param dh handle with the connection to disconnect | ||
192 | */ | ||
193 | static void | ||
194 | disconnect (struct GNUNET_DNS_Handle *dh) | ||
195 | { | ||
196 | struct ReplyQueueEntry *qe; | ||
197 | |||
198 | if (NULL != dh->dns_transmit_handle) | ||
109 | { | 199 | { |
110 | GNUNET_break (0); | 200 | GNUNET_CLIENT_notify_transmit_ready_cancel (dh->dns_transmit_handle); |
111 | len = 0; | 201 | dh->dns_transmit_handle = NULL; |
112 | } | 202 | } |
113 | 203 | if (NULL != dh->dns_connection) | |
114 | /* | ||
115 | * Check whether more data is to be sent | ||
116 | */ | ||
117 | if (h->head != NULL) | ||
118 | { | 204 | { |
119 | h->dns_transmit_handle = | 205 | GNUNET_CLIENT_disconnect (dh->dns_connection, GNUNET_NO); |
120 | GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, | 206 | dh->dns_connection = NULL; |
121 | ntohs (h->head->pkt.hdr.size), | ||
122 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
123 | GNUNET_YES, &send_query, h); | ||
124 | } | 207 | } |
125 | else if (h->restart_hijack == 1) | 208 | while (NULL != (qe = dh->rq_head)) |
126 | { | 209 | { |
127 | h->dns_transmit_handle = | 210 | GNUNET_CONTAINER_DLL_remove (dh->rq_head, |
128 | GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, | 211 | dh->rq_tail, |
129 | sizeof (struct | 212 | qe); |
130 | GNUNET_MessageHeader), | 213 | GNUNET_free (qe); |
131 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
132 | GNUNET_YES, &send_query, h); | ||
133 | } | 214 | } |
134 | 215 | dh->in_receive = GNUNET_NO; | |
135 | return len; | ||
136 | } | 216 | } |
137 | 217 | ||
138 | /* }}} */ | ||
139 | |||
140 | |||
141 | 218 | ||
142 | /** | 219 | /** |
143 | * This receives packets from the service-dns and schedules process_answer to | 220 | * This receives packets from the DNS service and calls the application to |
144 | * handle it | 221 | * handle it. |
222 | * | ||
223 | * @param cls the struct GNUNET_DNS_Handle | ||
224 | * @param msg message from the service (request) | ||
145 | */ | 225 | */ |
146 | static void | 226 | static void |
147 | dns_answer_handler (void *cls, | 227 | request_handler (void *cls, |
148 | const struct GNUNET_MessageHeader *msg) | 228 | const struct GNUNET_MessageHeader *msg) |
149 | { | 229 | { |
150 | struct GNUNET_DNS_Handle *h = cls; | 230 | struct GNUNET_DNS_Handle *dh = cls; |
231 | const struct GNUNET_DNS_Request *req; | ||
232 | struct GNUNET_DNS_RequestHandle *rh; | ||
233 | size_t payload_length; | ||
151 | 234 | ||
152 | /* the service disconnected, reconnect after short wait */ | 235 | /* the service disconnected, reconnect after short wait */ |
153 | if (msg == NULL) | 236 | if (msg == NULL) |
154 | { | 237 | { |
155 | if (h->dns_transmit_handle != NULL) | 238 | disconnect (dh); |
156 | GNUNET_CLIENT_notify_transmit_ready_cancel (h->dns_transmit_handle); | 239 | dh->reconnect_task = |
157 | h->dns_transmit_handle = NULL; | ||
158 | GNUNET_CLIENT_disconnect (h->dns_connection, GNUNET_NO); | ||
159 | h->dns_connection = NULL; | ||
160 | #if 0 | ||
161 | h->conn_task = | ||
162 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | 240 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, |
163 | &connect_to_service_dns, h); | 241 | &reconnect, dh); |
164 | #endif | ||
165 | return; | 242 | return; |
166 | } | 243 | } |
167 | 244 | if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST) || | |
168 | /* the service did something strange, reconnect immediately */ | 245 | (ntohs (msg->size) < sizeof (struct GNUNET_DNS_Request)) ) |
169 | if (msg->type != htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS)) | ||
170 | { | 246 | { |
247 | /* the service did something strange, reconnect immediately */ | ||
171 | GNUNET_break (0); | 248 | GNUNET_break (0); |
172 | GNUNET_CLIENT_disconnect (h->dns_connection, GNUNET_NO); | 249 | disconnect (dh); |
173 | h->dns_connection = NULL; | 250 | dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); |
174 | #if 0 | ||
175 | conn_task = GNUNET_SCHEDULER_add_now (&connect_to_service_dns, NULL); | ||
176 | #endif | ||
177 | return; | 251 | return; |
178 | } | 252 | } |
179 | h->process_answer_cb (h->process_answer_cb_cls, | 253 | req = (const struct GNUNET_DNS_Request *) msg; |
180 | (const struct answer_packet*) msg); | 254 | GNUNET_break (ntohl (req->reserved) == 0); |
181 | GNUNET_CLIENT_receive (h->dns_connection, &dns_answer_handler, h, | 255 | payload_length = ntohs (req->header.size) - sizeof (struct GNUNET_DNS_Request); |
256 | GNUNET_CLIENT_receive (dh->dns_connection, | ||
257 | &request_handler, dh, | ||
182 | GNUNET_TIME_UNIT_FOREVER_REL); | 258 | GNUNET_TIME_UNIT_FOREVER_REL); |
259 | |||
260 | /* finally, pass request to callback for answers */ | ||
261 | rh = GNUNET_malloc (sizeof (struct GNUNET_DNS_RequestHandle)); | ||
262 | rh->dh =dh; | ||
263 | rh->request_id = req->request_id; | ||
264 | rh->generation = dh->generation; | ||
265 | dh->pending_requests++; | ||
266 | dh->rh (dh->rh_cls, | ||
267 | rh, | ||
268 | payload_length, | ||
269 | (const char*) &req[1]); | ||
183 | } | 270 | } |
184 | 271 | ||
185 | 272 | ||
186 | /** | 273 | /** |
187 | * Connect to the service-dns | 274 | * Callback called by notify_transmit_ready; sends DNS replies |
275 | * to the DNS service. | ||
276 | * | ||
277 | * @param cls the struct GNUNET_DNS_Handle | ||
278 | * @param size number of bytes available in buf | ||
279 | * @param buf where to copy the message for transmission | ||
280 | * @return number of bytes copied to buf | ||
188 | */ | 281 | */ |
189 | struct GNUNET_DNS_Handle * | 282 | static size_t |
190 | GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | 283 | send_response (void *cls, size_t size, void *buf) |
191 | GNUNET_DNS_ResponseCallback cb, | ||
192 | void *cb_cls) | ||
193 | { | 284 | { |
194 | struct GNUNET_DNS_Handle *h; | 285 | struct GNUNET_DNS_Handle *dh = cls; |
195 | 286 | struct ReplyQueueEntry *qe; | |
196 | h = GNUNET_malloc (sizeof (struct GNUNET_DNS_Handle)); | 287 | size_t len; |
197 | h->cfg = cfg; | 288 | |
198 | h->process_answer_cb = cb; | 289 | dh->dns_transmit_handle = NULL; |
199 | h->process_answer_cb_cls = cb_cls; | 290 | if (NULL == buf) |
200 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to service-dns\n"); | 291 | { |
201 | h->dns_connection = GNUNET_CLIENT_connect ("dns", h->cfg); | 292 | disconnect (dh); |
202 | /* This would most likely be a misconfiguration */ | 293 | dh->reconnect_task = |
203 | GNUNET_assert (NULL != h->dns_connection); | 294 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, |
204 | GNUNET_CLIENT_receive (h->dns_connection, | 295 | &reconnect, dh); |
205 | &dns_answer_handler, NULL, | 296 | return 0; |
206 | GNUNET_TIME_UNIT_FOREVER_REL); | 297 | } |
207 | /* If a packet is already in the list, schedule to send it */ | 298 | qe = dh->rq_head; |
208 | if (h->dns_transmit_handle == NULL && h->head != NULL) | 299 | if (NULL == qe) |
209 | h->dns_transmit_handle = | 300 | return 0; |
210 | GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, | 301 | len = ntohs (qe->msg->size); |
211 | ntohs (h->head->pkt.hdr.size), | 302 | if (len > size) |
212 | GNUNET_TIME_UNIT_FOREVER_REL, | 303 | { |
213 | GNUNET_YES, &send_query, h); | 304 | dh->dns_transmit_handle = |
214 | else if (h->dns_transmit_handle == NULL && h->restart_hijack == 1) | 305 | GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, |
306 | len, | ||
307 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
308 | GNUNET_NO, | ||
309 | &send_response, dh); | ||
310 | return 0; | ||
311 | } | ||
312 | memcpy (buf, qe->msg, len); | ||
313 | GNUNET_CONTAINER_DLL_remove (dh->rq_head, | ||
314 | dh->rq_tail, | ||
315 | qe); | ||
316 | GNUNET_free (qe); | ||
317 | if (GNUNET_NO == dh->in_receive) | ||
215 | { | 318 | { |
216 | h->dns_transmit_handle = | 319 | dh->in_receive = GNUNET_YES; |
217 | GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, | 320 | GNUNET_CLIENT_receive (dh->dns_connection, |
218 | sizeof (struct | 321 | &request_handler, dh, |
219 | GNUNET_MessageHeader), | 322 | GNUNET_TIME_UNIT_FOREVER_REL); |
220 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
221 | GNUNET_YES, &send_query, NULL); | ||
222 | } | 323 | } |
223 | return h; | 324 | if (NULL != (qe = dh->rq_head)) |
325 | { | ||
326 | dh->dns_transmit_handle = | ||
327 | GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, | ||
328 | ntohs (qe->msg->size), | ||
329 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
330 | GNUNET_NO, | ||
331 | &send_response, dh); | ||
332 | } | ||
333 | return len; | ||
334 | } | ||
335 | |||
336 | |||
337 | /** | ||
338 | * Add the given reply to our transmission queue and trigger sending if needed. | ||
339 | * | ||
340 | * @param dh handle with the connection | ||
341 | * @param qe reply to queue | ||
342 | */ | ||
343 | static void | ||
344 | queue_reply (struct GNUNET_DNS_Handle *dh, | ||
345 | struct ReplyQueueEntry *qe) | ||
346 | { | ||
347 | if (NULL == dh->dns_connection) | ||
348 | { | ||
349 | GNUNET_free (qe); | ||
350 | return; | ||
351 | } | ||
352 | GNUNET_CONTAINER_DLL_insert_tail (dh->rq_head, | ||
353 | dh->rq_tail, | ||
354 | qe); | ||
355 | if (NULL != dh->dns_transmit_handle) | ||
356 | return; | ||
357 | /* trigger sending */ | ||
358 | dh->dns_transmit_handle = | ||
359 | GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, | ||
360 | ntohs (dh->rq_head->msg->size), | ||
361 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
362 | GNUNET_NO, | ||
363 | &send_response, dh); | ||
224 | } | 364 | } |
225 | 365 | ||
226 | 366 | ||
367 | /** | ||
368 | * If a GNUNET_DNS_RequestHandler calls this function, the request is | ||
369 | * given to other clients or the global DNS for resolution. Once a | ||
370 | * global response has been obtained, the request handler is AGAIN | ||
371 | * called to give it a chance to observe and modify the response after | ||
372 | * the "normal" resolution. It is not legal for the request handler | ||
373 | * to call this function if a response is already present. | ||
374 | * | ||
375 | * @param rh request that should now be forwarded | ||
376 | */ | ||
227 | void | 377 | void |
228 | GNUNET_DNS_restart_hijack (struct GNUNET_DNS_Handle *h) | 378 | GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh) |
229 | { | 379 | { |
230 | h->restart_hijack = 1; | 380 | struct ReplyQueueEntry *qe; |
231 | if (NULL != h->dns_connection && h->dns_transmit_handle == NULL) | 381 | struct GNUNET_DNS_Response *resp; |
232 | h->dns_transmit_handle = | 382 | |
233 | GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, | 383 | GNUNET_assert (0 < rh->dh->pending_requests--); |
234 | sizeof (struct | 384 | if (rh->generation != rh->dh->generation) |
235 | GNUNET_MessageHeader), | 385 | { |
236 | GNUNET_TIME_UNIT_FOREVER_REL, | 386 | GNUNET_free (rh); |
237 | GNUNET_YES, &send_query, h); | 387 | return; |
388 | } | ||
389 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
390 | sizeof (struct GNUNET_DNS_Response)); | ||
391 | resp = (struct GNUNET_DNS_Response*) &qe[1]; | ||
392 | qe->msg = &resp->header; | ||
393 | resp->header.size = htons (sizeof (struct GNUNET_DNS_Response)); | ||
394 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); | ||
395 | resp->drop_flag = htonl (1); | ||
396 | resp->request_id = rh->request_id; | ||
397 | queue_reply (rh->dh, qe); | ||
398 | GNUNET_free (rh); | ||
238 | } | 399 | } |
239 | 400 | ||
240 | 401 | ||
241 | /** | 402 | /** |
242 | * FIXME: we should not expost our internal structures like this. | 403 | * If a GNUNET_DNS_RequestHandler calls this function, the request is |
243 | * Just a quick initial hack. | 404 | * to be dropped and no response should be generated. |
405 | * | ||
406 | * @param rh request that should now be dropped | ||
244 | */ | 407 | */ |
245 | static void | 408 | void |
246 | queue_request (struct GNUNET_DNS_Handle *h, | 409 | GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh) |
247 | struct query_packet_list *q) | ||
248 | { | 410 | { |
249 | GNUNET_CONTAINER_DLL_insert_tail (h->head, h->tail, q); | 411 | struct ReplyQueueEntry *qe; |
250 | if (h->dns_connection != NULL && h->dns_transmit_handle == NULL) | 412 | struct GNUNET_DNS_Response *resp; |
251 | h->dns_transmit_handle = | ||
252 | GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, ntohs(q->pkt.hdr.size), | ||
253 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
254 | GNUNET_YES, &send_query, | ||
255 | h); | ||
256 | } | ||
257 | 413 | ||
414 | GNUNET_assert (0 < rh->dh->pending_requests--); | ||
415 | if (rh->generation != rh->dh->generation) | ||
416 | { | ||
417 | GNUNET_free (rh); | ||
418 | return; | ||
419 | } | ||
420 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
421 | sizeof (struct GNUNET_DNS_Response)); | ||
422 | resp = (struct GNUNET_DNS_Response*) &qe[1]; | ||
423 | qe->msg = &resp->header; | ||
424 | resp->header.size = htons (sizeof (struct GNUNET_DNS_Response)); | ||
425 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); | ||
426 | resp->request_id = rh->request_id; | ||
427 | resp->drop_flag = htonl (0); | ||
428 | queue_reply (rh->dh, qe); | ||
429 | GNUNET_free (rh); | ||
430 | } | ||
258 | 431 | ||
259 | 432 | ||
260 | /** | 433 | /** |
261 | * Process a DNS request sent to an IPv4 resolver. Pass it | 434 | * If a GNUNET_DNS_RequestHandler calls this function, the request is |
262 | * to the DNS service for resolution. | 435 | * supposed to be answered with the data provided to this call (with |
436 | * the modifications the function might have made). | ||
263 | * | 437 | * |
264 | * @param h DNS handle | 438 | * @param rh request that should now be answered |
265 | * @param dst_ip destination IPv4 address | 439 | * @param reply_length size of reply (uint16_t to force sane size) |
266 | * @param src_ip source IPv4 address (usually local machine) | 440 | * @param reply reply data |
267 | * @param src_port source port (to be used for reply) | ||
268 | * @param udp_packet_len length of the UDP payload in bytes | ||
269 | * @param udp_packet UDP payload | ||
270 | */ | 441 | */ |
271 | void | 442 | void |
272 | GNUNET_DNS_queue_request_v4 (struct GNUNET_DNS_Handle *h, | 443 | GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh, |
273 | const struct in_addr *dst_ip, | 444 | uint16_t reply_length, |
274 | const struct in_addr *src_ip, | 445 | const char *reply) |
275 | uint16_t src_port, | ||
276 | size_t udp_packet_len, | ||
277 | const char *udp_packet) | ||
278 | { | 446 | { |
279 | size_t len = sizeof (struct query_packet) + udp_packet_len - 1; | 447 | struct ReplyQueueEntry *qe; |
280 | struct query_packet_list *query = | 448 | struct GNUNET_DNS_Response *resp; |
281 | GNUNET_malloc (len + sizeof (struct query_packet_list) - | 449 | |
282 | sizeof (struct query_packet)); | 450 | GNUNET_assert (0 < rh->dh->pending_requests--); |
283 | query->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_QUERY_DNS); | 451 | if (rh->generation != rh->dh->generation) |
284 | query->pkt.hdr.size = htons (len); | 452 | { |
285 | memcpy (query->pkt.orig_to, dst_ip, 4); | 453 | GNUNET_free (rh); |
286 | memcpy (query->pkt.orig_from, src_ip, 4); | 454 | return; |
287 | query->pkt.addrlen = 4; | 455 | } |
288 | query->pkt.src_port = htons (src_port); | 456 | if (reply_length + sizeof (struct GNUNET_DNS_Response) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) |
289 | memcpy (query->pkt.data, udp_packet, udp_packet_len); | 457 | { |
290 | queue_request (h, query); | 458 | GNUNET_break (0); |
459 | GNUNET_free (rh); | ||
460 | return; | ||
461 | } | ||
462 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
463 | sizeof (struct GNUNET_DNS_Response) + reply_length); | ||
464 | resp = (struct GNUNET_DNS_Response*) &qe[1]; | ||
465 | qe->msg = &resp->header; | ||
466 | resp->header.size = htons (sizeof (struct GNUNET_DNS_Response) + reply_length); | ||
467 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); | ||
468 | resp->drop_flag = htonl (2); | ||
469 | resp->request_id = rh->request_id; | ||
470 | memcpy (&resp[1], reply, reply_length); | ||
471 | queue_reply (rh->dh, qe); | ||
472 | GNUNET_free (rh); | ||
291 | } | 473 | } |
292 | 474 | ||
293 | 475 | ||
294 | /** | 476 | /** |
295 | * Process a DNS request sent to an IPv6 resolver. Pass it | 477 | * Connect to the service-dns |
296 | * to the DNS service for resolution. | ||
297 | * | 478 | * |
298 | * @param h DNS handle | 479 | * @param cfg configuration to use |
299 | * @param dst_ip destination IPv6 address | 480 | * @param flags when to call rh |
300 | * @param src_ip source IPv6 address (usually local machine) | 481 | * @param rh function to call with DNS requests |
301 | * @param src_port source port (to be used for reply) | 482 | * @param rh_cls closure to pass to rh |
302 | * @param udp_packet_len length of the UDP payload in bytes | 483 | * @return DNS handle |
303 | * @param udp_packet UDP payload | ||
304 | */ | 484 | */ |
305 | void | 485 | struct GNUNET_DNS_Handle * |
306 | GNUNET_DNS_queue_request_v6 (struct GNUNET_DNS_Handle *h, | 486 | GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, |
307 | const struct in6_addr *dst_ip, | 487 | enum GNUNET_DNS_Flags flags, |
308 | const struct in6_addr *src_ip, | 488 | GNUNET_DNS_RequestHandler rh, |
309 | uint16_t src_port, | 489 | void *rh_cls) |
310 | size_t udp_packet_len, | ||
311 | const char *udp_packet) | ||
312 | { | 490 | { |
313 | size_t len = | 491 | struct GNUNET_DNS_Handle *dh; |
314 | sizeof (struct query_packet) + udp_packet_len - 1; | 492 | |
315 | struct query_packet_list *query = | 493 | dh = GNUNET_malloc (sizeof (struct GNUNET_DNS_Handle)); |
316 | GNUNET_malloc (len + sizeof (struct query_packet_list) - | 494 | dh->cfg = cfg; |
317 | sizeof (struct answer_packet)); | 495 | dh->flags = flags; |
318 | query->pkt.hdr.type = | 496 | dh->rh = rh; |
319 | htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_QUERY_DNS); | 497 | dh->rh_cls = rh_cls; |
320 | query->pkt.hdr.size = htons (len); | 498 | dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); |
321 | memcpy (query->pkt.orig_to, dst_ip, 16); | 499 | return dh; |
322 | memcpy (query->pkt.orig_from, src_ip, 16); | ||
323 | query->pkt.addrlen = 16; | ||
324 | query->pkt.src_port = htons (src_port); | ||
325 | memcpy (query->pkt.data, udp_packet, | ||
326 | udp_packet_len); | ||
327 | queue_request (h, query); | ||
328 | } | 500 | } |
329 | 501 | ||
330 | 502 | ||
503 | /** | ||
504 | * Disconnect from the DNS service. | ||
505 | * | ||
506 | * @param dh DNS handle | ||
507 | */ | ||
331 | void | 508 | void |
332 | GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *h) | 509 | GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh) |
333 | { | 510 | { |
334 | if (h->dns_connection != NULL) | 511 | if (GNUNET_SCHEDULER_NO_TASK != dh->reconnect_task) |
335 | { | 512 | { |
336 | GNUNET_CLIENT_disconnect (h->dns_connection, GNUNET_NO); | 513 | GNUNET_SCHEDULER_cancel (dh->reconnect_task); |
337 | h->dns_connection = NULL; | 514 | dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; |
338 | } | 515 | } |
339 | GNUNET_free (h); | 516 | disconnect (dh); |
517 | /* make sure client has no pending requests left over! */ | ||
518 | GNUNET_assert (0 == dh->pending_requests); | ||
519 | GNUNET_free (dh); | ||
340 | } | 520 | } |
341 | 521 | ||
342 | /* end of dns_api.c */ | 522 | /* end of dns_api_new.c */ |
diff --git a/src/dns/dns_api_new.c b/src/dns/dns_api_new.c deleted file mode 100644 index 9e479fce7..000000000 --- a/src/dns/dns_api_new.c +++ /dev/null | |||
@@ -1,522 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2012 Christian Grothoff (and other contributing authors) | ||
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 2, 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., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file dns/dns_api_new.c | ||
23 | * @brief API to access the DNS service. | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_dns_service-new.h" | ||
28 | #include "dns_new.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * Reply to send to service. | ||
33 | */ | ||
34 | struct ReplyQueueEntry | ||
35 | { | ||
36 | /** | ||
37 | * Kept in DLL. | ||
38 | */ | ||
39 | struct ReplyQueueEntry *next; | ||
40 | |||
41 | /** | ||
42 | * Kept in DLL. | ||
43 | */ | ||
44 | struct ReplyQueueEntry *prev; | ||
45 | |||
46 | /** | ||
47 | * Message to transmit, allocated at the end of this struct. | ||
48 | */ | ||
49 | const struct GNUNET_MessageHeader *msg; | ||
50 | |||
51 | }; | ||
52 | |||
53 | |||
54 | /** | ||
55 | * Handle to identify an individual DNS request. | ||
56 | */ | ||
57 | struct GNUNET_DNS_RequestHandle | ||
58 | { | ||
59 | |||
60 | /** | ||
61 | * Handle to DNS API. | ||
62 | */ | ||
63 | struct GNUNET_DNS_Handle *dh; | ||
64 | |||
65 | /** | ||
66 | * Stored in network byte order (as for us, it is just a random number). | ||
67 | */ | ||
68 | uint64_t request_id; | ||
69 | |||
70 | /** | ||
71 | * Re-connect counter, to make sure we did not reconnect in the meantime. | ||
72 | */ | ||
73 | uint32_t generation; | ||
74 | |||
75 | }; | ||
76 | |||
77 | |||
78 | /** | ||
79 | * DNS handle | ||
80 | */ | ||
81 | struct GNUNET_DNS_Handle | ||
82 | { | ||
83 | |||
84 | /** | ||
85 | * Connection to DNS service, or NULL. | ||
86 | */ | ||
87 | struct GNUNET_CLIENT_Connection *dns_connection; | ||
88 | |||
89 | /** | ||
90 | * Handle to active transmission request, or NULL. | ||
91 | */ | ||
92 | struct GNUNET_CLIENT_TransmitHandle *dns_transmit_handle; | ||
93 | |||
94 | /** | ||
95 | * Configuration to use. | ||
96 | */ | ||
97 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
98 | |||
99 | /** | ||
100 | * Function to call to get replies. | ||
101 | */ | ||
102 | GNUNET_DNS_RequestHandler rh; | ||
103 | |||
104 | /** | ||
105 | * Closure for 'rh'. | ||
106 | */ | ||
107 | void *rh_cls; | ||
108 | |||
109 | /** | ||
110 | * Head of replies to transmit. | ||
111 | */ | ||
112 | struct ReplyQueueEntry *rq_head; | ||
113 | |||
114 | /** | ||
115 | * Tail of replies to transmit. | ||
116 | */ | ||
117 | struct ReplyQueueEntry *rq_tail; | ||
118 | |||
119 | /** | ||
120 | * Task to reconnect to the service. | ||
121 | */ | ||
122 | GNUNET_SCHEDULER_TaskIdentifier reconnect_task; | ||
123 | |||
124 | /** | ||
125 | * Re-connect counter, to make sure we did not reconnect in the meantime. | ||
126 | */ | ||
127 | uint32_t generation; | ||
128 | |||
129 | /** | ||
130 | * Flags for events we care about. | ||
131 | */ | ||
132 | enum GNUNET_DNS_Flags flags; | ||
133 | |||
134 | /** | ||
135 | * Did we start the receive loop yet? | ||
136 | */ | ||
137 | int in_receive; | ||
138 | |||
139 | /** | ||
140 | * Number of GNUNET_DNS_RequestHandles we have outstanding. Must be 0 before | ||
141 | * we can be disconnected. | ||
142 | */ | ||
143 | unsigned int pending_requests; | ||
144 | }; | ||
145 | |||
146 | |||
147 | /** | ||
148 | * Add the given reply to our transmission queue and trigger sending if needed. | ||
149 | * | ||
150 | * @param dh handle with the connection | ||
151 | * @param qe reply to queue | ||
152 | */ | ||
153 | static void | ||
154 | queue_reply (struct GNUNET_DNS_Handle *dh, | ||
155 | struct ReplyQueueEntry *qe); | ||
156 | |||
157 | |||
158 | /** | ||
159 | * Reconnect to the DNS service. | ||
160 | * | ||
161 | * @param cls handle with the connection to connect | ||
162 | * @param tc scheduler context (unused) | ||
163 | */ | ||
164 | static void | ||
165 | reconnect (void *cls, | ||
166 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
167 | { | ||
168 | struct GNUNET_DNS_Handle *dh = cls; | ||
169 | struct ReplyQueueEntry *qe; | ||
170 | struct GNUNET_DNS_Register *msg; | ||
171 | |||
172 | dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
173 | dh->dns_connection = GNUNET_CLIENT_connect ("dns", dh->cfg); | ||
174 | if (NULL == dh->dns_connection) | ||
175 | return; | ||
176 | dh->generation++; | ||
177 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
178 | sizeof (struct GNUNET_DNS_Register)); | ||
179 | msg = (struct GNUNET_DNS_Register*) &qe[1]; | ||
180 | qe->msg = &msg->header; | ||
181 | msg->header.size = htons (sizeof (struct GNUNET_DNS_Register)); | ||
182 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT); | ||
183 | msg->flags = htonl (dh->flags); | ||
184 | queue_reply (dh, qe); | ||
185 | } | ||
186 | |||
187 | |||
188 | /** | ||
189 | * Disconnect from the DNS service. | ||
190 | * | ||
191 | * @param dh handle with the connection to disconnect | ||
192 | */ | ||
193 | static void | ||
194 | disconnect (struct GNUNET_DNS_Handle *dh) | ||
195 | { | ||
196 | struct ReplyQueueEntry *qe; | ||
197 | |||
198 | if (NULL != dh->dns_transmit_handle) | ||
199 | { | ||
200 | GNUNET_CLIENT_notify_transmit_ready_cancel (dh->dns_transmit_handle); | ||
201 | dh->dns_transmit_handle = NULL; | ||
202 | } | ||
203 | if (NULL != dh->dns_connection) | ||
204 | { | ||
205 | GNUNET_CLIENT_disconnect (dh->dns_connection, GNUNET_NO); | ||
206 | dh->dns_connection = NULL; | ||
207 | } | ||
208 | while (NULL != (qe = dh->rq_head)) | ||
209 | { | ||
210 | GNUNET_CONTAINER_DLL_remove (dh->rq_head, | ||
211 | dh->rq_tail, | ||
212 | qe); | ||
213 | GNUNET_free (qe); | ||
214 | } | ||
215 | dh->in_receive = GNUNET_NO; | ||
216 | } | ||
217 | |||
218 | |||
219 | /** | ||
220 | * This receives packets from the DNS service and calls the application to | ||
221 | * handle it. | ||
222 | * | ||
223 | * @param cls the struct GNUNET_DNS_Handle | ||
224 | * @param msg message from the service (request) | ||
225 | */ | ||
226 | static void | ||
227 | request_handler (void *cls, | ||
228 | const struct GNUNET_MessageHeader *msg) | ||
229 | { | ||
230 | struct GNUNET_DNS_Handle *dh = cls; | ||
231 | const struct GNUNET_DNS_Request *req; | ||
232 | struct GNUNET_DNS_RequestHandle *rh; | ||
233 | size_t payload_length; | ||
234 | |||
235 | /* the service disconnected, reconnect after short wait */ | ||
236 | if (msg == NULL) | ||
237 | { | ||
238 | disconnect (dh); | ||
239 | dh->reconnect_task = | ||
240 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
241 | &reconnect, dh); | ||
242 | return; | ||
243 | } | ||
244 | if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST) || | ||
245 | (ntohs (msg->size) < sizeof (struct GNUNET_DNS_Request)) ) | ||
246 | { | ||
247 | /* the service did something strange, reconnect immediately */ | ||
248 | GNUNET_break (0); | ||
249 | disconnect (dh); | ||
250 | dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); | ||
251 | return; | ||
252 | } | ||
253 | req = (const struct GNUNET_DNS_Request *) msg; | ||
254 | GNUNET_break (ntohl (req->reserved) == 0); | ||
255 | payload_length = ntohs (req->header.size) - sizeof (struct GNUNET_DNS_Request); | ||
256 | GNUNET_CLIENT_receive (dh->dns_connection, | ||
257 | &request_handler, dh, | ||
258 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
259 | |||
260 | /* finally, pass request to callback for answers */ | ||
261 | rh = GNUNET_malloc (sizeof (struct GNUNET_DNS_RequestHandle)); | ||
262 | rh->dh =dh; | ||
263 | rh->request_id = req->request_id; | ||
264 | rh->generation = dh->generation; | ||
265 | dh->pending_requests++; | ||
266 | dh->rh (dh->rh_cls, | ||
267 | rh, | ||
268 | payload_length, | ||
269 | (const char*) &req[1]); | ||
270 | } | ||
271 | |||
272 | |||
273 | /** | ||
274 | * Callback called by notify_transmit_ready; sends DNS replies | ||
275 | * to the DNS service. | ||
276 | * | ||
277 | * @param cls the struct GNUNET_DNS_Handle | ||
278 | * @param size number of bytes available in buf | ||
279 | * @param buf where to copy the message for transmission | ||
280 | * @return number of bytes copied to buf | ||
281 | */ | ||
282 | static size_t | ||
283 | send_response (void *cls, size_t size, void *buf) | ||
284 | { | ||
285 | struct GNUNET_DNS_Handle *dh = cls; | ||
286 | struct ReplyQueueEntry *qe; | ||
287 | size_t len; | ||
288 | |||
289 | dh->dns_transmit_handle = NULL; | ||
290 | if (NULL == buf) | ||
291 | { | ||
292 | disconnect (dh); | ||
293 | dh->reconnect_task = | ||
294 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
295 | &reconnect, dh); | ||
296 | return 0; | ||
297 | } | ||
298 | qe = dh->rq_head; | ||
299 | if (NULL == qe) | ||
300 | return 0; | ||
301 | len = ntohs (qe->msg->size); | ||
302 | if (len > size) | ||
303 | { | ||
304 | dh->dns_transmit_handle = | ||
305 | GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, | ||
306 | len, | ||
307 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
308 | GNUNET_NO, | ||
309 | &send_response, dh); | ||
310 | return 0; | ||
311 | } | ||
312 | memcpy (buf, qe->msg, len); | ||
313 | GNUNET_CONTAINER_DLL_remove (dh->rq_head, | ||
314 | dh->rq_tail, | ||
315 | qe); | ||
316 | GNUNET_free (qe); | ||
317 | if (GNUNET_NO == dh->in_receive) | ||
318 | { | ||
319 | dh->in_receive = GNUNET_YES; | ||
320 | GNUNET_CLIENT_receive (dh->dns_connection, | ||
321 | &request_handler, dh, | ||
322 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
323 | } | ||
324 | if (NULL != (qe = dh->rq_head)) | ||
325 | { | ||
326 | dh->dns_transmit_handle = | ||
327 | GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, | ||
328 | ntohs (qe->msg->size), | ||
329 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
330 | GNUNET_NO, | ||
331 | &send_response, dh); | ||
332 | } | ||
333 | return len; | ||
334 | } | ||
335 | |||
336 | |||
337 | /** | ||
338 | * Add the given reply to our transmission queue and trigger sending if needed. | ||
339 | * | ||
340 | * @param dh handle with the connection | ||
341 | * @param qe reply to queue | ||
342 | */ | ||
343 | static void | ||
344 | queue_reply (struct GNUNET_DNS_Handle *dh, | ||
345 | struct ReplyQueueEntry *qe) | ||
346 | { | ||
347 | if (NULL == dh->dns_connection) | ||
348 | { | ||
349 | GNUNET_free (qe); | ||
350 | return; | ||
351 | } | ||
352 | GNUNET_CONTAINER_DLL_insert_tail (dh->rq_head, | ||
353 | dh->rq_tail, | ||
354 | qe); | ||
355 | if (NULL != dh->dns_transmit_handle) | ||
356 | return; | ||
357 | /* trigger sending */ | ||
358 | dh->dns_transmit_handle = | ||
359 | GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, | ||
360 | ntohs (dh->rq_head->msg->size), | ||
361 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
362 | GNUNET_NO, | ||
363 | &send_response, dh); | ||
364 | } | ||
365 | |||
366 | |||
367 | /** | ||
368 | * If a GNUNET_DNS_RequestHandler calls this function, the request is | ||
369 | * given to other clients or the global DNS for resolution. Once a | ||
370 | * global response has been obtained, the request handler is AGAIN | ||
371 | * called to give it a chance to observe and modify the response after | ||
372 | * the "normal" resolution. It is not legal for the request handler | ||
373 | * to call this function if a response is already present. | ||
374 | * | ||
375 | * @param rh request that should now be forwarded | ||
376 | */ | ||
377 | void | ||
378 | GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh) | ||
379 | { | ||
380 | struct ReplyQueueEntry *qe; | ||
381 | struct GNUNET_DNS_Response *resp; | ||
382 | |||
383 | GNUNET_assert (0 < rh->dh->pending_requests--); | ||
384 | if (rh->generation != rh->dh->generation) | ||
385 | { | ||
386 | GNUNET_free (rh); | ||
387 | return; | ||
388 | } | ||
389 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
390 | sizeof (struct GNUNET_DNS_Response)); | ||
391 | resp = (struct GNUNET_DNS_Response*) &qe[1]; | ||
392 | qe->msg = &resp->header; | ||
393 | resp->header.size = htons (sizeof (struct GNUNET_DNS_Response)); | ||
394 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); | ||
395 | resp->drop_flag = htonl (1); | ||
396 | resp->request_id = rh->request_id; | ||
397 | queue_reply (rh->dh, qe); | ||
398 | GNUNET_free (rh); | ||
399 | } | ||
400 | |||
401 | |||
402 | /** | ||
403 | * If a GNUNET_DNS_RequestHandler calls this function, the request is | ||
404 | * to be dropped and no response should be generated. | ||
405 | * | ||
406 | * @param rh request that should now be dropped | ||
407 | */ | ||
408 | void | ||
409 | GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh) | ||
410 | { | ||
411 | struct ReplyQueueEntry *qe; | ||
412 | struct GNUNET_DNS_Response *resp; | ||
413 | |||
414 | GNUNET_assert (0 < rh->dh->pending_requests--); | ||
415 | if (rh->generation != rh->dh->generation) | ||
416 | { | ||
417 | GNUNET_free (rh); | ||
418 | return; | ||
419 | } | ||
420 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
421 | sizeof (struct GNUNET_DNS_Response)); | ||
422 | resp = (struct GNUNET_DNS_Response*) &qe[1]; | ||
423 | qe->msg = &resp->header; | ||
424 | resp->header.size = htons (sizeof (struct GNUNET_DNS_Response)); | ||
425 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); | ||
426 | resp->request_id = rh->request_id; | ||
427 | resp->drop_flag = htonl (0); | ||
428 | queue_reply (rh->dh, qe); | ||
429 | GNUNET_free (rh); | ||
430 | } | ||
431 | |||
432 | |||
433 | /** | ||
434 | * If a GNUNET_DNS_RequestHandler calls this function, the request is | ||
435 | * supposed to be answered with the data provided to this call (with | ||
436 | * the modifications the function might have made). | ||
437 | * | ||
438 | * @param rh request that should now be answered | ||
439 | * @param reply_length size of reply (uint16_t to force sane size) | ||
440 | * @param reply reply data | ||
441 | */ | ||
442 | void | ||
443 | GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh, | ||
444 | uint16_t reply_length, | ||
445 | const char *reply) | ||
446 | { | ||
447 | struct ReplyQueueEntry *qe; | ||
448 | struct GNUNET_DNS_Response *resp; | ||
449 | |||
450 | GNUNET_assert (0 < rh->dh->pending_requests--); | ||
451 | if (rh->generation != rh->dh->generation) | ||
452 | { | ||
453 | GNUNET_free (rh); | ||
454 | return; | ||
455 | } | ||
456 | if (reply_length + sizeof (struct GNUNET_DNS_Response) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
457 | { | ||
458 | GNUNET_break (0); | ||
459 | GNUNET_free (rh); | ||
460 | return; | ||
461 | } | ||
462 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
463 | sizeof (struct GNUNET_DNS_Response) + reply_length); | ||
464 | resp = (struct GNUNET_DNS_Response*) &qe[1]; | ||
465 | qe->msg = &resp->header; | ||
466 | resp->header.size = htons (sizeof (struct GNUNET_DNS_Response) + reply_length); | ||
467 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); | ||
468 | resp->drop_flag = htonl (2); | ||
469 | resp->request_id = rh->request_id; | ||
470 | memcpy (&resp[1], reply, reply_length); | ||
471 | queue_reply (rh->dh, qe); | ||
472 | GNUNET_free (rh); | ||
473 | } | ||
474 | |||
475 | |||
476 | /** | ||
477 | * Connect to the service-dns | ||
478 | * | ||
479 | * @param cfg configuration to use | ||
480 | * @param flags when to call rh | ||
481 | * @param rh function to call with DNS requests | ||
482 | * @param rh_cls closure to pass to rh | ||
483 | * @return DNS handle | ||
484 | */ | ||
485 | struct GNUNET_DNS_Handle * | ||
486 | GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
487 | enum GNUNET_DNS_Flags flags, | ||
488 | GNUNET_DNS_RequestHandler rh, | ||
489 | void *rh_cls) | ||
490 | { | ||
491 | struct GNUNET_DNS_Handle *dh; | ||
492 | |||
493 | dh = GNUNET_malloc (sizeof (struct GNUNET_DNS_Handle)); | ||
494 | dh->cfg = cfg; | ||
495 | dh->flags = flags; | ||
496 | dh->rh = rh; | ||
497 | dh->rh_cls = rh_cls; | ||
498 | dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); | ||
499 | return dh; | ||
500 | } | ||
501 | |||
502 | |||
503 | /** | ||
504 | * Disconnect from the DNS service. | ||
505 | * | ||
506 | * @param dh DNS handle | ||
507 | */ | ||
508 | void | ||
509 | GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh) | ||
510 | { | ||
511 | if (GNUNET_SCHEDULER_NO_TASK != dh->reconnect_task) | ||
512 | { | ||
513 | GNUNET_SCHEDULER_cancel (dh->reconnect_task); | ||
514 | dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
515 | } | ||
516 | disconnect (dh); | ||
517 | /* make sure client has no pending requests left over! */ | ||
518 | GNUNET_assert (0 == dh->pending_requests); | ||
519 | GNUNET_free (dh); | ||
520 | } | ||
521 | |||
522 | /* end of dns_api_new.c */ | ||
diff --git a/src/dns/dns_new.h b/src/dns/dns_new.h deleted file mode 100644 index 29a9f937b..000000000 --- a/src/dns/dns_new.h +++ /dev/null | |||
@@ -1,101 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2012 Christian Grothoff (and other contributing authors) | ||
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 2, 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., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file dns/dns_new.h | ||
23 | * @brief IPC messages between DNS API and DNS service | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef DNS_NEW_H | ||
27 | #define DNS_NEW_H | ||
28 | |||
29 | GNUNET_NETWORK_STRUCT_BEGIN | ||
30 | |||
31 | |||
32 | /** | ||
33 | * Message from client to DNS service to register itself. | ||
34 | */ | ||
35 | struct GNUNET_DNS_Register | ||
36 | { | ||
37 | /** | ||
38 | * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT | ||
39 | */ | ||
40 | struct GNUNET_MessageHeader header; | ||
41 | |||
42 | /** | ||
43 | * NBO encoding of 'enum GNUNET_DNS_Flags' for the client. | ||
44 | */ | ||
45 | uint32_t flags; | ||
46 | }; | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Message from DNS service to client: please handle a request. | ||
51 | */ | ||
52 | struct GNUNET_DNS_Request | ||
53 | { | ||
54 | /** | ||
55 | * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST | ||
56 | */ | ||
57 | struct GNUNET_MessageHeader header; | ||
58 | |||
59 | /** | ||
60 | * Always zero. | ||
61 | */ | ||
62 | uint32_t reserved GNUNET_PACKED; | ||
63 | |||
64 | /** | ||
65 | * Unique request ID. | ||
66 | */ | ||
67 | uint64_t request_id GNUNET_PACKED; | ||
68 | |||
69 | /* followed by original DNS request (without UDP header) */ | ||
70 | |||
71 | }; | ||
72 | |||
73 | |||
74 | /** | ||
75 | * Message from client to DNS service: here is my reply. | ||
76 | */ | ||
77 | struct GNUNET_DNS_Response | ||
78 | { | ||
79 | /** | ||
80 | * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE | ||
81 | */ | ||
82 | struct GNUNET_MessageHeader header; | ||
83 | |||
84 | /** | ||
85 | * Zero to drop, 1 for no change (no payload), 2 for update (message has payload). | ||
86 | */ | ||
87 | uint32_t drop_flag GNUNET_PACKED; | ||
88 | |||
89 | /** | ||
90 | * Unique request ID. | ||
91 | */ | ||
92 | uint64_t request_id GNUNET_PACKED; | ||
93 | |||
94 | /* followed by original DNS request (without UDP header) */ | ||
95 | |||
96 | }; | ||
97 | |||
98 | |||
99 | GNUNET_NETWORK_STRUCT_END | ||
100 | |||
101 | #endif | ||
diff --git a/src/dns/dnsparser.c b/src/dns/dnsparser.c index 2e9e73f1c..12253a2e7 100644 --- a/src/dns/dnsparser.c +++ b/src/dns/dnsparser.c | |||
@@ -793,331 +793,4 @@ GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p, | |||
793 | return GNUNET_OK; | 793 | return GNUNET_OK; |
794 | } | 794 | } |
795 | 795 | ||
796 | 796 | /* end of dnsparser.c */ | |
797 | |||
798 | |||
799 | |||
800 | |||
801 | |||
802 | |||
803 | |||
804 | |||
805 | |||
806 | |||
807 | |||
808 | |||
809 | |||
810 | |||
811 | |||
812 | |||
813 | |||
814 | |||
815 | |||
816 | |||
817 | |||
818 | |||
819 | |||
820 | |||
821 | |||
822 | |||
823 | |||
824 | |||
825 | /* legacy code follows */ | ||
826 | |||
827 | /** | ||
828 | * Parse a name from DNS to a normal .-delimited, 0-terminated string. | ||
829 | * | ||
830 | * @param d The destination of the name. Should have at least 255 bytes allocated. | ||
831 | * @param src The DNS-Packet | ||
832 | * @param idx The offset inside the Packet from which on the name should be read | ||
833 | * @returns The offset of the first unparsed byte (the byte right behind the name) | ||
834 | */ | ||
835 | static unsigned int | ||
836 | parse_dns_name (char *d, const unsigned char *src, unsigned short idx) | ||
837 | { /*{{{ */ | ||
838 | char *dest = d; | ||
839 | |||
840 | int len = src[idx++]; | ||
841 | |||
842 | while (len != 0) | ||
843 | { | ||
844 | if (len & 0xC0) | ||
845 | { /* Compressed name, offset in this and the next octet */ | ||
846 | unsigned short offset = ((len & 0x3F) << 8) | src[idx++]; | ||
847 | |||
848 | parse_dns_name (dest, src, offset - 12); /* 12 for the Header of the DNS-Packet, idx starts at 0 which is 12 bytes from the start of the packet */ | ||
849 | return idx; | ||
850 | } | ||
851 | memcpy (dest, src + idx, len); | ||
852 | idx += len; | ||
853 | dest += len; | ||
854 | *dest = '.'; | ||
855 | dest++; | ||
856 | len = src[idx++]; | ||
857 | }; | ||
858 | *dest = 0; | ||
859 | |||
860 | return idx; | ||
861 | } | ||
862 | |||
863 | /*}}}*/ | ||
864 | |||
865 | /** | ||
866 | * Parse a complete DNS-Record from raw DNS-data to a struct dns_record | ||
867 | * | ||
868 | * @param data The DNS-data | ||
869 | * @param dst Pointer to count pointers; individual pointers will be allocated | ||
870 | * @param count Number of records to parse | ||
871 | * @param idx The offset inside the Packet from which on the name should be read | ||
872 | * @returns The offset of the first unparsed byte (the byte right behind the last record) | ||
873 | */ | ||
874 | static unsigned short | ||
875 | parse_dns_record (unsigned char *data, /*{{{ */ | ||
876 | struct dns_record **dst, unsigned short count, | ||
877 | unsigned short idx) | ||
878 | { | ||
879 | int i; | ||
880 | unsigned short _idx; | ||
881 | |||
882 | for (i = 0; i < count; i++) | ||
883 | { | ||
884 | dst[i] = GNUNET_malloc (sizeof (struct dns_record)); | ||
885 | dst[i]->name = alloca (255); // see RFC1035, no name can be longer than this. | ||
886 | char *name = dst[i]->name; | ||
887 | |||
888 | _idx = parse_dns_name (name, data, idx); | ||
889 | dst[i]->namelen = _idx - idx; | ||
890 | |||
891 | dst[i]->name = GNUNET_malloc (dst[i]->namelen); | ||
892 | memcpy (dst[i]->name, name, dst[i]->namelen); | ||
893 | |||
894 | idx = _idx; | ||
895 | |||
896 | dst[i]->type = *((unsigned short *) (data + idx)); | ||
897 | idx += 2; | ||
898 | dst[i]->class = *((unsigned short *) (data + idx)); | ||
899 | idx += 2; | ||
900 | dst[i]->ttl = *((unsigned int *) (data + idx)); | ||
901 | idx += 4; | ||
902 | dst[i]->data_len = *((unsigned short *) (data + idx)); | ||
903 | idx += 2; | ||
904 | dst[i]->data = GNUNET_malloc (ntohs (dst[i]->data_len)); | ||
905 | memcpy (dst[i]->data, data + idx, ntohs (dst[i]->data_len)); | ||
906 | idx += ntohs (dst[i]->data_len); | ||
907 | } | ||
908 | return idx; | ||
909 | } /*}}} */ | ||
910 | |||
911 | /** | ||
912 | * Parse a raw DNS-Packet into an usable struct | ||
913 | */ | ||
914 | struct dns_pkt_parsed * | ||
915 | parse_dns_packet (struct dns_pkt *pkt) | ||
916 | { /*{{{ */ | ||
917 | struct dns_pkt_parsed *ppkt = GNUNET_malloc (sizeof (struct dns_pkt_parsed)); | ||
918 | |||
919 | memcpy (&ppkt->s, &pkt->s, sizeof pkt->s); | ||
920 | |||
921 | unsigned short qdcount = ntohs (ppkt->s.qdcount); | ||
922 | unsigned short ancount = ntohs (ppkt->s.ancount); | ||
923 | unsigned short nscount = ntohs (ppkt->s.nscount); | ||
924 | unsigned short arcount = ntohs (ppkt->s.arcount); | ||
925 | |||
926 | ppkt->queries = GNUNET_malloc (qdcount * sizeof (struct dns_query *)); | ||
927 | ppkt->answers = GNUNET_malloc (ancount * sizeof (struct dns_record *)); | ||
928 | ppkt->nameservers = GNUNET_malloc (nscount * sizeof (struct dns_record *)); | ||
929 | ppkt->additional = GNUNET_malloc (arcount * sizeof (struct dns_record *)); | ||
930 | |||
931 | unsigned short idx = 0, _idx; /* This keeps track how far we have parsed the data */ | ||
932 | |||
933 | /* Parse the Query */ | ||
934 | int i; | ||
935 | |||
936 | for (i = 0; i < qdcount; i++) | ||
937 | { /*{{{ */ | ||
938 | ppkt->queries[i] = GNUNET_malloc (sizeof (struct dns_query)); | ||
939 | char *name = alloca (255); /* see RFC1035, it can't be more than this. */ | ||
940 | |||
941 | _idx = parse_dns_name (name, pkt->data, idx); | ||
942 | ppkt->queries[i]->namelen = _idx - idx; | ||
943 | idx = _idx; | ||
944 | |||
945 | ppkt->queries[i]->name = GNUNET_malloc (ppkt->queries[i]->namelen); | ||
946 | memcpy (ppkt->queries[i]->name, name, ppkt->queries[i]->namelen); | ||
947 | |||
948 | ppkt->queries[i]->qtype = *((unsigned short *) (pkt->data + idx)); | ||
949 | idx += 2; | ||
950 | ppkt->queries[i]->qclass = *((unsigned short *) (pkt->data + idx)); | ||
951 | idx += 2; | ||
952 | } | ||
953 | /*}}} */ | ||
954 | idx = parse_dns_record (pkt->data, ppkt->answers, ancount, idx); | ||
955 | idx = parse_dns_record (pkt->data, ppkt->nameservers, nscount, idx); | ||
956 | idx = parse_dns_record (pkt->data, ppkt->additional, arcount, idx); | ||
957 | return ppkt; | ||
958 | } /*}}} */ | ||
959 | |||
960 | static void | ||
961 | unparse_dns_name (char *dest, char *src, size_t len) | ||
962 | { | ||
963 | char *b = dest; | ||
964 | char cnt = 0; | ||
965 | |||
966 | dest++; | ||
967 | while (*src != 0) | ||
968 | { | ||
969 | while (*src != '.' && *src != 0) | ||
970 | { | ||
971 | *dest = *src; | ||
972 | src++; | ||
973 | dest++; | ||
974 | cnt++; | ||
975 | } | ||
976 | *b = cnt; | ||
977 | cnt = 0; | ||
978 | b = dest; | ||
979 | dest++; | ||
980 | src++; | ||
981 | } | ||
982 | *b = 0; | ||
983 | } | ||
984 | |||
985 | struct dns_pkt * | ||
986 | unparse_dns_packet (struct dns_pkt_parsed *ppkt) | ||
987 | { | ||
988 | size_t size = sizeof (struct dns_pkt) - 1; | ||
989 | int i; | ||
990 | |||
991 | for (i = 0; i < ntohs (ppkt->s.qdcount); i++) | ||
992 | size += ppkt->queries[i]->namelen + 1; | ||
993 | |||
994 | for (i = 0; i < ntohs (ppkt->s.ancount); i++) | ||
995 | { | ||
996 | size += ppkt->answers[i]->namelen + 1; | ||
997 | size += ppkt->answers[i]->data_len; | ||
998 | } | ||
999 | for (i = 0; i < ntohs (ppkt->s.nscount); i++) | ||
1000 | { | ||
1001 | size += ppkt->nameservers[i]->namelen + 1; | ||
1002 | size += ppkt->nameservers[i]->data_len; | ||
1003 | } | ||
1004 | for (i = 0; i < ntohs (ppkt->s.arcount); i++) | ||
1005 | { | ||
1006 | size += ppkt->additional[i]->namelen + 1; | ||
1007 | size += ppkt->additional[i]->data_len; | ||
1008 | } | ||
1009 | |||
1010 | size += | ||
1011 | 4 * ntohs (ppkt->s.qdcount) + 10 * (ntohs (ppkt->s.ancount) + | ||
1012 | ntohs (ppkt->s.arcount) + | ||
1013 | ntohs (ppkt->s.nscount)); | ||
1014 | |||
1015 | struct dns_pkt *pkt = GNUNET_malloc (size); | ||
1016 | char *pkt_c = (char *) pkt; | ||
1017 | |||
1018 | memcpy (&pkt->s, &ppkt->s, sizeof ppkt->s); | ||
1019 | size_t idx = sizeof ppkt->s; | ||
1020 | |||
1021 | for (i = 0; i < ntohs (ppkt->s.qdcount); i++) | ||
1022 | { | ||
1023 | unparse_dns_name (&pkt_c[idx], ppkt->queries[i]->name, | ||
1024 | ppkt->queries[i]->namelen); | ||
1025 | idx += ppkt->queries[i]->namelen; | ||
1026 | struct dns_query_line *d = (struct dns_query_line *) &pkt_c[idx]; | ||
1027 | |||
1028 | d->class = ppkt->queries[i]->qclass; | ||
1029 | d->type = ppkt->queries[i]->qtype; | ||
1030 | idx += sizeof (struct dns_query_line); | ||
1031 | } | ||
1032 | |||
1033 | for (i = 0; i < ntohs (ppkt->s.ancount); i++) | ||
1034 | { | ||
1035 | unparse_dns_name (&pkt_c[idx], ppkt->answers[i]->name, | ||
1036 | ppkt->answers[i]->namelen); | ||
1037 | idx += ppkt->answers[i]->namelen; | ||
1038 | struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx]; | ||
1039 | |||
1040 | r->type = ppkt->answers[i]->type; | ||
1041 | r->class = ppkt->answers[i]->class; | ||
1042 | r->ttl = ppkt->answers[i]->ttl; | ||
1043 | r->data_len = ppkt->answers[i]->data_len; | ||
1044 | idx += sizeof (struct dns_record_line); | ||
1045 | memcpy (&r->data, ppkt->answers[i]->data, ppkt->answers[i]->data_len); | ||
1046 | idx += ppkt->answers[i]->data_len; | ||
1047 | } | ||
1048 | |||
1049 | for (i = 0; i < ntohs (ppkt->s.nscount); i++) | ||
1050 | { | ||
1051 | unparse_dns_name (&pkt_c[idx], ppkt->nameservers[i]->name, | ||
1052 | ppkt->nameservers[i]->namelen); | ||
1053 | idx += ppkt->nameservers[i]->namelen; | ||
1054 | struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx]; | ||
1055 | |||
1056 | r->type = ppkt->nameservers[i]->type; | ||
1057 | r->class = ppkt->nameservers[i]->class; | ||
1058 | r->ttl = ppkt->nameservers[i]->ttl; | ||
1059 | r->data_len = ppkt->nameservers[i]->data_len; | ||
1060 | idx += sizeof (struct dns_record_line); | ||
1061 | memcpy (&r->data, ppkt->nameservers[i]->data, | ||
1062 | ppkt->nameservers[i]->data_len); | ||
1063 | idx += ppkt->nameservers[i]->data_len; | ||
1064 | } | ||
1065 | |||
1066 | for (i = 0; i < ntohs (ppkt->s.arcount); i++) | ||
1067 | { | ||
1068 | unparse_dns_name (&pkt_c[idx], ppkt->additional[i]->name, | ||
1069 | ppkt->additional[i]->namelen); | ||
1070 | idx += ppkt->additional[i]->namelen; | ||
1071 | struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx]; | ||
1072 | |||
1073 | r->type = ppkt->additional[i]->type; | ||
1074 | r->class = ppkt->additional[i]->class; | ||
1075 | r->ttl = ppkt->additional[i]->ttl; | ||
1076 | r->data_len = ppkt->additional[i]->data_len; | ||
1077 | idx += sizeof (struct dns_record_line); | ||
1078 | memcpy (&r->data, ppkt->additional[i]->data, ppkt->additional[i]->data_len); | ||
1079 | idx += ppkt->additional[i]->data_len; | ||
1080 | } | ||
1081 | |||
1082 | return pkt; | ||
1083 | } | ||
1084 | |||
1085 | void | ||
1086 | free_parsed_dns_packet (struct dns_pkt_parsed *ppkt) | ||
1087 | { | ||
1088 | unsigned short qdcount = ntohs (ppkt->s.qdcount); | ||
1089 | unsigned short ancount = ntohs (ppkt->s.ancount); | ||
1090 | unsigned short nscount = ntohs (ppkt->s.nscount); | ||
1091 | unsigned short arcount = ntohs (ppkt->s.arcount); | ||
1092 | |||
1093 | int i; | ||
1094 | |||
1095 | for (i = 0; i < qdcount; i++) | ||
1096 | { | ||
1097 | GNUNET_free (ppkt->queries[i]->name); | ||
1098 | GNUNET_free (ppkt->queries[i]); | ||
1099 | } | ||
1100 | GNUNET_free (ppkt->queries); | ||
1101 | for (i = 0; i < ancount; i++) | ||
1102 | { | ||
1103 | GNUNET_free (ppkt->answers[i]->name); | ||
1104 | GNUNET_free (ppkt->answers[i]->data); | ||
1105 | GNUNET_free (ppkt->answers[i]); | ||
1106 | } | ||
1107 | GNUNET_free (ppkt->answers); | ||
1108 | for (i = 0; i < nscount; i++) | ||
1109 | { | ||
1110 | GNUNET_free (ppkt->nameservers[i]->name); | ||
1111 | GNUNET_free (ppkt->nameservers[i]->data); | ||
1112 | GNUNET_free (ppkt->nameservers[i]); | ||
1113 | } | ||
1114 | GNUNET_free (ppkt->nameservers); | ||
1115 | for (i = 0; i < arcount; i++) | ||
1116 | { | ||
1117 | GNUNET_free (ppkt->additional[i]->name); | ||
1118 | GNUNET_free (ppkt->additional[i]->data); | ||
1119 | GNUNET_free (ppkt->additional[i]); | ||
1120 | } | ||
1121 | GNUNET_free (ppkt->additional); | ||
1122 | GNUNET_free (ppkt); | ||
1123 | } | ||
diff --git a/src/dns/gnunet-dns-monitor.c b/src/dns/gnunet-dns-monitor.c index 9e86f9c2d..3c7f31985 100644 --- a/src/dns/gnunet-dns-monitor.c +++ b/src/dns/gnunet-dns-monitor.c | |||
@@ -26,7 +26,7 @@ | |||
26 | 26 | ||
27 | #include "platform.h" | 27 | #include "platform.h" |
28 | #include "gnunet_util_lib.h" | 28 | #include "gnunet_util_lib.h" |
29 | #include "gnunet_dns_service-new.h" | 29 | #include "gnunet_dns_service.h" |
30 | #include "gnunet_dnsparser_lib.h" | 30 | #include "gnunet_dnsparser_lib.h" |
31 | 31 | ||
32 | /** | 32 | /** |
diff --git a/src/dns/gnunet-dns-redirector.c b/src/dns/gnunet-dns-redirector.c index 4eabc8c79..41667ee9f 100644 --- a/src/dns/gnunet-dns-redirector.c +++ b/src/dns/gnunet-dns-redirector.c | |||
@@ -26,7 +26,7 @@ | |||
26 | 26 | ||
27 | #include "platform.h" | 27 | #include "platform.h" |
28 | #include "gnunet_util_lib.h" | 28 | #include "gnunet_util_lib.h" |
29 | #include "gnunet_dns_service-new.h" | 29 | #include "gnunet_dns_service.h" |
30 | #include "gnunet_dnsparser_lib.h" | 30 | #include "gnunet_dnsparser_lib.h" |
31 | 31 | ||
32 | /** | 32 | /** |
diff --git a/src/dns/gnunet-helper-hijack-dns.c b/src/dns/gnunet-helper-hijack-dns.c deleted file mode 100644 index 833bda8ad..000000000 --- a/src/dns/gnunet-helper-hijack-dns.c +++ /dev/null | |||
@@ -1,328 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2010, 2011, 2012 Christian Grothoff | ||
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., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file dns/gnunet-helper-hijack-dns.c | ||
23 | * @brief helper to install firewall rules to hijack all DNS traffic | ||
24 | * and send it to our virtual interface except for DNS traffic | ||
25 | * that originates on the specified port. | ||
26 | * @author Philipp Tölke | ||
27 | * @author Christian Grothoff | ||
28 | * | ||
29 | * This program alters the Linux firewall rules so that DNS traffic | ||
30 | * that ordinarily exits the system can be intercepted and managed by | ||
31 | * a virtual interface. In order to achieve this, DNS traffic is | ||
32 | * marked with the DNS_MARK given in below and re-routed to a custom | ||
33 | * table with the DNS_TABLE ID given below. Systems and | ||
34 | * administrators must take care to not cause conflicts with these | ||
35 | * values (it was deemed safest to hardcode them as passing these | ||
36 | * values as arguments might permit messing with arbitrary firewall | ||
37 | * rules, which would be dangerous). | ||
38 | * | ||
39 | * Note that having this binary SUID is only partially safe: it will | ||
40 | * allow redirecting (and intercepting / mangling) of all DNS traffic | ||
41 | * originating from this system by any user who can create a virtual | ||
42 | * interface (and this is again enabled by other GNUnet SUID | ||
43 | * binaries). Furthermore, even without the ability to create a | ||
44 | * tunnel interface, this code will make it possible to DoS all DNS | ||
45 | * traffic originating from the current system, simply by sending it | ||
46 | * to nowhere. | ||
47 | * | ||
48 | * Naturally, neither of these problems can be helped as this is the | ||
49 | * fundamental purpose of the binary. Certifying that this code is | ||
50 | * "safe" thus only means that it doesn't allow anything else (such | ||
51 | * as local priv. escalation, etc.). | ||
52 | * | ||
53 | * The following list of people have reviewed this code and considered | ||
54 | * it safe (within specifications) since the last modification (if you | ||
55 | * reviewed it, please have your name added to the list): | ||
56 | * | ||
57 | * - Christian Grothoff | ||
58 | */ | ||
59 | #include "platform.h" | ||
60 | |||
61 | /** | ||
62 | * Name and full path of IPTABLES binary. | ||
63 | */ | ||
64 | #define SBIN_IPTABLES "/sbin/iptables" | ||
65 | |||
66 | /** | ||
67 | * Name and full path of IPTABLES binary. | ||
68 | */ | ||
69 | #define SBIN_IP "/sbin/ip" | ||
70 | |||
71 | /** | ||
72 | * Port for DNS traffic. | ||
73 | */ | ||
74 | #define DNS_PORT "53" | ||
75 | |||
76 | /** | ||
77 | * Marker we set for our hijacked DNS traffic. We use GNUnet's | ||
78 | * port (2086) plus the DNS port (53) in HEX to make a 32-bit mark | ||
79 | * (which is hopefully long enough to not collide); so | ||
80 | * 0x08260035 = 136708149 (hopefully unique enough...). | ||
81 | */ | ||
82 | #define DNS_MARK "136708149" | ||
83 | |||
84 | /** | ||
85 | * Table we use for our DNS rules. 0-255 is the range and | ||
86 | * 0, 253, 254 and 255 are already reserved. As this is about | ||
87 | * DNS and as "53" is likely (fingers crossed!) high enough to | ||
88 | * not usually conflict with a normal user's setup, we use 53 | ||
89 | * to give a hint that this has something to do with DNS. | ||
90 | */ | ||
91 | #define DNS_TABLE "53" | ||
92 | |||
93 | |||
94 | /** | ||
95 | * Run the given command and wait for it to complete. | ||
96 | * | ||
97 | * @param file name of the binary to run | ||
98 | * @param cmd command line arguments (as given to 'execv') | ||
99 | * @return 0 on success, 1 on any error | ||
100 | */ | ||
101 | static int | ||
102 | fork_and_exec (const char *file, | ||
103 | char *const cmd[]) | ||
104 | { | ||
105 | int status; | ||
106 | pid_t pid; | ||
107 | pid_t ret; | ||
108 | |||
109 | pid = fork (); | ||
110 | if (-1 == pid) | ||
111 | { | ||
112 | fprintf (stderr, | ||
113 | "fork failed: %s\n", | ||
114 | strerror (errno)); | ||
115 | return 1; | ||
116 | } | ||
117 | if (0 == pid) | ||
118 | { | ||
119 | /* we are the child process */ | ||
120 | (void) execv (file, cmd); | ||
121 | /* can only get here on error */ | ||
122 | fprintf (stderr, | ||
123 | "exec `%s' failed: %s\n", | ||
124 | file, | ||
125 | strerror (errno)); | ||
126 | _exit (1); | ||
127 | } | ||
128 | /* keep running waitpid as long as the only error we get is 'EINTR' */ | ||
129 | while ( (-1 == (ret = waitpid (pid, &status, 0))) && | ||
130 | (errno == EINTR) ); | ||
131 | if (-1 == ret) | ||
132 | { | ||
133 | fprintf (stderr, | ||
134 | "waitpid failed: %s\n", | ||
135 | strerror (errno)); | ||
136 | return 1; | ||
137 | } | ||
138 | if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)))) | ||
139 | return 1; | ||
140 | /* child process completed and returned success, we're happy */ | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | |||
145 | /** | ||
146 | * Main function of "gnunet-helper-hijack-dns". | ||
147 | * Use "-d" as the first argument to remove the firewall rules. | ||
148 | * The other arguments are the DNS source port to NOT affect | ||
149 | * by the rules, followed by the name of the virtual interface | ||
150 | * to redirect all of the remaining DNS traffic to. | ||
151 | * | ||
152 | * @param argc number of arguments | ||
153 | * @param argv ["-d"] PORT VTUN | ||
154 | * @return 0 on success, otherwise code indicating type of error: | ||
155 | * 1 wrong number of arguments | ||
156 | * 2 invalid port number | ||
157 | * 3 iptables not executable | ||
158 | * 4 ip not executable | ||
159 | * 8 failed to change routing table, cleanup successfull | ||
160 | * 16-31 failed to undo some changes to routing table | ||
161 | * 31-47 failed to fully change routing table and then might have failed to undo everything | ||
162 | */ | ||
163 | int | ||
164 | main (int argc, char *const*argv) | ||
165 | { | ||
166 | int delete; | ||
167 | unsigned int port; | ||
168 | char *virt_dns; | ||
169 | char localport[6]; | ||
170 | int r; | ||
171 | |||
172 | /* check command-line arguments */ | ||
173 | if (argc < 3) | ||
174 | { | ||
175 | fprintf (stderr, | ||
176 | "Syntax: gnunet-helper-hijack-dns [-d] PORT INTERFACENAME\n"); | ||
177 | return 1; | ||
178 | } | ||
179 | if (0 == strcmp (argv[1], "-d")) | ||
180 | delete = 1; | ||
181 | else | ||
182 | delete = 0; | ||
183 | if (argc != 3 + delete) | ||
184 | { | ||
185 | fprintf (stderr, | ||
186 | "Syntax: gnunet-helper-hijack-dns [-d] PORT INTERFACENAME\n"); | ||
187 | return 1; | ||
188 | } | ||
189 | port = atoi (argv[1 + delete]); | ||
190 | virt_dns = argv[2 + delete]; | ||
191 | if ( (port == 0) || (port >= 65536) ) | ||
192 | { | ||
193 | fprintf (stderr, | ||
194 | "Port `%u' is invalid\n", | ||
195 | port); | ||
196 | return 2; | ||
197 | } | ||
198 | /* verify that the binaries were care about are executable */ | ||
199 | if (0 != access (SBIN_IPTABLES, X_OK)) | ||
200 | { | ||
201 | fprintf (stderr, | ||
202 | "`%s' is not executable: %s\n", | ||
203 | SBIN_IPTABLES, | ||
204 | strerror (errno)); | ||
205 | return 3; | ||
206 | } | ||
207 | if (0 != access (SBIN_IP, X_OK)) | ||
208 | { | ||
209 | fprintf (stderr, | ||
210 | "`%s' is not executable: %s\n", | ||
211 | SBIN_IP, | ||
212 | strerror (errno)); | ||
213 | return 4; | ||
214 | } | ||
215 | |||
216 | /* print port number to string for command-line use*/ | ||
217 | (void) snprintf (localport, | ||
218 | sizeof (localport), | ||
219 | "%u", | ||
220 | port); | ||
221 | |||
222 | /* update routing tables -- this is why we are SUID! */ | ||
223 | if (! delete) | ||
224 | { | ||
225 | /* Forward everything from the given local port (with destination | ||
226 | to port 53, and only for UDP) without hijacking */ | ||
227 | { | ||
228 | char *const mangle_args[] = | ||
229 | { | ||
230 | "iptables", "-t", "mangle", "-I", "OUTPUT", "1", "-p", | ||
231 | "udp", "--sport", localport, "--dport", DNS_PORT, "-j", | ||
232 | "ACCEPT", NULL | ||
233 | }; | ||
234 | if (0 != fork_and_exec (SBIN_IPTABLES, mangle_args)) | ||
235 | goto cleanup_mangle_1; | ||
236 | } | ||
237 | /* Mark all of the other DNS traffic using our mark DNS_MARK */ | ||
238 | { | ||
239 | char *const mark_args[] = | ||
240 | { | ||
241 | "iptables", "-t", "mangle", "-I", "OUTPUT", DNS_TABLE, "-p", | ||
242 | "udp", "--dport", DNS_PORT, "-j", "MARK", "--set-mark", DNS_MARK, | ||
243 | NULL | ||
244 | }; | ||
245 | if (0 != fork_and_exec (SBIN_IPTABLES, mark_args)) | ||
246 | goto cleanup_mark_2; | ||
247 | } | ||
248 | /* Forward all marked DNS traffic to our DNS_TABLE */ | ||
249 | { | ||
250 | char *const forward_args[] = | ||
251 | { | ||
252 | "ip", "rule", "add", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL | ||
253 | }; | ||
254 | if (0 != fork_and_exec (SBIN_IP, forward_args)) | ||
255 | goto cleanup_forward_3; | ||
256 | } | ||
257 | /* Finally, add rule in our forwarding table to pass to our virtual interface */ | ||
258 | { | ||
259 | char *const route_args[] = | ||
260 | { | ||
261 | "ip", "route", "add", "default", "via", virt_dns, | ||
262 | "table", DNS_TABLE, NULL | ||
263 | }; | ||
264 | if (0 != fork_and_exec (SBIN_IP, route_args)) | ||
265 | goto cleanup_route_4; | ||
266 | } | ||
267 | } | ||
268 | else | ||
269 | { | ||
270 | r = 0; | ||
271 | /* delete or clean-up-on-error case */ | ||
272 | cleanup_route_4: | ||
273 | { | ||
274 | char *const route_clean_args[] = | ||
275 | { | ||
276 | "ip", "route", "del", "default", "via", virt_dns, | ||
277 | "table", DNS_TABLE, NULL | ||
278 | }; | ||
279 | if (0 != fork_and_exec (SBIN_IP, route_clean_args)) | ||
280 | r += 1; | ||
281 | } | ||
282 | cleanup_forward_3: | ||
283 | { | ||
284 | char *const forward_clean_args[] = | ||
285 | { | ||
286 | "ip", "rule", "del", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL | ||
287 | }; | ||
288 | if (0 != fork_and_exec (SBIN_IP, forward_clean_args)) | ||
289 | r += 2; | ||
290 | } | ||
291 | cleanup_mark_2: | ||
292 | { | ||
293 | char *const mark_clean_args[] = | ||
294 | { | ||
295 | "iptables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", | ||
296 | "--dport", DNS_PORT, "-j", "MARK", "--set-mark", DNS_MARK, NULL | ||
297 | }; | ||
298 | if (0 != fork_and_exec (SBIN_IPTABLES, mark_clean_args)) | ||
299 | r += 4; | ||
300 | } | ||
301 | cleanup_mangle_1: | ||
302 | { | ||
303 | char *const mangle_clean_args[] = | ||
304 | { | ||
305 | "iptables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", | ||
306 | "--sport", localport, "--dport", DNS_PORT, "-j", "ACCEPT", | ||
307 | NULL | ||
308 | }; | ||
309 | if (0 != fork_and_exec (SBIN_IPTABLES, mangle_clean_args)) | ||
310 | r += 8; | ||
311 | } | ||
312 | if (r != 0) | ||
313 | { | ||
314 | if (delete) | ||
315 | return 16 + r; /* failed to delete */ | ||
316 | return 32 + r; /* first failed to install, then also failed to clean up! */ | ||
317 | } | ||
318 | if (! delete) | ||
319 | { | ||
320 | /* got here via goto to clean up handler, failed to install, succeeded with clean up */ | ||
321 | return 8; | ||
322 | } | ||
323 | } | ||
324 | /* success ! */ | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | /* end of gnunet-helper-hijack-dns.c */ | ||
diff --git a/src/dns/gnunet-service-dns.c b/src/dns/gnunet-service-dns.c index c0e7e56ff..764ede782 100644 --- a/src/dns/gnunet-service-dns.c +++ b/src/dns/gnunet-service-dns.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | (C) 2009 Christian Grothoff (and other contributing authors) | 3 | (C) 2012 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -20,119 +20,177 @@ | |||
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file dns/gnunet-service-dns.c | 22 | * @file dns/gnunet-service-dns.c |
23 | * @author Philipp Toelke | 23 | * @author Christian Grothoff |
24 | */ | 24 | */ |
25 | #include "platform.h" | 25 | #include "platform.h" |
26 | #include "gnunet_getopt_lib.h" | 26 | #include "gnunet_util_lib.h" |
27 | #include "gnunet_service_lib.h" | 27 | #include "gnunet_constants.h" |
28 | #include <gnunet_constants.h> | ||
29 | #include "gnunet_network_lib.h" | ||
30 | #include "gnunet_os_lib.h" | ||
31 | #include "gnunet_dns_service.h" | ||
32 | #include "gnunet_connection_lib.h" | ||
33 | #include "gnunet_protocols.h" | 28 | #include "gnunet_protocols.h" |
34 | #include "gnunet_applications.h" | ||
35 | #include "gnunet_container_lib.h" | ||
36 | #include "gnunet_dnsparser_lib.h" | ||
37 | #include "gnunet_dht_service.h" | ||
38 | #include "gnunet_block_lib.h" | ||
39 | #include "block_dns.h" | ||
40 | #include "gnunet_crypto_lib.h" | ||
41 | #include "gnunet_mesh_service.h" | ||
42 | #include "gnunet_signatures.h" | 29 | #include "gnunet_signatures.h" |
43 | |||
44 | #include "dns.h" | 30 | #include "dns.h" |
31 | #include "gnunet_dns_service.h" | ||
32 | #include "gnunet_statistics_service.h" | ||
33 | #include "tcpip_tun.h" | ||
45 | 34 | ||
46 | /** | 35 | #ifndef IPVERSION |
47 | * A structure containing a mapping from network-byte-ordered DNS-id (16 bit) to | 36 | #define IPVERSION 4 |
48 | * some information needed to handle this query | 37 | #endif |
49 | * | ||
50 | * It currently allocates at least | ||
51 | * (1 + machine-width + machine-width + 32 + 32 + 16 + machine-width + 8) * 65536 bit | ||
52 | * = 17 MiB on 64 bit. | ||
53 | * = 11 MiB on 32 bit. | ||
54 | */ | ||
55 | static struct | ||
56 | { | ||
57 | unsigned valid:1; | ||
58 | struct GNUNET_SERVER_Client *client; | ||
59 | struct GNUNET_MESH_Tunnel *tunnel; | ||
60 | char local_ip[16]; | ||
61 | char remote_ip[16]; | ||
62 | char addrlen; | ||
63 | uint16_t local_port; | ||
64 | char *name; | ||
65 | uint8_t namelen; | ||
66 | uint16_t qtype; | ||
67 | } query_states[UINT16_MAX + 1]; | ||
68 | 38 | ||
69 | /** | 39 | /** |
70 | * A struct used to give more than one value as | 40 | * Phases each request goes through. |
71 | * closure to receive_dht | ||
72 | */ | 41 | */ |
73 | struct receive_dht_cls | 42 | enum RequestPhase |
74 | { | 43 | { |
75 | uint16_t id; | 44 | /** |
76 | struct GNUNET_DHT_GetHandle *handle; | 45 | * Request has just been received. |
77 | }; | 46 | */ |
47 | RP_INIT, | ||
78 | 48 | ||
79 | struct tunnel_notify_queue | 49 | /** |
80 | { | 50 | * Showing the request to all monitor clients. If |
81 | struct tunnel_notify_queue *next; | 51 | * client list is empty, will enter QUERY phase. |
82 | struct tunnel_notify_queue *prev; | 52 | */ |
83 | void *cls; | 53 | RP_REQUEST_MONITOR, |
84 | size_t len; | ||
85 | GNUNET_CONNECTION_TransmitReadyNotify cb; | ||
86 | }; | ||
87 | 54 | ||
88 | struct tunnel_state | 55 | /** |
89 | { | 56 | * Showing the request to PRE-RESOLUTION clients to find an answer. |
90 | struct tunnel_notify_queue *head, *tail; | 57 | * If client list is empty, will trigger global DNS request. |
91 | struct GNUNET_MESH_TransmitHandle *th; | 58 | */ |
59 | RP_QUERY, | ||
60 | |||
61 | /** | ||
62 | * Global Internet query is now pending. | ||
63 | */ | ||
64 | RP_INTERNET_DNS, | ||
65 | |||
66 | /** | ||
67 | * Client (or global DNS request) has resulted in a response. | ||
68 | * Forward to all POST-RESOLUTION clients. If client list is empty, | ||
69 | * will enter RESPONSE_MONITOR phase. | ||
70 | */ | ||
71 | RP_MODIFY, | ||
72 | |||
73 | /** | ||
74 | * Showing the request to all monitor clients. If | ||
75 | * client list is empty, give the result to the hijacker (and be done). | ||
76 | */ | ||
77 | RP_RESPONSE_MONITOR, | ||
78 | |||
79 | /** | ||
80 | * Some client has told us to drop the request. | ||
81 | */ | ||
82 | RP_DROP | ||
92 | }; | 83 | }; |
93 | 84 | ||
94 | 85 | ||
95 | struct answer_packet_list | 86 | /** |
87 | * Entry we keep for each client. | ||
88 | */ | ||
89 | struct ClientRecord | ||
96 | { | 90 | { |
97 | struct answer_packet_list *next; | 91 | /** |
98 | struct answer_packet_list *prev; | 92 | * Kept in doubly-linked list. |
93 | */ | ||
94 | struct ClientRecord *next; | ||
95 | |||
96 | /** | ||
97 | * Kept in doubly-linked list. | ||
98 | */ | ||
99 | struct ClientRecord *prev; | ||
100 | |||
101 | /** | ||
102 | * Handle to the client. | ||
103 | */ | ||
99 | struct GNUNET_SERVER_Client *client; | 104 | struct GNUNET_SERVER_Client *client; |
100 | struct answer_packet pkt; | 105 | |
106 | /** | ||
107 | * Flags for the client. | ||
108 | */ | ||
109 | enum GNUNET_DNS_Flags flags; | ||
110 | |||
101 | }; | 111 | }; |
102 | 112 | ||
103 | GNUNET_NETWORK_STRUCT_BEGIN | 113 | |
104 | struct tunnel_cls | 114 | /** |
115 | * Entry we keep for each active request. | ||
116 | */ | ||
117 | struct RequestRecord | ||
105 | { | 118 | { |
106 | struct GNUNET_MESH_Tunnel *tunnel; | ||
107 | struct GNUNET_MessageHeader hdr; | ||
108 | struct dns_pkt dns; | ||
109 | }; | ||
110 | GNUNET_NETWORK_STRUCT_END | ||
111 | 119 | ||
112 | struct tunnel_cls *remote_pending[UINT16_MAX]; | 120 | /** |
121 | * List of clients that still need to see this request (each entry | ||
122 | * is set to NULL when the client is done). | ||
123 | */ | ||
124 | struct ClientRecord **client_wait_list; | ||
113 | 125 | ||
126 | /** | ||
127 | * Payload of the UDP packet (the UDP payload), can be either query | ||
128 | * or already the response. | ||
129 | */ | ||
130 | char *payload; | ||
114 | 131 | ||
115 | static struct GNUNET_MESH_Handle *mesh_handle; | 132 | /** |
133 | * Source address of the original request (for sending response). | ||
134 | */ | ||
135 | struct sockaddr_storage src_addr; | ||
136 | |||
137 | /** | ||
138 | * Destination address of the original request (for potential use as exit). | ||
139 | */ | ||
140 | struct sockaddr_storage dst_addr; | ||
141 | |||
142 | /** | ||
143 | * ID of this request, also basis for hashing. Lowest 16 bit will | ||
144 | * be our message ID when doing a global DNS request and our index | ||
145 | * into the 'requests' array. | ||
146 | */ | ||
147 | uint64_t request_id; | ||
148 | |||
149 | /** | ||
150 | * Number of bytes in payload. | ||
151 | */ | ||
152 | size_t payload_length; | ||
153 | |||
154 | /** | ||
155 | * Length of the client wait list. | ||
156 | */ | ||
157 | unsigned int client_wait_list_length; | ||
158 | |||
159 | /** | ||
160 | * In which phase this this request? | ||
161 | */ | ||
162 | enum RequestPhase phase; | ||
163 | |||
164 | }; | ||
116 | 165 | ||
117 | static struct GNUNET_CONNECTION_TransmitHandle *server_notify; | ||
118 | 166 | ||
119 | /** | 167 | /** |
120 | * The UDP-Socket through which DNS-Resolves will be sent if they are not to be | 168 | * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be |
121 | * sent through gnunet. The port of this socket will not be hijacked. | 169 | * sent through gnunet. The port of this socket will not be hijacked. |
122 | */ | 170 | */ |
123 | static struct GNUNET_NETWORK_Handle *dnsout; | 171 | static struct GNUNET_NETWORK_Handle *dnsout4; |
124 | 172 | ||
173 | /** | ||
174 | * The IPv6 UDP-Socket through which DNS-Resolves will be sent if they are not to be | ||
175 | * sent through gnunet. The port of this socket will not be hijacked. | ||
176 | */ | ||
125 | static struct GNUNET_NETWORK_Handle *dnsout6; | 177 | static struct GNUNET_NETWORK_Handle *dnsout6; |
126 | 178 | ||
127 | /** | 179 | /** |
128 | * The port bound to the socket dnsout | 180 | * Task for reading from dnsout4. |
129 | */ | 181 | */ |
130 | static unsigned short dnsoutport; | 182 | static GNUNET_SCHEDULER_TaskIdentifier read4_task; |
131 | 183 | ||
132 | /** | 184 | /** |
133 | * A handle to the DHT-Service | 185 | * Task for reading from dnsout6. |
134 | */ | 186 | */ |
135 | static struct GNUNET_DHT_Handle *dht; | 187 | static GNUNET_SCHEDULER_TaskIdentifier read6_task; |
188 | |||
189 | /** | ||
190 | * The port bound to the socket dnsout (and/or dnsout6). We always (try) to bind | ||
191 | * both sockets to the same port. | ||
192 | */ | ||
193 | static uint16_t dnsoutport; | ||
136 | 194 | ||
137 | /** | 195 | /** |
138 | * The configuration to use | 196 | * The configuration to use |
@@ -140,1538 +198,975 @@ static struct GNUNET_DHT_Handle *dht; | |||
140 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | 198 | static const struct GNUNET_CONFIGURATION_Handle *cfg; |
141 | 199 | ||
142 | /** | 200 | /** |
143 | * A list of DNS-Responses that have to be sent to the requesting client | 201 | * Statistics. |
144 | */ | 202 | */ |
145 | static struct answer_packet_list *head; | 203 | static struct GNUNET_STATISTICS_Handle *stats; |
146 | 204 | ||
147 | /** | 205 | /** |
148 | * The tail of the list of DNS-responses | 206 | * Handle to DNS hijacker helper process ("gnunet-helper-dns"). |
149 | */ | 207 | */ |
150 | static struct answer_packet_list *tail; | 208 | static struct GNUNET_HELPER_Handle *hijacker; |
151 | 209 | ||
210 | /** | ||
211 | * Command-line arguments we are giving to the hijacker process. | ||
212 | */ | ||
213 | static char *helper_argv[8]; | ||
152 | 214 | ||
153 | static size_t | 215 | /** |
154 | send_answer (void *cls, size_t size, void *buf); | 216 | * Head of DLL of clients we consult. |
217 | */ | ||
218 | static struct ClientRecord *clients_head; | ||
155 | 219 | ||
156 | static void | 220 | /** |
157 | client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | 221 | * Tail of DLL of clients we consult. |
158 | { | 222 | */ |
159 | if (NULL == head) | 223 | static struct ClientRecord *clients_tail; |
160 | return; | ||
161 | 224 | ||
162 | if (head->client == client) | 225 | /** |
163 | { | 226 | * Our notification context. |
164 | GNUNET_CONNECTION_notify_transmit_ready_cancel (server_notify); | 227 | */ |
165 | server_notify = | 228 | static struct GNUNET_SERVER_NotificationContext *nc; |
166 | GNUNET_SERVER_notify_transmit_ready (head->next->client, | ||
167 | ntohs (head->next->pkt.hdr.size), | ||
168 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
169 | &send_answer, NULL); | ||
170 | } | ||
171 | 229 | ||
172 | struct answer_packet_list *element = head; | 230 | /** |
231 | * Array of all open requests. | ||
232 | */ | ||
233 | static struct RequestRecord requests[UINT16_MAX + 1]; | ||
173 | 234 | ||
174 | while (element != NULL) | 235 | /** |
175 | { | 236 | * Generator for unique request IDs. |
176 | if (element->client == client) | 237 | */ |
177 | { | 238 | static uint64_t request_id_gen; |
178 | GNUNET_SERVER_client_drop (client); | ||
179 | GNUNET_CONTAINER_DLL_remove (head, tail, element); | ||
180 | struct answer_packet_list *t = element; | ||
181 | 239 | ||
182 | element = element->next; | ||
183 | GNUNET_free (t); | ||
184 | } | ||
185 | else | ||
186 | element = element->next; | ||
187 | } | ||
188 | } | ||
189 | 240 | ||
190 | /** | 241 | /** |
191 | * Hijack all outgoing DNS-Traffic but for traffic leaving "our" port. | 242 | * We're done processing a DNS request, free associated memory. |
243 | * | ||
244 | * @param rr request to clean up | ||
192 | */ | 245 | */ |
193 | static void | 246 | static void |
194 | hijack (void *cls GNUNET_UNUSED, const struct GNUNET_SCHEDULER_TaskContext *tc) | 247 | cleanup_rr (struct RequestRecord *rr) |
195 | { | 248 | { |
196 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | 249 | GNUNET_free_non_null (rr->payload); |
197 | return; | 250 | rr->payload = NULL; |
198 | 251 | rr->payload_length = 0; | |
199 | if (0 == dnsoutport) | 252 | GNUNET_array_grow (rr->client_wait_list, |
200 | { | 253 | rr->client_wait_list_length, |
201 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 254 | 0); |
202 | "Delaying the hijacking, port is still %d!\n", dnsoutport); | ||
203 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &hijack, NULL); | ||
204 | return; | ||
205 | } | ||
206 | |||
207 | char port_s[6]; | ||
208 | char *virt_dns; | ||
209 | struct GNUNET_OS_Process *proc; | ||
210 | |||
211 | if (GNUNET_SYSERR == | ||
212 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS", &virt_dns)) | ||
213 | { | ||
214 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
215 | "No entry 'VIRTDNS' in configuration!\n"); | ||
216 | exit (1); | ||
217 | } | ||
218 | |||
219 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacking, port is %d\n", dnsoutport); | ||
220 | snprintf (port_s, 6, "%d", dnsoutport); | ||
221 | if (NULL != | ||
222 | (proc = | ||
223 | GNUNET_OS_start_process (NULL, NULL, "gnunet-helper-hijack-dns", | ||
224 | "gnunet-hijack-dns", port_s, virt_dns, NULL))) | ||
225 | { | ||
226 | GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (proc)); | ||
227 | GNUNET_OS_process_close (proc); | ||
228 | } | ||
229 | GNUNET_free (virt_dns); | ||
230 | } | ||
231 | |||
232 | static void * | ||
233 | new_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
234 | const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED, | ||
235 | const struct GNUNET_ATS_Information *ats GNUNET_UNUSED) | ||
236 | { | ||
237 | struct tunnel_state *s = GNUNET_malloc (sizeof *s); | ||
238 | |||
239 | s->head = NULL; | ||
240 | s->tail = NULL; | ||
241 | s->th = NULL; | ||
242 | return s; | ||
243 | } | 255 | } |
244 | 256 | ||
245 | static void | ||
246 | clean_tunnel (void *cls GNUNET_UNUSED, const struct GNUNET_MESH_Tunnel *tunnel, | ||
247 | void *tunnel_ctx) | ||
248 | { | ||
249 | GNUNET_free (tunnel_ctx); | ||
250 | } | ||
251 | 257 | ||
252 | /** | 258 | /** |
253 | * Delete the hijacking-routes | 259 | * Task run during shutdown. |
260 | * | ||
261 | * @param cls unused | ||
262 | * @param tc unused | ||
254 | */ | 263 | */ |
255 | static void | 264 | static void |
256 | unhijack (unsigned short port) | 265 | cleanup_task (void *cls GNUNET_UNUSED, |
266 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
257 | { | 267 | { |
258 | char port_s[6]; | 268 | unsigned int i; |
259 | char *virt_dns; | ||
260 | struct GNUNET_OS_Process *proc; | ||
261 | 269 | ||
262 | if (GNUNET_SYSERR == | 270 | GNUNET_HELPER_stop (hijacker); |
263 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS", &virt_dns)) | 271 | hijacker = NULL; |
272 | for (i=0;i<8;i++) | ||
273 | GNUNET_free_non_null (helper_argv[i]); | ||
274 | if (NULL != dnsout4) | ||
264 | { | 275 | { |
265 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 276 | GNUNET_NETWORK_socket_close (dnsout4); |
266 | "No entry 'VIRTDNS' in configuration!\n"); | 277 | dnsout4 = NULL; |
267 | exit (1); | ||
268 | } | 278 | } |
269 | 279 | if (GNUNET_SCHEDULER_NO_TASK != read4_task) | |
270 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "unHijacking, port is %d\n", port); | ||
271 | snprintf (port_s, 6, "%d", port); | ||
272 | if (NULL != | ||
273 | (proc = | ||
274 | GNUNET_OS_start_process (NULL, NULL, "gnunet-helper-hijack-dns", | ||
275 | "gnunet-hijack-dns", "-d", port_s, virt_dns, | ||
276 | NULL))) | ||
277 | { | 280 | { |
278 | GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (proc)); | 281 | GNUNET_SCHEDULER_cancel (read4_task); |
279 | GNUNET_OS_process_close (proc); | 282 | read4_task = GNUNET_SCHEDULER_NO_TASK; |
280 | } | 283 | } |
281 | GNUNET_free (virt_dns); | 284 | if (NULL != dnsout6) |
282 | } | ||
283 | |||
284 | /** | ||
285 | * Send the DNS-Response to the client. Gets called via the notify_transmit_ready- | ||
286 | * system. | ||
287 | */ | ||
288 | static size_t | ||
289 | send_answer (void *cls, size_t size, void *buf) | ||
290 | { | ||
291 | server_notify = NULL; | ||
292 | struct answer_packet_list *query = head; | ||
293 | size_t len = ntohs (query->pkt.hdr.size); | ||
294 | |||
295 | GNUNET_assert (len <= size); | ||
296 | |||
297 | memcpy (buf, &query->pkt.hdr, len); | ||
298 | |||
299 | GNUNET_CONTAINER_DLL_remove (head, tail, query); | ||
300 | |||
301 | /* When more data is to be sent, reschedule */ | ||
302 | if (head != NULL) | ||
303 | server_notify = | ||
304 | GNUNET_SERVER_notify_transmit_ready (head->client, | ||
305 | ntohs (head->pkt.hdr.size), | ||
306 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
307 | &send_answer, NULL); | ||
308 | |||
309 | GNUNET_SERVER_client_drop (query->client); | ||
310 | GNUNET_free (query); | ||
311 | return len; | ||
312 | } | ||
313 | |||
314 | |||
315 | static size_t | ||
316 | mesh_send_response (void *cls, size_t size, void *buf) | ||
317 | { | ||
318 | GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); | ||
319 | struct GNUNET_MessageHeader *hdr = buf; | ||
320 | uint32_t *sz = cls; | ||
321 | struct GNUNET_MESH_Tunnel **tunnel = (struct GNUNET_MESH_Tunnel **) (sz + 1); | ||
322 | struct dns_pkt *dns = (struct dns_pkt *) (tunnel + 1); | ||
323 | |||
324 | GNUNET_MESH_tunnel_set_data (*tunnel, NULL); | ||
325 | |||
326 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_REMOTE_ANSWER_DNS); | ||
327 | hdr->size = htons (*sz + sizeof (struct GNUNET_MessageHeader)); | ||
328 | |||
329 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
330 | "Sending response, size=%d, sz=%d, sz+hdr=%d\n", size, *sz, | ||
331 | *sz + sizeof (struct GNUNET_MessageHeader)); | ||
332 | |||
333 | GNUNET_assert (size >= (*sz + sizeof (struct GNUNET_MessageHeader))); | ||
334 | |||
335 | memcpy (hdr + 1, dns, *sz); | ||
336 | struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (*tunnel); | ||
337 | |||
338 | if (NULL != s->head) | ||
339 | { | 285 | { |
340 | struct tunnel_notify_queue *element = s->head; | 286 | GNUNET_NETWORK_socket_close (dnsout6); |
341 | struct tunnel_notify_queue *head = s->head; | 287 | dnsout6 = NULL; |
342 | struct tunnel_notify_queue *tail = s->tail; | ||
343 | |||
344 | GNUNET_CONTAINER_DLL_remove (head, tail, element); | ||
345 | |||
346 | s->th = | ||
347 | GNUNET_MESH_notify_transmit_ready (*tunnel, GNUNET_NO, 42, | ||
348 | GNUNET_TIME_relative_divide | ||
349 | (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), | ||
350 | (const struct GNUNET_PeerIdentity *) | ||
351 | NULL, element->len, element->cb, | ||
352 | element->cls); | ||
353 | } | 288 | } |
354 | 289 | if (GNUNET_SCHEDULER_NO_TASK != read6_task) | |
355 | GNUNET_free (cls); | ||
356 | |||
357 | return ntohs (hdr->size); | ||
358 | } | ||
359 | |||
360 | static size_t | ||
361 | mesh_send (void *cls, size_t size, void *buf) | ||
362 | { | ||
363 | struct tunnel_cls *cls_ = (struct tunnel_cls *) cls; | ||
364 | |||
365 | GNUNET_MESH_tunnel_set_data (cls_->tunnel, NULL); | ||
366 | |||
367 | GNUNET_assert (cls_->hdr.size <= size); | ||
368 | |||
369 | size = cls_->hdr.size; | ||
370 | cls_->hdr.size = htons (cls_->hdr.size); | ||
371 | |||
372 | memcpy (buf, &cls_->hdr, size); | ||
373 | |||
374 | struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (cls_->tunnel); | ||
375 | |||
376 | if (NULL != s->head) | ||
377 | { | 290 | { |
378 | struct tunnel_notify_queue *element = s->head; | 291 | GNUNET_SCHEDULER_cancel (read6_task); |
379 | struct tunnel_notify_queue *head = s->head; | 292 | read6_task = GNUNET_SCHEDULER_NO_TASK; |
380 | struct tunnel_notify_queue *tail = s->tail;; | ||
381 | |||
382 | GNUNET_CONTAINER_DLL_remove (head, tail, element); | ||
383 | |||
384 | s->th = | ||
385 | GNUNET_MESH_notify_transmit_ready (cls_->tunnel, GNUNET_NO, 42, | ||
386 | GNUNET_TIME_relative_divide | ||
387 | (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), | ||
388 | (const struct GNUNET_PeerIdentity *) | ||
389 | NULL, element->len, element->cb, | ||
390 | element->cls); | ||
391 | |||
392 | GNUNET_free (element); | ||
393 | } | 293 | } |
394 | 294 | for (i=0;i<65536;i++) | |
395 | return size; | 295 | cleanup_rr (&requests[i]); |
396 | } | 296 | GNUNET_SERVER_notification_context_destroy (nc); |
397 | 297 | nc = NULL; | |
398 | 298 | if (stats != NULL) | |
399 | static void | ||
400 | mesh_connect (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
401 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
402 | { | ||
403 | if (NULL == peer) | ||
404 | return; | ||
405 | struct tunnel_cls *cls_ = (struct tunnel_cls *) cls; | ||
406 | |||
407 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
408 | "Connected to peer %s, %x, sending query with id %d\n", | ||
409 | GNUNET_i2s (peer), peer, ntohs (cls_->dns.s.id)); | ||
410 | |||
411 | struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (cls_->tunnel); | ||
412 | |||
413 | if (NULL == s->head) | ||
414 | { | ||
415 | s->th = | ||
416 | GNUNET_MESH_notify_transmit_ready (cls_->tunnel, GNUNET_YES, 42, | ||
417 | GNUNET_TIME_UNIT_MINUTES, NULL, | ||
418 | cls_->hdr.size, mesh_send, cls); | ||
419 | |||
420 | } | ||
421 | else | ||
422 | { | 299 | { |
423 | struct tunnel_notify_queue *head = s->head; | 300 | GNUNET_STATISTICS_destroy (stats, GNUNET_YES); |
424 | struct tunnel_notify_queue *tail = s->tail; | 301 | stats = NULL; |
425 | |||
426 | struct tunnel_notify_queue *element = | ||
427 | GNUNET_malloc (sizeof (struct tunnel_notify_queue)); | ||
428 | element->cls = cls; | ||
429 | element->len = cls_->hdr.size; | ||
430 | element->cb = mesh_send; | ||
431 | |||
432 | GNUNET_CONTAINER_DLL_insert_tail (head, tail, element); | ||
433 | } | 302 | } |
434 | } | 303 | } |
435 | 304 | ||
436 | 305 | ||
306 | /** | ||
307 | * We're done with some request, finish processing. | ||
308 | * | ||
309 | * @param rr request send to the network or just clean up. | ||
310 | */ | ||
437 | static void | 311 | static void |
438 | send_mesh_query (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 312 | request_done (struct RequestRecord *rr) |
439 | { | ||
440 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
441 | return; | ||
442 | |||
443 | struct tunnel_cls *cls_ = (struct tunnel_cls *) cls; | ||
444 | |||
445 | struct tunnel_state *s = GNUNET_malloc (sizeof *s); | ||
446 | |||
447 | s->head = NULL; | ||
448 | s->tail = NULL; | ||
449 | s->th = NULL; | ||
450 | |||
451 | cls_->tunnel = | ||
452 | GNUNET_MESH_tunnel_create (mesh_handle, s, mesh_connect, NULL, cls_); | ||
453 | |||
454 | GNUNET_MESH_peer_request_connect_by_type (cls_->tunnel, | ||
455 | GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER); | ||
456 | |||
457 | remote_pending[cls_->dns.s.id] = cls_; | ||
458 | } | ||
459 | |||
460 | static int | ||
461 | receive_mesh_query (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
462 | void **ctx GNUNET_UNUSED, | ||
463 | const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, | ||
464 | const struct GNUNET_MessageHeader *message, | ||
465 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
466 | { | 313 | { |
467 | struct dns_pkt *dns = (struct dns_pkt *) (message + 1); | 314 | struct GNUNET_MessageHeader *hdr; |
468 | 315 | size_t reply_len; | |
469 | struct sockaddr_in dest; | 316 | uint16_t spt; |
470 | 317 | uint16_t dpt; | |
471 | struct dns_pkt_parsed *pdns = parse_dns_packet (dns); | 318 | |
472 | 319 | GNUNET_array_grow (rr->client_wait_list, | |
473 | memset (&dest, 0, sizeof dest); | 320 | rr->client_wait_list_length, |
474 | dest.sin_port = htons (53); | 321 | 0); |
475 | char *dns_resolver; | 322 | if (RP_RESPONSE_MONITOR != rr->phase) |
476 | |||
477 | if (GNUNET_OK != | ||
478 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "EXTERNAL_DNS", | ||
479 | &dns_resolver) || | ||
480 | 1 != inet_pton (AF_INET, dns_resolver, &dest.sin_addr)) | ||
481 | inet_pton (AF_INET, "8.8.8.8", &dest.sin_addr); | ||
482 | |||
483 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Querying for remote, id=%d\n", | ||
484 | ntohs (dns->s.id)); | ||
485 | query_states[dns->s.id].tunnel = tunnel; | ||
486 | query_states[dns->s.id].valid = GNUNET_YES; | ||
487 | |||
488 | int i; | ||
489 | |||
490 | for (i = 0; i < ntohs (pdns->s.qdcount); i++) | ||
491 | { | 323 | { |
492 | if (pdns->queries[i]->qtype == htons (28) || | 324 | /* no response, drop */ |
493 | pdns->queries[i]->qtype == htons (1)) | 325 | cleanup_rr (rr); |
494 | { | 326 | return; |
495 | query_states[dns->s.id].qtype = pdns->queries[i]->qtype; | ||
496 | break; | ||
497 | } | ||
498 | } | ||
499 | free_parsed_dns_packet (pdns); | ||
500 | |||
501 | GNUNET_NETWORK_socket_sendto (dnsout, dns, | ||
502 | ntohs (message->size) - | ||
503 | sizeof (struct GNUNET_MessageHeader), | ||
504 | (struct sockaddr *) &dest, sizeof dest); | ||
505 | |||
506 | return GNUNET_SYSERR; | ||
507 | } | ||
508 | |||
509 | static int | ||
510 | receive_mesh_answer (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
511 | void **ctx GNUNET_UNUSED, | ||
512 | const struct GNUNET_PeerIdentity *sender, | ||
513 | const struct GNUNET_MessageHeader *message, | ||
514 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
515 | { | ||
516 | /* TODo: size check */ | ||
517 | struct dns_pkt *dns = (struct dns_pkt *) (message + 1); | ||
518 | |||
519 | /* They sent us a packet we were not waiting for */ | ||
520 | if (remote_pending[dns->s.id] == NULL || | ||
521 | remote_pending[dns->s.id]->tunnel != tunnel) | ||
522 | return GNUNET_OK; | ||
523 | |||
524 | GNUNET_free (remote_pending[dns->s.id]); | ||
525 | remote_pending[dns->s.id] = NULL; | ||
526 | |||
527 | if (query_states[dns->s.id].valid != GNUNET_YES) | ||
528 | return GNUNET_SYSERR; | ||
529 | query_states[dns->s.id].valid = GNUNET_NO; | ||
530 | |||
531 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
532 | "Received answer from peer %s, dns-id %d\n", GNUNET_i2s (sender), | ||
533 | ntohs (dns->s.id)); | ||
534 | |||
535 | size_t len = sizeof (struct answer_packet) - 1 + sizeof (struct dns_static) + query_states[dns->s.id].namelen + sizeof (struct dns_query_line) + 2 /* To hold the pointer (as defined in RFC1035) to the name */ | ||
536 | + sizeof (struct dns_record_line) - 1 + 16; /* To hold the IPv6-Address */ | ||
537 | |||
538 | struct answer_packet_list *answer = | ||
539 | GNUNET_malloc (len + sizeof (struct answer_packet_list) - | ||
540 | sizeof (struct answer_packet)); | ||
541 | |||
542 | answer->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS); | ||
543 | answer->pkt.hdr.size = htons (len); | ||
544 | |||
545 | struct dns_pkt_parsed *pdns = parse_dns_packet (dns); | ||
546 | |||
547 | if (ntohs (pdns->s.ancount) < 1) | ||
548 | { | ||
549 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Answer only contains %d answers.\n", | ||
550 | ntohs (pdns->s.ancount)); | ||
551 | free_parsed_dns_packet (pdns); | ||
552 | GNUNET_free (answer); | ||
553 | return GNUNET_OK; | ||
554 | } | ||
555 | |||
556 | int i = 0; | ||
557 | |||
558 | while (i < ntohs (pdns->s.ancount) && ntohs (pdns->answers[i]->type) != 28 && | ||
559 | ntohs (pdns->answers[i]->type) != 1) | ||
560 | { | ||
561 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Answer contains %d.\n", | ||
562 | ntohs (pdns->answers[i]->type)); | ||
563 | i++; | ||
564 | } | 327 | } |
565 | 328 | ||
566 | if (i >= ntohs (pdns->s.ancount)) | 329 | /* send response via hijacker */ |
330 | reply_len = sizeof (struct GNUNET_MessageHeader); | ||
331 | reply_len += sizeof (struct tun_header); | ||
332 | switch (rr->src_addr.ss_family) | ||
567 | { | 333 | { |
568 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 334 | case AF_INET: |
569 | "Answer does not contain any usable answers.\n"); | 335 | reply_len += sizeof (struct ip4_header); |
570 | free_parsed_dns_packet (pdns); | 336 | break; |
571 | GNUNET_free (answer); | 337 | case AF_INET6: |
572 | return GNUNET_OK; | 338 | reply_len += sizeof (struct ip6_header); |
339 | break; | ||
340 | default: | ||
341 | GNUNET_break (0); | ||
342 | cleanup_rr (rr); | ||
343 | return; | ||
573 | } | 344 | } |
574 | 345 | reply_len += sizeof (struct udp_packet); | |
575 | answer->pkt.addrsize = ntohs (pdns->answers[i]->data_len); | 346 | reply_len += rr->payload_length; |
576 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "The first answer has the addrlen %d\n", | 347 | if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) |
577 | answer->pkt.addrsize); | ||
578 | memcpy (answer->pkt.addr, pdns->answers[i]->data, | ||
579 | ntohs (pdns->answers[i]->data_len)); | ||
580 | |||
581 | memcpy (answer->pkt.from, query_states[dns->s.id].remote_ip, | ||
582 | query_states[dns->s.id].addrlen); | ||
583 | memcpy (answer->pkt.to, query_states[dns->s.id].local_ip, | ||
584 | query_states[dns->s.id].addrlen); | ||
585 | answer->pkt.addrlen = query_states[dns->s.id].addrlen; | ||
586 | answer->pkt.dst_port = query_states[dns->s.id].local_port; | ||
587 | |||
588 | struct dns_pkt *dpkt = (struct dns_pkt *) answer->pkt.data; | ||
589 | |||
590 | dpkt->s.id = dns->s.id; | ||
591 | dpkt->s.aa = 1; | ||
592 | dpkt->s.qr = 1; | ||
593 | dpkt->s.ra = 1; | ||
594 | dpkt->s.qdcount = htons (1); | ||
595 | dpkt->s.ancount = htons (1); | ||
596 | |||
597 | memcpy (dpkt->data, query_states[dns->s.id].name, | ||
598 | query_states[dns->s.id].namelen); | ||
599 | GNUNET_free (query_states[dns->s.id].name); | ||
600 | query_states[dns->s.id].name = NULL; | ||
601 | |||
602 | struct dns_query_line *dque = | ||
603 | (struct dns_query_line *) (dpkt->data + | ||
604 | (query_states[dns->s.id].namelen)); | ||
605 | |||
606 | struct dns_record_line *drec_data = | ||
607 | (struct dns_record_line *) (dpkt->data + | ||
608 | (query_states[dns->s.id].namelen) + | ||
609 | sizeof (struct dns_query_line) + 2); | ||
610 | if (htons (28) == query_states[dns->s.id].qtype) | ||
611 | { | 348 | { |
612 | answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_REMOTE_AAAA; | 349 | /* response too big, drop */ |
613 | dque->type = htons (28); /* AAAA */ | 350 | GNUNET_break (0); /* how can this be? */ |
614 | drec_data->type = htons (28); /* AAAA */ | 351 | cleanup_rr(rr); |
615 | drec_data->data_len = htons (16); | 352 | return; |
616 | } | 353 | } |
617 | else if (htons (1) == query_states[dns->s.id].qtype) | ||
618 | { | 354 | { |
619 | answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_REMOTE_A; | 355 | char buf[reply_len]; |
620 | dque->type = htons (1); /* A */ | 356 | size_t off; |
621 | drec_data->type = htons (1); /* A */ | 357 | uint32_t udp_crc_sum; |
622 | drec_data->data_len = htons (4); | ||
623 | } | ||
624 | else | ||
625 | { | ||
626 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "dns-answer with pending qtype = %d\n", | ||
627 | query_states[dns->s.id].qtype); | ||
628 | GNUNET_assert (0); | ||
629 | } | ||
630 | dque->class = htons (1); /* IN */ | ||
631 | |||
632 | char *anname = | ||
633 | (char *) (dpkt->data + (query_states[dns->s.id].namelen) + | ||
634 | sizeof (struct dns_query_line)); | ||
635 | memcpy (anname, "\xc0\x0c", 2); | ||
636 | drec_data->class = htons (1); /* IN */ | ||
637 | |||
638 | drec_data->ttl = pdns->answers[i]->ttl; | ||
639 | 358 | ||
640 | /* Calculate at which offset in the packet the IPv6-Address belongs, it is | 359 | /* first, GNUnet message header */ |
641 | * filled in by the daemon-vpn */ | 360 | hdr = (struct GNUNET_MessageHeader*) buf; |
642 | answer->pkt.addroffset = | 361 | hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER); |
643 | htons ((unsigned short) ((unsigned long) (&drec_data->data) - | 362 | hdr->size = htons ((uint16_t) reply_len); |
644 | (unsigned long) (&answer->pkt))); | 363 | off = sizeof (struct GNUNET_MessageHeader); |
645 | 364 | ||
646 | GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer); | 365 | /* first, TUN header */ |
647 | answer->client = query_states[dns->s.id].client; | 366 | { |
367 | struct tun_header tun; | ||
648 | 368 | ||
649 | if (server_notify == NULL) | 369 | tun.flags = htons (0); |
650 | server_notify = | 370 | if (rr->src_addr.ss_family == AF_INET) |
651 | GNUNET_SERVER_notify_transmit_ready (query_states[dns->s.id].client, | 371 | tun.proto = htons (ETH_P_IPV4); |
652 | len, GNUNET_TIME_UNIT_FOREVER_REL, | 372 | else |
653 | &send_answer, NULL); | 373 | tun.proto = htons (ETH_P_IPV6); |
374 | memcpy (&buf[off], &tun, sizeof (struct tun_header)); | ||
375 | off += sizeof (struct tun_header); | ||
376 | } | ||
654 | 377 | ||
655 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 378 | /* now IP header */ |
656 | "Sent answer of length %d on to client, addroffset = %d\n", len, | 379 | udp_crc_sum = 0; |
657 | answer->pkt.addroffset); | 380 | switch (rr->src_addr.ss_family) |
381 | { | ||
382 | case AF_INET: | ||
383 | { | ||
384 | struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr; | ||
385 | struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr; | ||
386 | struct ip4_header ip; | ||
387 | |||
388 | spt = dst->sin_port; | ||
389 | dpt = src->sin_port; | ||
390 | ip.header_length = sizeof (struct ip4_header) / 4; | ||
391 | ip.version = IPVERSION; /* aka 4 */ | ||
392 | ip.diff_serv = 0; | ||
393 | ip.total_length = htons ((uint16_t) reply_len - off); | ||
394 | ip.identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
395 | 65536); | ||
396 | ip.flags = 0; | ||
397 | ip.fragmentation_offset = 0; | ||
398 | ip.ttl = 255; /* or lower? */ | ||
399 | ip.protocol = IPPROTO_UDP; | ||
400 | ip.checksum = 0; /* checksum is optional */ | ||
401 | ip.source_address = dst->sin_addr; | ||
402 | ip.destination_address = src->sin_addr; | ||
403 | ip.checksum = GNUNET_CRYPTO_crc16_n (&ip, sizeof (ip)); | ||
404 | |||
405 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
406 | &ip.source_address, | ||
407 | sizeof (struct in_addr) * 2); | ||
408 | { | ||
409 | uint16_t tmp; | ||
410 | |||
411 | tmp = htons (IPPROTO_UDP); | ||
412 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
413 | &tmp, | ||
414 | sizeof (uint16_t)); | ||
415 | tmp = htons (rr->payload_length + sizeof (struct udp_packet)); | ||
416 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
417 | &tmp, | ||
418 | sizeof (uint16_t)); | ||
419 | } | ||
420 | memcpy (&buf[off], &ip, sizeof (ip)); | ||
421 | off += sizeof (ip); | ||
422 | } | ||
423 | break; | ||
424 | case AF_INET6: | ||
425 | { | ||
426 | struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr; | ||
427 | struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr; | ||
428 | struct ip6_header ip; | ||
429 | |||
430 | spt = dst->sin6_port; | ||
431 | dpt = src->sin6_port; | ||
432 | ip.traffic_class_h = 0; | ||
433 | ip.version = 6; /* is there a named constant? I couldn't find one */ | ||
434 | ip.traffic_class_l = 0; | ||
435 | ip.flow_label = 0; | ||
436 | ip.payload_length = htons ((uint16_t) reply_len); | ||
437 | ip.next_header = IPPROTO_UDP; | ||
438 | ip.hop_limit = 255; /* or lower? */ | ||
439 | ip.source_address = dst->sin6_addr; | ||
440 | ip.destination_address = src->sin6_addr; | ||
441 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
442 | &ip.source_address, | ||
443 | sizeof (struct in6_addr) * 2); | ||
444 | { | ||
445 | uint32_t tmp; | ||
446 | |||
447 | tmp = htons (rr->payload_length + sizeof (struct udp_packet)); | ||
448 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
449 | &tmp, | ||
450 | sizeof (uint32_t)); | ||
451 | tmp = htons (IPPROTO_UDP); | ||
452 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
453 | &tmp, | ||
454 | sizeof (uint32_t)); | ||
455 | } | ||
456 | memcpy (&buf[off], &ip, sizeof (ip)); | ||
457 | off += sizeof (ip); | ||
458 | } | ||
459 | break; | ||
460 | default: | ||
461 | GNUNET_assert (0); | ||
462 | } | ||
658 | 463 | ||
659 | free_parsed_dns_packet (pdns); | 464 | /* now UDP header */ |
660 | return GNUNET_OK; | 465 | { |
466 | struct udp_packet udp; | ||
467 | |||
468 | udp.spt = spt; | ||
469 | udp.dpt = dpt; | ||
470 | udp.len = htons (reply_len - off); | ||
471 | udp.crc = 0; | ||
472 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
473 | &udp, | ||
474 | sizeof (udp)); | ||
475 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
476 | rr->payload, | ||
477 | rr->payload_length); | ||
478 | udp.crc = GNUNET_CRYPTO_crc16_finish (udp_crc_sum); | ||
479 | memcpy (&buf[off], &udp, sizeof (udp)); | ||
480 | off += sizeof (udp); | ||
481 | } | ||
482 | /* now DNS payload */ | ||
483 | { | ||
484 | memcpy (&buf[off], rr->payload, rr->payload_length); | ||
485 | off += rr->payload_length; | ||
486 | } | ||
487 | /* final checks & sending */ | ||
488 | GNUNET_assert (off == reply_len); | ||
489 | GNUNET_HELPER_send (hijacker, | ||
490 | hdr, | ||
491 | GNUNET_YES, | ||
492 | NULL, NULL); | ||
493 | GNUNET_STATISTICS_update (stats, | ||
494 | gettext_noop ("# DNS requests answered via TUN interface"), | ||
495 | 1, GNUNET_NO); | ||
496 | } | ||
497 | /* clean up, we're done */ | ||
498 | cleanup_rr (rr); | ||
661 | } | 499 | } |
662 | 500 | ||
663 | 501 | ||
664 | static void | ||
665 | send_rev_query (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
666 | { | ||
667 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
668 | return; | ||
669 | |||
670 | struct dns_pkt_parsed *pdns = (struct dns_pkt_parsed *) cls; | ||
671 | |||
672 | unsigned short id = pdns->s.id; | ||
673 | |||
674 | free_parsed_dns_packet (pdns); | ||
675 | |||
676 | if (query_states[id].valid != GNUNET_YES) | ||
677 | return; | ||
678 | query_states[id].valid = GNUNET_NO; | ||
679 | |||
680 | GNUNET_assert (query_states[id].namelen == 74); | ||
681 | |||
682 | size_t len = sizeof (struct answer_packet) - 1 + sizeof (struct dns_static) + 74 /* this is the length of a reverse ipv6-lookup */ | ||
683 | + sizeof (struct dns_query_line) + 2 /* To hold the pointer (as defined in RFC1035) to the name */ | ||
684 | + sizeof (struct dns_record_line) - 1 - | ||
685 | 2 /* We do not know the lenght of the answer yet */ ; | ||
686 | |||
687 | struct answer_packet_list *answer = | ||
688 | GNUNET_malloc (len + sizeof (struct answer_packet_list) - | ||
689 | sizeof (struct answer_packet)); | ||
690 | |||
691 | answer->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS); | ||
692 | answer->pkt.hdr.size = htons (len); | ||
693 | answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_REV; | ||
694 | |||
695 | memcpy (answer->pkt.from, query_states[id].remote_ip, | ||
696 | query_states[id].addrlen); | ||
697 | memcpy (answer->pkt.to, query_states[id].local_ip, query_states[id].addrlen); | ||
698 | |||
699 | answer->pkt.dst_port = query_states[id].local_port; | ||
700 | |||
701 | struct dns_pkt *dpkt = (struct dns_pkt *) answer->pkt.data; | ||
702 | |||
703 | dpkt->s.id = id; | ||
704 | dpkt->s.aa = 1; | ||
705 | dpkt->s.qr = 1; | ||
706 | dpkt->s.ra = 1; | ||
707 | dpkt->s.qdcount = htons (1); | ||
708 | dpkt->s.ancount = htons (1); | ||
709 | |||
710 | memcpy (dpkt->data, query_states[id].name, query_states[id].namelen); | ||
711 | GNUNET_free (query_states[id].name); | ||
712 | query_states[id].name = NULL; | ||
713 | |||
714 | struct dns_query_line *dque = | ||
715 | (struct dns_query_line *) (dpkt->data + (query_states[id].namelen)); | ||
716 | dque->type = htons (12); /* PTR */ | ||
717 | dque->class = htons (1); /* IN */ | ||
718 | |||
719 | char *anname = | ||
720 | (char *) (dpkt->data + (query_states[id].namelen) + | ||
721 | sizeof (struct dns_query_line)); | ||
722 | memcpy (anname, "\xc0\x0c", 2); | ||
723 | |||
724 | struct dns_record_line *drec_data = | ||
725 | (struct dns_record_line *) (dpkt->data + (query_states[id].namelen) + | ||
726 | sizeof (struct dns_query_line) + 2); | ||
727 | drec_data->type = htons (12); /* AAAA */ | ||
728 | drec_data->class = htons (1); /* IN */ | ||
729 | /* FIXME: read the TTL from block: | ||
730 | * GNUNET_TIME_absolute_get_remaining(rec->expiration_time) | ||
731 | * | ||
732 | * But how to get the seconds out of this? | ||
733 | */ | ||
734 | drec_data->ttl = htonl (3600); | ||
735 | |||
736 | /* Calculate at which offset in the packet the length of the name and the | ||
737 | * name, it is filled in by the daemon-vpn */ | ||
738 | answer->pkt.addroffset = | ||
739 | htons ((unsigned short) ((unsigned long) (&drec_data->data_len) - | ||
740 | (unsigned long) (&answer->pkt))); | ||
741 | |||
742 | GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer); | ||
743 | answer->client = query_states[id].client; | ||
744 | |||
745 | if (server_notify == NULL) | ||
746 | server_notify = | ||
747 | GNUNET_SERVER_notify_transmit_ready (query_states[id].client, len, | ||
748 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
749 | &send_answer, NULL); | ||
750 | } | ||
751 | |||
752 | /** | 502 | /** |
753 | * Receive a block from the dht. | 503 | * Show the payload of the given request record to the client |
504 | * (and wait for a response). | ||
505 | * | ||
506 | * @param rr request to send to client | ||
507 | * @param client client to send the response to | ||
754 | */ | 508 | */ |
755 | static void | 509 | static void |
756 | receive_dht (void *cls, struct GNUNET_TIME_Absolute exp GNUNET_UNUSED, | 510 | send_request_to_client (struct RequestRecord *rr, |
757 | const GNUNET_HashCode * key GNUNET_UNUSED, | 511 | struct GNUNET_SERVER_Client *client) |
758 | const struct GNUNET_PeerIdentity *get_path GNUNET_UNUSED, | ||
759 | unsigned int get_path_length GNUNET_UNUSED, | ||
760 | const struct GNUNET_PeerIdentity *put_path GNUNET_UNUSED, | ||
761 | unsigned int put_path_length GNUNET_UNUSED, | ||
762 | enum GNUNET_BLOCK_Type type, size_t size, const void *data) | ||
763 | { | 512 | { |
513 | char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length]; | ||
514 | struct GNUNET_DNS_Request *req; | ||
764 | 515 | ||
765 | unsigned short id = ((struct receive_dht_cls *) cls)->id; | 516 | if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) |
766 | struct GNUNET_DHT_GetHandle *handle = | 517 | { |
767 | ((struct receive_dht_cls *) cls)->handle; | 518 | GNUNET_break (0); |
768 | GNUNET_free (cls); | 519 | cleanup_rr (rr); |
769 | |||
770 | GNUNET_DHT_get_stop (handle); | ||
771 | |||
772 | GNUNET_assert (type == GNUNET_BLOCK_TYPE_DNS); | ||
773 | |||
774 | /* If no query with this id is pending, ignore the block */ | ||
775 | if (query_states[id].valid != GNUNET_YES) | ||
776 | return; | 520 | return; |
777 | query_states[id].valid = GNUNET_NO; | 521 | } |
778 | 522 | req = (struct GNUNET_DNS_Request*) buf; | |
779 | const struct GNUNET_DNS_Record *rec = data; | 523 | req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST); |
780 | 524 | req->header.size = htons (sizeof (buf)); | |
781 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 525 | req->reserved = htonl (0); |
782 | "Got block of size %d, peer: %08x, desc: %08x\n", size, | 526 | req->request_id = rr->request_id; |
783 | *((unsigned int *) &rec->peer), | 527 | memcpy (&req[1], rr->payload, rr->payload_length); |
784 | *((unsigned int *) &rec->service_descriptor)); | 528 | GNUNET_SERVER_notification_context_unicast (nc, |
785 | 529 | client, | |
786 | size_t len = sizeof (struct answer_packet) - 1 + sizeof (struct dns_static) + query_states[id].namelen + sizeof (struct dns_query_line) + 2 /* To hold the pointer (as defined in RFC1035) to the name */ | 530 | &req->header, |
787 | + sizeof (struct dns_record_line) - 1 + 16; /* To hold the IPv6-Address */ | 531 | GNUNET_NO); |
788 | |||
789 | struct answer_packet_list *answer = | ||
790 | GNUNET_malloc (len + sizeof (struct answer_packet_list) - | ||
791 | sizeof (struct answer_packet)); | ||
792 | |||
793 | answer->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS); | ||
794 | answer->pkt.hdr.size = htons (len); | ||
795 | answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_SERVICE; | ||
796 | answer->client = query_states[id].client; | ||
797 | |||
798 | GNUNET_CRYPTO_hash (&rec->peer, | ||
799 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
800 | &answer->pkt.service_descr.peer); | ||
801 | |||
802 | memcpy (&answer->pkt.service_descr.service_descriptor, | ||
803 | &rec->service_descriptor, sizeof (GNUNET_HashCode)); | ||
804 | memcpy (&answer->pkt.service_descr.service_type, &rec->service_type, | ||
805 | sizeof (answer->pkt.service_descr.service_type)); | ||
806 | memcpy (&answer->pkt.service_descr.ports, &rec->ports, | ||
807 | sizeof (answer->pkt.service_descr.ports)); | ||
808 | |||
809 | memcpy (answer->pkt.from, query_states[id].remote_ip, | ||
810 | query_states[id].addrlen); | ||
811 | memcpy (answer->pkt.to, query_states[id].local_ip, query_states[id].addrlen); | ||
812 | answer->pkt.addrlen = query_states[id].addrlen; | ||
813 | |||
814 | answer->pkt.dst_port = query_states[id].local_port; | ||
815 | |||
816 | struct dns_pkt *dpkt = (struct dns_pkt *) answer->pkt.data; | ||
817 | |||
818 | dpkt->s.id = id; | ||
819 | dpkt->s.aa = 1; | ||
820 | dpkt->s.qr = 1; | ||
821 | dpkt->s.ra = 1; | ||
822 | dpkt->s.qdcount = htons (1); | ||
823 | dpkt->s.ancount = htons (1); | ||
824 | |||
825 | memcpy (dpkt->data, query_states[id].name, query_states[id].namelen); | ||
826 | GNUNET_free (query_states[id].name); | ||
827 | query_states[id].name = NULL; | ||
828 | |||
829 | struct dns_query_line *dque = | ||
830 | (struct dns_query_line *) (dpkt->data + (query_states[id].namelen)); | ||
831 | dque->type = htons (28); /* AAAA */ | ||
832 | dque->class = htons (1); /* IN */ | ||
833 | |||
834 | char *anname = | ||
835 | (char *) (dpkt->data + (query_states[id].namelen) + | ||
836 | sizeof (struct dns_query_line)); | ||
837 | memcpy (anname, "\xc0\x0c", 2); | ||
838 | |||
839 | struct dns_record_line *drec_data = | ||
840 | (struct dns_record_line *) (dpkt->data + (query_states[id].namelen) + | ||
841 | sizeof (struct dns_query_line) + 2); | ||
842 | drec_data->type = htons (28); /* AAAA */ | ||
843 | drec_data->class = htons (1); /* IN */ | ||
844 | |||
845 | /* FIXME: read the TTL from block: | ||
846 | * GNUNET_TIME_absolute_get_remaining(rec->expiration_time) | ||
847 | * | ||
848 | * But how to get the seconds out of this? | ||
849 | */ | ||
850 | drec_data->ttl = htonl (3600); | ||
851 | drec_data->data_len = htons (16); | ||
852 | |||
853 | /* Calculate at which offset in the packet the IPv6-Address belongs, it is | ||
854 | * filled in by the daemon-vpn */ | ||
855 | answer->pkt.addroffset = | ||
856 | htons ((unsigned short) ((unsigned long) (&drec_data->data) - | ||
857 | (unsigned long) (&answer->pkt))); | ||
858 | |||
859 | GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer); | ||
860 | |||
861 | if (server_notify == NULL) | ||
862 | server_notify = | ||
863 | GNUNET_SERVER_notify_transmit_ready (answer->client, len, | ||
864 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
865 | &send_answer, NULL); | ||
866 | } | 532 | } |
867 | 533 | ||
868 | /** | ||
869 | * This receives a GNUNET_MESSAGE_TYPE_REHIJACK and rehijacks the DNS | ||
870 | */ | ||
871 | static void | ||
872 | rehijack (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client, | ||
873 | const struct GNUNET_MessageHeader *message GNUNET_UNUSED) | ||
874 | { | ||
875 | unhijack (dnsoutport); | ||
876 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &hijack, NULL); | ||
877 | |||
878 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
879 | } | ||
880 | 534 | ||
881 | /** | 535 | /** |
882 | * This receives the dns-payload from the daemon-vpn and sends it on over the udp-socket | 536 | * A client has completed its processing for this |
537 | * request. Move on. | ||
538 | * | ||
539 | * @param rr request to process further | ||
883 | */ | 540 | */ |
884 | static void | 541 | static void |
885 | receive_query (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client, | 542 | next_phase (struct RequestRecord *rr) |
886 | const struct GNUNET_MessageHeader *message) | ||
887 | { | 543 | { |
888 | struct query_packet *pkt = (struct query_packet *) message; | 544 | struct ClientRecord *cr; |
889 | struct dns_pkt *dns = (struct dns_pkt *) pkt->data; | 545 | int nz; |
890 | struct dns_pkt_parsed *pdns = parse_dns_packet (dns); | 546 | unsigned int j; |
547 | struct GNUNET_NETWORK_Handle *dnsout; | ||
548 | socklen_t salen; | ||
891 | 549 | ||
892 | query_states[dns->s.id].valid = GNUNET_YES; | 550 | if (rr->phase == RP_DROP) |
893 | query_states[dns->s.id].client = client; | 551 | { |
894 | GNUNET_SERVER_client_keep (client); | 552 | cleanup_rr (rr); |
895 | memcpy (query_states[dns->s.id].local_ip, pkt->orig_from, pkt->addrlen); | 553 | return; |
896 | query_states[dns->s.id].addrlen = pkt->addrlen; | 554 | } |
897 | query_states[dns->s.id].local_port = pkt->src_port; | 555 | nz = -1; |
898 | memcpy (query_states[dns->s.id].remote_ip, pkt->orig_to, pkt->addrlen); | 556 | for (j=0;j<rr->client_wait_list_length;j++) |
899 | query_states[dns->s.id].namelen = strlen ((char *) dns->data) + 1; | ||
900 | if (query_states[dns->s.id].name != NULL) | ||
901 | GNUNET_free (query_states[dns->s.id].name); | ||
902 | query_states[dns->s.id].name = | ||
903 | GNUNET_malloc (query_states[dns->s.id].namelen); | ||
904 | memcpy (query_states[dns->s.id].name, dns->data, | ||
905 | query_states[dns->s.id].namelen); | ||
906 | |||
907 | int i; | ||
908 | |||
909 | for (i = 0; i < ntohs (pdns->s.qdcount); i++) | ||
910 | { | 557 | { |
911 | if (pdns->queries[i]->qtype == htons (28) || | 558 | if (NULL != rr->client_wait_list[j]) |
912 | pdns->queries[i]->qtype == htons (1)) | ||
913 | { | 559 | { |
914 | query_states[dns->s.id].qtype = pdns->queries[i]->qtype; | 560 | nz = (int) j; |
915 | break; | 561 | break; |
916 | } | 562 | } |
917 | } | 563 | } |
918 | 564 | if (-1 != nz) | |
919 | /* The query is for a .gnunet-address */ | ||
920 | if (pdns->queries[0]->namelen > 9 && | ||
921 | 0 == strncmp (pdns->queries[0]->name + (pdns->queries[0]->namelen - 9), | ||
922 | ".gnunet.", 9)) | ||
923 | { | 565 | { |
924 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Query for .gnunet!\n"); | 566 | send_request_to_client (rr, rr->client_wait_list[nz]->client); |
925 | GNUNET_HashCode key; | 567 | return; |
926 | |||
927 | GNUNET_CRYPTO_hash (pdns->queries[0]->name, pdns->queries[0]->namelen, | ||
928 | &key); | ||
929 | |||
930 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting with key %08x, len is %d\n", | ||
931 | *((unsigned int *) &key), pdns->queries[0]->namelen); | ||
932 | |||
933 | struct receive_dht_cls *cls = | ||
934 | GNUNET_malloc (sizeof (struct receive_dht_cls)); | ||
935 | cls->id = dns->s.id; | ||
936 | |||
937 | cls->handle = | ||
938 | GNUNET_DHT_get_start (dht, GNUNET_TIME_UNIT_MINUTES, | ||
939 | GNUNET_BLOCK_TYPE_DNS, &key, | ||
940 | 5 /* DEFAULT_GET_REPLICATION */ , | ||
941 | GNUNET_DHT_RO_NONE, NULL, 0, &receive_dht, cls); | ||
942 | |||
943 | goto outfree; | ||
944 | } | 568 | } |
945 | 569 | /* done with current phase, advance! */ | |
946 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Query for '%s'; namelen=%d\n", | 570 | switch (rr->phase) |
947 | pdns->queries[0]->name, pdns->queries[0]->namelen); | ||
948 | |||
949 | /* This is a PTR-Query. Check if it is for "our" network */ | ||
950 | if (htons (pdns->queries[0]->qtype) == 12 && 74 == pdns->queries[0]->namelen) | ||
951 | { | 571 | { |
952 | char *ipv6addr; | 572 | case RP_INIT: |
953 | char ipv6[16]; | 573 | rr->phase = RP_REQUEST_MONITOR; |
954 | char ipv6rev[74] = | 574 | for (cr = clients_head; NULL != cr; cr = cr->next) |
955 | "X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.ip6.arpa."; | ||
956 | unsigned int i; | ||
957 | unsigned long long ipv6prefix; | ||
958 | unsigned int comparelen; | ||
959 | |||
960 | GNUNET_assert (GNUNET_OK == | ||
961 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", | ||
962 | "IPV6ADDR", | ||
963 | &ipv6addr)); | ||
964 | inet_pton (AF_INET6, ipv6addr, ipv6); | ||
965 | GNUNET_free (ipv6addr); | ||
966 | |||
967 | GNUNET_assert (GNUNET_OK == | ||
968 | GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", | ||
969 | "IPV6PREFIX", | ||
970 | &ipv6prefix)); | ||
971 | GNUNET_assert (ipv6prefix < 127); | ||
972 | ipv6prefix = (ipv6prefix + 7) / 8; | ||
973 | |||
974 | for (i = ipv6prefix; i < 16; i++) | ||
975 | ipv6[i] = 0; | ||
976 | |||
977 | for (i = 0; i < 16; i++) | ||
978 | { | 575 | { |
979 | unsigned char c1 = ipv6[i] >> 4; | 576 | if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR)) |
980 | unsigned char c2 = ipv6[i] & 0xf; | 577 | GNUNET_array_append (rr->client_wait_list, |
981 | 578 | rr->client_wait_list_length, | |
982 | if (c1 <= 9) | 579 | cr); |
983 | ipv6rev[62 - (4 * i)] = c1 + '0'; | ||
984 | else | ||
985 | ipv6rev[62 - (4 * i)] = c1 + 87; /* 87 is the difference between 'a' and 10 */ | ||
986 | |||
987 | if (c2 <= 9) | ||
988 | ipv6rev[62 - ((4 * i) + 2)] = c2 + '0'; | ||
989 | else | ||
990 | ipv6rev[62 - ((4 * i) + 2)] = c2 + 87; | ||
991 | } | 580 | } |
992 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "My network is %s'.\n", ipv6rev); | 581 | next_phase (rr); |
993 | comparelen = 10 + 4 * ipv6prefix; | 582 | return; |
994 | if (0 == | 583 | case RP_REQUEST_MONITOR: |
995 | strncmp (pdns->queries[0]->name + | 584 | rr->phase = RP_QUERY; |
996 | (pdns->queries[0]->namelen - comparelen), | 585 | for (cr = clients_head; NULL != cr; cr = cr->next) |
997 | ipv6rev + (74 - comparelen), comparelen)) | ||
998 | { | 586 | { |
999 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reverse-Query for .gnunet!\n"); | 587 | if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION)) |
1000 | 588 | GNUNET_array_append (rr->client_wait_list, | |
1001 | GNUNET_SCHEDULER_add_now (send_rev_query, pdns); | 589 | rr->client_wait_list_length, |
1002 | 590 | cr); | |
1003 | goto out; | ||
1004 | } | 591 | } |
1005 | } | 592 | next_phase (rr); |
1006 | 593 | return; | |
1007 | unsigned char virt_dns_bytes[16]; | 594 | case RP_QUERY: |
1008 | 595 | rr->phase = RP_INTERNET_DNS; | |
1009 | if (pkt->addrlen == 4) | 596 | switch (rr->dst_addr.ss_family) |
1010 | { | ||
1011 | char *virt_dns; | ||
1012 | |||
1013 | if (GNUNET_SYSERR == | ||
1014 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS", | ||
1015 | &virt_dns)) | ||
1016 | { | 597 | { |
1017 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 598 | case AF_INET: |
1018 | "No entry 'VIRTDNS' in configuration!\n"); | 599 | dnsout = dnsout4; |
1019 | exit (1); | 600 | salen = sizeof (struct ip4_header); |
601 | break; | ||
602 | case AF_INET6: | ||
603 | dnsout = dnsout6; | ||
604 | salen = sizeof (struct ip6_header); | ||
605 | break; | ||
606 | default: | ||
607 | GNUNET_break (0); | ||
608 | cleanup_rr (rr); | ||
609 | return; | ||
1020 | } | 610 | } |
1021 | 611 | if (NULL == dnsout) | |
1022 | if (1 != inet_pton (AF_INET, virt_dns, &virt_dns_bytes)) | ||
1023 | { | 612 | { |
1024 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error parsing 'VIRTDNS': %s; %m!\n", | 613 | GNUNET_STATISTICS_update (stats, |
1025 | virt_dns); | 614 | gettext_noop ("# DNS exit failed (address family not supported)"), |
1026 | exit (1); | 615 | 1, GNUNET_NO); |
616 | cleanup_rr (rr); | ||
617 | return; | ||
1027 | } | 618 | } |
1028 | 619 | GNUNET_NETWORK_socket_sendto (dnsout, | |
1029 | GNUNET_free (virt_dns); | 620 | rr->payload, |
1030 | } | 621 | rr->payload_length, |
1031 | else if (pkt->addrlen == 16) | 622 | (struct sockaddr*) &rr->dst_addr, |
1032 | { | 623 | salen); |
1033 | char *virt_dns; | 624 | return; |
1034 | 625 | case RP_INTERNET_DNS: | |
1035 | if (GNUNET_SYSERR == | 626 | rr->phase = RP_MODIFY; |
1036 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS6", | 627 | for (cr = clients_head; NULL != cr; cr = cr->next) |
1037 | &virt_dns)) | ||
1038 | { | 628 | { |
1039 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 629 | if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION)) |
1040 | "No entry 'VIRTDNS6' in configuration!\n"); | 630 | GNUNET_array_append (rr->client_wait_list, |
1041 | exit (1); | 631 | rr->client_wait_list_length, |
632 | cr); | ||
1042 | } | 633 | } |
1043 | 634 | next_phase (rr); | |
1044 | if (1 != inet_pton (AF_INET6, virt_dns, &virt_dns_bytes)) | 635 | return; |
636 | case RP_MODIFY: | ||
637 | rr->phase = RP_RESPONSE_MONITOR; | ||
638 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
1045 | { | 639 | { |
1046 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 640 | if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR)) |
1047 | "Error parsing 'VIRTDNS6': %s; %m!\n", virt_dns); | 641 | GNUNET_array_append (rr->client_wait_list, |
1048 | exit (1); | 642 | rr->client_wait_list_length, |
643 | cr); | ||
1049 | } | 644 | } |
1050 | 645 | next_phase (rr); | |
1051 | GNUNET_free (virt_dns); | 646 | return; |
1052 | } | 647 | case RP_RESPONSE_MONITOR: |
1053 | else | 648 | request_done (rr); |
1054 | { | 649 | break; |
1055 | GNUNET_assert (0); | 650 | case RP_DROP: |
651 | cleanup_rr (rr); | ||
652 | break; | ||
653 | default: | ||
654 | GNUNET_break (0); | ||
655 | cleanup_rr (rr); | ||
656 | break; | ||
1056 | } | 657 | } |
658 | } | ||
1057 | 659 | ||
1058 | if (memcmp (virt_dns_bytes, pkt->orig_to, pkt->addrlen) == 0) | ||
1059 | { | ||
1060 | /* This is a packet that was sent directly to the virtual dns-server | ||
1061 | * | ||
1062 | * This means we have to send this query over gnunet | ||
1063 | */ | ||
1064 | |||
1065 | size_t size = | ||
1066 | sizeof (struct GNUNET_MESH_Tunnel *) + | ||
1067 | sizeof (struct GNUNET_MessageHeader) + (ntohs (message->size) - | ||
1068 | sizeof (struct query_packet) + | ||
1069 | 1); | ||
1070 | struct tunnel_cls *cls_ = GNUNET_malloc (size); | ||
1071 | |||
1072 | cls_->hdr.size = size - sizeof (struct GNUNET_MESH_Tunnel *); | ||
1073 | |||
1074 | cls_->hdr.type = ntohs (GNUNET_MESSAGE_TYPE_VPN_REMOTE_QUERY_DNS); | ||
1075 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "size: %d\n", size); | ||
1076 | 660 | ||
1077 | memcpy (&cls_->dns, dns, | 661 | /** |
1078 | cls_->hdr.size - sizeof (struct GNUNET_MessageHeader)); | 662 | * A client disconnected, clean up after it. |
1079 | GNUNET_SCHEDULER_add_now (send_mesh_query, cls_); | 663 | * |
664 | * @param cls unused | ||
665 | * @param client handle of client that disconnected | ||
666 | */ | ||
667 | static void | ||
668 | client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | ||
669 | { | ||
670 | struct ClientRecord *cr; | ||
671 | struct RequestRecord *rr; | ||
672 | unsigned int i; | ||
673 | unsigned int j; | ||
1080 | 674 | ||
1081 | if (ntohs (pdns->s.qdcount) == 1) | 675 | for (cr = clients_head; NULL != cr; cr = cr->next) |
676 | { | ||
677 | if (cr->client == client) | ||
1082 | { | 678 | { |
1083 | if (ntohs (pdns->queries[0]->qtype) == 1) | 679 | GNUNET_SERVER_client_drop (client); |
1084 | pdns->queries[0]->qtype = htons (28); | 680 | GNUNET_CONTAINER_DLL_remove (clients_head, |
1085 | else if (ntohs (pdns->queries[0]->qtype) == 28) | 681 | clients_tail, |
1086 | pdns->queries[0]->qtype = htons (1); | 682 | cr); |
1087 | else | 683 | for (i=0;i<UINT16_MAX;i++) |
1088 | { | 684 | { |
1089 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "not sending second packet\n"); | 685 | rr = &requests[i]; |
1090 | goto outfree; | 686 | if (0 == rr->client_wait_list_length) |
687 | continue; /* not in use */ | ||
688 | for (j=0;j<rr->client_wait_list_length;j++) | ||
689 | { | ||
690 | if (rr->client_wait_list[j] == cr) | ||
691 | { | ||
692 | rr->client_wait_list[j] = NULL; | ||
693 | next_phase (rr); | ||
694 | } | ||
695 | } | ||
1091 | } | 696 | } |
1092 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending second packet\n"); | 697 | GNUNET_free (cr); |
1093 | struct dns_pkt *rdns = unparse_dns_packet (pdns); | 698 | return; |
1094 | size_t size = | ||
1095 | sizeof (struct GNUNET_MESH_Tunnel *) + | ||
1096 | sizeof (struct GNUNET_MessageHeader) + (ntohs (message->size) - | ||
1097 | sizeof (struct query_packet) + | ||
1098 | 1); | ||
1099 | struct tunnel_cls *cls_ = GNUNET_malloc (size); | ||
1100 | |||
1101 | cls_->hdr.size = size - sizeof (struct GNUNET_MESH_Tunnel *); | ||
1102 | |||
1103 | cls_->hdr.type = ntohs (GNUNET_MESSAGE_TYPE_VPN_REMOTE_QUERY_DNS); | ||
1104 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "size: %d\n", size); | ||
1105 | |||
1106 | memcpy (&cls_->dns, rdns, | ||
1107 | cls_->hdr.size - sizeof (struct GNUNET_MessageHeader)); | ||
1108 | GNUNET_SCHEDULER_add_now (send_mesh_query, cls_); | ||
1109 | GNUNET_free (rdns); | ||
1110 | } | 699 | } |
1111 | |||
1112 | goto outfree; | ||
1113 | } | ||
1114 | |||
1115 | |||
1116 | /* The query should be sent to the network */ | ||
1117 | if (pkt->addrlen == 4) | ||
1118 | { | ||
1119 | struct sockaddr_in dest; | ||
1120 | |||
1121 | memset (&dest, 0, sizeof dest); | ||
1122 | dest.sin_port = htons (53); | ||
1123 | memcpy (&dest.sin_addr.s_addr, pkt->orig_to, pkt->addrlen); | ||
1124 | |||
1125 | GNUNET_NETWORK_socket_sendto (dnsout, dns, | ||
1126 | ntohs (pkt->hdr.size) - | ||
1127 | sizeof (struct query_packet) + 1, | ||
1128 | (struct sockaddr *) &dest, sizeof dest); | ||
1129 | } | 700 | } |
1130 | else if (pkt->addrlen == 16) | ||
1131 | { | ||
1132 | struct sockaddr_in6 dest; | ||
1133 | |||
1134 | memset (&dest, 0, sizeof dest); | ||
1135 | dest.sin6_port = htons (53); | ||
1136 | memcpy (&dest.sin6_addr, pkt->orig_to, pkt->addrlen); | ||
1137 | |||
1138 | GNUNET_NETWORK_socket_sendto (dnsout6, dns, | ||
1139 | ntohs (pkt->hdr.size) - | ||
1140 | sizeof (struct query_packet) + 1, | ||
1141 | (struct sockaddr *) &dest, sizeof dest); | ||
1142 | } | ||
1143 | |||
1144 | outfree: | ||
1145 | free_parsed_dns_packet (pdns); | ||
1146 | pdns = NULL; | ||
1147 | out: | ||
1148 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1149 | } | 701 | } |
1150 | 702 | ||
1151 | static void | ||
1152 | read_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
1153 | 703 | ||
704 | /** | ||
705 | * Read a DNS response from the (unhindered) UDP-Socket | ||
706 | * | ||
707 | * @param cls socket to read from | ||
708 | * @param tc scheduler context (must be shutdown or read ready) | ||
709 | */ | ||
1154 | static void | 710 | static void |
1155 | read_response6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | 711 | read_response (void *cls, |
1156 | 712 | const struct GNUNET_SCHEDULER_TaskContext *tc) | |
1157 | static int | ||
1158 | open_port6 () | ||
1159 | { | 713 | { |
1160 | struct sockaddr_in6 addr; | 714 | struct GNUNET_NETWORK_Handle *dnsout = cls; |
715 | struct sockaddr_in addr4; | ||
716 | struct sockaddr_in6 addr6; | ||
717 | struct sockaddr *addr; | ||
718 | struct dns_header *dns; | ||
719 | socklen_t addrlen; | ||
720 | struct RequestRecord *rr; | ||
721 | ssize_t r; | ||
722 | int len; | ||
1161 | 723 | ||
1162 | dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0); | 724 | if (dnsout == dnsout4) |
1163 | if (dnsout6 == NULL) | ||
1164 | { | 725 | { |
1165 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not create socket: %m\n"); | 726 | addrlen = sizeof (struct sockaddr_in); |
1166 | return GNUNET_SYSERR; | 727 | addr = (struct sockaddr* ) &addr4; |
728 | read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
729 | dnsout, | ||
730 | &read_response, | ||
731 | dnsout); | ||
1167 | } | 732 | } |
1168 | memset (&addr, 0, sizeof (struct sockaddr_in6)); | 733 | else |
1169 | 734 | { | |
1170 | addr.sin6_family = AF_INET6; | 735 | addrlen = sizeof (struct sockaddr_in6); |
1171 | int err = GNUNET_NETWORK_socket_bind (dnsout6, | 736 | addr = (struct sockaddr* ) &addr6; |
1172 | (struct sockaddr *) &addr, | 737 | read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, |
1173 | sizeof (struct sockaddr_in6)); | 738 | dnsout, |
739 | &read_response, | ||
740 | dnsout); | ||
741 | } | ||
742 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
743 | return; | ||
1174 | 744 | ||
1175 | if (err != GNUNET_OK) | 745 | #ifndef MINGW |
746 | if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len)) | ||
1176 | { | 747 | { |
1177 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not bind a port: %m\n"); | 748 | /* conservative choice: */ |
1178 | return GNUNET_SYSERR; | 749 | len = 65536; |
1179 | } | 750 | } |
751 | #else | ||
752 | /* port the code above? */ | ||
753 | len = 65536; | ||
754 | #endif | ||
1180 | 755 | ||
1181 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, dnsout6, | 756 | { |
1182 | &read_response6, NULL); | 757 | unsigned char buf[len]; |
1183 | 758 | ||
1184 | return GNUNET_YES; | 759 | memset (addr, 0, addrlen); |
760 | r = GNUNET_NETWORK_socket_recvfrom (dnsout, | ||
761 | buf, sizeof (buf), | ||
762 | addr, &addrlen); | ||
763 | if (-1 == r) | ||
764 | { | ||
765 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom"); | ||
766 | return; | ||
767 | } | ||
768 | if (sizeof (struct dns_header) > r) | ||
769 | { | ||
770 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
771 | _("Received DNS response that is too small (%u bytes)"), | ||
772 | r); | ||
773 | return; | ||
774 | } | ||
775 | dns = (struct dns_header *) buf; | ||
776 | rr = &requests[dns->id]; | ||
777 | if (rr->phase != RP_INTERNET_DNS) | ||
778 | { | ||
779 | /* unexpected / bogus reply */ | ||
780 | GNUNET_STATISTICS_update (stats, | ||
781 | gettext_noop ("# External DNS response discarded (no matching request)"), | ||
782 | 1, GNUNET_NO); | ||
783 | return; | ||
784 | } | ||
785 | GNUNET_free_non_null (rr->payload); | ||
786 | rr->payload = GNUNET_malloc (len); | ||
787 | memcpy (rr->payload, buf, len); | ||
788 | rr->payload_length = len; | ||
789 | next_phase (rr); | ||
790 | } | ||
1185 | } | 791 | } |
1186 | 792 | ||
793 | |||
794 | /** | ||
795 | * Open source port for sending DNS request on IPv4. | ||
796 | * | ||
797 | * @return GNUNET_OK on success | ||
798 | */ | ||
1187 | static int | 799 | static int |
1188 | open_port () | 800 | open_port4 () |
1189 | { | 801 | { |
1190 | struct sockaddr_in addr; | 802 | struct sockaddr_in addr; |
803 | socklen_t addrlen; | ||
1191 | 804 | ||
1192 | dnsout = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0); | 805 | dnsout4 = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0); |
1193 | if (dnsout == NULL) | 806 | if (dnsout4 == NULL) |
1194 | return GNUNET_SYSERR; | 807 | return GNUNET_SYSERR; |
1195 | memset (&addr, 0, sizeof (struct sockaddr_in)); | ||
1196 | 808 | ||
809 | memset (&addr, 0, sizeof (struct sockaddr_in)); | ||
1197 | addr.sin_family = AF_INET; | 810 | addr.sin_family = AF_INET; |
1198 | int err = GNUNET_NETWORK_socket_bind (dnsout, | 811 | int err = GNUNET_NETWORK_socket_bind (dnsout4, |
1199 | (struct sockaddr *) &addr, | 812 | (struct sockaddr *) &addr, |
1200 | sizeof (struct sockaddr_in)); | 813 | sizeof (struct sockaddr_in)); |
1201 | 814 | ||
1202 | if (err != GNUNET_OK) | 815 | if (err != GNUNET_OK) |
1203 | { | 816 | { |
1204 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not bind a port: %m\n"); | 817 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
818 | _("Could not bind to any port: %s\n"), | ||
819 | STRERROR (errno)); | ||
820 | GNUNET_NETWORK_socket_close (dnsout4); | ||
821 | dnsout4 = NULL; | ||
1205 | return GNUNET_SYSERR; | 822 | return GNUNET_SYSERR; |
1206 | } | 823 | } |
1207 | 824 | ||
1208 | /* Read the port we bound to */ | 825 | /* Read the port we bound to */ |
1209 | socklen_t addrlen = sizeof (struct sockaddr_in); | 826 | addrlen = sizeof (struct sockaddr_in); |
1210 | 827 | if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout4), | |
1211 | err = | 828 | (struct sockaddr *) &addr, |
1212 | getsockname (GNUNET_NETWORK_get_fd (dnsout), (struct sockaddr *) &addr, | 829 | &addrlen)) |
1213 | &addrlen); | 830 | { |
1214 | 831 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | |
832 | _("Could not determine port I got: %s\n"), | ||
833 | STRERROR (errno)); | ||
834 | GNUNET_NETWORK_socket_close (dnsout4); | ||
835 | dnsout4 = NULL; | ||
836 | return GNUNET_SYSERR; | ||
837 | } | ||
1215 | dnsoutport = htons (addr.sin_port); | 838 | dnsoutport = htons (addr.sin_port); |
1216 | 839 | ||
1217 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bound to port %d.\n", dnsoutport); | 840 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1218 | 841 | _("GNUnet DNS will exit on source port %u\n"), | |
1219 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, dnsout, | 842 | (unsigned int) dnsoutport); |
1220 | &read_response, NULL); | 843 | read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, |
1221 | 844 | dnsout4, | |
1222 | return GNUNET_YES; | 845 | &read_response, dnsout4); |
846 | return GNUNET_OK; | ||
1223 | } | 847 | } |
1224 | 848 | ||
1225 | static void | ||
1226 | handle_response (struct dns_pkt *dns, struct sockaddr *addr, socklen_t addrlen, | ||
1227 | int r); | ||
1228 | 849 | ||
1229 | /** | 850 | /** |
1230 | * Read a response-packet of the UDP-Socket | 851 | * Open source port for sending DNS request on IPv6. Should be |
1231 | */ | 852 | * called AFTER open_port4. |
1232 | static void | 853 | * |
1233 | read_response6 (void *cls GNUNET_UNUSED, | 854 | * @return GNUNET_OK on success |
1234 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 855 | */ |
856 | static int | ||
857 | open_port6 () | ||
1235 | { | 858 | { |
1236 | struct sockaddr_in6 addr; | 859 | struct sockaddr_in6 addr; |
1237 | socklen_t addrlen = sizeof (addr); | 860 | socklen_t addrlen; |
1238 | int r; | ||
1239 | int len; | ||
1240 | |||
1241 | if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) | ||
1242 | return; | ||
1243 | |||
1244 | memset (&addr, 0, sizeof addr); | ||
1245 | |||
1246 | #ifndef MINGW | ||
1247 | if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout6), FIONREAD, &len)) | ||
1248 | { | ||
1249 | (void) open_port6 (); | ||
1250 | return; | ||
1251 | } | ||
1252 | #else | ||
1253 | /* port the code above? */ | ||
1254 | len = 65536; | ||
1255 | #endif | ||
1256 | |||
1257 | unsigned char buf[len]; | ||
1258 | struct dns_pkt *dns = (struct dns_pkt *) buf; | ||
1259 | |||
1260 | r = GNUNET_NETWORK_socket_recvfrom (dnsout, buf, sizeof (buf), | ||
1261 | (struct sockaddr *) &addr, &addrlen); | ||
1262 | |||
1263 | if (r < 0) | ||
1264 | { | ||
1265 | (void) open_port6 (); | ||
1266 | return; | ||
1267 | } | ||
1268 | |||
1269 | struct sockaddr *addr_ = GNUNET_malloc (sizeof addr); | ||
1270 | 861 | ||
1271 | memcpy (addr_, &addr, sizeof addr); | 862 | dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0); |
1272 | handle_response (dns, addr_, 4, r); | 863 | if (dnsout6 == NULL) |
1273 | |||
1274 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, dnsout6, | ||
1275 | &read_response6, NULL); | ||
1276 | } | ||
1277 | |||
1278 | /** | ||
1279 | * Read a response-packet of the UDP-Socket | ||
1280 | */ | ||
1281 | static void | ||
1282 | read_response (void *cls GNUNET_UNUSED, | ||
1283 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1284 | { | ||
1285 | struct sockaddr_in addr; | ||
1286 | socklen_t addrlen = sizeof (addr); | ||
1287 | int r; | ||
1288 | int len; | ||
1289 | |||
1290 | if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) | ||
1291 | return; | ||
1292 | |||
1293 | memset (&addr, 0, sizeof addr); | ||
1294 | |||
1295 | #ifndef MINGW | ||
1296 | if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len)) | ||
1297 | { | 864 | { |
1298 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctl"); | 865 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1299 | unhijack (dnsoutport); | 866 | _("Could not create IPv6 socket: %s\n"), |
1300 | if (GNUNET_YES == open_port ()) | 867 | STRERROR (errno)); |
1301 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &hijack, NULL); | 868 | return GNUNET_SYSERR; |
1302 | return; | ||
1303 | } | 869 | } |
1304 | #else | 870 | memset (&addr, 0, sizeof (struct sockaddr_in6)); |
1305 | /* port the code above? */ | 871 | addr.sin6_family = AF_INET6; |
1306 | len = 65536; | 872 | addr.sin6_port = htons (dnsoutport); |
1307 | #endif | 873 | int err = GNUNET_NETWORK_socket_bind (dnsout6, |
1308 | 874 | (struct sockaddr *) &addr, | |
1309 | unsigned char buf[len]; | 875 | sizeof (struct sockaddr_in6)); |
1310 | struct dns_pkt *dns = (struct dns_pkt *) buf; | ||
1311 | |||
1312 | r = GNUNET_NETWORK_socket_recvfrom (dnsout, buf, sizeof (buf), | ||
1313 | (struct sockaddr *) &addr, &addrlen); | ||
1314 | 876 | ||
1315 | if (r < 0) | 877 | if (err != GNUNET_OK) |
1316 | { | 878 | { |
1317 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom"); | 879 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1318 | unhijack (dnsoutport); | 880 | _("Could not bind to port %u: %s\n"), |
1319 | if (GNUNET_YES == open_port ()) | 881 | (unsigned int) dnsoutport, |
1320 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &hijack, NULL); | 882 | STRERROR (errno)); |
1321 | return; | 883 | GNUNET_NETWORK_socket_close (dnsout6); |
884 | dnsout6 = NULL; | ||
885 | return GNUNET_SYSERR; | ||
1322 | } | 886 | } |
1323 | 887 | if (0 == dnsoutport) | |
1324 | struct sockaddr *addr_ = GNUNET_malloc (sizeof addr); | ||
1325 | |||
1326 | memcpy (addr_, &addr, sizeof addr); | ||
1327 | handle_response (dns, addr_, 4, r); | ||
1328 | |||
1329 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, dnsout, | ||
1330 | &read_response, NULL); | ||
1331 | } | ||
1332 | |||
1333 | static void | ||
1334 | handle_response (struct dns_pkt *dns, struct sockaddr *addr, socklen_t addrlen, | ||
1335 | int r) | ||
1336 | { | ||
1337 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Answer to query %d\n", | ||
1338 | ntohs (dns->s.id)); | ||
1339 | |||
1340 | |||
1341 | if (query_states[dns->s.id].valid == GNUNET_YES) | ||
1342 | { | 888 | { |
1343 | if (query_states[dns->s.id].tunnel != NULL) | 889 | addrlen = sizeof (struct sockaddr_in6); |
890 | if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout6), | ||
891 | (struct sockaddr *) &addr, | ||
892 | &addrlen)) | ||
1344 | { | 893 | { |
1345 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 894 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1346 | "Answer to query %d for a remote peer!\n", ntohs (dns->s.id)); | 895 | _("Could not determine port I got: %s\n"), |
1347 | /* This response should go through a tunnel */ | 896 | STRERROR (errno)); |
1348 | uint32_t *c = | 897 | GNUNET_NETWORK_socket_close (dnsout6); |
1349 | GNUNET_malloc (4 + sizeof (struct GNUNET_MESH_Tunnel *) + r); | 898 | dnsout6 = NULL; |
1350 | *c = r; | 899 | return GNUNET_SYSERR; |
1351 | struct GNUNET_MESH_Tunnel **t = (struct GNUNET_MESH_Tunnel **) (c + 1); | ||
1352 | |||
1353 | *t = query_states[dns->s.id].tunnel; | ||
1354 | memcpy (t + 1, dns, r); | ||
1355 | struct tunnel_state *s = | ||
1356 | GNUNET_MESH_tunnel_get_data (query_states[dns->s.id].tunnel); | ||
1357 | if (NULL == s->th) | ||
1358 | { | ||
1359 | s->th = | ||
1360 | GNUNET_MESH_notify_transmit_ready (query_states[dns->s.id].tunnel, | ||
1361 | GNUNET_YES, 32, | ||
1362 | GNUNET_TIME_UNIT_MINUTES, NULL, | ||
1363 | r + | ||
1364 | sizeof (struct | ||
1365 | GNUNET_MessageHeader), | ||
1366 | mesh_send_response, c); | ||
1367 | } | ||
1368 | else | ||
1369 | { | ||
1370 | struct tunnel_notify_queue *element = | ||
1371 | GNUNET_malloc (sizeof (struct tunnel_notify_queue)); | ||
1372 | element->cls = c; | ||
1373 | element->len = r + sizeof (struct GNUNET_MessageHeader); | ||
1374 | element->cb = mesh_send_response; | ||
1375 | |||
1376 | GNUNET_CONTAINER_DLL_insert_tail (s->head, s->tail, element); | ||
1377 | } | ||
1378 | } | ||
1379 | else | ||
1380 | { | ||
1381 | query_states[dns->s.id].valid = GNUNET_NO; | ||
1382 | |||
1383 | size_t len = sizeof (struct answer_packet) + r - 1; /* 1 for the unsigned char data[1]; */ | ||
1384 | struct answer_packet_list *answer = | ||
1385 | GNUNET_malloc (len + sizeof (struct answer_packet_list) - | ||
1386 | (sizeof (struct answer_packet))); | ||
1387 | answer->pkt.hdr.type = | ||
1388 | htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS); | ||
1389 | answer->pkt.hdr.size = htons (len); | ||
1390 | answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_IP; | ||
1391 | answer->pkt.addrlen = addrlen; | ||
1392 | if (addrlen == 16) | ||
1393 | { | ||
1394 | struct sockaddr_in6 *addr_ = (struct sockaddr_in6 *) addr; | ||
1395 | |||
1396 | memcpy (answer->pkt.from, &addr_->sin6_addr, addrlen); | ||
1397 | memcpy (answer->pkt.to, query_states[dns->s.id].local_ip, addrlen); | ||
1398 | } | ||
1399 | else if (addrlen == 4) | ||
1400 | { | ||
1401 | struct sockaddr_in *addr_ = (struct sockaddr_in *) addr; | ||
1402 | |||
1403 | memcpy (answer->pkt.from, &addr_->sin_addr.s_addr, addrlen); | ||
1404 | memcpy (answer->pkt.to, query_states[dns->s.id].local_ip, addrlen); | ||
1405 | } | ||
1406 | else | ||
1407 | { | ||
1408 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "addrlen = %d\n", addrlen); | ||
1409 | GNUNET_assert (0); | ||
1410 | } | ||
1411 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending answer with addrlen = %d\n", | ||
1412 | addrlen); | ||
1413 | answer->pkt.dst_port = query_states[dns->s.id].local_port; | ||
1414 | memcpy (answer->pkt.data, dns, r); | ||
1415 | answer->client = query_states[dns->s.id].client; | ||
1416 | |||
1417 | GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer); | ||
1418 | |||
1419 | if (server_notify == NULL) | ||
1420 | server_notify = | ||
1421 | GNUNET_SERVER_notify_transmit_ready (query_states[dns->s.id].client, | ||
1422 | len, | ||
1423 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
1424 | &send_answer, NULL); | ||
1425 | } | 900 | } |
1426 | } | 901 | } |
1427 | GNUNET_free (addr); | 902 | dnsoutport = htons (addr.sin6_port); |
903 | read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
904 | dnsout6, | ||
905 | &read_response, dnsout6); | ||
906 | return GNUNET_YES; | ||
1428 | } | 907 | } |
1429 | 908 | ||
1430 | 909 | ||
1431 | /** | 910 | /** |
1432 | * Task run during shutdown. | 911 | * We got a new client. Make sure all new DNS requests pass by its desk. |
1433 | * | 912 | * |
1434 | * @param cls unused | 913 | * @param cls unused |
1435 | * @param tc unused | 914 | * @param client the new client |
915 | * @param message the init message (unused) | ||
1436 | */ | 916 | */ |
1437 | static void | 917 | static void |
1438 | cleanup_task (void *cls GNUNET_UNUSED, | 918 | handle_client_init (void *cls GNUNET_UNUSED, |
1439 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 919 | struct GNUNET_SERVER_Client *client, |
920 | const struct GNUNET_MessageHeader *message) | ||
1440 | { | 921 | { |
1441 | GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)); | 922 | struct ClientRecord *cr; |
923 | const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message; | ||
1442 | 924 | ||
1443 | unhijack (dnsoutport); | 925 | cr = GNUNET_malloc (sizeof (struct ClientRecord)); |
1444 | GNUNET_DHT_disconnect (dht); | 926 | cr->client = client; |
1445 | GNUNET_MESH_disconnect (mesh_handle); | 927 | cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags); |
928 | GNUNET_SERVER_client_keep (client); | ||
929 | GNUNET_CONTAINER_DLL_insert (clients_head, | ||
930 | clients_tail, | ||
931 | cr); | ||
932 | GNUNET_SERVER_notification_context_add (nc, client); | ||
933 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1446 | } | 934 | } |
1447 | 935 | ||
936 | |||
1448 | /** | 937 | /** |
1449 | * @brief Create a port-map from udp and tcp redirects | 938 | * We got a response from a client. |
1450 | * | ||
1451 | * @param udp_redirects | ||
1452 | * @param tcp_redirects | ||
1453 | * | 939 | * |
1454 | * @return | 940 | * @param cls unused |
941 | * @param client the client | ||
942 | * @param message the response | ||
1455 | */ | 943 | */ |
1456 | static uint64_t | 944 | static void |
1457 | get_port_from_redirects (const char *udp_redirects, const char *tcp_redirects) | 945 | handle_client_response (void *cls GNUNET_UNUSED, |
946 | struct GNUNET_SERVER_Client *client, | ||
947 | const struct GNUNET_MessageHeader *message) | ||
1458 | { | 948 | { |
1459 | uint64_t ret = 0; | 949 | const struct GNUNET_DNS_Response *resp; |
1460 | char *cpy, *hostname, *redirect; | 950 | struct RequestRecord *rr; |
1461 | int local_port; | 951 | unsigned int i; |
1462 | unsigned int count = 0; | 952 | uint16_t msize; |
1463 | 953 | uint16_t off; | |
1464 | cpy = NULL; | 954 | |
1465 | if (NULL != udp_redirects) | 955 | msize = ntohs (message->size); |
956 | if (msize < sizeof (struct GNUNET_DNS_Response)) | ||
1466 | { | 957 | { |
1467 | cpy = GNUNET_strdup (udp_redirects); | 958 | GNUNET_break (0); |
1468 | for (redirect = strtok (cpy, " "); redirect != NULL; | 959 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); |
1469 | redirect = strtok (NULL, " ")) | 960 | return; |
1470 | { | ||
1471 | if (NULL == (hostname = strstr (redirect, ":"))) | ||
1472 | { | ||
1473 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1474 | "Warning: option %s is not formatted correctly!\n", | ||
1475 | redirect); | ||
1476 | continue; | ||
1477 | } | ||
1478 | hostname[0] = '\0'; | ||
1479 | local_port = atoi (redirect); | ||
1480 | if (!((local_port > 0) && (local_port < 65536))) | ||
1481 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1482 | "Warning: %s is not a correct port.", redirect); | ||
1483 | |||
1484 | ret |= (0xFFFF & htons (local_port)); | ||
1485 | ret <<= 16; | ||
1486 | count++; | ||
1487 | |||
1488 | if (count > 4) | ||
1489 | { | ||
1490 | ret = 0; | ||
1491 | goto out; | ||
1492 | } | ||
1493 | } | ||
1494 | GNUNET_free (cpy); | ||
1495 | cpy = NULL; | ||
1496 | } | 961 | } |
1497 | 962 | resp = (const struct GNUNET_DNS_Response*) message; | |
1498 | if (NULL != tcp_redirects) | 963 | off = (uint16_t) resp->request_id; |
964 | rr = &requests[off]; | ||
965 | if (rr->request_id != resp->request_id) | ||
1499 | { | 966 | { |
1500 | cpy = GNUNET_strdup (tcp_redirects); | 967 | GNUNET_STATISTICS_update (stats, |
1501 | for (redirect = strtok (cpy, " "); redirect != NULL; | 968 | gettext_noop ("# Client response discarded (no matching request)"), |
1502 | redirect = strtok (NULL, " ")) | 969 | 1, GNUNET_NO); |
970 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
971 | return; | ||
972 | } | ||
973 | for (i=0;i<rr->client_wait_list_length;i++) | ||
974 | { | ||
975 | if (NULL == rr->client_wait_list[i]) | ||
976 | continue; | ||
977 | if (rr->client_wait_list[i]->client != client) | ||
978 | continue; | ||
979 | rr->client_wait_list[i] = NULL; | ||
980 | switch (ntohl (resp->drop_flag)) | ||
1503 | { | 981 | { |
1504 | if (NULL == (hostname = strstr (redirect, ":"))) | 982 | case 0: /* drop */ |
983 | rr->phase = RP_DROP; | ||
984 | break; | ||
985 | case 1: /* no change */ | ||
986 | break; | ||
987 | case 2: /* update */ | ||
988 | msize -= sizeof (struct GNUNET_DNS_Response); | ||
989 | if ( (sizeof (struct dns_header) > msize) || | ||
990 | (RP_REQUEST_MONITOR == rr->phase) || | ||
991 | (RP_RESPONSE_MONITOR == rr->phase) ) | ||
1505 | { | 992 | { |
1506 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 993 | GNUNET_break (0); |
1507 | "Warning: option %s is not formatted correctly!\n", | 994 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); |
1508 | redirect); | 995 | next_phase (rr); |
1509 | continue; | 996 | return; |
1510 | } | 997 | } |
1511 | hostname[0] = '\0'; | 998 | GNUNET_free_non_null (rr->payload); |
1512 | local_port = atoi (redirect); | 999 | #if DEBUG_DNS |
1513 | if (!((local_port > 0) && (local_port < 65536))) | 1000 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1514 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 1001 | _("Changing DNS reply according to client specifications\n")); |
1515 | "Warning: %s is not a correct port.", redirect); | 1002 | #endif |
1516 | 1003 | rr->payload = GNUNET_malloc (msize); | |
1517 | ret |= (0xFFFF & htons (local_port)); | 1004 | rr->payload_length = msize; |
1518 | ret <<= 16; | 1005 | memcpy (rr->payload, &resp[1], msize); |
1519 | count++; | 1006 | if (rr->phase == RP_QUERY) |
1520 | |||
1521 | if (count > 4) | ||
1522 | { | 1007 | { |
1523 | ret = 0; | 1008 | /* clear wait list, we're moving to MODIFY phase next */ |
1524 | goto out; | 1009 | GNUNET_array_grow (rr->client_wait_list, |
1010 | rr->client_wait_list_length, | ||
1011 | 0); | ||
1525 | } | 1012 | } |
1013 | break; | ||
1526 | } | 1014 | } |
1527 | GNUNET_free (cpy); | 1015 | next_phase (rr); |
1528 | cpy = NULL; | 1016 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
1017 | return; | ||
1529 | } | 1018 | } |
1530 | 1019 | /* odd, client was not on our list for the request, that ought | |
1531 | out: | 1020 | to be an error */ |
1532 | GNUNET_free_non_null (cpy); | 1021 | GNUNET_break (0); |
1533 | return ret; | 1022 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); |
1534 | } | ||
1535 | |||
1536 | static void | ||
1537 | publish_name (const char *name, uint64_t ports, uint32_t service_type, | ||
1538 | struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key) | ||
1539 | { | ||
1540 | size_t size = sizeof (struct GNUNET_DNS_Record); | ||
1541 | struct GNUNET_DNS_Record data; | ||
1542 | |||
1543 | memset (&data, 0, size); | ||
1544 | |||
1545 | data.purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature)); | ||
1546 | data.purpose.purpose = GNUNET_SIGNATURE_PURPOSE_DNS_RECORD; | ||
1547 | |||
1548 | GNUNET_CRYPTO_hash (name, strlen (name) + 1, &data.service_descriptor); | ||
1549 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Store with key1 %x\n", | ||
1550 | *((unsigned long long *) &data.service_descriptor)); | ||
1551 | |||
1552 | data.service_type = service_type; | ||
1553 | data.ports = ports; | ||
1554 | |||
1555 | GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &data.peer); | ||
1556 | |||
1557 | data.expiration_time = | ||
1558 | GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute | ||
1559 | (GNUNET_TIME_relative_multiply | ||
1560 | (GNUNET_TIME_UNIT_HOURS, 2))); | ||
1561 | |||
1562 | /* Sign the block */ | ||
1563 | if (GNUNET_OK != | ||
1564 | GNUNET_CRYPTO_rsa_sign (my_private_key, &data.purpose, &data.signature)) | ||
1565 | { | ||
1566 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not sign DNS_Record\n"); | ||
1567 | return; | ||
1568 | } | ||
1569 | |||
1570 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Putting with key %08x, size = %d\n", | ||
1571 | *((unsigned int *) &data.service_descriptor), size); | ||
1572 | |||
1573 | GNUNET_DHT_put (dht, &data.service_descriptor, | ||
1574 | 5 /* DEFAULT_PUT_REPLICATION */ , | ||
1575 | GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_DNS, size, | ||
1576 | (char *) &data, | ||
1577 | GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS), | ||
1578 | GNUNET_TIME_UNIT_MINUTES, NULL, NULL); | ||
1579 | } | 1023 | } |
1580 | 1024 | ||
1581 | 1025 | ||
1582 | /** | 1026 | /** |
1583 | * @brief Publishes the record defined by the section section | 1027 | * Functions with this signature are called whenever a complete |
1028 | * message is received by the tokenizer from the DNS hijack process. | ||
1584 | * | 1029 | * |
1585 | * @param cls closure | 1030 | * @param cls closure |
1586 | * @param section the current section | 1031 | * @param client identification of the client |
1032 | * @param message the actual message, a DNS request we should handle | ||
1587 | */ | 1033 | */ |
1588 | static void | 1034 | static void |
1589 | publish_iterate (void *cls GNUNET_UNUSED, const char *section) | 1035 | process_helper_messages (void *cls GNUNET_UNUSED, void *client, |
1036 | const struct GNUNET_MessageHeader *message) | ||
1590 | { | 1037 | { |
1591 | char *udp_redirects; | 1038 | uint16_t msize; |
1592 | char *tcp_redirects; | 1039 | const struct tun_header *tun; |
1593 | char *alternative_names; | 1040 | const struct ip4_header *ip4; |
1594 | char *alternative_name; | 1041 | const struct ip6_header *ip6; |
1595 | char *keyfile; | 1042 | const struct udp_packet *udp; |
1596 | 1043 | const struct dns_header *dns; | |
1597 | if ((strlen (section) < 8) || | 1044 | struct RequestRecord *rr; |
1598 | (0 != strcmp (".gnunet.", section + (strlen (section) - 8)))) | 1045 | struct sockaddr_in *srca4; |
1599 | return; | 1046 | struct sockaddr_in6 *srca6; |
1600 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing dns-name %s\n", section); | 1047 | struct sockaddr_in *dsta4; |
1601 | if (GNUNET_OK != | 1048 | struct sockaddr_in6 *dsta6; |
1602 | GNUNET_CONFIGURATION_get_value_string (cfg, section, "UDP_REDIRECTS", | 1049 | |
1603 | &udp_redirects)) | 1050 | msize = ntohs (message->size); |
1604 | udp_redirects = NULL; | 1051 | if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header) + sizeof (struct ip4_header)) |
1605 | if (GNUNET_OK != | ||
1606 | GNUNET_CONFIGURATION_get_value_string (cfg, section, "TCP_REDIRECTS", | ||
1607 | &tcp_redirects)) | ||
1608 | tcp_redirects = NULL; | ||
1609 | |||
1610 | if (GNUNET_OK != | ||
1611 | GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", | ||
1612 | &keyfile)) | ||
1613 | { | 1052 | { |
1614 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not read keyfile-value\n"); | 1053 | /* non-IP packet received on TUN!? */ |
1615 | if (keyfile != NULL) | 1054 | GNUNET_break (0); |
1616 | GNUNET_free (keyfile); | ||
1617 | return; | 1055 | return; |
1618 | } | 1056 | } |
1619 | 1057 | msize -= sizeof (struct GNUNET_MessageHeader); | |
1620 | struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key = | 1058 | tun = (const struct tun_header *) &message[1]; |
1621 | GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); | 1059 | msize -= sizeof (struct tun_header); |
1622 | GNUNET_free (keyfile); | 1060 | switch (ntohs (tun->proto)) |
1623 | GNUNET_assert (my_private_key != NULL); | ||
1624 | |||
1625 | uint64_t ports = get_port_from_redirects (udp_redirects, tcp_redirects); | ||
1626 | uint32_t service_type = 0; | ||
1627 | |||
1628 | if (NULL != udp_redirects) | ||
1629 | service_type = GNUNET_DNS_SERVICE_TYPE_UDP; | ||
1630 | |||
1631 | if (NULL != tcp_redirects) | ||
1632 | service_type |= GNUNET_DNS_SERVICE_TYPE_TCP; | ||
1633 | |||
1634 | service_type = htonl (service_type); | ||
1635 | |||
1636 | |||
1637 | publish_name (section, ports, service_type, my_private_key); | ||
1638 | if (GNUNET_OK == | ||
1639 | GNUNET_CONFIGURATION_get_value_string (cfg, section, "ALTERNATIVE_NAMES", | ||
1640 | &alternative_names)) | ||
1641 | { | 1061 | { |
1642 | for (alternative_name = strtok (alternative_names, " "); | 1062 | case ETH_P_IPV4: |
1643 | alternative_name != NULL; alternative_name = strtok (NULL, " ")) | 1063 | ip4 = (const struct ip4_header *) &tun[1]; |
1064 | if ( (msize < sizeof (struct ip4_header)) || | ||
1065 | (ip4->version != IPVERSION) || | ||
1066 | (ip4->header_length != sizeof (struct ip4_header) / 4) || | ||
1067 | (ntohs(ip4->total_length) != msize) || | ||
1068 | (ip4->protocol != IPPROTO_UDP) ) | ||
1644 | { | 1069 | { |
1645 | char *altname = | 1070 | /* non-IP/UDP packet received on TUN (or with options) */ |
1646 | alloca (strlen (alternative_name) + strlen (section) + 1 + 1); | 1071 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1647 | strcpy (altname, alternative_name); | 1072 | _("Received malformed IPv4-UDP packet on TUN interface.\n")); |
1648 | strcpy (altname + strlen (alternative_name) + 1, section); | 1073 | return; |
1649 | altname[strlen (alternative_name)] = '.'; | 1074 | } |
1650 | 1075 | udp = (const struct udp_packet*) &ip4[1]; | |
1651 | publish_name (altname, ports, service_type, my_private_key); | 1076 | msize -= sizeof (struct ip4_header); |
1077 | break; | ||
1078 | case ETH_P_IPV6: | ||
1079 | ip6 = (const struct ip6_header *) &tun[1]; | ||
1080 | if ( (msize < sizeof (struct ip6_header)) || | ||
1081 | (ip6->version != 6) || | ||
1082 | (ntohs (ip6->payload_length) != msize) || | ||
1083 | (ip6->next_header != IPPROTO_UDP) ) | ||
1084 | { | ||
1085 | /* non-IP/UDP packet received on TUN (or with extensions) */ | ||
1086 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1087 | _("Received malformed IPv6-UDP packet on TUN interface.\n")); | ||
1088 | return; | ||
1652 | } | 1089 | } |
1653 | GNUNET_free (alternative_names); | 1090 | udp = (const struct udp_packet*) &ip6[1]; |
1091 | msize -= sizeof (struct ip6_header); | ||
1092 | break; | ||
1093 | default: | ||
1094 | /* non-IP packet received on TUN!? */ | ||
1095 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1096 | _("Got non-IP packet with %u bytes and protocol %u from TUN\n"), | ||
1097 | (unsigned int) msize, | ||
1098 | ntohs (tun->proto)); | ||
1099 | return; | ||
1654 | } | 1100 | } |
1655 | GNUNET_CRYPTO_rsa_key_free (my_private_key); | 1101 | if (msize <= sizeof (struct udp_packet) + sizeof (struct dns_header)) |
1656 | GNUNET_free_non_null (udp_redirects); | 1102 | { |
1657 | GNUNET_free_non_null (tcp_redirects); | 1103 | /* non-DNS packet received on TUN, ignore */ |
1658 | } | 1104 | GNUNET_STATISTICS_update (stats, |
1659 | 1105 | gettext_noop ("# Non-DNS UDP packet received via TUN interface"), | |
1660 | /** | 1106 | 1, GNUNET_NO); |
1661 | * Publish a DNS-record in the DHT. | ||
1662 | */ | ||
1663 | static void | ||
1664 | publish_names (void *cls GNUNET_UNUSED, | ||
1665 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1666 | { | ||
1667 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1668 | return; | 1107 | return; |
1669 | 1108 | } | |
1670 | GNUNET_CONFIGURATION_iterate_sections (cfg, &publish_iterate, NULL); | 1109 | msize -= sizeof (struct udp_packet); |
1671 | 1110 | dns = (const struct dns_header*) &udp[1]; | |
1672 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_HOURS, &publish_names, NULL); | 1111 | rr = &requests[dns->id]; |
1112 | |||
1113 | /* clean up from previous request */ | ||
1114 | GNUNET_free_non_null (rr->payload); | ||
1115 | rr->payload = NULL; | ||
1116 | GNUNET_array_grow (rr->client_wait_list, | ||
1117 | rr->client_wait_list_length, | ||
1118 | 0); | ||
1119 | |||
1120 | /* setup new request */ | ||
1121 | rr->phase = RP_INIT; | ||
1122 | if (ip4->version == IPVERSION) | ||
1123 | { | ||
1124 | srca4 = (struct sockaddr_in*) &rr->src_addr; | ||
1125 | dsta4 = (struct sockaddr_in*) &rr->dst_addr; | ||
1126 | memset (srca4, 0, sizeof (struct sockaddr_in)); | ||
1127 | memset (dsta4, 0, sizeof (struct sockaddr_in)); | ||
1128 | srca4->sin_family = AF_INET; | ||
1129 | dsta4->sin_family = AF_INET; | ||
1130 | srca4->sin_addr = ip4->source_address; | ||
1131 | dsta4->sin_addr = ip4->destination_address; | ||
1132 | srca4->sin_port = udp->spt; | ||
1133 | dsta4->sin_port = udp->dpt; | ||
1134 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1135 | srca4->sin_len = sizeof (sizeof (struct sockaddr_in)); | ||
1136 | dsta4->sin_len = sizeof (sizeof (struct sockaddr_in)); | ||
1137 | #endif | ||
1138 | } | ||
1139 | else /* ipv6 */ | ||
1140 | { | ||
1141 | srca6 = (struct sockaddr_in6*) &rr->src_addr; | ||
1142 | dsta6 = (struct sockaddr_in6*) &rr->dst_addr; | ||
1143 | memset (srca6, 0, sizeof (struct sockaddr_in6)); | ||
1144 | memset (dsta6, 0, sizeof (struct sockaddr_in6)); | ||
1145 | srca6->sin6_family = AF_INET6; | ||
1146 | dsta6->sin6_family = AF_INET6; | ||
1147 | srca6->sin6_addr = ip6->source_address; | ||
1148 | dsta6->sin6_addr = ip6->destination_address; | ||
1149 | srca6->sin6_port = udp->spt; | ||
1150 | dsta6->sin6_port = udp->dpt; | ||
1151 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1152 | srca6->sin6_len = sizeof (sizeof (struct sockaddr_in6)); | ||
1153 | dsta6->sin6_len = sizeof (sizeof (struct sockaddr_in6)); | ||
1154 | #endif | ||
1155 | } | ||
1156 | rr->payload = GNUNET_malloc (msize); | ||
1157 | rr->payload_length = msize; | ||
1158 | memcpy (rr->payload, dns, msize); | ||
1159 | rr->request_id = dns->id | (request_id_gen << 16); | ||
1160 | request_id_gen++; | ||
1161 | |||
1162 | GNUNET_STATISTICS_update (stats, | ||
1163 | gettext_noop ("# DNS requests received via TUN interface"), | ||
1164 | 1, GNUNET_NO); | ||
1165 | /* start request processing state machine */ | ||
1166 | next_phase (rr); | ||
1673 | } | 1167 | } |
1674 | 1168 | ||
1169 | |||
1675 | /** | 1170 | /** |
1676 | * @param cls closure | 1171 | * @param cls closure |
1677 | * @param server the initialized server | 1172 | * @param server the initialized server |
@@ -1683,51 +1178,102 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, | |||
1683 | { | 1178 | { |
1684 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | 1179 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { |
1685 | /* callback, cls, type, size */ | 1180 | /* callback, cls, type, size */ |
1686 | {&receive_query, NULL, GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_QUERY_DNS, 0}, | 1181 | {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, |
1687 | {&rehijack, NULL, GNUNET_MESSAGE_TYPE_REHIJACK, | 1182 | sizeof (struct GNUNET_DNS_Register)}, |
1688 | sizeof (struct GNUNET_MessageHeader)}, | 1183 | {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0}, |
1689 | {NULL, NULL, 0, 0} | 1184 | {NULL, NULL, 0, 0} |
1690 | }; | 1185 | }; |
1186 | char port_s[6]; | ||
1187 | char *ifc_name; | ||
1188 | char *ipv4addr; | ||
1189 | char *ipv4mask; | ||
1190 | char *ipv6addr; | ||
1191 | char *ipv6prefix; | ||
1691 | 1192 | ||
1692 | static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = { | 1193 | cfg = cfg_; |
1693 | {receive_mesh_query, GNUNET_MESSAGE_TYPE_VPN_REMOTE_QUERY_DNS, 0}, | 1194 | stats = GNUNET_STATISTICS_create ("dns", cfg); |
1694 | {receive_mesh_answer, GNUNET_MESSAGE_TYPE_VPN_REMOTE_ANSWER_DNS, 0}, | 1195 | nc = GNUNET_SERVER_notification_context_create (server, 1); |
1695 | {NULL, 0, 0} | 1196 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, |
1696 | }; | 1197 | cls); |
1697 | 1198 | if (GNUNET_YES == | |
1698 | static GNUNET_MESH_ApplicationType apptypes[] = { | 1199 | GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) |
1699 | GNUNET_APPLICATION_TYPE_END, | 1200 | { |
1700 | GNUNET_APPLICATION_TYPE_END | 1201 | if ( (GNUNET_OK != open_port4 ()) && |
1701 | }; | 1202 | (GNUNET_OK != open_port6 ()) ) |
1203 | { | ||
1204 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1205 | _("Failed to open any port to provide DNS exit\n")); | ||
1206 | GNUNET_SCHEDULER_shutdown (); | ||
1207 | return; | ||
1208 | } | ||
1209 | } | ||
1702 | 1210 | ||
1703 | if (GNUNET_YES != open_port6 ()) | 1211 | helper_argv[0] = GNUNET_strdup ("gnunet-dns"); |
1212 | if (GNUNET_SYSERR == | ||
1213 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name)) | ||
1704 | { | 1214 | { |
1215 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1216 | "No entry 'IFNAME' in configuration!\n"); | ||
1705 | GNUNET_SCHEDULER_shutdown (); | 1217 | GNUNET_SCHEDULER_shutdown (); |
1706 | return; | 1218 | return; |
1707 | } | 1219 | } |
1708 | 1220 | helper_argv[1] = ifc_name; | |
1709 | if (GNUNET_YES != open_port ()) | 1221 | if ( (GNUNET_SYSERR == |
1222 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR", | ||
1223 | &ipv6addr)) ) | ||
1710 | { | 1224 | { |
1225 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1226 | "No entry 'IPV6ADDR' in configuration!\n"); | ||
1711 | GNUNET_SCHEDULER_shutdown (); | 1227 | GNUNET_SCHEDULER_shutdown (); |
1712 | return; | 1228 | return; |
1713 | } | 1229 | } |
1230 | helper_argv[2] = ipv6addr; | ||
1231 | if (GNUNET_SYSERR == | ||
1232 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX", | ||
1233 | &ipv6prefix)) | ||
1234 | { | ||
1235 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1236 | "No entry 'IPV6PREFIX' in configuration!\n"); | ||
1237 | GNUNET_SCHEDULER_shutdown (); | ||
1238 | return; | ||
1239 | } | ||
1240 | helper_argv[3] = ipv6prefix; | ||
1714 | 1241 | ||
1715 | if (GNUNET_YES == | 1242 | if (GNUNET_SYSERR == |
1716 | GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) | 1243 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR", |
1717 | apptypes[0] = GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER; | 1244 | &ipv4addr)) |
1718 | mesh_handle = | 1245 | { |
1719 | GNUNET_MESH_connect (cfg_, 42, NULL, new_tunnel, clean_tunnel, | 1246 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1720 | mesh_handlers, apptypes); | 1247 | "No entry 'IPV4ADDR' in configuration!\n"); |
1721 | 1248 | GNUNET_SCHEDULER_shutdown (); | |
1722 | cfg = cfg_; | 1249 | return; |
1723 | dht = GNUNET_DHT_connect (cfg, 1024); | 1250 | } |
1724 | GNUNET_SCHEDULER_add_now (publish_names, NULL); | 1251 | helper_argv[4] = ipv4addr; |
1252 | if (GNUNET_SYSERR == | ||
1253 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK", | ||
1254 | &ipv4mask)) | ||
1255 | { | ||
1256 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1257 | "No entry 'IPV4MASK' in configuration!\n"); | ||
1258 | GNUNET_SCHEDULER_shutdown (); | ||
1259 | return; | ||
1260 | } | ||
1261 | helper_argv[5] = ipv4mask; | ||
1262 | GNUNET_snprintf (port_s, | ||
1263 | sizeof (port_s), | ||
1264 | "%u", | ||
1265 | (unsigned int) dnsoutport); | ||
1266 | helper_argv[6] = GNUNET_strdup (port_s); | ||
1267 | helper_argv[7] = NULL; | ||
1268 | hijacker = GNUNET_HELPER_start ("gnunet-helper-dns", | ||
1269 | helper_argv, | ||
1270 | &process_helper_messages, | ||
1271 | NULL); | ||
1725 | GNUNET_SERVER_add_handlers (server, handlers); | 1272 | GNUNET_SERVER_add_handlers (server, handlers); |
1726 | GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL); | 1273 | GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL); |
1727 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, | ||
1728 | cls); | ||
1729 | } | 1274 | } |
1730 | 1275 | ||
1276 | |||
1731 | /** | 1277 | /** |
1732 | * The main function for the dns service. | 1278 | * The main function for the dns service. |
1733 | * | 1279 | * |
@@ -1742,3 +1288,6 @@ main (int argc, char *const *argv) | |||
1742 | GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE, | 1288 | GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE, |
1743 | &run, NULL)) ? 0 : 1; | 1289 | &run, NULL)) ? 0 : 1; |
1744 | } | 1290 | } |
1291 | |||
1292 | |||
1293 | /* end of gnunet-service-dns_new.c */ | ||
diff --git a/src/dns/gnunet-service-dns_new.c b/src/dns/gnunet-service-dns_new.c deleted file mode 100644 index 0bb7fb21c..000000000 --- a/src/dns/gnunet-service-dns_new.c +++ /dev/null | |||
@@ -1,1293 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2012 Christian Grothoff (and other contributing authors) | ||
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., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file dns/gnunet-service-dns_new.c | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "gnunet_constants.h" | ||
28 | #include "gnunet_protocols.h" | ||
29 | #include "gnunet_signatures.h" | ||
30 | #include "dns_new.h" | ||
31 | #include "gnunet_dns_service-new.h" | ||
32 | #include "gnunet_statistics_service.h" | ||
33 | #include "tcpip_tun.h" | ||
34 | |||
35 | #ifndef IPVERSION | ||
36 | #define IPVERSION 4 | ||
37 | #endif | ||
38 | |||
39 | /** | ||
40 | * Phases each request goes through. | ||
41 | */ | ||
42 | enum RequestPhase | ||
43 | { | ||
44 | /** | ||
45 | * Request has just been received. | ||
46 | */ | ||
47 | RP_INIT, | ||
48 | |||
49 | /** | ||
50 | * Showing the request to all monitor clients. If | ||
51 | * client list is empty, will enter QUERY phase. | ||
52 | */ | ||
53 | RP_REQUEST_MONITOR, | ||
54 | |||
55 | /** | ||
56 | * Showing the request to PRE-RESOLUTION clients to find an answer. | ||
57 | * If client list is empty, will trigger global DNS request. | ||
58 | */ | ||
59 | RP_QUERY, | ||
60 | |||
61 | /** | ||
62 | * Global Internet query is now pending. | ||
63 | */ | ||
64 | RP_INTERNET_DNS, | ||
65 | |||
66 | /** | ||
67 | * Client (or global DNS request) has resulted in a response. | ||
68 | * Forward to all POST-RESOLUTION clients. If client list is empty, | ||
69 | * will enter RESPONSE_MONITOR phase. | ||
70 | */ | ||
71 | RP_MODIFY, | ||
72 | |||
73 | /** | ||
74 | * Showing the request to all monitor clients. If | ||
75 | * client list is empty, give the result to the hijacker (and be done). | ||
76 | */ | ||
77 | RP_RESPONSE_MONITOR, | ||
78 | |||
79 | /** | ||
80 | * Some client has told us to drop the request. | ||
81 | */ | ||
82 | RP_DROP | ||
83 | }; | ||
84 | |||
85 | |||
86 | /** | ||
87 | * Entry we keep for each client. | ||
88 | */ | ||
89 | struct ClientRecord | ||
90 | { | ||
91 | /** | ||
92 | * Kept in doubly-linked list. | ||
93 | */ | ||
94 | struct ClientRecord *next; | ||
95 | |||
96 | /** | ||
97 | * Kept in doubly-linked list. | ||
98 | */ | ||
99 | struct ClientRecord *prev; | ||
100 | |||
101 | /** | ||
102 | * Handle to the client. | ||
103 | */ | ||
104 | struct GNUNET_SERVER_Client *client; | ||
105 | |||
106 | /** | ||
107 | * Flags for the client. | ||
108 | */ | ||
109 | enum GNUNET_DNS_Flags flags; | ||
110 | |||
111 | }; | ||
112 | |||
113 | |||
114 | /** | ||
115 | * Entry we keep for each active request. | ||
116 | */ | ||
117 | struct RequestRecord | ||
118 | { | ||
119 | |||
120 | /** | ||
121 | * List of clients that still need to see this request (each entry | ||
122 | * is set to NULL when the client is done). | ||
123 | */ | ||
124 | struct ClientRecord **client_wait_list; | ||
125 | |||
126 | /** | ||
127 | * Payload of the UDP packet (the UDP payload), can be either query | ||
128 | * or already the response. | ||
129 | */ | ||
130 | char *payload; | ||
131 | |||
132 | /** | ||
133 | * Source address of the original request (for sending response). | ||
134 | */ | ||
135 | struct sockaddr_storage src_addr; | ||
136 | |||
137 | /** | ||
138 | * Destination address of the original request (for potential use as exit). | ||
139 | */ | ||
140 | struct sockaddr_storage dst_addr; | ||
141 | |||
142 | /** | ||
143 | * ID of this request, also basis for hashing. Lowest 16 bit will | ||
144 | * be our message ID when doing a global DNS request and our index | ||
145 | * into the 'requests' array. | ||
146 | */ | ||
147 | uint64_t request_id; | ||
148 | |||
149 | /** | ||
150 | * Number of bytes in payload. | ||
151 | */ | ||
152 | size_t payload_length; | ||
153 | |||
154 | /** | ||
155 | * Length of the client wait list. | ||
156 | */ | ||
157 | unsigned int client_wait_list_length; | ||
158 | |||
159 | /** | ||
160 | * In which phase this this request? | ||
161 | */ | ||
162 | enum RequestPhase phase; | ||
163 | |||
164 | }; | ||
165 | |||
166 | |||
167 | /** | ||
168 | * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be | ||
169 | * sent through gnunet. The port of this socket will not be hijacked. | ||
170 | */ | ||
171 | static struct GNUNET_NETWORK_Handle *dnsout4; | ||
172 | |||
173 | /** | ||
174 | * The IPv6 UDP-Socket through which DNS-Resolves will be sent if they are not to be | ||
175 | * sent through gnunet. The port of this socket will not be hijacked. | ||
176 | */ | ||
177 | static struct GNUNET_NETWORK_Handle *dnsout6; | ||
178 | |||
179 | /** | ||
180 | * Task for reading from dnsout4. | ||
181 | */ | ||
182 | static GNUNET_SCHEDULER_TaskIdentifier read4_task; | ||
183 | |||
184 | /** | ||
185 | * Task for reading from dnsout6. | ||
186 | */ | ||
187 | static GNUNET_SCHEDULER_TaskIdentifier read6_task; | ||
188 | |||
189 | /** | ||
190 | * The port bound to the socket dnsout (and/or dnsout6). We always (try) to bind | ||
191 | * both sockets to the same port. | ||
192 | */ | ||
193 | static uint16_t dnsoutport; | ||
194 | |||
195 | /** | ||
196 | * The configuration to use | ||
197 | */ | ||
198 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
199 | |||
200 | /** | ||
201 | * Statistics. | ||
202 | */ | ||
203 | static struct GNUNET_STATISTICS_Handle *stats; | ||
204 | |||
205 | /** | ||
206 | * Handle to DNS hijacker helper process ("gnunet-helper-dns"). | ||
207 | */ | ||
208 | static struct GNUNET_HELPER_Handle *hijacker; | ||
209 | |||
210 | /** | ||
211 | * Command-line arguments we are giving to the hijacker process. | ||
212 | */ | ||
213 | static char *helper_argv[8]; | ||
214 | |||
215 | /** | ||
216 | * Head of DLL of clients we consult. | ||
217 | */ | ||
218 | static struct ClientRecord *clients_head; | ||
219 | |||
220 | /** | ||
221 | * Tail of DLL of clients we consult. | ||
222 | */ | ||
223 | static struct ClientRecord *clients_tail; | ||
224 | |||
225 | /** | ||
226 | * Our notification context. | ||
227 | */ | ||
228 | static struct GNUNET_SERVER_NotificationContext *nc; | ||
229 | |||
230 | /** | ||
231 | * Array of all open requests. | ||
232 | */ | ||
233 | static struct RequestRecord requests[UINT16_MAX + 1]; | ||
234 | |||
235 | /** | ||
236 | * Generator for unique request IDs. | ||
237 | */ | ||
238 | static uint64_t request_id_gen; | ||
239 | |||
240 | |||
241 | /** | ||
242 | * We're done processing a DNS request, free associated memory. | ||
243 | * | ||
244 | * @param rr request to clean up | ||
245 | */ | ||
246 | static void | ||
247 | cleanup_rr (struct RequestRecord *rr) | ||
248 | { | ||
249 | GNUNET_free_non_null (rr->payload); | ||
250 | rr->payload = NULL; | ||
251 | rr->payload_length = 0; | ||
252 | GNUNET_array_grow (rr->client_wait_list, | ||
253 | rr->client_wait_list_length, | ||
254 | 0); | ||
255 | } | ||
256 | |||
257 | |||
258 | /** | ||
259 | * Task run during shutdown. | ||
260 | * | ||
261 | * @param cls unused | ||
262 | * @param tc unused | ||
263 | */ | ||
264 | static void | ||
265 | cleanup_task (void *cls GNUNET_UNUSED, | ||
266 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
267 | { | ||
268 | unsigned int i; | ||
269 | |||
270 | GNUNET_HELPER_stop (hijacker); | ||
271 | hijacker = NULL; | ||
272 | for (i=0;i<8;i++) | ||
273 | GNUNET_free_non_null (helper_argv[i]); | ||
274 | if (NULL != dnsout4) | ||
275 | { | ||
276 | GNUNET_NETWORK_socket_close (dnsout4); | ||
277 | dnsout4 = NULL; | ||
278 | } | ||
279 | if (GNUNET_SCHEDULER_NO_TASK != read4_task) | ||
280 | { | ||
281 | GNUNET_SCHEDULER_cancel (read4_task); | ||
282 | read4_task = GNUNET_SCHEDULER_NO_TASK; | ||
283 | } | ||
284 | if (NULL != dnsout6) | ||
285 | { | ||
286 | GNUNET_NETWORK_socket_close (dnsout6); | ||
287 | dnsout6 = NULL; | ||
288 | } | ||
289 | if (GNUNET_SCHEDULER_NO_TASK != read6_task) | ||
290 | { | ||
291 | GNUNET_SCHEDULER_cancel (read6_task); | ||
292 | read6_task = GNUNET_SCHEDULER_NO_TASK; | ||
293 | } | ||
294 | for (i=0;i<65536;i++) | ||
295 | cleanup_rr (&requests[i]); | ||
296 | GNUNET_SERVER_notification_context_destroy (nc); | ||
297 | nc = NULL; | ||
298 | if (stats != NULL) | ||
299 | { | ||
300 | GNUNET_STATISTICS_destroy (stats, GNUNET_YES); | ||
301 | stats = NULL; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | |||
306 | /** | ||
307 | * We're done with some request, finish processing. | ||
308 | * | ||
309 | * @param rr request send to the network or just clean up. | ||
310 | */ | ||
311 | static void | ||
312 | request_done (struct RequestRecord *rr) | ||
313 | { | ||
314 | struct GNUNET_MessageHeader *hdr; | ||
315 | size_t reply_len; | ||
316 | uint16_t spt; | ||
317 | uint16_t dpt; | ||
318 | |||
319 | GNUNET_array_grow (rr->client_wait_list, | ||
320 | rr->client_wait_list_length, | ||
321 | 0); | ||
322 | if (RP_RESPONSE_MONITOR != rr->phase) | ||
323 | { | ||
324 | /* no response, drop */ | ||
325 | cleanup_rr (rr); | ||
326 | return; | ||
327 | } | ||
328 | |||
329 | /* send response via hijacker */ | ||
330 | reply_len = sizeof (struct GNUNET_MessageHeader); | ||
331 | reply_len += sizeof (struct tun_header); | ||
332 | switch (rr->src_addr.ss_family) | ||
333 | { | ||
334 | case AF_INET: | ||
335 | reply_len += sizeof (struct ip4_header); | ||
336 | break; | ||
337 | case AF_INET6: | ||
338 | reply_len += sizeof (struct ip6_header); | ||
339 | break; | ||
340 | default: | ||
341 | GNUNET_break (0); | ||
342 | cleanup_rr (rr); | ||
343 | return; | ||
344 | } | ||
345 | reply_len += sizeof (struct udp_packet); | ||
346 | reply_len += rr->payload_length; | ||
347 | if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
348 | { | ||
349 | /* response too big, drop */ | ||
350 | GNUNET_break (0); /* how can this be? */ | ||
351 | cleanup_rr(rr); | ||
352 | return; | ||
353 | } | ||
354 | { | ||
355 | char buf[reply_len]; | ||
356 | size_t off; | ||
357 | uint32_t udp_crc_sum; | ||
358 | |||
359 | /* first, GNUnet message header */ | ||
360 | hdr = (struct GNUNET_MessageHeader*) buf; | ||
361 | hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER); | ||
362 | hdr->size = htons ((uint16_t) reply_len); | ||
363 | off = sizeof (struct GNUNET_MessageHeader); | ||
364 | |||
365 | /* first, TUN header */ | ||
366 | { | ||
367 | struct tun_header tun; | ||
368 | |||
369 | tun.flags = htons (0); | ||
370 | if (rr->src_addr.ss_family == AF_INET) | ||
371 | tun.proto = htons (ETH_P_IPV4); | ||
372 | else | ||
373 | tun.proto = htons (ETH_P_IPV6); | ||
374 | memcpy (&buf[off], &tun, sizeof (struct tun_header)); | ||
375 | off += sizeof (struct tun_header); | ||
376 | } | ||
377 | |||
378 | /* now IP header */ | ||
379 | udp_crc_sum = 0; | ||
380 | switch (rr->src_addr.ss_family) | ||
381 | { | ||
382 | case AF_INET: | ||
383 | { | ||
384 | struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr; | ||
385 | struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr; | ||
386 | struct ip4_header ip; | ||
387 | |||
388 | spt = dst->sin_port; | ||
389 | dpt = src->sin_port; | ||
390 | ip.header_length = sizeof (struct ip4_header) / 4; | ||
391 | ip.version = IPVERSION; /* aka 4 */ | ||
392 | ip.diff_serv = 0; | ||
393 | ip.total_length = htons ((uint16_t) reply_len - off); | ||
394 | ip.identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
395 | 65536); | ||
396 | ip.flags = 0; | ||
397 | ip.fragmentation_offset = 0; | ||
398 | ip.ttl = 255; /* or lower? */ | ||
399 | ip.protocol = IPPROTO_UDP; | ||
400 | ip.checksum = 0; /* checksum is optional */ | ||
401 | ip.source_address = dst->sin_addr; | ||
402 | ip.destination_address = src->sin_addr; | ||
403 | ip.checksum = GNUNET_CRYPTO_crc16_n (&ip, sizeof (ip)); | ||
404 | |||
405 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
406 | &ip.source_address, | ||
407 | sizeof (struct in_addr) * 2); | ||
408 | { | ||
409 | uint16_t tmp; | ||
410 | |||
411 | tmp = htons (IPPROTO_UDP); | ||
412 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
413 | &tmp, | ||
414 | sizeof (uint16_t)); | ||
415 | tmp = htons (rr->payload_length + sizeof (struct udp_packet)); | ||
416 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
417 | &tmp, | ||
418 | sizeof (uint16_t)); | ||
419 | } | ||
420 | memcpy (&buf[off], &ip, sizeof (ip)); | ||
421 | off += sizeof (ip); | ||
422 | } | ||
423 | break; | ||
424 | case AF_INET6: | ||
425 | { | ||
426 | struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr; | ||
427 | struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr; | ||
428 | struct ip6_header ip; | ||
429 | |||
430 | spt = dst->sin6_port; | ||
431 | dpt = src->sin6_port; | ||
432 | ip.traffic_class_h = 0; | ||
433 | ip.version = 6; /* is there a named constant? I couldn't find one */ | ||
434 | ip.traffic_class_l = 0; | ||
435 | ip.flow_label = 0; | ||
436 | ip.payload_length = htons ((uint16_t) reply_len); | ||
437 | ip.next_header = IPPROTO_UDP; | ||
438 | ip.hop_limit = 255; /* or lower? */ | ||
439 | ip.source_address = dst->sin6_addr; | ||
440 | ip.destination_address = src->sin6_addr; | ||
441 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
442 | &ip.source_address, | ||
443 | sizeof (struct in6_addr) * 2); | ||
444 | { | ||
445 | uint32_t tmp; | ||
446 | |||
447 | tmp = htons (rr->payload_length + sizeof (struct udp_packet)); | ||
448 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
449 | &tmp, | ||
450 | sizeof (uint32_t)); | ||
451 | tmp = htons (IPPROTO_UDP); | ||
452 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
453 | &tmp, | ||
454 | sizeof (uint32_t)); | ||
455 | } | ||
456 | memcpy (&buf[off], &ip, sizeof (ip)); | ||
457 | off += sizeof (ip); | ||
458 | } | ||
459 | break; | ||
460 | default: | ||
461 | GNUNET_assert (0); | ||
462 | } | ||
463 | |||
464 | /* now UDP header */ | ||
465 | { | ||
466 | struct udp_packet udp; | ||
467 | |||
468 | udp.spt = spt; | ||
469 | udp.dpt = dpt; | ||
470 | udp.len = htons (reply_len - off); | ||
471 | udp.crc = 0; | ||
472 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
473 | &udp, | ||
474 | sizeof (udp)); | ||
475 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
476 | rr->payload, | ||
477 | rr->payload_length); | ||
478 | udp.crc = GNUNET_CRYPTO_crc16_finish (udp_crc_sum); | ||
479 | memcpy (&buf[off], &udp, sizeof (udp)); | ||
480 | off += sizeof (udp); | ||
481 | } | ||
482 | /* now DNS payload */ | ||
483 | { | ||
484 | memcpy (&buf[off], rr->payload, rr->payload_length); | ||
485 | off += rr->payload_length; | ||
486 | } | ||
487 | /* final checks & sending */ | ||
488 | GNUNET_assert (off == reply_len); | ||
489 | GNUNET_HELPER_send (hijacker, | ||
490 | hdr, | ||
491 | GNUNET_YES, | ||
492 | NULL, NULL); | ||
493 | GNUNET_STATISTICS_update (stats, | ||
494 | gettext_noop ("# DNS requests answered via TUN interface"), | ||
495 | 1, GNUNET_NO); | ||
496 | } | ||
497 | /* clean up, we're done */ | ||
498 | cleanup_rr (rr); | ||
499 | } | ||
500 | |||
501 | |||
502 | /** | ||
503 | * Show the payload of the given request record to the client | ||
504 | * (and wait for a response). | ||
505 | * | ||
506 | * @param rr request to send to client | ||
507 | * @param client client to send the response to | ||
508 | */ | ||
509 | static void | ||
510 | send_request_to_client (struct RequestRecord *rr, | ||
511 | struct GNUNET_SERVER_Client *client) | ||
512 | { | ||
513 | char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length]; | ||
514 | struct GNUNET_DNS_Request *req; | ||
515 | |||
516 | if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
517 | { | ||
518 | GNUNET_break (0); | ||
519 | cleanup_rr (rr); | ||
520 | return; | ||
521 | } | ||
522 | req = (struct GNUNET_DNS_Request*) buf; | ||
523 | req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST); | ||
524 | req->header.size = htons (sizeof (buf)); | ||
525 | req->reserved = htonl (0); | ||
526 | req->request_id = rr->request_id; | ||
527 | memcpy (&req[1], rr->payload, rr->payload_length); | ||
528 | GNUNET_SERVER_notification_context_unicast (nc, | ||
529 | client, | ||
530 | &req->header, | ||
531 | GNUNET_NO); | ||
532 | } | ||
533 | |||
534 | |||
535 | /** | ||
536 | * A client has completed its processing for this | ||
537 | * request. Move on. | ||
538 | * | ||
539 | * @param rr request to process further | ||
540 | */ | ||
541 | static void | ||
542 | next_phase (struct RequestRecord *rr) | ||
543 | { | ||
544 | struct ClientRecord *cr; | ||
545 | int nz; | ||
546 | unsigned int j; | ||
547 | struct GNUNET_NETWORK_Handle *dnsout; | ||
548 | socklen_t salen; | ||
549 | |||
550 | if (rr->phase == RP_DROP) | ||
551 | { | ||
552 | cleanup_rr (rr); | ||
553 | return; | ||
554 | } | ||
555 | nz = -1; | ||
556 | for (j=0;j<rr->client_wait_list_length;j++) | ||
557 | { | ||
558 | if (NULL != rr->client_wait_list[j]) | ||
559 | { | ||
560 | nz = (int) j; | ||
561 | break; | ||
562 | } | ||
563 | } | ||
564 | if (-1 != nz) | ||
565 | { | ||
566 | send_request_to_client (rr, rr->client_wait_list[nz]->client); | ||
567 | return; | ||
568 | } | ||
569 | /* done with current phase, advance! */ | ||
570 | switch (rr->phase) | ||
571 | { | ||
572 | case RP_INIT: | ||
573 | rr->phase = RP_REQUEST_MONITOR; | ||
574 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
575 | { | ||
576 | if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR)) | ||
577 | GNUNET_array_append (rr->client_wait_list, | ||
578 | rr->client_wait_list_length, | ||
579 | cr); | ||
580 | } | ||
581 | next_phase (rr); | ||
582 | return; | ||
583 | case RP_REQUEST_MONITOR: | ||
584 | rr->phase = RP_QUERY; | ||
585 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
586 | { | ||
587 | if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION)) | ||
588 | GNUNET_array_append (rr->client_wait_list, | ||
589 | rr->client_wait_list_length, | ||
590 | cr); | ||
591 | } | ||
592 | next_phase (rr); | ||
593 | return; | ||
594 | case RP_QUERY: | ||
595 | rr->phase = RP_INTERNET_DNS; | ||
596 | switch (rr->dst_addr.ss_family) | ||
597 | { | ||
598 | case AF_INET: | ||
599 | dnsout = dnsout4; | ||
600 | salen = sizeof (struct ip4_header); | ||
601 | break; | ||
602 | case AF_INET6: | ||
603 | dnsout = dnsout6; | ||
604 | salen = sizeof (struct ip6_header); | ||
605 | break; | ||
606 | default: | ||
607 | GNUNET_break (0); | ||
608 | cleanup_rr (rr); | ||
609 | return; | ||
610 | } | ||
611 | if (NULL == dnsout) | ||
612 | { | ||
613 | GNUNET_STATISTICS_update (stats, | ||
614 | gettext_noop ("# DNS exit failed (address family not supported)"), | ||
615 | 1, GNUNET_NO); | ||
616 | cleanup_rr (rr); | ||
617 | return; | ||
618 | } | ||
619 | GNUNET_NETWORK_socket_sendto (dnsout, | ||
620 | rr->payload, | ||
621 | rr->payload_length, | ||
622 | (struct sockaddr*) &rr->dst_addr, | ||
623 | salen); | ||
624 | return; | ||
625 | case RP_INTERNET_DNS: | ||
626 | rr->phase = RP_MODIFY; | ||
627 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
628 | { | ||
629 | if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION)) | ||
630 | GNUNET_array_append (rr->client_wait_list, | ||
631 | rr->client_wait_list_length, | ||
632 | cr); | ||
633 | } | ||
634 | next_phase (rr); | ||
635 | return; | ||
636 | case RP_MODIFY: | ||
637 | rr->phase = RP_RESPONSE_MONITOR; | ||
638 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
639 | { | ||
640 | if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR)) | ||
641 | GNUNET_array_append (rr->client_wait_list, | ||
642 | rr->client_wait_list_length, | ||
643 | cr); | ||
644 | } | ||
645 | next_phase (rr); | ||
646 | return; | ||
647 | case RP_RESPONSE_MONITOR: | ||
648 | request_done (rr); | ||
649 | break; | ||
650 | case RP_DROP: | ||
651 | cleanup_rr (rr); | ||
652 | break; | ||
653 | default: | ||
654 | GNUNET_break (0); | ||
655 | cleanup_rr (rr); | ||
656 | break; | ||
657 | } | ||
658 | } | ||
659 | |||
660 | |||
661 | /** | ||
662 | * A client disconnected, clean up after it. | ||
663 | * | ||
664 | * @param cls unused | ||
665 | * @param client handle of client that disconnected | ||
666 | */ | ||
667 | static void | ||
668 | client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | ||
669 | { | ||
670 | struct ClientRecord *cr; | ||
671 | struct RequestRecord *rr; | ||
672 | unsigned int i; | ||
673 | unsigned int j; | ||
674 | |||
675 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
676 | { | ||
677 | if (cr->client == client) | ||
678 | { | ||
679 | GNUNET_SERVER_client_drop (client); | ||
680 | GNUNET_CONTAINER_DLL_remove (clients_head, | ||
681 | clients_tail, | ||
682 | cr); | ||
683 | for (i=0;i<UINT16_MAX;i++) | ||
684 | { | ||
685 | rr = &requests[i]; | ||
686 | if (0 == rr->client_wait_list_length) | ||
687 | continue; /* not in use */ | ||
688 | for (j=0;j<rr->client_wait_list_length;j++) | ||
689 | { | ||
690 | if (rr->client_wait_list[j] == cr) | ||
691 | { | ||
692 | rr->client_wait_list[j] = NULL; | ||
693 | next_phase (rr); | ||
694 | } | ||
695 | } | ||
696 | } | ||
697 | GNUNET_free (cr); | ||
698 | return; | ||
699 | } | ||
700 | } | ||
701 | } | ||
702 | |||
703 | |||
704 | /** | ||
705 | * Read a DNS response from the (unhindered) UDP-Socket | ||
706 | * | ||
707 | * @param cls socket to read from | ||
708 | * @param tc scheduler context (must be shutdown or read ready) | ||
709 | */ | ||
710 | static void | ||
711 | read_response (void *cls, | ||
712 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
713 | { | ||
714 | struct GNUNET_NETWORK_Handle *dnsout = cls; | ||
715 | struct sockaddr_in addr4; | ||
716 | struct sockaddr_in6 addr6; | ||
717 | struct sockaddr *addr; | ||
718 | struct dns_header *dns; | ||
719 | socklen_t addrlen; | ||
720 | struct RequestRecord *rr; | ||
721 | ssize_t r; | ||
722 | int len; | ||
723 | |||
724 | if (dnsout == dnsout4) | ||
725 | { | ||
726 | addrlen = sizeof (struct sockaddr_in); | ||
727 | addr = (struct sockaddr* ) &addr4; | ||
728 | read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
729 | dnsout, | ||
730 | &read_response, | ||
731 | dnsout); | ||
732 | } | ||
733 | else | ||
734 | { | ||
735 | addrlen = sizeof (struct sockaddr_in6); | ||
736 | addr = (struct sockaddr* ) &addr6; | ||
737 | read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
738 | dnsout, | ||
739 | &read_response, | ||
740 | dnsout); | ||
741 | } | ||
742 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
743 | return; | ||
744 | |||
745 | #ifndef MINGW | ||
746 | if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len)) | ||
747 | { | ||
748 | /* conservative choice: */ | ||
749 | len = 65536; | ||
750 | } | ||
751 | #else | ||
752 | /* port the code above? */ | ||
753 | len = 65536; | ||
754 | #endif | ||
755 | |||
756 | { | ||
757 | unsigned char buf[len]; | ||
758 | |||
759 | memset (addr, 0, addrlen); | ||
760 | r = GNUNET_NETWORK_socket_recvfrom (dnsout, | ||
761 | buf, sizeof (buf), | ||
762 | addr, &addrlen); | ||
763 | if (-1 == r) | ||
764 | { | ||
765 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom"); | ||
766 | return; | ||
767 | } | ||
768 | if (sizeof (struct dns_header) > r) | ||
769 | { | ||
770 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
771 | _("Received DNS response that is too small (%u bytes)"), | ||
772 | r); | ||
773 | return; | ||
774 | } | ||
775 | dns = (struct dns_header *) buf; | ||
776 | rr = &requests[dns->id]; | ||
777 | if (rr->phase != RP_INTERNET_DNS) | ||
778 | { | ||
779 | /* unexpected / bogus reply */ | ||
780 | GNUNET_STATISTICS_update (stats, | ||
781 | gettext_noop ("# External DNS response discarded (no matching request)"), | ||
782 | 1, GNUNET_NO); | ||
783 | return; | ||
784 | } | ||
785 | GNUNET_free_non_null (rr->payload); | ||
786 | rr->payload = GNUNET_malloc (len); | ||
787 | memcpy (rr->payload, buf, len); | ||
788 | rr->payload_length = len; | ||
789 | next_phase (rr); | ||
790 | } | ||
791 | } | ||
792 | |||
793 | |||
794 | /** | ||
795 | * Open source port for sending DNS request on IPv4. | ||
796 | * | ||
797 | * @return GNUNET_OK on success | ||
798 | */ | ||
799 | static int | ||
800 | open_port4 () | ||
801 | { | ||
802 | struct sockaddr_in addr; | ||
803 | socklen_t addrlen; | ||
804 | |||
805 | dnsout4 = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0); | ||
806 | if (dnsout4 == NULL) | ||
807 | return GNUNET_SYSERR; | ||
808 | |||
809 | memset (&addr, 0, sizeof (struct sockaddr_in)); | ||
810 | addr.sin_family = AF_INET; | ||
811 | int err = GNUNET_NETWORK_socket_bind (dnsout4, | ||
812 | (struct sockaddr *) &addr, | ||
813 | sizeof (struct sockaddr_in)); | ||
814 | |||
815 | if (err != GNUNET_OK) | ||
816 | { | ||
817 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
818 | _("Could not bind to any port: %s\n"), | ||
819 | STRERROR (errno)); | ||
820 | GNUNET_NETWORK_socket_close (dnsout4); | ||
821 | dnsout4 = NULL; | ||
822 | return GNUNET_SYSERR; | ||
823 | } | ||
824 | |||
825 | /* Read the port we bound to */ | ||
826 | addrlen = sizeof (struct sockaddr_in); | ||
827 | if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout4), | ||
828 | (struct sockaddr *) &addr, | ||
829 | &addrlen)) | ||
830 | { | ||
831 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
832 | _("Could not determine port I got: %s\n"), | ||
833 | STRERROR (errno)); | ||
834 | GNUNET_NETWORK_socket_close (dnsout4); | ||
835 | dnsout4 = NULL; | ||
836 | return GNUNET_SYSERR; | ||
837 | } | ||
838 | dnsoutport = htons (addr.sin_port); | ||
839 | |||
840 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
841 | _("GNUnet DNS will exit on source port %u\n"), | ||
842 | (unsigned int) dnsoutport); | ||
843 | read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
844 | dnsout4, | ||
845 | &read_response, dnsout4); | ||
846 | return GNUNET_OK; | ||
847 | } | ||
848 | |||
849 | |||
850 | /** | ||
851 | * Open source port for sending DNS request on IPv6. Should be | ||
852 | * called AFTER open_port4. | ||
853 | * | ||
854 | * @return GNUNET_OK on success | ||
855 | */ | ||
856 | static int | ||
857 | open_port6 () | ||
858 | { | ||
859 | struct sockaddr_in6 addr; | ||
860 | socklen_t addrlen; | ||
861 | |||
862 | dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0); | ||
863 | if (dnsout6 == NULL) | ||
864 | { | ||
865 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
866 | _("Could not create IPv6 socket: %s\n"), | ||
867 | STRERROR (errno)); | ||
868 | return GNUNET_SYSERR; | ||
869 | } | ||
870 | memset (&addr, 0, sizeof (struct sockaddr_in6)); | ||
871 | addr.sin6_family = AF_INET6; | ||
872 | addr.sin6_port = htons (dnsoutport); | ||
873 | int err = GNUNET_NETWORK_socket_bind (dnsout6, | ||
874 | (struct sockaddr *) &addr, | ||
875 | sizeof (struct sockaddr_in6)); | ||
876 | |||
877 | if (err != GNUNET_OK) | ||
878 | { | ||
879 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
880 | _("Could not bind to port %u: %s\n"), | ||
881 | (unsigned int) dnsoutport, | ||
882 | STRERROR (errno)); | ||
883 | GNUNET_NETWORK_socket_close (dnsout6); | ||
884 | dnsout6 = NULL; | ||
885 | return GNUNET_SYSERR; | ||
886 | } | ||
887 | if (0 == dnsoutport) | ||
888 | { | ||
889 | addrlen = sizeof (struct sockaddr_in6); | ||
890 | if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout6), | ||
891 | (struct sockaddr *) &addr, | ||
892 | &addrlen)) | ||
893 | { | ||
894 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
895 | _("Could not determine port I got: %s\n"), | ||
896 | STRERROR (errno)); | ||
897 | GNUNET_NETWORK_socket_close (dnsout6); | ||
898 | dnsout6 = NULL; | ||
899 | return GNUNET_SYSERR; | ||
900 | } | ||
901 | } | ||
902 | dnsoutport = htons (addr.sin6_port); | ||
903 | read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
904 | dnsout6, | ||
905 | &read_response, dnsout6); | ||
906 | return GNUNET_YES; | ||
907 | } | ||
908 | |||
909 | |||
910 | /** | ||
911 | * We got a new client. Make sure all new DNS requests pass by its desk. | ||
912 | * | ||
913 | * @param cls unused | ||
914 | * @param client the new client | ||
915 | * @param message the init message (unused) | ||
916 | */ | ||
917 | static void | ||
918 | handle_client_init (void *cls GNUNET_UNUSED, | ||
919 | struct GNUNET_SERVER_Client *client, | ||
920 | const struct GNUNET_MessageHeader *message) | ||
921 | { | ||
922 | struct ClientRecord *cr; | ||
923 | const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message; | ||
924 | |||
925 | cr = GNUNET_malloc (sizeof (struct ClientRecord)); | ||
926 | cr->client = client; | ||
927 | cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags); | ||
928 | GNUNET_SERVER_client_keep (client); | ||
929 | GNUNET_CONTAINER_DLL_insert (clients_head, | ||
930 | clients_tail, | ||
931 | cr); | ||
932 | GNUNET_SERVER_notification_context_add (nc, client); | ||
933 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
934 | } | ||
935 | |||
936 | |||
937 | /** | ||
938 | * We got a response from a client. | ||
939 | * | ||
940 | * @param cls unused | ||
941 | * @param client the client | ||
942 | * @param message the response | ||
943 | */ | ||
944 | static void | ||
945 | handle_client_response (void *cls GNUNET_UNUSED, | ||
946 | struct GNUNET_SERVER_Client *client, | ||
947 | const struct GNUNET_MessageHeader *message) | ||
948 | { | ||
949 | const struct GNUNET_DNS_Response *resp; | ||
950 | struct RequestRecord *rr; | ||
951 | unsigned int i; | ||
952 | uint16_t msize; | ||
953 | uint16_t off; | ||
954 | |||
955 | msize = ntohs (message->size); | ||
956 | if (msize < sizeof (struct GNUNET_DNS_Response)) | ||
957 | { | ||
958 | GNUNET_break (0); | ||
959 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
960 | return; | ||
961 | } | ||
962 | resp = (const struct GNUNET_DNS_Response*) message; | ||
963 | off = (uint16_t) resp->request_id; | ||
964 | rr = &requests[off]; | ||
965 | if (rr->request_id != resp->request_id) | ||
966 | { | ||
967 | GNUNET_STATISTICS_update (stats, | ||
968 | gettext_noop ("# Client response discarded (no matching request)"), | ||
969 | 1, GNUNET_NO); | ||
970 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
971 | return; | ||
972 | } | ||
973 | for (i=0;i<rr->client_wait_list_length;i++) | ||
974 | { | ||
975 | if (NULL == rr->client_wait_list[i]) | ||
976 | continue; | ||
977 | if (rr->client_wait_list[i]->client != client) | ||
978 | continue; | ||
979 | rr->client_wait_list[i] = NULL; | ||
980 | switch (ntohl (resp->drop_flag)) | ||
981 | { | ||
982 | case 0: /* drop */ | ||
983 | rr->phase = RP_DROP; | ||
984 | break; | ||
985 | case 1: /* no change */ | ||
986 | break; | ||
987 | case 2: /* update */ | ||
988 | msize -= sizeof (struct GNUNET_DNS_Response); | ||
989 | if ( (sizeof (struct dns_header) > msize) || | ||
990 | (RP_REQUEST_MONITOR == rr->phase) || | ||
991 | (RP_RESPONSE_MONITOR == rr->phase) ) | ||
992 | { | ||
993 | GNUNET_break (0); | ||
994 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
995 | next_phase (rr); | ||
996 | return; | ||
997 | } | ||
998 | GNUNET_free_non_null (rr->payload); | ||
999 | #if DEBUG_DNS | ||
1000 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1001 | _("Changing DNS reply according to client specifications\n")); | ||
1002 | #endif | ||
1003 | rr->payload = GNUNET_malloc (msize); | ||
1004 | rr->payload_length = msize; | ||
1005 | memcpy (rr->payload, &resp[1], msize); | ||
1006 | if (rr->phase == RP_QUERY) | ||
1007 | { | ||
1008 | /* clear wait list, we're moving to MODIFY phase next */ | ||
1009 | GNUNET_array_grow (rr->client_wait_list, | ||
1010 | rr->client_wait_list_length, | ||
1011 | 0); | ||
1012 | } | ||
1013 | break; | ||
1014 | } | ||
1015 | next_phase (rr); | ||
1016 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1017 | return; | ||
1018 | } | ||
1019 | /* odd, client was not on our list for the request, that ought | ||
1020 | to be an error */ | ||
1021 | GNUNET_break (0); | ||
1022 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1023 | } | ||
1024 | |||
1025 | |||
1026 | /** | ||
1027 | * Functions with this signature are called whenever a complete | ||
1028 | * message is received by the tokenizer from the DNS hijack process. | ||
1029 | * | ||
1030 | * @param cls closure | ||
1031 | * @param client identification of the client | ||
1032 | * @param message the actual message, a DNS request we should handle | ||
1033 | */ | ||
1034 | static void | ||
1035 | process_helper_messages (void *cls GNUNET_UNUSED, void *client, | ||
1036 | const struct GNUNET_MessageHeader *message) | ||
1037 | { | ||
1038 | uint16_t msize; | ||
1039 | const struct tun_header *tun; | ||
1040 | const struct ip4_header *ip4; | ||
1041 | const struct ip6_header *ip6; | ||
1042 | const struct udp_packet *udp; | ||
1043 | const struct dns_header *dns; | ||
1044 | struct RequestRecord *rr; | ||
1045 | struct sockaddr_in *srca4; | ||
1046 | struct sockaddr_in6 *srca6; | ||
1047 | struct sockaddr_in *dsta4; | ||
1048 | struct sockaddr_in6 *dsta6; | ||
1049 | |||
1050 | msize = ntohs (message->size); | ||
1051 | if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header) + sizeof (struct ip4_header)) | ||
1052 | { | ||
1053 | /* non-IP packet received on TUN!? */ | ||
1054 | GNUNET_break (0); | ||
1055 | return; | ||
1056 | } | ||
1057 | msize -= sizeof (struct GNUNET_MessageHeader); | ||
1058 | tun = (const struct tun_header *) &message[1]; | ||
1059 | msize -= sizeof (struct tun_header); | ||
1060 | switch (ntohs (tun->proto)) | ||
1061 | { | ||
1062 | case ETH_P_IPV4: | ||
1063 | ip4 = (const struct ip4_header *) &tun[1]; | ||
1064 | if ( (msize < sizeof (struct ip4_header)) || | ||
1065 | (ip4->version != IPVERSION) || | ||
1066 | (ip4->header_length != sizeof (struct ip4_header) / 4) || | ||
1067 | (ntohs(ip4->total_length) != msize) || | ||
1068 | (ip4->protocol != IPPROTO_UDP) ) | ||
1069 | { | ||
1070 | /* non-IP/UDP packet received on TUN (or with options) */ | ||
1071 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1072 | _("Received malformed IPv4-UDP packet on TUN interface.\n")); | ||
1073 | return; | ||
1074 | } | ||
1075 | udp = (const struct udp_packet*) &ip4[1]; | ||
1076 | msize -= sizeof (struct ip4_header); | ||
1077 | break; | ||
1078 | case ETH_P_IPV6: | ||
1079 | ip6 = (const struct ip6_header *) &tun[1]; | ||
1080 | if ( (msize < sizeof (struct ip6_header)) || | ||
1081 | (ip6->version != 6) || | ||
1082 | (ntohs (ip6->payload_length) != msize) || | ||
1083 | (ip6->next_header != IPPROTO_UDP) ) | ||
1084 | { | ||
1085 | /* non-IP/UDP packet received on TUN (or with extensions) */ | ||
1086 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1087 | _("Received malformed IPv6-UDP packet on TUN interface.\n")); | ||
1088 | return; | ||
1089 | } | ||
1090 | udp = (const struct udp_packet*) &ip6[1]; | ||
1091 | msize -= sizeof (struct ip6_header); | ||
1092 | break; | ||
1093 | default: | ||
1094 | /* non-IP packet received on TUN!? */ | ||
1095 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1096 | _("Got non-IP packet with %u bytes and protocol %u from TUN\n"), | ||
1097 | (unsigned int) msize, | ||
1098 | ntohs (tun->proto)); | ||
1099 | return; | ||
1100 | } | ||
1101 | if (msize <= sizeof (struct udp_packet) + sizeof (struct dns_header)) | ||
1102 | { | ||
1103 | /* non-DNS packet received on TUN, ignore */ | ||
1104 | GNUNET_STATISTICS_update (stats, | ||
1105 | gettext_noop ("# Non-DNS UDP packet received via TUN interface"), | ||
1106 | 1, GNUNET_NO); | ||
1107 | return; | ||
1108 | } | ||
1109 | msize -= sizeof (struct udp_packet); | ||
1110 | dns = (const struct dns_header*) &udp[1]; | ||
1111 | rr = &requests[dns->id]; | ||
1112 | |||
1113 | /* clean up from previous request */ | ||
1114 | GNUNET_free_non_null (rr->payload); | ||
1115 | rr->payload = NULL; | ||
1116 | GNUNET_array_grow (rr->client_wait_list, | ||
1117 | rr->client_wait_list_length, | ||
1118 | 0); | ||
1119 | |||
1120 | /* setup new request */ | ||
1121 | rr->phase = RP_INIT; | ||
1122 | if (ip4->version == IPVERSION) | ||
1123 | { | ||
1124 | srca4 = (struct sockaddr_in*) &rr->src_addr; | ||
1125 | dsta4 = (struct sockaddr_in*) &rr->dst_addr; | ||
1126 | memset (srca4, 0, sizeof (struct sockaddr_in)); | ||
1127 | memset (dsta4, 0, sizeof (struct sockaddr_in)); | ||
1128 | srca4->sin_family = AF_INET; | ||
1129 | dsta4->sin_family = AF_INET; | ||
1130 | srca4->sin_addr = ip4->source_address; | ||
1131 | dsta4->sin_addr = ip4->destination_address; | ||
1132 | srca4->sin_port = udp->spt; | ||
1133 | dsta4->sin_port = udp->dpt; | ||
1134 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1135 | srca4->sin_len = sizeof (sizeof (struct sockaddr_in)); | ||
1136 | dsta4->sin_len = sizeof (sizeof (struct sockaddr_in)); | ||
1137 | #endif | ||
1138 | } | ||
1139 | else /* ipv6 */ | ||
1140 | { | ||
1141 | srca6 = (struct sockaddr_in6*) &rr->src_addr; | ||
1142 | dsta6 = (struct sockaddr_in6*) &rr->dst_addr; | ||
1143 | memset (srca6, 0, sizeof (struct sockaddr_in6)); | ||
1144 | memset (dsta6, 0, sizeof (struct sockaddr_in6)); | ||
1145 | srca6->sin6_family = AF_INET6; | ||
1146 | dsta6->sin6_family = AF_INET6; | ||
1147 | srca6->sin6_addr = ip6->source_address; | ||
1148 | dsta6->sin6_addr = ip6->destination_address; | ||
1149 | srca6->sin6_port = udp->spt; | ||
1150 | dsta6->sin6_port = udp->dpt; | ||
1151 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1152 | srca6->sin6_len = sizeof (sizeof (struct sockaddr_in6)); | ||
1153 | dsta6->sin6_len = sizeof (sizeof (struct sockaddr_in6)); | ||
1154 | #endif | ||
1155 | } | ||
1156 | rr->payload = GNUNET_malloc (msize); | ||
1157 | rr->payload_length = msize; | ||
1158 | memcpy (rr->payload, dns, msize); | ||
1159 | rr->request_id = dns->id | (request_id_gen << 16); | ||
1160 | request_id_gen++; | ||
1161 | |||
1162 | GNUNET_STATISTICS_update (stats, | ||
1163 | gettext_noop ("# DNS requests received via TUN interface"), | ||
1164 | 1, GNUNET_NO); | ||
1165 | /* start request processing state machine */ | ||
1166 | next_phase (rr); | ||
1167 | } | ||
1168 | |||
1169 | |||
1170 | /** | ||
1171 | * @param cls closure | ||
1172 | * @param server the initialized server | ||
1173 | * @param cfg_ configuration to use | ||
1174 | */ | ||
1175 | static void | ||
1176 | run (void *cls, struct GNUNET_SERVER_Handle *server, | ||
1177 | const struct GNUNET_CONFIGURATION_Handle *cfg_) | ||
1178 | { | ||
1179 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
1180 | /* callback, cls, type, size */ | ||
1181 | {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, | ||
1182 | sizeof (struct GNUNET_DNS_Register)}, | ||
1183 | {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0}, | ||
1184 | {NULL, NULL, 0, 0} | ||
1185 | }; | ||
1186 | char port_s[6]; | ||
1187 | char *ifc_name; | ||
1188 | char *ipv4addr; | ||
1189 | char *ipv4mask; | ||
1190 | char *ipv6addr; | ||
1191 | char *ipv6prefix; | ||
1192 | |||
1193 | cfg = cfg_; | ||
1194 | stats = GNUNET_STATISTICS_create ("dns", cfg); | ||
1195 | nc = GNUNET_SERVER_notification_context_create (server, 1); | ||
1196 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, | ||
1197 | cls); | ||
1198 | if (GNUNET_YES == | ||
1199 | GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) | ||
1200 | { | ||
1201 | if ( (GNUNET_OK != open_port4 ()) && | ||
1202 | (GNUNET_OK != open_port6 ()) ) | ||
1203 | { | ||
1204 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1205 | _("Failed to open any port to provide DNS exit\n")); | ||
1206 | GNUNET_SCHEDULER_shutdown (); | ||
1207 | return; | ||
1208 | } | ||
1209 | } | ||
1210 | |||
1211 | helper_argv[0] = GNUNET_strdup ("gnunet-dns"); | ||
1212 | if (GNUNET_SYSERR == | ||
1213 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name)) | ||
1214 | { | ||
1215 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1216 | "No entry 'IFNAME' in configuration!\n"); | ||
1217 | GNUNET_SCHEDULER_shutdown (); | ||
1218 | return; | ||
1219 | } | ||
1220 | helper_argv[1] = ifc_name; | ||
1221 | if ( (GNUNET_SYSERR == | ||
1222 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR", | ||
1223 | &ipv6addr)) ) | ||
1224 | { | ||
1225 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1226 | "No entry 'IPV6ADDR' in configuration!\n"); | ||
1227 | GNUNET_SCHEDULER_shutdown (); | ||
1228 | return; | ||
1229 | } | ||
1230 | helper_argv[2] = ipv6addr; | ||
1231 | if (GNUNET_SYSERR == | ||
1232 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX", | ||
1233 | &ipv6prefix)) | ||
1234 | { | ||
1235 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1236 | "No entry 'IPV6PREFIX' in configuration!\n"); | ||
1237 | GNUNET_SCHEDULER_shutdown (); | ||
1238 | return; | ||
1239 | } | ||
1240 | helper_argv[3] = ipv6prefix; | ||
1241 | |||
1242 | if (GNUNET_SYSERR == | ||
1243 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR", | ||
1244 | &ipv4addr)) | ||
1245 | { | ||
1246 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1247 | "No entry 'IPV4ADDR' in configuration!\n"); | ||
1248 | GNUNET_SCHEDULER_shutdown (); | ||
1249 | return; | ||
1250 | } | ||
1251 | helper_argv[4] = ipv4addr; | ||
1252 | if (GNUNET_SYSERR == | ||
1253 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK", | ||
1254 | &ipv4mask)) | ||
1255 | { | ||
1256 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1257 | "No entry 'IPV4MASK' in configuration!\n"); | ||
1258 | GNUNET_SCHEDULER_shutdown (); | ||
1259 | return; | ||
1260 | } | ||
1261 | helper_argv[5] = ipv4mask; | ||
1262 | GNUNET_snprintf (port_s, | ||
1263 | sizeof (port_s), | ||
1264 | "%u", | ||
1265 | (unsigned int) dnsoutport); | ||
1266 | helper_argv[6] = GNUNET_strdup (port_s); | ||
1267 | helper_argv[7] = NULL; | ||
1268 | hijacker = GNUNET_HELPER_start ("gnunet-helper-dns", | ||
1269 | helper_argv, | ||
1270 | &process_helper_messages, | ||
1271 | NULL); | ||
1272 | GNUNET_SERVER_add_handlers (server, handlers); | ||
1273 | GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL); | ||
1274 | } | ||
1275 | |||
1276 | |||
1277 | /** | ||
1278 | * The main function for the dns service. | ||
1279 | * | ||
1280 | * @param argc number of arguments from the command line | ||
1281 | * @param argv command line arguments | ||
1282 | * @return 0 ok, 1 on error | ||
1283 | */ | ||
1284 | int | ||
1285 | main (int argc, char *const *argv) | ||
1286 | { | ||
1287 | return (GNUNET_OK == | ||
1288 | GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE, | ||
1289 | &run, NULL)) ? 0 : 1; | ||
1290 | } | ||
1291 | |||
1292 | |||
1293 | /* end of gnunet-service-dns_new.c */ | ||
diff --git a/src/include/Makefile.am b/src/include/Makefile.am index b066c7cdc..d0cd70d01 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am | |||
@@ -42,7 +42,6 @@ gnunetinclude_HEADERS = \ | |||
42 | gnunet_disk_lib.h \ | 42 | gnunet_disk_lib.h \ |
43 | gnunet_dnsparser_lib.h \ | 43 | gnunet_dnsparser_lib.h \ |
44 | gnunet_dns_service.h \ | 44 | gnunet_dns_service.h \ |
45 | gnunet_dns_service-new.h \ | ||
46 | gnunet_dv_service.h \ | 45 | gnunet_dv_service.h \ |
47 | gnunet_fragmentation_lib.h \ | 46 | gnunet_fragmentation_lib.h \ |
48 | gnunet_fs_service.h \ | 47 | gnunet_fs_service.h \ |
diff --git a/src/include/gnunet_dns_service-new.h b/src/include/gnunet_dns_service-new.h deleted file mode 100644 index 3517a4609..000000000 --- a/src/include/gnunet_dns_service-new.h +++ /dev/null | |||
@@ -1,186 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2012 Christian Grothoff (and other contributing authors) | ||
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 2, 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., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file include/gnunet_dns_service-new.h | ||
23 | * @brief API to access the DNS service. | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_DNS_SERVICE_NEW_H | ||
27 | #define GNUNET_DNS_SERVICE_NEW_H | ||
28 | |||
29 | #include "gnunet_common.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * Opaque DNS handle | ||
35 | */ | ||
36 | struct GNUNET_DNS_Handle; | ||
37 | |||
38 | /** | ||
39 | * Handle to identify an individual DNS request. | ||
40 | */ | ||
41 | struct GNUNET_DNS_RequestHandle; | ||
42 | |||
43 | /** | ||
44 | * Flags that specify when to call the client's handler. | ||
45 | */ | ||
46 | enum GNUNET_DNS_Flags | ||
47 | { | ||
48 | |||
49 | /** | ||
50 | * Useless option: never call the client. | ||
51 | */ | ||
52 | GNUNET_DNS_FLAG_NEVER = 0, | ||
53 | |||
54 | /** | ||
55 | * Set this flag to see all requests first prior to resolution | ||
56 | * (for monitoring). Clients that set this flag must then | ||
57 | * call "GNUNET_DNS_request_forward" when they process a request | ||
58 | * for the first time. Caling "GNUNET_DNS_request_answer" is | ||
59 | * not allowed for MONITOR peers. | ||
60 | */ | ||
61 | GNUNET_DNS_FLAG_REQUEST_MONITOR = 1, | ||
62 | |||
63 | /** | ||
64 | * This client should be called on requests that have not | ||
65 | * yet been resolved as this client provides a resolution | ||
66 | * service. Note that this does not guarantee that the | ||
67 | * client will see all requests as another client might be | ||
68 | * called first and that client might have already done the | ||
69 | * resolution, in which case other pre-resolution clients | ||
70 | * won't see the request anymore. | ||
71 | */ | ||
72 | GNUNET_DNS_FLAG_PRE_RESOLUTION = 2, | ||
73 | |||
74 | /** | ||
75 | * This client wants to be called on the results of a DNS resolution | ||
76 | * (either resolved by PRE-RESOLUTION clients or the global DNS). | ||
77 | * The client then has a chance to modify the answer (or cause it to | ||
78 | * be dropped). There is no guarantee that other POST-RESOLUTION | ||
79 | * client's won't modify (or drop) the answer afterwards. | ||
80 | */ | ||
81 | GNUNET_DNS_FLAG_POST_RESOLUTION = 4, | ||
82 | |||
83 | /** | ||
84 | * Set this flag to see all requests just before they are | ||
85 | * returned to the network. Clients that set this flag must then | ||
86 | * call "GNUNET_DNS_request_forward" when they process a request | ||
87 | * for the last time. Caling "GNUNET_DNS_request_answer" is | ||
88 | * not allowed for MONITOR peers. | ||
89 | */ | ||
90 | GNUNET_DNS_FLAG_RESPONSE_MONITOR = 8 | ||
91 | |||
92 | }; | ||
93 | |||
94 | |||
95 | |||
96 | /** | ||
97 | * Signature of a function that is called whenever the DNS service | ||
98 | * encounters a DNS request and needs to do something with it. The | ||
99 | * function has then the chance to generate or modify the response by | ||
100 | * calling one of the three "GNUNET_DNS_request_*" continuations. | ||
101 | * | ||
102 | * When a request is intercepted, this function is called first to | ||
103 | * give the client a chance to do the complete address resolution; | ||
104 | * "rdata" will be NULL for this first call for a DNS request, unless | ||
105 | * some other client has already filled in a response. | ||
106 | * | ||
107 | * If multiple clients exist, all of them are called before the global | ||
108 | * DNS. The global DNS is only called if all of the clients' | ||
109 | * functions call GNUNET_DNS_request_forward. Functions that call | ||
110 | * GNUNET_DNS_request_forward will be called again before a final | ||
111 | * response is returned to the application. If any of the clients' | ||
112 | * functions call GNUNET_DNS_request_drop, the response is dropped. | ||
113 | * | ||
114 | * @param cls closure | ||
115 | * @param rh request handle to user for reply | ||
116 | * @param request_length number of bytes in request | ||
117 | * @param request udp payload of the DNS request | ||
118 | */ | ||
119 | typedef void (*GNUNET_DNS_RequestHandler)(void *cls, | ||
120 | struct GNUNET_DNS_RequestHandle *rh, | ||
121 | size_t request_length, | ||
122 | const char *request); | ||
123 | |||
124 | |||
125 | /** | ||
126 | * If a GNUNET_DNS_RequestHandler calls this function, the client | ||
127 | * has no desire to interfer with the request and it should | ||
128 | * continue to be processed normally. | ||
129 | * | ||
130 | * @param rh request that should now be forwarded | ||
131 | */ | ||
132 | void | ||
133 | GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh); | ||
134 | |||
135 | |||
136 | /** | ||
137 | * If a GNUNET_DNS_RequestHandler calls this function, the request is | ||
138 | * to be dropped and no response should be generated. | ||
139 | * | ||
140 | * @param rh request that should now be dropped | ||
141 | */ | ||
142 | void | ||
143 | GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh); | ||
144 | |||
145 | |||
146 | /** | ||
147 | * If a GNUNET_DNS_RequestHandler calls this function, the request is | ||
148 | * supposed to be answered with the data provided to this call (with | ||
149 | * the modifications the function might have made). The reply given | ||
150 | * must always be a valid DNS reply and not a mutated DNS request. | ||
151 | * | ||
152 | * @param rh request that should now be answered | ||
153 | * @param reply_length size of reply (uint16_t to force sane size) | ||
154 | * @param reply reply data | ||
155 | */ | ||
156 | void | ||
157 | GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh, | ||
158 | uint16_t reply_length, | ||
159 | const char *reply); | ||
160 | |||
161 | |||
162 | /** | ||
163 | * Connect to the service-dns | ||
164 | * | ||
165 | * @param cfg configuration to use | ||
166 | * @param flags when to call rh | ||
167 | * @param rh function to call with DNS requests | ||
168 | * @param rh_cls closure to pass to rh | ||
169 | * @return DNS handle | ||
170 | */ | ||
171 | struct GNUNET_DNS_Handle * | ||
172 | GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
173 | enum GNUNET_DNS_Flags flags, | ||
174 | GNUNET_DNS_RequestHandler rh, | ||
175 | void *rh_cls); | ||
176 | |||
177 | |||
178 | /** | ||
179 | * Disconnect from the DNS service. | ||
180 | * | ||
181 | * @param dh DNS handle | ||
182 | */ | ||
183 | void | ||
184 | GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh); | ||
185 | |||
186 | #endif | ||
diff --git a/src/include/gnunet_dns_service.h b/src/include/gnunet_dns_service.h index 329a083ff..3517a4609 100644 --- a/src/include/gnunet_dns_service.h +++ b/src/include/gnunet_dns_service.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors) | 3 | (C) 2012 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -19,190 +19,168 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file include/gnunet_dns_service.h | 22 | * @file include/gnunet_dns_service-new.h |
23 | * @brief API to access the DNS service. Not finished at all, | 23 | * @brief API to access the DNS service. |
24 | * currently only contains the structs for the IPC, which | 24 | * @author Christian Grothoff |
25 | * don't even belong here (legacy code in transition) | ||
26 | * @author Philipp Toelke | ||
27 | * | ||
28 | * TODO: | ||
29 | * - replace (most?) structs with nice function (prototypes) that take | ||
30 | * the appropriate arguments to pass the data | ||
31 | * - clean up API implementation itself (nicer reconnect, etc.) | ||
32 | */ | 25 | */ |
33 | #ifndef GNUNET_DNS_SERVICE_H | 26 | #ifndef GNUNET_DNS_SERVICE_NEW_H |
34 | #define GNUNET_DNS_SERVICE_H | 27 | #define GNUNET_DNS_SERVICE_NEW_H |
35 | 28 | ||
36 | #include "gnunet_common.h" | 29 | #include "gnunet_common.h" |
37 | #include "gnunet_util_lib.h" | 30 | #include "gnunet_util_lib.h" |
38 | 31 | ||
39 | 32 | ||
40 | /** | 33 | /** |
41 | * Subtypes of DNS answers. | 34 | * Opaque DNS handle |
35 | */ | ||
36 | struct GNUNET_DNS_Handle; | ||
37 | |||
38 | /** | ||
39 | * Handle to identify an individual DNS request. | ||
42 | */ | 40 | */ |
43 | enum GNUNET_DNS_ANSWER_Subtype | 41 | struct GNUNET_DNS_RequestHandle; |
42 | |||
43 | /** | ||
44 | * Flags that specify when to call the client's handler. | ||
45 | */ | ||
46 | enum GNUNET_DNS_Flags | ||
44 | { | 47 | { |
48 | |||
45 | /** | 49 | /** |
46 | * Answers of this type contain a dns-packet that just has to be transmitted | 50 | * Useless option: never call the client. |
47 | */ | 51 | */ |
48 | GNUNET_DNS_ANSWER_TYPE_IP, | 52 | GNUNET_DNS_FLAG_NEVER = 0, |
49 | 53 | ||
50 | /** | 54 | /** |
51 | * Answers of this type contain an incomplete dns-packet. The IP-Address | 55 | * Set this flag to see all requests first prior to resolution |
52 | * is all 0s. The addroffset points to it. | 56 | * (for monitoring). Clients that set this flag must then |
57 | * call "GNUNET_DNS_request_forward" when they process a request | ||
58 | * for the first time. Caling "GNUNET_DNS_request_answer" is | ||
59 | * not allowed for MONITOR peers. | ||
53 | */ | 60 | */ |
54 | GNUNET_DNS_ANSWER_TYPE_SERVICE, | 61 | GNUNET_DNS_FLAG_REQUEST_MONITOR = 1, |
55 | 62 | ||
56 | /** | 63 | /** |
57 | * Answers of this type contain an incomplete dns-packet as answer to a | 64 | * This client should be called on requests that have not |
58 | * PTR-Query. The resolved name is not allocated. The addroffset points to it. | 65 | * yet been resolved as this client provides a resolution |
66 | * service. Note that this does not guarantee that the | ||
67 | * client will see all requests as another client might be | ||
68 | * called first and that client might have already done the | ||
69 | * resolution, in which case other pre-resolution clients | ||
70 | * won't see the request anymore. | ||
59 | */ | 71 | */ |
60 | GNUNET_DNS_ANSWER_TYPE_REV, | 72 | GNUNET_DNS_FLAG_PRE_RESOLUTION = 2, |
61 | 73 | ||
62 | /** | 74 | /** |
63 | * Answers of this type contains an IP6-Address but traffic to this IP should | 75 | * This client wants to be called on the results of a DNS resolution |
64 | * be routed through the GNUNet. | 76 | * (either resolved by PRE-RESOLUTION clients or the global DNS). |
77 | * The client then has a chance to modify the answer (or cause it to | ||
78 | * be dropped). There is no guarantee that other POST-RESOLUTION | ||
79 | * client's won't modify (or drop) the answer afterwards. | ||
65 | */ | 80 | */ |
66 | GNUNET_DNS_ANSWER_TYPE_REMOTE_AAAA, | 81 | GNUNET_DNS_FLAG_POST_RESOLUTION = 4, |
67 | 82 | ||
68 | /** | 83 | /** |
69 | * Answers of this type contains an IP4-Address but traffic to this IP should | 84 | * Set this flag to see all requests just before they are |
70 | * be routed through the GNUNet. | 85 | * returned to the network. Clients that set this flag must then |
86 | * call "GNUNET_DNS_request_forward" when they process a request | ||
87 | * for the last time. Caling "GNUNET_DNS_request_answer" is | ||
88 | * not allowed for MONITOR peers. | ||
71 | */ | 89 | */ |
72 | GNUNET_DNS_ANSWER_TYPE_REMOTE_A | 90 | GNUNET_DNS_FLAG_RESPONSE_MONITOR = 8 |
73 | 91 | ||
74 | }; | 92 | }; |
75 | 93 | ||
76 | 94 | ||
77 | GNUNET_NETWORK_STRUCT_BEGIN | ||
78 | struct GNUNET_vpn_service_descriptor | ||
79 | { | ||
80 | GNUNET_HashCode peer GNUNET_PACKED; | ||
81 | GNUNET_HashCode service_descriptor GNUNET_PACKED; | ||
82 | uint64_t ports GNUNET_PACKED; | ||
83 | uint32_t service_type GNUNET_PACKED; | ||
84 | }; | ||
85 | |||
86 | |||
87 | struct answer_packet | ||
88 | { | ||
89 | /* General data */ | ||
90 | struct GNUNET_MessageHeader hdr; | ||
91 | enum GNUNET_DNS_ANSWER_Subtype subtype GNUNET_PACKED; | ||
92 | |||
93 | char from[16]; | ||
94 | char to[16]; | ||
95 | char addrlen; | ||
96 | unsigned dst_port:16 GNUNET_PACKED; | ||
97 | /* -- */ | ||
98 | |||
99 | /* Data for GNUNET_DNS_ANSWER_TYPE_SERVICE */ | ||
100 | struct GNUNET_vpn_service_descriptor service_descr; | ||
101 | /* -- */ | ||
102 | |||
103 | /* Data for GNUNET_DNS_ANSWER_TYPE_REV */ | ||
104 | /* The offsett in octets from the beginning of the struct to the field | ||
105 | * in data where the IP-Address has to go. */ | ||
106 | uint16_t addroffset GNUNET_PACKED; | ||
107 | /* -- */ | ||
108 | |||
109 | /* Data for GNUNET_DNS_ANSWER_TYPE_REMOTE */ | ||
110 | /* either 4 or 16 */ | ||
111 | char addrsize; | ||
112 | unsigned char addr[16]; | ||
113 | /* -- */ | ||
114 | |||
115 | unsigned char data[1]; | ||
116 | }; | ||
117 | GNUNET_NETWORK_STRUCT_END | ||
118 | |||
119 | |||
120 | 95 | ||
121 | /** | 96 | /** |
122 | * Type of a function to be called by the DNS API whenever | 97 | * Signature of a function that is called whenever the DNS service |
123 | * a DNS reply is obtained. | 98 | * encounters a DNS request and needs to do something with it. The |
99 | * function has then the chance to generate or modify the response by | ||
100 | * calling one of the three "GNUNET_DNS_request_*" continuations. | ||
101 | * | ||
102 | * When a request is intercepted, this function is called first to | ||
103 | * give the client a chance to do the complete address resolution; | ||
104 | * "rdata" will be NULL for this first call for a DNS request, unless | ||
105 | * some other client has already filled in a response. | ||
106 | * | ||
107 | * If multiple clients exist, all of them are called before the global | ||
108 | * DNS. The global DNS is only called if all of the clients' | ||
109 | * functions call GNUNET_DNS_request_forward. Functions that call | ||
110 | * GNUNET_DNS_request_forward will be called again before a final | ||
111 | * response is returned to the application. If any of the clients' | ||
112 | * functions call GNUNET_DNS_request_drop, the response is dropped. | ||
124 | * | 113 | * |
125 | * @param cls closure | 114 | * @param cls closure |
126 | * @param pkt reply that we got | 115 | * @param rh request handle to user for reply |
116 | * @param request_length number of bytes in request | ||
117 | * @param request udp payload of the DNS request | ||
127 | */ | 118 | */ |
128 | typedef void (*GNUNET_DNS_ResponseCallback)(void *cls, | 119 | typedef void (*GNUNET_DNS_RequestHandler)(void *cls, |
129 | const struct answer_packet *pkt); | 120 | struct GNUNET_DNS_RequestHandle *rh, |
121 | size_t request_length, | ||
122 | const char *request); | ||
130 | 123 | ||
131 | 124 | ||
132 | /** | 125 | /** |
133 | * Opaque DNS handle | 126 | * If a GNUNET_DNS_RequestHandler calls this function, the client |
134 | */ | 127 | * has no desire to interfer with the request and it should |
135 | struct GNUNET_DNS_Handle; | 128 | * continue to be processed normally. |
136 | |||
137 | |||
138 | /** | ||
139 | * Connect to the service-dns | ||
140 | * | 129 | * |
141 | * @param cfg configuration to use | 130 | * @param rh request that should now be forwarded |
142 | * @param cb function to call with DNS replies | ||
143 | * @param cb_cls closure to pass to cb | ||
144 | * @return DNS handle | ||
145 | */ | 131 | */ |
146 | struct GNUNET_DNS_Handle * | 132 | void |
147 | GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | 133 | GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh); |
148 | GNUNET_DNS_ResponseCallback cb, | ||
149 | void *cb_cls); | ||
150 | 134 | ||
151 | 135 | ||
152 | /** | 136 | /** |
153 | * Signal the DNS service that it needs to re-initialize the DNS | 137 | * If a GNUNET_DNS_RequestHandler calls this function, the request is |
154 | * hijacking (the network setup has changed significantly). | 138 | * to be dropped and no response should be generated. |
155 | * | 139 | * |
156 | * @param h DNS handle | 140 | * @param rh request that should now be dropped |
157 | */ | 141 | */ |
158 | void | 142 | void |
159 | GNUNET_DNS_restart_hijack (struct GNUNET_DNS_Handle *h); | 143 | GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh); |
160 | 144 | ||
161 | 145 | ||
162 | /** | 146 | /** |
163 | * Process a DNS request sent to an IPv4 resolver. Pass it | 147 | * If a GNUNET_DNS_RequestHandler calls this function, the request is |
164 | * to the DNS service for resolution. | 148 | * supposed to be answered with the data provided to this call (with |
149 | * the modifications the function might have made). The reply given | ||
150 | * must always be a valid DNS reply and not a mutated DNS request. | ||
165 | * | 151 | * |
166 | * @param h DNS handle | 152 | * @param rh request that should now be answered |
167 | * @param dst_ip destination IPv4 address | 153 | * @param reply_length size of reply (uint16_t to force sane size) |
168 | * @param src_ip source IPv4 address (usually local machine) | 154 | * @param reply reply data |
169 | * @param src_port source port (to be used for reply) | ||
170 | * @param udp_packet_len length of the UDP payload in bytes | ||
171 | * @param udp_packet UDP payload | ||
172 | */ | 155 | */ |
173 | void | 156 | void |
174 | GNUNET_DNS_queue_request_v4 (struct GNUNET_DNS_Handle *h, | 157 | GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh, |
175 | const struct in_addr *dst_ip, | 158 | uint16_t reply_length, |
176 | const struct in_addr *src_ip, | 159 | const char *reply); |
177 | uint16_t src_port, | 160 | |
178 | size_t udp_packet_len, | ||
179 | const char *udp_packet); | ||
180 | 161 | ||
181 | /** | 162 | /** |
182 | * Process a DNS request sent to an IPv6 resolver. Pass it | 163 | * Connect to the service-dns |
183 | * to the DNS service for resolution. | ||
184 | * | 164 | * |
185 | * @param h DNS handle | 165 | * @param cfg configuration to use |
186 | * @param dst_ip destination IPv6 address | 166 | * @param flags when to call rh |
187 | * @param src_ip source IPv6 address (usually local machine) | 167 | * @param rh function to call with DNS requests |
188 | * @param src_port source port (to be used for reply) | 168 | * @param rh_cls closure to pass to rh |
189 | * @param udp_packet_len length of the UDP payload in bytes | 169 | * @return DNS handle |
190 | * @param udp_packet UDP payload | ||
191 | */ | 170 | */ |
192 | void | 171 | struct GNUNET_DNS_Handle * |
193 | GNUNET_DNS_queue_request_v6 (struct GNUNET_DNS_Handle *h, | 172 | GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, |
194 | const struct in6_addr *dst_ip, | 173 | enum GNUNET_DNS_Flags flags, |
195 | const struct in6_addr *src_ip, | 174 | GNUNET_DNS_RequestHandler rh, |
196 | uint16_t src_port, | 175 | void *rh_cls); |
197 | size_t udp_packet_len, | 176 | |
198 | const char *udp_packet); | ||
199 | 177 | ||
200 | /** | 178 | /** |
201 | * Disconnect from the DNS service. | 179 | * Disconnect from the DNS service. |
202 | * | 180 | * |
203 | * @param h DNS handle | 181 | * @param dh DNS handle |
204 | */ | 182 | */ |
205 | void | 183 | void |
206 | GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *h); | 184 | GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh); |
207 | 185 | ||
208 | #endif | 186 | #endif |
diff --git a/src/include/gnunet_dnsparser_lib.h b/src/include/gnunet_dnsparser_lib.h index 6654394be..a1fb920a7 100644 --- a/src/include/gnunet_dnsparser_lib.h +++ b/src/include/gnunet_dnsparser_lib.h | |||
@@ -394,97 +394,4 @@ GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p, | |||
394 | size_t *buf_length); | 394 | size_t *buf_length); |
395 | 395 | ||
396 | 396 | ||
397 | |||
398 | |||
399 | /* legacy API below */ | ||
400 | |||
401 | // DNS-Stuff | ||
402 | GNUNET_NETWORK_STRUCT_BEGIN | ||
403 | |||
404 | struct dns_static | ||
405 | { | ||
406 | uint16_t id GNUNET_PACKED; | ||
407 | |||
408 | unsigned rd:1 GNUNET_PACKED; // recursion desired (client -> server) | ||
409 | unsigned tc:1 GNUNET_PACKED; // message is truncated | ||
410 | unsigned aa:1 GNUNET_PACKED; // authoritative answer | ||
411 | unsigned op:4 GNUNET_PACKED; // query:0, inverse q.:1, status: 2 | ||
412 | unsigned qr:1 GNUNET_PACKED; // query:0, response:1 | ||
413 | |||
414 | unsigned rcode:4 GNUNET_PACKED; // 0 No error | ||
415 | // 1 Format error | ||
416 | // 2 Server failure | ||
417 | // 3 Name Error | ||
418 | // 4 Not Implemented | ||
419 | // 5 Refused | ||
420 | unsigned z:3 GNUNET_PACKED; // reserved | ||
421 | unsigned ra:1 GNUNET_PACKED; // recursion available (server -> client) | ||
422 | |||
423 | uint16_t qdcount GNUNET_PACKED; // number of questions | ||
424 | uint16_t ancount GNUNET_PACKED; // number of answers | ||
425 | uint16_t nscount GNUNET_PACKED; // number of authority-records | ||
426 | uint16_t arcount GNUNET_PACKED; // number of additional records | ||
427 | }; | ||
428 | GNUNET_NETWORK_STRUCT_END | ||
429 | |||
430 | |||
431 | struct dns_pkt | ||
432 | { | ||
433 | struct dns_static s; | ||
434 | unsigned char data[1]; | ||
435 | }; | ||
436 | |||
437 | struct dns_pkt_parsed | ||
438 | { | ||
439 | struct dns_static s; | ||
440 | struct dns_query **queries; | ||
441 | struct dns_record **answers; | ||
442 | struct dns_record **nameservers; | ||
443 | struct dns_record **additional; | ||
444 | }; | ||
445 | |||
446 | struct dns_query_line | ||
447 | { | ||
448 | uint16_t type; | ||
449 | uint16_t class; | ||
450 | }; | ||
451 | |||
452 | struct dns_query | ||
453 | { | ||
454 | char *name; | ||
455 | unsigned char namelen; | ||
456 | uint16_t qtype; | ||
457 | uint16_t qclass; | ||
458 | }; | ||
459 | |||
460 | struct dns_record_line | ||
461 | { | ||
462 | uint16_t type; | ||
463 | uint16_t class; | ||
464 | uint32_t ttl; | ||
465 | uint16_t data_len; | ||
466 | unsigned char data; | ||
467 | }; | ||
468 | |||
469 | struct dns_record | ||
470 | { | ||
471 | char *name; | ||
472 | unsigned char namelen; | ||
473 | uint16_t type; | ||
474 | uint16_t class; | ||
475 | uint32_t ttl; | ||
476 | uint16_t data_len; | ||
477 | unsigned char *data; | ||
478 | }; | ||
479 | |||
480 | |||
481 | struct dns_pkt_parsed * | ||
482 | parse_dns_packet (struct dns_pkt *pkt); | ||
483 | |||
484 | struct dns_pkt * | ||
485 | unparse_dns_packet (struct dns_pkt_parsed *pkt); | ||
486 | |||
487 | void | ||
488 | free_parsed_dns_packet (struct dns_pkt_parsed *ppkt); | ||
489 | |||
490 | #endif | 397 | #endif |
diff --git a/src/vpn/Makefile.am b/src/vpn/Makefile.am index be28949c5..bb0993c66 100644 --- a/src/vpn/Makefile.am +++ b/src/vpn/Makefile.am | |||
@@ -30,23 +30,12 @@ lib_LTLIBRARIES = \ | |||
30 | 30 | ||
31 | 31 | ||
32 | bin_PROGRAMS = \ | 32 | bin_PROGRAMS = \ |
33 | gnunet-daemon-exit gnunet-daemon-vpn $(VPNBIN) gnunet-service-vpn gnunet-vpn | 33 | $(VPNBIN) gnunet-service-vpn gnunet-vpn |
34 | 34 | ||
35 | 35 | ||
36 | gnunet_helper_vpn_SOURCES = \ | 36 | gnunet_helper_vpn_SOURCES = \ |
37 | gnunet-helper-vpn.c | 37 | gnunet-helper-vpn.c |
38 | 38 | ||
39 | gnunet_daemon_vpn_SOURCES = \ | ||
40 | gnunet-daemon-vpn.c | ||
41 | gnunet_daemon_vpn_LDADD = \ | ||
42 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
43 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
44 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
45 | $(top_builddir)/src/mesh/libgnunetmesh.la \ | ||
46 | $(top_builddir)/src/dns/libgnunetdnsparser.la \ | ||
47 | $(top_builddir)/src/dns/libgnunetdns.la \ | ||
48 | $(GN_LIBINTL) | ||
49 | |||
50 | gnunet_service_vpn_SOURCES = \ | 39 | gnunet_service_vpn_SOURCES = \ |
51 | gnunet-service-vpn.c | 40 | gnunet-service-vpn.c |
52 | gnunet_service_vpn_LDADD = \ | 41 | gnunet_service_vpn_LDADD = \ |
@@ -57,15 +46,6 @@ gnunet_service_vpn_LDADD = \ | |||
57 | gnunet_service_vpn_CFLAGS = \ | 46 | gnunet_service_vpn_CFLAGS = \ |
58 | -I$(top_srcdir)/src/exit $(CFLAGS) | 47 | -I$(top_srcdir)/src/exit $(CFLAGS) |
59 | 48 | ||
60 | gnunet_daemon_exit_SOURCES = \ | ||
61 | gnunet-daemon-exit.c | ||
62 | gnunet_daemon_exit_LDADD = \ | ||
63 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
64 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
65 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
66 | $(top_builddir)/src/mesh/libgnunetmesh.la \ | ||
67 | $(GN_LIBINTL) | ||
68 | |||
69 | gnunet_vpn_SOURCES = \ | 49 | gnunet_vpn_SOURCES = \ |
70 | gnunet-vpn.c | 50 | gnunet-vpn.c |
71 | gnunet_vpn_LDADD = \ | 51 | gnunet_vpn_LDADD = \ |
@@ -94,6 +74,3 @@ endif | |||
94 | # $(top_builddir)/src/transport/libgnunettransport.la \ | 74 | # $(top_builddir)/src/transport/libgnunettransport.la \ |
95 | # $(top_builddir)/src/util/libgnunetutil.la | 75 | # $(top_builddir)/src/util/libgnunetutil.la |
96 | 76 | ||
97 | EXTRA_DIST = \ | ||
98 | gnunet-vpn-packet.h \ | ||
99 | test-conf.conf | ||
diff --git a/src/vpn/gnunet-daemon-exit.c b/src/vpn/gnunet-daemon-exit.c deleted file mode 100644 index 6d5dc7797..000000000 --- a/src/vpn/gnunet-daemon-exit.c +++ /dev/null | |||
@@ -1,1501 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2010, 2012 Christian Grothoff | ||
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., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file vpn/gnunet-daemon-exit.c | ||
23 | * @brief | ||
24 | * @author Philipp Toelke | ||
25 | */ | ||
26 | #include <platform.h> | ||
27 | #include <gnunet_common.h> | ||
28 | #include <gnunet_program_lib.h> | ||
29 | #include <gnunet_protocols.h> | ||
30 | #include <gnunet_applications.h> | ||
31 | #include <gnunet_mesh_service.h> | ||
32 | #include <gnunet_constants.h> | ||
33 | #include <string.h> | ||
34 | |||
35 | #include "gnunet-vpn-packet.h" | ||
36 | |||
37 | |||
38 | struct remote_addr | ||
39 | { | ||
40 | char addrlen; | ||
41 | unsigned char addr[16]; | ||
42 | char proto; | ||
43 | }; | ||
44 | |||
45 | /** | ||
46 | * This struct is saved into the services-hashmap | ||
47 | */ | ||
48 | struct redirect_service | ||
49 | { | ||
50 | /** | ||
51 | * One of 4 or 6 | ||
52 | */ | ||
53 | unsigned int version; | ||
54 | uint16_t my_port; | ||
55 | uint16_t remote_port; | ||
56 | |||
57 | union | ||
58 | { | ||
59 | struct | ||
60 | { | ||
61 | char ip4address[4]; | ||
62 | } v4; | ||
63 | struct | ||
64 | { | ||
65 | char ip6address[16]; | ||
66 | } v6; | ||
67 | }; | ||
68 | }; | ||
69 | |||
70 | struct redirect_info | ||
71 | { | ||
72 | /** | ||
73 | * The source-address of this connection. When a packet to this address is | ||
74 | * received, this tunnel is used to forward it. ipv4-addresses will be put | ||
75 | * here left-aligned */ | ||
76 | char addr[16]; | ||
77 | /** | ||
78 | * The source-port of this connection | ||
79 | */ | ||
80 | uint16_t pt; | ||
81 | }; | ||
82 | |||
83 | /** | ||
84 | * This struct is saved into {tcp,udp}_connections; | ||
85 | */ | ||
86 | struct redirect_state | ||
87 | { | ||
88 | struct GNUNET_MESH_Tunnel *tunnel; | ||
89 | GNUNET_HashCode desc; | ||
90 | struct redirect_service *serv; | ||
91 | struct remote_addr remote; | ||
92 | |||
93 | struct GNUNET_CONTAINER_HeapNode *heap_node; | ||
94 | struct GNUNET_CONTAINER_MultiHashMap *hashmap; | ||
95 | GNUNET_HashCode hash; | ||
96 | |||
97 | enum { SERVICE, REMOTE } type; | ||
98 | |||
99 | /** | ||
100 | * The source-address and -port of this connection | ||
101 | */ | ||
102 | struct redirect_info redirect_info; | ||
103 | }; | ||
104 | |||
105 | struct tunnel_notify_queue | ||
106 | { | ||
107 | struct tunnel_notify_queue *next; | ||
108 | struct tunnel_notify_queue *prev; | ||
109 | void *cls; | ||
110 | size_t len; | ||
111 | }; | ||
112 | |||
113 | struct tunnel_state | ||
114 | { | ||
115 | struct tunnel_notify_queue *head; | ||
116 | struct tunnel_notify_queue *tail; | ||
117 | struct GNUNET_MESH_TransmitHandle *th; | ||
118 | }; | ||
119 | |||
120 | |||
121 | /** | ||
122 | * The handle to the configuration used throughout the process | ||
123 | */ | ||
124 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
125 | |||
126 | /** | ||
127 | * The handle to the helper | ||
128 | */ | ||
129 | static struct GNUNET_HELPER_Handle *helper_handle; | ||
130 | |||
131 | /** | ||
132 | * Arguments to the exit helper. | ||
133 | */ | ||
134 | static char *exit_argv[7]; | ||
135 | |||
136 | /** | ||
137 | * Final status code. | ||
138 | */ | ||
139 | static int ret; | ||
140 | |||
141 | /** | ||
142 | * The handle to mesh | ||
143 | */ | ||
144 | static struct GNUNET_MESH_Handle *mesh_handle; | ||
145 | |||
146 | /** | ||
147 | * This hashmaps contains the mapping from peer, service-descriptor, | ||
148 | * source-port and destination-port to a struct redirect_state | ||
149 | */ | ||
150 | static struct GNUNET_CONTAINER_MultiHashMap *udp_connections; | ||
151 | |||
152 | static struct GNUNET_CONTAINER_Heap *udp_connections_heap; | ||
153 | |||
154 | static struct GNUNET_CONTAINER_MultiHashMap *tcp_connections; | ||
155 | |||
156 | static struct GNUNET_CONTAINER_Heap *tcp_connections_heap; | ||
157 | |||
158 | /** | ||
159 | * If there are at least this many udp-Connections, old ones will be removed | ||
160 | */ | ||
161 | static long long unsigned int max_udp_connections = 200; | ||
162 | |||
163 | /** | ||
164 | * If there are at least this many tcp-Connections, old ones will be removed | ||
165 | */ | ||
166 | static long long unsigned int max_tcp_connections = 200; | ||
167 | |||
168 | /** | ||
169 | * This hashmaps saves interesting things about the configured UDP services | ||
170 | */ | ||
171 | static struct GNUNET_CONTAINER_MultiHashMap *udp_services; | ||
172 | |||
173 | /** | ||
174 | * This hashmaps saves interesting things about the configured TCP services | ||
175 | */ | ||
176 | |||
177 | static struct GNUNET_CONTAINER_MultiHashMap *tcp_services; | ||
178 | |||
179 | |||
180 | /** | ||
181 | * Function that frees everything from a hashmap | ||
182 | */ | ||
183 | static int | ||
184 | free_iterate (void *cls GNUNET_UNUSED, | ||
185 | const GNUNET_HashCode * hash GNUNET_UNUSED, void *value) | ||
186 | { | ||
187 | GNUNET_free (value); | ||
188 | return GNUNET_YES; | ||
189 | } | ||
190 | |||
191 | /** | ||
192 | * Function scheduled as very last function, cleans up after us | ||
193 | */ | ||
194 | static void | ||
195 | cleanup (void *cls GNUNET_UNUSED, | ||
196 | const struct GNUNET_SCHEDULER_TaskContext *tskctx) | ||
197 | { | ||
198 | unsigned int i; | ||
199 | |||
200 | GNUNET_assert (0 != (tskctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)); | ||
201 | if (mesh_handle != NULL) | ||
202 | { | ||
203 | GNUNET_MESH_disconnect (mesh_handle); | ||
204 | mesh_handle = NULL; | ||
205 | } | ||
206 | if (helper_handle != NULL) | ||
207 | { | ||
208 | GNUNET_HELPER_stop (helper_handle); | ||
209 | helper_handle = NULL; | ||
210 | } | ||
211 | GNUNET_CONTAINER_multihashmap_iterate (udp_connections, &free_iterate, NULL); | ||
212 | GNUNET_CONTAINER_multihashmap_iterate (tcp_connections, &free_iterate, NULL); | ||
213 | for (i=0;i<5;i++) | ||
214 | GNUNET_free_non_null (exit_argv[i]); | ||
215 | } | ||
216 | |||
217 | static void * | ||
218 | new_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
219 | const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED, | ||
220 | const struct GNUNET_ATS_Information *ats GNUNET_UNUSED) | ||
221 | { | ||
222 | struct tunnel_state *s = GNUNET_malloc (sizeof *s); | ||
223 | |||
224 | s->head = NULL; | ||
225 | s->tail = NULL; | ||
226 | s->th = NULL; | ||
227 | return s; | ||
228 | } | ||
229 | |||
230 | static void | ||
231 | clean_tunnel (void *cls GNUNET_UNUSED, const struct GNUNET_MESH_Tunnel *tunnel, | ||
232 | void *tunnel_ctx) | ||
233 | { | ||
234 | GNUNET_free (tunnel_ctx); | ||
235 | } | ||
236 | |||
237 | static void | ||
238 | collect_connections (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
239 | { | ||
240 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
241 | return; | ||
242 | |||
243 | |||
244 | struct GNUNET_CONTAINER_Heap *heap = cls; | ||
245 | |||
246 | struct redirect_state *state = GNUNET_CONTAINER_heap_remove_root (heap); | ||
247 | |||
248 | /* This is free()ed memory! */ | ||
249 | state->heap_node = NULL; | ||
250 | |||
251 | /* FIXME! GNUNET_MESH_close_tunnel(state->tunnel); */ | ||
252 | |||
253 | GNUNET_assert (GNUNET_OK == | ||
254 | GNUNET_CONTAINER_multihashmap_remove (state->hashmap, | ||
255 | &state->hash, state)); | ||
256 | |||
257 | GNUNET_free (state); | ||
258 | } | ||
259 | |||
260 | static void | ||
261 | hash_redirect_info (GNUNET_HashCode * hash, struct redirect_info *u_i, | ||
262 | size_t addrlen) | ||
263 | { | ||
264 | |||
265 | /* the gnunet hashmap only uses the first sizeof(unsigned int) of the hash | ||
266 | * | ||
267 | * build the hash out of the last bytes of the address and the 2 bytes of | ||
268 | * the port | ||
269 | */ | ||
270 | memcpy (hash, &u_i->pt, sizeof (u_i->pt)); | ||
271 | memcpy (((unsigned char *) hash) + 2, | ||
272 | u_i->addr + (addrlen - (sizeof (unsigned int) - 2)), | ||
273 | (sizeof (unsigned int) - 2)); | ||
274 | memset (((unsigned char *) hash) + sizeof (unsigned int), 0, | ||
275 | sizeof (GNUNET_HashCode) - sizeof (unsigned int)); | ||
276 | } | ||
277 | |||
278 | /** | ||
279 | * cls is the pointer to a GNUNET_MessageHeader that is | ||
280 | * followed by the service-descriptor and the udp-packet that should be sent; | ||
281 | */ | ||
282 | static size_t | ||
283 | send_udp_to_peer_notify_callback (void *cls, size_t size, void *buf) | ||
284 | { | ||
285 | struct GNUNET_MESH_Tunnel **tunnel = cls; | ||
286 | |||
287 | GNUNET_MESH_tunnel_set_data (*tunnel, NULL); | ||
288 | struct GNUNET_MessageHeader *hdr = | ||
289 | (struct GNUNET_MessageHeader *) (tunnel + 1); | ||
290 | GNUNET_assert (size >= ntohs (hdr->size)); | ||
291 | memcpy (buf, hdr, ntohs (hdr->size)); | ||
292 | size = ntohs (hdr->size); | ||
293 | |||
294 | struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (*tunnel); | ||
295 | |||
296 | if (NULL != s->head) | ||
297 | { | ||
298 | struct tunnel_notify_queue *element = s->head; | ||
299 | |||
300 | GNUNET_CONTAINER_DLL_remove (s->head, s->tail, element); | ||
301 | |||
302 | s->th = | ||
303 | GNUNET_MESH_notify_transmit_ready (*tunnel, GNUNET_NO, 42, | ||
304 | GNUNET_TIME_relative_divide | ||
305 | (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), | ||
306 | (const struct GNUNET_PeerIdentity *) | ||
307 | NULL, element->len, | ||
308 | send_udp_to_peer_notify_callback, | ||
309 | element->cls); | ||
310 | |||
311 | /* save the handle */ | ||
312 | GNUNET_free (element); | ||
313 | } | ||
314 | |||
315 | GNUNET_free (cls); | ||
316 | |||
317 | return size; | ||
318 | } | ||
319 | |||
320 | /** | ||
321 | * @brief Handles an UDP-Packet received from the helper. | ||
322 | * | ||
323 | * @param udp A pointer to the Packet | ||
324 | * @param dadr The IP-Destination-address | ||
325 | * @param addrlen The length of the address | ||
326 | */ | ||
327 | static void | ||
328 | udp_from_helper (struct udp_pkt *udp, unsigned char *dadr, size_t addrlen) | ||
329 | { | ||
330 | struct redirect_info u_i; | ||
331 | struct GNUNET_MESH_Tunnel *tunnel; | ||
332 | uint32_t len; | ||
333 | struct GNUNET_MessageHeader *msg; | ||
334 | |||
335 | memset (&u_i, 0, sizeof (struct redirect_info)); | ||
336 | |||
337 | memcpy (&u_i.addr, dadr, addrlen); | ||
338 | |||
339 | u_i.pt = udp->dpt; | ||
340 | |||
341 | /* get tunnel and service-descriptor from this */ | ||
342 | GNUNET_HashCode hash; | ||
343 | |||
344 | hash_redirect_info (&hash, &u_i, addrlen); | ||
345 | |||
346 | struct redirect_state *state = | ||
347 | GNUNET_CONTAINER_multihashmap_get (udp_connections, &hash); | ||
348 | |||
349 | /* Mark this connection as freshly used */ | ||
350 | GNUNET_CONTAINER_heap_update_cost (udp_connections_heap, state->heap_node, | ||
351 | GNUNET_TIME_absolute_get ().abs_value); | ||
352 | |||
353 | tunnel = state->tunnel; | ||
354 | |||
355 | if (state->type == SERVICE) | ||
356 | { | ||
357 | /* check if spt == serv.remote if yes: set spt = serv.myport ("nat") */ | ||
358 | if (ntohs (udp->spt) == state->serv->remote_port) | ||
359 | { | ||
360 | udp->spt = htons (state->serv->my_port); | ||
361 | } | ||
362 | else | ||
363 | { | ||
364 | /* otherwise the answer came from a different port (tftp does this) | ||
365 | * add this new port to the list of all services, so that the packets | ||
366 | * coming back from the client to this new port will be routed correctly | ||
367 | */ | ||
368 | struct redirect_service *serv = | ||
369 | GNUNET_malloc (sizeof (struct redirect_service)); | ||
370 | memcpy (serv, state->serv, sizeof (struct redirect_service)); | ||
371 | serv->my_port = ntohs (udp->spt); | ||
372 | serv->remote_port = ntohs (udp->spt); | ||
373 | uint16_t *desc = alloca (sizeof (GNUNET_HashCode) + 2); | ||
374 | |||
375 | memcpy ((GNUNET_HashCode *) (desc + 1), &state->desc, | ||
376 | sizeof (GNUNET_HashCode)); | ||
377 | *desc = ntohs (udp->spt); | ||
378 | GNUNET_assert (GNUNET_OK == | ||
379 | GNUNET_CONTAINER_multihashmap_put (udp_services, | ||
380 | (GNUNET_HashCode *) | ||
381 | desc, serv, | ||
382 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
383 | |||
384 | state->serv = serv; | ||
385 | } | ||
386 | } | ||
387 | |||
388 | /* send udp-packet back */ | ||
389 | len = | ||
390 | sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + | ||
391 | ntohs (udp->len); | ||
392 | struct GNUNET_MESH_Tunnel **ctunnel = | ||
393 | GNUNET_malloc (sizeof (struct GNUNET_MESH_TUNNEL *) + len); | ||
394 | *ctunnel = tunnel; | ||
395 | msg = (struct GNUNET_MessageHeader *) (ctunnel + 1); | ||
396 | msg->size = htons (len); | ||
397 | msg->type = | ||
398 | htons (state->type == | ||
399 | SERVICE ? GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK : | ||
400 | GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP_BACK); | ||
401 | GNUNET_HashCode *desc = (GNUNET_HashCode *) (msg + 1); | ||
402 | |||
403 | if (state->type == SERVICE) | ||
404 | memcpy (desc, &state->desc, sizeof (GNUNET_HashCode)); | ||
405 | else | ||
406 | memcpy (desc, &state->remote, sizeof (struct remote_addr)); | ||
407 | void *_udp = desc + 1; | ||
408 | |||
409 | memcpy (_udp, udp, ntohs (udp->len)); | ||
410 | |||
411 | struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (tunnel); | ||
412 | |||
413 | if (NULL == s->th) | ||
414 | { | ||
415 | /* No notify is pending */ | ||
416 | s->th = | ||
417 | GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO, 42, | ||
418 | GNUNET_TIME_relative_divide | ||
419 | (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), | ||
420 | (const struct GNUNET_PeerIdentity *) | ||
421 | NULL, len, | ||
422 | send_udp_to_peer_notify_callback, | ||
423 | ctunnel); | ||
424 | } | ||
425 | else | ||
426 | { | ||
427 | struct tunnel_notify_queue *element = | ||
428 | GNUNET_malloc (sizeof (struct tunnel_notify_queue)); | ||
429 | element->cls = ctunnel; | ||
430 | element->len = len; | ||
431 | |||
432 | GNUNET_CONTAINER_DLL_insert_tail (s->head, s->tail, element); | ||
433 | } | ||
434 | } | ||
435 | |||
436 | /** | ||
437 | * @brief Handles a TCP-Packet received from the helper. | ||
438 | * | ||
439 | * @param tcp A pointer to the Packet | ||
440 | * @param dadr The IP-Destination-address | ||
441 | * @param addrlen The length of the address | ||
442 | * @param pktlen the length of the packet, including its header | ||
443 | */ | ||
444 | static void | ||
445 | tcp_from_helper (struct tcp_pkt *tcp, unsigned char *dadr, size_t addrlen, | ||
446 | size_t pktlen) | ||
447 | { | ||
448 | struct redirect_info u_i; | ||
449 | struct GNUNET_MESH_Tunnel *tunnel; | ||
450 | uint32_t len; | ||
451 | struct GNUNET_MessageHeader *msg; | ||
452 | |||
453 | memset (&u_i, 0, sizeof (struct redirect_info)); | ||
454 | |||
455 | memcpy (&u_i.addr, dadr, addrlen); | ||
456 | u_i.pt = tcp->dpt; | ||
457 | |||
458 | /* get tunnel and service-descriptor from this */ | ||
459 | GNUNET_HashCode hash; | ||
460 | |||
461 | hash_redirect_info (&hash, &u_i, addrlen); | ||
462 | |||
463 | struct redirect_state *state = | ||
464 | GNUNET_CONTAINER_multihashmap_get (tcp_connections, &hash); | ||
465 | |||
466 | if (state == NULL) | ||
467 | { | ||
468 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
469 | "No mapping for this connection; hash is %x\n", | ||
470 | *((uint32_t *) & hash)); | ||
471 | return; | ||
472 | } | ||
473 | |||
474 | /* Mark this connection as freshly used */ | ||
475 | GNUNET_CONTAINER_heap_update_cost (tcp_connections_heap, state->heap_node, | ||
476 | GNUNET_TIME_absolute_get ().abs_value); | ||
477 | |||
478 | tunnel = state->tunnel; | ||
479 | |||
480 | if (state->type == SERVICE) | ||
481 | { | ||
482 | /* check if spt == serv.remote if yes: set spt = serv.myport ("nat") */ | ||
483 | if (ntohs (tcp->spt) == state->serv->remote_port) | ||
484 | { | ||
485 | tcp->spt = htons (state->serv->my_port); | ||
486 | } | ||
487 | else | ||
488 | { | ||
489 | // This is an illegal packet. | ||
490 | return; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | /* send tcp-packet back */ | ||
495 | len = | ||
496 | sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + pktlen; | ||
497 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "len: %d\n", pktlen); | ||
498 | struct GNUNET_MESH_Tunnel **ctunnel = | ||
499 | GNUNET_malloc (sizeof (struct GNUNET_MESH_TUNNEL *) + len); | ||
500 | *ctunnel = tunnel; | ||
501 | msg = (struct GNUNET_MessageHeader *) (ctunnel + 1); | ||
502 | msg->size = htons (len); | ||
503 | msg->type = | ||
504 | htons (state->type == | ||
505 | SERVICE ? GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK : | ||
506 | GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP_BACK); | ||
507 | GNUNET_HashCode *desc = (GNUNET_HashCode *) (msg + 1); | ||
508 | |||
509 | if (state->type == SERVICE) | ||
510 | memcpy (desc, &state->desc, sizeof (GNUNET_HashCode)); | ||
511 | else | ||
512 | memcpy (desc, &state->remote, sizeof (struct remote_addr)); | ||
513 | void *_tcp = desc + 1; | ||
514 | |||
515 | memcpy (_tcp, tcp, pktlen); | ||
516 | |||
517 | struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (tunnel); | ||
518 | |||
519 | if (NULL == s->th) | ||
520 | { | ||
521 | /* No notify is pending */ | ||
522 | s->th = | ||
523 | GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO, 42, | ||
524 | GNUNET_TIME_relative_divide | ||
525 | (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), | ||
526 | (const struct GNUNET_PeerIdentity *) | ||
527 | NULL, len, | ||
528 | send_udp_to_peer_notify_callback, | ||
529 | ctunnel); | ||
530 | } | ||
531 | else | ||
532 | { | ||
533 | struct tunnel_notify_queue *element = | ||
534 | GNUNET_malloc (sizeof (struct tunnel_notify_queue)); | ||
535 | element->cls = ctunnel; | ||
536 | element->len = len; | ||
537 | |||
538 | GNUNET_CONTAINER_DLL_insert_tail (s->head, s->tail, element); | ||
539 | } | ||
540 | } | ||
541 | |||
542 | |||
543 | /** | ||
544 | * Receive packets from the helper-process | ||
545 | */ | ||
546 | static void | ||
547 | message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED, | ||
548 | const struct GNUNET_MessageHeader *message) | ||
549 | { | ||
550 | GNUNET_assert (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
551 | |||
552 | struct tun_pkt *pkt_tun = (struct tun_pkt *) message; | ||
553 | |||
554 | /* ethertype is ipv6 */ | ||
555 | if (ntohs (pkt_tun->tun.type) == 0x86dd) | ||
556 | { | ||
557 | struct ip6_pkt *pkt6 = (struct ip6_pkt *) pkt_tun; | ||
558 | |||
559 | if (IPPROTO_UDP == pkt6->ip6_hdr.nxthdr) | ||
560 | udp_from_helper (&((struct ip6_udp *) pkt6)->udp_hdr, | ||
561 | (unsigned char *) &pkt6->ip6_hdr.dadr, 16); | ||
562 | else if (IPPROTO_TCP == pkt6->ip6_hdr.nxthdr) | ||
563 | tcp_from_helper (&((struct ip6_tcp *) pkt6)->tcp_hdr, | ||
564 | (unsigned char *) &pkt6->ip6_hdr.dadr, 16, | ||
565 | ntohs (pkt6->ip6_hdr.paylgth)); | ||
566 | } | ||
567 | else if (ntohs (pkt_tun->tun.type) == 0x0800) | ||
568 | { | ||
569 | struct ip_pkt *pkt4 = (struct ip_pkt *) pkt_tun; | ||
570 | |||
571 | if (IPPROTO_UDP == pkt4->ip_hdr.proto) | ||
572 | udp_from_helper (&((struct ip_udp *) pkt4)->udp_hdr, | ||
573 | (unsigned char *) &pkt4->ip_hdr.dadr, 4); | ||
574 | else if (IPPROTO_TCP == pkt4->ip_hdr.proto) | ||
575 | { | ||
576 | size_t pktlen = ntohs (pkt4->ip_hdr.tot_lngth); | ||
577 | |||
578 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tot: %d\n", pktlen); | ||
579 | pktlen -= 4 * pkt4->ip_hdr.hdr_lngth; | ||
580 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "-hdr: %d\n", pktlen); | ||
581 | tcp_from_helper (&((struct ip_tcp *) pkt4)->tcp_hdr, | ||
582 | (unsigned char *) &pkt4->ip_hdr.dadr, 4, pktlen); | ||
583 | } | ||
584 | } | ||
585 | else | ||
586 | { | ||
587 | return; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * Reads the configuration servicecfg and populates udp_services | ||
593 | * | ||
594 | * @param cls unused | ||
595 | * @param section name of section in config, equal to hostname | ||
596 | */ | ||
597 | static void | ||
598 | read_service_conf (void *cls GNUNET_UNUSED, const char *section) | ||
599 | { | ||
600 | if ((strlen (section) < 8) || | ||
601 | (0 != strcmp (".gnunet.", section + (strlen (section) - 8)))) | ||
602 | return; | ||
603 | |||
604 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing dns-name %d %s %s\n", | ||
605 | strlen (section), section, section + (strlen (section) - 8)); | ||
606 | |||
607 | char *cpy; | ||
608 | char *redirect; | ||
609 | char *hostname; | ||
610 | char *hostport; | ||
611 | uint16_t *desc = alloca (sizeof (GNUNET_HashCode) + 2); | ||
612 | |||
613 | GNUNET_CRYPTO_hash (section, strlen (section) + 1, | ||
614 | (GNUNET_HashCode *) (desc + 1)); | ||
615 | |||
616 | #define TCP 2 | ||
617 | #define UDP 1 | ||
618 | |||
619 | int proto = UDP; | ||
620 | |||
621 | do | ||
622 | { | ||
623 | if (proto == UDP && | ||
624 | (GNUNET_OK != | ||
625 | GNUNET_CONFIGURATION_get_value_string (cfg, section, "UDP_REDIRECTS", | ||
626 | &cpy))) | ||
627 | goto next; | ||
628 | else if (proto == TCP && | ||
629 | (GNUNET_OK != | ||
630 | GNUNET_CONFIGURATION_get_value_string (cfg, section, | ||
631 | "TCP_REDIRECTS", &cpy))) | ||
632 | goto next; | ||
633 | |||
634 | for (redirect = strtok (cpy, " "); redirect != NULL; | ||
635 | redirect = strtok (NULL, " ")) | ||
636 | { | ||
637 | if (NULL == (hostname = strstr (redirect, ":"))) | ||
638 | { | ||
639 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
640 | "Warning: option %s is not formatted correctly!\n", | ||
641 | redirect); | ||
642 | continue; | ||
643 | } | ||
644 | hostname[0] = '\0'; | ||
645 | hostname++; | ||
646 | if (NULL == (hostport = strstr (hostname, ":"))) | ||
647 | { | ||
648 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
649 | "Warning: option %s is not formatted correctly!\n", | ||
650 | redirect); | ||
651 | continue; | ||
652 | } | ||
653 | hostport[0] = '\0'; | ||
654 | hostport++; | ||
655 | |||
656 | int local_port = atoi (redirect); | ||
657 | |||
658 | if (!((local_port > 0) && (local_port < 65536))) | ||
659 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
660 | "Warning: %s is not a correct port.", redirect); | ||
661 | |||
662 | *desc = local_port; | ||
663 | |||
664 | struct redirect_service *serv = | ||
665 | GNUNET_malloc (sizeof (struct redirect_service)); | ||
666 | serv->my_port = local_port; | ||
667 | |||
668 | if (0 == strcmp ("localhost4", hostname)) | ||
669 | { | ||
670 | serv->version = 4; | ||
671 | |||
672 | char *ip4addr; | ||
673 | |||
674 | GNUNET_assert (GNUNET_OK == | ||
675 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", | ||
676 | "IPV4ADDR", | ||
677 | &ip4addr)); | ||
678 | GNUNET_assert (1 == inet_pton (AF_INET, ip4addr, serv->v4.ip4address)); | ||
679 | GNUNET_free (ip4addr); | ||
680 | } | ||
681 | else if (0 == strcmp ("localhost6", hostname)) | ||
682 | { | ||
683 | serv->version = 6; | ||
684 | |||
685 | char *ip6addr; | ||
686 | |||
687 | GNUNET_assert (GNUNET_OK == | ||
688 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", | ||
689 | "IPV6ADDR", | ||
690 | &ip6addr)); | ||
691 | GNUNET_assert (1 == inet_pton (AF_INET6, ip6addr, serv->v6.ip6address)); | ||
692 | GNUNET_free (ip6addr); | ||
693 | } | ||
694 | else | ||
695 | { | ||
696 | struct addrinfo *res; | ||
697 | |||
698 | int ret = getaddrinfo (hostname, NULL, NULL, &res); | ||
699 | |||
700 | if (ret != 0) | ||
701 | { | ||
702 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No addresses found for %s!\n", | ||
703 | hostname); | ||
704 | GNUNET_free (serv); | ||
705 | continue; | ||
706 | } | ||
707 | else | ||
708 | { | ||
709 | char buf[256]; | ||
710 | struct addrinfo *c = res; | ||
711 | |||
712 | if (c) | ||
713 | { | ||
714 | if (c->ai_family == AF_INET) | ||
715 | { | ||
716 | serv->version = 4; | ||
717 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
718 | "Found %s as address for %s\n", | ||
719 | inet_ntop (c->ai_family, | ||
720 | &((struct sockaddr_in *) (c-> | ||
721 | ai_addr))->sin_addr, | ||
722 | (char *) &buf, 256), hostname); | ||
723 | memcpy (serv->v4.ip4address, | ||
724 | &((struct sockaddr_in *) (c->ai_addr))->sin_addr, 4); | ||
725 | } | ||
726 | else if (c->ai_family == AF_INET6) | ||
727 | { | ||
728 | serv->version = 6; | ||
729 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
730 | "Found %s as address for %s\n", | ||
731 | inet_ntop (c->ai_family, | ||
732 | &((struct sockaddr_in6 *) (c-> | ||
733 | ai_addr))->sin6_addr, | ||
734 | (char *) &buf, 256), hostname); | ||
735 | memcpy (serv->v6.ip6address, | ||
736 | &((struct sockaddr_in6 *) (c->ai_addr))->sin6_addr, 16); | ||
737 | } | ||
738 | } | ||
739 | else | ||
740 | { | ||
741 | freeaddrinfo (res); | ||
742 | GNUNET_free (serv); | ||
743 | continue; | ||
744 | } | ||
745 | freeaddrinfo (res); | ||
746 | } | ||
747 | } | ||
748 | serv->remote_port = atoi (hostport); | ||
749 | if (UDP == proto) | ||
750 | GNUNET_assert (GNUNET_OK == | ||
751 | GNUNET_CONTAINER_multihashmap_put (udp_services, | ||
752 | (GNUNET_HashCode *) | ||
753 | desc, serv, | ||
754 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
755 | else | ||
756 | GNUNET_assert (GNUNET_OK == | ||
757 | GNUNET_CONTAINER_multihashmap_put (tcp_services, | ||
758 | (GNUNET_HashCode *) | ||
759 | desc, serv, | ||
760 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
761 | |||
762 | } | ||
763 | GNUNET_free (cpy); | ||
764 | next: | ||
765 | proto = (proto == UDP) ? TCP : UDP; | ||
766 | } | ||
767 | while (proto != UDP); | ||
768 | } | ||
769 | |||
770 | |||
771 | |||
772 | static void | ||
773 | prepare_ipv4_packet (size_t len, uint16_t pktlen, void *payload, | ||
774 | uint16_t protocol, void *ipaddress, void *tunnel, | ||
775 | struct redirect_state *state, struct ip_pkt *pkt4) | ||
776 | { | ||
777 | uint32_t tmp, tmp2; | ||
778 | |||
779 | pkt4->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
780 | pkt4->shdr.size = htons (len); | ||
781 | pkt4->tun.flags = 0; | ||
782 | pkt4->tun.type = htons (0x0800); | ||
783 | |||
784 | memcpy (&pkt4->data, payload, pktlen); | ||
785 | |||
786 | pkt4->ip_hdr.version = 4; | ||
787 | pkt4->ip_hdr.hdr_lngth = 5; | ||
788 | pkt4->ip_hdr.diff_serv = 0; | ||
789 | pkt4->ip_hdr.tot_lngth = htons (20 + pktlen); | ||
790 | pkt4->ip_hdr.ident = 0; | ||
791 | pkt4->ip_hdr.flags = 0; | ||
792 | pkt4->ip_hdr.frag_off = 0; | ||
793 | pkt4->ip_hdr.ttl = 255; | ||
794 | pkt4->ip_hdr.proto = protocol; | ||
795 | pkt4->ip_hdr.chks = 0; /* Will be calculated later */ | ||
796 | |||
797 | memcpy (&pkt4->ip_hdr.dadr, ipaddress, sizeof (struct in_addr)); | ||
798 | |||
799 | /* Generate a new src-address */ | ||
800 | char *ipv4addr; | ||
801 | char *ipv4mask; | ||
802 | |||
803 | GNUNET_assert (GNUNET_OK == | ||
804 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4ADDR", | ||
805 | &ipv4addr)); | ||
806 | GNUNET_assert (GNUNET_OK == | ||
807 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4MASK", | ||
808 | &ipv4mask)); | ||
809 | inet_pton (AF_INET, ipv4addr, &tmp); | ||
810 | inet_pton (AF_INET, ipv4mask, &tmp2); | ||
811 | GNUNET_free (ipv4addr); | ||
812 | GNUNET_free (ipv4mask); | ||
813 | |||
814 | /* This should be a noop */ | ||
815 | tmp = tmp & tmp2; | ||
816 | |||
817 | tmp |= ntohl (*((uint32_t *) tunnel)) & (~tmp2); | ||
818 | |||
819 | pkt4->ip_hdr.sadr.s_addr = tmp; | ||
820 | |||
821 | memcpy (&state->redirect_info.addr, &tmp, 4); | ||
822 | if (IPPROTO_UDP == protocol) | ||
823 | { | ||
824 | struct ip_udp *pkt4_udp = (struct ip_udp *) pkt4; | ||
825 | |||
826 | state->redirect_info.pt = pkt4_udp->udp_hdr.spt; | ||
827 | |||
828 | pkt4_udp->udp_hdr.crc = 0; /* Optional for IPv4 */ | ||
829 | } | ||
830 | else if (IPPROTO_TCP == protocol) | ||
831 | { | ||
832 | struct ip_tcp *pkt4_tcp = (struct ip_tcp *) pkt4; | ||
833 | |||
834 | state->redirect_info.pt = pkt4_tcp->tcp_hdr.spt; | ||
835 | |||
836 | pkt4_tcp->tcp_hdr.crc = 0; | ||
837 | uint32_t sum = 0; | ||
838 | |||
839 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) &pkt4->ip_hdr.sadr, sizeof (struct in_addr)); | ||
840 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) &pkt4->ip_hdr.dadr, sizeof (struct in_addr)); | ||
841 | |||
842 | tmp = (protocol << 16) | (0xffff & pktlen); | ||
843 | |||
844 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "line: %08x, %x \n", tmp, | ||
845 | (0xffff & pktlen)); | ||
846 | |||
847 | tmp = htonl (tmp); | ||
848 | |||
849 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
850 | |||
851 | sum = | ||
852 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt4_tcp->tcp_hdr, | ||
853 | pktlen); | ||
854 | pkt4_tcp->tcp_hdr.crc = GNUNET_CRYPTO_crc16_finish (sum); | ||
855 | } | ||
856 | |||
857 | pkt4->ip_hdr.chks = | ||
858 | GNUNET_CRYPTO_crc16_n ((uint16_t *) & pkt4->ip_hdr, 5 * 4); | ||
859 | } | ||
860 | |||
861 | static void | ||
862 | prepare_ipv6_packet (size_t len, uint16_t pktlen, void *payload, | ||
863 | uint16_t protocol, void *ipaddress, void *tunnel, | ||
864 | struct redirect_state *state, struct ip6_pkt *pkt6) | ||
865 | { | ||
866 | uint32_t tmp; | ||
867 | |||
868 | pkt6->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
869 | pkt6->shdr.size = htons (len); | ||
870 | pkt6->tun.flags = 0; | ||
871 | |||
872 | pkt6->tun.type = htons (0x86dd); | ||
873 | |||
874 | memcpy (&pkt6->data, payload, pktlen); | ||
875 | |||
876 | pkt6->ip6_hdr.version = 6; | ||
877 | pkt6->ip6_hdr.nxthdr = protocol; | ||
878 | pkt6->ip6_hdr.paylgth = htons (pktlen); | ||
879 | pkt6->ip6_hdr.hoplmt = 64; | ||
880 | |||
881 | memcpy (&pkt6->ip6_hdr.dadr, ipaddress, sizeof (struct in6_addr)); | ||
882 | |||
883 | /* Generate a new src-address | ||
884 | * This takes as much from the address of the tunnel as fits into | ||
885 | * the host-mask*/ | ||
886 | char *ipv6addr; | ||
887 | unsigned long long ipv6prefix; | ||
888 | |||
889 | GNUNET_assert (GNUNET_OK == | ||
890 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6ADDR", | ||
891 | &ipv6addr)); | ||
892 | GNUNET_assert (GNUNET_OK == | ||
893 | GNUNET_CONFIGURATION_get_value_number (cfg, "exit", | ||
894 | "IPV6PREFIX", | ||
895 | &ipv6prefix)); | ||
896 | GNUNET_assert (ipv6prefix < 127); | ||
897 | ipv6prefix = (ipv6prefix + 7) / 8; | ||
898 | |||
899 | inet_pton (AF_INET6, ipv6addr, &pkt6->ip6_hdr.sadr); | ||
900 | GNUNET_free (ipv6addr); | ||
901 | |||
902 | if (ipv6prefix < (16 - sizeof (void *))) | ||
903 | ipv6prefix = 16 - sizeof (void *); | ||
904 | |||
905 | unsigned int offset = ipv6prefix - (16 - sizeof (void *)); | ||
906 | |||
907 | memcpy ((((char *) &pkt6->ip6_hdr.sadr)) + ipv6prefix, | ||
908 | ((char *) &tunnel) + offset, 16 - ipv6prefix); | ||
909 | |||
910 | /* copy the needed information into the state */ | ||
911 | memcpy (&state->redirect_info.addr, &pkt6->ip6_hdr.sadr, 16); | ||
912 | |||
913 | if (IPPROTO_UDP == protocol) | ||
914 | { | ||
915 | struct ip6_udp *pkt6_udp = (struct ip6_udp *) pkt6; | ||
916 | |||
917 | state->redirect_info.pt = pkt6_udp->udp_hdr.spt; | ||
918 | |||
919 | pkt6_udp->udp_hdr.crc = 0; | ||
920 | uint32_t sum = 0; | ||
921 | |||
922 | sum = | ||
923 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6_udp->ip6_hdr.sadr, | ||
924 | 16); | ||
925 | sum = | ||
926 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6_udp->ip6_hdr.dadr, | ||
927 | 16); | ||
928 | tmp = (htons (pktlen) & 0xffff); | ||
929 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
930 | tmp = htons (((pkt6_udp->ip6_hdr.nxthdr & 0x00ff))); | ||
931 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
932 | |||
933 | sum = | ||
934 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6_udp->udp_hdr, | ||
935 | ntohs (pkt6_udp->udp_hdr.len)); | ||
936 | pkt6_udp->udp_hdr.crc = GNUNET_CRYPTO_crc16_finish (sum); | ||
937 | } | ||
938 | else if (IPPROTO_TCP == protocol) | ||
939 | { | ||
940 | struct ip6_tcp *pkt6_tcp = (struct ip6_tcp *) pkt6; | ||
941 | |||
942 | state->redirect_info.pt = pkt6_tcp->tcp_hdr.spt; | ||
943 | |||
944 | pkt6_tcp->tcp_hdr.crc = 0; | ||
945 | uint32_t sum = 0; | ||
946 | |||
947 | sum = | ||
948 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->ip6_hdr.sadr, 16); | ||
949 | sum = | ||
950 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->ip6_hdr.dadr, 16); | ||
951 | tmp = htonl (pktlen); | ||
952 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
953 | tmp = htonl (((pkt6->ip6_hdr.nxthdr & 0x000000ff))); | ||
954 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
955 | |||
956 | sum = | ||
957 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6_tcp->tcp_hdr, | ||
958 | ntohs (pkt6->ip6_hdr.paylgth)); | ||
959 | pkt6_tcp->tcp_hdr.crc = GNUNET_CRYPTO_crc16_finish (sum); | ||
960 | } | ||
961 | } | ||
962 | |||
963 | /** | ||
964 | * The messages are one GNUNET_HashCode for the service followed by a struct tcp_pkt | ||
965 | */ | ||
966 | static int | ||
967 | receive_tcp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
968 | void **tunnel_ctx GNUNET_UNUSED, | ||
969 | const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, | ||
970 | const struct GNUNET_MessageHeader *message, | ||
971 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
972 | { | ||
973 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received TCP-Packet\n"); | ||
974 | GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); | ||
975 | struct tcp_pkt *pkt = (struct tcp_pkt *) (desc + 1); | ||
976 | uint16_t pkt_len = | ||
977 | ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - | ||
978 | sizeof (GNUNET_HashCode); | ||
979 | |||
980 | /** Get the configuration from the services-hashmap. | ||
981 | * | ||
982 | * Which service is needed only depends on the service-descriptor and the | ||
983 | * destination-port | ||
984 | */ | ||
985 | uint16_t *tcp_desc = alloca (sizeof (GNUNET_HashCode) + 2); | ||
986 | |||
987 | memcpy (tcp_desc + 1, desc, sizeof (GNUNET_HashCode)); | ||
988 | *tcp_desc = ntohs (pkt->dpt); | ||
989 | struct redirect_service *serv = | ||
990 | GNUNET_CONTAINER_multihashmap_get (tcp_services, | ||
991 | (GNUNET_HashCode *) tcp_desc); | ||
992 | |||
993 | if (NULL == serv) | ||
994 | { | ||
995 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "No service found for TCP dpt %d!\n", | ||
996 | *tcp_desc); | ||
997 | return GNUNET_YES; | ||
998 | } | ||
999 | |||
1000 | pkt->dpt = htons (serv->remote_port); | ||
1001 | |||
1002 | /* | ||
1003 | * At this point it would be possible to check against some kind of ACL. | ||
1004 | */ | ||
1005 | |||
1006 | size_t len; | ||
1007 | |||
1008 | /* Prepare the state. | ||
1009 | * This will be saved in the hashmap, so that the receiving procedure knows | ||
1010 | * through which tunnel this connection has to be routed. | ||
1011 | */ | ||
1012 | struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state)); | ||
1013 | |||
1014 | state->tunnel = tunnel; | ||
1015 | state->serv = serv; | ||
1016 | state->type = SERVICE; | ||
1017 | state->hashmap = tcp_connections; | ||
1018 | memcpy (&state->desc, desc, sizeof (GNUNET_HashCode)); | ||
1019 | |||
1020 | len = | ||
1021 | sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) + | ||
1022 | sizeof (struct ip6_hdr) + pkt_len; | ||
1023 | { | ||
1024 | char buf[len]; | ||
1025 | |||
1026 | memset (buf, 0, len); | ||
1027 | switch (serv->version) | ||
1028 | { | ||
1029 | case 4: | ||
1030 | prepare_ipv4_packet (len, pkt_len, pkt, IPPROTO_TCP, &serv->v4.ip4address, | ||
1031 | tunnel, state, (struct ip_pkt *) buf); | ||
1032 | break; | ||
1033 | case 6: | ||
1034 | prepare_ipv6_packet (len, pkt_len, pkt, IPPROTO_TCP, &serv->v6.ip6address, | ||
1035 | tunnel, state, (struct ip6_pkt *) buf); | ||
1036 | |||
1037 | break; | ||
1038 | default: | ||
1039 | GNUNET_assert (0); | ||
1040 | break; | ||
1041 | } | ||
1042 | |||
1043 | hash_redirect_info (&state->hash, &state->redirect_info, | ||
1044 | serv->version == 4 ? 4 : 16); | ||
1045 | |||
1046 | if (GNUNET_NO == | ||
1047 | GNUNET_CONTAINER_multihashmap_contains (tcp_connections, &state->hash)) | ||
1048 | { | ||
1049 | GNUNET_CONTAINER_multihashmap_put (tcp_connections, &state->hash, state, | ||
1050 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1051 | |||
1052 | state->heap_node = | ||
1053 | GNUNET_CONTAINER_heap_insert (tcp_connections_heap, state, | ||
1054 | GNUNET_TIME_absolute_get ().abs_value); | ||
1055 | |||
1056 | if (GNUNET_CONTAINER_heap_get_size (tcp_connections_heap) > | ||
1057 | max_tcp_connections) | ||
1058 | GNUNET_SCHEDULER_add_now (collect_connections, tcp_connections_heap); | ||
1059 | } | ||
1060 | else | ||
1061 | GNUNET_free (state); | ||
1062 | |||
1063 | /* FIXME: here, flow-control with mesh would be nice to have... */ | ||
1064 | (void) GNUNET_HELPER_send (helper_handle, | ||
1065 | (const struct GNUNET_MessageHeader*) buf, | ||
1066 | GNUNET_YES, | ||
1067 | NULL, NULL); | ||
1068 | } | ||
1069 | return GNUNET_YES; | ||
1070 | } | ||
1071 | |||
1072 | |||
1073 | static int | ||
1074 | receive_tcp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
1075 | void **tunnel_ctx GNUNET_UNUSED, | ||
1076 | const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, | ||
1077 | const struct GNUNET_MessageHeader *message, | ||
1078 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
1079 | { | ||
1080 | GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); | ||
1081 | struct tcp_pkt *pkt = (struct tcp_pkt *) (desc + 1); | ||
1082 | struct remote_addr *s = (struct remote_addr *) desc; | ||
1083 | char *buf; | ||
1084 | size_t len; | ||
1085 | uint16_t pkt_len = | ||
1086 | ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - | ||
1087 | sizeof (GNUNET_HashCode); | ||
1088 | |||
1089 | struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state)); | ||
1090 | |||
1091 | state->tunnel = tunnel; | ||
1092 | state->type = REMOTE; | ||
1093 | state->hashmap = tcp_connections; | ||
1094 | memcpy (&state->remote, s, sizeof (struct remote_addr)); | ||
1095 | |||
1096 | len = | ||
1097 | sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) + | ||
1098 | sizeof (struct ip6_hdr) + pkt_len; | ||
1099 | buf = alloca (len); | ||
1100 | |||
1101 | memset (buf, 0, len); | ||
1102 | |||
1103 | switch (s->addrlen) | ||
1104 | { | ||
1105 | case 4: | ||
1106 | prepare_ipv4_packet (len, pkt_len, pkt, IPPROTO_TCP, &s->addr, tunnel, | ||
1107 | state, (struct ip_pkt *) buf); | ||
1108 | break; | ||
1109 | case 16: | ||
1110 | prepare_ipv6_packet (len, pkt_len, pkt, IPPROTO_TCP, &s->addr, tunnel, | ||
1111 | state, (struct ip6_pkt *) buf); | ||
1112 | break; | ||
1113 | default: | ||
1114 | GNUNET_free (state); | ||
1115 | return GNUNET_SYSERR; | ||
1116 | } | ||
1117 | |||
1118 | hash_redirect_info (&state->hash, &state->redirect_info, s->addrlen); | ||
1119 | |||
1120 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Packet from remote; hash is %x\n", | ||
1121 | *((uint32_t *) & state->hash)); | ||
1122 | |||
1123 | if (GNUNET_NO == | ||
1124 | GNUNET_CONTAINER_multihashmap_contains (tcp_connections, &state->hash)) | ||
1125 | { | ||
1126 | GNUNET_CONTAINER_multihashmap_put (tcp_connections, &state->hash, state, | ||
1127 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1128 | |||
1129 | state->heap_node = | ||
1130 | GNUNET_CONTAINER_heap_insert (tcp_connections_heap, state, | ||
1131 | GNUNET_TIME_absolute_get ().abs_value); | ||
1132 | |||
1133 | if (GNUNET_CONTAINER_heap_get_size (tcp_connections_heap) > | ||
1134 | max_tcp_connections) | ||
1135 | GNUNET_SCHEDULER_add_now (collect_connections, tcp_connections_heap); | ||
1136 | } | ||
1137 | else | ||
1138 | GNUNET_free (state); | ||
1139 | |||
1140 | /* FIXME: here, flow-control with mesh would be nice to have... */ | ||
1141 | (void) GNUNET_HELPER_send (helper_handle, | ||
1142 | (const struct GNUNET_MessageHeader*) buf, | ||
1143 | GNUNET_YES, | ||
1144 | NULL, NULL); | ||
1145 | return GNUNET_YES; | ||
1146 | |||
1147 | } | ||
1148 | |||
1149 | static int | ||
1150 | receive_udp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
1151 | void **tunnel_ctx GNUNET_UNUSED, | ||
1152 | const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, | ||
1153 | const struct GNUNET_MessageHeader *message, | ||
1154 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
1155 | { | ||
1156 | GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); | ||
1157 | struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1); | ||
1158 | struct remote_addr *s = (struct remote_addr *) desc; | ||
1159 | char *buf; | ||
1160 | size_t len; | ||
1161 | |||
1162 | GNUNET_assert (ntohs (pkt->len) == | ||
1163 | ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - | ||
1164 | sizeof (GNUNET_HashCode)); | ||
1165 | |||
1166 | /* Prepare the state. | ||
1167 | * This will be saved in the hashmap, so that the receiving procedure knows | ||
1168 | * through which tunnel this connection has to be routed. | ||
1169 | */ | ||
1170 | struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state)); | ||
1171 | |||
1172 | state->tunnel = tunnel; | ||
1173 | state->hashmap = udp_connections; | ||
1174 | state->type = REMOTE; | ||
1175 | memcpy (&state->remote, s, sizeof (struct remote_addr)); | ||
1176 | |||
1177 | len = | ||
1178 | sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) + | ||
1179 | sizeof (struct ip6_hdr) + ntohs (pkt->len); | ||
1180 | buf = alloca (len); | ||
1181 | |||
1182 | memset (buf, 0, len); | ||
1183 | |||
1184 | switch (s->addrlen) | ||
1185 | { | ||
1186 | case 4: | ||
1187 | prepare_ipv4_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, &s->addr, | ||
1188 | tunnel, state, (struct ip_pkt *) buf); | ||
1189 | break; | ||
1190 | case 16: | ||
1191 | prepare_ipv6_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, &s->addr, | ||
1192 | tunnel, state, (struct ip6_pkt *) buf); | ||
1193 | break; | ||
1194 | default: | ||
1195 | GNUNET_assert (0); | ||
1196 | break; | ||
1197 | } | ||
1198 | |||
1199 | hash_redirect_info (&state->hash, &state->redirect_info, s->addrlen); | ||
1200 | |||
1201 | if (GNUNET_NO == | ||
1202 | GNUNET_CONTAINER_multihashmap_contains (udp_connections, &state->hash)) | ||
1203 | { | ||
1204 | GNUNET_CONTAINER_multihashmap_put (udp_connections, &state->hash, state, | ||
1205 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1206 | |||
1207 | state->heap_node = | ||
1208 | GNUNET_CONTAINER_heap_insert (udp_connections_heap, state, | ||
1209 | GNUNET_TIME_absolute_get ().abs_value); | ||
1210 | |||
1211 | if (GNUNET_CONTAINER_heap_get_size (udp_connections_heap) > | ||
1212 | max_udp_connections) | ||
1213 | GNUNET_SCHEDULER_add_now (collect_connections, udp_connections_heap); | ||
1214 | } | ||
1215 | else | ||
1216 | GNUNET_free (state); | ||
1217 | |||
1218 | (void) GNUNET_HELPER_send (helper_handle, | ||
1219 | (const struct GNUNET_MessageHeader*) buf, | ||
1220 | GNUNET_YES, | ||
1221 | NULL, NULL); | ||
1222 | return GNUNET_YES; | ||
1223 | } | ||
1224 | |||
1225 | /** | ||
1226 | * The messages are one GNUNET_HashCode for the service, followed by a struct udp_pkt | ||
1227 | */ | ||
1228 | static int | ||
1229 | receive_udp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
1230 | void **tunnel_ctx, | ||
1231 | const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, | ||
1232 | const struct GNUNET_MessageHeader *message, | ||
1233 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
1234 | { | ||
1235 | GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); | ||
1236 | struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1); | ||
1237 | |||
1238 | GNUNET_assert (ntohs (pkt->len) == | ||
1239 | ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - | ||
1240 | sizeof (GNUNET_HashCode)); | ||
1241 | |||
1242 | /* Get the configuration from the hashmap */ | ||
1243 | uint16_t *udp_desc = alloca (sizeof (GNUNET_HashCode) + 2); | ||
1244 | |||
1245 | memcpy (udp_desc + 1, desc, sizeof (GNUNET_HashCode)); | ||
1246 | *udp_desc = ntohs (pkt->dpt); | ||
1247 | struct redirect_service *serv = | ||
1248 | GNUNET_CONTAINER_multihashmap_get (udp_services, | ||
1249 | (GNUNET_HashCode *) udp_desc); | ||
1250 | |||
1251 | if (NULL == serv) | ||
1252 | { | ||
1253 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "No service found for UDP dpt %d!\n", | ||
1254 | *udp_desc); | ||
1255 | return GNUNET_YES; | ||
1256 | } | ||
1257 | |||
1258 | pkt->dpt = htons (serv->remote_port); | ||
1259 | |||
1260 | /* | ||
1261 | * At this point it would be possible to check against some kind of ACL. | ||
1262 | */ | ||
1263 | |||
1264 | char *buf; | ||
1265 | size_t len; | ||
1266 | |||
1267 | /* Prepare the state. | ||
1268 | * This will be saved in the hashmap, so that the receiving procedure knows | ||
1269 | * through which tunnel this connection has to be routed. | ||
1270 | */ | ||
1271 | struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state)); | ||
1272 | |||
1273 | state->tunnel = tunnel; | ||
1274 | state->serv = serv; | ||
1275 | state->type = SERVICE; | ||
1276 | state->hashmap = udp_connections; | ||
1277 | memcpy (&state->desc, desc, sizeof (GNUNET_HashCode)); | ||
1278 | |||
1279 | len = | ||
1280 | sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) + | ||
1281 | sizeof (struct ip6_hdr) + ntohs (pkt->len); | ||
1282 | buf = alloca (len); | ||
1283 | |||
1284 | memset (buf, 0, len); | ||
1285 | |||
1286 | switch (serv->version) | ||
1287 | { | ||
1288 | case 4: | ||
1289 | prepare_ipv4_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, | ||
1290 | &serv->v4.ip4address, tunnel, state, | ||
1291 | (struct ip_pkt *) buf); | ||
1292 | break; | ||
1293 | case 6: | ||
1294 | prepare_ipv6_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, | ||
1295 | &serv->v6.ip6address, tunnel, state, | ||
1296 | (struct ip6_pkt *) buf); | ||
1297 | |||
1298 | break; | ||
1299 | default: | ||
1300 | GNUNET_assert (0); | ||
1301 | break; | ||
1302 | } | ||
1303 | |||
1304 | hash_redirect_info (&state->hash, &state->redirect_info, | ||
1305 | serv->version == 4 ? 4 : 16); | ||
1306 | |||
1307 | if (GNUNET_NO == | ||
1308 | GNUNET_CONTAINER_multihashmap_contains (udp_connections, &state->hash)) | ||
1309 | { | ||
1310 | GNUNET_CONTAINER_multihashmap_put (udp_connections, &state->hash, state, | ||
1311 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1312 | |||
1313 | state->heap_node = | ||
1314 | GNUNET_CONTAINER_heap_insert (udp_connections_heap, state, | ||
1315 | GNUNET_TIME_absolute_get ().abs_value); | ||
1316 | |||
1317 | if (GNUNET_CONTAINER_heap_get_size (udp_connections_heap) > | ||
1318 | max_udp_connections) | ||
1319 | GNUNET_SCHEDULER_add_now (collect_connections, udp_connections_heap); | ||
1320 | } | ||
1321 | else | ||
1322 | GNUNET_free (state); | ||
1323 | |||
1324 | (void) GNUNET_HELPER_send (helper_handle, | ||
1325 | (const struct GNUNET_MessageHeader*) buf, | ||
1326 | GNUNET_YES, | ||
1327 | NULL, NULL); | ||
1328 | return GNUNET_YES; | ||
1329 | } | ||
1330 | |||
1331 | static void | ||
1332 | connect_to_mesh () | ||
1333 | { | ||
1334 | int udp, tcp; | ||
1335 | int handler_idx, app_idx; | ||
1336 | |||
1337 | udp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_UDP"); | ||
1338 | tcp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_TCP"); | ||
1339 | |||
1340 | static struct GNUNET_MESH_MessageHandler handlers[] = { | ||
1341 | {receive_udp_service, GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP, 0}, | ||
1342 | {receive_tcp_service, GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP, 0}, | ||
1343 | {NULL, 0, 0}, | ||
1344 | {NULL, 0, 0}, | ||
1345 | {NULL, 0, 0} | ||
1346 | }; | ||
1347 | |||
1348 | static GNUNET_MESH_ApplicationType apptypes[] = { | ||
1349 | GNUNET_APPLICATION_TYPE_END, | ||
1350 | GNUNET_APPLICATION_TYPE_END, | ||
1351 | GNUNET_APPLICATION_TYPE_END | ||
1352 | }; | ||
1353 | |||
1354 | app_idx = 0; | ||
1355 | handler_idx = 2; | ||
1356 | |||
1357 | if (GNUNET_YES == udp) | ||
1358 | { | ||
1359 | handlers[handler_idx].callback = receive_udp_remote; | ||
1360 | handlers[handler_idx].expected_size = 0; | ||
1361 | handlers[handler_idx].type = GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP; | ||
1362 | apptypes[app_idx] = GNUNET_APPLICATION_TYPE_INTERNET_UDP_GATEWAY; | ||
1363 | handler_idx++; | ||
1364 | app_idx++; | ||
1365 | } | ||
1366 | |||
1367 | if (GNUNET_YES == tcp) | ||
1368 | { | ||
1369 | handlers[handler_idx].callback = receive_tcp_remote; | ||
1370 | handlers[handler_idx].expected_size = 0; | ||
1371 | handlers[handler_idx].type = GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP; | ||
1372 | apptypes[app_idx] = GNUNET_APPLICATION_TYPE_INTERNET_TCP_GATEWAY; | ||
1373 | handler_idx++; | ||
1374 | app_idx++; | ||
1375 | } | ||
1376 | |||
1377 | mesh_handle = | ||
1378 | GNUNET_MESH_connect (cfg, 42, NULL, new_tunnel, clean_tunnel, handlers, | ||
1379 | apptypes); | ||
1380 | } | ||
1381 | |||
1382 | |||
1383 | |||
1384 | /** | ||
1385 | * @brief Main function that will be run by the scheduler. | ||
1386 | * | ||
1387 | * @param cls closure | ||
1388 | * @param args remaining command-line arguments | ||
1389 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
1390 | * @param cfg_ configuration | ||
1391 | */ | ||
1392 | static void | ||
1393 | run (void *cls, char *const *args GNUNET_UNUSED, | ||
1394 | const char *cfgfile GNUNET_UNUSED, | ||
1395 | const struct GNUNET_CONFIGURATION_Handle *cfg_) | ||
1396 | { | ||
1397 | char *ifname; | ||
1398 | char *ipv6addr; | ||
1399 | char *ipv6prefix; | ||
1400 | char *ipv4addr; | ||
1401 | char *ipv4mask; | ||
1402 | |||
1403 | cfg = cfg_; | ||
1404 | connect_to_mesh (); | ||
1405 | udp_connections = GNUNET_CONTAINER_multihashmap_create (65536); | ||
1406 | udp_connections_heap = | ||
1407 | GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
1408 | tcp_connections = GNUNET_CONTAINER_multihashmap_create (65536); | ||
1409 | tcp_connections_heap = | ||
1410 | GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
1411 | udp_services = GNUNET_CONTAINER_multihashmap_create (65536); | ||
1412 | tcp_services = GNUNET_CONTAINER_multihashmap_create (65536); | ||
1413 | if (GNUNET_OK != | ||
1414 | GNUNET_CONFIGURATION_get_value_number (cfg, "exit", "MAX_UDP_CONNECTIONS", | ||
1415 | &max_udp_connections)) | ||
1416 | max_udp_connections = 1024; | ||
1417 | if (GNUNET_OK != | ||
1418 | GNUNET_CONFIGURATION_get_value_number (cfg, "exit", "MAX_TCP_CONNECTIONS", | ||
1419 | &max_tcp_connections)) | ||
1420 | max_tcp_connections = 256; | ||
1421 | GNUNET_CONFIGURATION_iterate_sections (cfg, read_service_conf, NULL); | ||
1422 | |||
1423 | if (GNUNET_SYSERR == | ||
1424 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IFNAME", &ifname)) | ||
1425 | { | ||
1426 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1427 | "No entry 'IFNAME' in configuration!\n"); | ||
1428 | exit (1); | ||
1429 | } | ||
1430 | |||
1431 | if (GNUNET_SYSERR == | ||
1432 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6ADDR", | ||
1433 | &ipv6addr)) | ||
1434 | { | ||
1435 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1436 | "No entry 'IPV6ADDR' in configuration!\n"); | ||
1437 | exit (1); | ||
1438 | } | ||
1439 | |||
1440 | if (GNUNET_SYSERR == | ||
1441 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6PREFIX", | ||
1442 | &ipv6prefix)) | ||
1443 | { | ||
1444 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1445 | "No entry 'IPV6PREFIX' in configuration!\n"); | ||
1446 | exit (1); | ||
1447 | } | ||
1448 | |||
1449 | if (GNUNET_SYSERR == | ||
1450 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4ADDR", | ||
1451 | &ipv4addr)) | ||
1452 | { | ||
1453 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1454 | "No entry 'IPV4ADDR' in configuration!\n"); | ||
1455 | exit (1); | ||
1456 | } | ||
1457 | |||
1458 | if (GNUNET_SYSERR == | ||
1459 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4MASK", | ||
1460 | &ipv4mask)) | ||
1461 | { | ||
1462 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1463 | "No entry 'IPV4MASK' in configuration!\n"); | ||
1464 | exit (1); | ||
1465 | } | ||
1466 | exit_argv[0] = GNUNET_strdup ("exit-gnunet"); | ||
1467 | exit_argv[1] = ifname; | ||
1468 | exit_argv[2] = ipv6addr; | ||
1469 | exit_argv[3] = ipv6prefix; | ||
1470 | exit_argv[4] = ipv4addr; | ||
1471 | exit_argv[5] = ipv4mask; | ||
1472 | exit_argv[6] = NULL; | ||
1473 | helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", exit_argv, | ||
1474 | &message_token, NULL); | ||
1475 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); | ||
1476 | } | ||
1477 | |||
1478 | |||
1479 | /** | ||
1480 | * The main function | ||
1481 | * | ||
1482 | * @param argc number of arguments from the command line | ||
1483 | * @param argv command line arguments | ||
1484 | * @return 0 ok, 1 on error | ||
1485 | */ | ||
1486 | int | ||
1487 | main (int argc, char *const *argv) | ||
1488 | { | ||
1489 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
1490 | GNUNET_GETOPT_OPTION_END | ||
1491 | }; | ||
1492 | |||
1493 | return (GNUNET_OK == | ||
1494 | GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-exit", | ||
1495 | gettext_noop | ||
1496 | ("Daemon to run to provide an IP exit node for the VPN"), | ||
1497 | options, &run, NULL)) ? ret : 1; | ||
1498 | } | ||
1499 | |||
1500 | |||
1501 | /* end of gnunet-daemon-exit.c */ | ||
diff --git a/src/vpn/gnunet-daemon-vpn.c b/src/vpn/gnunet-daemon-vpn.c deleted file mode 100644 index 6945fc772..000000000 --- a/src/vpn/gnunet-daemon-vpn.c +++ /dev/null | |||
@@ -1,1808 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2010 Christian Grothoff | ||
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., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file vpn/gnunet-daemon-vpn.c | ||
23 | * @brief | ||
24 | * @author Philipp Toelke | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_getopt_lib.h" | ||
28 | #include "gnunet_program_lib.h" | ||
29 | #include "gnunet-vpn-packet.h" | ||
30 | #include "gnunet_common.h" | ||
31 | #include "gnunet_protocols.h" | ||
32 | #include "gnunet_applications.h" | ||
33 | #include <gnunet_mesh_service.h> | ||
34 | #include "gnunet_client_lib.h" | ||
35 | #include "gnunet_container_lib.h" | ||
36 | #include "gnunet_constants.h" | ||
37 | #include <block_dns.h> | ||
38 | #include "gnunet_dns_service.h" | ||
39 | |||
40 | |||
41 | struct answer_packet_list | ||
42 | { | ||
43 | struct answer_packet_list *next; | ||
44 | struct answer_packet_list *prev; | ||
45 | struct GNUNET_SERVER_Client *client; | ||
46 | struct answer_packet pkt; | ||
47 | }; | ||
48 | |||
49 | |||
50 | struct map_entry | ||
51 | { | ||
52 | /** The description of the service (used for service) */ | ||
53 | struct GNUNET_vpn_service_descriptor desc; | ||
54 | |||
55 | /** The real address of the service (used for remote) */ | ||
56 | char addrlen; | ||
57 | char addr[16]; | ||
58 | |||
59 | struct GNUNET_MESH_Tunnel *tunnel; | ||
60 | uint16_t namelen; | ||
61 | char additional_ports[8192]; | ||
62 | |||
63 | struct GNUNET_CONTAINER_HeapNode *heap_node; | ||
64 | GNUNET_HashCode hash; | ||
65 | /** | ||
66 | * After this struct the name is located in DNS-Format! | ||
67 | */ | ||
68 | }; | ||
69 | |||
70 | |||
71 | struct remote_addr | ||
72 | { | ||
73 | char addrlen; | ||
74 | unsigned char addr[16]; | ||
75 | char proto; | ||
76 | }; | ||
77 | |||
78 | |||
79 | struct tunnel_notify_queue | ||
80 | { | ||
81 | struct tunnel_notify_queue *next; | ||
82 | struct tunnel_notify_queue *prev; | ||
83 | size_t len; | ||
84 | void *cls; | ||
85 | }; | ||
86 | |||
87 | |||
88 | struct tunnel_state | ||
89 | { | ||
90 | struct GNUNET_MESH_TransmitHandle *th; | ||
91 | struct tunnel_notify_queue *head, *tail; | ||
92 | |||
93 | int addrlen; | ||
94 | }; | ||
95 | |||
96 | |||
97 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
98 | |||
99 | static struct GNUNET_MESH_Handle *mesh_handle; | ||
100 | |||
101 | static struct GNUNET_CONTAINER_MultiHashMap *hashmap; | ||
102 | |||
103 | static struct GNUNET_CONTAINER_Heap *heap; | ||
104 | |||
105 | /** | ||
106 | * The handle to the helper | ||
107 | */ | ||
108 | static struct GNUNET_HELPER_Handle *helper_handle; | ||
109 | |||
110 | /** | ||
111 | * Arguments to the exit helper. | ||
112 | */ | ||
113 | static char *vpn_argv[7]; | ||
114 | |||
115 | static struct GNUNET_DNS_Handle *dns_handle; | ||
116 | |||
117 | static struct answer_packet_list *answer_proc_head; | ||
118 | |||
119 | static struct answer_packet_list *answer_proc_tail; | ||
120 | |||
121 | /** | ||
122 | * If there are at least this many address-mappings, old ones will be removed | ||
123 | */ | ||
124 | static long long unsigned int max_mappings = 200; | ||
125 | |||
126 | /** | ||
127 | * Final status code. | ||
128 | */ | ||
129 | static int ret; | ||
130 | |||
131 | /** | ||
132 | * This hashmap contains the mapping from peer, service-descriptor, | ||
133 | * source-port and destination-port to a socket | ||
134 | */ | ||
135 | static struct GNUNET_CONTAINER_MultiHashMap *udp_connections; | ||
136 | |||
137 | static GNUNET_SCHEDULER_TaskIdentifier conn_task; | ||
138 | |||
139 | static GNUNET_SCHEDULER_TaskIdentifier shs_task; | ||
140 | |||
141 | /** | ||
142 | * The tunnels that will be used to send tcp- and udp-packets | ||
143 | */ | ||
144 | static struct GNUNET_MESH_Tunnel *tcp_tunnel; | ||
145 | static struct GNUNET_MESH_Tunnel *udp_tunnel; | ||
146 | |||
147 | |||
148 | static unsigned int | ||
149 | port_in_ports (uint64_t ports, uint16_t port) | ||
150 | { | ||
151 | uint16_t *ps = (uint16_t *) & ports; | ||
152 | |||
153 | return ports == 0 || ps[0] == port || ps[1] == port || ps[2] == port || | ||
154 | ps[3] == port; | ||
155 | } | ||
156 | |||
157 | |||
158 | /** | ||
159 | * Sets a bit active in a bitArray. | ||
160 | * | ||
161 | * @param bitArray memory area to set the bit in | ||
162 | * @param bitIdx which bit to set | ||
163 | */ | ||
164 | static void | ||
165 | setBit (char *bitArray, unsigned int bitIdx) | ||
166 | { | ||
167 | size_t arraySlot; | ||
168 | unsigned int targetBit; | ||
169 | |||
170 | arraySlot = bitIdx / 8; | ||
171 | targetBit = (1L << (bitIdx % 8)); | ||
172 | bitArray[arraySlot] |= targetBit; | ||
173 | } | ||
174 | |||
175 | |||
176 | /** | ||
177 | * Checks if a bit is active in the bitArray | ||
178 | * | ||
179 | * @param bitArray memory area to set the bit in | ||
180 | * @param bitIdx which bit to test | ||
181 | * @return GNUNET_YES if the bit is set, GNUNET_NO if not. | ||
182 | */ | ||
183 | static int | ||
184 | testBit (char *bitArray, unsigned int bitIdx) | ||
185 | { | ||
186 | size_t slot; | ||
187 | unsigned int targetBit; | ||
188 | |||
189 | slot = bitIdx / 8; | ||
190 | targetBit = (1L << (bitIdx % 8)); | ||
191 | if (bitArray[slot] & targetBit) | ||
192 | return GNUNET_YES; | ||
193 | else | ||
194 | return GNUNET_NO; | ||
195 | } | ||
196 | |||
197 | |||
198 | /** | ||
199 | * Function scheduled as very last function, cleans up after us | ||
200 | *{{{ | ||
201 | */ | ||
202 | static void | ||
203 | cleanup (void *cls GNUNET_UNUSED, | ||
204 | const struct GNUNET_SCHEDULER_TaskContext *tskctx) | ||
205 | { | ||
206 | unsigned int i; | ||
207 | |||
208 | GNUNET_assert (0 != (tskctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)); | ||
209 | /* close the connection to the service-dns */ | ||
210 | GNUNET_DNS_disconnect (dns_handle); | ||
211 | if (mesh_handle != NULL) | ||
212 | { | ||
213 | GNUNET_MESH_disconnect (mesh_handle); | ||
214 | mesh_handle = NULL; | ||
215 | } | ||
216 | if (helper_handle != NULL) | ||
217 | { | ||
218 | GNUNET_HELPER_stop (helper_handle); | ||
219 | helper_handle = NULL; | ||
220 | } | ||
221 | if (GNUNET_SCHEDULER_NO_TASK != shs_task) | ||
222 | { | ||
223 | GNUNET_SCHEDULER_cancel (shs_task); | ||
224 | shs_task = GNUNET_SCHEDULER_NO_TASK; | ||
225 | } | ||
226 | if (GNUNET_SCHEDULER_NO_TASK != conn_task) | ||
227 | { | ||
228 | GNUNET_SCHEDULER_cancel (conn_task); | ||
229 | conn_task = GNUNET_SCHEDULER_NO_TASK; | ||
230 | } | ||
231 | for (i=0;i<5;i++) | ||
232 | GNUNET_free_non_null (vpn_argv[i]); | ||
233 | } | ||
234 | |||
235 | /*}}}*/ | ||
236 | |||
237 | /** | ||
238 | * @return the hash of the IP-Address if a mapping exists, NULL otherwise | ||
239 | */ | ||
240 | static GNUNET_HashCode * | ||
241 | address6_mapping_exists (struct in6_addr *v6addr) | ||
242 | { | ||
243 | unsigned char *addr = (unsigned char*) v6addr; | ||
244 | GNUNET_HashCode *key = GNUNET_malloc (sizeof (GNUNET_HashCode)); | ||
245 | unsigned char *k = (unsigned char *) key; | ||
246 | |||
247 | memset (key, 0, sizeof (GNUNET_HashCode)); | ||
248 | unsigned int i; | ||
249 | |||
250 | for (i = 0; i < 16; i++) | ||
251 | k[15 - i] = addr[i]; | ||
252 | |||
253 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (hashmap, key)) | ||
254 | return key; | ||
255 | else | ||
256 | { | ||
257 | GNUNET_free (key); | ||
258 | return NULL; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | /** | ||
263 | * @return the hash of the IP-Address if a mapping exists, NULL otherwise | ||
264 | */ | ||
265 | static GNUNET_HashCode * | ||
266 | address4_mapping_exists (uint32_t addr) | ||
267 | { | ||
268 | GNUNET_HashCode *key = GNUNET_malloc (sizeof (GNUNET_HashCode)); | ||
269 | |||
270 | memset (key, 0, sizeof (GNUNET_HashCode)); | ||
271 | unsigned char *c = (unsigned char *) &addr; | ||
272 | unsigned char *k = (unsigned char *) key; | ||
273 | unsigned int i; | ||
274 | |||
275 | for (i = 0; i < 4; i++) | ||
276 | k[3 - i] = c[i]; | ||
277 | |||
278 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
279 | "a4_m_e: getting with key %08x, addr is %08x, %d.%d.%d.%d\n", | ||
280 | *((uint32_t *) (key)), addr, c[0], c[1], c[2], c[3]); | ||
281 | |||
282 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (hashmap, key)) | ||
283 | return key; | ||
284 | else | ||
285 | { | ||
286 | GNUNET_free (key); | ||
287 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mapping not found!\n"); | ||
288 | return NULL; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | |||
293 | static void * | ||
294 | initialize_tunnel_state (int addrlen, struct GNUNET_MESH_TransmitHandle *th) | ||
295 | { | ||
296 | struct tunnel_state *ts = GNUNET_malloc (sizeof *ts); | ||
297 | |||
298 | ts->addrlen = addrlen; | ||
299 | ts->th = th; | ||
300 | return ts; | ||
301 | } | ||
302 | |||
303 | |||
304 | static void | ||
305 | send_icmp4_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
306 | { | ||
307 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
308 | return; | ||
309 | |||
310 | struct ip_icmp *request = cls; | ||
311 | |||
312 | struct ip_icmp *response = alloca (ntohs (request->shdr.size)); | ||
313 | |||
314 | GNUNET_assert (response != NULL); | ||
315 | memset (response, 0, ntohs (request->shdr.size)); | ||
316 | |||
317 | response->shdr.size = request->shdr.size; | ||
318 | response->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
319 | |||
320 | response->tun.flags = 0; | ||
321 | response->tun.type = htons (0x0800); | ||
322 | |||
323 | response->ip_hdr.hdr_lngth = 5; | ||
324 | response->ip_hdr.version = 4; | ||
325 | response->ip_hdr.proto = 0x01; | ||
326 | response->ip_hdr.dadr = request->ip_hdr.sadr; | ||
327 | response->ip_hdr.sadr = request->ip_hdr.dadr; | ||
328 | response->ip_hdr.tot_lngth = request->ip_hdr.tot_lngth; | ||
329 | |||
330 | response->ip_hdr.chks = | ||
331 | GNUNET_CRYPTO_crc16_n ((uint16_t *) & response->ip_hdr, 20); | ||
332 | |||
333 | response->icmp_hdr.code = 0; | ||
334 | response->icmp_hdr.type = 0x0; | ||
335 | |||
336 | /* Magic, more Magic! */ | ||
337 | response->icmp_hdr.chks = request->icmp_hdr.chks + 0x8; | ||
338 | |||
339 | /* Copy the rest of the packet */ | ||
340 | memcpy (response + 1, request + 1, | ||
341 | ntohs (request->shdr.size) - sizeof (struct ip_icmp)); | ||
342 | |||
343 | (void) GNUNET_HELPER_send (helper_handle, | ||
344 | &response->shdr, | ||
345 | GNUNET_YES, | ||
346 | NULL, NULL); | ||
347 | GNUNET_free (request); | ||
348 | } | ||
349 | |||
350 | |||
351 | static void | ||
352 | send_icmp6_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
353 | { | ||
354 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
355 | return; | ||
356 | |||
357 | struct ip6_icmp *request = cls; | ||
358 | |||
359 | struct ip6_icmp *response = alloca (ntohs (request->shdr.size)); | ||
360 | |||
361 | GNUNET_assert (response != NULL); | ||
362 | memset (response, 0, ntohs (request->shdr.size)); | ||
363 | |||
364 | response->shdr.size = request->shdr.size; | ||
365 | response->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
366 | |||
367 | response->tun.flags = 0; | ||
368 | response->tun.type = htons (0x86dd); | ||
369 | |||
370 | response->ip6_hdr.hoplmt = 255; | ||
371 | response->ip6_hdr.paylgth = request->ip6_hdr.paylgth; | ||
372 | response->ip6_hdr.nxthdr = 0x3a; | ||
373 | response->ip6_hdr.version = 6; | ||
374 | memcpy (&response->ip6_hdr.sadr, &request->ip6_hdr.dadr, 16); | ||
375 | memcpy (&response->ip6_hdr.dadr, &request->ip6_hdr.sadr, 16); | ||
376 | |||
377 | response->icmp_hdr.code = 0; | ||
378 | response->icmp_hdr.type = 0x81; | ||
379 | |||
380 | /* Magic, more Magic! */ | ||
381 | response->icmp_hdr.chks = request->icmp_hdr.chks - 0x1; | ||
382 | |||
383 | /* Copy the rest of the packet */ | ||
384 | memcpy (response + 1, request + 1, | ||
385 | ntohs (request->shdr.size) - sizeof (struct ip6_icmp)); | ||
386 | |||
387 | (void) GNUNET_HELPER_send (helper_handle, | ||
388 | &response->shdr, | ||
389 | GNUNET_YES, | ||
390 | NULL, NULL); | ||
391 | GNUNET_free (request); | ||
392 | } | ||
393 | |||
394 | |||
395 | /** | ||
396 | * cls is the pointer to a GNUNET_MessageHeader that is | ||
397 | * followed by the service-descriptor and the packet that should be sent; | ||
398 | */ | ||
399 | static size_t | ||
400 | send_pkt_to_peer_notify_callback (void *cls, size_t size, void *buf) | ||
401 | { | ||
402 | struct GNUNET_MESH_Tunnel **tunnel = cls; | ||
403 | |||
404 | struct tunnel_state *ts = GNUNET_MESH_tunnel_get_data (*tunnel); | ||
405 | |||
406 | ts->th = NULL; | ||
407 | |||
408 | if (NULL != buf) | ||
409 | { | ||
410 | struct GNUNET_MessageHeader *hdr = | ||
411 | (struct GNUNET_MessageHeader *) (tunnel + 1); | ||
412 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
413 | "send_pkt_to_peer_notify_callback: buf = %x; size = %u;\n", buf, | ||
414 | size); | ||
415 | GNUNET_assert (size >= ntohs (hdr->size)); | ||
416 | memcpy (buf, hdr, ntohs (hdr->size)); | ||
417 | size = ntohs (hdr->size); | ||
418 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent!\n"); | ||
419 | } | ||
420 | else | ||
421 | size = 0; | ||
422 | |||
423 | if (NULL != ts->head) | ||
424 | { | ||
425 | struct tunnel_notify_queue *element = ts->head; | ||
426 | |||
427 | GNUNET_CONTAINER_DLL_remove (ts->head, ts->tail, element); | ||
428 | |||
429 | ts->th = | ||
430 | GNUNET_MESH_notify_transmit_ready (*tunnel, GNUNET_NO, 42, | ||
431 | GNUNET_TIME_relative_divide | ||
432 | (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), | ||
433 | (const struct GNUNET_PeerIdentity *) | ||
434 | NULL, element->len, | ||
435 | send_pkt_to_peer_notify_callback, | ||
436 | element->cls); | ||
437 | |||
438 | /* save the handle */ | ||
439 | GNUNET_free (element); | ||
440 | } | ||
441 | GNUNET_free (cls); | ||
442 | |||
443 | return size; | ||
444 | } | ||
445 | |||
446 | |||
447 | static void | ||
448 | send_pkt_to_peer (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
449 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
450 | { | ||
451 | /* peer == NULL means that all peers in this request are connected */ | ||
452 | if (peer == NULL) | ||
453 | return; | ||
454 | struct GNUNET_MESH_Tunnel **tunnel = cls; | ||
455 | struct GNUNET_MessageHeader *hdr = | ||
456 | (struct GNUNET_MessageHeader *) (tunnel + 1); | ||
457 | |||
458 | GNUNET_assert (NULL != tunnel); | ||
459 | GNUNET_assert (NULL != *tunnel); | ||
460 | |||
461 | struct tunnel_state *ts = GNUNET_MESH_tunnel_get_data (*tunnel); | ||
462 | |||
463 | if (NULL == ts->th) | ||
464 | { | ||
465 | ts->th = | ||
466 | GNUNET_MESH_notify_transmit_ready (*tunnel, GNUNET_NO, 42, | ||
467 | GNUNET_TIME_relative_divide | ||
468 | (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), | ||
469 | (const struct GNUNET_PeerIdentity *) | ||
470 | NULL, ntohs (hdr->size), | ||
471 | send_pkt_to_peer_notify_callback, | ||
472 | cls); | ||
473 | } | ||
474 | else | ||
475 | { | ||
476 | struct tunnel_notify_queue *element = GNUNET_malloc (sizeof *element); | ||
477 | |||
478 | element->cls = cls; | ||
479 | element->len = ntohs (hdr->size); | ||
480 | |||
481 | GNUNET_CONTAINER_DLL_insert_tail (ts->head, ts->tail, element); | ||
482 | } | ||
483 | } | ||
484 | |||
485 | |||
486 | |||
487 | |||
488 | /** | ||
489 | * Receive packets from the helper-process | ||
490 | */ | ||
491 | static void | ||
492 | message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED, | ||
493 | const struct GNUNET_MessageHeader *message) | ||
494 | { | ||
495 | GNUNET_assert (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
496 | |||
497 | struct tun_pkt *pkt_tun = (struct tun_pkt *) message; | ||
498 | GNUNET_HashCode *key; | ||
499 | |||
500 | /* ethertype is ipv6 */ | ||
501 | if (ntohs (pkt_tun->tun.type) == 0x86dd) | ||
502 | { | ||
503 | struct ip6_pkt *pkt6 = (struct ip6_pkt *) message; | ||
504 | |||
505 | GNUNET_assert (pkt6->ip6_hdr.version == 6); | ||
506 | struct ip6_tcp *pkt6_tcp; | ||
507 | struct ip6_udp *pkt6_udp; | ||
508 | struct ip6_icmp *pkt6_icmp; | ||
509 | |||
510 | pkt6_udp = NULL; /* make compiler happy */ | ||
511 | switch (pkt6->ip6_hdr.nxthdr) | ||
512 | { | ||
513 | case IPPROTO_UDP: | ||
514 | pkt6_udp = (struct ip6_udp *) pkt6; | ||
515 | /* Send dns-packets to the service-dns */ | ||
516 | if (ntohs (pkt6_udp->udp_hdr.dpt) == 53) | ||
517 | { | ||
518 | /* 9 = 8 for the udp-header + 1 for the unsigned char data[1]; */ | ||
519 | GNUNET_DNS_queue_request_v6 (dns_handle, | ||
520 | &pkt6->ip6_hdr.dadr, | ||
521 | &pkt6->ip6_hdr.sadr, | ||
522 | ntohs (pkt6_udp->udp_hdr.spt), | ||
523 | ntohs (pkt6_udp->udp_hdr.len) - 8, | ||
524 | (const void*) pkt6_udp->data); | ||
525 | |||
526 | break; | ||
527 | } | ||
528 | /* fall through */ | ||
529 | case IPPROTO_TCP: | ||
530 | pkt6_tcp = (struct ip6_tcp *) pkt6; | ||
531 | |||
532 | if ((key = address6_mapping_exists (&pkt6->ip6_hdr.dadr)) != NULL) | ||
533 | { | ||
534 | struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); | ||
535 | |||
536 | GNUNET_assert (me != NULL); | ||
537 | GNUNET_free (key); | ||
538 | |||
539 | size_t size = | ||
540 | sizeof (struct GNUNET_MESH_Tunnel *) + | ||
541 | sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + | ||
542 | ntohs (pkt6->ip6_hdr.paylgth); | ||
543 | |||
544 | struct GNUNET_MESH_Tunnel **cls = GNUNET_malloc (size); | ||
545 | struct GNUNET_MessageHeader *hdr = | ||
546 | (struct GNUNET_MessageHeader *) (cls + 1); | ||
547 | GNUNET_HashCode *hc = (GNUNET_HashCode *) (hdr + 1); | ||
548 | |||
549 | hdr->size = | ||
550 | htons (sizeof (struct GNUNET_MessageHeader) + | ||
551 | sizeof (GNUNET_HashCode) + ntohs (pkt6->ip6_hdr.paylgth)); | ||
552 | |||
553 | GNUNET_MESH_ApplicationType app_type = 0; /* fix compiler uninitialized warning... */ | ||
554 | |||
555 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "me->addrlen is %d\n", | ||
556 | me->addrlen); | ||
557 | if (me->addrlen == 0) | ||
558 | { | ||
559 | /* This is a mapping to a gnunet-service */ | ||
560 | memcpy (hc, &me->desc.service_descriptor, sizeof (GNUNET_HashCode)); | ||
561 | |||
562 | if (IPPROTO_UDP == pkt6->ip6_hdr.nxthdr && | ||
563 | (me->desc.service_type & htonl (GNUNET_DNS_SERVICE_TYPE_UDP)) && | ||
564 | (port_in_ports (me->desc.ports, pkt6_udp->udp_hdr.dpt) || | ||
565 | testBit (me->additional_ports, ntohs (pkt6_udp->udp_hdr.dpt)))) | ||
566 | { | ||
567 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP); | ||
568 | |||
569 | memcpy (hc + 1, &pkt6_udp->udp_hdr, ntohs (pkt6_udp->udp_hdr.len)); | ||
570 | |||
571 | } | ||
572 | else if (IPPROTO_TCP == pkt6->ip6_hdr.nxthdr && | ||
573 | (me->desc.service_type & htonl (GNUNET_DNS_SERVICE_TYPE_TCP)) | ||
574 | && (port_in_ports (me->desc.ports, pkt6_tcp->tcp_hdr.dpt))) | ||
575 | { | ||
576 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP); | ||
577 | |||
578 | memcpy (hc + 1, &pkt6_tcp->tcp_hdr, ntohs (pkt6->ip6_hdr.paylgth)); | ||
579 | |||
580 | } | ||
581 | else | ||
582 | { | ||
583 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pip: %d\n", | ||
584 | port_in_ports (me->desc.ports, pkt6_tcp->tcp_hdr.dpt)); | ||
585 | GNUNET_assert (0); | ||
586 | } | ||
587 | if (me->tunnel == NULL && NULL != cls) | ||
588 | { | ||
589 | *cls = | ||
590 | GNUNET_MESH_tunnel_create (mesh_handle, | ||
591 | initialize_tunnel_state (16, NULL), | ||
592 | &send_pkt_to_peer, NULL, cls); | ||
593 | |||
594 | GNUNET_MESH_peer_request_connect_add (*cls, | ||
595 | (struct GNUNET_PeerIdentity *) | ||
596 | &me->desc.peer); | ||
597 | me->tunnel = *cls; | ||
598 | } | ||
599 | else if (NULL != cls) | ||
600 | { | ||
601 | *cls = me->tunnel; | ||
602 | send_pkt_to_peer (cls, (struct GNUNET_PeerIdentity *) 1, NULL); | ||
603 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
604 | "Queued to send IPv6 to peer %x, type %d\n", | ||
605 | *((unsigned int *) &me->desc.peer), ntohs (hdr->type)); | ||
606 | } | ||
607 | } | ||
608 | else | ||
609 | { | ||
610 | /* This is a mapping to a "real" address */ | ||
611 | struct remote_addr *s = (struct remote_addr *) hc; | ||
612 | |||
613 | s->addrlen = me->addrlen; | ||
614 | memcpy (s->addr, me->addr, me->addrlen); | ||
615 | s->proto = pkt6->ip6_hdr.nxthdr; | ||
616 | if (s->proto == IPPROTO_UDP) | ||
617 | { | ||
618 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP); | ||
619 | memcpy (hc + 1, &pkt6_udp->udp_hdr, ntohs (pkt6_udp->udp_hdr.len)); | ||
620 | app_type = GNUNET_APPLICATION_TYPE_INTERNET_UDP_GATEWAY; | ||
621 | if (NULL != udp_tunnel) | ||
622 | me->tunnel = udp_tunnel; | ||
623 | } | ||
624 | else if (s->proto == IPPROTO_TCP) | ||
625 | { | ||
626 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP); | ||
627 | memcpy (hc + 1, &pkt6_tcp->tcp_hdr, ntohs (pkt6->ip6_hdr.paylgth)); | ||
628 | app_type = GNUNET_APPLICATION_TYPE_INTERNET_TCP_GATEWAY; | ||
629 | if (NULL != tcp_tunnel) | ||
630 | me->tunnel = tcp_tunnel; | ||
631 | } | ||
632 | else | ||
633 | { | ||
634 | GNUNET_assert (0); | ||
635 | } | ||
636 | if (me->tunnel == NULL && NULL != cls) | ||
637 | { | ||
638 | *cls = | ||
639 | GNUNET_MESH_tunnel_create (mesh_handle, | ||
640 | initialize_tunnel_state (16, NULL), | ||
641 | &send_pkt_to_peer, NULL, cls); | ||
642 | |||
643 | GNUNET_MESH_peer_request_connect_by_type (*cls, app_type); | ||
644 | me->tunnel = *cls; | ||
645 | if (GNUNET_APPLICATION_TYPE_INTERNET_UDP_GATEWAY == app_type) | ||
646 | udp_tunnel = *cls; | ||
647 | else if (GNUNET_APPLICATION_TYPE_INTERNET_TCP_GATEWAY == app_type) | ||
648 | tcp_tunnel = *cls; | ||
649 | } | ||
650 | else if (NULL != cls) | ||
651 | { | ||
652 | *cls = me->tunnel; | ||
653 | send_pkt_to_peer (cls, (struct GNUNET_PeerIdentity *) 1, NULL); | ||
654 | } | ||
655 | } | ||
656 | } | ||
657 | else | ||
658 | { | ||
659 | char pbuf[INET6_ADDRSTRLEN]; | ||
660 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
661 | "Packet to %s, which has no mapping\n", | ||
662 | inet_ntop (AF_INET6, | ||
663 | &pkt6->ip6_hdr.dadr, | ||
664 | pbuf, | ||
665 | sizeof (pbuf))); | ||
666 | } | ||
667 | break; | ||
668 | case 0x3a: | ||
669 | /* ICMPv6 */ | ||
670 | pkt6_icmp = (struct ip6_icmp *) pkt6; | ||
671 | /* If this packet is an icmp-echo-request and a mapping exists, answer */ | ||
672 | if (pkt6_icmp->icmp_hdr.type == 0x80 && | ||
673 | (key = address6_mapping_exists (&pkt6->ip6_hdr.dadr)) != NULL) | ||
674 | { | ||
675 | GNUNET_free (key); | ||
676 | pkt6_icmp = GNUNET_malloc (ntohs (pkt6->shdr.size)); | ||
677 | memcpy (pkt6_icmp, pkt6, ntohs (pkt6->shdr.size)); | ||
678 | GNUNET_SCHEDULER_add_now (&send_icmp6_response, pkt6_icmp); | ||
679 | } | ||
680 | break; | ||
681 | } | ||
682 | } | ||
683 | /* ethertype is ipv4 */ | ||
684 | else if (ntohs (pkt_tun->tun.type) == 0x0800) | ||
685 | { | ||
686 | struct ip_pkt *pkt = (struct ip_pkt *) message; | ||
687 | struct ip_udp *udp = (struct ip_udp *) message; | ||
688 | struct ip_tcp *pkt_tcp; | ||
689 | struct ip_udp *pkt_udp; | ||
690 | struct ip_icmp *pkt_icmp; | ||
691 | |||
692 | GNUNET_assert (pkt->ip_hdr.version == 4); | ||
693 | |||
694 | /* Send dns-packets to the service-dns */ | ||
695 | if (pkt->ip_hdr.proto == IPPROTO_UDP && ntohs (udp->udp_hdr.dpt) == 53) | ||
696 | { | ||
697 | GNUNET_DNS_queue_request_v4 (dns_handle, | ||
698 | &pkt->ip_hdr.dadr, | ||
699 | &pkt->ip_hdr.sadr, | ||
700 | ntohs (udp->udp_hdr.spt), | ||
701 | ntohs (udp->udp_hdr.len) - 8, | ||
702 | (const void*) udp->data); | ||
703 | } | ||
704 | else | ||
705 | { | ||
706 | uint32_t dadr = pkt->ip_hdr.dadr.s_addr; | ||
707 | unsigned char *c = (unsigned char *) &dadr; | ||
708 | |||
709 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Packet to %d.%d.%d.%d, proto %x\n", | ||
710 | c[0], c[1], c[2], c[3], pkt->ip_hdr.proto); | ||
711 | switch (pkt->ip_hdr.proto) | ||
712 | { | ||
713 | case IPPROTO_TCP: | ||
714 | case IPPROTO_UDP: | ||
715 | pkt_tcp = (struct ip_tcp *) pkt; | ||
716 | pkt_udp = (struct ip_udp *) pkt; | ||
717 | |||
718 | if ((key = address4_mapping_exists (dadr)) != NULL) | ||
719 | { | ||
720 | struct map_entry *me = | ||
721 | GNUNET_CONTAINER_multihashmap_get (hashmap, key); | ||
722 | GNUNET_assert (me != NULL); | ||
723 | GNUNET_free (key); | ||
724 | |||
725 | size_t size = | ||
726 | sizeof (struct GNUNET_MESH_Tunnel *) + | ||
727 | sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + | ||
728 | ntohs (pkt->ip_hdr.tot_lngth) - 4 * pkt->ip_hdr.hdr_lngth; | ||
729 | |||
730 | struct GNUNET_MESH_Tunnel **cls = GNUNET_malloc (size); | ||
731 | struct GNUNET_MessageHeader *hdr = | ||
732 | (struct GNUNET_MessageHeader *) (cls + 1); | ||
733 | GNUNET_HashCode *hc = (GNUNET_HashCode *) (hdr + 1); | ||
734 | |||
735 | hdr->size = | ||
736 | htons (sizeof (struct GNUNET_MessageHeader) + | ||
737 | sizeof (GNUNET_HashCode) + ntohs (pkt->ip_hdr.tot_lngth) - | ||
738 | 4 * pkt->ip_hdr.hdr_lngth); | ||
739 | |||
740 | GNUNET_MESH_ApplicationType app_type = 0; /* make compiler happy */ | ||
741 | |||
742 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "me->addrlen is %d\n", | ||
743 | me->addrlen); | ||
744 | if (me->addrlen == 0) | ||
745 | { | ||
746 | /* This is a mapping to a gnunet-service */ | ||
747 | memcpy (hc, &me->desc.service_descriptor, sizeof (GNUNET_HashCode)); | ||
748 | |||
749 | if ((IPPROTO_UDP == pkt->ip_hdr.proto) && | ||
750 | (me->desc.service_type & htonl (GNUNET_DNS_SERVICE_TYPE_UDP)) && | ||
751 | (port_in_ports (me->desc.ports, pkt_udp->udp_hdr.dpt) || | ||
752 | testBit (me->additional_ports, ntohs (pkt_udp->udp_hdr.dpt)))) | ||
753 | { | ||
754 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP); | ||
755 | |||
756 | memcpy (hc + 1, &pkt_udp->udp_hdr, ntohs (pkt_udp->udp_hdr.len)); | ||
757 | |||
758 | } | ||
759 | else if ((IPPROTO_TCP == pkt->ip_hdr.proto) && | ||
760 | (me-> | ||
761 | desc.service_type & htonl (GNUNET_DNS_SERVICE_TYPE_TCP)) | ||
762 | && (port_in_ports (me->desc.ports, pkt_tcp->tcp_hdr.dpt))) | ||
763 | { | ||
764 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP); | ||
765 | |||
766 | memcpy (hc + 1, &pkt_tcp->tcp_hdr, | ||
767 | ntohs (pkt->ip_hdr.tot_lngth) - | ||
768 | 4 * pkt->ip_hdr.hdr_lngth); | ||
769 | |||
770 | } | ||
771 | if (me->tunnel == NULL && NULL != cls) | ||
772 | { | ||
773 | *cls = | ||
774 | GNUNET_MESH_tunnel_create (mesh_handle, | ||
775 | initialize_tunnel_state (4, NULL), | ||
776 | send_pkt_to_peer, NULL, cls); | ||
777 | GNUNET_MESH_peer_request_connect_add (*cls, | ||
778 | (struct GNUNET_PeerIdentity | ||
779 | *) &me->desc.peer); | ||
780 | me->tunnel = *cls; | ||
781 | } | ||
782 | else if (NULL != cls) | ||
783 | { | ||
784 | *cls = me->tunnel; | ||
785 | send_pkt_to_peer (cls, (struct GNUNET_PeerIdentity *) 1, NULL); | ||
786 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
787 | "Queued to send IPv4 to peer %x, type %d\n", | ||
788 | *((unsigned int *) &me->desc.peer), | ||
789 | ntohs (hdr->type)); | ||
790 | } | ||
791 | } | ||
792 | else | ||
793 | { | ||
794 | /* This is a mapping to a "real" address */ | ||
795 | struct remote_addr *s = (struct remote_addr *) hc; | ||
796 | |||
797 | s->addrlen = me->addrlen; | ||
798 | memcpy (s->addr, me->addr, me->addrlen); | ||
799 | s->proto = pkt->ip_hdr.proto; | ||
800 | if (s->proto == IPPROTO_UDP) | ||
801 | { | ||
802 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP); | ||
803 | memcpy (hc + 1, &pkt_udp->udp_hdr, ntohs (pkt_udp->udp_hdr.len)); | ||
804 | app_type = GNUNET_APPLICATION_TYPE_INTERNET_UDP_GATEWAY; | ||
805 | } | ||
806 | else if (s->proto == IPPROTO_TCP) | ||
807 | { | ||
808 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP); | ||
809 | memcpy (hc + 1, &pkt_tcp->tcp_hdr, | ||
810 | ntohs (pkt->ip_hdr.tot_lngth) - | ||
811 | 4 * pkt->ip_hdr.hdr_lngth); | ||
812 | app_type = GNUNET_APPLICATION_TYPE_INTERNET_TCP_GATEWAY; | ||
813 | } | ||
814 | else | ||
815 | GNUNET_assert (0); | ||
816 | if (me->tunnel == NULL && NULL != cls) | ||
817 | { | ||
818 | *cls = | ||
819 | GNUNET_MESH_tunnel_create (mesh_handle, | ||
820 | initialize_tunnel_state (4, NULL), | ||
821 | send_pkt_to_peer, NULL, cls); | ||
822 | |||
823 | GNUNET_MESH_peer_request_connect_by_type (*cls, app_type); | ||
824 | me->tunnel = *cls; | ||
825 | } | ||
826 | else if (NULL != cls) | ||
827 | { | ||
828 | *cls = me->tunnel; | ||
829 | send_pkt_to_peer (cls, (struct GNUNET_PeerIdentity *) 1, NULL); | ||
830 | } | ||
831 | } | ||
832 | } | ||
833 | else | ||
834 | { | ||
835 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
836 | "Packet to %x which has no mapping\n", dadr); | ||
837 | } | ||
838 | break; | ||
839 | case 0x01: | ||
840 | /* ICMP */ | ||
841 | pkt_icmp = (struct ip_icmp *) pkt; | ||
842 | if (pkt_icmp->icmp_hdr.type == 0x8 && | ||
843 | (key = address4_mapping_exists (dadr)) != NULL) | ||
844 | { | ||
845 | GNUNET_free (key); | ||
846 | pkt_icmp = GNUNET_malloc (ntohs (pkt->shdr.size)); | ||
847 | memcpy (pkt_icmp, pkt, ntohs (pkt->shdr.size)); | ||
848 | GNUNET_SCHEDULER_add_now (&send_icmp4_response, pkt_icmp); | ||
849 | } | ||
850 | break; | ||
851 | } | ||
852 | } | ||
853 | } | ||
854 | } | ||
855 | |||
856 | |||
857 | |||
858 | static void | ||
859 | collect_mappings (void *cls GNUNET_UNUSED, | ||
860 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
861 | { | ||
862 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
863 | return; | ||
864 | |||
865 | struct map_entry *me = GNUNET_CONTAINER_heap_remove_root (heap); | ||
866 | |||
867 | /* This is free()ed memory! */ | ||
868 | me->heap_node = NULL; | ||
869 | |||
870 | /* FIXME! GNUNET_MESH_close_tunnel(me->tunnel); */ | ||
871 | |||
872 | GNUNET_assert (GNUNET_YES == | ||
873 | GNUNET_CONTAINER_multihashmap_remove (hashmap, &me->hash, me)); | ||
874 | |||
875 | GNUNET_free (me); | ||
876 | } | ||
877 | |||
878 | |||
879 | /** | ||
880 | * Create a new Address from an answer-packet | ||
881 | */ | ||
882 | static void | ||
883 | new_ip6addr (struct in6_addr *v6addr, | ||
884 | const GNUNET_HashCode * peer, | ||
885 | const GNUNET_HashCode * service_desc) | ||
886 | { /* {{{ */ | ||
887 | unsigned char *buf = (unsigned char*) v6addr; | ||
888 | char *ipv6addr; | ||
889 | unsigned long long ipv6prefix; | ||
890 | |||
891 | GNUNET_assert (GNUNET_OK == | ||
892 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR", | ||
893 | &ipv6addr)); | ||
894 | GNUNET_assert (GNUNET_OK == | ||
895 | GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", | ||
896 | "IPV6PREFIX", | ||
897 | &ipv6prefix)); | ||
898 | GNUNET_assert (ipv6prefix < 127); | ||
899 | ipv6prefix = (ipv6prefix + 7) / 8; | ||
900 | |||
901 | inet_pton (AF_INET6, ipv6addr, buf); | ||
902 | GNUNET_free (ipv6addr); | ||
903 | |||
904 | int peer_length = 16 - ipv6prefix - 6; | ||
905 | |||
906 | if (peer_length <= 0) | ||
907 | peer_length = 0; | ||
908 | |||
909 | int service_length = 16 - ipv6prefix - peer_length; | ||
910 | |||
911 | if (service_length <= 0) | ||
912 | service_length = 0; | ||
913 | |||
914 | memcpy (buf + ipv6prefix, service_desc, service_length); | ||
915 | memcpy (buf + ipv6prefix + service_length, peer, peer_length); | ||
916 | } | ||
917 | |||
918 | /*}}}*/ | ||
919 | |||
920 | |||
921 | /** | ||
922 | * Create a new Address from an answer-packet | ||
923 | */ | ||
924 | static void | ||
925 | new_ip6addr_remote (struct in6_addr *v6addr, | ||
926 | unsigned char *addr, char addrlen) | ||
927 | { /* {{{ */ | ||
928 | unsigned char *buf = (unsigned char*) v6addr; | ||
929 | char *ipv6addr; | ||
930 | unsigned long long ipv6prefix; | ||
931 | |||
932 | GNUNET_assert (GNUNET_OK == | ||
933 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR", | ||
934 | &ipv6addr)); | ||
935 | GNUNET_assert (GNUNET_OK == | ||
936 | GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", | ||
937 | "IPV6PREFIX", | ||
938 | &ipv6prefix)); | ||
939 | GNUNET_assert (ipv6prefix < 127); | ||
940 | ipv6prefix = (ipv6prefix + 7) / 8; | ||
941 | |||
942 | inet_pton (AF_INET6, ipv6addr, buf); | ||
943 | GNUNET_free (ipv6addr); | ||
944 | |||
945 | int local_length = 16 - ipv6prefix; | ||
946 | |||
947 | memcpy (buf + ipv6prefix, addr, GNUNET_MIN (addrlen, local_length)); | ||
948 | } | ||
949 | |||
950 | /*}}}*/ | ||
951 | |||
952 | /** | ||
953 | * Create a new Address from an answer-packet | ||
954 | */ | ||
955 | static void | ||
956 | new_ip4addr_remote (unsigned char *buf, unsigned char *addr, char addrlen) | ||
957 | { /* {{{ */ | ||
958 | char *ipv4addr; | ||
959 | char *ipv4mask; | ||
960 | |||
961 | GNUNET_assert (GNUNET_OK == | ||
962 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR", | ||
963 | &ipv4addr)); | ||
964 | GNUNET_assert (GNUNET_OK == | ||
965 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK", | ||
966 | &ipv4mask)); | ||
967 | uint32_t mask; | ||
968 | |||
969 | inet_pton (AF_INET, ipv4addr, buf); | ||
970 | int r = inet_pton (AF_INET, ipv4mask, &mask); | ||
971 | |||
972 | mask = htonl (mask); | ||
973 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "inet_pton: %d; %m; mask: %08x\n", r, | ||
974 | mask); | ||
975 | |||
976 | GNUNET_free (ipv4addr); | ||
977 | |||
978 | int c; | ||
979 | |||
980 | if (mask) | ||
981 | { | ||
982 | mask = (mask ^ (mask - 1)) >> 1; | ||
983 | for (c = 0; mask; c++) | ||
984 | { | ||
985 | mask >>= 1; | ||
986 | } | ||
987 | } | ||
988 | else | ||
989 | { | ||
990 | c = CHAR_BIT * sizeof (mask); | ||
991 | } | ||
992 | |||
993 | c = 32 - c; | ||
994 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "The mask %s has %d leading 1s.\n", | ||
995 | ipv4mask, c); | ||
996 | |||
997 | GNUNET_free (ipv4mask); | ||
998 | |||
999 | if (c % 8 == 0) | ||
1000 | c = c / 8; | ||
1001 | else | ||
1002 | GNUNET_assert (0); | ||
1003 | |||
1004 | memcpy (buf + c, addr, GNUNET_MIN (addrlen, 4 - c)); | ||
1005 | } | ||
1006 | |||
1007 | /*}}}*/ | ||
1008 | |||
1009 | /** | ||
1010 | * This gets scheduled with cls pointing to an answer_packet and does everything | ||
1011 | * needed in order to send it to the helper. | ||
1012 | * | ||
1013 | * At the moment this means "inventing" and IPv6-Address for .gnunet-services and | ||
1014 | * doing nothing for "real" services. | ||
1015 | */ | ||
1016 | static void | ||
1017 | process_answer (void *cls, | ||
1018 | const struct answer_packet *pkt) | ||
1019 | { | ||
1020 | struct answer_packet_list *list; | ||
1021 | |||
1022 | /* This answer is about a .gnunet-service | ||
1023 | * | ||
1024 | * It contains an almost complete DNS-Response, we have to fill in the ip | ||
1025 | * at the offset pkt->addroffset | ||
1026 | */ | ||
1027 | if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_SERVICE) | ||
1028 | { | ||
1029 | |||
1030 | GNUNET_HashCode key; | ||
1031 | |||
1032 | memset (&key, 0, sizeof (GNUNET_HashCode)); | ||
1033 | |||
1034 | list = | ||
1035 | GNUNET_malloc (htons (pkt->hdr.size) + | ||
1036 | sizeof (struct answer_packet_list) - | ||
1037 | sizeof (struct answer_packet)); | ||
1038 | memcpy (&list->pkt, pkt, htons (pkt->hdr.size)); | ||
1039 | |||
1040 | unsigned char *c = ((unsigned char *) &list->pkt) + ntohs (pkt->addroffset); | ||
1041 | unsigned char *k = (unsigned char *) &key; | ||
1042 | |||
1043 | new_ip6addr ((struct in6_addr*) c, | ||
1044 | &pkt->service_descr.peer, | ||
1045 | &pkt->service_descr.service_descriptor); | ||
1046 | /* | ||
1047 | * Copy the newly generated ip-address to the key backwarts (as only the first part is hashed) | ||
1048 | */ | ||
1049 | unsigned int i; | ||
1050 | |||
1051 | for (i = 0; i < 16; i++) | ||
1052 | k[15 - i] = c[i]; | ||
1053 | |||
1054 | uint16_t namelen = strlen ((char *) pkt->data + 12) + 1; | ||
1055 | |||
1056 | struct map_entry *value = | ||
1057 | GNUNET_malloc (sizeof (struct map_entry) + namelen); | ||
1058 | char *name = (char *) (value + 1); | ||
1059 | |||
1060 | value->namelen = namelen; | ||
1061 | memcpy (name, pkt->data + 12, namelen); | ||
1062 | |||
1063 | memcpy (&value->desc, &pkt->service_descr, | ||
1064 | sizeof (struct GNUNET_vpn_service_descriptor)); | ||
1065 | |||
1066 | memset (value->additional_ports, 0, 8192); | ||
1067 | |||
1068 | memcpy (&value->hash, &key, sizeof (GNUNET_HashCode)); | ||
1069 | |||
1070 | if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (hashmap, &key)) | ||
1071 | { | ||
1072 | GNUNET_CONTAINER_multihashmap_put (hashmap, &key, value, | ||
1073 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1074 | |||
1075 | value->heap_node = | ||
1076 | GNUNET_CONTAINER_heap_insert (heap, value, | ||
1077 | GNUNET_TIME_absolute_get ().abs_value); | ||
1078 | if (GNUNET_CONTAINER_heap_get_size (heap) > max_mappings) | ||
1079 | GNUNET_SCHEDULER_add_now (collect_mappings, NULL); | ||
1080 | } | ||
1081 | else | ||
1082 | GNUNET_free (value); | ||
1083 | |||
1084 | |||
1085 | list->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_IP; | ||
1086 | |||
1087 | |||
1088 | } | ||
1089 | else if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_REV) | ||
1090 | { | ||
1091 | GNUNET_HashCode key; | ||
1092 | |||
1093 | memset (&key, 0, sizeof key); | ||
1094 | unsigned char *k = (unsigned char *) &key; | ||
1095 | const unsigned char *s = pkt->data + 12; | ||
1096 | int i = 0; | ||
1097 | |||
1098 | /* Whoever designed the reverse IPv6-lookup is batshit insane */ | ||
1099 | for (i = 0; i < 16; i++) | ||
1100 | { | ||
1101 | unsigned char c1 = s[(4 * i) + 1]; | ||
1102 | unsigned char c2 = s[(4 * i) + 3]; | ||
1103 | |||
1104 | if (c1 <= '9') | ||
1105 | k[i] = c1 - '0'; | ||
1106 | else | ||
1107 | k[i] = c1 - 87; /* 87 is the difference between 'a' and 10 */ | ||
1108 | if (c2 <= '9') | ||
1109 | k[i] += 16 * (c2 - '0'); | ||
1110 | else | ||
1111 | k[i] += 16 * (c2 - 87); | ||
1112 | } | ||
1113 | |||
1114 | struct map_entry *map_entry = | ||
1115 | GNUNET_CONTAINER_multihashmap_get (hashmap, &key); | ||
1116 | uint16_t offset = ntohs (pkt->addroffset); | ||
1117 | |||
1118 | if (map_entry == NULL) | ||
1119 | return; | ||
1120 | |||
1121 | GNUNET_CONTAINER_heap_update_cost (heap, map_entry->heap_node, | ||
1122 | GNUNET_TIME_absolute_get ().abs_value); | ||
1123 | |||
1124 | |||
1125 | unsigned short namelen = htons (map_entry->namelen); | ||
1126 | char *name = (char *) (map_entry + 1); | ||
1127 | |||
1128 | list = | ||
1129 | GNUNET_malloc (sizeof (struct answer_packet_list) - | ||
1130 | sizeof (struct answer_packet) + offset + 2 + | ||
1131 | ntohs (namelen)); | ||
1132 | |||
1133 | struct answer_packet *rpkt = &list->pkt; | ||
1134 | |||
1135 | /* The offset points to the first byte belonging to the address */ | ||
1136 | memcpy (rpkt, pkt, offset - 1); | ||
1137 | |||
1138 | rpkt->subtype = GNUNET_DNS_ANSWER_TYPE_IP; | ||
1139 | rpkt->hdr.size = ntohs (offset + 2 + ntohs (namelen)); | ||
1140 | |||
1141 | memcpy (((char *) rpkt) + offset, &namelen, 2); | ||
1142 | memcpy (((char *) rpkt) + offset + 2, name, ntohs (namelen)); | ||
1143 | |||
1144 | } | ||
1145 | else if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_IP) | ||
1146 | { | ||
1147 | list = | ||
1148 | GNUNET_malloc (htons (pkt->hdr.size) + | ||
1149 | sizeof (struct answer_packet_list) - | ||
1150 | sizeof (struct answer_packet)); | ||
1151 | memcpy (&list->pkt, pkt, htons (pkt->hdr.size)); | ||
1152 | } | ||
1153 | else if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_REMOTE_AAAA) | ||
1154 | { | ||
1155 | |||
1156 | GNUNET_HashCode key; | ||
1157 | |||
1158 | memset (&key, 0, sizeof (GNUNET_HashCode)); | ||
1159 | |||
1160 | list = | ||
1161 | GNUNET_malloc (htons (pkt->hdr.size) + | ||
1162 | sizeof (struct answer_packet_list) - | ||
1163 | sizeof (struct answer_packet)); | ||
1164 | |||
1165 | memcpy (&list->pkt, pkt, htons (pkt->hdr.size)); | ||
1166 | list->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_IP; | ||
1167 | |||
1168 | unsigned char *c = ((unsigned char *) &list->pkt) + ntohs (list->pkt.addroffset); | ||
1169 | |||
1170 | new_ip6addr_remote ((struct in6_addr*) c, | ||
1171 | list->pkt.addr, list->pkt.addrsize); | ||
1172 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1173 | "New mapping to %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", | ||
1174 | c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], | ||
1175 | c[10], c[11], c[12], c[13], c[14], c[15]); | ||
1176 | unsigned char *k = (unsigned char *) &key; | ||
1177 | |||
1178 | /* | ||
1179 | * Copy the newly generated ip-address to the key backwards (as only the first part is used in the hash-table) | ||
1180 | */ | ||
1181 | unsigned int i; | ||
1182 | |||
1183 | for (i = 0; i < 16; i++) | ||
1184 | k[15 - i] = c[i]; | ||
1185 | |||
1186 | uint16_t namelen = strlen ((char *) pkt->data + 12) + 1; | ||
1187 | |||
1188 | struct map_entry *value = | ||
1189 | GNUNET_malloc (sizeof (struct map_entry) + namelen); | ||
1190 | char *name = (char *) (value + 1); | ||
1191 | |||
1192 | value->namelen = namelen; | ||
1193 | memcpy (name, pkt->data + 12, namelen); | ||
1194 | |||
1195 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting addrlen to %d\n", | ||
1196 | pkt->addrsize); | ||
1197 | value->addrlen = pkt->addrsize; | ||
1198 | memcpy (&value->addr, &pkt->addr, pkt->addrsize); | ||
1199 | memset (value->additional_ports, 0, 8192); | ||
1200 | |||
1201 | memcpy (&value->hash, &key, sizeof (GNUNET_HashCode)); | ||
1202 | |||
1203 | if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (hashmap, &key)) | ||
1204 | { | ||
1205 | GNUNET_CONTAINER_multihashmap_put (hashmap, &key, value, | ||
1206 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1207 | value->heap_node = | ||
1208 | GNUNET_CONTAINER_heap_insert (heap, value, | ||
1209 | GNUNET_TIME_absolute_get ().abs_value); | ||
1210 | if (GNUNET_CONTAINER_heap_get_size (heap) > max_mappings) | ||
1211 | GNUNET_SCHEDULER_add_now (collect_mappings, NULL); | ||
1212 | } | ||
1213 | else | ||
1214 | GNUNET_free (value); | ||
1215 | |||
1216 | |||
1217 | } | ||
1218 | else if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_REMOTE_A) | ||
1219 | { | ||
1220 | list = | ||
1221 | GNUNET_malloc (htons (pkt->hdr.size) + | ||
1222 | sizeof (struct answer_packet_list) - | ||
1223 | sizeof (struct answer_packet)); | ||
1224 | |||
1225 | memcpy (&list->pkt, pkt, htons (pkt->hdr.size)); | ||
1226 | list->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_IP; | ||
1227 | |||
1228 | GNUNET_HashCode key; | ||
1229 | |||
1230 | memset (&key, 0, sizeof (GNUNET_HashCode)); | ||
1231 | |||
1232 | unsigned char *c = ((unsigned char *) &list->pkt) + ntohs (pkt->addroffset); | ||
1233 | |||
1234 | new_ip4addr_remote (c, list->pkt.addr, pkt->addrsize); | ||
1235 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New mapping to %d.%d.%d.%d\n", c[0], | ||
1236 | c[1], c[2], c[3]); | ||
1237 | unsigned char *k = (unsigned char *) &key; | ||
1238 | |||
1239 | /* | ||
1240 | * Copy the newly generated ip-address to the key backwards (as only the first part is used in the hash-table) | ||
1241 | */ | ||
1242 | unsigned int i; | ||
1243 | |||
1244 | for (i = 0; i < 4; i++) | ||
1245 | k[3 - i] = c[i]; | ||
1246 | |||
1247 | uint16_t namelen = strlen ((char *) pkt->data + 12) + 1; | ||
1248 | |||
1249 | struct map_entry *value = | ||
1250 | GNUNET_malloc (sizeof (struct map_entry) + namelen); | ||
1251 | char *name = (char *) (value + 1); | ||
1252 | |||
1253 | value->namelen = namelen; | ||
1254 | memcpy (name, pkt->data + 12, namelen); | ||
1255 | |||
1256 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting addrlen to %d\n", | ||
1257 | pkt->addrsize); | ||
1258 | value->addrlen = pkt->addrsize; | ||
1259 | memcpy (&value->addr, &pkt->addr, pkt->addrsize); | ||
1260 | memset (value->additional_ports, 0, 8192); | ||
1261 | |||
1262 | memcpy (&value->hash, &key, sizeof (GNUNET_HashCode)); | ||
1263 | |||
1264 | if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (hashmap, &key)) | ||
1265 | { | ||
1266 | GNUNET_CONTAINER_multihashmap_put (hashmap, &key, value, | ||
1267 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1268 | value->heap_node = | ||
1269 | GNUNET_CONTAINER_heap_insert (heap, value, | ||
1270 | GNUNET_TIME_absolute_get ().abs_value); | ||
1271 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1272 | "Mapping is saved in the hashmap with key %08x.\n", | ||
1273 | *((uint32_t *) (&key))); | ||
1274 | if (GNUNET_CONTAINER_heap_get_size (heap) > max_mappings) | ||
1275 | GNUNET_SCHEDULER_add_now (collect_mappings, NULL); | ||
1276 | } | ||
1277 | else | ||
1278 | GNUNET_free (value); | ||
1279 | |||
1280 | } | ||
1281 | else | ||
1282 | { | ||
1283 | GNUNET_break (0); | ||
1284 | return; | ||
1285 | } | ||
1286 | |||
1287 | GNUNET_CONTAINER_DLL_insert_after (answer_proc_head, answer_proc_tail, | ||
1288 | answer_proc_tail, list); | ||
1289 | |||
1290 | } | ||
1291 | |||
1292 | |||
1293 | /** | ||
1294 | * @brief Add the port to the list of additional ports in the map_entry | ||
1295 | * | ||
1296 | * @param me the map_entry | ||
1297 | * @param port the port in host-byte-order | ||
1298 | */ | ||
1299 | static void | ||
1300 | add_additional_port (struct map_entry *me, uint16_t port) | ||
1301 | { | ||
1302 | setBit (me->additional_ports, port); | ||
1303 | } | ||
1304 | |||
1305 | static int | ||
1306 | receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
1307 | void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, | ||
1308 | const struct GNUNET_MessageHeader *message, | ||
1309 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
1310 | { | ||
1311 | GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); | ||
1312 | struct remote_addr *s = (struct remote_addr *) desc; | ||
1313 | struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1); | ||
1314 | const struct GNUNET_PeerIdentity *other = sender; | ||
1315 | struct tunnel_state *ts = *tunnel_ctx; | ||
1316 | |||
1317 | if (16 == ts->addrlen) | ||
1318 | { | ||
1319 | size_t size = | ||
1320 | sizeof (struct ip6_udp) + ntohs (pkt->len) - 1 - | ||
1321 | sizeof (struct udp_pkt); | ||
1322 | |||
1323 | struct ip6_udp *pkt6 = alloca (size); | ||
1324 | |||
1325 | GNUNET_assert (pkt6 != NULL); | ||
1326 | |||
1327 | if (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK) | ||
1328 | new_ip6addr (&pkt6->ip6_hdr.sadr, &other->hashPubKey, desc); | ||
1329 | else | ||
1330 | new_ip6addr_remote (&pkt6->ip6_hdr.sadr, s->addr, s->addrlen); | ||
1331 | |||
1332 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1333 | "Relaying calc:%d gnu:%d udp:%d bytes!\n", size, | ||
1334 | ntohs (message->size), ntohs (pkt->len)); | ||
1335 | |||
1336 | pkt6->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
1337 | pkt6->shdr.size = htons (size); | ||
1338 | |||
1339 | pkt6->tun.flags = 0; | ||
1340 | pkt6->tun.type = htons (0x86dd); | ||
1341 | |||
1342 | pkt6->ip6_hdr.version = 6; | ||
1343 | pkt6->ip6_hdr.tclass_h = 0; | ||
1344 | pkt6->ip6_hdr.tclass_l = 0; | ||
1345 | pkt6->ip6_hdr.flowlbl = 0; | ||
1346 | pkt6->ip6_hdr.paylgth = pkt->len; | ||
1347 | pkt6->ip6_hdr.nxthdr = IPPROTO_UDP; | ||
1348 | pkt6->ip6_hdr.hoplmt = 0xff; | ||
1349 | |||
1350 | { | ||
1351 | char *ipv6addr; | ||
1352 | |||
1353 | GNUNET_assert (GNUNET_OK == | ||
1354 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", | ||
1355 | "IPV6ADDR", | ||
1356 | &ipv6addr)); | ||
1357 | inet_pton (AF_INET6, ipv6addr, &pkt6->ip6_hdr.dadr); | ||
1358 | GNUNET_free (ipv6addr); | ||
1359 | } | ||
1360 | memcpy (&pkt6->udp_hdr, pkt, ntohs (pkt->len)); | ||
1361 | |||
1362 | GNUNET_HashCode *key = address6_mapping_exists (&pkt6->ip6_hdr.sadr); | ||
1363 | |||
1364 | GNUNET_assert (key != NULL); | ||
1365 | |||
1366 | struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); | ||
1367 | |||
1368 | GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node, | ||
1369 | GNUNET_TIME_absolute_get ().abs_value); | ||
1370 | |||
1371 | GNUNET_free (key); | ||
1372 | |||
1373 | GNUNET_assert (me != NULL); | ||
1374 | if (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK) | ||
1375 | { | ||
1376 | GNUNET_assert (me->desc. | ||
1377 | service_type & htonl (GNUNET_DNS_SERVICE_TYPE_UDP)); | ||
1378 | if (!port_in_ports (me->desc.ports, pkt6->udp_hdr.spt) && | ||
1379 | !testBit (me->additional_ports, ntohs (pkt6->udp_hdr.spt))) | ||
1380 | { | ||
1381 | add_additional_port (me, ntohs (pkt6->udp_hdr.spt)); | ||
1382 | } | ||
1383 | } | ||
1384 | |||
1385 | pkt6->udp_hdr.crc = 0; | ||
1386 | uint32_t sum = 0; | ||
1387 | |||
1388 | sum = | ||
1389 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->ip6_hdr.sadr, 16); | ||
1390 | sum = | ||
1391 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->ip6_hdr.dadr, 16); | ||
1392 | uint32_t tmp = (pkt6->udp_hdr.len & 0xffff); | ||
1393 | |||
1394 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
1395 | tmp = htons (((pkt6->ip6_hdr.nxthdr & 0x00ff))); | ||
1396 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
1397 | |||
1398 | sum = | ||
1399 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->udp_hdr, | ||
1400 | ntohs (pkt->len)); | ||
1401 | pkt6->udp_hdr.crc = GNUNET_CRYPTO_crc16_finish (sum); | ||
1402 | |||
1403 | (void) GNUNET_HELPER_send (helper_handle, | ||
1404 | &pkt6->shdr, | ||
1405 | GNUNET_YES, | ||
1406 | NULL, NULL); | ||
1407 | } | ||
1408 | else | ||
1409 | { | ||
1410 | size_t size = | ||
1411 | sizeof (struct ip_udp) + ntohs (pkt->len) - 1 - sizeof (struct udp_pkt); | ||
1412 | |||
1413 | struct ip_udp *pkt4 = alloca (size); | ||
1414 | |||
1415 | GNUNET_assert (pkt4 != NULL); | ||
1416 | |||
1417 | GNUNET_assert (ntohs (message->type) == | ||
1418 | GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP_BACK); | ||
1419 | uint32_t sadr; | ||
1420 | |||
1421 | new_ip4addr_remote ((unsigned char *) &sadr, s->addr, s->addrlen); | ||
1422 | pkt4->ip_hdr.sadr.s_addr = sadr; | ||
1423 | |||
1424 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1425 | "Relaying calc:%d gnu:%d udp:%d bytes!\n", size, | ||
1426 | ntohs (message->size), ntohs (pkt->len)); | ||
1427 | |||
1428 | pkt4->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
1429 | pkt4->shdr.size = htons (size); | ||
1430 | |||
1431 | pkt4->tun.flags = 0; | ||
1432 | pkt4->tun.type = htons (0x0800); | ||
1433 | |||
1434 | pkt4->ip_hdr.version = 4; | ||
1435 | pkt4->ip_hdr.hdr_lngth = 5; | ||
1436 | pkt4->ip_hdr.diff_serv = 0; | ||
1437 | pkt4->ip_hdr.tot_lngth = htons (20 + ntohs (pkt->len)); | ||
1438 | pkt4->ip_hdr.ident = 0; | ||
1439 | pkt4->ip_hdr.flags = 0; | ||
1440 | pkt4->ip_hdr.frag_off = 0; | ||
1441 | pkt4->ip_hdr.ttl = 255; | ||
1442 | pkt4->ip_hdr.proto = IPPROTO_UDP; | ||
1443 | pkt4->ip_hdr.chks = 0; /* Will be calculated later */ | ||
1444 | |||
1445 | { | ||
1446 | char *ipv4addr; | ||
1447 | uint32_t dadr; | ||
1448 | |||
1449 | GNUNET_assert (GNUNET_OK == | ||
1450 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", | ||
1451 | "IPV4ADDR", | ||
1452 | &ipv4addr)); | ||
1453 | inet_pton (AF_INET, ipv4addr, &dadr); | ||
1454 | GNUNET_free (ipv4addr); | ||
1455 | pkt4->ip_hdr.dadr.s_addr = dadr; | ||
1456 | } | ||
1457 | memcpy (&pkt4->udp_hdr, pkt, ntohs (pkt->len)); | ||
1458 | |||
1459 | GNUNET_HashCode *key = address4_mapping_exists (pkt4->ip_hdr.sadr.s_addr); | ||
1460 | |||
1461 | GNUNET_assert (key != NULL); | ||
1462 | |||
1463 | struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); | ||
1464 | |||
1465 | GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node, | ||
1466 | GNUNET_TIME_absolute_get ().abs_value); | ||
1467 | |||
1468 | GNUNET_free (key); | ||
1469 | |||
1470 | GNUNET_assert (me != NULL); | ||
1471 | |||
1472 | pkt4->udp_hdr.crc = 0; /* Optional for IPv4 */ | ||
1473 | |||
1474 | pkt4->ip_hdr.chks = | ||
1475 | GNUNET_CRYPTO_crc16_n ((uint16_t *) & pkt4->ip_hdr, 5 * 4); | ||
1476 | |||
1477 | (void) GNUNET_HELPER_send (helper_handle, | ||
1478 | &pkt4->shdr, | ||
1479 | GNUNET_YES, | ||
1480 | NULL, NULL); | ||
1481 | } | ||
1482 | |||
1483 | return GNUNET_OK; | ||
1484 | } | ||
1485 | |||
1486 | static int | ||
1487 | receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
1488 | void **tunnel_ctx, | ||
1489 | const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, | ||
1490 | const struct GNUNET_MessageHeader *message, | ||
1491 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
1492 | { | ||
1493 | GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); | ||
1494 | struct remote_addr *s = (struct remote_addr *) desc; | ||
1495 | struct tcp_pkt *pkt = (struct tcp_pkt *) (desc + 1); | ||
1496 | const struct GNUNET_PeerIdentity *other = sender; | ||
1497 | struct tunnel_state *ts = *tunnel_ctx; | ||
1498 | |||
1499 | size_t pktlen = | ||
1500 | ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - | ||
1501 | sizeof (GNUNET_HashCode); | ||
1502 | |||
1503 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1504 | "Received TCP-Packet back, addrlen = %d\n", s->addrlen); | ||
1505 | |||
1506 | if (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK || | ||
1507 | ts->addrlen == 16) | ||
1508 | { | ||
1509 | size_t size = pktlen + sizeof (struct ip6_tcp) - 1; | ||
1510 | |||
1511 | struct ip6_tcp *pkt6 = alloca (size); | ||
1512 | |||
1513 | memset (pkt6, 0, size); | ||
1514 | |||
1515 | GNUNET_assert (pkt6 != NULL); | ||
1516 | |||
1517 | if (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK) | ||
1518 | new_ip6addr (&pkt6->ip6_hdr.sadr, &other->hashPubKey, desc); | ||
1519 | else | ||
1520 | new_ip6addr_remote (&pkt6->ip6_hdr.sadr, s->addr, s->addrlen); | ||
1521 | |||
1522 | pkt6->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
1523 | pkt6->shdr.size = htons (size); | ||
1524 | |||
1525 | pkt6->tun.flags = 0; | ||
1526 | pkt6->tun.type = htons (0x86dd); | ||
1527 | |||
1528 | pkt6->ip6_hdr.version = 6; | ||
1529 | pkt6->ip6_hdr.tclass_h = 0; | ||
1530 | pkt6->ip6_hdr.tclass_l = 0; | ||
1531 | pkt6->ip6_hdr.flowlbl = 0; | ||
1532 | pkt6->ip6_hdr.paylgth = htons (pktlen); | ||
1533 | pkt6->ip6_hdr.nxthdr = IPPROTO_TCP; | ||
1534 | pkt6->ip6_hdr.hoplmt = 0xff; | ||
1535 | |||
1536 | { | ||
1537 | char *ipv6addr; | ||
1538 | |||
1539 | GNUNET_assert (GNUNET_OK == | ||
1540 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", | ||
1541 | "IPV6ADDR", | ||
1542 | &ipv6addr)); | ||
1543 | inet_pton (AF_INET6, ipv6addr, &pkt6->ip6_hdr.dadr); | ||
1544 | GNUNET_free (ipv6addr); | ||
1545 | } | ||
1546 | memcpy (&pkt6->tcp_hdr, pkt, pktlen); | ||
1547 | |||
1548 | GNUNET_HashCode *key = address6_mapping_exists (&pkt6->ip6_hdr.sadr); | ||
1549 | |||
1550 | GNUNET_assert (key != NULL); | ||
1551 | |||
1552 | struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); | ||
1553 | |||
1554 | GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node, | ||
1555 | GNUNET_TIME_absolute_get ().abs_value); | ||
1556 | |||
1557 | GNUNET_free (key); | ||
1558 | |||
1559 | GNUNET_assert (me != NULL); | ||
1560 | if (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK) | ||
1561 | GNUNET_assert (me->desc. | ||
1562 | service_type & htonl (GNUNET_DNS_SERVICE_TYPE_TCP)); | ||
1563 | |||
1564 | pkt6->tcp_hdr.crc = 0; | ||
1565 | uint32_t sum = 0; | ||
1566 | uint32_t tmp; | ||
1567 | |||
1568 | sum = | ||
1569 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->ip6_hdr.sadr, 16); | ||
1570 | sum = | ||
1571 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->ip6_hdr.dadr, 16); | ||
1572 | tmp = htonl (pktlen); | ||
1573 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
1574 | tmp = htonl (((pkt6->ip6_hdr.nxthdr & 0x000000ff))); | ||
1575 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
1576 | |||
1577 | sum = | ||
1578 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->tcp_hdr, | ||
1579 | ntohs (pkt6->ip6_hdr.paylgth)); | ||
1580 | pkt6->tcp_hdr.crc = GNUNET_CRYPTO_crc16_finish (sum); | ||
1581 | |||
1582 | (void) GNUNET_HELPER_send (helper_handle, | ||
1583 | &pkt6->shdr, | ||
1584 | GNUNET_YES, | ||
1585 | NULL, NULL); | ||
1586 | } | ||
1587 | else | ||
1588 | { | ||
1589 | size_t size = pktlen + sizeof (struct ip_tcp) - 1; | ||
1590 | |||
1591 | struct ip_tcp *pkt4 = alloca (size); | ||
1592 | |||
1593 | GNUNET_assert (pkt4 != NULL); | ||
1594 | memset (pkt4, 0, size); | ||
1595 | |||
1596 | GNUNET_assert (ntohs (message->type) == | ||
1597 | GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP_BACK); | ||
1598 | uint32_t sadr; | ||
1599 | |||
1600 | new_ip4addr_remote ((unsigned char *) &sadr, s->addr, s->addrlen); | ||
1601 | pkt4->ip_hdr.sadr.s_addr = sadr; | ||
1602 | |||
1603 | pkt4->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
1604 | pkt4->shdr.size = htons (size); | ||
1605 | |||
1606 | pkt4->tun.flags = 0; | ||
1607 | pkt4->tun.type = htons (0x0800); | ||
1608 | |||
1609 | pkt4->ip_hdr.version = 4; | ||
1610 | pkt4->ip_hdr.hdr_lngth = 5; | ||
1611 | pkt4->ip_hdr.diff_serv = 0; | ||
1612 | pkt4->ip_hdr.tot_lngth = htons (20 + pktlen); | ||
1613 | pkt4->ip_hdr.ident = 0; | ||
1614 | pkt4->ip_hdr.flags = 0; | ||
1615 | pkt4->ip_hdr.frag_off = 0; | ||
1616 | pkt4->ip_hdr.ttl = 255; | ||
1617 | pkt4->ip_hdr.proto = IPPROTO_TCP; | ||
1618 | pkt4->ip_hdr.chks = 0; /* Will be calculated later */ | ||
1619 | |||
1620 | { | ||
1621 | char *ipv4addr; | ||
1622 | uint32_t dadr; | ||
1623 | |||
1624 | GNUNET_assert (GNUNET_OK == | ||
1625 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", | ||
1626 | "IPV4ADDR", | ||
1627 | &ipv4addr)); | ||
1628 | inet_pton (AF_INET, ipv4addr, &dadr); | ||
1629 | GNUNET_free (ipv4addr); | ||
1630 | pkt4->ip_hdr.dadr.s_addr = dadr; | ||
1631 | } | ||
1632 | |||
1633 | memcpy (&pkt4->tcp_hdr, pkt, pktlen); | ||
1634 | |||
1635 | GNUNET_HashCode *key = address4_mapping_exists (pkt4->ip_hdr.sadr.s_addr); | ||
1636 | |||
1637 | GNUNET_assert (key != NULL); | ||
1638 | |||
1639 | struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); | ||
1640 | |||
1641 | GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node, | ||
1642 | GNUNET_TIME_absolute_get ().abs_value); | ||
1643 | |||
1644 | GNUNET_free (key); | ||
1645 | |||
1646 | GNUNET_assert (me != NULL); | ||
1647 | pkt4->tcp_hdr.crc = 0; | ||
1648 | uint32_t sum = 0; | ||
1649 | uint32_t tmp; | ||
1650 | |||
1651 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) &pkt4->ip_hdr.sadr, 4); | ||
1652 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) &pkt4->ip_hdr.dadr, 4); | ||
1653 | |||
1654 | tmp = (0x06 << 16) | (0xffff & pktlen); // 0x06 for TCP? | ||
1655 | |||
1656 | tmp = htonl (tmp); | ||
1657 | |||
1658 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
1659 | |||
1660 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt4->tcp_hdr, pktlen); | ||
1661 | pkt4->tcp_hdr.crc = GNUNET_CRYPTO_crc16_finish (sum); | ||
1662 | |||
1663 | pkt4->ip_hdr.chks = | ||
1664 | GNUNET_CRYPTO_crc16_n ((uint16_t *) & pkt4->ip_hdr, 5 * 4); | ||
1665 | |||
1666 | (void) GNUNET_HELPER_send (helper_handle, | ||
1667 | &pkt4->shdr, | ||
1668 | GNUNET_YES, | ||
1669 | NULL, NULL); | ||
1670 | |||
1671 | } | ||
1672 | |||
1673 | return GNUNET_OK; | ||
1674 | } | ||
1675 | |||
1676 | static void * | ||
1677 | new_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel, | ||
1678 | const struct GNUNET_PeerIdentity *initiator, | ||
1679 | const struct GNUNET_ATS_Information *atsi) | ||
1680 | { | ||
1681 | /* Why should anyone open an inbound tunnel to vpn? */ | ||
1682 | GNUNET_break (0); | ||
1683 | return NULL; | ||
1684 | } | ||
1685 | |||
1686 | static void | ||
1687 | cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx) | ||
1688 | { | ||
1689 | /* Why should anyone open an inbound tunnel to vpn? */ | ||
1690 | GNUNET_break (0); | ||
1691 | } | ||
1692 | |||
1693 | /** | ||
1694 | * Main function that will be run by the scheduler. | ||
1695 | * | ||
1696 | * @param cls closure | ||
1697 | * @param args remaining command-line arguments | ||
1698 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
1699 | * @param cfg_ configuration | ||
1700 | */ | ||
1701 | static void | ||
1702 | run (void *cls, char *const *args GNUNET_UNUSED, | ||
1703 | const char *cfgfile GNUNET_UNUSED, | ||
1704 | const struct GNUNET_CONFIGURATION_Handle *cfg_) | ||
1705 | { | ||
1706 | static const struct GNUNET_MESH_MessageHandler handlers[] = { | ||
1707 | {receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK, 0}, | ||
1708 | {receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK, 0}, | ||
1709 | {receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP_BACK, 0}, | ||
1710 | {receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP_BACK, 0}, | ||
1711 | {NULL, 0, 0} | ||
1712 | }; | ||
1713 | static const GNUNET_MESH_ApplicationType types[] = { | ||
1714 | GNUNET_APPLICATION_TYPE_END | ||
1715 | }; | ||
1716 | char *ifname; | ||
1717 | char *ipv6addr; | ||
1718 | char *ipv6prefix; | ||
1719 | char *ipv4addr; | ||
1720 | char *ipv4mask; | ||
1721 | |||
1722 | mesh_handle = | ||
1723 | GNUNET_MESH_connect (cfg_, 42, NULL, new_tunnel, cleaner, handlers, | ||
1724 | types); | ||
1725 | cfg = cfg_; | ||
1726 | hashmap = GNUNET_CONTAINER_multihashmap_create (65536); | ||
1727 | heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
1728 | GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPINGg", | ||
1729 | &max_mappings); | ||
1730 | udp_connections = GNUNET_CONTAINER_multihashmap_create (65536); | ||
1731 | dns_handle = GNUNET_DNS_connect (cfg, | ||
1732 | &process_answer, | ||
1733 | NULL); | ||
1734 | if (GNUNET_SYSERR == | ||
1735 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname)) | ||
1736 | { | ||
1737 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1738 | "No entry 'IFNAME' in configuration!\n"); | ||
1739 | exit (1); | ||
1740 | } | ||
1741 | |||
1742 | if (GNUNET_SYSERR == | ||
1743 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR", &ipv6addr)) | ||
1744 | { | ||
1745 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1746 | "No entry 'IPV6ADDR' in configuration!\n"); | ||
1747 | exit (1); | ||
1748 | } | ||
1749 | |||
1750 | if (GNUNET_SYSERR == | ||
1751 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX", | ||
1752 | &ipv6prefix)) | ||
1753 | { | ||
1754 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1755 | "No entry 'IPV6PREFIX' in configuration!\n"); | ||
1756 | exit (1); | ||
1757 | } | ||
1758 | |||
1759 | if (GNUNET_SYSERR == | ||
1760 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR", &ipv4addr)) | ||
1761 | { | ||
1762 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1763 | "No entry 'IPV4ADDR' in configuration!\n"); | ||
1764 | exit (1); | ||
1765 | } | ||
1766 | |||
1767 | if (GNUNET_SYSERR == | ||
1768 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK", &ipv4mask)) | ||
1769 | { | ||
1770 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1771 | "No entry 'IPV4MASK' in configuration!\n"); | ||
1772 | exit (1); | ||
1773 | } | ||
1774 | |||
1775 | vpn_argv[0] = GNUNET_strdup ("vpn-gnunet"); | ||
1776 | vpn_argv[1] = ifname; | ||
1777 | vpn_argv[2] = ipv6addr; | ||
1778 | vpn_argv[3] = ipv6prefix; | ||
1779 | vpn_argv[4] = ipv4addr; | ||
1780 | vpn_argv[5] = ipv4mask; | ||
1781 | vpn_argv[6] = NULL; | ||
1782 | |||
1783 | helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", vpn_argv, | ||
1784 | &message_token, NULL); | ||
1785 | GNUNET_DNS_restart_hijack (dns_handle); | ||
1786 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); | ||
1787 | } | ||
1788 | |||
1789 | /** | ||
1790 | * The main function to obtain template from gnunetd. | ||
1791 | * | ||
1792 | * @param argc number of arguments from the command line | ||
1793 | * @param argv command line arguments | ||
1794 | * @return 0 ok, 1 on error | ||
1795 | */ | ||
1796 | int | ||
1797 | main (int argc, char *const *argv) | ||
1798 | { | ||
1799 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
1800 | GNUNET_GETOPT_OPTION_END | ||
1801 | }; | ||
1802 | |||
1803 | return (GNUNET_OK == | ||
1804 | GNUNET_PROGRAM_run (argc, argv, "vpn", gettext_noop ("help text"), | ||
1805 | options, &run, NULL)) ? ret : 1; | ||
1806 | } | ||
1807 | |||
1808 | /* end of gnunet-daemon-vpn.c */ | ||
diff --git a/src/vpn/test-conf.conf b/src/vpn/test-conf.conf deleted file mode 100644 index b805c7c94..000000000 --- a/src/vpn/test-conf.conf +++ /dev/null | |||
@@ -1,276 +0,0 @@ | |||
1 | [PATHS] | ||
2 | SERVICEHOME = ~/.gnunet/ | ||
3 | # SERVICEHOME = /var/lib/gnunet/ | ||
4 | # DEFAULTCONFIG = /etc/gnunet.conf | ||
5 | # If 'DEFAULTCONFIG' is not defined, the current | ||
6 | # configuration file is assumed to be the default, | ||
7 | # which is what we want by default... | ||
8 | |||
9 | [gnunetd] | ||
10 | HOSTKEY = $SERVICEHOME/.hostkey | ||
11 | |||
12 | [TESTING] | ||
13 | WEAKRANDOM = NO | ||
14 | |||
15 | [client] | ||
16 | HOME = $SERVICEHOME | ||
17 | |||
18 | [transport-tcp] | ||
19 | PORT = 2086 | ||
20 | TIMEOUT = 300s | ||
21 | # MAXBUF = | ||
22 | # DISABLEV6 = | ||
23 | # BINDTO = | ||
24 | # ACCEPT_FROM = | ||
25 | # ACCEPT_FROM6 = | ||
26 | # REJECT_FROM = | ||
27 | # REJECT_FROM6 = | ||
28 | |||
29 | [dht] | ||
30 | AUTOSTART = YES | ||
31 | DEBUG = YES | ||
32 | PORT = 2095 | ||
33 | HOSTNAME = localhost | ||
34 | HOME = $SERVICEHOME | ||
35 | CONFIG = $DEFAULTCONFIG | ||
36 | BINARY = gnunet-service-dht | ||
37 | ACCEPT_FROM = 127.0.0.1; | ||
38 | ACCEPT_FROM6 = ::1; | ||
39 | UNIXPATH = /tmp/gnunet-service-dht.sock | ||
40 | # DISABLE_SOCKET_FORWARDING = NO | ||
41 | # DEBUG = YES | ||
42 | # USERNAME = | ||
43 | # MAXBUF = | ||
44 | # TIMEOUT = | ||
45 | # DISABLEV6 = | ||
46 | # BINDTO = | ||
47 | # REJECT_FROM = | ||
48 | # REJECT_FROM6 = | ||
49 | # PREFIX = | ||
50 | |||
51 | [dhtcache] | ||
52 | QUOTA = 1 MB | ||
53 | DATABASE = sqlite | ||
54 | |||
55 | [arm] | ||
56 | PORT = 2087 | ||
57 | HOSTNAME = localhost | ||
58 | HOME = $SERVICEHOME | ||
59 | CONFIG = $DEFAULTCONFIG | ||
60 | BINARY = gnunet-service-arm | ||
61 | ACCEPT_FROM = 127.0.0.1; | ||
62 | ACCEPT_FROM6 = ::1; | ||
63 | DEFAULTSERVICES = core transport dht vpn dns | ||
64 | UNIXPATH = /tmp/gnunet-service-arm.sock | ||
65 | # GLOBAL_POSTFIX = -l $SERVICEHOME/{}-logs | ||
66 | # GLOBAL_PREFIX = | ||
67 | # USERNAME = | ||
68 | # MAXBUF = | ||
69 | # TIMEOUT = | ||
70 | # DISABLEV6 = | ||
71 | # BINDTO = | ||
72 | # REJECT_FROM = | ||
73 | # REJECT_FROM6 = | ||
74 | # PREFIX = | ||
75 | |||
76 | [statistics] | ||
77 | AUTOSTART = YES | ||
78 | PORT = 2088 | ||
79 | HOSTNAME = localhost | ||
80 | HOME = $SERVICEHOME | ||
81 | CONFIG = $DEFAULTCONFIG | ||
82 | BINARY = gnunet-service-statistics | ||
83 | ACCEPT_FROM = 127.0.0.1; | ||
84 | ACCEPT_FROM6 = ::1; | ||
85 | UNIXPATH = /tmp/gnunet-service-statistics.sock | ||
86 | # USERNAME = | ||
87 | # MAXBUF = | ||
88 | # TIMEOUT = | ||
89 | # DISABLEV6 = | ||
90 | # BINDTO = | ||
91 | # REJECT_FROM = | ||
92 | # REJECT_FROM6 = | ||
93 | # PREFIX = | ||
94 | |||
95 | [resolver] | ||
96 | AUTOSTART = YES | ||
97 | PORT = 2089 | ||
98 | HOSTNAME = localhost | ||
99 | HOME = $SERVICEHOME | ||
100 | CONFIG = $DEFAULTCONFIG | ||
101 | BINARY = gnunet-service-resolver | ||
102 | ACCEPT_FROM = 127.0.0.1; | ||
103 | ACCEPT_FROM6 = ::1; | ||
104 | UNIXPATH = /tmp/gnunet-service-resolver.sock | ||
105 | # USERNAME = | ||
106 | # MAXBUF = | ||
107 | # TIMEOUT = | ||
108 | # DISABLEV6 = | ||
109 | # BINDTO = | ||
110 | # REJECT_FROM = | ||
111 | # REJECT_FROM6 = | ||
112 | # PREFIX = | ||
113 | |||
114 | [peerinfo] | ||
115 | AUTOSTART = YES | ||
116 | PORT = 2090 | ||
117 | HOSTNAME = localhost | ||
118 | HOME = $SERVICEHOME | ||
119 | CONFIG = $DEFAULTCONFIG | ||
120 | BINARY = gnunet-service-peerinfo | ||
121 | ACCEPT_FROM = 127.0.0.1; | ||
122 | ACCEPT_FROM6 = ::1; | ||
123 | UNIXPATH = /tmp/gnunet-service-peerinfo.sock | ||
124 | # USERNAME = | ||
125 | # MAXBUF = | ||
126 | # TIMEOUT = | ||
127 | # DISABLEV6 = | ||
128 | # BINDTO = | ||
129 | # REJECT_FROM = | ||
130 | # REJECT_FROM6 = | ||
131 | # PREFIX = | ||
132 | HOSTS = $SERVICEHOME/data/hosts/ | ||
133 | TRUST = $SERVICEHOME/data/credit/ | ||
134 | |||
135 | |||
136 | [transport] | ||
137 | AUTOSTART = YES | ||
138 | PORT = 2091 | ||
139 | HOSTNAME = localhost | ||
140 | HOME = $SERVICEHOME | ||
141 | CONFIG = $DEFAULTCONFIG | ||
142 | BINARY = gnunet-service-transport | ||
143 | NEIGHBOUR_LIMIT = 50 | ||
144 | ACCEPT_FROM = 127.0.0.1; | ||
145 | ACCEPT_FROM6 = ::1; | ||
146 | PLUGINS = tcp | ||
147 | UNIXPATH = /tmp/gnunet-service-transport.sock | ||
148 | # USERNAME = | ||
149 | # MAXBUF = | ||
150 | # TIMEOUT = | ||
151 | # DISABLEV6 = | ||
152 | # BINDTO = | ||
153 | # REJECT_FROM = | ||
154 | # REJECT_FROM6 = | ||
155 | # PREFIX = | ||
156 | |||
157 | [ats] | ||
158 | WAN_QUOTA_IN = 64 kiB | ||
159 | WAN_QUOTA_OUT = 64 kiB | ||
160 | |||
161 | [core] | ||
162 | AUTOSTART = YES | ||
163 | PORT = 2092 | ||
164 | HOSTNAME = localhost | ||
165 | HOME = $SERVICEHOME | ||
166 | CONFIG = $DEFAULTCONFIG | ||
167 | BINARY = gnunet-service-core | ||
168 | ACCEPT_FROM = 127.0.0.1; | ||
169 | ACCEPT_FROM6 = ::1; | ||
170 | UNIXPATH = /tmp/gnunet-service-core.sock | ||
171 | # DEBUG = YES | ||
172 | # USERNAME = | ||
173 | # MAXBUF = | ||
174 | # TIMEOUT = | ||
175 | # DISABLEV6 = | ||
176 | # BINDTO = | ||
177 | # REJECT_FROM = | ||
178 | # REJECT_FROM6 = | ||
179 | # PREFIX = | ||
180 | |||
181 | |||
182 | [topology] | ||
183 | MINIMUM-FRIENDS = 0 | ||
184 | FRIENDS-ONLY = NO | ||
185 | AUTOCONNECT = YES | ||
186 | TARGET-CONNECTION-COUNT = 16 | ||
187 | FRIENDS = $SERVICEHOME/friends | ||
188 | CONFIG = $DEFAULTCONFIG | ||
189 | BINARY = gnunet-daemon-topology | ||
190 | |||
191 | [hostlist] | ||
192 | # port for hostlist http server | ||
193 | AUTOSTART = NO | ||
194 | HTTPPORT = 8080 | ||
195 | DEBUG = YES | ||
196 | HOME = $SERVICEHOME | ||
197 | HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data | ||
198 | CONFIG = $DEFAULTCONFIG | ||
199 | BINARY = gnunet-daemon-hostlist | ||
200 | # consider having "-e" as default as well once implemented | ||
201 | OPTIONS = -p -e -a | ||
202 | SERVERS = # http://v9.gnunet.org:58080/ | ||
203 | # proxy for downloading hostlists | ||
204 | HTTP-PROXY = | ||
205 | |||
206 | [vpn] | ||
207 | CONFIG = $DEFAULTCONFIG | ||
208 | BINARY = gnunet-daemon-vpn | ||
209 | DEBUG = YES | ||
210 | |||
211 | [datastore] | ||
212 | AUTOSTART = YES | ||
213 | UNIXPATH = /tmp/gnunet-service-datastore.sock | ||
214 | PORT = 2093 | ||
215 | HOSTNAME = localhost | ||
216 | HOME = $SERVICEHOME | ||
217 | CONFIG = $DEFAULTCONFIG | ||
218 | BINARY = gnunet-service-datastore | ||
219 | ACCEPT_FROM = 127.0.0.1; | ||
220 | ACCEPT_FROM6 = ::1; | ||
221 | QUOTA = 100 MB | ||
222 | BLOOMFILTER = $SERVICEHOME/fs/bloomfilter | ||
223 | DATABASE = sqlite | ||
224 | |||
225 | [datastore-sqlite] | ||
226 | FILENAME = $SERVICEHOME/datastore/sqlite.db | ||
227 | |||
228 | [fs] | ||
229 | AUTOSTART = YES | ||
230 | INDEXDB = $SERVICEHOME/idxinfo.lst | ||
231 | IDENTITY_DIR = $SERVICEHOME/identities/ | ||
232 | STATE_DIR = $SERVICEHOME/persistence/ | ||
233 | PORT = 2094 | ||
234 | HOSTNAME = localhost | ||
235 | HOME = $SERVICEHOME | ||
236 | CONFIG = $DEFAULTCONFIG | ||
237 | BINARY = gnunet-service-fs | ||
238 | ACCEPT_FROM = 127.0.0.1; | ||
239 | ACCEPT_FROM6 = ::1; | ||
240 | ACTIVEMIGRATION = YES | ||
241 | UNIXPATH = /tmp/gnunet-service-fs.sock | ||
242 | # DEBUG = YES | ||
243 | |||
244 | [dns] | ||
245 | AUTOSTART = YES | ||
246 | PORT = 2098 | ||
247 | HOSTNAME = localhost | ||
248 | HOME = $SERVICEHOME | ||
249 | CONFIG = $DEFAULTCONFIG | ||
250 | BINARY = gnunet-service-dns | ||
251 | ACCEPT_FROM = 127.0.0.1; | ||
252 | ACCEPT_FROM6 = ::1; | ||
253 | # quotas are in bytes per second now! | ||
254 | TOTAL_QUOTA_IN = 65536 | ||
255 | TOTAL_QUOTA_OUT = 65536 | ||
256 | UNIXPATH = /tmp/gnunet-service-dns.sock | ||
257 | DEBUG = YES | ||
258 | # USERNAME = | ||
259 | # MAXBUF = | ||
260 | # TIMEOUT = | ||
261 | # DISABLEV6 = | ||
262 | # BINDTO = | ||
263 | # REJECT_FROM = | ||
264 | # REJECT_FROM6 = | ||
265 | # PREFIX = | ||
266 | |||
267 | [block] | ||
268 | PLUGINS = fs dns | ||
269 | |||
270 | |||
271 | |||
272 | |||
273 | [nse] | ||
274 | AUTOSTART = NO | ||
275 | |||
276 | |||