123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549 |
- /*************************************************************************
- *
- * Copyright (C) 2018-2020 Ruilin Peng (Nick) <[email protected]>.
- *
- * smartdns is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * smartdns is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #define _GNU_SOURCE
- #include "art.h"
- #include "atomic.h"
- #include "dns_client.h"
- #include "dns_conf.h"
- #include "dns_server.h"
- #include "fast_ping.h"
- #include "hashtable.h"
- #include "list.h"
- #include "rbtree.h"
- #include "tlog.h"
- #include "util.h"
- #include <errno.h>
- #include <fcntl.h>
- #include <libgen.h>
- #include <linux/capability.h>
- #include <openssl/err.h>
- #include <openssl/ssl.h>
- #include <pwd.h>
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/prctl.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <ucontext.h>
- #define RESOLVE_FILE "/etc/resolv.conf"
- #define MAX_LINE_LEN 1024
- #define MAX_KEY_LEN 64
- #define SMARTDNS_PID_FILE "/var/run/smartdns.pid"
- #define TMP_BUFF_LEN_32 32
- static int verbose_screen;
- int capget(struct __user_cap_header_struct *header, struct __user_cap_data_struct *cap);
- int capset(struct __user_cap_header_struct *header, struct __user_cap_data_struct *cap);
- static int get_uid_gid(int *uid, int *gid)
- {
- struct passwd *result = NULL;
- struct passwd pwd;
- char *buf = NULL;
- ssize_t bufsize = 0;
- int ret = -1;
- if (dns_conf_user[0] == '\0') {
- return -1;
- }
- bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
- if (bufsize == -1) {
- bufsize = 1024 * 16;
- }
- buf = malloc(bufsize);
- if (buf == NULL) {
- goto out;
- }
- ret = getpwnam_r(dns_conf_user, &pwd, buf, bufsize, &result);
- if (ret != 0) {
- goto out;
- }
- *uid = result->pw_uid;
- *gid = result->pw_gid;
- out:
- if (buf) {
- free(buf);
- }
- return ret;
- }
- static int drop_root_privilege(void)
- {
- struct __user_cap_data_struct cap;
- struct __user_cap_header_struct header;
- header.version = _LINUX_CAPABILITY_VERSION;
- header.pid = 0;
- int uid = 0;
- int gid = 0;
- int unused __attribute__((unused)) = 0;
- if (get_uid_gid(&uid, &gid) != 0) {
- return -1;
- }
- if (capget(&header, &cap) < 0) {
- return -1;
- }
- prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
- cap.effective |= (1 << CAP_NET_RAW | 1 << CAP_NET_ADMIN);
- cap.permitted |= (1 << CAP_NET_RAW | 1 << CAP_NET_ADMIN);
- unused = setuid(uid);
- unused = setgid(gid);
- if (capset(&header, &cap) < 0) {
- return -1;
- }
- prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0);
- return 0;
- }
- static void _help(void)
- {
- /* clang-format off */
- char *help = ""
- "Usage: smartdns [OPTION]...\n"
- "Start smartdns server.\n"
- " -f run forground.\n"
- " -c [conf] config file.\n"
- " -p [pid] pid file path\n"
- " -S ignore segment fault signal.\n"
- " -x verbose screen.\n"
- " -v dispaly version.\n"
- " -h show this help message.\n"
- "Online help: http://pymumu.github.io/smartdns\n"
- "Copyright (C) Nick Peng <[email protected]>\n"
- ;
- /* clang-format on */
- printf("%s", help);
- }
- static void _show_version(void)
- {
- char str_ver[256] = {0};
- #ifdef SMARTDNS_VERION
- const char *ver = SMARTDNS_VERION;
- snprintf(str_ver, sizeof(str_ver), "%s", ver);
- #else
- struct tm tm;
- get_compiled_time(&tm);
- snprintf(str_ver, sizeof(str_ver), "1.%.4d%.2d%.2d-%.2d%.2d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min);
- #endif
- printf("smartdns %s\n", str_ver);
- }
- static int _smartdns_load_from_resolv(void)
- {
- FILE *fp = NULL;
- char line[MAX_LINE_LEN];
- char key[MAX_KEY_LEN];
- char value[MAX_LINE_LEN];
- char ns_ip[DNS_MAX_IPLEN];
- int port = PORT_NOT_DEFINED;
- int ret = -1;
- int filed_num = 0;
- int line_num = 0;
- fp = fopen(RESOLVE_FILE, "r");
- if (fp == NULL) {
- tlog(TLOG_ERROR, "open %s failed, %s", RESOLVE_FILE, strerror(errno));
- return -1;
- }
- while (fgets(line, MAX_LINE_LEN, fp)) {
- line_num++;
- filed_num = sscanf(line, "%63s %1023[^\r\n]s", key, value);
- if (filed_num != 2) {
- continue;
- }
- if (strncmp(key, "nameserver", MAX_KEY_LEN - 1) != 0) {
- continue;
- }
- if (parse_ip(value, ns_ip, &port) != 0) {
- continue;
- }
- if (port == PORT_NOT_DEFINED) {
- port = DEFAULT_DNS_PORT;
- }
- safe_strncpy(dns_conf_servers[dns_conf_server_num].server, ns_ip, DNS_MAX_IPLEN);
- dns_conf_servers[dns_conf_server_num].port = port;
- dns_conf_servers[dns_conf_server_num].type = DNS_SERVER_UDP;
- dns_conf_server_num++;
- ret = 0;
- }
- fclose(fp);
- return ret;
- }
- static int _smartdns_add_servers(void)
- {
- unsigned long i = 0;
- int j = 0;
- int ret = 0;
- struct dns_server_groups *group = NULL;
- struct dns_servers *server = NULL;
- struct client_dns_server_flags flags;
- for (i = 0; i < (unsigned int)dns_conf_server_num; i++) {
- memset(&flags, 0, sizeof(flags));
- switch (dns_conf_servers[i].type) {
- case DNS_SERVER_UDP: {
- struct client_dns_server_flag_udp *flag_udp = &flags.udp;
- flag_udp->ttl = dns_conf_servers[i].ttl;
- } break;
- case DNS_SERVER_HTTPS: {
- struct client_dns_server_flag_https *flag_http = &flags.https;
- flag_http->spi_len = dns_client_spki_decode(dns_conf_servers[i].spki, (unsigned char *)flag_http->spki);
- safe_strncpy(flag_http->hostname, dns_conf_servers[i].hostname, sizeof(flag_http->hostname));
- safe_strncpy(flag_http->path, dns_conf_servers[i].path, sizeof(flag_http->path));
- safe_strncpy(flag_http->httphost, dns_conf_servers[i].httphost, sizeof(flag_http->httphost));
- safe_strncpy(flag_http->tls_host_verify, dns_conf_servers[i].tls_host_verify,
- sizeof(flag_http->tls_host_verify));
- flag_http->skip_check_cert = dns_conf_servers[i].skip_check_cert;
- } break;
- case DNS_SERVER_TLS: {
- struct client_dns_server_flag_tls *flag_tls = &flags.tls;
- flag_tls->spi_len = dns_client_spki_decode(dns_conf_servers[i].spki, (unsigned char *)flag_tls->spki);
- safe_strncpy(flag_tls->hostname, dns_conf_servers[i].hostname, sizeof(flag_tls->hostname));
- safe_strncpy(flag_tls->tls_host_verify, dns_conf_servers[i].tls_host_verify,
- sizeof(flag_tls->tls_host_verify));
- flag_tls->skip_check_cert = dns_conf_servers[i].skip_check_cert;
- } break;
- case DNS_SERVER_TCP:
- break;
- default:
- return -1;
- break;
- }
- flags.type = dns_conf_servers[i].type;
- flags.server_flag = dns_conf_servers[i].server_flag;
- flags.result_flag = dns_conf_servers[i].result_flag;
- ret = dns_client_add_server(dns_conf_servers[i].server, dns_conf_servers[i].port, dns_conf_servers[i].type,
- &flags);
- if (ret != 0) {
- tlog(TLOG_ERROR, "add server failed, %s:%d", dns_conf_servers[i].server, dns_conf_servers[i].port);
- return -1;
- }
- }
- hash_for_each(dns_group_table.group, i, group, node)
- {
- ret = dns_client_add_group(group->group_name);
- if (ret != 0) {
- tlog(TLOG_ERROR, "add group failed, %s", group->group_name);
- return -1;
- }
- for (j = 0; j < group->server_num; j++) {
- server = group->servers[j];
- if (server == NULL) {
- continue;
- }
- ret = dns_client_add_to_group(group->group_name, server->server, server->port, server->type);
- if (ret != 0) {
- tlog(TLOG_ERROR, "add server %s to group %s failed", server->server, group->group_name);
- return -1;
- }
- }
- }
- return 0;
- }
- static int _smartdns_set_ecs_ip(void)
- {
- int ret = 0;
- if (dns_conf_ipv4_ecs.enable) {
- ret |= dns_client_set_ecs(dns_conf_ipv4_ecs.ip, dns_conf_ipv4_ecs.subnet);
- }
- if (dns_conf_ipv6_ecs.enable) {
- ret |= dns_client_set_ecs(dns_conf_ipv6_ecs.ip, dns_conf_ipv6_ecs.subnet);
- }
- return ret;
- }
- static int _smartdns_init_ssl(void)
- {
- #if OPENSSL_API_COMPAT < 0x10100000L
- SSL_load_error_strings();
- SSL_library_init();
- OpenSSL_add_all_algorithms();
- SSL_CRYPTO_thread_setup();
- #endif
- return 0;
- }
- static int _smartdns_destroy_ssl(void)
- {
- #if OPENSSL_API_COMPAT < 0x10100000L
- SSL_CRYPTO_thread_cleanup();
- ERR_free_strings();
- EVP_cleanup();
- #endif
- return 0;
- }
- static int _smartdns_init(void)
- {
- int ret = 0;
- char *logfile = SMARTDNS_LOG_FILE;
- if (dns_conf_log_file[0] != 0) {
- logfile = dns_conf_log_file;
- }
- ret = tlog_init(logfile, dns_conf_log_size, dns_conf_log_num, 0, 0);
- if (ret != 0) {
- tlog(TLOG_ERROR, "start tlog failed.\n");
- goto errout;
- }
- tlog_setlogscreen(verbose_screen);
- tlog_setlevel(dns_conf_log_level);
- tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <[email protected]>, build:%s %s)", __DATE__,
- __TIME__);
- if (_smartdns_init_ssl() != 0) {
- tlog(TLOG_ERROR, "init ssl failed.");
- goto errout;
- }
- if (dns_conf_server_num <= 0) {
- if (_smartdns_load_from_resolv() != 0) {
- tlog(TLOG_ERROR, "load dns from resolv failed.");
- goto errout;
- }
- }
- ret = fast_ping_init();
- if (ret != 0) {
- tlog(TLOG_ERROR, "start ping failed.\n");
- goto errout;
- }
- ret = dns_server_init();
- if (ret != 0) {
- tlog(TLOG_ERROR, "start dns server failed.\n");
- goto errout;
- }
- ret = dns_client_init();
- if (ret != 0) {
- tlog(TLOG_ERROR, "start dns client failed.\n");
- goto errout;
- }
- ret = _smartdns_add_servers();
- if (ret != 0) {
- tlog(TLOG_ERROR, "add servers failed.");
- goto errout;
- }
- ret = _smartdns_set_ecs_ip();
- if (ret != 0) {
- tlog(TLOG_WARN, "set ecs ip address failed.");
- }
- return 0;
- errout:
- return -1;
- }
- static int _smartdns_run(void)
- {
- return dns_server_run();
- }
- static void _smartdns_exit(void)
- {
- tlog(TLOG_INFO, "smartdns exit...");
- dns_client_exit();
- fast_ping_exit();
- dns_server_exit();
- _smartdns_destroy_ssl();
- tlog_exit();
- dns_server_load_exit();
- }
- static void _sig_exit(int signo)
- {
- tlog(TLOG_INFO, "stop smartdns by signal %d", signo);
- dns_server_stop();
- }
- static void _sig_error_exit(int signo, siginfo_t *siginfo, void *ct)
- {
- unsigned long PC = 0;
- ucontext_t *context = ct;
- const char *arch = NULL;
- #if defined(__i386__)
- int *pgregs = (int *)(&(context->uc_mcontext.gregs));
- PC = pgregs[REG_EIP];
- arch = "i386";
- #elif defined(__x86_64__)
- int *pgregs = (int *)(&(context->uc_mcontext.gregs));
- PC = pgregs[REG_RIP];
- arch = "x86_64";
- #elif defined(__arm__)
- PC = context->uc_mcontext.arm_pc;
- arch = "arm";
- #elif defined(__aarch64__)
- PC = context->uc_mcontext.pc;
- arch = "arm64";
- #elif defined(__mips__)
- PC = context->uc_mcontext.pc;
- arch = "mips";
- #endif
- tlog(TLOG_FATAL,
- "process exit with signal %d, code = %d, errno = %d, pid = %d, self = %d, pc = %#lx, addr = %#lx, build(%s "
- "%s %s)\n",
- signo, siginfo->si_code, siginfo->si_errno, siginfo->si_pid, getpid(), PC, (unsigned long)siginfo->si_addr,
- __DATE__, __TIME__, arch);
- print_stack();
- sleep(1);
- _exit(0);
- }
- static int sig_list[] = {SIGSEGV, SIGABRT, SIGBUS, SIGILL, SIGFPE};
- static int sig_num = sizeof(sig_list) / sizeof(int);
- static void _reg_signal(void)
- {
- struct sigaction act;
- struct sigaction old;
- int i = 0;
- act.sa_sigaction = _sig_error_exit;
- sigemptyset(&act.sa_mask);
- act.sa_flags = SA_RESTART | SA_SIGINFO;
- for (i = 0; i < sig_num; i++) {
- sigaction(sig_list[i], &act, &old);
- }
- }
- int main(int argc, char *argv[])
- {
- int ret = 0;
- int is_forground = 0;
- int opt = 0;
- char config_file[MAX_LINE_LEN];
- char pid_file[MAX_LINE_LEN];
- int signal_ignore = 0;
- sigset_t empty_sigblock;
- safe_strncpy(config_file, SMARTDNS_CONF_FILE, MAX_LINE_LEN);
- safe_strncpy(pid_file, SMARTDNS_PID_FILE, MAX_LINE_LEN);
- /* patch for Asus router: unblock all signal*/
- sigemptyset(&empty_sigblock);
- sigprocmask(SIG_SETMASK, &empty_sigblock, NULL);
- while ((opt = getopt(argc, argv, "fhc:p:Svx")) != -1) {
- switch (opt) {
- case 'f':
- is_forground = 1;
- break;
- case 'c':
- snprintf(config_file, sizeof(config_file), "%s", optarg);
- break;
- case 'p':
- snprintf(pid_file, sizeof(pid_file), "%s", optarg);
- break;
- case 'S':
- signal_ignore = 1;
- break;
- case 'x':
- verbose_screen = 1;
- break;
- case 'v':
- _show_version();
- return 0;
- break;
- case 'h':
- _help();
- return 1;
- }
- }
- if (dns_server_load_conf(config_file) != 0) {
- fprintf(stderr, "load config failed.\n");
- goto errout;
- }
- if (is_forground == 0) {
- if (daemon(0, 0) < 0) {
- fprintf(stderr, "run daemon process failed, %s\n", strerror(errno));
- return 1;
- }
- }
- if (signal_ignore == 0) {
- _reg_signal();
- }
- if (create_pid_file(pid_file) != 0) {
- goto errout;
- }
- signal(SIGPIPE, SIG_IGN);
- signal(SIGINT, _sig_exit);
- signal(SIGTERM, _sig_exit);
- drop_root_privilege();
- ret = _smartdns_init();
- if (ret != 0) {
- usleep(100000);
- goto errout;
- }
- atexit(_smartdns_exit);
- return _smartdns_run();
- errout:
- return 1;
- }
|