-
Notifications
You must be signed in to change notification settings - Fork 12
/
parse.go
92 lines (86 loc) · 2.35 KB
/
parse.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package dnsredir
import (
"fmt"
"github.com/coredns/coredns/plugin/pkg/transport"
"net"
"net/url"
"strings"
)
// Strips trailing IP zone and/or TLS server name
// If above two both present, the former one should always comes before the latter one.
// see: https://www.ietf.org/rfc/rfc4001.txt
func stripZoneAndTlsName(host string) string {
if strings.Contains(host, "%") {
return host[:strings.Index(host, "%")]
}
if strings.Contains(host, "@") {
return host[:strings.Index(host, "@")]
}
return host
}
var knownTrans = []string{
"dns", // Use protocol specified in incoming DNS requests, i.e. it may UDP, TCP.
"udp",
"tcp",
"tls",
"json-doh",
"ietf-doh",
"doh",
}
func SplitTransportHost(s string) (trans string, addr string) {
s = strings.ToLower(s)
for _, trans := range knownTrans {
if strings.HasPrefix(s, trans+"://") {
return trans, s[len(trans+"://"):]
}
}
// Have no proceeding transport? assume it's classic DNS protocol
return "dns", s
}
// Taken from parse.HostPortOrFile() with modification
func HostPort(servers []string) ([]string, error) {
var list []string
for _, h := range servers {
trans, host := SplitTransportHost(h)
addr, _, err := net.SplitHostPort(host)
if err != nil {
if strings.HasSuffix(trans, "doh") {
if _, err := url.ParseRequestURI(h); err != nil {
return nil, fmt.Errorf("failed to parse %q: %v", h, err)
}
} else {
// Parse didn't work, it is not an addr:port combo
if _, ok := stringToDomain(host); !ok && net.ParseIP(stripZoneAndTlsName(host)) == nil {
return nil, fmt.Errorf("#1 not a domain name or an IP address: %q", host)
}
}
var s string
switch trans {
case "dns":
fallthrough
case "udp":
fallthrough
case "tcp":
s = trans + "://" + net.JoinHostPort(host, transport.Port)
case "tls":
host, tlsName := SplitByByte(host, '@')
s = trans + "://" + net.JoinHostPort(host, transport.TLSPort) + tlsName
case "json-doh":
fallthrough
case "ietf-doh":
fallthrough
case "doh":
s = h
default:
panic(fmt.Sprintf("Unknown transport %q", trans))
}
list = append(list, s)
} else {
if _, ok := stringToDomain(addr); !ok && net.ParseIP(stripZoneAndTlsName(addr)) == nil {
return nil, fmt.Errorf("#2 not a domain name or an IP address: %q", host)
}
list = append(list, trans+"://"+host)
}
}
return list, nil
}