gpointer resp;
gsize resplen;
struct listener_data *ifdata;
+ gboolean append_domain;
};
struct listener_data {
{
unsigned char *ptr = buf;
char *offset;
+ int len;
DBG("query %s domain %s", query, domain);
tmp = strchr(offset, '.');
if (tmp == NULL) {
- if (strlen(offset) == 0)
+ len = strlen(offset);
+ if (len == 0)
break;
- *ptr = strlen(offset);
- memcpy(ptr + 1, offset, strlen(offset));
- ptr += strlen(offset) + 1;
+ *ptr = len;
+ memcpy(ptr + 1, offset, len);
+ ptr += len + 1;
break;
}
tmp = strchr(offset, '.');
if (tmp == NULL) {
- if (strlen(offset) == 0)
+ len = strlen(offset);
+ if (len == 0)
break;
- *ptr = strlen(offset);
- memcpy(ptr + 1, offset, strlen(offset));
- ptr += strlen(offset) + 1;
+ *ptr = len;
+ memcpy(ptr + 1, offset, len);
+ ptr += len + 1;
break;
}
if (dot != NULL && dot != lookup + strlen(lookup) - 1)
return 0;
+ if (server->domains != NULL && server->domains->data != NULL)
+ req->append_domain = TRUE;
+
for (list = server->domains; list; list = list->next) {
char *domain;
unsigned char alt[1024];
memcpy(alt + offset + altlen,
request + offset + altlen - domlen,
- req->request_len - altlen + domlen);
+ req->request_len - altlen - offset + domlen);
if (server->protocol == IPPROTO_TCP) {
- int req_len = req->request_len + domlen - 1;
+ int req_len = req->request_len + domlen - 2;
alt[0] = (req_len >> 8) & 0xff;
alt[1] = req_len & 0xff;
}
- err = send(sk, alt, req->request_len + domlen + 1, 0);
+ err = send(sk, alt, req->request_len + domlen, 0);
if (err < 0)
return -EIO;
req->numresp++;
if (hdr->rcode == 0 || req->resp == NULL) {
+
+ /*
+ * If the domain name was append
+ * remove it before forwarding the reply.
+ */
+ if (req->append_domain == TRUE) {
+ unsigned char *ptr;
+ uint8_t host_len;
+ unsigned int domain_len;
+
+ /*
+ * ptr points to the first char of the hostname.
+ * ->hostname.domain.net
+ */
+ ptr = reply + offset + sizeof(struct domain_hdr);
+ host_len = *ptr;
+ domain_len = strlen((const char *)ptr) - host_len - 1;
+
+ /*
+ * remove the domain name and replaced it by the end
+ * of reply.
+ */
+ memmove(ptr + host_len + 1,
+ ptr + host_len + domain_len + 1,
+ reply_len - (ptr - reply + domain_len));
+
+ reply_len = reply_len - domain_len;
+ }
+
g_free(req->resp);
req->resplen = 0;
req->numserv = 0;
req->ifdata = (struct listener_data *) ifdata;
+ req->append_domain = FALSE;
request_list = g_slist_append(request_list, req);
for (list = server_list; list; list = list->next) {
req->numserv = 0;
req->ifdata = (struct listener_data *) ifdata;
req->timeout = g_timeout_add_seconds(5, request_timeout, req);
+ req->append_domain = FALSE;
request_list = g_slist_append(request_list, req);
return resolv(req, buf, query);
}
-static int create_dns_listener(int protocol, const char *ifname)
+static int create_dns_listener(int protocol, struct listener_data *ifdata)
{
GIOChannel *channel;
const char *proto;
socklen_t slen;
int sk, type, v6only = 0;
int family = AF_INET6;
- struct listener_data *ifdata;
- DBG("interface %s", ifname);
- ifdata = g_hash_table_lookup(listener_table, ifname);
- if (ifdata == NULL)
- return -ENODEV;
+ DBG("interface %s", ifdata->ifname);
switch (protocol) {
case IPPROTO_UDP:
proto = "UDP";
- type = SOCK_DGRAM;
+ type = SOCK_DGRAM | SOCK_CLOEXEC;
break;
case IPPROTO_TCP:
proto = "TCP";
- type = SOCK_STREAM;
+ type = SOCK_STREAM | SOCK_CLOEXEC;
break;
default:
}
if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
- ifname, strlen(ifname) + 1) < 0) {
+ ifdata->ifname,
+ strlen(ifdata->ifname) + 1) < 0) {
connman_error("Failed to bind %s listener interface", proto);
close(sk);
return -EIO;
return 0;
}
-static void destroy_udp_listener(const char *interface)
+static void destroy_udp_listener(struct listener_data *ifdata)
{
- struct listener_data *ifdata;
-
- DBG("interface %s", interface);
-
- ifdata = g_hash_table_lookup(listener_table, interface);
- if (ifdata == NULL)
- return;
+ DBG("interface %s", ifdata->ifname);
if (ifdata->udp_listener_watch > 0)
g_source_remove(ifdata->udp_listener_watch);
g_io_channel_unref(ifdata->udp_listener_channel);
}
-static void destroy_tcp_listener(const char *interface)
+static void destroy_tcp_listener(struct listener_data *ifdata)
{
- struct listener_data *ifdata;
-
- DBG("interface %s", interface);
-
- ifdata = g_hash_table_lookup(listener_table, interface);
- if (ifdata == NULL)
- return;
+ DBG("interface %s", ifdata->ifname);
if (ifdata->tcp_listener_watch > 0)
g_source_remove(ifdata->tcp_listener_watch);
g_io_channel_unref(ifdata->tcp_listener_channel);
}
-static int create_listener(const char *interface)
+static int create_listener(struct listener_data *ifdata)
{
int err;
- err = create_dns_listener(IPPROTO_UDP, interface);
+ err = create_dns_listener(IPPROTO_UDP, ifdata);
if (err < 0)
return err;
- err = create_dns_listener(IPPROTO_TCP, interface);
+ err = create_dns_listener(IPPROTO_TCP, ifdata);
if (err < 0) {
- destroy_udp_listener(interface);
+ destroy_udp_listener(ifdata);
return err;
}
- if (g_strcmp0(interface, "lo") == 0)
+ if (g_strcmp0(ifdata->ifname, "lo") == 0)
__connman_resolvfile_append("lo", NULL, "127.0.0.1");
return 0;
}
-static void destroy_listener(const char *interface)
+static void destroy_listener(struct listener_data *ifdata)
{
GSList *list;
- if (interface == NULL)
- return;
-
- if (g_strcmp0(interface, "lo") == 0)
+ if (g_strcmp0(ifdata->ifname, "lo") == 0)
__connman_resolvfile_remove("lo", NULL, "127.0.0.1");
for (list = request_pending_list; list; list = list->next) {
g_slist_free(request_list);
request_list = NULL;
- destroy_tcp_listener(interface);
- destroy_udp_listener(interface);
+ destroy_tcp_listener(ifdata);
+ destroy_udp_listener(ifdata);
}
int __connman_dnsproxy_add_listener(const char *interface)
ifdata->tcp_listener_channel = NULL;
ifdata->tcp_listener_watch = 0;
- err = create_listener(interface);
+ err = create_listener(ifdata);
if (err < 0) {
connman_error("Couldn't create listener for %s err %d",
interface, err);
void __connman_dnsproxy_remove_listener(const char *interface)
{
+ struct listener_data *ifdata;
+
DBG("interface %s", interface);
- destroy_listener(interface);
+ ifdata = g_hash_table_lookup(listener_table, interface);
+ if (ifdata == NULL)
+ return;
+
+ destroy_listener(ifdata);
g_hash_table_remove(listener_table, interface);
}