Sfoglia il codice sorgente

dns_conf: add option -interface for server

Nick Peng 1 anno fa
parent
commit
70ec291eee
7 ha cambiato i file con 100 aggiunte e 9 eliminazioni
  1. 1 0
      etc/smartdns/smartdns.conf
  2. 62 8
      src/dns_client.c
  3. 2 1
      src/dns_client.h
  4. 5 0
      src/dns_conf.c
  5. 2 0
      src/dns_conf.h
  6. 1 0
      src/smartdns.c
  7. 27 0
      test/cases/test-server.cc

+ 1 - 0
etc/smartdns/smartdns.conf

@@ -208,6 +208,7 @@ log-level info
 #   -set-mark: set mark on packets.
 #   -set-mark: set mark on packets.
 #   -subnet [ip/subnet]: set edns client subnet.
 #   -subnet [ip/subnet]: set edns client subnet.
 #   -host-ip [ip]: set dns server host ip.
 #   -host-ip [ip]: set dns server host ip.
+#   -interface [interface]: set dns server interface.
 # server 8.8.8.8 -blacklist-ip -check-edns -group g1 -group g2
 # server 8.8.8.8 -blacklist-ip -check-edns -group g1 -group g2
 # server tls://dns.google:853 
 # server tls://dns.google:853 
 # server https://dns.google/dns-query
 # server https://dns.google/dns-query

+ 62 - 8
src/dns_client.c

@@ -1074,6 +1074,7 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
 	char port_s[8];
 	char port_s[8];
 	int sock_type = 0;
 	int sock_type = 0;
 	char skip_check_cert = 0;
 	char skip_check_cert = 0;
+	char ifname[IFNAMSIZ * 2] = {0};
 
 
 	switch (server_type) {
 	switch (server_type) {
 	case DNS_SERVER_UDP: {
 	case DNS_SERVER_UDP: {
@@ -1110,8 +1111,10 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
 		sock_type = SOCK_STREAM;
 		sock_type = SOCK_STREAM;
 		break;
 		break;
 	case DNS_SERVER_MDNS: {
 	case DNS_SERVER_MDNS: {
-		struct client_dns_server_flag_mdns *flag_mdns = &flags->mdns;
-		safe_strncpy(flag_mdns->ifname, server_host, DNS_MAX_CNAME_LEN);
+		if (flags->ifname[0] == '\0') {
+			tlog(TLOG_ERROR, "mdns server must set ifname.");
+			return -1;
+		}
 		sock_type = SOCK_DGRAM;
 		sock_type = SOCK_DGRAM;
 	} break;
 	} break;
 	default:
 	default:
@@ -1220,7 +1223,12 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
 
 
 	_dns_server_inc_server_num(server_info);
 	_dns_server_inc_server_num(server_info);
 	freeaddrinfo(gai);
 	freeaddrinfo(gai);
-	tlog(TLOG_INFO, "add server %s:%d, type: %s", server_ip, port, _dns_server_get_type_string(server_info->type));
+
+	if (flags->ifname[0]) {
+		snprintf(ifname, sizeof(ifname), "@%s", flags->ifname);
+	}
+
+	tlog(TLOG_INFO, "add server %s:%d%s, type: %s", server_ip, port, ifname, _dns_server_get_type_string(server_info->type));
 
 
 	return 0;
 	return 0;
 errout:
 errout:
@@ -1876,6 +1884,17 @@ static int _dns_client_create_socket_udp_proxy(struct dns_server_info *server_in
 		}
 		}
 	}
 	}
 
 
+	if (server_info->flags.ifname[0] != '\0') {
+		struct ifreq ifr;
+		memset(&ifr, 0, sizeof(struct ifreq));
+		safe_strncpy(ifr.ifr_name, server_info->flags.ifname, sizeof(ifr.ifr_name));
+		ioctl(fd, SIOCGIFINDEX, &ifr);
+		if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(struct ifreq)) < 0) {
+			tlog(TLOG_ERROR, "bind socket to device %s failed, %s\n", ifr.ifr_name, strerror(errno));
+			goto errout;
+		}
+	}
+
 	set_fd_nonblock(fd, 1);
 	set_fd_nonblock(fd, 1);
 	set_sock_keepalive(fd, 30, 3, 5);
 	set_sock_keepalive(fd, 30, 3, 5);
 
 
@@ -1932,6 +1951,17 @@ static int _dns_client_create_socket_udp(struct dns_server_info *server_info)
 		goto errout;
 		goto errout;
 	}
 	}
 
 
