am 7a12cb36: am 4e0ada97: Properly initialize struct irec pointers after malloc()
* commit '7a12cb364297118947f9ce9786f94a47eb710ce8':
Properly initialize struct irec pointers after malloc()
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index c4fda28..0b9dbd2 100755
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -321,6 +321,7 @@
union mysockaddr source_addr;
char interface[IF_NAMESIZE+1];
struct serverfd *next;
+ uint32_t mark;
};
struct randfd {
@@ -335,6 +336,7 @@
char *domain; /* set if this server only handles a domain. */
int flags, tcpfd;
unsigned int queries, failed_queries;
+ uint32_t mark;
struct server *next;
};
@@ -775,7 +777,7 @@
/* network.c */
int indextoname(int fd, int index, char *name);
-int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
+int local_bind(int fd, union mysockaddr *addr, char *intname, uint32_t mark, int is_tcp);
int random_sock(int family);
void pre_allocate_sfds(void);
int reload_servers(char *fname);
diff --git a/src/forward.c b/src/forward.c
index 40cda1c..a121123 100755
--- a/src/forward.c
+++ b/src/forward.c
@@ -318,8 +318,20 @@
daemon->rfd_save = forward->rfd4;
fd = forward->rfd4->fd;
}
+
+#ifdef ANDROID
+ // Mark the socket so it goes out on the correct network. Note
+ // that we never clear the mark, only re-set it the next time we
+ // allocate a new random fd. This is because we buffer DNS
+ // queries (in daemon->srv_save, daemon->packet_len) and socket
+ // file descriptors (in daemon->rfd_save) with the expectation of
+ // being able to use them again.
+ //
+ // Server fds are marked separately in allocate_sfd.
+ setsockopt(fd, SOL_SOCKET, SO_MARK, &start->mark, sizeof(start->mark));
+#endif
}
-
+
if (sendto(fd, (char *)header, plen, 0,
&start->addr.sa,
sa_len(&start->addr)) == -1)
@@ -815,7 +827,8 @@
if ((last_server->tcpfd == -1) &&
(last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
- (!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
+ (!local_bind(last_server->tcpfd, &last_server->source_addr,
+ last_server->interface, last_server->mark, 1) ||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
{
close(last_server->tcpfd);
diff --git a/src/network.c b/src/network.c
index e24ec3a..c7431df 100755
--- a/src/network.c
+++ b/src/network.c
@@ -481,6 +481,31 @@
}
/**
+ * If a listener has a struct irec pointer whose address matches the newly
+ * malloc()d struct irec's address, update its pointer to refer to this new
+ * struct irec instance.
+ *
+ * Otherwise, any listeners that are preserved across interface list changes
+ * will point at interface structures that are free()d at the end of
+ * set_interfaces(), and can get overwritten by subsequent memory allocations.
+ *
+ * See b/17475756 for further discussion.
+ */
+void fixup_possible_existing_listener(struct irec *new_iface) {
+ /* find the listener, if present */
+ struct listener *l;
+ for (l = daemon->listeners; l; l = l->next) {
+ struct irec *listener_iface = l->iface;
+ if (listener_iface) {
+ if (sockaddr_isequal(&listener_iface->addr, &new_iface->addr)) {
+ l->iface = new_iface;
+ return;
+ }
+ }
+ }
+}
+
+/**
* Close the sockets listening on the given interface
*
* This new function is needed as we're dynamically changing the interfaces
@@ -682,7 +707,7 @@
}
-int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
+int local_bind(int fd, union mysockaddr *addr, char *intname, uint32_t mark, int is_tcp)
{
union mysockaddr addr_copy = *addr;
@@ -706,10 +731,13 @@
return 0;
#endif
+ if (mark != 0 && setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) == -1)
+ return 0;
+
return 1;
}
-static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
+static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname, uint32_t mark)
{
struct serverfd *sfd;
int errsave;
@@ -736,6 +764,7 @@
/* may have a suitable one already */
for (sfd = daemon->sfds; sfd; sfd = sfd->next )
if (sockaddr_isequal(&sfd->source_addr, addr) &&
+ mark == sfd->mark &&
strcmp(intname, sfd->interface) == 0)
return sfd;
@@ -750,7 +779,7 @@
return NULL;
}
- if (!local_bind(sfd->fd, addr, intname, 0) || !fix_fd(sfd->fd))
+ if (!local_bind(sfd->fd, addr, intname, mark, 0) || !fix_fd(sfd->fd))
{
errsave = errno; /* save error from bind. */
close(sfd->fd);
@@ -761,6 +790,7 @@
strcpy(sfd->interface, intname);
sfd->source_addr = *addr;
+ sfd->mark = mark;
sfd->next = daemon->sfds;
daemon->sfds = sfd;
return sfd;
@@ -782,7 +812,7 @@
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in.sin_len = sizeof(struct sockaddr_in);
#endif
- allocate_sfd(&addr, "");
+ allocate_sfd(&addr, "", 0);
#ifdef HAVE_IPV6
memset(&addr, 0, sizeof(addr));
addr.in6.sin6_family = AF_INET6;
@@ -791,13 +821,13 @@
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif
- allocate_sfd(&addr, "");
+ allocate_sfd(&addr, "", 0);
#endif
}
for (srv = daemon->servers; srv; srv = srv->next)
if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
- !allocate_sfd(&srv->source_addr, srv->interface) &&
+ !allocate_sfd(&srv->source_addr, srv->interface, srv->mark) &&
errno != 0 &&
(daemon->options & OPT_NOWILD))
{
@@ -847,7 +877,7 @@
/* Do we need a socket set? */
if (!new->sfd &&
- !(new->sfd = allocate_sfd(&new->source_addr, new->interface)) &&
+ !(new->sfd = allocate_sfd(&new->source_addr, new->interface, new->mark)) &&
errno != 0)
{
my_syslog(LOG_WARNING,
@@ -919,7 +949,7 @@
strncpy(s, interfaces, sizeof(s));
while((interface = strsep(&next, ":"))) {
if_tmp = safe_malloc(sizeof(struct iname));
- memset(if_tmp, sizeof(struct iname), 0);
+ memset(if_tmp, 0, sizeof(struct iname));
if ((if_tmp->name = strdup(interface)) == NULL) {
die(_("malloc failure in set_interfaces: %s"), NULL, EC_BADNET);
}
@@ -942,11 +972,14 @@
int found = 0;
for (new_iface = daemon->interfaces; new_iface; new_iface = new_iface->next) {
if (sockaddr_isequal(&old_iface->addr, &new_iface->addr)) {
- found = -1;
+ found = 1;
break;
}
}
- if (!found) {
+
+ if (found) {
+ fixup_possible_existing_listener(new_iface);
+ } else {
#ifdef __ANDROID_DEBUG__
char debug_buff[MAXDNAME];
prettyprint_addr(&old_iface->addr, debug_buff);
@@ -1001,7 +1034,9 @@
}
/*
- * Takes a string in the format "1.2.3.4:1.2.3.4:..." - up to 1024 bytes in length
+ * Takes a string in the format "0x100b:1.2.3.4:1.2.3.4:..." - up to 1024 bytes in length
+ * - The first element is the socket mark to set on sockets that forward DNS queries.
+ * - The subsequent elements are the DNS servers to forward queries to.
*/
int set_servers(const char *servers)
{
@@ -1009,6 +1044,8 @@
struct server *old_servers = NULL;
struct server *new_servers = NULL;
struct server *serv;
+ char *mark_string;
+ uint32_t mark;
strncpy(s, servers, sizeof(s));
@@ -1033,10 +1070,14 @@
serv = tmp;
}
- char *next = s;
- char *saddr;
+ char *next = s;
+ char *saddr;
- while ((saddr = strsep(&next, ":"))) {
+ /* Parse the mark. */
+ mark_string = strsep(&next, ":");
+ mark = strtoul(mark_string, NULL, 0);
+
+ while ((saddr = strsep(&next, ":"))) {
union mysockaddr addr, source_addr;
memset(&addr, 0, sizeof(addr));
memset(&source_addr, 0, sizeof(source_addr));
@@ -1082,6 +1123,7 @@
serv->source_addr = source_addr;
serv->domain = NULL;
serv->interface[0] = 0;
+ serv->mark = mark;
serv->sfd = NULL;
serv->flags = SERV_FROM_RESOLV;
serv->queries = serv->failed_queries = 0;
@@ -1195,6 +1237,7 @@
serv->source_addr = source_addr;
serv->domain = NULL;
serv->interface[0] = 0;
+ serv->mark = 0;
serv->sfd = NULL;
serv->flags = SERV_FROM_RESOLV;
serv->queries = serv->failed_queries = 0;