summaryrefslogtreecommitdiff
path: root/src/dnsproxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dnsproxy.c')
-rw-r--r--src/dnsproxy.c92
1 files changed, 52 insertions, 40 deletions
diff --git a/src/dnsproxy.c b/src/dnsproxy.c
index bdd7fd5c..cf3490c4 100644
--- a/src/dnsproxy.c
+++ b/src/dnsproxy.c
@@ -215,10 +215,15 @@ static GSList *request_list = NULL;
static GHashTable *listener_table = NULL;
static time_t next_refresh;
static GHashTable *partial_tcp_req_table;
+static guint cache_timer = 0;
static guint16 get_id(void)
{
- return random();
+ uint64_t rand;
+
+ __connman_util_get_random(&rand);
+
+ return rand;
}
static int protocol_offset(int protocol)
@@ -526,6 +531,8 @@ static void destroy_request_data(struct request_data *req)
static gboolean request_timeout(gpointer user_data)
{
struct request_data *req = user_data;
+ struct sockaddr *sa;
+ int sk;
if (!req)
return FALSE;
@@ -533,47 +540,38 @@ static gboolean request_timeout(gpointer user_data)
DBG("id 0x%04x", req->srcid);
request_list = g_slist_remove(request_list, req);
- req->numserv--;
- if (req->resplen > 0 && req->resp) {
- int sk, err;
+ if (req->protocol == IPPROTO_UDP) {
+ sk = get_req_udp_socket(req);
+ sa = &req->sa;
+ } else if (req->protocol == IPPROTO_TCP) {
+ sk = req->client_sk;
+ sa = NULL;
+ } else
+ goto out;
- if (req->protocol == IPPROTO_UDP) {
- sk = get_req_udp_socket(req);
- if (sk < 0)
- return FALSE;
+ if (req->resplen > 0 && req->resp) {
+ /*
+ * Here we have received at least one reply (probably telling
+ * "not found" result), so send that back to client instead
+ * of more fatal server failed error.
+ */
+ if (sk >= 0)
+ sendto(sk, req->resp, req->resplen, MSG_NOSIGNAL,
+ sa, req->sa_len);
- err = sendto(sk, req->resp, req->resplen, MSG_NOSIGNAL,
- &req->sa, req->sa_len);
- } else {
- sk = req->client_sk;
- err = send(sk, req->resp, req->resplen, MSG_NOSIGNAL);
- if (err < 0)
- close(sk);
- }
- if (err < 0)
- return FALSE;
- } else if (req->request && req->numserv == 0) {
+ } else if (req->request) {
+ /*
+ * There was not reply from server at all.
+ */
struct domain_hdr *hdr;
- if (req->protocol == IPPROTO_TCP) {
- hdr = (void *) (req->request + 2);
- hdr->id = req->srcid;
- send_response(req->client_sk, req->request,
- req->request_len, NULL, 0, IPPROTO_TCP);
-
- } else if (req->protocol == IPPROTO_UDP) {
- int sk;
+ hdr = (void *)(req->request + protocol_offset(req->protocol));
+ hdr->id = req->srcid;
- hdr = (void *) (req->request);
- hdr->id = req->srcid;
-
- sk = get_req_udp_socket(req);
- if (sk >= 0)
- send_response(sk, req->request,
- req->request_len, &req->sa,
- req->sa_len, IPPROTO_UDP);
- }
+ if (sk >= 0)
+ send_response(sk, req->request, req->request_len,
+ sa, req->sa_len, req->protocol);
}
/*
@@ -586,6 +584,7 @@ static gboolean request_timeout(gpointer user_data)
GINT_TO_POINTER(req->client_sk));
}
+out:
req->timeout = 0;
destroy_request_data(req);
@@ -764,6 +763,8 @@ static void cache_element_destroy(gpointer value)
static gboolean try_remove_cache(gpointer user_data)
{
+ cache_timer = 0;
+
if (__sync_fetch_and_sub(&cache_refcount, 1) == 1) {
DBG("No cache users, removing it.");
@@ -2204,8 +2205,8 @@ static void destroy_server(struct server_data *server)
* without any good reason. The small delay allows the new RDNSS to
* create a new DNS server instance and the refcount does not go to 0.
*/
- if (cache)
- g_timeout_add_seconds(3, try_remove_cache, NULL);
+ if (cache && !cache_timer)
+ cache_timer = g_timeout_add_seconds(3, try_remove_cache, NULL);
g_free(server);
}
@@ -3460,6 +3461,9 @@ static bool udp_listener_event(GIOChannel *channel, GIOCondition condition,
return true;
}
+ req->name = g_strdup(query);
+ req->request = g_malloc(len);
+ memcpy(req->request, buf, len);
req->timeout = g_timeout_add_seconds(5, request_timeout, req);
request_list = g_slist_append(request_list, req);
@@ -3829,8 +3833,6 @@ int __connman_dnsproxy_init(void)
DBG("");
- srandom(time(NULL));
-
listener_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, g_free);
@@ -3862,6 +3864,16 @@ void __connman_dnsproxy_cleanup(void)
{
DBG("");
+ if (cache_timer) {
+ g_source_remove(cache_timer);
+ cache_timer = 0;
+ }
+
+ if (cache) {
+ g_hash_table_destroy(cache);
+ cache = NULL;
+ }
+
connman_notifier_unregister(&dnsproxy_notifier);
g_hash_table_foreach(listener_table, remove_listener, NULL);