aboutsummaryrefslogtreecommitdiff
path: root/plugin/pkg/parse/host.go
blob: 78f7cd93b79a3b8b549bfd087e09730b94c7c6ca (plain) (blame)
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package parse

import (
	"errors"
	"fmt"
	"net"
	"os"
	"strings"

	"github.com/coredns/coredns/plugin/pkg/transport"

	"github.com/miekg/dns"
)

// ErrNoNameservers is returned by HostPortOrFile if no servers can be parsed.
var ErrNoNameservers = errors.New("no nameservers found")

// Strips the zone, but preserves any port that comes after the zone
func stripZone(host string) string {
	if strings.Contains(host, "%") {
		lastPercent := strings.LastIndex(host, "%")
		newHost := host[:lastPercent]
		return newHost
	}
	return host
}

// HostPortOrFile parses the strings in s, each string can either be a
// address, [scheme://]address:port or a filename. The address part is checked
// and in case of filename a resolv.conf like file is (assumed) and parsed and
// the nameservers found are returned.
func HostPortOrFile(s ...string) ([]string, error) {
	var servers []string
	for _, h := range s {
		trans, host := Transport(h)
		if len(host) == 0 {
			return servers, fmt.Errorf("invalid address: %q", h)
		}

		if trans == transport.UNIX {
			servers = append(servers, trans+"://"+host)
			continue
		}

		addr, _, err := net.SplitHostPort(host)

		if err != nil {
			// Parse didn't work, it is not a addr:port combo
			hostNoZone := stripZone(host)
			if net.ParseIP(hostNoZone) == nil {
				ss, err := tryFile(host)
				if err == nil {
					servers = append(servers, ss...)
					continue
				}
				return servers, fmt.Errorf("not an IP address or file: %q", host)
			}
			var ss string
			switch trans {
			case transport.DNS:
				ss = net.JoinHostPort(host, transport.Port)
			case transport.TLS:
				ss = transport.TLS + "://" + net.JoinHostPort(host, transport.TLSPort)
			case transport.QUIC:
				ss = transport.QUIC + "://" + net.JoinHostPort(host, transport.QUICPort)
			case transport.GRPC:
				ss = transport.GRPC + "://" + net.JoinHostPort(host, transport.GRPCPort)
			case transport.HTTPS:
				ss = transport.HTTPS + "://" + net.JoinHostPort(host, transport.HTTPSPort)
			}
			servers = append(servers, ss)
			continue
		}

		if net.ParseIP(stripZone(addr)) == nil {
			ss, err := tryFile(host)
			if err == nil {
				servers = append(servers, ss...)
				continue
			}
			return servers, fmt.Errorf("not an IP address or file: %q", host)
		}
		servers = append(servers, h)
	}
	if len(servers) == 0 {
		return servers, ErrNoNameservers
	}
	return servers, nil
}

// Try to open this is a file first.
func tryFile(s string) ([]string, error) {
	c, err := dns.ClientConfigFromFile(s)
	if err == os.ErrNotExist {
		return nil, fmt.Errorf("failed to open file %q: %q", s, err)
	} else if err != nil {
		return nil, err
	}

	servers := []string{}
	for _, s := range c.Servers {
		servers = append(servers, net.JoinHostPort(stripZone(s), c.Port))
	}
	return servers, nil
}

// HostPort will check if the host part is a valid IP address, if the
// IP address is valid, but no port is found, defaultPort is added.
func HostPort(s, defaultPort string) (string, error) {
	addr, port, err := net.SplitHostPort(s)
	if port == "" {
		port = defaultPort
	}
	if err != nil {
		if net.ParseIP(s) == nil {
			return "", fmt.Errorf("must specify an IP address: `%s'", s)
		}
		return net.JoinHostPort(s, port), nil
	}

	if net.ParseIP(addr) == nil {
		return "", fmt.Errorf("must specify an IP address: `%s'", addr)
	}
	return net.JoinHostPort(addr, port), nil
}
tro' width='13' height='13' alt='Gravatar' /> Ai Hoshino 1-1/+1 2023-09-04fix(HTMLRewriter) buffer response before transform (#4418)Gravatar Ciro Spaciari 18-5941/+6655 2023-09-03initialize JSC for macros from cliGravatar Dylan Conway 1-0/+4 2023-09-03fix(syscall): fix handling syscall errno (#4461)Gravatar Ai Hoshino 2-1/+22 2023-09-02workaround a zig bug (#4440)Gravatar dave caruso 1-3/+4 2023-09-01docs: fix http simple example log statement (#4320)Gravatar Karl Böhlmark 1-1/+1 2023-09-01Fix typo (#4445)Gravatar Jorge Jiménez 1-1/+1 2023-09-01keep export star as (#4451)Gravatar Dylan Conway 1-14/+0 2023-09-01bun-vscode 0.0.8Gravatar Colin McDonnell 3-41/+39 2023-09-01Update commandsGravatar Colin McDonnell 3-4/+6 2023-09-01fix `Bun.serve` with tls and `Bun.file` (#4450)Gravatar Dylan Conway 3-14/+40 2023-09-01exclusive maxGravatar Dylan Conway 1-1/+1 2023-09-01Fix debug console from appears on startGravatar Ashcon Partovi 2-2/+5 2023-09-01Add configuration options to extensionGravatar Ashcon Partovi 5-5/+137 2023-09-01Fix run button starting cwd at /Gravatar Ashcon Partovi 1-0/+2 2023-09-01fix(runtime): fix dns_resolver crash (#4435)Gravatar dave caruso 3-17/+19 2023-09-01Fix background colorGravatar Ashcon Partovi 1-2/+3 2023-09-01Allow older versions of VSCodeGravatar Ashcon Partovi 2-6/+5 2023-09-01Fix README for extensionGravatar Ashcon Partovi 2-7/+12 2023-09-01Update VSCode extensionGravatar Ashcon Partovi 1-3/+4 2023-09-01Fix breakpoint on entry for extensionGravatar Ashcon Partovi 5-18/+15 2023-09-01Add Bun.canReload event to inspectorGravatar Ashcon Partovi 2-0/+17 2023-08-31JavaScript Debug Terminal == Bun TerminalGravatar Ashcon Partovi 1-0/+32 2023-08-31fix(runtime): `fs.cp` edge cases (#4439)Gravatar dave caruso 2-8/+44 2023-08-31only set initial debugger breakpoint once (#4441)Gravatar Dylan Conway 1-2/+11 2023-08-31Make breakpoints faster in VSCode extensionGravatar Ashcon Partovi 1-241/+327 2023-08-31`bun install` correctly join dependency URLs (#4421)Gravatar Julian 6-64/+243 2023-08-31get name if not provided in `FormData.append` (#4434)Gravatar Dylan Conway 4-5/+45 2023-08-31Fix vscode debug terminalGravatar Ashcon Partovi 1-21/+0