January
parent
21945b75e0
commit
99b545bc28
|
@ -1,639 +0,0 @@
|
||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Tom Marshall <tdm@cyngn.com>
|
|
||||||
Date: Fri, 17 Jun 2016 16:38:12 -0700
|
|
||||||
Subject: [PATCH] bionic: Sort and cache hosts file data for fast lookup
|
|
||||||
|
|
||||||
The hosts file is normally searched linearly. This is very slow when
|
|
||||||
the file is large. To mitigate this, read the hosts file and sort the
|
|
||||||
entries in an in-memory cache. When an address is requested via
|
|
||||||
gethostbyname or getaddrinfo, binary search the cache.
|
|
||||||
|
|
||||||
In case where the cache is not available, return a suitable error code
|
|
||||||
and fall back to the existing lookup code.
|
|
||||||
|
|
||||||
This has been written to behave as much like the existing lookup code as
|
|
||||||
possible. But note bionic and glibc differ in behavior for some corner
|
|
||||||
cases. Choose the most standard compliant behavior for these where
|
|
||||||
possible. Otherwise choose the behavior that seems most reasonable.
|
|
||||||
|
|
||||||
RM-290
|
|
||||||
|
|
||||||
Change-Id: I3b322883cbc48b0d76a0ce9d149b59faaac1dc58
|
|
||||||
(cherry picked from commit ed4c3a6bd449a4ed70645071a440ae146f194116)
|
|
||||||
---
|
|
||||||
libc/dns/net/getaddrinfo.c | 10 +
|
|
||||||
libc/dns/net/hosts_cache.c | 520 +++++++++++++++++++++++++++++++++++++
|
|
||||||
libc/dns/net/hosts_cache.h | 23 ++
|
|
||||||
libc/dns/net/sethostent.c | 7 +
|
|
||||||
4 files changed, 560 insertions(+)
|
|
||||||
create mode 100644 libc/dns/net/hosts_cache.c
|
|
||||||
create mode 100644 libc/dns/net/hosts_cache.h
|
|
||||||
|
|
||||||
diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
|
|
||||||
index d0c11d2b0..cc94b21e2 100644
|
|
||||||
--- a/libc/dns/net/getaddrinfo.c
|
|
||||||
+++ b/libc/dns/net/getaddrinfo.c
|
|
||||||
@@ -109,6 +109,8 @@
|
|
||||||
#include "nsswitch.h"
|
|
||||||
#include "private/bionic_defs.h"
|
|
||||||
|
|
||||||
+#include "hosts_cache.h"
|
|
||||||
+
|
|
||||||
typedef union sockaddr_union {
|
|
||||||
struct sockaddr generic;
|
|
||||||
struct sockaddr_in in;
|
|
||||||
@@ -2125,6 +2127,14 @@ _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
|
|
||||||
name = va_arg(ap, char *);
|
|
||||||
pai = va_arg(ap, struct addrinfo *);
|
|
||||||
|
|
||||||
+ memset(&sentinel, 0, sizeof(sentinel));
|
|
||||||
+ cur = &sentinel;
|
|
||||||
+ int gai_error = hc_getaddrinfo(name, NULL, pai, &cur);
|
|
||||||
+ if (gai_error != EAI_SYSTEM) {
|
|
||||||
+ *((struct addrinfo **)rv) = sentinel.ai_next;
|
|
||||||
+ return (gai_error == 0 ? NS_SUCCESS : NS_NOTFOUND);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
// fprintf(stderr, "_files_getaddrinfo() name = '%s'\n", name);
|
|
||||||
memset(&sentinel, 0, sizeof(sentinel));
|
|
||||||
cur = &sentinel;
|
|
||||||
diff --git a/libc/dns/net/hosts_cache.c b/libc/dns/net/hosts_cache.c
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000..52d29e032
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/libc/dns/net/hosts_cache.c
|
|
||||||
@@ -0,0 +1,520 @@
|
|
||||||
+/*
|
|
||||||
+ * Copyright (C) 2016 The CyanogenMod Project
|
|
||||||
+ *
|
|
||||||
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
+ * you may not use this file except in compliance with the License.
|
|
||||||
+ * You may obtain a copy of the License at
|
|
||||||
+ *
|
|
||||||
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
+ *
|
|
||||||
+ * Unless required by applicable law or agreed to in writing, software
|
|
||||||
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
+ * See the License for the specific language governing permissions and
|
|
||||||
+ * limitations under the License.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <fcntl.h>
|
|
||||||
+#include <netdb.h>
|
|
||||||
+#include <stdio.h>
|
|
||||||
+#include <stdlib.h>
|
|
||||||
+#include <string.h>
|
|
||||||
+#include <ctype.h>
|
|
||||||
+#include <strings.h>
|
|
||||||
+#include <sys/file.h>
|
|
||||||
+#include <sys/mman.h>
|
|
||||||
+#include <sys/socket.h>
|
|
||||||
+#include <sys/stat.h>
|
|
||||||
+#include <sys/types.h>
|
|
||||||
+#include <unistd.h>
|
|
||||||
+#include <utime.h>
|
|
||||||
+#include <pthread.h>
|
|
||||||
+
|
|
||||||
+#include <netinet/in6.h>
|
|
||||||
+#include <arpa/inet.h>
|
|
||||||
+
|
|
||||||
+#include "hostent.h"
|
|
||||||
+#include "resolv_private.h"
|
|
||||||
+
|
|
||||||
+#define MAX_ADDRLEN (INET6_ADDRSTRLEN - (1 + 5))
|
|
||||||
+#define MAX_HOSTLEN MAXHOSTNAMELEN
|
|
||||||
+
|
|
||||||
+#define ESTIMATED_LINELEN 32
|
|
||||||
+#define HCFILE_ALLOC_SIZE 256
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Host cache entry for hcfile.c_data.
|
|
||||||
+ * Offsets are into hcfile.h_data.
|
|
||||||
+ * Strings are *not* terminated by NULL, but by whitespace (isspace) or '#'.
|
|
||||||
+ * Use hstr* functions with these.
|
|
||||||
+ */
|
|
||||||
+struct hcent
|
|
||||||
+{
|
|
||||||
+ uint32_t addr;
|
|
||||||
+ uint32_t name;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Overall host cache file state.
|
|
||||||
+ */
|
|
||||||
+struct hcfile
|
|
||||||
+{
|
|
||||||
+ int h_fd;
|
|
||||||
+ struct stat h_st;
|
|
||||||
+ char *h_data;
|
|
||||||
+
|
|
||||||
+ uint32_t c_alloc;
|
|
||||||
+ uint32_t c_len;
|
|
||||||
+ struct hcent *c_data;
|
|
||||||
+};
|
|
||||||
+static struct hcfile hcfile;
|
|
||||||
+static pthread_mutex_t hclock = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
+
|
|
||||||
+static size_t hstrlen(const char *s)
|
|
||||||
+{
|
|
||||||
+ const char *p = s;
|
|
||||||
+ while (*p && *p != '#' && !isspace(*p))
|
|
||||||
+ ++p;
|
|
||||||
+ return p - s;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int hstrcmp(const char *a, const char *b)
|
|
||||||
+{
|
|
||||||
+ size_t alen = hstrlen(a);
|
|
||||||
+ size_t blen = hstrlen(b);
|
|
||||||
+ int res = strncmp(a, b, MIN(alen, blen));
|
|
||||||
+ if (res == 0)
|
|
||||||
+ res = alen - blen;
|
|
||||||
+ return res;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static char *hstrcpy(char *dest, const char *src)
|
|
||||||
+{
|
|
||||||
+ size_t len = hstrlen(src);
|
|
||||||
+ memcpy(dest, src, len);
|
|
||||||
+ dest[len] = '\0';
|
|
||||||
+ return dest;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static char *hstrdup(const char *s)
|
|
||||||
+{
|
|
||||||
+ size_t len = hstrlen(s);
|
|
||||||
+ char *dest = (char *)malloc(len + 1);
|
|
||||||
+ if (!dest)
|
|
||||||
+ return NULL;
|
|
||||||
+ memcpy(dest, s, len);
|
|
||||||
+ dest[len] = '\0';
|
|
||||||
+ return dest;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int cmp_hcent_name(const void *a, const void *b)
|
|
||||||
+{
|
|
||||||
+ struct hcent *ea = (struct hcent *)a;
|
|
||||||
+ const char *na = hcfile.h_data + ea->name;
|
|
||||||
+ struct hcent *eb = (struct hcent *)b;
|
|
||||||
+ const char *nb = hcfile.h_data + eb->name;
|
|
||||||
+
|
|
||||||
+ return hstrcmp(na, nb);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct hcent *_hcfindname(const char *name)
|
|
||||||
+{
|
|
||||||
+ size_t first, last, mid;
|
|
||||||
+ struct hcent *cur = NULL;
|
|
||||||
+ int cmp;
|
|
||||||
+
|
|
||||||
+ if (hcfile.c_len == 0)
|
|
||||||
+ return NULL;
|
|
||||||
+
|
|
||||||
+ first = 0;
|
|
||||||
+ last = hcfile.c_len - 1;
|
|
||||||
+ mid = (first + last) / 2;
|
|
||||||
+ while (first <= last) {
|
|
||||||
+ cur = hcfile.c_data + mid;
|
|
||||||
+ cmp = hstrcmp(hcfile.h_data + cur->name, name);
|
|
||||||
+ if (cmp == 0)
|
|
||||||
+ goto found;
|
|
||||||
+ if (cmp < 0)
|
|
||||||
+ first = mid + 1;
|
|
||||||
+ else {
|
|
||||||
+ if (mid > 0)
|
|
||||||
+ last = mid - 1;
|
|
||||||
+ else
|
|
||||||
+ return NULL;
|
|
||||||
+ }
|
|
||||||
+ mid = (first + last) / 2;
|
|
||||||
+ }
|
|
||||||
+ return NULL;
|
|
||||||
+
|
|
||||||
+found:
|
|
||||||
+ while (cur > hcfile.c_data) {
|
|
||||||
+ struct hcent *prev = cur - 1;
|
|
||||||
+ cmp = cmp_hcent_name(cur, prev);
|
|
||||||
+ if (cmp)
|
|
||||||
+ break;
|
|
||||||
+ cur = prev;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return cur;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Find next name on line, if any.
|
|
||||||
+ *
|
|
||||||
+ * Assumes that line is terminated by LF.
|
|
||||||
+ */
|
|
||||||
+static const char *_hcnextname(const char *name)
|
|
||||||
+{
|
|
||||||
+ while (!isspace(*name)) {
|
|
||||||
+ if (*name == '#')
|
|
||||||
+ return NULL;
|
|
||||||
+ ++name;
|
|
||||||
+ }
|
|
||||||
+ while (isspace(*name)) {
|
|
||||||
+ if (*name == '\n')
|
|
||||||
+ return NULL;
|
|
||||||
+ ++name;
|
|
||||||
+ }
|
|
||||||
+ if (*name == '#')
|
|
||||||
+ return NULL;
|
|
||||||
+ return name;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int _hcfilemmap(void)
|
|
||||||
+{
|
|
||||||
+ struct stat st;
|
|
||||||
+ int h_fd;
|
|
||||||
+ char *h_addr;
|
|
||||||
+ const char *p, *pend;
|
|
||||||
+ uint32_t c_alloc;
|
|
||||||
+
|
|
||||||
+ h_fd = open(_PATH_HOSTS, O_RDONLY);
|
|
||||||
+ if (h_fd < 0)
|
|
||||||
+ return -1;
|
|
||||||
+ if (flock(h_fd, LOCK_EX) != 0) {
|
|
||||||
+ close(h_fd);
|
|
||||||
+ return -1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (hcfile.h_data) {
|
|
||||||
+ memset(&st, 0, sizeof(st));
|
|
||||||
+ if (fstat(h_fd, &st) == 0) {
|
|
||||||
+ if (st.st_size == hcfile.h_st.st_size &&
|
|
||||||
+ st.st_mtime == hcfile.h_st.st_mtime) {
|
|
||||||
+ flock(h_fd, LOCK_UN);
|
|
||||||
+ close(h_fd);
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ free(hcfile.c_data);
|
|
||||||
+ munmap(hcfile.h_data, hcfile.h_st.st_size);
|
|
||||||
+ close(hcfile.h_fd);
|
|
||||||
+ memset(&hcfile, 0, sizeof(struct hcfile));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (fstat(h_fd, &st) != 0) {
|
|
||||||
+ flock(h_fd, LOCK_UN);
|
|
||||||
+ close(h_fd);
|
|
||||||
+ return -1;
|
|
||||||
+ }
|
|
||||||
+ h_addr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, h_fd, 0);
|
|
||||||
+ if (h_addr == MAP_FAILED) {
|
|
||||||
+ flock(h_fd, LOCK_UN);
|
|
||||||
+ close(h_fd);
|
|
||||||
+ return -1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ hcfile.h_fd = h_fd;
|
|
||||||
+ hcfile.h_st = st;
|
|
||||||
+ hcfile.h_data = h_addr;
|
|
||||||
+
|
|
||||||
+ c_alloc = 0;
|
|
||||||
+ /*
|
|
||||||
+ * Do an initial allocation if the file is "large". Estimate
|
|
||||||
+ * 32 bytes per line and define "large" as more than half of
|
|
||||||
+ * the alloc growth size (256 entries).
|
|
||||||
+ */
|
|
||||||
+ if (st.st_size >= ESTIMATED_LINELEN * HCFILE_ALLOC_SIZE / 2) {
|
|
||||||
+ c_alloc = st.st_size / ESTIMATED_LINELEN;
|
|
||||||
+ hcfile.c_data = malloc(c_alloc * sizeof(struct hcent));
|
|
||||||
+ if (!hcfile.c_data) {
|
|
||||||
+ goto oom;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ p = (const char *)h_addr;
|
|
||||||
+ pend = p + st.st_size;
|
|
||||||
+ while (p < pend) {
|
|
||||||
+ const char *eol, *addr, *name;
|
|
||||||
+ size_t len;
|
|
||||||
+ addr = p;
|
|
||||||
+ eol = memchr(p, '\n', pend - p);
|
|
||||||
+ if (!eol)
|
|
||||||
+ break;
|
|
||||||
+ p = eol + 1;
|
|
||||||
+ if (*addr == '#' || *addr == '\n')
|
|
||||||
+ continue;
|
|
||||||
+ len = hstrlen(addr);
|
|
||||||
+ if (len > MAX_ADDRLEN)
|
|
||||||
+ continue;
|
|
||||||
+ name = addr + len;
|
|
||||||
+ while (name < eol && isspace(*name))
|
|
||||||
+ ++name;
|
|
||||||
+ while (name < eol) {
|
|
||||||
+ len = hstrlen(name);
|
|
||||||
+ if (len == 0)
|
|
||||||
+ break;
|
|
||||||
+ if (len < MAX_HOSTLEN) {
|
|
||||||
+ struct hcent *ent;
|
|
||||||
+ if (c_alloc <= hcfile.c_len) {
|
|
||||||
+ struct hcent *c_data;
|
|
||||||
+ c_alloc += HCFILE_ALLOC_SIZE;
|
|
||||||
+ c_data = realloc(hcfile.c_data, c_alloc * sizeof(struct hcent));
|
|
||||||
+ if (!c_data) {
|
|
||||||
+ goto oom;
|
|
||||||
+ }
|
|
||||||
+ hcfile.c_data = c_data;
|
|
||||||
+ }
|
|
||||||
+ ent = hcfile.c_data + hcfile.c_len;
|
|
||||||
+ ent->addr = addr - h_addr;
|
|
||||||
+ ent->name = name - h_addr;
|
|
||||||
+ ++hcfile.c_len;
|
|
||||||
+ }
|
|
||||||
+ name += len;
|
|
||||||
+ while (name < eol && isspace(*name))
|
|
||||||
+ ++name;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ qsort(hcfile.c_data, hcfile.c_len,
|
|
||||||
+ sizeof(struct hcent), cmp_hcent_name);
|
|
||||||
+
|
|
||||||
+ flock(h_fd, LOCK_UN);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+oom:
|
|
||||||
+ free(hcfile.c_data);
|
|
||||||
+ munmap(hcfile.h_data, hcfile.h_st.st_size);
|
|
||||||
+ flock(hcfile.h_fd, LOCK_UN);
|
|
||||||
+ close(hcfile.h_fd);
|
|
||||||
+ memset(&hcfile, 0, sizeof(struct hcfile));
|
|
||||||
+ return -1;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Caching version of getaddrinfo.
|
|
||||||
+ *
|
|
||||||
+ * If we find the requested host name in the cache, use getaddrinfo to
|
|
||||||
+ * populate the result for each address we find.
|
|
||||||
+ *
|
|
||||||
+ * Note glibc and bionic differ in the handling of ai_canonname. POSIX
|
|
||||||
+ * says that ai_canonname is only populated in the first result entry.
|
|
||||||
+ * glibc does this. bionic populates ai_canonname in all result entries.
|
|
||||||
+ * We choose the POSIX/glibc way here.
|
|
||||||
+ */
|
|
||||||
+int hc_getaddrinfo(const char *host, const char *service,
|
|
||||||
+ const struct addrinfo *hints,
|
|
||||||
+ struct addrinfo **result)
|
|
||||||
+{
|
|
||||||
+ int ret = 0;
|
|
||||||
+ struct hcent *ent, *cur;
|
|
||||||
+ struct addrinfo *ai;
|
|
||||||
+ struct addrinfo rhints;
|
|
||||||
+ struct addrinfo *last;
|
|
||||||
+ int canonname = 0;
|
|
||||||
+ int cmp;
|
|
||||||
+
|
|
||||||
+ if (getenv("ANDROID_HOSTS_CACHE_DISABLE") != NULL)
|
|
||||||
+ return EAI_SYSTEM;
|
|
||||||
+
|
|
||||||
+ /* Avoid needless work and recursion */
|
|
||||||
+ if (hints && (hints->ai_flags & AI_NUMERICHOST))
|
|
||||||
+ return EAI_SYSTEM;
|
|
||||||
+ if (!host)
|
|
||||||
+ return EAI_SYSTEM;
|
|
||||||
+
|
|
||||||
+ pthread_mutex_lock(&hclock);
|
|
||||||
+
|
|
||||||
+ if (_hcfilemmap() != 0) {
|
|
||||||
+ ret = EAI_SYSTEM;
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+ ent = _hcfindname(host);
|
|
||||||
+ if (!ent) {
|
|
||||||
+ ret = EAI_NONAME;
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (hints) {
|
|
||||||
+ canonname = (hints->ai_flags & AI_CANONNAME);
|
|
||||||
+ memcpy(&rhints, hints, sizeof(rhints));
|
|
||||||
+ rhints.ai_flags &= ~AI_CANONNAME;
|
|
||||||
+ }
|
|
||||||
+ else {
|
|
||||||
+ memset(&rhints, 0, sizeof(rhints));
|
|
||||||
+ }
|
|
||||||
+ rhints.ai_flags |= AI_NUMERICHOST;
|
|
||||||
+
|
|
||||||
+ last = NULL;
|
|
||||||
+ cur = ent;
|
|
||||||
+ do {
|
|
||||||
+ char addrstr[MAX_ADDRLEN];
|
|
||||||
+ struct addrinfo *res;
|
|
||||||
+
|
|
||||||
+ hstrcpy(addrstr, hcfile.h_data + cur->addr);
|
|
||||||
+
|
|
||||||
+ if (getaddrinfo(addrstr, service, &rhints, &res) == 0) {
|
|
||||||
+ if (!last)
|
|
||||||
+ (*result)->ai_next = res;
|
|
||||||
+ else
|
|
||||||
+ last->ai_next = res;
|
|
||||||
+ last = res;
|
|
||||||
+ while (last->ai_next)
|
|
||||||
+ last = last->ai_next;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if(cur + 1 >= hcfile.c_data + hcfile.c_len)
|
|
||||||
+ break;
|
|
||||||
+ cmp = cmp_hcent_name(cur, cur + 1);
|
|
||||||
+ cur = cur + 1;
|
|
||||||
+ }
|
|
||||||
+ while (!cmp);
|
|
||||||
+
|
|
||||||
+ if (last == NULL) {
|
|
||||||
+ /* This check is equivalent to (*result)->ai_next == NULL */
|
|
||||||
+ ret = EAI_NODATA;
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (canonname) {
|
|
||||||
+ ai = (*result)->ai_next;
|
|
||||||
+ free(ai->ai_canonname);
|
|
||||||
+ ai->ai_canonname = hstrdup(hcfile.h_data + ent->name);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+out:
|
|
||||||
+ pthread_mutex_unlock(&hclock);
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Caching version of gethtbyname.
|
|
||||||
+ *
|
|
||||||
+ * Note glibc and bionic differ in the handling of aliases. glibc returns
|
|
||||||
+ * all aliases for all entries, regardless of whether they match h_addrtype.
|
|
||||||
+ * bionic returns only the aliases for the first hosts entry. We return all
|
|
||||||
+ * aliases for all IPv4 entries.
|
|
||||||
+ *
|
|
||||||
+ * Additionally, if an alias is IPv6 and the primary name for an alias also
|
|
||||||
+ * has an IPv4 entry, glibc will return the IPv4 address(es), but bionic
|
|
||||||
+ * will not. Neither do we.
|
|
||||||
+ */
|
|
||||||
+int hc_gethtbyname(const char *host, int af, struct getnamaddr *info)
|
|
||||||
+{
|
|
||||||
+ int ret = NETDB_SUCCESS;
|
|
||||||
+ struct hcent *ent, *cur;
|
|
||||||
+ int cmp;
|
|
||||||
+ size_t addrlen;
|
|
||||||
+ unsigned int naliases = 0;
|
|
||||||
+ char *aliases[MAXALIASES];
|
|
||||||
+ unsigned int naddrs = 0;
|
|
||||||
+ char *addr_ptrs[MAXADDRS];
|
|
||||||
+ unsigned int n;
|
|
||||||
+
|
|
||||||
+ if (getenv("ANDROID_HOSTS_CACHE_DISABLE") != NULL)
|
|
||||||
+ return NETDB_INTERNAL;
|
|
||||||
+
|
|
||||||
+ switch (af) {
|
|
||||||
+ case AF_INET: addrlen = NS_INADDRSZ; break;
|
|
||||||
+ case AF_INET6: addrlen = NS_IN6ADDRSZ; break;
|
|
||||||
+ default:
|
|
||||||
+ return NETDB_INTERNAL;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ pthread_mutex_lock(&hclock);
|
|
||||||
+
|
|
||||||
+ if (_hcfilemmap() != 0) {
|
|
||||||
+ ret = NETDB_INTERNAL;
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ent = _hcfindname(host);
|
|
||||||
+ if (!ent) {
|
|
||||||
+ ret = HOST_NOT_FOUND;
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ cur = ent;
|
|
||||||
+ do {
|
|
||||||
+ char addr[16];
|
|
||||||
+ char addrstr[MAX_ADDRLEN];
|
|
||||||
+ char namestr[MAX_HOSTLEN];
|
|
||||||
+ const char *name;
|
|
||||||
+
|
|
||||||
+ hstrcpy(addrstr, hcfile.h_data + cur->addr);
|
|
||||||
+ if (inet_pton(af, addrstr, &addr) == 1) {
|
|
||||||
+ char *aligned;
|
|
||||||
+ /* First match is considered the official hostname */
|
|
||||||
+ if (naddrs == 0) {
|
|
||||||
+ hstrcpy(namestr, hcfile.h_data + cur->name);
|
|
||||||
+ HENT_SCOPY(info->hp->h_name, namestr, info->buf, info->buflen);
|
|
||||||
+ }
|
|
||||||
+ for (name = hcfile.h_data + cur->name; name; name = _hcnextname(name)) {
|
|
||||||
+ if (!hstrcmp(name, host))
|
|
||||||
+ continue;
|
|
||||||
+ hstrcpy(namestr, name);
|
|
||||||
+ HENT_SCOPY(aliases[naliases], namestr, info->buf, info->buflen);
|
|
||||||
+ ++naliases;
|
|
||||||
+ if (naliases >= MAXALIASES)
|
|
||||||
+ goto nospc;
|
|
||||||
+ }
|
|
||||||
+ aligned = (char *)ALIGN(info->buf);
|
|
||||||
+ if (info->buf != aligned) {
|
|
||||||
+ if ((ptrdiff_t)info->buflen < (aligned - info->buf))
|
|
||||||
+ goto nospc;
|
|
||||||
+ info->buflen -= (aligned - info->buf);
|
|
||||||
+ info->buf = aligned;
|
|
||||||
+ }
|
|
||||||
+ HENT_COPY(addr_ptrs[naddrs], addr, addrlen, info->buf, info->buflen);
|
|
||||||
+ ++naddrs;
|
|
||||||
+ if (naddrs >= MAXADDRS)
|
|
||||||
+ goto nospc;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if(cur + 1 >= hcfile.c_data + hcfile.c_len)
|
|
||||||
+ break;
|
|
||||||
+ cmp = cmp_hcent_name(cur, cur + 1);
|
|
||||||
+ cur = cur + 1;
|
|
||||||
+ }
|
|
||||||
+ while (!cmp);
|
|
||||||
+
|
|
||||||
+ if (naddrs == 0) {
|
|
||||||
+ ret = HOST_NOT_FOUND;
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ addr_ptrs[naddrs++] = NULL;
|
|
||||||
+ aliases[naliases++] = NULL;
|
|
||||||
+
|
|
||||||
+ /* hp->h_name already populated */
|
|
||||||
+ HENT_ARRAY(info->hp->h_aliases, naliases, info->buf, info->buflen);
|
|
||||||
+ for (n = 0; n < naliases; ++n) {
|
|
||||||
+ info->hp->h_aliases[n] = aliases[n];
|
|
||||||
+ }
|
|
||||||
+ info->hp->h_addrtype = af;
|
|
||||||
+ info->hp->h_length = addrlen;
|
|
||||||
+ HENT_ARRAY(info->hp->h_addr_list, naddrs, info->buf, info->buflen);
|
|
||||||
+ for (n = 0; n < naddrs; ++n) {
|
|
||||||
+ info->hp->h_addr_list[n] = addr_ptrs[n];
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+out:
|
|
||||||
+ pthread_mutex_unlock(&hclock);
|
|
||||||
+ *info->he = ret;
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+nospc:
|
|
||||||
+ ret = NETDB_INTERNAL;
|
|
||||||
+ goto out;
|
|
||||||
+}
|
|
||||||
diff --git a/libc/dns/net/hosts_cache.h b/libc/dns/net/hosts_cache.h
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000..fa5488f51
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/libc/dns/net/hosts_cache.h
|
|
||||||
@@ -0,0 +1,23 @@
|
|
||||||
+/*
|
|
||||||
+ * Copyright (C) 2016 The CyanogenMod Project
|
|
||||||
+ *
|
|
||||||
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
+ * you may not use this file except in compliance with the License.
|
|
||||||
+ * You may obtain a copy of the License at
|
|
||||||
+ *
|
|
||||||
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
+ *
|
|
||||||
+ * Unless required by applicable law or agreed to in writing, software
|
|
||||||
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
+ * See the License for the specific language governing permissions and
|
|
||||||
+ * limitations under the License.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+struct getnamaddr;
|
|
||||||
+
|
|
||||||
+int hc_getaddrinfo(const char *host, const char *service,
|
|
||||||
+ const struct addrinfo *hints,
|
|
||||||
+ struct addrinfo **result);
|
|
||||||
+
|
|
||||||
+int hc_gethtbyname(const char *host, int af, struct getnamaddr *info);
|
|
||||||
diff --git a/libc/dns/net/sethostent.c b/libc/dns/net/sethostent.c
|
|
||||||
index 483105a95..1399378cd 100644
|
|
||||||
--- a/libc/dns/net/sethostent.c
|
|
||||||
+++ b/libc/dns/net/sethostent.c
|
|
||||||
@@ -55,6 +55,8 @@ __RCSID("$NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $");
|
|
||||||
#include "hostent.h"
|
|
||||||
#include "resolv_private.h"
|
|
||||||
|
|
||||||
+#include "hosts_cache.h"
|
|
||||||
+
|
|
||||||
#ifndef _REENTRANT
|
|
||||||
void res_close(void);
|
|
||||||
#endif
|
|
||||||
@@ -109,6 +111,11 @@ _hf_gethtbyname(void *rv, void *cb_data, va_list ap)
|
|
||||||
/* NOSTRICT skip string len */(void)va_arg(ap, int);
|
|
||||||
af = va_arg(ap, int);
|
|
||||||
|
|
||||||
+ int rc = hc_gethtbyname(name, af, info);
|
|
||||||
+ if (rc != NETDB_INTERNAL) {
|
|
||||||
+ return (rc == NETDB_SUCCESS ? NS_SUCCESS : NS_NOTFOUND);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
#if 0
|
|
||||||
{
|
|
||||||
res_state res = __res_get_state();
|
|
|
@ -1,69 +0,0 @@
|
||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Tom Marshall <tdm.code@gmail.com>
|
|
||||||
Date: Thu, 16 Jan 2020 13:07:04 -0800
|
|
||||||
Subject: [PATCH] bionic: Support wildcards in cached hosts file
|
|
||||||
|
|
||||||
If an exact name is not found in the hosts file and the host name
|
|
||||||
contains at least one dot, search for entries of the form "*.domain",
|
|
||||||
where domain is the portion of the host name after the first dot. If
|
|
||||||
that is not found, repeat using the domain.
|
|
||||||
|
|
||||||
Example: a.b.c.example.com would search for the following in turn:
|
|
||||||
a.b.c.example.com
|
|
||||||
*.b.c.example.com
|
|
||||||
*.c.example.com
|
|
||||||
*.example.com
|
|
||||||
*.com
|
|
||||||
|
|
||||||
Change-Id: I4b0bb81699151d5b371850daebf785e35ec9b180
|
|
||||||
---
|
|
||||||
libc/dns/net/hosts_cache.c | 29 ++++++++++++++++++++++++++++-
|
|
||||||
1 file changed, 28 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/libc/dns/net/hosts_cache.c b/libc/dns/net/hosts_cache.c
|
|
||||||
index 52d29e032..fc6370d0c 100644
|
|
||||||
--- a/libc/dns/net/hosts_cache.c
|
|
||||||
+++ b/libc/dns/net/hosts_cache.c
|
|
||||||
@@ -117,7 +117,7 @@ static int cmp_hcent_name(const void *a, const void *b)
|
|
||||||
return hstrcmp(na, nb);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct hcent *_hcfindname(const char *name)
|
|
||||||
+static struct hcent *_hcfindname_exact(const char *name)
|
|
||||||
{
|
|
||||||
size_t first, last, mid;
|
|
||||||
struct hcent *cur = NULL;
|
|
||||||
@@ -158,6 +158,33 @@ found:
|
|
||||||
return cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static struct hcent *_hcfindname(const char *name)
|
|
||||||
+{
|
|
||||||
+ struct hcent *ent;
|
|
||||||
+ char namebuf[MAX_HOSTLEN];
|
|
||||||
+ char *p;
|
|
||||||
+ char *dot;
|
|
||||||
+
|
|
||||||
+ ent = _hcfindname_exact(name);
|
|
||||||
+ if (!ent && strlen(name) < sizeof(namebuf)) {
|
|
||||||
+ strcpy(namebuf, name);
|
|
||||||
+ p = namebuf;
|
|
||||||
+ do {
|
|
||||||
+ dot = strchr(p, '.');
|
|
||||||
+ if (!dot)
|
|
||||||
+ break;
|
|
||||||
+ if (dot > p) {
|
|
||||||
+ *(dot - 1) = '*';
|
|
||||||
+ ent = _hcfindname_exact(dot - 1);
|
|
||||||
+ }
|
|
||||||
+ p = dot + 1;
|
|
||||||
+ }
|
|
||||||
+ while (!ent);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return ent;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
* Find next name on line, if any.
|
|
||||||
*
|
|
|
@ -1,35 +0,0 @@
|
||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Tad <tad@spotco.us>
|
|
||||||
Date: Wed, 20 Apr 2022 00:40:52 -0400
|
|
||||||
Subject: [PATCH] Add a toggle to disable /etc/hosts lookup
|
|
||||||
|
|
||||||
Signed-off-by: Tad <tad@spotco.us>
|
|
||||||
Change-Id: I92679c57e73228dc194e61a86ea1a18b2ac90e04
|
|
||||||
---
|
|
||||||
libc/dns/net/getaddrinfo.c | 6 ++++++
|
|
||||||
1 file changed, 6 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
|
|
||||||
index cc94b21e2..12294da04 100644
|
|
||||||
--- a/libc/dns/net/getaddrinfo.c
|
|
||||||
+++ b/libc/dns/net/getaddrinfo.c
|
|
||||||
@@ -83,6 +83,7 @@
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
+#include <sys/system_properties.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <net/if.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
@@ -2127,6 +2128,11 @@ _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
|
|
||||||
name = va_arg(ap, char *);
|
|
||||||
pai = va_arg(ap, struct addrinfo *);
|
|
||||||
|
|
||||||
+ char value[PROP_VALUE_MAX] = { 0 };
|
|
||||||
+ if (__system_property_get("persist.security.hosts_disable", value) != 0)
|
|
||||||
+ if (atoi(value) != 0 && strcmp(name, "localhost") != 0 && strcmp(name, "ip6-localhost") != 0)
|
|
||||||
+ return NS_NOTFOUND;
|
|
||||||
+
|
|
||||||
memset(&sentinel, 0, sizeof(sentinel));
|
|
||||||
cur = &sentinel;
|
|
||||||
int gai_error = hc_getaddrinfo(name, NULL, pai, &cur);
|
|
|
@ -1,156 +0,0 @@
|
||||||
From 436f872cd2d42cf2ad1015eb921376cbe1eede1b Mon Sep 17 00:00:00 2001
|
|
||||||
From: harvey186 <harvey186@hotmail.com>
|
|
||||||
Date: Mon, 18 Dec 2023 11:59:34 +0100
|
|
||||||
Subject: [PATCH] Host toogle new
|
|
||||||
|
|
||||||
Change-Id: I30b1221f456bb0bb95966789724e292f5b3047b9
|
|
||||||
---
|
|
||||||
res/values/strings.xml | 3 +
|
|
||||||
res/xml/privacy_dashboard_settings.xml | 7 ++
|
|
||||||
.../security/HostsPreferenceController.java | 106 ++++++++++++++++++
|
|
||||||
.../settings/security/SecuritySettings.java | 1 +
|
|
||||||
4 files changed, 117 insertions(+)
|
|
||||||
create mode 100644 src/com/android/settings/security/HostsPreferenceController.java
|
|
||||||
|
|
||||||
diff --git a/res/values/strings.xml b/res/values/strings.xml
|
|
||||||
index 69a03bd4f9..1f58bb9d62 100644
|
|
||||||
--- a/res/values/strings.xml
|
|
||||||
+++ b/res/values/strings.xml
|
|
||||||
@@ -752,6 +752,9 @@
|
|
||||||
<string name="security_settings_face_settings_require_confirmation">Always require confirmation</string>
|
|
||||||
<!-- When authenticating in apps, always require confirmation (e.g. confirm button) after a face is authenticated. [CHAR LIMIT=70] -->
|
|
||||||
<string name="security_settings_face_settings_require_confirmation_details">When using Face Unlock in apps, always require confirmation step</string>
|
|
||||||
+ <string name="hosts_disable_title">Disable DNS content blocker</string>
|
|
||||||
+ <string name="hosts_disable_summary">Disables use of the included /etc/hosts database for data collection and malware blocking.</string>
|
|
||||||
+
|
|
||||||
<!-- Button text in face settings which removes the user's face model from the device [CHAR LIMIT=40] -->
|
|
||||||
<string name="security_settings_face_settings_remove_face_model">Delete face model</string>
|
|
||||||
<!-- Button text in face settings which lets the user enroll their face [CHAR LIMIT=40] -->
|
|
||||||
|
|
||||||
diff --git a/src/com/android/settings/security/HostsPreferenceController.java b/src/com/android/settings/security/HostsPreferenceController.java
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000..d8af6d2649
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/com/android/settings/security/HostsPreferenceController.java
|
|
||||||
@@ -0,0 +1,106 @@
|
|
||||||
+/*
|
|
||||||
+ * Copyright (C) 2022 The Android Open Source Project
|
|
||||||
+ *
|
|
||||||
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
+ * you may not use this file except in compliance with the License.
|
|
||||||
+ * You may obtain a copy of the License at
|
|
||||||
+ *
|
|
||||||
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
+ *
|
|
||||||
+ * Unless required by applicable law or agreed to in writing, software
|
|
||||||
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
+ * See the License for the specific language governing permissions and
|
|
||||||
+ * limitations under the License
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+package com.android.settings.security;
|
|
||||||
+
|
|
||||||
+import android.content.Context;
|
|
||||||
+
|
|
||||||
+import android.os.UserHandle;
|
|
||||||
+import android.os.UserManager;
|
|
||||||
+import android.os.SystemProperties;
|
|
||||||
+
|
|
||||||
+import android.provider.Settings;
|
|
||||||
+
|
|
||||||
+import androidx.preference.Preference;
|
|
||||||
+import androidx.preference.PreferenceCategory;
|
|
||||||
+import androidx.preference.PreferenceGroup;
|
|
||||||
+import androidx.preference.PreferenceScreen;
|
|
||||||
+import androidx.preference.TwoStatePreference;
|
|
||||||
+import androidx.preference.SwitchPreference;
|
|
||||||
+
|
|
||||||
+import com.android.internal.widget.LockPatternUtils;
|
|
||||||
+import com.android.settings.core.PreferenceControllerMixin;
|
|
||||||
+import com.android.settingslib.core.AbstractPreferenceController;
|
|
||||||
+import com.android.settingslib.core.lifecycle.events.OnResume;
|
|
||||||
+
|
|
||||||
+public class HostsPreferenceController extends AbstractPreferenceController
|
|
||||||
+ implements PreferenceControllerMixin, OnResume, Preference.OnPreferenceChangeListener {
|
|
||||||
+
|
|
||||||
+ private static final String SYS_KEY_HOSTS_DISABLE = "persist.security.hosts_disable";
|
|
||||||
+ private static final String PREF_KEY_HOSTS_DISABLE = "hosts_disable";
|
|
||||||
+ private static final String PREF_KEY_SECURITY_CATEGORY = "security_category";
|
|
||||||
+
|
|
||||||
+ private PreferenceCategory mSecurityCategory;
|
|
||||||
+ private SwitchPreference mHostsDisable;
|
|
||||||
+ private boolean mIsAdmin;
|
|
||||||
+ private UserManager mUm;
|
|
||||||
+
|
|
||||||
+ public HostsPreferenceController(Context context) {
|
|
||||||
+ super(context);
|
|
||||||
+ mUm = UserManager.get(context);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public void displayPreference(PreferenceScreen screen) {
|
|
||||||
+ super.displayPreference(screen);
|
|
||||||
+ mSecurityCategory = screen.findPreference(PREF_KEY_SECURITY_CATEGORY);
|
|
||||||
+ updatePreferenceState();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public boolean isAvailable() {
|
|
||||||
+ mIsAdmin = mUm.isAdminUser();
|
|
||||||
+ return mIsAdmin;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public String getPreferenceKey() {
|
|
||||||
+ return PREF_KEY_HOSTS_DISABLE;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ // TODO: should we use onCreatePreferences() instead?
|
|
||||||
+ private void updatePreferenceState() {
|
|
||||||
+ if (mSecurityCategory == null) {
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (mIsAdmin) {
|
|
||||||
+ mHostsDisable = (SwitchPreference) mSecurityCategory.findPreference(PREF_KEY_HOSTS_DISABLE);
|
|
||||||
+ mHostsDisable.setChecked(SystemProperties.getInt(SYS_KEY_HOSTS_DISABLE, 0) == 1);
|
|
||||||
+ } else {
|
|
||||||
+ mSecurityCategory.removePreference(mSecurityCategory.findPreference(PREF_KEY_HOSTS_DISABLE));
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public void onResume() {
|
|
||||||
+ updatePreferenceState();
|
|
||||||
+ if (mHostsDisable != null) {
|
|
||||||
+ boolean mode = mHostsDisable.isChecked();
|
|
||||||
+ SystemProperties.set(SYS_KEY_HOSTS_DISABLE, mode ? "1" : "0");
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public boolean onPreferenceChange(Preference preference, Object value) {
|
|
||||||
+ final String key = preference.getKey();
|
|
||||||
+ if (PREF_KEY_HOSTS_DISABLE.equals(key)) {
|
|
||||||
+ final boolean mode = !mHostsDisable.isChecked();
|
|
||||||
+ SystemProperties.set(SYS_KEY_HOSTS_DISABLE, mode ? "1" : "0");
|
|
||||||
+ }
|
|
||||||
+ return true;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java
|
|
||||||
index b30b54d4d4..62eeaefd57 100644
|
|
||||||
--- a/src/com/android/settings/security/SecuritySettings.java
|
|
||||||
+++ b/src/com/android/settings/security/SecuritySettings.java
|
|
||||||
@@ -105,6 +105,7 @@ public class SecuritySettings extends DashboardFragment {
|
|
||||||
securityPreferenceControllers.add(new CombinedBiometricStatusPreferenceController(
|
|
||||||
context, lifecycle));
|
|
||||||
securityPreferenceControllers.add(new ChangeScreenLockPreferenceController(context, host));
|
|
||||||
+ securityPreferenceControllers.add(new HostsPreferenceController(context));
|
|
||||||
controllers.add(new PreferenceCategoryController(context, SECURITY_CATEGORY)
|
|
||||||
.setChildren(securityPreferenceControllers));
|
|
||||||
controllers.addAll(securityPreferenceControllers);
|
|
||||||
--
|
|
||||||
2.34.1
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
From 1da77885c43a2f95f427f0a30be648c63e505d64 Mon Sep 17 00:00:00 2001
|
|
||||||
From: harvey186 <harvey186@hotmail.com>
|
|
||||||
Date: Mon, 18 Dec 2023 12:38:03 +0100
|
|
||||||
Subject: [PATCH] Hosts_toogle_new_dev_options
|
|
||||||
|
|
||||||
Change-Id: I126c43dd2d011439591bf3f6ff1d718056359a86
|
|
||||||
---
|
|
||||||
res/xml/development_settings.xml | 7 ++
|
|
||||||
1 files changed, 163 insertions(+), 7 deletions(-)
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
|
|
||||||
index 32acac66dd..ee433d1c34 100644
|
|
||||||
--- a/res/xml/development_settings.xml
|
|
||||||
+++ b/res/xml/development_settings.xml
|
|
||||||
@@ -28,6 +28,13 @@
|
|
||||||
android:title="@string/memory_settings_title"
|
|
||||||
android:summary="@string/summary_placeholder"
|
|
||||||
android:fragment="com.android.settings.applications.ProcessStatsSummary" />
|
|
||||||
+
|
|
||||||
+ <!-- Hosts toggle -->
|
|
||||||
+ <SwitchPreference
|
|
||||||
+ android:key="hosts_disable"
|
|
||||||
+ android:title="@string/hosts_disable_title"
|
|
||||||
+ android:summary="@string/hosts_disable_summary"
|
|
||||||
+ android:persistent="false" />
|
|
||||||
|
|
||||||
<com.android.settings.BugreportPreference
|
|
||||||
android:key="bugreport"
|
|
||||||
--
|
|
||||||
2.34.1
|
|
||||||
|
|
|
@ -1,375 +0,0 @@
|
||||||
From fd6e31cb762b210326b08d77502235812cc80905 Mon Sep 17 00:00:00 2001
|
|
||||||
From: harvey186 <harvey186@hotmail.com>
|
|
||||||
Date: Sat, 21 Oct 2023 13:10:09 +0200
|
|
||||||
Subject: [PATCH] Captive_Portal_Toggle.patch
|
|
||||||
|
|
||||||
---
|
|
||||||
res/values/arrays.xml | 21 ++
|
|
||||||
res/values/strings.xml | 3 +
|
|
||||||
...ConnectivityCheckPreferenceController.java | 295 ++++++++++++++++++
|
|
||||||
.../network/NetworkDashboardFragment.java | 3 +
|
|
||||||
4 files changed, 322 insertions(+)
|
|
||||||
create mode 100644 src/com/android/settings/network/ConnectivityCheckPreferenceController.java
|
|
||||||
|
|
||||||
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
|
|
||||||
index 787163e0ff..ebba89e7e1 100644
|
|
||||||
--- a/res/values/arrays.xml
|
|
||||||
+++ b/res/values/arrays.xml
|
|
||||||
@@ -82,6 +82,27 @@
|
|
||||||
<item>10 minutes</item>
|
|
||||||
<item>30 minutes</item>
|
|
||||||
</string-array>
|
|
||||||
+
|
|
||||||
+ <string-array name="connectivity_check_entries">
|
|
||||||
+ <item>Disabled</item>
|
|
||||||
+ <item>DivestOS (US)</item>
|
|
||||||
+ <item>Kuketz (DE) [default]</item>
|
|
||||||
+ <item>openSUSE (DE)</item>
|
|
||||||
+ <item>Ubuntu (UK)</item>
|
|
||||||
+ <item>Graphene (US)</item>
|
|
||||||
+ <item>Kuketz (DE)</item>
|
|
||||||
+ </string-array>
|
|
||||||
+
|
|
||||||
+ <string-array name="connectivity_check_values" translatable="false">
|
|
||||||
+ <item>0</item>
|
|
||||||
+ <item>1</item>
|
|
||||||
+ <item>2</item>
|
|
||||||
+ <item>3</item>
|
|
||||||
+ <item>4</item>
|
|
||||||
+ <item>5</item>
|
|
||||||
+ <item>6</item>
|
|
||||||
+ </string-array>
|
|
||||||
+
|
|
||||||
|
|
||||||
<!-- Do not translate. -->
|
|
||||||
<string-array name="lock_after_timeout_values" translatable="false">
|
|
||||||
diff --git a/res/values/strings.xml b/res/values/strings.xml
|
|
||||||
index 1ad45d59e1..4a78bcba5e 100644
|
|
||||||
--- a/res/values/strings.xml
|
|
||||||
+++ b/res/values/strings.xml
|
|
||||||
@@ -12133,4 +12133,7 @@
|
|
||||||
|
|
||||||
<!-- Warning message when we try to dock an app not supporting multiple instances split into multiple sides [CHAR LIMIT=NONE] -->
|
|
||||||
<string name="dock_multi_instances_not_supported_text">"This app can only be opened in 1 window"</string>
|
|
||||||
+ <string name="connectivity_check_title">Internet connectivity check</string>
|
|
||||||
+ <string name="connectivity_check_summary">HTTP endpoints to use for performing internet connectivity checks.</string>
|
|
||||||
+
|
|
||||||
</resources>
|
|
||||||
diff --git a/src/com/android/settings/network/ConnectivityCheckPreferenceController.java b/src/com/android/settings/network/ConnectivityCheckPreferenceController.java
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000..04bcbe3b60
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/com/android/settings/network/ConnectivityCheckPreferenceController.java
|
|
||||||
@@ -0,0 +1,295 @@
|
|
||||||
+/*
|
|
||||||
+ * Copyright (C) 2020 The Android Open Source Project
|
|
||||||
+ *
|
|
||||||
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
+ * you may not use this file except in compliance with the License.
|
|
||||||
+ * You may obtain a copy of the License at
|
|
||||||
+ *
|
|
||||||
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
+ *
|
|
||||||
+ * Unless required by applicable law or agreed to in writing, software
|
|
||||||
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
+ * See the License for the specific language governing permissions and
|
|
||||||
+ * limitations under the License.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+package com.android.settings.network;
|
|
||||||
+
|
|
||||||
+import android.content.ContentResolver;
|
|
||||||
+import android.content.Context;
|
|
||||||
+import android.content.res.Resources;
|
|
||||||
+import android.database.ContentObserver;
|
|
||||||
+import android.net.LinkProperties;
|
|
||||||
+import android.net.Network;
|
|
||||||
+import android.os.Handler;
|
|
||||||
+import android.os.Looper;
|
|
||||||
+import android.os.UserHandle;
|
|
||||||
+import android.os.UserManager;
|
|
||||||
+import android.provider.Settings;
|
|
||||||
+import androidx.preference.ListPreference;
|
|
||||||
+import androidx.preference.Preference;
|
|
||||||
+import androidx.preference.PreferenceScreen;
|
|
||||||
+import com.android.internal.util.ArrayUtils;
|
|
||||||
+import com.android.settings.R;
|
|
||||||
+import com.android.settings.core.BasePreferenceController;
|
|
||||||
+import com.android.settings.core.PreferenceControllerMixin;
|
|
||||||
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
|
||||||
+import com.android.settingslib.RestrictedLockUtilsInternal;
|
|
||||||
+import com.android.settingslib.core.lifecycle.events.OnResume;
|
|
||||||
+
|
|
||||||
+public class ConnectivityCheckPreferenceController
|
|
||||||
+ extends BasePreferenceController
|
|
||||||
+ implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener,
|
|
||||||
+ OnResume {
|
|
||||||
+
|
|
||||||
+ // imported defaults from AOSP NetworkStack
|
|
||||||
+ private static final String STANDARD_HTTPS_URL =
|
|
||||||
+ "http://captiveportal.kuketz.de/generate_204";
|
|
||||||
+ private static final String STANDARD_HTTP_URL =
|
|
||||||
+ "http://captiveportal.kuketz.de/generate_204";
|
|
||||||
+ private static final String STANDARD_FALLBACK_URL =
|
|
||||||
+ "http://captiveportal.kuketz.de/gen_204";
|
|
||||||
+ private static final String STANDARD_OTHER_FALLBACK_URLS =
|
|
||||||
+ "http://captiveportal.kuketz.de/generate_204";
|
|
||||||
+
|
|
||||||
+ // GrapheneOS
|
|
||||||
+ private static final String GRAPHENEOS_CAPTIVE_PORTAL_HTTPS_URL =
|
|
||||||
+ "https://connectivitycheck.grapheneos.network/generate_204";
|
|
||||||
+ private static final String GRAPHENEOS_CAPTIVE_PORTAL_HTTP_URL =
|
|
||||||
+ "http://connectivitycheck.grapheneos.network/generate_204";
|
|
||||||
+ private static final String GRAPHENEOS_CAPTIVE_PORTAL_FALLBACK_URL =
|
|
||||||
+ "http://grapheneos.online/gen_204";
|
|
||||||
+ private static final String GRAPHENEOS_CAPTIVE_PORTAL_OTHER_FALLBACK_URL =
|
|
||||||
+ "http://grapheneos.online/generate_204";
|
|
||||||
+
|
|
||||||
+ // DivestOS
|
|
||||||
+ private static final String DIVESTOS_HTTPS_URL =
|
|
||||||
+ "https://divestos.org/generate_204";
|
|
||||||
+ private static final String DIVESTOS_HTTP_URL =
|
|
||||||
+ "http://divestos.org/generate_204";
|
|
||||||
+
|
|
||||||
+ // openSUSE
|
|
||||||
+ private static final String OPENSUSE_HTTPS_URL =
|
|
||||||
+ "https://conncheck.opensuse.org";
|
|
||||||
+ private static final String OPENSUSE_HTTP_URL =
|
|
||||||
+ "http://conncheck.opensuse.org";
|
|
||||||
+
|
|
||||||
+ // Ubuntu
|
|
||||||
+ private static final String UBUNTU_HTTPS_URL =
|
|
||||||
+ "https://connectivity-check.ubuntu.com";
|
|
||||||
+ private static final String UBUNTU_HTTP_URL =
|
|
||||||
+ "http://connectivity-check.ubuntu.com";
|
|
||||||
+
|
|
||||||
+ // Kuketz, https://www.kuketz-blog.de/android-captive-portal-check-204-http-antwort-von-captiveportal-kuketz-de/
|
|
||||||
+ private static final String KUKETZ_HTTPS_URL =
|
|
||||||
+ "https://captiveportal.kuketz.de";
|
|
||||||
+ private static final String KUKETZ_HTTP_URL =
|
|
||||||
+ "http://captiveportal.kuketz.de";
|
|
||||||
+
|
|
||||||
+ private static final int DISABLED_CAPTIVE_PORTAL_INTVAL = 0;
|
|
||||||
+ private static final int DIVESTOS_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 1;
|
|
||||||
+ private static final int STANDARD_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 2;
|
|
||||||
+ private static final int OPENSUSE_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 3;
|
|
||||||
+ private static final int UBUNTU_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 4;
|
|
||||||
+ private static final int GRAPHENEOS_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 5;
|
|
||||||
+ private static final int KUKETZ_CAPTIVE_PORTAL_HTTP_URL_INTVAL = 6;
|
|
||||||
+
|
|
||||||
+ private static final String KEY_CONNECTIVITY_CHECK_SETTINGS =
|
|
||||||
+ "connectivity_check_settings";
|
|
||||||
+
|
|
||||||
+ private ListPreference mConnectivityPreference;
|
|
||||||
+
|
|
||||||
+ public ConnectivityCheckPreferenceController(Context context) {
|
|
||||||
+ super(context, KEY_CONNECTIVITY_CHECK_SETTINGS);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public int getAvailabilityStatus() {
|
|
||||||
+ if (isDisabledByAdmin()) {
|
|
||||||
+ return BasePreferenceController.DISABLED_FOR_USER;
|
|
||||||
+ }
|
|
||||||
+ return BasePreferenceController.AVAILABLE;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public void displayPreference(PreferenceScreen screen) {
|
|
||||||
+ ListPreference captiveList = new ListPreference(screen.getContext());
|
|
||||||
+ captiveList.setKey(KEY_CONNECTIVITY_CHECK_SETTINGS);
|
|
||||||
+ captiveList.setOrder(30);
|
|
||||||
+ captiveList.setIcon(R.drawable.ic_settings_language);
|
|
||||||
+ captiveList.setTitle(R.string.connectivity_check_title);
|
|
||||||
+ captiveList.setSummary(R.string.connectivity_check_summary);
|
|
||||||
+ captiveList.setEntries(R.array.connectivity_check_entries);
|
|
||||||
+ captiveList.setEntryValues(R.array.connectivity_check_values);
|
|
||||||
+
|
|
||||||
+ if (mConnectivityPreference == null) {
|
|
||||||
+ screen.addPreference(captiveList);
|
|
||||||
+ mConnectivityPreference = captiveList;
|
|
||||||
+ }
|
|
||||||
+ super.displayPreference(screen);
|
|
||||||
+ updatePreferenceState();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public String getPreferenceKey() {
|
|
||||||
+ return KEY_CONNECTIVITY_CHECK_SETTINGS;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private void updatePreferenceState() {
|
|
||||||
+ if (Settings.Global.getInt(mContext.getContentResolver(),
|
|
||||||
+ Settings.Global.CAPTIVE_PORTAL_MODE, Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT)
|
|
||||||
+ == Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE) {
|
|
||||||
+ mConnectivityPreference.setValueIndex(DISABLED_CAPTIVE_PORTAL_INTVAL);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ String pref = Settings.Global.getString(
|
|
||||||
+ mContext.getContentResolver(), Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
|
|
||||||
+ if (STANDARD_HTTP_URL.equals(pref)) {
|
|
||||||
+ mConnectivityPreference.setValueIndex(
|
|
||||||
+ STANDARD_CAPTIVE_PORTAL_HTTP_URL_INTVAL);
|
|
||||||
+ } else if (GRAPHENEOS_CAPTIVE_PORTAL_HTTP_URL.equals(pref)) {
|
|
||||||
+ mConnectivityPreference.setValueIndex(
|
|
||||||
+ GRAPHENEOS_CAPTIVE_PORTAL_HTTP_URL_INTVAL);
|
|
||||||
+ } else if (DIVESTOS_HTTP_URL.equals(pref)) {
|
|
||||||
+ mConnectivityPreference.setValueIndex(
|
|
||||||
+ DIVESTOS_CAPTIVE_PORTAL_HTTP_URL_INTVAL);
|
|
||||||
+ } else if (OPENSUSE_HTTP_URL.equals(pref)) {
|
|
||||||
+ mConnectivityPreference.setValueIndex(
|
|
||||||
+ OPENSUSE_CAPTIVE_PORTAL_HTTP_URL_INTVAL);
|
|
||||||
+ } else if (UBUNTU_HTTP_URL.equals(pref)) {
|
|
||||||
+ mConnectivityPreference.setValueIndex(
|
|
||||||
+ UBUNTU_CAPTIVE_PORTAL_HTTP_URL_INTVAL);
|
|
||||||
+ } else if (KUKETZ_HTTP_URL.equals(pref)) {
|
|
||||||
+ mConnectivityPreference.setValueIndex(
|
|
||||||
+ KUKETZ_CAPTIVE_PORTAL_HTTP_URL_INTVAL);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public void onResume() {
|
|
||||||
+ updatePreferenceState();
|
|
||||||
+ if (mConnectivityPreference != null) {
|
|
||||||
+ setCaptivePortalURLs(
|
|
||||||
+ mContext.getContentResolver(),
|
|
||||||
+ Integer.parseInt(mConnectivityPreference.getValue()));
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private void setCaptivePortalURLs(ContentResolver cr, int mode) {
|
|
||||||
+ switch (mode) {
|
|
||||||
+ case STANDARD_CAPTIVE_PORTAL_HTTP_URL_INTVAL:
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
|
|
||||||
+ STANDARD_HTTP_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
|
|
||||||
+ STANDARD_HTTPS_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
|
|
||||||
+ STANDARD_FALLBACK_URL);
|
|
||||||
+ Settings.Global.putString(
|
|
||||||
+ cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
|
|
||||||
+ STANDARD_OTHER_FALLBACK_URLS);
|
|
||||||
+ Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE,
|
|
||||||
+ Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
|
|
||||||
+ break;
|
|
||||||
+ case GRAPHENEOS_CAPTIVE_PORTAL_HTTP_URL_INTVAL:
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
|
|
||||||
+ GRAPHENEOS_CAPTIVE_PORTAL_HTTP_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
|
|
||||||
+ GRAPHENEOS_CAPTIVE_PORTAL_HTTPS_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
|
|
||||||
+ GRAPHENEOS_CAPTIVE_PORTAL_FALLBACK_URL);
|
|
||||||
+ Settings.Global.putString(
|
|
||||||
+ cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
|
|
||||||
+ GRAPHENEOS_CAPTIVE_PORTAL_OTHER_FALLBACK_URL);
|
|
||||||
+ Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE,
|
|
||||||
+ Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
|
|
||||||
+ break;
|
|
||||||
+ case DIVESTOS_CAPTIVE_PORTAL_HTTP_URL_INTVAL:
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
|
|
||||||
+ DIVESTOS_HTTP_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
|
|
||||||
+ DIVESTOS_HTTPS_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
|
|
||||||
+ DIVESTOS_HTTP_URL);
|
|
||||||
+ Settings.Global.putString(
|
|
||||||
+ cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
|
|
||||||
+ DIVESTOS_HTTP_URL);
|
|
||||||
+ Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE,
|
|
||||||
+ Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
|
|
||||||
+ break;
|
|
||||||
+ case OPENSUSE_CAPTIVE_PORTAL_HTTP_URL_INTVAL:
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
|
|
||||||
+ OPENSUSE_HTTP_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
|
|
||||||
+ OPENSUSE_HTTPS_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
|
|
||||||
+ OPENSUSE_HTTP_URL);
|
|
||||||
+ Settings.Global.putString(
|
|
||||||
+ cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
|
|
||||||
+ OPENSUSE_HTTP_URL);
|
|
||||||
+ Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE,
|
|
||||||
+ Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
|
|
||||||
+ break;
|
|
||||||
+ case UBUNTU_CAPTIVE_PORTAL_HTTP_URL_INTVAL:
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
|
|
||||||
+ UBUNTU_HTTP_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
|
|
||||||
+ UBUNTU_HTTPS_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
|
|
||||||
+ UBUNTU_HTTP_URL);
|
|
||||||
+ Settings.Global.putString(
|
|
||||||
+ cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
|
|
||||||
+ UBUNTU_HTTP_URL);
|
|
||||||
+ Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE,
|
|
||||||
+ Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
|
|
||||||
+ break;
|
|
||||||
+ case KUKETZ_CAPTIVE_PORTAL_HTTP_URL_INTVAL:
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
|
|
||||||
+ KUKETZ_HTTP_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
|
|
||||||
+ KUKETZ_HTTPS_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
|
|
||||||
+ KUKETZ_HTTP_URL);
|
|
||||||
+ Settings.Global.putString(
|
|
||||||
+ cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
|
|
||||||
+ KUKETZ_HTTP_URL);
|
|
||||||
+ Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE,
|
|
||||||
+ Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ // Default URLs as placeholder
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
|
|
||||||
+ STANDARD_HTTP_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
|
|
||||||
+ STANDARD_HTTPS_URL);
|
|
||||||
+ Settings.Global.putString(cr, Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
|
|
||||||
+ STANDARD_FALLBACK_URL);
|
|
||||||
+ Settings.Global.putString(
|
|
||||||
+ cr, Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
|
|
||||||
+ STANDARD_OTHER_FALLBACK_URLS);
|
|
||||||
+ Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE,
|
|
||||||
+ Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public boolean onPreferenceChange(Preference preference, Object value) {
|
|
||||||
+ final String key = preference.getKey();
|
|
||||||
+ if (KEY_CONNECTIVITY_CHECK_SETTINGS.equals(key)) {
|
|
||||||
+ setCaptivePortalURLs(mContext.getContentResolver(),
|
|
||||||
+ Integer.parseInt((String)value));
|
|
||||||
+ return true;
|
|
||||||
+ } else {
|
|
||||||
+ return false;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private EnforcedAdmin getEnforcedAdmin() {
|
|
||||||
+ return RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
|
|
||||||
+ mContext, UserManager.DISALLOW_CONFIG_PRIVATE_DNS,
|
|
||||||
+ UserHandle.myUserId());
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private boolean isDisabledByAdmin() { return getEnforcedAdmin() != null; }
|
|
||||||
+}
|
|
||||||
diff --git a/src/com/android/settings/network/NetworkDashboardFragment.java b/src/com/android/settings/network/NetworkDashboardFragment.java
|
|
||||||
index 4ea3464569..00daadb8dc 100644
|
|
||||||
--- a/src/com/android/settings/network/NetworkDashboardFragment.java
|
|
||||||
+++ b/src/com/android/settings/network/NetworkDashboardFragment.java
|
|
||||||
@@ -123,6 +123,9 @@ public class NetworkDashboardFragment extends DashboardFragment implements
|
|
||||||
}
|
|
||||||
controllers.add(privateDnsPreferenceController);
|
|
||||||
controllers.add(new NetworkProviderCallsSmsController(context, lifecycle, lifecycleOwner));
|
|
||||||
+ ConnectivityCheckPreferenceController connectivityCheck =
|
|
||||||
+ new ConnectivityCheckPreferenceController(context);
|
|
||||||
+ controllers.add(connectivityCheck);
|
|
||||||
|
|
||||||
// Start SettingsDumpService after the MobileNetworkRepository is created.
|
|
||||||
Intent intent = new Intent(context, SettingsDumpService.class);
|
|
||||||
--
|
|
||||||
2.34.1
|
|
||||||
|
|
|
@ -1,655 +0,0 @@
|
||||||
From 87ba93bc9d164aefb840ea8eea654036a3116e49 Mon Sep 17 00:00:00 2001
|
|
||||||
From: harvey186 <harvey186@hotmail.com>
|
|
||||||
Date: Sat, 21 Oct 2023 11:09:30 +0200
|
|
||||||
Subject: [PATCH] 0000-Hosts_Cache
|
|
||||||
|
|
||||||
Change-Id: Icb58ddeedcc49c3b3a23f9ef145a256be3d03b81
|
|
||||||
---
|
|
||||||
0000-Hosts_Cache.patch | 633 ++++++++++++++++++++++
|
|
||||||
0001-Hosts_Wildcards.patch | 72 +++
|
|
||||||
0002-hosts_toggle.patch | 33 ++
|
|
||||||
0003-Reuse-align_ptr-in-hosts_cache.patch | 34 ++
|
|
||||||
Android.bp | 1 +
|
|
||||||
getaddrinfo.cpp | 8 +
|
|
||||||
hosts_cache.cpp | 523 ++++++++++++++++++
|
|
||||||
hosts_cache.h | 28 +
|
|
||||||
sethostent.cpp | 7 +
|
|
||||||
9 files changed, 1339 insertions(+)
|
|
||||||
create mode 100644 0000-Hosts_Cache.patch
|
|
||||||
create mode 100644 0001-Hosts_Wildcards.patch
|
|
||||||
create mode 100644 0002-hosts_toggle.patch
|
|
||||||
create mode 100644 0003-Reuse-align_ptr-in-hosts_cache.patch
|
|
||||||
create mode 100644 hosts_cache.cpp
|
|
||||||
create mode 100644 hosts_cache.h
|
|
||||||
|
|
||||||
diff --git a/Android.bp b/Android.bp
|
|
||||||
index beead98..1841347 100644
|
|
||||||
--- a/Android.bp
|
|
||||||
+++ b/Android.bp
|
|
||||||
@@ -193,6 +193,7 @@ cc_library {
|
|
||||||
"getaddrinfo.cpp",
|
|
||||||
"gethnamaddr.cpp",
|
|
||||||
"sethostent.cpp",
|
|
||||||
+ "hosts_cache.cpp",
|
|
||||||
"res_cache.cpp",
|
|
||||||
"res_comp.cpp",
|
|
||||||
"res_debug.cpp",
|
|
||||||
diff --git a/getaddrinfo.cpp b/getaddrinfo.cpp
|
|
||||||
index ca3c535..064ff57 100644
|
|
||||||
--- a/getaddrinfo.cpp
|
|
||||||
+++ b/getaddrinfo.cpp
|
|
||||||
@@ -64,6 +64,7 @@
|
|
||||||
#include "res_debug.h"
|
|
||||||
#include "resolv_cache.h"
|
|
||||||
#include "resolv_private.h"
|
|
||||||
+#include "hosts_cache.h"
|
|
||||||
|
|
||||||
#define ANY 0
|
|
||||||
|
|
||||||
@@ -1552,6 +1553,13 @@ static bool files_getaddrinfo(const size_t netid, const char* name, const addrin
|
|
||||||
FILE* hostf = nullptr;
|
|
||||||
|
|
||||||
cur = &sentinel;
|
|
||||||
+
|
|
||||||
+ int hc_error = hc_getaddrinfo(name, pai, &cur);
|
|
||||||
+ if (hc_error != EAI_SYSTEM) {
|
|
||||||
+ *res = sentinel.ai_next;
|
|
||||||
+ return sentinel.ai_next != NULL;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
_sethtent(&hostf);
|
|
||||||
while ((p = _gethtent(&hostf, name, pai)) != nullptr) {
|
|
||||||
cur->ai_next = p;
|
|
||||||
diff --git a/hosts_cache.cpp b/hosts_cache.cpp
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..a40fb40
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/hosts_cache.cpp
|
|
||||||
@@ -0,0 +1,523 @@
|
|
||||||
+/*
|
|
||||||
+ * Copyright (C) 2016 The CyanogenMod Project
|
|
||||||
+ * Copyright (C) 2020 The LineageOS Project
|
|
||||||
+ *
|
|
||||||
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
+ * you may not use this file except in compliance with the License.
|
|
||||||
+ * You may obtain a copy of the License at
|
|
||||||
+ *
|
|
||||||
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
+ *
|
|
||||||
+ * Unless required by applicable law or agreed to in writing, software
|
|
||||||
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
+ * See the License for the specific language governing permissions and
|
|
||||||
+ * limitations under the License.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <fcntl.h>
|
|
||||||
+#include <netdb.h>
|
|
||||||
+#include <stdio.h>
|
|
||||||
+#include <stdlib.h>
|
|
||||||
+#include <string.h>
|
|
||||||
+#include <ctype.h>
|
|
||||||
+#include <strings.h>
|
|
||||||
+#include <sys/file.h>
|
|
||||||
+#include <sys/mman.h>
|
|
||||||
+#include <sys/socket.h>
|
|
||||||
+#include <sys/stat.h>
|
|
||||||
+#include <sys/types.h>
|
|
||||||
+#include <unistd.h>
|
|
||||||
+#include <utime.h>
|
|
||||||
+#include <pthread.h>
|
|
||||||
+
|
|
||||||
+#include <netinet/in6.h>
|
|
||||||
+#include <arpa/inet.h>
|
|
||||||
+#include <arpa/nameser.h>
|
|
||||||
+
|
|
||||||
+#include "hostent.h"
|
|
||||||
+#include "resolv_private.h"
|
|
||||||
+
|
|
||||||
+constexpr int MAXALIASES = 35;
|
|
||||||
+constexpr int MAXADDRS = 35;
|
|
||||||
+
|
|
||||||
+#define MAX_ADDRLEN (INET6_ADDRSTRLEN - (1 + 5))
|
|
||||||
+#define MAX_HOSTLEN MAXHOSTNAMELEN
|
|
||||||
+
|
|
||||||
+#define ESTIMATED_LINELEN 32
|
|
||||||
+#define HCFILE_ALLOC_SIZE 256
|
|
||||||
+
|
|
||||||
+/* From sethostent.c */
|
|
||||||
+#define ALIGNBYTES (sizeof(uintptr_t) - 1)
|
|
||||||
+#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
|
|
||||||
+
|
|
||||||
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Host cache entry for hcfile.c_data.
|
|
||||||
+ * Offsets are into hcfile.h_data.
|
|
||||||
+ * Strings are *not* terminated by NULL, but by whitespace (isspace) or '#'.
|
|
||||||
+ * Use hstr* functions with these.
|
|
||||||
+ */
|
|
||||||
+struct hcent
|
|
||||||
+{
|
|
||||||
+ uint32_t addr;
|
|
||||||
+ uint32_t name;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Overall host cache file state.
|
|
||||||
+ */
|
|
||||||
+struct hcfile
|
|
||||||
+{
|
|
||||||
+ int h_fd;
|
|
||||||
+ struct stat h_st;
|
|
||||||
+ char* h_data;
|
|
||||||
+
|
|
||||||
+ uint32_t c_alloc;
|
|
||||||
+ uint32_t c_len;
|
|
||||||
+ struct hcent* c_data;
|
|
||||||
+};
|
|
||||||
+static struct hcfile hcfile;
|
|
||||||
+static pthread_mutex_t hclock = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
+
|
|
||||||
+static size_t hstrlen(const char *s)
|
|
||||||
+{
|
|
||||||
+ const char *p = s;
|
|
||||||
+ while (*p && *p != '#' && !isspace(*p))
|
|
||||||
+ ++p;
|
|
||||||
+ return p - s;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int hstrcmp(const char *a, const char *b)
|
|
||||||
+{
|
|
||||||
+ size_t alen = hstrlen(a);
|
|
||||||
+ size_t blen = hstrlen(b);
|
|
||||||
+ int res = strncmp(a, b, MIN(alen, blen));
|
|
||||||
+ if (res == 0)
|
|
||||||
+ res = alen - blen;
|
|
||||||
+ return res;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static char *hstrcpy(char *dest, const char *src)
|
|
||||||
+{
|
|
||||||
+ size_t len = hstrlen(src);
|
|
||||||
+ memcpy(dest, src, len);
|
|
||||||
+ dest[len] = '\0';
|
|
||||||
+ return dest;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static char *hstrdup(const char *s)
|
|
||||||
+{
|
|
||||||
+ size_t len = hstrlen(s);
|
|
||||||
+ char *dest = (char *)malloc(len + 1);
|
|
||||||
+ if (!dest)
|
|
||||||
+ return NULL;
|
|
||||||
+ memcpy(dest, s, len);
|
|
||||||
+ dest[len] = '\0';
|
|
||||||
+ return dest;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int cmp_hcent_name(const void *a, const void *b)
|
|
||||||
+{
|
|
||||||
+ struct hcent *ea = (struct hcent *)a;
|
|
||||||
+ const char *na = hcfile.h_data + ea->name;
|
|
||||||
+ struct hcent *eb = (struct hcent *)b;
|
|
||||||
+ const char *nb = hcfile.h_data + eb->name;
|
|
||||||
+
|
|
||||||
+ return hstrcmp(na, nb);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct hcent *_hcfindname(const char *name)
|
|
||||||
+{
|
|
||||||
+ size_t first, last, mid;
|
|
||||||
+ struct hcent *cur = NULL;
|
|
||||||
+ int cmp;
|
|
||||||
+
|
|
||||||
+ if (hcfile.c_len == 0)
|
|
||||||
+ return NULL;
|
|
||||||
+
|
|
||||||
+ first = 0;
|
|
||||||
+ last = hcfile.c_len - 1;
|
|
||||||
+ mid = (first + last) / 2;
|
|
||||||
+ while (first <= last) {
|
|
||||||
+ cur = hcfile.c_data + mid;
|
|
||||||
+ cmp = hstrcmp(hcfile.h_data + cur->name, name);
|
|
||||||
+ if (cmp == 0)
|
|
||||||
+ goto found;
|
|
||||||
+ if (cmp < 0)
|
|
||||||
+ first = mid + 1;
|
|
||||||
+ else {
|
|
||||||
+ if (mid > 0)
|
|
||||||
+ last = mid - 1;
|
|
||||||
+ else
|
|
||||||
+ return NULL;
|
|
||||||
+ }
|
|
||||||
+ mid = (first + last) / 2;
|
|
||||||
+ }
|
|
||||||
+ return NULL;
|
|
||||||
+
|
|
||||||
+found:
|
|
||||||
+ while (cur > hcfile.c_data) {
|
|
||||||
+ struct hcent *prev = cur - 1;
|
|
||||||
+ cmp = cmp_hcent_name(cur, prev);
|
|
||||||
+ if (cmp)
|
|
||||||
+ break;
|
|
||||||
+ cur = prev;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return cur;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Find next name on line, if any.
|
|
||||||
+ *
|
|
||||||
+ * Assumes that line is terminated by LF.
|
|
||||||
+ */
|
|
||||||
+static const char *_hcnextname(const char *name)
|
|
||||||
+{
|
|
||||||
+ while (!isspace(*name)) {
|
|
||||||
+ if (*name == '#')
|
|
||||||
+ return NULL;
|
|
||||||
+ ++name;
|
|
||||||
+ }
|
|
||||||
+ while (isspace(*name)) {
|
|
||||||
+ if (*name == '\n')
|
|
||||||
+ return NULL;
|
|
||||||
+ ++name;
|
|
||||||
+ }
|
|
||||||
+ if (*name == '#')
|
|
||||||
+ return NULL;
|
|
||||||
+ return name;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int _hcfilemmap(void)
|
|
||||||
+{
|
|
||||||
+ struct stat st;
|
|
||||||
+ int h_fd;
|
|
||||||
+ char *h_addr;
|
|
||||||
+ const char *p, *pend;
|
|
||||||
+ uint32_t c_alloc;
|
|
||||||
+
|
|
||||||
+ h_fd = open(_PATH_HOSTS, O_CLOEXEC);
|
|
||||||
+ if (h_fd < 0)
|
|
||||||
+ return -1;
|
|
||||||
+ if (flock(h_fd, LOCK_EX) != 0) {
|
|
||||||
+ close(h_fd);
|
|
||||||
+ return -1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (hcfile.h_data) {
|
|
||||||
+ memset(&st, 0, sizeof(st));
|
|
||||||
+ if (fstat(h_fd, &st) == 0) {
|
|
||||||
+ if (st.st_size == hcfile.h_st.st_size &&
|
|
||||||
+ st.st_mtime == hcfile.h_st.st_mtime) {
|
|
||||||
+ flock(h_fd, LOCK_UN);
|
|
||||||
+ close(h_fd);
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ free(hcfile.c_data);
|
|
||||||
+ munmap(hcfile.h_data, hcfile.h_st.st_size);
|
|
||||||
+ close(hcfile.h_fd);
|
|
||||||
+ memset(&hcfile, 0, sizeof(struct hcfile));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (fstat(h_fd, &st) != 0) {
|
|
||||||
+ flock(h_fd, LOCK_UN);
|
|
||||||
+ close(h_fd);
|
|
||||||
+ return -1;
|
|
||||||
+ }
|
|
||||||
+ h_addr = (char*)mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, h_fd, 0);
|
|
||||||
+ if (h_addr == MAP_FAILED) {
|
|
||||||
+ flock(h_fd, LOCK_UN);
|
|
||||||
+ close(h_fd);
|
|
||||||
+ return -1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ hcfile.h_fd = h_fd;
|
|
||||||
+ hcfile.h_st = st;
|
|
||||||
+ hcfile.h_data = h_addr;
|
|
||||||
+
|
|
||||||
+ c_alloc = 0;
|
|
||||||
+ /*
|
|
||||||
+ * Do an initial allocation if the file is "large". Estimate
|
|
||||||
+ * 32 bytes per line and define "large" as more than half of
|
|
||||||
+ * the alloc growth size (256 entries).
|
|
||||||
+ */
|
|
||||||
+ if (st.st_size >= ESTIMATED_LINELEN * HCFILE_ALLOC_SIZE / 2) {
|
|
||||||
+ c_alloc = st.st_size / ESTIMATED_LINELEN;
|
|
||||||
+ hcfile.c_data = (struct hcent*)malloc(c_alloc * sizeof(struct hcent));
|
|
||||||
+ if (!hcfile.c_data) {
|
|
||||||
+ goto oom;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ p = (const char *)h_addr;
|
|
||||||
+ pend = p + st.st_size;
|
|
||||||
+ while (p < pend) {
|
|
||||||
+ const char *eol, *addr, *name;
|
|
||||||
+ size_t len;
|
|
||||||
+ addr = p;
|
|
||||||
+ eol = (const char*)memchr(p, '\n', pend - p);
|
|
||||||
+ if (!eol)
|
|
||||||
+ break;
|
|
||||||
+ p = eol + 1;
|
|
||||||
+ if (*addr == '#' || *addr == '\n')
|
|
||||||
+ continue;
|
|
||||||
+ len = hstrlen(addr);
|
|
||||||
+ if (len > MAX_ADDRLEN)
|
|
||||||
+ continue;
|
|
||||||
+ name = addr + len;
|
|
||||||
+ while (name < eol && isspace(*name))
|
|
||||||
+ ++name;
|
|
||||||
+ while (name < eol) {
|
|
||||||
+ len = hstrlen(name);
|
|
||||||
+ if (len == 0)
|
|
||||||
+ break;
|
|
||||||
+ if (len < MAX_HOSTLEN) {
|
|
||||||
+ struct hcent *ent;
|
|
||||||
+ if (c_alloc <= hcfile.c_len) {
|
|
||||||
+ struct hcent *c_data;
|
|
||||||
+ c_alloc += HCFILE_ALLOC_SIZE;
|
|
||||||
+ c_data = (struct hcent*)realloc(hcfile.c_data, c_alloc * sizeof(struct hcent));
|
|
||||||
+ if (!c_data) {
|
|
||||||
+ goto oom;
|
|
||||||
+ }
|
|
||||||
+ hcfile.c_data = c_data;
|
|
||||||
+ }
|
|
||||||
+ ent = hcfile.c_data + hcfile.c_len;
|
|
||||||
+ ent->addr = addr - h_addr;
|
|
||||||
+ ent->name = name - h_addr;
|
|
||||||
+ ++hcfile.c_len;
|
|
||||||
+ }
|
|
||||||
+ name += len;
|
|
||||||
+ while (name < eol && isspace(*name))
|
|
||||||
+ ++name;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ qsort(hcfile.c_data, hcfile.c_len,
|
|
||||||
+ sizeof(struct hcent), cmp_hcent_name);
|
|
||||||
+
|
|
||||||
+ flock(h_fd, LOCK_UN);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+oom:
|
|
||||||
+ free(hcfile.c_data);
|
|
||||||
+ munmap(hcfile.h_data, hcfile.h_st.st_size);
|
|
||||||
+ flock(hcfile.h_fd, LOCK_UN);
|
|
||||||
+ close(hcfile.h_fd);
|
|
||||||
+ memset(&hcfile, 0, sizeof(struct hcfile));
|
|
||||||
+ return -1;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Caching version of getaddrinfo.
|
|
||||||
+ *
|
|
||||||
+ * If we find the requested host name in the cache, use getaddrinfo to
|
|
||||||
+ * populate the result for each address we find.
|
|
||||||
+ *
|
|
||||||
+ * Note glibc and bionic differ in the handling of ai_canonname. POSIX
|
|
||||||
+ * says that ai_canonname is only populated in the first result entry.
|
|
||||||
+ * glibc does this. bionic populates ai_canonname in all result entries.
|
|
||||||
+ * We choose the POSIX/glibc way here.
|
|
||||||
+ */
|
|
||||||
+int hc_getaddrinfo(const char *name, const struct addrinfo* hints, struct addrinfo** result)
|
|
||||||
+{
|
|
||||||
+ int ret = 0;
|
|
||||||
+ struct hcent *ent, *cur;
|
|
||||||
+ struct addrinfo *ai;
|
|
||||||
+ struct addrinfo rhints;
|
|
||||||
+ struct addrinfo *last;
|
|
||||||
+ int canonname = 0;
|
|
||||||
+ int cmp;
|
|
||||||
+
|
|
||||||
+ if (getenv("ANDROID_HOSTS_CACHE_DISABLE") != NULL)
|
|
||||||
+ return EAI_SYSTEM;
|
|
||||||
+
|
|
||||||
+ if (!name)
|
|
||||||
+ return EAI_SYSTEM;
|
|
||||||
+
|
|
||||||
+ pthread_mutex_lock(&hclock);
|
|
||||||
+
|
|
||||||
+ if (_hcfilemmap() != 0) {
|
|
||||||
+ ret = EAI_SYSTEM;
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+ ent = _hcfindname(name);
|
|
||||||
+ if (!ent) {
|
|
||||||
+ ret = EAI_NONAME;
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (hints) {
|
|
||||||
+ canonname = (hints->ai_flags & AI_CANONNAME);
|
|
||||||
+ memcpy(&rhints, hints, sizeof(rhints));
|
|
||||||
+ rhints.ai_flags &= ~AI_CANONNAME;
|
|
||||||
+ }
|
|
||||||
+ else {
|
|
||||||
+ memset(&rhints, 0, sizeof(rhints));
|
|
||||||
+ }
|
|
||||||
+ rhints.ai_flags |= AI_NUMERICHOST;
|
|
||||||
+
|
|
||||||
+ last = NULL;
|
|
||||||
+ cur = ent;
|
|
||||||
+ do {
|
|
||||||
+ char addrstr[MAX_ADDRLEN];
|
|
||||||
+ struct addrinfo *res;
|
|
||||||
+
|
|
||||||
+ hstrcpy(addrstr, hcfile.h_data + cur->addr);
|
|
||||||
+
|
|
||||||
+ if (getaddrinfo_numeric(addrstr, nullptr, rhints, &res) == 0) {
|
|
||||||
+ if (!last)
|
|
||||||
+ (*result)->ai_next = res;
|
|
||||||
+ else
|
|
||||||
+ last->ai_next = res;
|
|
||||||
+ last = res;
|
|
||||||
+ while (last->ai_next)
|
|
||||||
+ last = last->ai_next;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if(cur + 1 >= hcfile.c_data + hcfile.c_len)
|
|
||||||
+ break;
|
|
||||||
+ cmp = cmp_hcent_name(cur, cur + 1);
|
|
||||||
+ cur = cur + 1;
|
|
||||||
+ }
|
|
||||||
+ while (!cmp);
|
|
||||||
+
|
|
||||||
+ if (last == NULL) {
|
|
||||||
+ /* This check is equivalent to (*result)->ai_next == NULL */
|
|
||||||
+ ret = EAI_NODATA;
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (canonname) {
|
|
||||||
+ ai = (*result)->ai_next;
|
|
||||||
+ free(ai->ai_canonname);
|
|
||||||
+ ai->ai_canonname = hstrdup(hcfile.h_data + ent->name);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+out:
|
|
||||||
+ pthread_mutex_unlock(&hclock);
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Caching version of gethtbyname.
|
|
||||||
+ *
|
|
||||||
+ * Note glibc and bionic differ in the handling of aliases. glibc returns
|
|
||||||
+ * all aliases for all entries, regardless of whether they match h_addrtype.
|
|
||||||
+ * bionic returns only the aliases for the first hosts entry. We return all
|
|
||||||
+ * aliases for all IPv4 entries.
|
|
||||||
+ *
|
|
||||||
+ * Additionally, if an alias is IPv6 and the primary name for an alias also
|
|
||||||
+ * has an IPv4 entry, glibc will return the IPv4 address(es), but bionic
|
|
||||||
+ * will not. Neither do we.
|
|
||||||
+ */
|
|
||||||
+int hc_gethtbyname(const char *host, int af, struct getnamaddr *info)
|
|
||||||
+{
|
|
||||||
+ int ret = NETDB_SUCCESS;
|
|
||||||
+ struct hcent *ent, *cur;
|
|
||||||
+ int cmp;
|
|
||||||
+ size_t addrlen;
|
|
||||||
+ unsigned int naliases = 0;
|
|
||||||
+ char *aliases[MAXALIASES];
|
|
||||||
+ unsigned int naddrs = 0;
|
|
||||||
+ char *addr_ptrs[MAXADDRS];
|
|
||||||
+ unsigned int n;
|
|
||||||
+
|
|
||||||
+ if (getenv("ANDROID_HOSTS_CACHE_DISABLE") != NULL)
|
|
||||||
+ return NETDB_INTERNAL;
|
|
||||||
+
|
|
||||||
+ switch (af) {
|
|
||||||
+ case AF_INET: addrlen = NS_INADDRSZ; break;
|
|
||||||
+ case AF_INET6: addrlen = NS_IN6ADDRSZ; break;
|
|
||||||
+ default:
|
|
||||||
+ return NETDB_INTERNAL;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ pthread_mutex_lock(&hclock);
|
|
||||||
+
|
|
||||||
+ if (_hcfilemmap() != 0) {
|
|
||||||
+ ret = NETDB_INTERNAL;
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ent = _hcfindname(host);
|
|
||||||
+ if (!ent) {
|
|
||||||
+ ret = HOST_NOT_FOUND;
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ cur = ent;
|
|
||||||
+ do {
|
|
||||||
+ char addr[16];
|
|
||||||
+ char addrstr[MAX_ADDRLEN];
|
|
||||||
+ char namestr[MAX_HOSTLEN];
|
|
||||||
+ const char *name;
|
|
||||||
+
|
|
||||||
+ hstrcpy(addrstr, hcfile.h_data + cur->addr);
|
|
||||||
+ if (inet_pton(af, addrstr, &addr) == 1) {
|
|
||||||
+ char *aligned;
|
|
||||||
+ /* First match is considered the official hostname */
|
|
||||||
+ if (naddrs == 0) {
|
|
||||||
+ hstrcpy(namestr, hcfile.h_data + cur->name);
|
|
||||||
+ HENT_SCOPY(info->hp->h_name, namestr, info->buf, info->buflen);
|
|
||||||
+ }
|
|
||||||
+ for (name = hcfile.h_data + cur->name; name; name = _hcnextname(name)) {
|
|
||||||
+ if (!hstrcmp(name, host))
|
|
||||||
+ continue;
|
|
||||||
+ hstrcpy(namestr, name);
|
|
||||||
+ HENT_SCOPY(aliases[naliases], namestr, info->buf, info->buflen);
|
|
||||||
+ ++naliases;
|
|
||||||
+ if (naliases >= MAXALIASES)
|
|
||||||
+ goto nospc;
|
|
||||||
+ }
|
|
||||||
+ aligned = (char *)ALIGN(info->buf);
|
|
||||||
+ if (info->buf != aligned) {
|
|
||||||
+ if ((ptrdiff_t)info->buflen < (aligned - info->buf))
|
|
||||||
+ goto nospc;
|
|
||||||
+ info->buflen -= (aligned - info->buf);
|
|
||||||
+ info->buf = aligned;
|
|
||||||
+ }
|
|
||||||
+ HENT_COPY(addr_ptrs[naddrs], addr, addrlen, info->buf, info->buflen);
|
|
||||||
+ ++naddrs;
|
|
||||||
+ if (naddrs >= MAXADDRS)
|
|
||||||
+ goto nospc;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if(cur + 1 >= hcfile.c_data + hcfile.c_len)
|
|
||||||
+ break;
|
|
||||||
+ cmp = cmp_hcent_name(cur, cur + 1);
|
|
||||||
+ cur = cur + 1;
|
|
||||||
+ }
|
|
||||||
+ while (!cmp);
|
|
||||||
+
|
|
||||||
+ if (naddrs == 0) {
|
|
||||||
+ ret = HOST_NOT_FOUND;
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ addr_ptrs[naddrs++] = NULL;
|
|
||||||
+ aliases[naliases++] = NULL;
|
|
||||||
+
|
|
||||||
+ /* hp->h_name already populated */
|
|
||||||
+ HENT_ARRAY(info->hp->h_aliases, naliases, info->buf, info->buflen);
|
|
||||||
+ for (n = 0; n < naliases; ++n) {
|
|
||||||
+ info->hp->h_aliases[n] = aliases[n];
|
|
||||||
+ }
|
|
||||||
+ info->hp->h_addrtype = af;
|
|
||||||
+ info->hp->h_length = addrlen;
|
|
||||||
+ HENT_ARRAY(info->hp->h_addr_list, naddrs, info->buf, info->buflen);
|
|
||||||
+ for (n = 0; n < naddrs; ++n) {
|
|
||||||
+ info->hp->h_addr_list[n] = addr_ptrs[n];
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+out:
|
|
||||||
+ pthread_mutex_unlock(&hclock);
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+nospc:
|
|
||||||
+ ret = NETDB_INTERNAL;
|
|
||||||
+ goto out;
|
|
||||||
+}
|
|
||||||
diff --git a/hosts_cache.h b/hosts_cache.h
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..55138dc
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/hosts_cache.h
|
|
||||||
@@ -0,0 +1,28 @@
|
|
||||||
+/*
|
|
||||||
+ * Copyright (C) 2016 The CyanogenMod Project
|
|
||||||
+ * Copyright (C) 2020 The LineageOS Project
|
|
||||||
+ *
|
|
||||||
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
+ * you may not use this file except in compliance with the License.
|
|
||||||
+ * You may obtain a copy of the License at
|
|
||||||
+ *
|
|
||||||
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
+ *
|
|
||||||
+ * Unless required by applicable law or agreed to in writing, software
|
|
||||||
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
+ * See the License for the specific language governing permissions and
|
|
||||||
+ * limitations under the License.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#ifndef NETD_RESOLV_HOSTS_CACHE_H
|
|
||||||
+#define NETD_RESOLV_HOSTS_CACHE_H
|
|
||||||
+
|
|
||||||
+struct getnamaddr;
|
|
||||||
+
|
|
||||||
+int hc_getaddrinfo(const char* name, const struct addrinfo* hints,
|
|
||||||
+ struct addrinfo** result);
|
|
||||||
+
|
|
||||||
+int hc_gethtbyname(const char *host, int af, struct getnamaddr *info);
|
|
||||||
+
|
|
||||||
+#endif
|
|
||||||
diff --git a/sethostent.cpp b/sethostent.cpp
|
|
||||||
index 7f9384c..f1bf657 100644
|
|
||||||
--- a/sethostent.cpp
|
|
||||||
+++ b/sethostent.cpp
|
|
||||||
@@ -43,6 +43,8 @@
|
|
||||||
#include "hostent.h"
|
|
||||||
#include "resolv_private.h"
|
|
||||||
|
|
||||||
+#include "hosts_cache.h"
|
|
||||||
+
|
|
||||||
constexpr int MAXALIASES = 35;
|
|
||||||
constexpr int MAXADDRS = 35;
|
|
||||||
|
|
||||||
@@ -69,6 +71,11 @@ int _hf_gethtbyname2(const char* name, int af, getnamaddr* info) {
|
|
||||||
char* aliases[MAXALIASES];
|
|
||||||
char* addr_ptrs[MAXADDRS];
|
|
||||||
|
|
||||||
+ int rc = hc_gethtbyname(name, af, info);
|
|
||||||
+ if (rc != NETDB_INTERNAL) {
|
|
||||||
+ return (rc == NETDB_SUCCESS ? 0 : EAI_NODATA);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
FILE* hf = NULL;
|
|
||||||
sethostent_r(&hf);
|
|
||||||
if (hf == NULL) {
|
|
||||||
--
|
|
||||||
2.34.1
|
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Tom Marshall <tdm.code@gmail.com>
|
|
||||||
Date: Thu, 16 Jan 2020 13:07:04 -0800
|
|
||||||
Subject: [PATCH] DnsResolver: Support wildcards in cached hosts file
|
|
||||||
|
|
||||||
If an exact name is not found in the hosts file and the host name
|
|
||||||
contains at least one dot, search for entries of the form "*.domain",
|
|
||||||
where domain is the portion of the host name after the first dot. If
|
|
||||||
that is not found, repeat using the domain.
|
|
||||||
|
|
||||||
Example: a.b.c.example.com would search for the following in turn:
|
|
||||||
a.b.c.example.com
|
|
||||||
*.b.c.example.com
|
|
||||||
*.c.example.com
|
|
||||||
*.example.com
|
|
||||||
*.com
|
|
||||||
|
|
||||||
Note: this change is the analogue of the bionic change of the same name.
|
|
||||||
Both should be kept in sync.
|
|
||||||
|
|
||||||
Change-Id: I4b0bb81699151d5b371850daebf785e35ec9b170
|
|
||||||
---
|
|
||||||
hosts_cache.cpp | 29 ++++++++++++++++++++++++++++-
|
|
||||||
1 file changed, 28 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/hosts_cache.cpp b/hosts_cache.cpp
|
|
||||||
index a40fb403..258eac1b 100644
|
|
||||||
--- a/hosts_cache.cpp
|
|
||||||
+++ b/hosts_cache.cpp
|
|
||||||
@@ -126,7 +126,7 @@ static int cmp_hcent_name(const void *a, const void *b)
|
|
||||||
return hstrcmp(na, nb);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct hcent *_hcfindname(const char *name)
|
|
||||||
+static struct hcent *_hcfindname_exact(const char *name)
|
|
||||||
{
|
|
||||||
size_t first, last, mid;
|
|
||||||
struct hcent *cur = NULL;
|
|
||||||
@@ -167,6 +167,33 @@ found:
|
|
||||||
return cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static struct hcent *_hcfindname(const char *name)
|
|
||||||
+{
|
|
||||||
+ struct hcent *ent;
|
|
||||||
+ char namebuf[MAX_HOSTLEN];
|
|
||||||
+ char *p;
|
|
||||||
+ char *dot;
|
|
||||||
+
|
|
||||||
+ ent = _hcfindname_exact(name);
|
|
||||||
+ if (!ent && strlen(name) < sizeof(namebuf)) {
|
|
||||||
+ strlcpy(namebuf, name, sizeof(namebuf));
|
|
||||||
+ p = namebuf;
|
|
||||||
+ do {
|
|
||||||
+ dot = strchr(p, '.');
|
|
||||||
+ if (!dot)
|
|
||||||
+ break;
|
|
||||||
+ if (dot > p) {
|
|
||||||
+ *(dot - 1) = '*';
|
|
||||||
+ ent = _hcfindname_exact(dot - 1);
|
|
||||||
+ }
|
|
||||||
+ p = dot + 1;
|
|
||||||
+ }
|
|
||||||
+ while (!ent);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return ent;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
* Find next name on line, if any.
|
|
||||||
*
|
|
|
@ -1,36 +0,0 @@
|
||||||
From 10344912d45747fc40cc07ae18c0b3753f4c545c Mon Sep 17 00:00:00 2001
|
|
||||||
From: harvey186 <harvey186@hotmail.com>
|
|
||||||
Date: Sat, 21 Oct 2023 11:14:38 +0200
|
|
||||||
Subject: [PATCH] 0002-hosts_toggle
|
|
||||||
|
|
||||||
Change-Id: Ie3f634e545352fd1f45d54fb75e255afe430e2a3
|
|
||||||
---
|
|
||||||
getaddrinfo.cpp | 5 ++++-
|
|
||||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/getaddrinfo.cpp b/getaddrinfo.cpp
|
|
||||||
index 064ff57..5177035 100644
|
|
||||||
--- a/getaddrinfo.cpp
|
|
||||||
+++ b/getaddrinfo.cpp
|
|
||||||
@@ -57,7 +57,7 @@
|
|
||||||
|
|
||||||
#include <android-base/logging.h>
|
|
||||||
#include <android-base/parseint.h>
|
|
||||||
-
|
|
||||||
+#include <android-base/properties.h>
|
|
||||||
#include "Experiments.h"
|
|
||||||
#include "netd_resolv/resolv.h"
|
|
||||||
#include "res_comp.h"
|
|
||||||
@@ -1548,6 +1548,9 @@ static struct addrinfo* getCustomHosts(const size_t netid, const char* _Nonnull
|
|
||||||
|
|
||||||
static bool files_getaddrinfo(const size_t netid, const char* name, const addrinfo* pai,
|
|
||||||
addrinfo** res) {
|
|
||||||
+ if ((android::base::GetIntProperty("persist.security.hosts_disable", 0) != 0) && (strcmp("localhost", name) != 0) && (strcmp("ip6-localhost", name) != 0))
|
|
||||||
+ return false;
|
|
||||||
+
|
|
||||||
struct addrinfo sentinel = {};
|
|
||||||
struct addrinfo *p, *cur;
|
|
||||||
FILE* hostf = nullptr;
|
|
||||||
--
|
|
||||||
2.34.1
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
From 25f474821b031c59b09d412c64900439ff0067de Mon Sep 17 00:00:00 2001
|
|
||||||
From: harvey186 <harvey186@hotmail.com>
|
|
||||||
Date: Mon, 11 Dec 2023 17:41:13 +0100
|
|
||||||
Subject: [PATCH] 0003-Reuse-align_ptr-in-hosts_cache
|
|
||||||
|
|
||||||
Change-Id: If83e3f195577e575a522c93172b414c0fd604272
|
|
||||||
---
|
|
||||||
hosts_cache.cpp | 5 +----
|
|
||||||
1 file changed, 1 insertion(+), 4 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/hosts_cache.cpp b/hosts_cache.cpp
|
|
||||||
index 489de4e..9578548 100644
|
|
||||||
--- a/hosts_cache.cpp
|
|
||||||
+++ b/hosts_cache.cpp
|
|
||||||
@@ -47,9 +47,6 @@ constexpr int MAXADDRS = 35;
|
|
||||||
#define ESTIMATED_LINELEN 32
|
|
||||||
#define HCFILE_ALLOC_SIZE 256
|
|
||||||
|
|
||||||
-/* From sethostent.c */
|
|
||||||
-#define ALIGNBYTES (sizeof(uintptr_t) - 1)
|
|
||||||
-#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
|
|
||||||
|
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
||||||
|
|
||||||
@@ -502,7 +499,7 @@ int hc_gethtbyname(const char *host, int af, struct getnamaddr *info)
|
|
||||||
if (naliases >= MAXALIASES)
|
|
||||||
goto nospc;
|
|
||||||
}
|
|
||||||
- aligned = (char *)ALIGN(info->buf);
|
|
||||||
+ aligned = align_ptr(info->buf);
|
|
||||||
if (info->buf != aligned) {
|
|
||||||
if ((ptrdiff_t)info->buflen < (aligned - info->buf))
|
|
||||||
goto nospc;
|
|
||||||
--
|
|
||||||
2.34.1
|
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
From 8756a464be8dfad7096d66850a14edcc196625a3 Mon Sep 17 00:00:00 2001
|
|
||||||
From: harvey186 <harvey186@hotmail.com>
|
|
||||||
Date: Tue, 12 Dec 2023 12:51:33 +0100
|
|
||||||
Subject: [PATCH] hosts_cache_refresh
|
|
||||||
|
|
||||||
Change-Id: I627d15f0d53efd1ce2723376268c28ee9cea2536
|
|
||||||
---
|
|
||||||
hosts_cache.cpp | 36 +++++++-----------------------------
|
|
||||||
1 file changed, 7 insertions(+), 29 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/hosts_cache.cpp b/hosts_cache.cpp
|
|
||||||
index 9578548..f795530 100644
|
|
||||||
--- a/hosts_cache.cpp
|
|
||||||
+++ b/hosts_cache.cpp
|
|
||||||
@@ -47,6 +47,9 @@ constexpr int MAXADDRS = 35;
|
|
||||||
#define ESTIMATED_LINELEN 32
|
|
||||||
#define HCFILE_ALLOC_SIZE 256
|
|
||||||
|
|
||||||
+/* From sethostent.c */
|
|
||||||
+#define ALIGNBYTES (sizeof(uintptr_t) - 1)
|
|
||||||
+#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
|
|
||||||
|
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
||||||
|
|
||||||
@@ -125,7 +128,7 @@ static int cmp_hcent_name(const void *a, const void *b)
|
|
||||||
return hstrcmp(na, nb);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct hcent *_hcfindname_exact(const char *name)
|
|
||||||
+static struct hcent *_hcfindname(const char *name)
|
|
||||||
{
|
|
||||||
size_t first, last, mid;
|
|
||||||
struct hcent *cur = NULL;
|
|
||||||
@@ -166,33 +169,6 @@ found:
|
|
||||||
return cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct hcent *_hcfindname(const char *name)
|
|
||||||
-{
|
|
||||||
- struct hcent *ent;
|
|
||||||
- char namebuf[MAX_HOSTLEN];
|
|
||||||
- char *p;
|
|
||||||
- char *dot;
|
|
||||||
-
|
|
||||||
- ent = _hcfindname_exact(name);
|
|
||||||
- if (!ent && strlen(name) < sizeof(namebuf)) {
|
|
||||||
- strlcpy(namebuf, name, sizeof(namebuf));
|
|
||||||
- p = namebuf;
|
|
||||||
- do {
|
|
||||||
- dot = strchr(p, '.');
|
|
||||||
- if (!dot)
|
|
||||||
- break;
|
|
||||||
- if (dot > p) {
|
|
||||||
- *(dot - 1) = '*';
|
|
||||||
- ent = _hcfindname_exact(dot - 1);
|
|
||||||
- }
|
|
||||||
- p = dot + 1;
|
|
||||||
- }
|
|
||||||
- while (!ent);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- return ent;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
/*
|
|
||||||
* Find next name on line, if any.
|
|
||||||
*
|
|
||||||
@@ -499,7 +475,7 @@ int hc_gethtbyname(const char *host, int af, struct getnamaddr *info)
|
|
||||||
if (naliases >= MAXALIASES)
|
|
||||||
goto nospc;
|
|
||||||
}
|
|
||||||
- aligned = align_ptr(info->buf);
|
|
||||||
+ aligned = (char *)ALIGN(info->buf);
|
|
||||||
if (info->buf != aligned) {
|
|
||||||
if ((ptrdiff_t)info->buflen < (aligned - info->buf))
|
|
||||||
goto nospc;
|
|
||||||
@@ -545,3 +521,5 @@ out:
|
|
||||||
|
|
||||||
nospc:
|
|
||||||
ret = NETDB_INTERNAL;
|
|
||||||
+ goto out;
|
|
||||||
+}
|
|
||||||
--
|
|
||||||
2.34.1
|
|
||||||
|
|
Loading…
Reference in New Issue