diff options
Diffstat (limited to 'src/dns/gnunet-service-dns.c')
-rw-r--r-- | src/dns/gnunet-service-dns.c | 758 |
1 files changed, 124 insertions, 634 deletions
diff --git a/src/dns/gnunet-service-dns.c b/src/dns/gnunet-service-dns.c index 6337538..d1689f4 100644 --- a/src/dns/gnunet-service-dns.c +++ b/src/dns/gnunet-service-dns.c @@ -45,21 +45,22 @@ #include "dns.h" #include "gnunet_dns_service.h" #include "gnunet_dnsparser_lib.h" -#include "gnunet_mesh_service.h" +#include "gnunet_dnsstub_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_tun_lib.h" - /** - * Timeout for an external (Internet-DNS) DNS resolution + * Port number for DNS */ -#define REQUEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) +#define DNS_PORT 53 + /** - * How many DNS sockets do we open at most at the same time? - * (technical socket maximum is this number x2 for IPv4+IPv6) + * Generic logging shorthand */ -#define DNS_SOCKET_MAX 128 +#define LOG(kind, ...) \ + GNUNET_log_from (kind, "dns", __VA_ARGS__); + /** * Phases each request goes through. @@ -137,34 +138,6 @@ struct ClientRecord /** - * UDP socket we are using for sending DNS requests to the Internet. - */ -struct RequestSocket -{ - - /** - * UDP socket we use for this request for IPv4 - */ - struct GNUNET_NETWORK_Handle *dnsout4; - - /** - * UDP socket we use for this request for IPv6 - */ - struct GNUNET_NETWORK_Handle *dnsout6; - - /** - * Task for reading from dnsout4 and dnsout6. - */ - GNUNET_SCHEDULER_TaskIdentifier read_task; - - /** - * When should this socket be closed? - */ - struct GNUNET_TIME_Absolute timeout; -}; - - -/** * Entry we keep for each active request. */ struct RequestRecord @@ -184,10 +157,9 @@ struct RequestRecord /** * Socket we are using to transmit this request (must match if we receive - * a response). Must NOT be freed as part of this request record (as it - * might be shared with other requests). + * a response). */ - struct GNUNET_NETWORK_Handle *dnsout; + struct GNUNET_DNSSTUB_RequestSocket *rs; /** * Source address of the original request (for sending response). @@ -200,11 +172,6 @@ struct RequestRecord struct sockaddr_storage dst_addr; /** - * When should this request time out? - */ - struct GNUNET_TIME_Absolute timeout; - - /** * ID of this request, also basis for hashing. Lowest 16 bit will * be our message ID when doing a global DNS request and our index * into the 'requests' array. @@ -230,66 +197,6 @@ struct RequestRecord /** - * State we keep for each DNS tunnel that terminates at this node. - */ -struct TunnelState -{ - - /** - * Associated MESH tunnel. - */ - struct GNUNET_MESH_Tunnel *tunnel; - - /** - * Active request for sending a reply. - */ - struct GNUNET_MESH_TransmitHandle *th; - - /** - * DNS reply ready for transmission. - */ - char *reply; - - /** - * Socket we are using to transmit this request (must match if we receive - * a response). Must NOT be freed as part of this request record (as it - * might be shared with other requests). - */ - struct GNUNET_NETWORK_Handle *dnsout; - - /** - * Address we sent the DNS request to. - */ - struct sockaddr_storage addr; - - /** - * When should this request time out? - */ - struct GNUNET_TIME_Absolute timeout; - - /** - * Number of bytes in 'addr'. - */ - socklen_t addrlen; - - /** - * Number of bytes in 'reply'. - */ - size_t reply_length; - - /** - * Original DNS request ID as used by the client. - */ - uint16_t original_id; - - /** - * DNS request ID that we used for forwarding. - */ - uint16_t my_id; -}; - - -/** * Global return value from 'main'. */ static int global_ret; @@ -335,57 +242,14 @@ static struct GNUNET_SERVER_NotificationContext *nc; static struct RequestRecord requests[UINT16_MAX + 1]; /** - * Array of all open requests from tunnels. - */ -static struct TunnelState *tunnels[UINT16_MAX + 1]; - -/** - * Array of all open sockets for DNS requests. - */ -static struct RequestSocket sockets[DNS_SOCKET_MAX]; - -/** * Generator for unique request IDs. */ static uint64_t request_id_gen; /** - * IP address to use for the DNS server if we are a DNS exit service - * (for VPN via mesh); otherwise NULL. - */ -static char *dns_exit; - -/** - * Handle to the MESH service (for receiving DNS queries), or NULL - * if we are not a DNS exit. - */ -static struct GNUNET_MESH_Handle *mesh; - - -/** - * We're done with a RequestSocket, close it for now. - * - * @param rs request socket to clean up + * Handle to the DNS Stub resolver. */ -static void -cleanup_rs (struct RequestSocket *rs) -{ - if (NULL != rs->dnsout4) - { - GNUNET_NETWORK_socket_close (rs->dnsout4); - rs->dnsout4 = NULL; - } - if (NULL != rs->dnsout6) - { - GNUNET_NETWORK_socket_close (rs->dnsout6); - rs->dnsout6 = NULL; - } - if (GNUNET_SCHEDULER_NO_TASK != rs->read_task) - { - GNUNET_SCHEDULER_cancel (rs->read_task); - rs->read_task = GNUNET_SCHEDULER_NO_TASK; - } -} +static struct GNUNET_DNSSTUB_Context *dnsstub; /** @@ -430,64 +294,11 @@ cleanup_task (void *cls GNUNET_UNUSED, GNUNET_STATISTICS_destroy (stats, GNUNET_NO); stats = NULL; } - if (NULL != dns_exit) - { - GNUNET_free (dns_exit); - dns_exit = NULL; - } - if (NULL != mesh) - { - GNUNET_MESH_disconnect(mesh); - mesh = NULL; - } -} - - -/** - * Open source port for sending DNS requests - * - * @param af AF_INET or AF_INET6 - * @return GNUNET_OK on success - */ -static struct GNUNET_NETWORK_Handle * -open_socket (int af) -{ - struct sockaddr_in a4; - struct sockaddr_in6 a6; - struct sockaddr *sa; - socklen_t alen; - struct GNUNET_NETWORK_Handle *ret; - - ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0); - if (NULL == ret) - return NULL; - switch (af) - { - case AF_INET: - memset (&a4, 0, alen = sizeof (struct sockaddr_in)); - sa = (struct sockaddr *) &a4; - break; - case AF_INET6: - memset (&a6, 0, alen = sizeof (struct sockaddr_in6)); - sa = (struct sockaddr *) &a6; - break; - default: - GNUNET_break (0); - GNUNET_NETWORK_socket_close (ret); - return NULL; - } - sa->sa_family = af; - if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret, - sa, - alen)) + if (NULL != dnsstub) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Could not bind to any port: %s\n"), - STRERROR (errno)); - GNUNET_NETWORK_socket_close (ret); - return NULL; + GNUNET_DNSSTUB_stop (dnsstub); + dnsstub = NULL; } - return ret; } @@ -510,10 +321,16 @@ request_done (struct RequestRecord *rr) if (RP_RESPONSE_MONITOR != rr->phase) { /* no response, drop */ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Got no response for request %llu, dropping\n", + (unsigned long long) rr->request_id); cleanup_rr (rr); return; } - + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting response for request %llu\n", + (unsigned long long) rr->request_id); /* send response via hijacker */ reply_len = sizeof (struct GNUNET_MessageHeader); reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader); @@ -664,6 +481,9 @@ send_request_to_client (struct RequestRecord *rr, cleanup_rr (rr); return; } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending information about request %llu to local client\n", + (unsigned long long) rr->request_id); req = (struct GNUNET_DNS_Request*) buf; req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST); req->header.size = htons (sizeof (buf)); @@ -677,70 +497,21 @@ send_request_to_client (struct RequestRecord *rr, } -/** - * Read a DNS response from the (unhindered) UDP-Socket - * - * @param cls socket to read from - * @param tc scheduler context (must be shutdown or read ready) - */ -static void -read_response (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc); - /** - * Get a socket of the specified address family to send out a - * UDP DNS request to the Internet. + * Callback called from DNSSTUB resolver when a resolution + * succeeded. * - * @param af desired address family - * @return NULL on error (given AF not "supported") + * @param cls NULL + * @param rs the socket that received the response + * @param dns the response itself + * @param r number of bytes in dns */ -static struct GNUNET_NETWORK_Handle * -get_request_socket (int af) -{ - struct RequestSocket *rs; - struct GNUNET_NETWORK_FDSet *rset; - static struct GNUNET_NETWORK_Handle *ret; - - rs = &sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, - DNS_SOCKET_MAX)]; - rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT); - switch (af) - { - case AF_INET: - if (NULL == rs->dnsout4) - rs->dnsout4 = open_socket (AF_INET); - ret = rs->dnsout4; - break; - case AF_INET6: - if (NULL == rs->dnsout6) - rs->dnsout6 = open_socket (AF_INET6); - ret = rs->dnsout6; - break; - default: - return NULL; - } - if (GNUNET_SCHEDULER_NO_TASK != rs->read_task) - { - GNUNET_SCHEDULER_cancel (rs->read_task); - rs->read_task = GNUNET_SCHEDULER_NO_TASK; - } - if ( (NULL == rs->dnsout4) && - (NULL == rs->dnsout6) ) - return NULL; - rset = GNUNET_NETWORK_fdset_create (); - if (NULL != rs->dnsout4) - GNUNET_NETWORK_fdset_set (rset, rs->dnsout4); - if (NULL != rs->dnsout6) - GNUNET_NETWORK_fdset_set (rset, rs->dnsout6); - rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - REQUEST_TIMEOUT, - rset, - NULL, - &read_response, rs); - GNUNET_NETWORK_fdset_destroy (rset); - return ret; -} +static void +process_dns_result (void *cls, + struct GNUNET_DNSSTUB_RequestSocket *rs, + const struct GNUNET_TUN_DnsHeader *dns, + size_t r); /** @@ -777,6 +548,10 @@ next_phase (struct RequestRecord *rr) return; } /* done with current phase, advance! */ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Request %llu now in phase %d\n", + rr->request_id, + rr->phase); switch (rr->phase) { case RP_INIT: @@ -815,8 +590,14 @@ next_phase (struct RequestRecord *rr) } rr->phase = RP_INTERNET_DNS; - rr->dnsout = get_request_socket (rr->dst_addr.ss_family); - if (NULL == rr->dnsout) + rr->rs = GNUNET_DNSSTUB_resolve (dnsstub, + (struct sockaddr*) &rr->dst_addr, + salen, + rr->payload, + rr->payload_length, + &process_dns_result, + NULL); + if (NULL == rr->rs) { GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS exit failed (failed to open socket)"), @@ -824,12 +605,6 @@ next_phase (struct RequestRecord *rr) cleanup_rr (rr); return; } - GNUNET_NETWORK_socket_sendto (rr->dnsout, - rr->payload, - rr->payload_length, - (struct sockaddr*) &rr->dst_addr, - salen); - rr->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT); return; case RP_INTERNET_DNS: rr->phase = RP_MODIFY; @@ -911,199 +686,45 @@ client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) /** - * We got a reply from DNS for a request of a MESH tunnel. Send it - * via the tunnel (after changing the request ID back). + * Callback called from DNSSTUB resolver when a resolution + * succeeded. * - * @param cls the 'struct TunnelState' - * @param size number of bytes available in buf - * @param buf where to copy the reply - * @return number of bytes written to buf - */ -static size_t -transmit_reply_to_mesh (void *cls, - size_t size, - void *buf) -{ - struct TunnelState *ts = cls; - size_t off; - size_t ret; - char *cbuf = buf; - struct GNUNET_MessageHeader hdr; - struct GNUNET_TUN_DnsHeader dns; - - ts->th = NULL; - GNUNET_assert (ts->reply != NULL); - if (size == 0) - return 0; - ret = sizeof (struct GNUNET_MessageHeader) + ts->reply_length; - GNUNET_assert (ret <= size); - hdr.size = htons (ret); - hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET); - memcpy (&dns, ts->reply, sizeof (dns)); - dns.id = ts->original_id; - off = 0; - memcpy (&cbuf[off], &hdr, sizeof (hdr)); - off += sizeof (hdr); - memcpy (&cbuf[off], &dns, sizeof (dns)); - off += sizeof (dns); - memcpy (&cbuf[off], &ts->reply[sizeof (dns)], ts->reply_length - sizeof (dns)); - off += ts->reply_length - sizeof (dns); - GNUNET_free (ts->reply); - ts->reply = NULL; - ts->reply_length = 0; - GNUNET_assert (ret == off); - return ret; -} - - -/** - * Actually do the reading of a DNS packet from our UDP socket and see - * if we have a valid, matching, pending request. - * - * @param dnsout socket to read from - * @return GNUNET_OK on success, GNUNET_NO on drop, GNUNET_SYSERR on IO-errors (closed socket) - */ -static int -do_dns_read (struct GNUNET_NETWORK_Handle *dnsout) -{ - struct sockaddr_storage addr; - socklen_t addrlen; - struct GNUNET_TUN_DnsHeader *dns; - struct RequestRecord *rr; - struct TunnelState *ts; - ssize_t r; - int len; - -#ifndef MINGW - if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len)) - { - /* conservative choice: */ - len = UINT16_MAX; - } -#else - /* port the code above? */ - len = UINT16_MAX; -#endif - - { - unsigned char buf[len] GNUNET_ALIGN; - - addrlen = sizeof (addr); - memset (&addr, 0, sizeof (addr)); - r = GNUNET_NETWORK_socket_recvfrom (dnsout, - buf, sizeof (buf), - (struct sockaddr*) &addr, &addrlen); - if (-1 == r) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom"); - GNUNET_NETWORK_socket_close (dnsout); - return GNUNET_SYSERR; - } - if (sizeof (struct GNUNET_TUN_DnsHeader) > r) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Received DNS response that is too small (%u bytes)"), - r); - return GNUNET_NO; - } - dns = (struct GNUNET_TUN_DnsHeader *) buf; - /* Handle case that this is a reply to a request from a MESH DNS tunnel */ - ts = tunnels[dns->id]; - if ( (NULL == ts) || - (ts->dnsout != dnsout) || - (addrlen != ts->addrlen) || - (0 != memcmp (&ts->addr, - &addr, - addrlen)) || - (0 == GNUNET_TIME_absolute_get_remaining (ts->timeout).rel_value) ) - ts = NULL; /* DNS responder address missmatch */ - if (NULL != ts) - { - tunnels[dns->id] = NULL; - GNUNET_free_non_null (ts->reply); - ts->reply = GNUNET_malloc (r); - ts->reply_length = r; - memcpy (ts->reply, dns, r); - if (ts->th != NULL) - GNUNET_MESH_notify_transmit_ready_cancel (ts->th); - ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel, - GNUNET_NO, 0, - GNUNET_TIME_UNIT_FOREVER_REL, - NULL, - sizeof (struct GNUNET_MessageHeader) + r, - &transmit_reply_to_mesh, - ts); - } - /* Handle case that this is a reply to a local request (intercepted from TUN interface) */ - rr = &requests[dns->id]; - if ( (rr->phase != RP_INTERNET_DNS) || - (rr->dnsout != dnsout) || - (0 != memcmp (&rr->dst_addr, - &addr, - addrlen)) || - (0 == GNUNET_TIME_absolute_get_remaining (rr->timeout).rel_value) ) - { - if (NULL == ts) - { - /* unexpected / bogus reply */ - GNUNET_STATISTICS_update (stats, - gettext_noop ("# External DNS response discarded (no matching request)"), - 1, GNUNET_NO); - } - return GNUNET_NO; - } - GNUNET_free_non_null (rr->payload); - rr->payload = GNUNET_malloc (r); - memcpy (rr->payload, buf, r); - rr->payload_length = r; - next_phase (rr); - } - return GNUNET_OK; -} - - -/** - * Read a DNS response from the (unhindered) UDP-Socket - * - * @param cls socket to read from - * @param tc scheduler context (must be shutdown or read ready) + * @param cls NULL + * @param rs the socket that received the response + * @param dns the response itself + * @param r number of bytes in dns */ static void -read_response (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +process_dns_result (void *cls, + struct GNUNET_DNSSTUB_RequestSocket *rs, + const struct GNUNET_TUN_DnsHeader *dns, + size_t r) { - struct RequestSocket *rs = cls; - struct GNUNET_NETWORK_FDSet *rset; + struct RequestRecord *rr; - rs->read_task = GNUNET_SCHEDULER_NO_TASK; - if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Processing DNS result from stub resolver\n"); + GNUNET_assert (NULL == cls); + rr = &requests[dns->id]; + if ( (rr->phase != RP_INTERNET_DNS) || + (rr->rs != rs) ) { - /* timeout or shutdown */ - cleanup_rs (rs); - return; + /* unexpected / bogus reply */ + GNUNET_STATISTICS_update (stats, + gettext_noop ("# External DNS response discarded (no matching request)"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received DNS reply that does not match any pending request. Dropping.\n"); + return; } - /* read and process ready sockets */ - if ((NULL != rs->dnsout4) && - (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout4)) && - (GNUNET_SYSERR == do_dns_read (rs->dnsout4))) - rs->dnsout4 = NULL; - if ((NULL != rs->dnsout6) && - (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout6)) && - (GNUNET_SYSERR == do_dns_read (rs->dnsout6))) - rs->dnsout6 = NULL; - - /* re-schedule read task */ - rset = GNUNET_NETWORK_fdset_create (); - if (NULL != rs->dnsout4) - GNUNET_NETWORK_fdset_set (rset, rs->dnsout4); - if (NULL != rs->dnsout6) - GNUNET_NETWORK_fdset_set (rset, rs->dnsout6); - rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_TIME_absolute_get_remaining (rs->timeout), - rset, - NULL, - &read_response, rs); - GNUNET_NETWORK_fdset_destroy (rset); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Got a response from the stub resolver for DNS request %llu intercepted locally!\n", + (unsigned long long) rr->request_id); + GNUNET_free_non_null (rr->payload); + rr->payload = GNUNET_malloc (r); + memcpy (rr->payload, dns, r); + rr->payload_length = r; + next_phase (rr); } @@ -1162,6 +783,9 @@ handle_client_response (void *cls GNUNET_UNUSED, resp = (const struct GNUNET_DNS_Response*) message; off = (uint16_t) resp->request_id; rr = &requests[off]; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received DNS response with ID %llu from local client!\n", + (unsigned long long) resp->request_id); if (rr->request_id != resp->request_id) { GNUNET_STATISTICS_update (stats, @@ -1255,6 +879,8 @@ process_helper_messages (void *cls GNUNET_UNUSED, void *client, struct sockaddr_in *dsta4; struct sockaddr_in6 *dsta6; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Intercepted message via DNS hijacker\n"); msize = ntohs (message->size); if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header)) { @@ -1308,7 +934,8 @@ process_helper_messages (void *cls GNUNET_UNUSED, void *client, ntohs (tun->proto)); return GNUNET_OK; } - if (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader)) + if ( (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader)) || + (DNS_PORT != ntohs (udp->destination_port)) ) { /* non-DNS packet received on TUN, ignore */ GNUNET_STATISTICS_update (stats, @@ -1375,7 +1002,9 @@ process_helper_messages (void *cls GNUNET_UNUSED, void *client, memcpy (rr->payload, dns, msize); rr->request_id = dns->id | (request_id_gen << 16); request_id_gen++; - + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Creating new DNS request %llu\n", + (unsigned long long) rr->request_id); GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS requests received via TUN interface"), 1, GNUNET_NO); @@ -1386,150 +1015,6 @@ process_helper_messages (void *cls GNUNET_UNUSED, void *client, /** - * Process a request via mesh to perform a DNS query. - * - * @param cls closure, NULL - * @param tunnel connection to the other end - * @param tunnel_ctx pointer to our 'struct TunnelState *' - * @param sender who sent the message - * @param message the actual message - * @param atsi performance data for the connection - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -static int -receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, - void **tunnel_ctx, - const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, - const struct GNUNET_MessageHeader *message, - const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) -{ - struct TunnelState *ts = *tunnel_ctx; - const struct GNUNET_TUN_DnsHeader *dns; - size_t mlen = ntohs (message->size); - size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader); - char buf[dlen] GNUNET_ALIGN; - struct GNUNET_TUN_DnsHeader *dout; - struct sockaddr_in v4; - struct sockaddr_in6 v6; - struct sockaddr *so; - socklen_t salen; - - if (dlen < sizeof (struct GNUNET_TUN_DnsHeader)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - dns = (const struct GNUNET_TUN_DnsHeader *) &message[1]; - ts->original_id = dns->id; - if (tunnels[ts->my_id] == ts) - tunnels[ts->my_id] = NULL; - ts->my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, - UINT16_MAX + 1); - tunnels[ts->my_id] = ts; - memcpy (buf, dns, dlen); - dout = (struct GNUNET_TUN_DnsHeader*) buf; - dout->id = ts->my_id; - memset (&v4, 0, sizeof (v4)); - memset (&v6, 0, sizeof (v6)); - if (1 == inet_pton (AF_INET, dns_exit, &v4.sin_addr)) - { - salen = sizeof (v4); - v4.sin_family = AF_INET; - v4.sin_port = htons (53); -#if HAVE_SOCKADDR_IN_SIN_LEN - v4.sin_len = (u_char) salen; -#endif - so = (struct sockaddr *) &v4; - ts->dnsout = get_request_socket (AF_INET); - } - else if (1 == inet_pton (AF_INET6, dns_exit, &v6.sin6_addr)) - { - salen = sizeof (v6); - v6.sin6_family = AF_INET6; - v6.sin6_port = htons (53); -#if HAVE_SOCKADDR_IN_SIN_LEN - v6.sin6_len = (u_char) salen; -#endif - so = (struct sockaddr *) &v6; - ts->dnsout = get_request_socket (AF_INET6); - } - else - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (NULL == ts->dnsout) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Configured DNS exit `%s' is not working / valid.\n"), - dns_exit); - return GNUNET_SYSERR; - } - memcpy (&ts->addr, - so, - salen); - ts->addrlen = salen; - GNUNET_NETWORK_socket_sendto (ts->dnsout, - buf, dlen, so, salen); - ts->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT); - return GNUNET_OK; -} - - -/** - * Callback from GNUNET_MESH for new tunnels. - * - * @param cls closure - * @param tunnel new handle to the tunnel - * @param initiator peer that started the tunnel - * @param ats performance information for the tunnel - * @return initial tunnel context for the tunnel - */ -static void * -accept_dns_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, - const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED, - const struct GNUNET_ATS_Information *ats GNUNET_UNUSED) -{ - struct TunnelState *ts = GNUNET_malloc (sizeof (struct TunnelState)); - - GNUNET_STATISTICS_update (stats, - gettext_noop ("# Inbound MESH tunnels created"), - 1, GNUNET_NO); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received inbound tunnel from `%s'\n", - GNUNET_i2s (initiator)); - ts->tunnel = tunnel; - return ts; -} - - -/** - * Function called by mesh whenever an inbound tunnel is destroyed. - * Should clean up any associated state. - * - * @param cls closure (set from GNUNET_MESH_connect) - * @param tunnel connection to the other end (henceforth invalid) - * @param tunnel_ctx place where local state associated - * with the tunnel is stored - */ -static void -destroy_dns_tunnel (void *cls GNUNET_UNUSED, - const struct GNUNET_MESH_Tunnel *tunnel, - void *tunnel_ctx) -{ - struct TunnelState *ts = tunnel_ctx; - - if (tunnels[ts->my_id] == ts) - tunnels[ts->my_id] = NULL; - if (NULL != ts->th) - GNUNET_MESH_notify_transmit_ready_cancel (ts->th); - GNUNET_free_non_null (ts->reply); - GNUNET_free (ts); -} - - -/** * @param cls closure * @param server the initialized server * @param cfg_ configuration to use @@ -1552,37 +1037,40 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, char *ipv6prefix; struct in_addr dns_exit4; struct in6_addr dns_exit6; + char *dns_exit; + char *binary; cfg = cfg_; + binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-dns"); if (GNUNET_YES != - GNUNET_OS_check_helper_binary ("gnunet-helper-dns")) + GNUNET_OS_check_helper_binary (binary)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("`%s' must be installed SUID, refusing to run\n"), - "gnunet-helper-dns"); + binary); global_ret = 1; + GNUNET_free (binary); return; } - + GNUNET_free (binary); stats = GNUNET_STATISTICS_create ("dns", cfg); nc = GNUNET_SERVER_notification_context_create (server, 1); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, cls); - if ( (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) && - ( (GNUNET_OK != + dns_exit = NULL; + if ( ( (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "DNS_EXIT", &dns_exit)) || ( (1 != inet_pton (AF_INET, dns_exit, &dns_exit4)) && (1 != inet_pton (AF_INET6, dns_exit, &dns_exit6)) ) ) ) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Configured to provide DNS exit, but no valid DNS server configured!\n")); + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "dns", "DNS_EXIT", + _("need a valid IPv4 or IPv6 address\n")); GNUNET_free_non_null (dns_exit); dns_exit = NULL; } - + dnsstub = GNUNET_DNSSTUB_start (dns_exit); helper_argv[0] = GNUNET_strdup ("gnunet-dns"); if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name)) @@ -1635,28 +1123,11 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, } helper_argv[5] = ipv4mask; helper_argv[6] = NULL; - - if (NULL != dns_exit) - { - static struct GNUNET_MESH_MessageHandler mesh_handlers[] = { - {&receive_dns_request, GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET, 0}, - {NULL, 0, 0} - }; - static GNUNET_MESH_ApplicationType mesh_types[] = { - GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER, - GNUNET_APPLICATION_TYPE_END - }; - mesh = GNUNET_MESH_connect (cfg, - 1, NULL, - &accept_dns_tunnel, - &destroy_dns_tunnel, - mesh_handlers, - mesh_types); - } - hijacker = GNUNET_HELPER_start ("gnunet-helper-dns", + hijacker = GNUNET_HELPER_start (GNUNET_NO, + "gnunet-helper-dns", helper_argv, &process_helper_messages, - NULL); + NULL, NULL); GNUNET_SERVER_add_handlers (server, handlers); GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL); } @@ -1672,6 +1143,25 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, int main (int argc, char *const *argv) { + /* make use of SGID capabilities on POSIX */ + /* FIXME: this might need a port on systems without 'getresgid' */ +#if HAVE_GETRESGID + gid_t rgid; + gid_t egid; + gid_t sgid; + + if (-1 == getresgid (&rgid, &egid, &sgid)) + { + fprintf (stderr, + "getresgid failed: %s\n", + strerror (errno)); + } + else if (sgid != rgid) + { + if (-1 == setregid (sgid, sgid)) + fprintf (stderr, "setregid failed: %s\n", strerror (errno)); + } +#endif return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? global_ret : 1; |