+	if (server_info->flags.ifname[0] != '\0') {
+		struct ifreq ifr;
+		memset(&ifr, 0, sizeof(struct ifreq));
+		safe_strncpy(ifr.ifr_name, server_info->flags.ifname, sizeof(ifr.ifr_name));
+		ioctl(fd, SIOCGIFINDEX, &ifr);
+		if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(struct ifreq)) < 0) {
+			tlog(TLOG_ERROR, "bind socket to device %s failed, %s\n", ifr.ifr_name, strerror(errno));
+			goto errout;
+		}
+	}
+
 	server_info->fd = fd;
 	server_info->fd = fd;
 	server_info->status = DNS_SERVER_STATUS_CONNECTIONLESS;
 	server_info->status = DNS_SERVER_STATUS_CONNECTIONLESS;
 
 
@@ -2005,7 +2035,7 @@ static int _dns_client_create_socket_udp_mdns(struct dns_server_info *server_inf
 
 
 	struct ifreq ifr;
 	struct ifreq ifr;
 	memset(&ifr, 0, sizeof(struct ifreq));
 	memset(&ifr, 0, sizeof(struct ifreq));
-	safe_strncpy(ifr.ifr_name, server_info->flags.mdns.ifname, sizeof(ifr.ifr_name));
+	safe_strncpy(ifr.ifr_name, server_info->flags.ifname, sizeof(ifr.ifr_name));
 	ioctl(fd, SIOCGIFINDEX, &ifr);
 	ioctl(fd, SIOCGIFINDEX, &ifr);
 	if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(struct ifreq)) < 0) {
 	if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(struct ifreq)) < 0) {
 		tlog(TLOG_ERROR, "bind socket to device %s failed, %s\n", ifr.ifr_name, strerror(errno));
 		tlog(TLOG_ERROR, "bind socket to device %s failed, %s\n", ifr.ifr_name, strerror(errno));
@@ -2074,6 +2104,17 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
 		goto errout;
 		goto errout;
 	}
 	}
 
 
+	if (server_info->flags.ifname[0] != '\0') {
+		struct ifreq ifr;
+		memset(&ifr, 0, sizeof(struct ifreq));
+		safe_strncpy(ifr.ifr_name, server_info->flags.ifname, sizeof(ifr.ifr_name));
+		ioctl(fd, SIOCGIFINDEX, &ifr);
+		if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(struct ifreq)) < 0) {
+			tlog(TLOG_ERROR, "bind socket to device %s failed, %s\n", ifr.ifr_name, strerror(errno));
+			goto errout;
+		}
+	}
+
 	if (set_fd_nonblock(fd, 1) != 0) {
 	if (set_fd_nonblock(fd, 1) != 0) {
 		tlog(TLOG_ERROR, "set socket non block failed, %s", strerror(errno));
 		tlog(TLOG_ERROR, "set socket non block failed, %s", strerror(errno));
 		goto errout;
 		goto errout;
@@ -2172,6 +2213,17 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
 		fd = socket(server_info->ai_family, SOCK_STREAM, 0);
 		fd = socket(server_info->ai_family, SOCK_STREAM, 0);
 	}
 	}
 
 
+	if (server_info->flags.ifname[0] != '\0') {
+		struct ifreq ifr;
+		memset(&ifr, 0, sizeof(struct ifreq));
+		safe_strncpy(ifr.ifr_name, server_info->flags.ifname, sizeof(ifr.ifr_name));
+		ioctl(fd, SIOCGIFINDEX, &ifr);
+		if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(struct ifreq)) < 0) {
+			tlog(TLOG_ERROR, "bind socket to device %s failed, %s\n", ifr.ifr_name, strerror(errno));
+			goto errout;
+		}
+	}
+
 	ssl = SSL_new(server_info->ssl_ctx);
 	ssl = SSL_new(server_info->ssl_ctx);
 	if (ssl == NULL) {
 	if (ssl == NULL) {
 		tlog(TLOG_ERROR, "new ssl failed, %s", server_info->ip);
 		tlog(TLOG_ERROR, "new ssl failed, %s", server_info->ip);
@@ -4611,15 +4663,16 @@ static int _dns_client_add_mdns_server(void)
 	}
 	}
 
 
 #ifdef TEST
 #ifdef TEST
