summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2022-11-17 12:52:53 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2022-11-17 13:16:55 +0000
commit7f227a83f225cf171425f94395cda7d43a2b6ba4 (patch)
tree0c6eb99cddd3a35741c578acb2cfd5968be0b249
parent9ed3ee67ecd2a388d319bff116b27bcc62286ccc (diff)
downloaddnsmasq-7f227a83f225cf171425f94395cda7d43a2b6ba4.tar.gz
Fix struct hostinfo free code and BSD compile.v2.88rc2
The code added in6 c596f1cc1d92b2b90ef5ce043ace314eefa868b fails to free the returned datastructures from gethostinfo() because sdetails.hostinfo is used to loop through the addresses and ends up NULL. In some libc implementations this results in a SEGV when freeaddrinfo() is called. Also fix FTBFS under BSD. Thanks to Johnny S. Lee for the bug report.
-rw-r--r--src/dbus.c4
-rw-r--r--src/dnsmasq.h4
-rw-r--r--src/option.c41
3 files changed, 27 insertions, 22 deletions
diff --git a/src/dbus.c b/src/dbus.c
index ef80711..fd5d1ca 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -461,8 +461,8 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
} while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
}
- if (sdetails.resolved)
- freeaddrinfo(sdetails.hostinfo);
+ if (sdetails.orig_hostinfo)
+ freeaddrinfo(sdetails.orig_hostinfo);
/* jump to next element in outer array */
dbus_message_iter_next(&array_iter);
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 7b59823..90dc986 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1295,9 +1295,9 @@ extern struct daemon {
struct server_details {
union mysockaddr *addr, *source_addr;
- struct addrinfo *hostinfo;
+ struct addrinfo *hostinfo, *orig_hostinfo;
char *interface, *source, *scope_id, *interface_opt;
- int serv_port, source_port, addr_type, scope_index, valid, resolved;
+ int serv_port, source_port, addr_type, scope_index, valid;
u16 *flags;
};
diff --git a/src/option.c b/src/option.c
index 06030c5..9692f3c 100644
--- a/src/option.c
+++ b/src/option.c
@@ -860,11 +860,16 @@ char *parse_server(char *arg, struct server_details *sdetails)
sdetails->serv_port = NAMESERVER_PORT;
char *portno;
int ecode = 0;
- struct addrinfo hints = { 0 };
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(struct addrinfo));
+
*sdetails->interface = 0;
sdetails->addr_type = AF_UNSPEC;
+ sdetails->valid = 0;
+ sdetails->hostinfo = sdetails->orig_hostinfo = NULL;
+
if (strcmp(arg, "#") == 0)
{
if (sdetails->flags)
@@ -943,7 +948,7 @@ char *parse_server(char *arg, struct server_details *sdetails)
above, and returns a pointer to the start of the list in <hostinfo>.
The items in the linked list are linked by the <ai_next> field. */
sdetails->valid = 1;
- sdetails->resolved = 1;
+ sdetails->orig_hostinfo = sdetails->hostinfo;
return NULL;
}
else
@@ -967,7 +972,7 @@ char *parse_server_addr(struct server_details *sdetails)
sdetails->addr->in.sin_port = htons(sdetails->serv_port);
sdetails->addr->sa.sa_family = sdetails->source_addr->sa.sa_family = AF_INET;
#ifdef HAVE_SOCKADDR_SA_LEN
- source_addr->in.sin_len = addr->in.sin_len = sizeof(struct sockaddr_in);
+ sdetails->source_addr->in.sin_len = sdetails->addr->in.sin_len = sizeof(struct sockaddr_in);
#endif
sdetails->source_addr->in.sin_addr.s_addr = INADDR_ANY;
sdetails->source_addr->in.sin_port = htons(daemon->query_port);
@@ -985,7 +990,7 @@ char *parse_server_addr(struct server_details *sdetails)
/* When resolving a server IP by hostname, we can simply skip mismatching
server / source IP pairs. Otherwise, when an IP address is given directly,
this is a fatal error. */
- if (!sdetails->resolved)
+ if (!sdetails->orig_hostinfo)
return _("cannot use IPv4 server address with IPv6 source address");
}
else
@@ -1016,7 +1021,7 @@ char *parse_server_addr(struct server_details *sdetails)
sdetails->addr->sa.sa_family = sdetails->source_addr->sa.sa_family = AF_INET6;
sdetails->addr->in6.sin6_flowinfo = sdetails->source_addr->in6.sin6_flowinfo = 0;
#ifdef HAVE_SOCKADDR_SA_LEN
- sdetails->addr->in6.sin6_len = sdetails->source_addr->in6.sin6_len = sizeof(addr->in6);
+ sdetails->addr->in6.sin6_len = sdetails->source_addr->in6.sin6_len = sizeof(sdetails->addr->in6);
#endif
if (sdetails->source)
{
@@ -1031,7 +1036,7 @@ char *parse_server_addr(struct server_details *sdetails)
/* When resolving a server IP by hostname, we can simply skip mismatching
server / source IP pairs. Otherwise, when an IP address is given directly,
this is a fatal error. */
- if(!sdetails->resolved)
+ if(!sdetails->orig_hostinfo)
return _("cannot use IPv6 server address with IPv4 source address");
}
else
@@ -1098,12 +1103,12 @@ static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int
union mysockaddr serv_addr, source_addr;
char interface[IF_NAMESIZE+1];
int count = 1, rem, addrbytes, addrbits;
- struct server_details sdetails = { 0 };
+ struct server_details sdetails;
sdetails.addr = &serv_addr;
sdetails.source_addr = &source_addr;
sdetails.interface = interface;
sdetails.flags = &flags;
-
+
if (!server)
flags = SERV_LITERAL_ADDRESS;
else if ((string = parse_server(server, &sdetails)))
@@ -1161,8 +1166,8 @@ static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int
return _("error");
}
- if (sdetails.resolved)
- freeaddrinfo(sdetails.hostinfo);
+ if (sdetails.orig_hostinfo)
+ freeaddrinfo(sdetails.orig_hostinfo);
}
}
@@ -1179,12 +1184,12 @@ static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, in
union mysockaddr serv_addr, source_addr;
char interface[IF_NAMESIZE+1];
int count = 1, rem, addrbytes, addrbits;
- struct server_details sdetails = { 0 };
+ struct server_details sdetails;
sdetails.addr = &serv_addr;
sdetails.source_addr = &source_addr;
sdetails.interface = interface;
sdetails.flags = &flags;
-
+
if (!server)
flags = SERV_LITERAL_ADDRESS;
else if ((string = parse_server(server, &sdetails)))
@@ -1244,8 +1249,8 @@ static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, in
return _("error");
}
- if (sdetails.resolved)
- freeaddrinfo(sdetails.hostinfo);
+ if (sdetails.orig_hostinfo)
+ freeaddrinfo(sdetails.orig_hostinfo);
}
}
@@ -2966,12 +2971,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
union mysockaddr serv_addr, source_addr;
char interface[IF_NAMESIZE+1];
- struct server_details sdetails = { 0 };
+ struct server_details sdetails;
sdetails.addr = &serv_addr;
sdetails.source_addr = &source_addr;
sdetails.interface = interface;
sdetails.flags = &flags;
-
+
unhide_metas(arg);
/* split the domain args, if any and skip to the end of them. */
@@ -3051,8 +3056,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break;
}
- if (sdetails.resolved)
- freeaddrinfo(sdetails.hostinfo);
+ if (sdetails.orig_hostinfo)
+ freeaddrinfo(sdetails.orig_hostinfo);
break;
}