Skip to content

Commit

Permalink
dns_conf: add option -interface for server
Browse files Browse the repository at this point in the history
  • Loading branch information
pymumu committed Jan 4, 2024
1 parent 0341387 commit 70ec291
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 9 deletions.
1 change: 1 addition & 0 deletions etc/smartdns/smartdns.conf
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ log-level info
# -set-mark: set mark on packets.
# -subnet [ip/subnet]: set edns client subnet.
# -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 tls://dns.google:853
# server https://dns.google/dns-query
Expand Down
70 changes: 62 additions & 8 deletions src/dns_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,7 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
char port_s[8];
int sock_type = 0;
char skip_check_cert = 0;
char ifname[IFNAMSIZ * 2] = {0};

switch (server_type) {
case DNS_SERVER_UDP: {
Expand Down Expand Up @@ -1110,8 +1111,10 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
sock_type = SOCK_STREAM;
break;
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;
} break;
default:
Expand Down Expand Up @@ -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);
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;
errout:
Expand Down Expand Up @@ -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_sock_keepalive(fd, 30, 3, 5);

Expand Down Expand Up @@ -1932,6 +1951,17 @@ static int _dns_client_create_socket_udp(struct dns_server_info *server_info)
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->status = DNS_SERVER_STATUS_CONNECTIONLESS;

Expand Down Expand Up @@ -2005,7 +2035,7 @@ static int _dns_client_create_socket_udp_mdns(struct dns_server_info *server_inf

struct ifreq ifr;
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);
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));
Expand Down Expand Up @@ -2074,6 +2104,17 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
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) {
tlog(TLOG_ERROR, "set socket non block failed, %s", strerror(errno));
goto errout;
Expand Down Expand Up @@ -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);
}

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);
if (ssl == NULL) {
tlog(TLOG_ERROR, "new ssl failed, %s", server_info->ip);
Expand Down Expand Up @@ -4611,15 +4663,16 @@ static int _dns_client_add_mdns_server(void)
}

#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) {
tlog(TLOG_ERROR, "add mdns server failed.");
tlog(TLOG_ERROR, "add mdns server to %s failed.", "lo");
goto errout;
}

if (dns_client_add_to_group(DNS_SERVER_GROUP_MDNS, DNS_MDNS_IP, DNS_MDNS_PORT, DNS_SERVER_MDNS, &server_flags) !=
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;
}

Expand Down Expand Up @@ -4654,7 +4707,8 @@ static int _dns_client_add_mdns_server(void)
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) {
tlog(TLOG_ERROR, "add mdns server failed.");
goto errout;
Expand Down
3 changes: 2 additions & 1 deletion src/dns_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
extern "C" {
#endif

#define DNS_SERVER_IFNAME_LEN 16
#define DNS_SERVER_SPKI_LEN 64
#define DNS_SERVER_GROUP_DEFAULT "default"
#define DNS_SERVER_GROUP_MDNS "mdns"
Expand Down Expand Up @@ -101,7 +102,6 @@ struct client_dns_server_flag_udp {
};

struct client_dns_server_flag_mdns {
char ifname[DNS_MAX_CNAME_LEN];
};

struct client_dns_server_flag_tls {
Expand Down Expand Up @@ -136,6 +136,7 @@ struct client_dns_server_flags {
long long set_mark;
int drop_packet_latency_ms;
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 ipv6_ecs;

Expand Down
5 changes: 5 additions & 0 deletions src/dns_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
{"no-check-certificate", no_argument, NULL, 'k'}, /* do not check certificate */
{"bootstrap-dns", no_argument, NULL, 'b'}, /* set as bootstrap dns */
{"interface", required_argument, NULL, 250}, /* interface */
#ifdef FEATURE_CHECK_EDNS
/* experimental feature */
{"check-edns", no_argument, NULL, 251}, /* check edns */
Expand Down Expand Up @@ -667,6 +668,10 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
is_bootstrap_dns = 1;
break;
}
case 250: {
safe_strncpy(server->ifname, optarg, MAX_INTERFACE_LEN);
break;
}
case 251: {
result_flag |= DNSSERVER_FLAG_CHECK_EDNS;
break;
Expand Down
2 changes: 2 additions & 0 deletions src/dns_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ extern "C" {
#define DNS_MAX_REPLY_IP_NUM 8
#define DNS_MAX_QUERY_LIMIT 65535
#define DNS_DEFAULT_CHECKPOINT_TIME (3600 * 24)
#define MAX_INTERFACE_LEN 16

#define SMARTDNS_CONF_FILE "/etc/smartdns/smartdns.conf"
#define SMARTDNS_LOG_FILE "/var/log/smartdns/smartdns.log"
Expand Down Expand Up @@ -340,6 +341,7 @@ struct dns_servers {
char tls_host_verify[DNS_MAX_CNAME_LEN];
char path[DNS_MAX_URL_LEN];
char proxyname[PROXY_NAME_LEN];
char ifname[MAX_INTERFACE_LEN];
struct dns_edns_client_subnet ipv4_ecs;
struct dns_edns_client_subnet ipv6_ecs;
};
Expand Down
1 change: 1 addition & 0 deletions src/smartdns.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ static int _smartdns_prepare_server_flags(struct client_dns_server_flags *flags,
flags->set_mark = server->set_mark;
flags->drop_packet_latency_ms = server->drop_packet_latency_ms;
safe_strncpy(flags->proxyname, server->proxyname, sizeof(flags->proxyname));
safe_strncpy(flags->ifname, server->ifname, sizeof(flags->ifname));
if (server->ipv4_ecs.enable) {
flags->ipv4_ecs.enable = 1;
safe_strncpy(flags->ipv4_ecs.ip, server->ipv4_ecs.ip, sizeof(flags->ipv4_ecs.ip));
Expand Down
27 changes: 27 additions & 0 deletions test/cases/test-server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,31 @@ max-query-limit 2
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
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");
}

0 comments on commit 70ec291

Please sign in to comment.