-	ret = _dns_client_server_add(DNS_MDNS_IP, "lo", DNS_MDNS_PORT, DNS_SERVER_MDNS, &server_flags);
+	safe_strncpy(server_flags.ifname, "lo", sizeof(server_flags.ifname));
+	ret = _dns_client_server_add(DNS_MDNS_IP, "", DNS_MDNS_PORT, DNS_SERVER_MDNS, &server_flags);
 	if (ret != 0) {
 	if (ret != 0) {
-		tlog(TLOG_ERROR, "add mdns server failed.");
+		tlog(TLOG_ERROR, "add mdns server to %s failed.", "lo");
 		goto errout;
 		goto errout;
 	}
 	}
 
 
 	if (dns_client_add_to_group(DNS_SERVER_GROUP_MDNS, DNS_MDNS_IP, DNS_MDNS_PORT, DNS_SERVER_MDNS, &server_flags) !=
 	if (dns_client_add_to_group(DNS_SERVER_GROUP_MDNS, DNS_MDNS_IP, DNS_MDNS_PORT, DNS_SERVER_MDNS, &server_flags) !=
 		0) {
 		0) {
-		tlog(TLOG_ERROR, "add mdns server to group failed.");
+		tlog(TLOG_ERROR, "add mdns server to group %s failed.", DNS_SERVER_GROUP_MDNS);
 		goto errout;
 		goto errout;
 	}
 	}
 
 
@@ -4654,7 +4707,8 @@ static int _dns_client_add_mdns_server(void)
 			continue;
 			continue;
 		}
 		}
 
 
