feat: Handle nameserver parsing on Windows

* system default nameserver in windows

* change
pull/14/head
huangnauh 2021-01-20 18:02:15 +08:00 committed by GitHub
parent 250591098b
commit 3019f1cee6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 166 additions and 18 deletions

View File

@ -1,18 +1,14 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"net" "net"
"net/url" "net/url"
"runtime"
"github.com/miekg/dns" "github.com/mr-karan/doggo/pkg/config"
) )
const ( const (
//DefaultResolvConfPath specifies path to default resolv config file on UNIX.
DefaultResolvConfPath = "/etc/resolv.conf"
// DefaultTLSPort specifies the default port for a DNS server connecting over TCP over TLS // DefaultTLSPort specifies the default port for a DNS server connecting over TCP over TLS
DefaultTLSPort = "853" DefaultTLSPort = "853"
// DefaultUDPPort specifies the default port for a DNS server connecting over UDP // DefaultUDPPort specifies the default port for a DNS server connecting over UDP
@ -58,28 +54,20 @@ func (hub *Hub) loadNameservers() error {
return nil return nil
} }
// getDefaultServers reads the `resolv.conf`
// file and returns a list of nameservers with it's config.
func getDefaultServers() ([]Nameserver, int, []string, error) { func getDefaultServers() ([]Nameserver, int, []string, error) {
if runtime.GOOS == "windows" { dnsServers, ndots, search, err := config.GetDefaultServers()
// TODO: Add a method for reading system default nameserver in windows.
return nil, 0, nil, errors.New(`unable to read default nameservers in this machine`)
}
// if no nameserver is provided, take it from `resolv.conf`
cfg, err := dns.ClientConfigFromFile(DefaultResolvConfPath)
if err != nil { if err != nil {
return nil, 0, nil, err return nil, 0, nil, err
} }
servers := make([]Nameserver, 0, len(cfg.Servers)) servers := make([]Nameserver, 0, len(dnsServers))
for _, s := range cfg.Servers { for _, s := range dnsServers {
addr := net.JoinHostPort(s, cfg.Port)
ns := Nameserver{ ns := Nameserver{
Type: UDPResolver, Type: UDPResolver,
Address: addr, Address: net.JoinHostPort(s, DefaultUDPPort),
} }
servers = append(servers, ns) servers = append(servers, ns)
} }
return servers, cfg.Ndots, cfg.Search, nil return servers, ndots, search, nil
} }
func initNameserver(n string) (Nameserver, error) { func initNameserver(n string) (Nameserver, error) {

1
go.mod
View File

@ -11,4 +11,5 @@ require (
github.com/sirupsen/logrus v1.7.0 github.com/sirupsen/logrus v1.7.0
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.6.1 // indirect github.com/stretchr/testify v1.6.1 // indirect
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d
) )

View File

@ -0,0 +1,9 @@
package config
import "net"
// the whole `FEC0::/10` prefix is deprecated.
// [RFC 3879]: https://tools.ietf.org/html/rfc3879
func isUnicastLinkLocal(ip net.IP) bool {
return len(ip) == net.IPv6len && ip[0] == 0xfe && ip[1] == 0xc0
}

View File

@ -0,0 +1,30 @@
// +build !windows
package config
import (
"net"
"github.com/miekg/dns"
)
// DefaultResolvConfPath specifies path to default resolv config file on UNIX.
const DefaultResolvConfPath = "/etc/resolv.conf"
// GetDefaultServers get system default nameserver
func GetDefaultServers() ([]string, int, []string, error) {
// if no nameserver is provided, take it from `resolv.conf`
cfg, err := dns.ClientConfigFromFile(DefaultResolvConfPath)
if err != nil {
return nil, 0, nil, err
}
servers := make([]string, 0)
for _, server := range cfg.Servers {
ip := net.ParseIP(server)
if isUnicastLinkLocal(ip) {
continue
}
servers = append(servers, server)
}
return servers, cfg.Ndots, cfg.Search, nil
}

View File

@ -0,0 +1,120 @@
package config
import (
"os"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// GAA_FLAG_INCLUDE_GATEWAYS Return the addresses of default gateways.
// This flag is supported on Windows Vista and later.
const GAA_FLAG_INCLUDE_GATEWAYS = 0x00000080
// IpAdapterWinsServerAddress structure in a linked list of Windows Internet Name Service (WINS) server addresses for the adapter.
type IpAdapterWinsServerAddress struct {
Length uint32
_ uint32
Next *IpAdapterWinsServerAddress
Address windows.SocketAddress
}
// IpAdapterGatewayAddress structure in a linked list of gateways for the adapter.
type IpAdapterGatewayAddress struct {
Length uint32
_ uint32
Next *IpAdapterGatewayAddress
Address windows.SocketAddress
}
// IpAdapterAddresses structure is the header node for a linked list of addresses for a particular adapter.
// This structure can simultaneously be used as part of a linked list of IP_ADAPTER_ADDRESSES structures.
type IpAdapterAddresses struct {
Length uint32
IfIndex uint32
Next *IpAdapterAddresses
AdapterName *byte
FirstUnicastAddress *windows.IpAdapterUnicastAddress
FirstAnycastAddress *windows.IpAdapterAnycastAddress
FirstMulticastAddress *windows.IpAdapterMulticastAddress
FirstDnsServerAddress *windows.IpAdapterDnsServerAdapter
DnsSuffix *uint16
Description *uint16
FriendlyName *uint16
PhysicalAddress [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte
PhysicalAddressLength uint32
Flags uint32
Mtu uint32
IfType uint32
OperStatus uint32
Ipv6IfIndex uint32
ZoneIndices [16]uint32
FirstPrefix *windows.IpAdapterPrefix
/* more fields might be present here. */
TransmitLinkSpeed uint64
ReceiveLinkSpeed uint64
FirstWinsServerAddress *IpAdapterWinsServerAddress
FirstGatewayAddress *IpAdapterGatewayAddress
}
func adapterAddresses() ([]*IpAdapterAddresses, error) {
var b []byte
// https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses
// #define WORKING_BUFFER_SIZE 15000
l := uint32(15000)
for {
b = make([]byte, l)
err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, GAA_FLAG_INCLUDE_GATEWAYS|windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l)
if err == nil {
if l == 0 {
return nil, nil
}
break
}
if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW {
return nil, os.NewSyscallError("getadaptersaddresses", err)
}
if l <= uint32(len(b)) {
return nil, os.NewSyscallError("getadaptersaddresses", err)
}
}
aas := make([]*IpAdapterAddresses, 0, uintptr(l)/unsafe.Sizeof(IpAdapterAddresses{}))
for aa := (*IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next {
aas = append(aas, aa)
}
return aas, nil
}
func getDefaultDNSServers() ([]string, error) {
ifs, err := adapterAddresses()
if err != nil {
return nil, err
}
dnsServers := make([]string, 0)
for _, ifi := range ifs {
if ifi.OperStatus != windows.IfOperStatusUp {
continue
}
if ifi.FirstGatewayAddress == nil {
continue
}
for dnsServer := ifi.FirstDnsServerAddress; dnsServer != nil; dnsServer = dnsServer.Next {
ip := dnsServer.Address.IP()
if isUnicastLinkLocal(ip) {
continue
}
dnsServers = append(dnsServers, ip.String())
}
}
return dnsServers, nil
}
// GetDefaultServers get system default nameserver
func GetDefaultServers() ([]string, int, []string, error) {
// TODO: DNS Suffix
servers, err := getDefaultDNSServers()
return servers, 0, nil, err
}