summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2010-07-26 12:13:41 +0200
committerSamuel Ortiz <sameo@linux.intel.com>2010-07-26 12:21:41 +0200
commit27118ae27ead53ab927f08173038c2f2498da9ce (patch)
tree235604e63d8042ba92aec1c22ccadccc12687186 /plugins
parenta7410b7b879e3875096f33452506fa521e0b3917 (diff)
downloadconnman-27118ae27ead53ab927f08173038c2f2498da9ce.tar.gz
connman-27118ae27ead53ab927f08173038c2f2498da9ce.tar.bz2
connman-27118ae27ead53ab927f08173038c2f2498da9ce.zip
dnsproxy flush method implementation
Diffstat (limited to 'plugins')
-rw-r--r--plugins/dnsproxy.c312
1 files changed, 181 insertions, 131 deletions
diff --git a/plugins/dnsproxy.c b/plugins/dnsproxy.c
index 2cb2f41f..5368ceb6 100644
--- a/plugins/dnsproxy.c
+++ b/plugins/dnsproxy.c
@@ -92,12 +92,16 @@ struct request_data {
guint timeout;
guint numserv;
guint numresp;
+ gpointer request;
+ gsize request_len;
+ gpointer name;
gpointer resp;
gsize resplen;
};
static GSList *server_list = NULL;
static GSList *request_list = NULL;
+static GSList *request_pending_list = NULL;
static guint16 request_id = 0x0000;
static GIOChannel *listener_channel = NULL;
@@ -297,6 +301,144 @@ static void destroy_server(struct server_data *data)
g_free(data);
}
+static int append_query(unsigned char *buf, unsigned int size,
+ const char *query, const char *domain)
+{
+ unsigned char *ptr = buf;
+ char *offset;
+
+ DBG("query %s domain %s", query, domain);
+
+ offset = (char *) query;
+ while (offset != NULL) {
+ char *tmp;
+
+ tmp = strchr(offset, '.');
+ if (tmp == NULL) {
+ if (strlen(offset) == 0)
+ break;
+ *ptr = strlen(offset);
+ memcpy(ptr + 1, offset, strlen(offset));
+ ptr += strlen(offset) + 1;
+ break;
+ }
+
+ *ptr = tmp - offset;
+ memcpy(ptr + 1, offset, tmp - offset);
+ ptr += tmp - offset + 1;
+
+ offset = tmp + 1;
+ }
+
+ offset = (char *) domain;
+ while (offset != NULL) {
+ char *tmp;
+
+ tmp = strchr(offset, '.');
+ if (tmp == NULL) {
+ if (strlen(offset) == 0)
+ break;
+ *ptr = strlen(offset);
+ memcpy(ptr + 1, offset, strlen(offset));
+ ptr += strlen(offset) + 1;
+ break;
+ }
+
+ *ptr = tmp - offset;
+ memcpy(ptr + 1, offset, tmp - offset);
+ ptr += tmp - offset + 1;
+
+ offset = tmp + 1;
+ }
+
+ *ptr++ = 0x00;
+
+ return ptr - buf;
+}
+
+static gboolean request_timeout(gpointer user_data)
+{
+ struct request_data *req = user_data;
+
+ DBG("id 0x%04x", req->srcid);
+
+ request_list = g_slist_remove(request_list, req);
+
+ if (req->resplen > 0 && req->resp != NULL) {
+ int sk, err;
+
+ sk = g_io_channel_unix_get_fd(listener_channel);
+
+ err = sendto(sk, req->resp, req->resplen, 0,
+ (struct sockaddr *) &req->sin, req->len);
+ }
+
+ g_free(req->resp);
+ g_free(req);
+
+ return FALSE;
+}
+
+static gboolean resolv(struct request_data *req,
+ gpointer request, gpointer name)
+{
+ int sk, err;
+ GSList *list;
+
+ request_list = g_slist_append(request_list, req);
+
+ req->numserv = 0;
+ req->timeout = g_timeout_add_seconds(5, request_timeout, req);
+
+ for (list = server_list; list; list = list->next) {
+ struct server_data *data = list->data;
+
+ DBG("server %s domain %s enabled %d",
+ data->server, data->domain, data->enabled);
+
+ if (data->enabled == FALSE)
+ continue;
+
+ sk = g_io_channel_unix_get_fd(data->channel);
+
+ err = send(sk, request, req->request_len, 0);
+
+ req->numserv++;
+
+ if (data->domain != NULL) {
+ unsigned char alt[1024];
+ struct domain_hdr *hdr = (void *) &alt;
+ int altlen, domlen;
+
+ domlen = strlen(data->domain) + 1;
+ if (domlen < 5)
+ continue;
+
+ alt[0] = req->altid & 0xff;
+ alt[1] = req->altid >> 8;
+
+ memcpy(alt + 2, request + 2, 10);
+ hdr->qdcount = htons(1);
+
+ altlen = append_query(alt + 12, sizeof(alt) - 12,
+ name, data->domain);
+ if (altlen < 0)
+ continue;
+
+ altlen += 12;
+
+ memcpy(alt + altlen, request + altlen - domlen,
+ req->request_len - altlen + domlen);
+
+ err = send(sk, alt, req->request_len + domlen + 1, 0);
+
+ req->numserv++;
+ }
+ }
+
+ return TRUE;
+}
+
static int dnsproxy_append(const char *interface, const char *domain,
const char *server)
{
@@ -337,11 +479,30 @@ static int dnsproxy_remove(const char *interface, const char *domain,
return 0;
}
+static void dnsproxy_flush(void)
+{
+ GSList *list;
+
+ list = request_pending_list;
+ while (list) {
+ struct request_data *req = list->data;
+
+ list = list->next;
+
+ request_pending_list =
+ g_slist_remove(request_pending_list, req);
+ resolv(req, req->request, req->name);
+ g_free(req->request);
+ g_free(req->name);
+ }
+}
+
static struct connman_resolver dnsproxy_resolver = {
.name = "dnsproxy",
.priority = CONNMAN_RESOLVER_PRIORITY_HIGH,
.append = dnsproxy_append,
.remove = dnsproxy_remove,
+ .flush = dnsproxy_flush,
};
static void dnsproxy_offline_mode(connman_bool_t enabled)
@@ -496,88 +657,9 @@ static void send_response(int sk, unsigned char *buf, int len,
err = sendto(sk, buf, len, 0, to, tolen);
}
-static int append_query(unsigned char *buf, unsigned int size,
- const char *query, const char *domain)
-{
- unsigned char *ptr = buf;
- char *offset;
-
- DBG("query %s domain %s", query, domain);
-
- offset = (char *) query;
- while (offset != NULL) {
- char *tmp;
-
- tmp = strchr(offset, '.');
- if (tmp == NULL) {
- if (strlen(offset) == 0)
- break;
- *ptr = strlen(offset);
- memcpy(ptr + 1, offset, strlen(offset));
- ptr += strlen(offset) + 1;
- break;
- }
-
- *ptr = tmp - offset;
- memcpy(ptr + 1, offset, tmp - offset);
- ptr += tmp - offset + 1;
-
- offset = tmp + 1;
- }
-
- offset = (char *) domain;
- while (offset != NULL) {
- char *tmp;
-
- tmp = strchr(offset, '.');
- if (tmp == NULL) {
- if (strlen(offset) == 0)
- break;
- *ptr = strlen(offset);
- memcpy(ptr + 1, offset, strlen(offset));
- ptr += strlen(offset) + 1;
- break;
- }
-
- *ptr = tmp - offset;
- memcpy(ptr + 1, offset, tmp - offset);
- ptr += tmp - offset + 1;
-
- offset = tmp + 1;
- }
-
- *ptr++ = 0x00;
-
- return ptr - buf;
-}
-
-static gboolean request_timeout(gpointer user_data)
-{
- struct request_data *req = user_data;
-
- DBG("id 0x%04x", req->srcid);
-
- request_list = g_slist_remove(request_list, req);
-
- if (req->resplen > 0 && req->resp != NULL) {
- int sk, err;
-
- sk = g_io_channel_unix_get_fd(listener_channel);
-
- err = sendto(sk, req->resp, req->resplen, 0,
- (struct sockaddr *) &req->sin, req->len);
- }
-
- g_free(req->resp);
- g_free(req);
-
- return FALSE;
-}
-
static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
gpointer user_data)
{
- GSList *list;
unsigned char buf[768];
char query[512];
struct request_data *req;
@@ -621,62 +703,12 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
req->srcid = buf[0] | (buf[1] << 8);
req->dstid = request_id;
req->altid = request_id + 1;
+ req->request_len = len;
buf[0] = req->dstid & 0xff;
buf[1] = req->dstid >> 8;
- request_list = g_slist_append(request_list, req);
-
- req->numserv = 0;
- req->timeout = g_timeout_add_seconds(5, request_timeout, req);
-
- for (list = server_list; list; list = list->next) {
- struct server_data *data = list->data;
-
- DBG("server %s domain %s enabled %d",
- data->server, data->domain, data->enabled);
-
- if (data->enabled == FALSE)
- continue;
-
- sk = g_io_channel_unix_get_fd(data->channel);
-
- err = send(sk, buf, len, 0);
-
- req->numserv++;
-
- if (data->domain != NULL) {
- unsigned char alt[1024];
- struct domain_hdr *hdr = (void *) &alt;
- int altlen, domlen;
-
- domlen = strlen(data->domain) + 1;
- if (domlen < 5)
- continue;
-
- alt[0] = req->altid & 0xff;
- alt[1] = req->altid >> 8;
-
- memcpy(alt + 2, buf + 2, 10);
- hdr->qdcount = htons(1);
-
- altlen = append_query(alt + 12, sizeof(alt) - 12,
- query, data->domain);
- if (altlen < 0)
- continue;
-
- altlen += 12;
-
- memcpy(alt + altlen, buf + altlen - domlen,
- len - altlen + domlen);
-
- err = send(sk, alt, len + domlen + 1, 0);
-
- req->numserv++;
- }
- }
-
- return TRUE;
+ return resolv(req, buf, query);
}
static int create_listener(void)
@@ -743,6 +775,22 @@ static void destroy_listener(void)
if (listener_watch > 0)
g_source_remove(listener_watch);
+ for (list = request_pending_list; list; list = list->next) {
+ struct request_data *req = list->data;
+
+ DBG("Dropping pending request (id 0x%04x -> 0x%04x)",
+ req->srcid, req->dstid);
+
+ g_free(req->resp);
+ g_free(req->request);
+ g_free(req->name);
+ g_free(req);
+ list->data = NULL;
+ }
+
+ g_slist_free(request_pending_list);
+ request_pending_list = NULL;
+
for (list = request_list; list; list = list->next) {
struct request_data *req = list->data;
@@ -750,6 +798,8 @@ static void destroy_listener(void)
req->srcid, req->dstid);
g_free(req->resp);
+ g_free(req->request);
+ g_free(req->name);
g_free(req);
list->data = NULL;
}