-		ret = _dns_client_server_add(DNS_MDNS_IP, ifa->ifa_name, DNS_MDNS_PORT, DNS_SERVER_MDNS, &server_flags);
+		safe_strncpy(server_flags.ifname, ifa->ifa_name, sizeof(server_flags.ifname));
+		ret = _dns_client_server_add(DNS_MDNS_IP, "", DNS_MDNS_PORT, DNS_SERVER_MDNS, &server_flags);
 		if (ret != 0) {
 		if (ret != 0) {
 			tlog(TLOG_ERROR, "add mdns server failed.");
 			tlog(TLOG_ERROR, "add mdns server failed.");
 			goto errout;
 			goto errout;

+ 2 - 1
src/dns_client.h

@@ -25,6 +25,7 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
+#define DNS_SERVER_IFNAME_LEN 16
 #define DNS_SERVER_SPKI_LEN 64
 #define DNS_SERVER_SPKI_LEN 64
 #define DNS_SERVER_GROUP_DEFAULT "default"
 #define DNS_SERVER_GROUP_DEFAULT "default"
 #define DNS_SERVER_GROUP_MDNS "mdns"
 #define DNS_SERVER_GROUP_MDNS "mdns"
@@ -101,7 +102,6 @@ struct client_dns_server_flag_udp {
 };
 };
 
 
 struct client_dns_server_flag_mdns {
 struct client_dns_server_flag_mdns {
-	char ifname[DNS_MAX_CNAME_LEN];
 };
 };
 
 
 struct client_dns_server_flag_tls {
 struct client_dns_server_flag_tls {
@@ -136,6 +136,7 @@ struct client_dns_server_flags {
 	long long set_mark;
 	long long set_mark;
 	int drop_packet_latency_ms;
 	int drop_packet_latency_ms;
 	char proxyname[DNS_MAX_CNAME_LEN];
 	char proxyname[DNS_MAX_CNAME_LEN];
+	char ifname[DNS_SERVER_IFNAME_LEN];
 	struct client_dns_server_flag_ecs ipv4_ecs;
 	struct client_dns_server_flag_ecs ipv4_ecs;
 	struct client_dns_server_flag_ecs ipv6_ecs;
 	struct client_dns_server_flag_ecs ipv6_ecs;
 
 

+ 5 - 0
src/dns_conf.c

@@ -559,6 +559,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
 		{"proxy", required_argument, NULL, 'p'}, /* proxy server */
 		{"proxy", required_argument, NULL, 'p'}, /* proxy server */
 		{"no-check-certificate", no_argument, NULL, 'k'}, /* do not check certificate */
 		{"no-check-certificate", no_argument, NULL, 'k'}, /* do not check certificate */
 		{"bootstrap-dns", no_argument, NULL, 'b'}, /* set as bootstrap dns */
 		{"bootstrap-dns", no_argument, NULL, 'b'}, /* set as bootstrap dns */
+		{"interface", required_argument, NULL, 250}, /* interface */
 #ifdef FEATURE_CHECK_EDNS
 #ifdef FEATURE_CHECK_EDNS
 		/* experimental feature */
 		/* experimental feature */
 		{"check-edns", no_argument, NULL, 251},   /* check edns */
 		{"check-edns", no_argument, NULL, 251},   /* check edns */
@@ -667,6 +668,10 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
 			is_bootstrap_dns = 1;
 			is_bootstrap_dns = 1;
 			break;
 			break;
 		}
 		}
+		case 250: {
+			safe_strncpy(server->ifname, optarg, MAX_INTERFACE_LEN);
+			break;
+		}
 		case 251: {
 		case 251: {
 			result_flag |= DNSSERVER_FLAG_CHECK_EDNS;
 			result_flag |= DNSSERVER_FLAG_CHECK_EDNS;
 			break;
 			break;

+ 2 - 0
src/dns_conf.h

@@ -61,6 +61,7 @@ extern "C" {
 #define DNS_MAX_REPLY_IP_NUM 8
 #define DNS_MAX_REPLY_IP_NUM 8
 #define DNS_MAX_QUERY_LIMIT 65535
 #define DNS_MAX_QUERY_LIMIT 65535
 #define DNS_DEFAULT_CHECKPOINT_TIME (3600 * 24)
 #define DNS_DEFAULT_CHECKPOINT_TIME (3600 * 24)
+#define MAX_INTERFACE_LEN 16
 
 
 #define SMARTDNS_CONF_FILE "/etc/smartdns/smartdns.conf"
 #define SMARTDNS_CONF_FILE "/etc/smartdns/smartdns.conf"
 #define SMARTDNS_LOG_FILE "/var/log/smartdns/smartdns.log"
 #define SMARTDNS_LOG_FILE "/var/log/smartdns/smartdns.log"
@@ -340,6 +341,7 @@ struct dns_servers {
 	char tls_host_verify[DNS_MAX_CNAME_LEN];
 	char tls_host_verify[DNS_MAX_CNAME_LEN];
 	char path[DNS_MAX_URL_LEN];
 	char path[DNS_MAX_URL_LEN];
 	char proxyname[PROXY_NAME_LEN];
 	char proxyname[PROXY_NAME_LEN];
+	char ifname[MAX_INTERFACE_LEN];
 	struct dns_edns_client_subnet ipv4_ecs;
 	struct dns_edns_client_subnet ipv4_ecs;
 	struct dns_edns_client_subnet ipv6_ecs;
 	struct dns_edns_client_subnet ipv6_ecs;
 };
 };

+ 1 - 0
src/smartdns.c

@@ -288,6 +288,7 @@ static int _smartdns_prepare_server_flags(struct client_dns_server_flags *flags,
 	flags->set_mark = server->set_mark;
 	flags->set_mark = server->set_mark;
 	flags->drop_packet_latency_ms = server->drop_packet_latency_ms;
 	flags->drop_packet_latency_ms = server->drop_packet_latency_ms;
 	safe_strncpy(flags->proxyname, server->proxyname, sizeof(flags->proxyname));
 	safe_strncpy(flags->proxyname, server->proxyname, sizeof(flags->proxyname));
+	safe_strncpy(flags->ifname, server->ifname, sizeof(flags->ifname));
 	if (server->ipv4_ecs.enable) {
 	if (server->ipv4_ecs.enable) {
 		flags->ipv4_ecs.enable = 1;
 		flags->ipv4_ecs.enable = 1;
 		safe_strncpy(flags->ipv4_ecs.ip, server->ipv4_ecs.ip, sizeof(flags->ipv4_ecs.ip));
 		safe_strncpy(flags->ipv4_ecs.ip, server->ipv4_ecs.ip, sizeof(flags->ipv4_ecs.ip));

+ 27 - 0
test/cases/test-server.cc

@@ -218,4 +218,31 @@ max-query-limit 2
 		EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
 		EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
 		EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
 		EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
 	}
 	}
+}
+
+TEST_F(Server, interface)
+{
+	smartdns::MockServer server_upstream;
+	smartdns::Server server;
+
+	server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) {
+		if (request->qtype != DNS_T_A) {
+			return smartdns::SERVER_REQUEST_SOA;
+		}
+		smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
+		return smartdns::SERVER_REQUEST_OK;
+	});
+
+	server.MockPing(PING_TYPE_ICMP, "2001::", 128, 10000);
+	server.Start(R"""(bind [::]:60053
+bind-tcp [::]:60053
+server 127.0.0.1:61053 -interface lo
+)""");
+	smartdns::Client client;
+	ASSERT_TRUE(client.Query("a.com", 60053));
+	std::cout << client.GetResult() << std::endl;
+	ASSERT_EQ(client.GetAnswerNum(), 1);
+	EXPECT_EQ(client.GetStatus(), "NOERROR");
+	EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
+	EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
 }
 }