Skip to content

Commit

Permalink
Ipv6 parsing error in upstream definition (#285)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xERR0R committed Sep 29, 2021
1 parent c2fb389 commit 9b6dc66
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 31 deletions.
70 changes: 44 additions & 26 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ type QueryLogType int16

type Duration time.Duration

const (
validUpstream = `(?P<Host>(?:\[[^\]]+\])|[^\s/:]+):?(?P<Port>[^\s/:]*)?(?P<Path>/[^\s]*)?`
)

// nolint:gochecknoglobals
var netDefaultPort = map[NetProtocol]uint16{
NetProtocolTcpUdp: 53,
Expand Down Expand Up @@ -152,45 +148,67 @@ func (c *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error {
return err
}

// ParseUpstream creates new Upstream from passed string in format [net]:host[:port][/path]
func ParseUpstream(upstream string) (result Upstream, err error) {
if strings.TrimSpace(upstream) == "" {
return Upstream{}, nil
}

var n NetProtocol
var validDomain = regexp.MustCompile(
`^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`)

n, upstream = extractNet(upstream)

r := regexp.MustCompile(validUpstream)

match := r.FindStringSubmatch(upstream)
// ParseUpstream creates new Upstream from passed string in format [net]:host[:port][/path]
func ParseUpstream(upstream string) (Upstream, error) {
var path string

host := match[1]
var port uint16

portPart := match[2]
n, upstream := extractNet(upstream)

path := match[3]
path, upstream = extractPath(upstream)

var port uint16
host, portString, err := net.SplitHostPort(upstream)

if len(portPart) > 0 {
// string contains host:port
if err == nil {
var p uint64
p, err = strconv.ParseUint(strings.TrimSpace(portPart), 10, 16)
p, err = strconv.ParseUint(strings.TrimSpace(portString), 10, 16)

if err != nil {
err = fmt.Errorf("can't convert port to number (1 - 65535) %w", err)
return
return Upstream{}, err
}

port = uint16(p)
} else {
// only host, use default port
host = upstream
port = netDefaultPort[n]
}

host = regexp.MustCompile(`[\[\]]`).ReplaceAllString(host, "")
// validate hostname or ip
ip := net.ParseIP(host)

if ip == nil {
// is not IP
if !validDomain.MatchString(host) {
return Upstream{}, fmt.Errorf("wrong host name '%s'", host)
}
}

return Upstream{
Net: n,
Host: host,
Port: port,
Path: path,
}, nil
}

func extractPath(in string) (path string, upstream string) {
slashIdx := strings.Index(in, "/")

if slashIdx >= 0 {
path = in[slashIdx:]
upstream = in[:slashIdx]
} else {
upstream = in
}

return Upstream{Net: n, Host: host, Port: port, Path: path}, nil
return
}

func extractNet(upstream string) (NetProtocol, string) {
Expand All @@ -214,7 +232,7 @@ func extractNet(upstream string) (NetProtocol, string) {
}

if strings.HasPrefix(upstream, NetProtocolHttps.String()+":") {
return NetProtocolHttps, strings.Replace(upstream, NetProtocolHttps.String()+":", "", 1)
return NetProtocolHttps, strings.TrimPrefix(strings.Replace(upstream, NetProtocolHttps.String()+":", "", 1), "//")
}

return NetProtocolTcpUdp, upstream
Expand Down
26 changes: 21 additions & 5 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,11 @@ var _ = Describe("Config", func() {
func(in string, wantResult Upstream, wantErr bool) {
result, err := ParseUpstream(in)
if wantErr {
Expect(err).Should(HaveOccurred())
Expect(err).Should(HaveOccurred(), in)
} else {
Expect(err).Should(Succeed())
Expect(err).Should(Succeed(), in)
}
Expect(result).Should(Equal(wantResult))
Expect(result).Should(Equal(wantResult), in)
},
Entry("udp with port",
"udp:4.4.4.4:531",
Expand Down Expand Up @@ -237,19 +237,23 @@ var _ = Describe("Config", func() {
Entry("empty",
"",
Upstream{Net: 0},
false),
true),
Entry("udpIpv6WithPort",
"udp:[fd00::6cd4:d7e0:d99d:2952]:53",
Upstream{Net: NetProtocolTcpUdp, Host: "fd00::6cd4:d7e0:d99d:2952", Port: 53},
false),
Entry("udpIpv6WithPort2",
"udp://[2001:4860:4860::8888]:53",
"udp:[2001:4860:4860::8888]:53",
Upstream{Net: NetProtocolTcpUdp, Host: "2001:4860:4860::8888", Port: 53},
false),
Entry("default net, default port",
"1.1.1.1",
Upstream{Net: NetProtocolTcpUdp, Host: "1.1.1.1", Port: 53},
false),
Entry("wrong host name",
"host$name",
Upstream{},
true),
Entry("default net with port",
"1.1.1.1:153",
Upstream{Net: NetProtocolTcpUdp, Host: "1.1.1.1", Port: 153},
Expand Down Expand Up @@ -278,5 +282,17 @@ var _ = Describe("Config", func() {
"tcp+udp:1.1.1.1",
Upstream{Net: NetProtocolTcpUdp, Host: "1.1.1.1", Port: 53},
false),
Entry("defaultIpv6Short",
"2620:fe::fe",
Upstream{Net: NetProtocolTcpUdp, Host: "2620:fe::fe", Port: 53},
false),
Entry("defaultIpv6Short2",
"2620:fe::9",
Upstream{Net: NetProtocolTcpUdp, Host: "2620:fe::9", Port: 53},
false),
Entry("defaultIpv6WithPort",
"[2620:fe::9]:55",
Upstream{Net: NetProtocolTcpUdp, Host: "2620:fe::9", Port: 55},
false),
)
})

0 comments on commit 9b6dc66

Please sign in to comment.