From 576e766b593e86139454550c5f9121f1d5a3048e Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Thu, 17 Nov 2022 12:52:53 +0000 Subject: [PATCH 1/3] Fix struct hostinfo free code and BSD compile. 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. Signed-off-by: DL6ER --- src/dnsmasq/dbus.c | 4 ++-- src/dnsmasq/dnsmasq.h | 4 ++-- src/dnsmasq/option.c | 41 +++++++++++++++++++++++------------------ 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/dnsmasq/dbus.c b/src/dnsmasq/dbus.c index ef807111..fd5d1ca6 100644 --- a/src/dnsmasq/dbus.c +++ b/src/dnsmasq/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/dnsmasq.h b/src/dnsmasq/dnsmasq.h index c27b93f1..f91729cb 100644 --- a/src/dnsmasq/dnsmasq.h +++ b/src/dnsmasq/dnsmasq.h @@ -1300,9 +1300,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/dnsmasq/option.c b/src/dnsmasq/option.c index b511ef34..cccf4f66 100644 --- a/src/dnsmasq/option.c +++ b/src/dnsmasq/option.c @@ -864,11 +864,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) @@ -947,7 +952,7 @@ char *parse_server(char *arg, struct server_details *sdetails) above, and returns a pointer to the start of the list in . The items in the linked list are linked by the field. */ sdetails->valid = 1; - sdetails->resolved = 1; + sdetails->orig_hostinfo = sdetails->hostinfo; return NULL; } else @@ -971,7 +976,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); @@ -989,7 +994,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 @@ -1020,7 +1025,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) { @@ -1035,7 +1040,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 @@ -1102,12 +1107,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))) @@ -1165,8 +1170,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); } } @@ -1183,12 +1188,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))) @@ -1248,8 +1253,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); } } @@ -2970,12 +2975,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. */ @@ -3055,8 +3060,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; } From b7c858f6b596718ec72b105fde7575dcb07e8ba8 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Thu, 17 Nov 2022 19:51:15 +0000 Subject: [PATCH 2/3] Fix SEGV on --local= added by immediately previous commit. Signed-off-by: DL6ER --- src/dnsmasq/option.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/dnsmasq/option.c b/src/dnsmasq/option.c index cccf4f66..0ad660fd 100644 --- a/src/dnsmasq/option.c +++ b/src/dnsmasq/option.c @@ -870,10 +870,7 @@ char *parse_server(char *arg, struct server_details *sdetails) *sdetails->interface = 0; sdetails->addr_type = AF_UNSPEC; - sdetails->valid = 0; - sdetails->hostinfo = sdetails->orig_hostinfo = NULL; - - + if (strcmp(arg, "#") == 0) { if (sdetails->flags) @@ -1108,6 +1105,8 @@ static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int char interface[IF_NAMESIZE+1]; int count = 1, rem, addrbytes, addrbits; struct server_details sdetails; + + memset(&sdetails, 0, sizeof(struct server_details)); sdetails.addr = &serv_addr; sdetails.source_addr = &source_addr; sdetails.interface = interface; @@ -1189,6 +1188,8 @@ static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, in char interface[IF_NAMESIZE+1]; int count = 1, rem, addrbytes, addrbits; struct server_details sdetails; + + memset(&sdetails, 0, sizeof(struct server_details)); sdetails.addr = &serv_addr; sdetails.source_addr = &source_addr; sdetails.interface = interface; @@ -2974,13 +2975,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma union all_addr addr; union mysockaddr serv_addr, source_addr; char interface[IF_NAMESIZE+1]; - struct server_details sdetails; + + memset(&sdetails, 0, sizeof(struct server_details)); 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. */ From 128096e7107f5a9cf2ee5e6d93af2d650e1bc713 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 19 Nov 2022 08:17:49 +0100 Subject: [PATCH 3/3] Update embedded dnsmasq to v2.88rc3 Signed-off-by: DL6ER --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a8e731d0..95b08c70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,6 @@ cmake_minimum_required(VERSION 2.8.12) project(PIHOLE_FTL C) -set(DNSMASQ_VERSION pi-hole-v2.88rc1) +set(DNSMASQ_VERSION pi-hole-v2.88rc3) add_subdirectory(src)