pub async fn create_resolver(
    dns: Option<ResolverConfig>,
    opts: Option<ResolverOpts>,
    connect_opts: ConnectOpts,
) -> Result<DnsResolver, ResolveError> {
    // Customized dns resolution
    match dns {
        Some(conf) => {
            trace!("initializing DNS resolver with config {:?}", conf,);

            let mut builder = DnsResolver::builder_with_config(
                conf,
                ShadowDnsConnectionProvider::new(ShadowDnsRuntimeProvider::new(connect_opts)),
            );
            if let Some(opts) = opts {
                *builder.options_mut() = opts;
            }
            let resolver_opts = builder.options_mut();

            // Use Ipv4AndIpv6 strategy. Because Ipv4ThenIpv6 or Ipv6ThenIpv4 will return if the first query returned.
            // Since we want to use Happy Eyeballs to connect to both IPv4 and IPv6 addresses, we need both A and AAAA records.
            resolver_opts.ip_strategy = LookupIpStrategy::Ipv4AndIpv6;

            // Enable EDNS0 for large records
            resolver_opts.edns0 = true;

            trace!("initializing DNS resolver with opts {:?}", resolver_opts);

            Ok(builder.build())
        }

        // To make this independent, if targeting macOS, BSD, Linux, or Windows, we can use the system's configuration
        // Android doesn't have /etc/resolv.conf.
        None => {
            match DnsResolver::builder(ShadowDnsConnectionProvider::new(ShadowDnsRuntimeProvider::new(
                connect_opts,
            ))) {
                Ok(mut builder) => {
                    let opts = builder.options_mut();
                    // NOTE: timeout will be set by config (for example, /etc/resolv.conf on UNIX-like system)
                    //
                    // Only ip_strategy should be changed. Why Ipv4AndIpv6? See comments above.
                    opts.ip_strategy = LookupIpStrategy::Ipv4AndIpv6;

                    // Enable EDNS0 for large records
                    opts.edns0 = true;

                    trace!("initializing DNS resolver with system-config opts {:?}", opts);

                    Ok(builder.build())
                }
                Err(err) => {
                    error!("initialize DNS resolver with system-config failed, error: {}", err);
                    Err(ResolveError::from(
                        "current platform doesn't support hickory-dns resolver with system configured".to_owned(),
                    ))
                }
            }
        }
    }
}
Create a `hickory-dns` asynchronous DNS resolver
crates/shadowsocks/src/dns_resolver/hickory_dns_resolver.rs