mirror of
https://github.com/cunnie/sslip.io.git
synced 2025-10-05 23:56:50 +08:00
Resolve hexadecimal notation for IPv6 addresses
e.g. `00000000000000000000000000000001.nip.io` → ::1 This is to bring parity with IPv4's hexadecimal notation, though IPv6's hexadecimal notation is so clunky that I doubt it'll ever be used. - The hexadecimal-notated IPv6 must be exactly 32 hexadecimal characters, no separators. - Any hexadecimal notation _must_ be bookended by dots or by the beginning or end of the string (www.0000000000000000000000000000001.sslip.io or 00000000000000000000000000000001.sslip.io). No dashes. - If a normal IP notation and a hex notation are in the same hostname, then the normal IP notation takes precedence. This preserves existing behavior for sslip.io users, e.g. (00000000000000000000000000000001.2600--.nip.io resolves to 2600::, not ::1)
This commit is contained in:
@@ -136,22 +136,6 @@ var _ = Describe("flags", func() {
|
|||||||
Eventually(digSession, 1).Should(Exit(0))
|
Eventually(digSession, 1).Should(Exit(0))
|
||||||
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`\? nil, SOA 8-8-8-8\.sslip\.io\. briancunnie\.gmail\.com\.`))
|
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`\? nil, SOA 8-8-8-8\.sslip\.io\. briancunnie\.gmail\.com\.`))
|
||||||
})
|
})
|
||||||
It("doesn't resolve public IPv4 addresses (hexadecimal)", func() {
|
|
||||||
digArgs := "@localhost 08080808.sslip.io -p " + strconv.Itoa(port)
|
|
||||||
digCmd := exec.Command("dig", strings.Split(digArgs, " ")...)
|
|
||||||
digSession, err := Start(digCmd, GinkgoWriter, GinkgoWriter)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Eventually(digSession, 1).Should(Exit(0))
|
|
||||||
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`\? nil, SOA 08080808\.sslip\.io\. briancunnie\.gmail\.com\.`))
|
|
||||||
})
|
|
||||||
It("resolves private IPv4 addresses (hexadecimal)", func() {
|
|
||||||
digArgs := "@localhost 7f000001.sslip.io -p " + strconv.Itoa(port)
|
|
||||||
digCmd := exec.Command("dig", strings.Split(digArgs, " ")...)
|
|
||||||
digSession, err := Start(digCmd, GinkgoWriter, GinkgoWriter)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Eventually(digSession, 1).Should(Exit(0))
|
|
||||||
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeA 7f000001.sslip.io. \? 127.0.0.1`))
|
|
||||||
})
|
|
||||||
It("doesn't resolve public IPv6 addresses", func() {
|
It("doesn't resolve public IPv6 addresses", func() {
|
||||||
digArgs := "@localhost aaaa 2600--.sslip.io -p " + strconv.Itoa(port)
|
digArgs := "@localhost aaaa 2600--.sslip.io -p " + strconv.Itoa(port)
|
||||||
digCmd := exec.Command("dig", strings.Split(digArgs, " ")...)
|
digCmd := exec.Command("dig", strings.Split(digArgs, " ")...)
|
||||||
@@ -160,6 +144,22 @@ var _ = Describe("flags", func() {
|
|||||||
Eventually(digSession, 1).Should(Exit(0))
|
Eventually(digSession, 1).Should(Exit(0))
|
||||||
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`\? nil, SOA 2600--\.sslip\.io\. briancunnie\.gmail\.com\.`))
|
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`\? nil, SOA 2600--\.sslip\.io\. briancunnie\.gmail\.com\.`))
|
||||||
})
|
})
|
||||||
|
It("doesn't resolve public IPv4 addresses (hexadecimal)", func() {
|
||||||
|
digArgs := "@localhost 08080808.nip.io -p " + strconv.Itoa(port)
|
||||||
|
digCmd := exec.Command("dig", strings.Split(digArgs, " ")...)
|
||||||
|
digSession, err := Start(digCmd, GinkgoWriter, GinkgoWriter)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Eventually(digSession, 1).Should(Exit(0))
|
||||||
|
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`\? nil, SOA 08080808\.nip\.io\. briancunnie\.gmail\.com\.`))
|
||||||
|
})
|
||||||
|
It("doesn't resolve public IPv6 addresses (hexadecimal)", func() {
|
||||||
|
digArgs := "@localhost aaaa 26010646010069f0042c6ab3cdd9e562.nip.io -p " + strconv.Itoa(port) // my laptop's IPv6 address
|
||||||
|
digCmd := exec.Command("dig", strings.Split(digArgs, " ")...)
|
||||||
|
digSession, err := Start(digCmd, GinkgoWriter, GinkgoWriter)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Eventually(digSession, 1).Should(Exit(0))
|
||||||
|
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`\? nil, SOA 26010646010069f0042c6ab3cdd9e562\.nip\.io\. briancunnie\.gmail\.com\.`))
|
||||||
|
})
|
||||||
It("resolves private IPv4 addresses", func() {
|
It("resolves private IPv4 addresses", func() {
|
||||||
digArgs := "@localhost 192-168-0-1.sslip.io -p " + strconv.Itoa(port)
|
digArgs := "@localhost 192-168-0-1.sslip.io -p " + strconv.Itoa(port)
|
||||||
digCmd := exec.Command("dig", strings.Split(digArgs, " ")...)
|
digCmd := exec.Command("dig", strings.Split(digArgs, " ")...)
|
||||||
@@ -176,6 +176,22 @@ var _ = Describe("flags", func() {
|
|||||||
Eventually(digSession, 1).Should(Exit(0))
|
Eventually(digSession, 1).Should(Exit(0))
|
||||||
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`fc00--\.sslip\.io\. \? fc00::`))
|
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`fc00--\.sslip\.io\. \? fc00::`))
|
||||||
})
|
})
|
||||||
|
It("resolves private IPv4 addresses (hexadecimal)", func() {
|
||||||
|
digArgs := "@localhost 7f000001.nip.io -p " + strconv.Itoa(port)
|
||||||
|
digCmd := exec.Command("dig", strings.Split(digArgs, " ")...)
|
||||||
|
digSession, err := Start(digCmd, GinkgoWriter, GinkgoWriter)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Eventually(digSession, 1).Should(Exit(0))
|
||||||
|
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeA 7f000001.nip.io. \? 127.0.0.1`))
|
||||||
|
})
|
||||||
|
It("resolves private IPv6 addresses (hexadecimal)", func() {
|
||||||
|
digArgs := "@localhost aaaa 00000000000000000000000000000001.nip.io -p " + strconv.Itoa(port)
|
||||||
|
digCmd := exec.Command("dig", strings.Split(digArgs, " ")...)
|
||||||
|
digSession, err := Start(digCmd, GinkgoWriter, GinkgoWriter)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Eventually(digSession, 1).Should(Exit(0))
|
||||||
|
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeAAAA 00000000000000000000000000000001.nip.io. \? ::1`))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
When("-delegates is set", func() {
|
When("-delegates is set", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
|
29
xip/xip.go
29
xip/xip.go
@@ -87,6 +87,7 @@ var (
|
|||||||
ipv4REHex = regexp.MustCompile(`(^|\.)([[:xdigit:]]{8})($|\.)`) // no dash separators, only dots
|
ipv4REHex = regexp.MustCompile(`(^|\.)([[:xdigit:]]{8})($|\.)`) // no dash separators, only dots
|
||||||
// https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
|
// https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
|
||||||
ipv6RE = regexp.MustCompile(`(^|[.-])(([[:xdigit:]]{1,4}-){7}[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}-){1,7}-|([[:xdigit:]]{1,4}-){1,6}-[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}-){1,5}(-[[:xdigit:]]{1,4}){1,2}|([[:xdigit:]]{1,4}-){1,4}(-[[:xdigit:]]{1,4}){1,3}|([[:xdigit:]]{1,4}-){1,3}(-[[:xdigit:]]{1,4}){1,4}|([[:xdigit:]]{1,4}-){1,2}(-[[:xdigit:]]{1,4}){1,5}|[[:xdigit:]]{1,4}-((-[[:xdigit:]]{1,4}){1,6})|-((-[[:xdigit:]]{1,4}){1,7}|-)|fe80-(-[[:xdigit:]]{0,4}){0,4}%[\da-zA-Z]+|--(ffff(-0{1,4})?-)?((25[0-5]|(2[0-4]|1?\d)?\d)\.){3}(25[0-5]|(2[0-4]|1?\d)?\d)|([[:xdigit:]]{1,4}-){1,4}-((25[0-5]|(2[0-4]|1?\d)?\d)\.){3}(25[0-5]|(2[0-4]|1?\d)?\d))($|[.-])`)
|
ipv6RE = regexp.MustCompile(`(^|[.-])(([[:xdigit:]]{1,4}-){7}[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}-){1,7}-|([[:xdigit:]]{1,4}-){1,6}-[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}-){1,5}(-[[:xdigit:]]{1,4}){1,2}|([[:xdigit:]]{1,4}-){1,4}(-[[:xdigit:]]{1,4}){1,3}|([[:xdigit:]]{1,4}-){1,3}(-[[:xdigit:]]{1,4}){1,4}|([[:xdigit:]]{1,4}-){1,2}(-[[:xdigit:]]{1,4}){1,5}|[[:xdigit:]]{1,4}-((-[[:xdigit:]]{1,4}){1,6})|-((-[[:xdigit:]]{1,4}){1,7}|-)|fe80-(-[[:xdigit:]]{0,4}){0,4}%[\da-zA-Z]+|--(ffff(-0{1,4})?-)?((25[0-5]|(2[0-4]|1?\d)?\d)\.){3}(25[0-5]|(2[0-4]|1?\d)?\d)|([[:xdigit:]]{1,4}-){1,4}-((25[0-5]|(2[0-4]|1?\d)?\d)\.){3}(25[0-5]|(2[0-4]|1?\d)?\d))($|[.-])`)
|
||||||
|
ipv6REHex = regexp.MustCompile(`(^|\.)([[:xdigit:]]{32})($|\.)`) // no dash separators, only dots
|
||||||
ipv4ReverseRE = regexp.MustCompile(`^(.*)\.in-addr\.arpa\.$`)
|
ipv4ReverseRE = regexp.MustCompile(`^(.*)\.in-addr\.arpa\.$`)
|
||||||
ipv6ReverseRE = regexp.MustCompile(`^(([[:xdigit:]]\.){32})ip6\.arpa\.`)
|
ipv6ReverseRE = regexp.MustCompile(`^(([[:xdigit:]]\.){32})ip6\.arpa\.`)
|
||||||
dns01ChallengeRE = regexp.MustCompile(`(?i)_acme-challenge\.`) // (?i) → non-capturing case insensitive
|
dns01ChallengeRE = regexp.MustCompile(`(?i)_acme-challenge\.`) // (?i) → non-capturing case insensitive
|
||||||
@@ -815,10 +816,7 @@ func NameToAAAA(fqdnString string, allowPublicIPs bool) []dnsmessage.AAAAResourc
|
|||||||
if domain, ok := Customizations[strings.ToLower(fqdnString)]; ok && len(domain.AAAA) > 0 {
|
if domain, ok := Customizations[strings.ToLower(fqdnString)]; ok && len(domain.AAAA) > 0 {
|
||||||
return domain.AAAA
|
return domain.AAAA
|
||||||
}
|
}
|
||||||
if !ipv6RE.Match(fqdn) {
|
if ipv6RE.Match(fqdn) {
|
||||||
return []dnsmessage.AAAAResource{}
|
|
||||||
}
|
|
||||||
|
|
||||||
ipv6RE.Longest()
|
ipv6RE.Longest()
|
||||||
match := string(ipv6RE.FindSubmatch(fqdn)[2])
|
match := string(ipv6RE.FindSubmatch(fqdn)[2])
|
||||||
match = strings.Replace(match, "-", ":", -1)
|
match = strings.Replace(match, "-", ":", -1)
|
||||||
@@ -837,6 +835,29 @@ func NameToAAAA(fqdnString string, allowPublicIPs bool) []dnsmessage.AAAAResourc
|
|||||||
}
|
}
|
||||||
return []dnsmessage.AAAAResource{AAAAR}
|
return []dnsmessage.AAAAResource{AAAAR}
|
||||||
}
|
}
|
||||||
|
if match := ipv6REHex.FindSubmatch(fqdn); match != nil {
|
||||||
|
hexes := match[2] // strip out leading & trailing "." by using only the 2nd capture group
|
||||||
|
ipBytes := make([]byte, 16)
|
||||||
|
_, err := hex.Decode(ipBytes, []byte(hexes))
|
||||||
|
if err != nil || len(ipBytes) != 16 {
|
||||||
|
return []dnsmessage.AAAAResource{}
|
||||||
|
}
|
||||||
|
ipv6address := net.IP(ipBytes)
|
||||||
|
if ipv6address == nil {
|
||||||
|
return []dnsmessage.AAAAResource{}
|
||||||
|
}
|
||||||
|
if (!allowPublicIPs) && IsPublic(ipv6address) {
|
||||||
|
return []dnsmessage.AAAAResource{}
|
||||||
|
}
|
||||||
|
return []dnsmessage.AAAAResource{
|
||||||
|
{AAAA: [16]byte{ipv6address[0], ipv6address[1], ipv6address[2], ipv6address[3],
|
||||||
|
ipv6address[4], ipv6address[5], ipv6address[6], ipv6address[7],
|
||||||
|
ipv6address[8], ipv6address[9], ipv6address[10], ipv6address[11],
|
||||||
|
ipv6address[12], ipv6address[13], ipv6address[14], ipv6address[15]}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []dnsmessage.AAAAResource{}
|
||||||
|
}
|
||||||
|
|
||||||
// CNAMEResource returns the CNAME via Customizations, otherwise nil
|
// CNAMEResource returns the CNAME via Customizations, otherwise nil
|
||||||
func CNAMEResource(fqdnString string) *dnsmessage.CNAMEResource {
|
func CNAMEResource(fqdnString string) *dnsmessage.CNAMEResource {
|
||||||
|
@@ -351,8 +351,8 @@ var _ = Describe("Xip", func() {
|
|||||||
DescribeTable("when it succeeds",
|
DescribeTable("when it succeeds",
|
||||||
func(fqdn string, expectedAAAA dnsmessage.AAAAResource) {
|
func(fqdn string, expectedAAAA dnsmessage.AAAAResource) {
|
||||||
ipv6Answers := xip.NameToAAAA(fqdn, true)
|
ipv6Answers := xip.NameToAAAA(fqdn, true)
|
||||||
Expect(len(ipv6Answers)).To(Equal(1))
|
|
||||||
Expect(ipv6Answers[0]).To(Equal(expectedAAAA))
|
Expect(ipv6Answers[0]).To(Equal(expectedAAAA))
|
||||||
|
Expect(len(ipv6Answers)).To(Equal(1))
|
||||||
},
|
},
|
||||||
// dashes only
|
// dashes only
|
||||||
Entry("loopback", "--1", dnsmessage.AAAAResource{AAAA: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}),
|
Entry("loopback", "--1", dnsmessage.AAAAResource{AAAA: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}),
|
||||||
@@ -362,6 +362,16 @@ var _ = Describe("Xip", func() {
|
|||||||
Entry("Browsing the logs", "2006-41d0-2-e01e--56dB-3598.sSLIP.io.", dnsmessage.AAAAResource{AAAA: [16]byte{32, 6, 65, 208, 0, 2, 224, 30, 0, 0, 0, 0, 86, 219, 53, 152}}),
|
Entry("Browsing the logs", "2006-41d0-2-e01e--56dB-3598.sSLIP.io.", dnsmessage.AAAAResource{AAAA: [16]byte{32, 6, 65, 208, 0, 2, 224, 30, 0, 0, 0, 0, 86, 219, 53, 152}}),
|
||||||
Entry("Browsing the logs", "1-2-3--4-5-6.sSLIP.io.", dnsmessage.AAAAResource{AAAA: [16]byte{0, 1, 0, 2, 0, 3, 0, 0, 0, 0, 0, 4, 0, 5, 0, 6}}),
|
Entry("Browsing the logs", "1-2-3--4-5-6.sSLIP.io.", dnsmessage.AAAAResource{AAAA: [16]byte{0, 1, 0, 2, 0, 3, 0, 0, 0, 0, 0, 4, 0, 5, 0, 6}}),
|
||||||
Entry("Browsing the logs", "1--2-3-4-5-6.sSLIP.io.", dnsmessage.AAAAResource{AAAA: [16]byte{0, 1, 0, 0, 0, 0, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6}}),
|
Entry("Browsing the logs", "1--2-3-4-5-6.sSLIP.io.", dnsmessage.AAAAResource{AAAA: [16]byte{0, 1, 0, 0, 0, 0, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6}}),
|
||||||
|
Entry("Hexadecimal #0", "filer.00000000000000000000000000000001.sslip.io", dnsmessage.AAAAResource{AAAA: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}),
|
||||||
|
Entry("Hexadecimal #1, TLD", "00000000000000000000000000000001", dnsmessage.AAAAResource{AAAA: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}),
|
||||||
|
Entry("Hexadecimal #1, TLD #2", "00000000000000000000000000000001.", dnsmessage.AAAAResource{AAAA: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}),
|
||||||
|
Entry("Hexadecimal #1, TLD #3", ".00000000000000000000000000000001.", dnsmessage.AAAAResource{AAAA: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}),
|
||||||
|
Entry("Hexadecimal #1, TLD #4", "www.00000000000000000000000000000001.", dnsmessage.AAAAResource{AAAA: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}),
|
||||||
|
Entry("Hexadecimal #2, mixed case", "89abcdef0000000089ABCDEF00000000.nip.io", dnsmessage.AAAAResource{AAAA: [16]byte{137, 171, 205, 239, 0, 0, 0, 0, 137, 171, 205, 239, 0, 0, 0, 0}}),
|
||||||
|
Entry("Hexadecimal #3, different numbers", "www.0123456789abcdef0123456789abcdef.nip.io", dnsmessage.AAAAResource{AAAA: [16]byte{1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239}}),
|
||||||
|
Entry("Hexadecimal #3, different numbers #2", "www.00000000000000000000000000000001.nip.io", dnsmessage.AAAAResource{AAAA: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}),
|
||||||
|
Entry("Hexadecimal #4, dashes trump hex", "www.2600--.00000000000000000000000000000001.nip.io", dnsmessage.AAAAResource{AAAA: [16]byte{38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}),
|
||||||
|
Entry("Hexadecimal #4, dashes trump hex #2", "www.00000000000000000000000000000001.--2.nip.io", dnsmessage.AAAAResource{AAAA: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}}),
|
||||||
)
|
)
|
||||||
DescribeTable("when it does not match an IP address",
|
DescribeTable("when it does not match an IP address",
|
||||||
func(fqdn string) {
|
func(fqdn string) {
|
||||||
@@ -374,6 +384,10 @@ var _ = Describe("Xip", func() {
|
|||||||
Entry("www", "www.sslip.io"),
|
Entry("www", "www.sslip.io"),
|
||||||
Entry("a 1 without double-dash", "-1"),
|
Entry("a 1 without double-dash", "-1"),
|
||||||
Entry("too big", "--g"),
|
Entry("too big", "--g"),
|
||||||
|
Entry("Hexadecimal with too many digits (33 instead of 32)", "www.0123456789abcdef0123456789abcdef0.com"),
|
||||||
|
Entry("Hexadecimal with too few digits (31 instead of 32)", "www.0123456789abcdef0123456789abcde.com"),
|
||||||
|
Entry("Hexadecimal with a dash instead of a .", "www-0123456789abcdef0123456789abcdef.com"),
|
||||||
|
Entry("Hexadecimal with a dash instead of a . #2", "www.0123456789abcdef0123456789abcdef-com"),
|
||||||
)
|
)
|
||||||
When("using randomly generated IPv6 addresses (fuzz testing)", func() {
|
When("using randomly generated IPv6 addresses (fuzz testing)", func() {
|
||||||
It("should succeed every time", func() {
|
It("should succeed every time", func() {
|
||||||
|
Reference in New Issue
Block a user