diff options
-rw-r--r-- | src/tools/wg-quick/android/binder_ndk.c | 126 | ||||
-rw-r--r-- | src/tools/wg-quick/android/binder_ndk.h | 134 | ||||
-rw-r--r-- | src/tools/wg-quick/android/dnsresolver.c | 272 | ||||
-rw-r--r-- | src/tools/wg-quick/android/dnsresolver.h | 38 | ||||
-rw-r--r-- | src/tools/wg-quick/android/wg-quick.c (renamed from src/tools/wg-quick/android.c) | 77 |
5 files changed, 647 insertions, 0 deletions
diff --git a/src/tools/wg-quick/android/binder_ndk.c b/src/tools/wg-quick/android/binder_ndk.c new file mode 100644 index 0000000..39a6323 --- /dev/null +++ b/src/tools/wg-quick/android/binder_ndk.c @@ -0,0 +1,126 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdbool.h> +#include <stdint.h> +#include <errno.h> +#include <dlfcn.h> + +#include "binder_ndk.h" + +static bool binder_available = false; + +bool binder_is_available(void) +{ + return binder_available; +} + +AIBinder_Class *(*AIBinder_Class_define)(const char *interfaceDescriptor, AIBinder_Class_onCreate onCreate, AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact) __attribute__((warn_unused_result)) = NULL; +bool (*AIBinder_associateClass)(AIBinder *binder, const AIBinder_Class *clazz) = NULL; +void (*AIBinder_decStrong)(AIBinder *binder) = NULL; +binder_status_t (*AIBinder_prepareTransaction)(AIBinder *binder, AParcel **in) = NULL; +binder_status_t (*AIBinder_transact)(AIBinder *binder, transaction_code_t code, AParcel **in, AParcel **out, binder_flags_t flags) = NULL; +binder_status_t (*AIBinder_ping)(AIBinder *binder) = NULL; +binder_status_t (*AIBinder_dump)(AIBinder *binder, int fd, const char **args, uint32_t numArgs) = NULL; +binder_status_t (*AParcel_readStatusHeader)(const AParcel *parcel, AStatus **status) = NULL; +binder_status_t (*AParcel_readBool)(const AParcel *parcel, bool *value) = NULL; +void (*AParcel_delete)(AParcel *parcel) = NULL; +binder_status_t (*AParcel_setDataPosition)(const AParcel *parcel, int32_t position) = NULL; +int32_t (*AParcel_getDataPosition)(const AParcel *parcel) = NULL; +binder_status_t (*AParcel_writeInt32)(AParcel *parcel, int32_t value) = NULL; +binder_status_t (*AParcel_writeStringArray)(AParcel *parcel, const void *arrayData, int32_t length, AParcel_stringArrayElementGetter getter) = NULL; +binder_status_t (*AParcel_writeString)(AParcel *parcel, const char *string, int32_t length) = NULL; +bool (*AStatus_isOk)(const AStatus *status) = NULL; +void (*AStatus_delete)(AStatus *status) = NULL; +binder_exception_t (*AStatus_getExceptionCode)(const AStatus *status) = NULL; +int32_t (*AStatus_getServiceSpecificError)(const AStatus *status) = NULL; +const char* (*AStatus_getMessage)(const AStatus *status) = NULL; +binder_status_t (*AStatus_getStatus)(const AStatus *status) = NULL; +AIBinder *(*AServiceManager_getService)(const char *instance) __attribute__((__warn_unused_result__)) = NULL; + +static __attribute__((__constructor__(65535))) void load_symbols(void) +{ + void *handle = NULL; + if (!(handle = dlopen("libbinder_ndk.so", RTLD_LAZY))) { + fprintf(stderr, "Warning: libbinder_ndk.so is not available\n"); + binder_available = false; + return; + } + else + binder_available = true; + +#define X(symb) ({ \ + if (!((symb) = (__typeof__(symb))dlsym(handle, #symb))) { \ + fprintf(stderr, "Error: unable to import " #symb " from libbinder_ndk.so\n"); \ + exit(ELIBACC); \ + } \ + }) + + X(AIBinder_Class_define); + X(AIBinder_associateClass); + X(AIBinder_decStrong); + X(AIBinder_prepareTransaction); + X(AIBinder_transact); + X(AIBinder_ping); + X(AIBinder_dump); + X(AParcel_readStatusHeader); + X(AParcel_readBool); + X(AParcel_delete); + X(AParcel_setDataPosition); + X(AParcel_getDataPosition); + X(AParcel_writeInt32); + X(AParcel_writeStringArray); + X(AParcel_writeString); + X(AStatus_isOk); + X(AStatus_delete); + X(AStatus_getExceptionCode); + X(AStatus_getServiceSpecificError); + X(AStatus_getMessage); + X(AStatus_getStatus); + X(AServiceManager_getService); +#undef X +} + +void cleanup_binder(AIBinder **binder) +{ + AIBinder_decStrong(*binder); +} + +void cleanup_status(AStatus **status) +{ + AStatus_delete(*status); +} + +void cleanup_parcel(AParcel **parcel) +{ + AParcel_delete(*parcel); +} + +binder_status_t meaningful_binder_status(const AStatus *status_out) +{ + binder_status_t status = STATUS_OK; + binder_exception_t exc_code; + int32_t exc_code_service; + const char *message; + + if (!AStatus_isOk(status_out)) { + exc_code = AStatus_getExceptionCode(status_out); + if (exc_code == EX_TRANSACTION_FAILED) { + status = AStatus_getStatus(status_out); + fprintf(stderr, "Error: transaction failed: %d\n", status); + } + else { + message = AStatus_getMessage(status_out); + + if (exc_code == EX_SERVICE_SPECIFIC) { + exc_code_service = AStatus_getServiceSpecificError(status_out); + fprintf(stderr, "Error: service specific exception code: %d%s%s\n", exc_code_service, message ? ": " : "", message ?: ""); + } + else + fprintf(stderr, "Error: exception code: %d%s%s\n", exc_code, message ? ": " : "", message ?: ""); + + status = STATUS_FAILED_TRANSACTION; + } + } + + return status; +} diff --git a/src/tools/wg-quick/android/binder_ndk.h b/src/tools/wg-quick/android/binder_ndk.h new file mode 100644 index 0000000..55f35eb --- /dev/null +++ b/src/tools/wg-quick/android/binder_ndk.h @@ -0,0 +1,134 @@ +#pragma once + +#include <stdbool.h> +#include <stdint.h> +#include <errno.h> +#include <string.h> + +#define _cleanup_status_ __attribute__((__cleanup__(cleanup_status))) +#define _cleanup_parcel_ __attribute__((__cleanup__(cleanup_parcel))) +#define _cleanup_binder_ __attribute__((__cleanup__(cleanup_binder))) + +bool binder_is_available(void); + +typedef int32_t binder_status_t; +typedef int32_t binder_exception_t; +typedef uint32_t transaction_code_t; +typedef uint32_t binder_flags_t; + +/* values are from AOSP repository platform/frameworks/native + * in libs/binder/ndk/include_ndk/android/binder_status.h + */ + +enum { + STATUS_OK = 0, + STATUS_UNKNOWN_ERROR = -2147483647 - 1, + STATUS_NO_MEMORY = -ENOMEM, + STATUS_INVALID_OPERATION = -ENOSYS, + STATUS_BAD_VALUE = -EINVAL, + STATUS_BAD_TYPE = STATUS_UNKNOWN_ERROR + 1, + STATUS_NAME_NOT_FOUND = -ENOENT, + STATUS_PERMISSION_DENIED = -EPERM, + STATUS_NO_INIT = -ENODEV, + STATUS_ALREADY_EXISTS = -EEXIST, + STATUS_DEAD_OBJECT = -EPIPE, + STATUS_FAILED_TRANSACTION = STATUS_UNKNOWN_ERROR + 2, + STATUS_BAD_INDEX = -EOVERFLOW, + STATUS_NOT_ENOUGH_DATA = -ENODATA, + STATUS_WOULD_BLOCK = -EWOULDBLOCK, + STATUS_TIMED_OUT = -ETIMEDOUT, + STATUS_UNKNOWN_TRANSACTION = -EBADMSG, + STATUS_FDS_NOT_ALLOWED = STATUS_UNKNOWN_ERROR + 7, + STATUS_UNEXPECTED_NULL = STATUS_UNKNOWN_ERROR + 8 +}; + +enum { + EX_NONE = 0, + EX_SECURITY = -1, + EX_BAD_PARCELABLE = -2, + EX_ILLEGAL_ARGUMENT = -3, + EX_NULL_POINTER = -4, + EX_ILLEGAL_STATE = -5, + EX_NETWORK_MAIN_THREAD = -6, + EX_UNSUPPORTED_OPERATION = -7, + EX_SERVICE_SPECIFIC = -8, + EX_PARCELABLE = -9, + EX_TRANSACTION_FAILED = -129 +}; + +enum { + FLAG_ONEWAY = 0x01, +}; + +enum { + FIRST_CALL_TRANSACTION = 0x00000001, + LAST_CALL_TRANSACTION = 0x00ffffff +}; + +struct AIBinder; +struct AParcel; +struct AStatus; +struct AIBinder_Class; + +typedef struct AIBinder AIBinder; +typedef struct AParcel AParcel; +typedef struct AStatus AStatus; +typedef struct AIBinder_Class AIBinder_Class; + +typedef void *(*AIBinder_Class_onCreate)(void *args); +typedef void (*AIBinder_Class_onDestroy)(void *userData); +typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder *binder, transaction_code_t code, const AParcel *in, AParcel *out); +typedef const char *(*AParcel_stringArrayElementGetter)(const void *arrayData, size_t index, int32_t *outLength); + +/* function pointers to the libbinder_ndk.so symbols, + * NULL if they cannot be loaded */ +extern AIBinder_Class *(*AIBinder_Class_define)(const char *interfaceDescriptor, AIBinder_Class_onCreate onCreate, AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact) __attribute__((warn_unused_result)); +extern bool (*AIBinder_associateClass)(AIBinder *binder, const AIBinder_Class *clazz); +extern void (*AIBinder_decStrong)(AIBinder *binder); +extern binder_status_t (*AIBinder_prepareTransaction)(AIBinder *binder, AParcel **in); +extern binder_status_t (*AIBinder_transact)(AIBinder *binder, transaction_code_t code, AParcel **in, AParcel **out, binder_flags_t flags); +extern binder_status_t (*AIBinder_ping)(AIBinder *binder); +extern binder_status_t (*AIBinder_dump)(AIBinder *binder, int fd, const char **args, uint32_t numArgs); +extern binder_status_t (*AParcel_readStatusHeader)(const AParcel *parcel, AStatus **status); +extern binder_status_t (*AParcel_readBool)(const AParcel *parcel, bool *value); +extern void (*AParcel_delete)(AParcel *parcel); +extern binder_status_t (*AParcel_setDataPosition)(const AParcel *parcel, int32_t position); +extern int32_t (*AParcel_getDataPosition)(const AParcel *parcel); +extern binder_status_t (*AParcel_writeInt32)(AParcel *parcel, int32_t value); +extern binder_status_t (*AParcel_writeStringArray)(AParcel *parcel, const void *arrayData, int32_t length, AParcel_stringArrayElementGetter getter); +extern binder_status_t (*AParcel_readStatusHeader)(const AParcel *parcel, AStatus **status); +extern binder_status_t (*AParcel_writeString)(AParcel *parcel, const char *string, int32_t length); +extern bool (*AStatus_isOk)(const AStatus *status); +extern void (*AStatus_delete)(AStatus *status); +extern binder_exception_t (*AStatus_getExceptionCode)(const AStatus *status); +extern int32_t (*AStatus_getServiceSpecificError)(const AStatus *status); +extern const char* (*AStatus_getMessage)(const AStatus *status); +extern binder_status_t (*AStatus_getStatus)(const AStatus *status); +extern AIBinder *(*AServiceManager_getService)(const char *instance) __attribute__((__warn_unused_result__)); + +void cleanup_binder(AIBinder **); +void cleanup_status(AStatus **); +void cleanup_parcel(AParcel **); + +static inline int32_t string_size(const char *str) +{ + return str ? strlen(str) : -1; +} + +static inline int32_t string_array_size(char *const *array) +{ + int32_t size = -1; + if (!array) + return size; + for (size = 0; array[size]; ++size); + return size; +} + +static inline const char *string_array_getter(const void *array_data, size_t index, int32_t *outlength) +{ + const char **array = (const char **)array_data; + *outlength = array[index] ? strlen(array[index]) : -1; + return array[index]; +} + +binder_status_t meaningful_binder_status(const AStatus *status_out); diff --git a/src/tools/wg-quick/android/dnsresolver.c b/src/tools/wg-quick/android/dnsresolver.c new file mode 100644 index 0000000..f07060d --- /dev/null +++ b/src/tools/wg-quick/android/dnsresolver.c @@ -0,0 +1,272 @@ +#include <stdio.h> +#include <stdlib.h> +#include <uchar.h> +#include <string.h> + +#include "dnsresolver.h" +#include "binder_ndk.h" + +#define DNSRESOLVER_DESCRIPTOR "android.net.IDnsResolver" + +static void *on_create() +{ + fprintf(stderr, "Error: on_create called on proxy object\n"); + exit(ENOTSUP); +} + +static void on_destroy() +{ + fprintf(stderr, "Error: on_destroy called on proxy object\n"); + exit(ENOTSUP); +} + +static binder_status_t on_transact() +{ + fprintf(stderr, "Error: on_transact called on a proxy object\n"); + exit(ENOTSUP); +} + +void *dnsresolver_get_handle(void) +{ + if (!binder_is_available()) { + return NULL; + } + + AIBinder *binder; + AIBinder_Class *clazz; + + binder = AServiceManager_getService("dnsresolver"); + if (!binder) + return NULL; + clazz = AIBinder_Class_define(DNSRESOLVER_DESCRIPTOR, &on_create, &on_destroy, &on_transact); + if (!clazz) + goto error; + + if (!AIBinder_associateClass(binder, clazz)) + goto error; + + return binder; +error: + AIBinder_decStrong(binder); + return NULL; +} + +void dnsresolver_dec_ref(void *handle) +{ + AIBinder *const binder = handle; + AIBinder_decStrong(binder); +} + +int32_t dnsresolver_is_alive(void *handle, bool *aidl_return) +{ + AIBinder *const binder = handle; + binder_status_t status; + _cleanup_parcel_ AParcel *parcel_in = NULL; + _cleanup_parcel_ AParcel *parcel_out = NULL; + _cleanup_status_ AStatus *status_out = NULL; + + status = AIBinder_prepareTransaction(binder, &parcel_in); + if (status != STATUS_OK) + return status; + + status = AIBinder_transact(binder, FIRST_CALL_TRANSACTION + 0 /* isAlive */, &parcel_in, &parcel_out, 0); + if (status != STATUS_OK) + return status; + + status = AParcel_readStatusHeader(parcel_out, &status_out); + if (status != STATUS_OK) + return status; + + if (!AStatus_isOk(status_out)) + return meaningful_binder_status(status_out); + + return AParcel_readBool(parcel_out, aidl_return); +} + +int32_t dnsresolver_create_network_cache(void *handle, int32_t netid) +{ + AIBinder *const binder = handle; + binder_status_t status; + _cleanup_parcel_ AParcel *parcel_in = NULL; + _cleanup_parcel_ AParcel *parcel_out = NULL; + _cleanup_status_ AStatus *status_out = NULL; + + status = AIBinder_prepareTransaction(binder, &parcel_in); + if (status != STATUS_OK) + return status; + + status = AParcel_writeInt32(parcel_in, netid); + if (status != STATUS_OK) + return status; + + status = AIBinder_transact(binder, FIRST_CALL_TRANSACTION + 7 /* createNetworkCache */, &parcel_in, &parcel_out, 0); + if (status != STATUS_OK) + return status; + + status = AParcel_readStatusHeader(parcel_out, &status_out); + if (status != STATUS_OK) + return status; + + if (!AStatus_isOk(status_out)) + return meaningful_binder_status(status_out); + + return STATUS_OK; +} + +int32_t dnsresolver_destroy_network_cache(void *handle, int32_t netid) +{ + AIBinder *const binder = handle; + binder_status_t status; + _cleanup_parcel_ AParcel *parcel_in = NULL; + _cleanup_parcel_ AParcel *parcel_out = NULL; + _cleanup_status_ AStatus *status_out = NULL; + + status = AIBinder_prepareTransaction(binder, &parcel_in); + if (status != STATUS_OK) + return status; + + status = AParcel_writeInt32(parcel_in, netid); + if (status != STATUS_OK) + return status; + + status = AIBinder_transact(binder, FIRST_CALL_TRANSACTION + 8 /* destroyNetworkCache */, &parcel_in, &parcel_out, 0); + if (status != STATUS_OK) + return status; + + status = AParcel_readStatusHeader(parcel_out, &status_out); + if (status != STATUS_OK) + return status; + + if (!AStatus_isOk(status_out)) + return meaningful_binder_status(status_out); + + return STATUS_OK; +} + +int32_t dnsresolver_set_log_severity(void *handle, int32_t log_severity) +{ + AIBinder *const binder = handle; + binder_status_t status; + _cleanup_parcel_ AParcel *parcel_in = NULL; + _cleanup_parcel_ AParcel *parcel_out = NULL; + _cleanup_status_ AStatus *status_out = NULL; + + status = AIBinder_prepareTransaction(binder, &parcel_in); + if (status != STATUS_OK) + return status; + + status = AParcel_writeInt32(parcel_in, log_severity); + if (status != STATUS_OK) + return status; + + status = AIBinder_transact(binder, FIRST_CALL_TRANSACTION + 9 /* setLogSeverity */, &parcel_in, &parcel_out, 0); + if (status != STATUS_OK) + return status; + + status = AParcel_readStatusHeader(parcel_out, &status_out); + if (status != STATUS_OK) + return status; + + if (!AStatus_isOk(status_out)) + return meaningful_binder_status(status_out); + + return STATUS_OK; +} + +int32_t dnsresolver_set_resolver_configuration(void *handle, const struct resolver_params *params) +{ + AIBinder *const binder = handle; + binder_status_t status; + _cleanup_parcel_ AParcel *parcel_in = NULL; + _cleanup_parcel_ AParcel *parcel_out = NULL; + _cleanup_status_ AStatus *status_out = NULL; + int32_t start_position, end_position; + + status = AIBinder_prepareTransaction(binder, &parcel_in); + if (status != STATUS_OK) + return status; + + status = AParcel_writeInt32(parcel_in, 1); + if (status != STATUS_OK) + return status; + + start_position = AParcel_getDataPosition(parcel_in); + status = AParcel_writeInt32(parcel_in, 0); + if (status != STATUS_OK) + return status; + + status = AParcel_writeInt32(parcel_in, params->netid); + if (status != STATUS_OK) + return status; + status = AParcel_writeInt32(parcel_in, params->sample_validity_seconds); + if (status != STATUS_OK) + return status; + status = AParcel_writeInt32(parcel_in, params->success_threshold); + if (status != STATUS_OK) + return status; + status = AParcel_writeInt32(parcel_in, params->min_samples); + if (status != STATUS_OK) + return status; + status = AParcel_writeInt32(parcel_in, params->max_samples); + if (status != STATUS_OK) + return status; + status = AParcel_writeInt32(parcel_in, params->base_timeout_msec); + if (status != STATUS_OK) + return status; + status = AParcel_writeInt32(parcel_in, params->retry_count); + if (status != STATUS_OK) + return status; + status = AParcel_writeStringArray(parcel_in, params->servers, string_array_size(params->servers), &string_array_getter); + if (status != STATUS_OK) + return status; + status = AParcel_writeStringArray(parcel_in, params->domains, string_array_size(params->domains), &string_array_getter); + if (status != STATUS_OK) + return status; + status = AParcel_writeString(parcel_in, params->tls_name, string_size(params->tls_name)); + if (status != STATUS_OK) + return status; + status = AParcel_writeStringArray(parcel_in, params->tls_servers, string_array_size(params->tls_servers), &string_array_getter); + if (status != STATUS_OK) + return status; + status = AParcel_writeStringArray(parcel_in, params->tls_fingerprints, string_array_size(params->tls_fingerprints), &string_array_getter); + if (status != STATUS_OK) + return status; + + end_position = AParcel_getDataPosition(parcel_in); + status = AParcel_setDataPosition(parcel_in, start_position); + if (status != STATUS_OK) + return status; + status = AParcel_writeInt32(parcel_in, end_position - start_position); + if (status != STATUS_OK) + return status; + status = AParcel_setDataPosition(parcel_in, end_position); + if (status != STATUS_OK) + return status; + + status = AIBinder_transact(binder, FIRST_CALL_TRANSACTION + 2 /* setResolverConfiguration */, &parcel_in, &parcel_out, 0); + if (status != STATUS_OK) + return status; + + status = AParcel_readStatusHeader(parcel_out, &status_out); + if (status != STATUS_OK) + return status; + + return meaningful_binder_status(status_out); +} + +void dnsresolver_dump(void *handle, int fd) +{ + AIBinder *const binder = handle; + AIBinder_dump(binder, fd, NULL, 0); +} + +int32_t dnsresolver_ping(void *handle) +{ + AIBinder *const binder = handle; + return AIBinder_ping(binder); +} + +void cleanup_dnsresolver(void **handle) +{ + dnsresolver_dec_ref(*handle); +} diff --git a/src/tools/wg-quick/android/dnsresolver.h b/src/tools/wg-quick/android/dnsresolver.h new file mode 100644 index 0000000..09519af --- /dev/null +++ b/src/tools/wg-quick/android/dnsresolver.h @@ -0,0 +1,38 @@ +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +#define _cleanup_dnsresolver_ __attribute__((__cleanup__(cleanup_dnsresolver))) + +struct resolver_params { + int32_t netid; + int32_t sample_validity_seconds; + int32_t success_threshold; + int32_t min_samples; + int32_t max_samples; + int32_t base_timeout_msec; + int32_t retry_count; + char **servers; /* NULL terminated array of zero-terminated UTF-8 strings */ + char **domains; /* NULL terminated array of zero-terminated UTF-8 strings */ + char *tls_name; /* zero-terminated UTF-8 string */ + char **tls_servers; /* NULL terminated array of zero-terminated UTF-8 strings */ + char **tls_fingerprints; /* NULL terminated array of zero-terminated UTF-8 strings */ +}; + +/* + * the int32_t return codes below are 0 if there is no error, + * see binder_status_t in binder_ndk.h for the meaning of other values + */ +void *dnsresolver_get_handle(void) __attribute__((__warn_unused_result__)); +void dnsresolver_dec_ref(void *handle); +int32_t dnsresolver_set_resolver_configuration(void *handle, const struct resolver_params *params); +int32_t dnsresolver_create_network_cache(void *handle, int32_t netid); +int32_t dnsresolver_destroy_network_cache(void *handle, int32_t netid); + +int32_t dnsresolver_is_alive(void *handle, bool *result); +int32_t dnsresolver_set_log_severity(void *handle, int32_t log_severity); +void dnsresolver_dump(void *handle, int fd); +int32_t dnsresolver_ping(void *handle); + +void cleanup_dnsresolver(void **handle); diff --git a/src/tools/wg-quick/android.c b/src/tools/wg-quick/android/wg-quick.c index 880fa1f..fcde744 100644 --- a/src/tools/wg-quick/android.c +++ b/src/tools/wg-quick/android/wg-quick.c @@ -25,6 +25,8 @@ #include <sys/wait.h> #include <sys/param.h> +#include "dnsresolver.h" + #ifndef WG_PACKAGE_NAME #define WG_PACKAGE_NAME "com.wireguard.android" #endif @@ -32,6 +34,17 @@ #define WG_CONFIG_SEARCH_PATHS "/data/misc/wireguard /data/data/" WG_PACKAGE_NAME "/files" #endif +/* + * the following values are default values observed in AOSP + */ +#define WG_DNS_SAMPLE_VALIDITY 1800 /* sec */ +#define WG_DNS_SUCCESS_THRESHOLD 25 +#define WG_DNS_MIN_SAMPLES 8 +#define WG_DNS_MAX_SAMPLES 8 +#define WG_DNS_BASE_TIMEOUT 5000 /* msec */ +#define WG_DNS_RETRY_COUNT 2 + + #define _printf_(x, y) __attribute__((format(printf, x, y))) #define _cleanup_(x) __attribute__((cleanup(x))) #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) @@ -121,6 +134,15 @@ static void free_command_buffer(struct command_buffer *c) pclose(c->stream); free(c->line); } +static void freenularr(void *p) +{ + void **a = *(void ***)p; + if (a) { + for (int i = 0; a[i]; ++i) + free(a[i]); + } + free(a); +} static void freep(void *p) { @@ -134,6 +156,7 @@ static void fclosep(FILE **f) #define _cleanup_free_ _cleanup_(freep) #define _cleanup_fclose_ _cleanup_(fclosep) #define _cleanup_regfree_ _cleanup_(regfree) +#define _cleanup_freenularr_ _cleanup_(freenularr) #define DEFINE_CMD(name) _cleanup_(free_command_buffer) struct command_buffer name = { 0 }; @@ -442,6 +465,10 @@ static void set_dnses(unsigned int netid, const char *dnses) _cleanup_free_ char *mutable = xstrdup(dnses); _cleanup_free_ char *arglist = xmalloc(len * 4 + 1); _cleanup_free_ char *arg = xmalloc(len + 4); + _cleanup_freenularr_ char **dns_list = xmalloc(len + 2); + size_t dns_list_size = 0; + _cleanup_free_ char *pretty_dns_list = NULL; + _cleanup_dnsresolver_ void *handle = NULL; if (!len) return; @@ -452,7 +479,57 @@ static void set_dnses(unsigned int netid, const char *dnses) continue; snprintf(arg, len + 3, "'%s' ", dns); strncat(arglist, arg, len * 4 - 1); + dns_list[dns_list_size++] = xstrdup(dns); } + dns_list[dns_list_size] = NULL; + + if ((handle = dnsresolver_get_handle())) { + if (!dns_list_size) + return; + + int32_t status; + + printf("[#] <binder>::dnsResolver::createNetworkCache(%u)\n", netid); + status = dnsresolver_create_network_cache(handle, netid); + if (status != 0) { + fprintf(stderr, "Error: unable to create network cache\n"); + exit(ELIBACC); + } + + struct resolver_params params = { + .netid = netid, + .sample_validity_seconds = WG_DNS_SAMPLE_VALIDITY, + .success_threshold = WG_DNS_SUCCESS_THRESHOLD, + .min_samples = WG_DNS_MIN_SAMPLES, + .max_samples = WG_DNS_MAX_SAMPLES, + .base_timeout_msec = WG_DNS_BASE_TIMEOUT, + .retry_count = WG_DNS_RETRY_COUNT, + .servers = dns_list, + .domains = (char *[]){NULL}, + .tls_name = "", + .tls_servers = (char *[]){NULL}, + .tls_fingerprints = (char *[]){NULL} + }; + + for (int i = 0; dns_list[i]; ++i) + pretty_dns_list = concat_and_free(pretty_dns_list, ", ", dns_list[i]); + + printf("[#] <binder>::dnsResolver::setResolverConfiguration(%u, [%s], [], %d, %d, %d, %d, %d, %d, [], [])\n", + netid, pretty_dns_list, WG_DNS_SAMPLE_VALIDITY, WG_DNS_SUCCESS_THRESHOLD, + WG_DNS_MIN_SAMPLES, WG_DNS_MAX_SAMPLES, WG_DNS_BASE_TIMEOUT, WG_DNS_RETRY_COUNT); + + status = dnsresolver_set_resolver_configuration(handle, ¶ms); + + if (status != 0) { + fprintf(stderr, "Error: unable to set DNS servers through Binder"); + printf("[#] <binder>::dnsResolver::destroyNetworkCache(%u)\n", netid); + dnsresolver_destroy_network_cache(handle, netid); + exit(ELIBACC); + } + + return; + } + if (!strlen(arglist)) return; cndc("resolver setnetdns %u '' %s", netid, arglist); |