mirror of
https://github.com/cunnie/sslip.io.git
synced 2025-10-05 23:56:50 +08:00
Resolve hexadecimal notation for IPv4 addresses
e.g. `7f000001.sslip.io` → 127.0.0.1 This came about as a result of the nip.io migration to sslip.io servers: nip.io supported hexadecimal notation; sslip.io didn't. Several nip.io users were blindsided by the feature's lack, and raised an issue. - The hexadecimal-notated IPv4 must be exactly 8 hexadecimal characters, no separators. - Any hexadecimal notation _must_ be bookended by dots or by the beginning or end of the string (www.0a09091e.sslip.io or 0a09091e.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. (0a09091e.127-0-0-1.sslip.io resolves to 127.0.0.1, not 10.9.9.30) [#92]
This commit is contained in:
@@ -136,6 +136,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 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, " ")...)
|
||||||
|
24
xip/xip.go
24
xip/xip.go
@@ -5,6 +5,7 @@ package xip
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -83,6 +84,7 @@ type DomainCustomizations map[string]DomainCustomization
|
|||||||
var (
|
var (
|
||||||
ipv4REDots = regexp.MustCompile(`(^|[.-])(((25[0-5]|(2[0-4]|1?\d)?\d)\.){3}(25[0-5]|(2[0-4]|1?\d)?\d))($|[.-])`)
|
ipv4REDots = regexp.MustCompile(`(^|[.-])(((25[0-5]|(2[0-4]|1?\d)?\d)\.){3}(25[0-5]|(2[0-4]|1?\d)?\d))($|[.-])`)
|
||||||
ipv4REDashes = regexp.MustCompile(`(^|[.-])(((25[0-5]|(2[0-4]|1?\d)?\d)-){3}(25[0-5]|(2[0-4]|1?\d)?\d))($|[.-])`)
|
ipv4REDashes = regexp.MustCompile(`(^|[.-])(((25[0-5]|(2[0-4]|1?\d)?\d)-){3}(25[0-5]|(2[0-4]|1?\d)?\d))($|[.-])`)
|
||||||
|
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))($|[.-])`)
|
||||||
ipv4ReverseRE = regexp.MustCompile(`^(.*)\.in-addr\.arpa\.$`)
|
ipv4ReverseRE = regexp.MustCompile(`^(.*)\.in-addr\.arpa\.$`)
|
||||||
@@ -783,6 +785,28 @@ func NameToA(fqdnString string, allowPublicIPs bool) []dnsmessage.AResource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if match := ipv4REHex.FindSubmatch(fqdn); match != nil {
|
||||||
|
hexes := match[2] // strip out leading & trailing "." by using only the 2nd capture group, e.g. "7f000001"
|
||||||
|
ipBytes := make([]byte, 4)
|
||||||
|
_, err := hex.Decode(ipBytes, []byte(hexes))
|
||||||
|
if err != nil || len(ipBytes) != 4 {
|
||||||
|
return []dnsmessage.AResource{}
|
||||||
|
}
|
||||||
|
ipv4address := net.IPv4(ipBytes[0], ipBytes[1], ipBytes[2], ipBytes[3])
|
||||||
|
if ipv4address == nil {
|
||||||
|
return []dnsmessage.AResource{}
|
||||||
|
}
|
||||||
|
ipv4address = ipv4address.To4()
|
||||||
|
if ipv4address == nil {
|
||||||
|
return []dnsmessage.AResource{}
|
||||||
|
}
|
||||||
|
if (!allowPublicIPs) && IsPublic(ipv4address) {
|
||||||
|
return []dnsmessage.AResource{}
|
||||||
|
}
|
||||||
|
return []dnsmessage.AResource{
|
||||||
|
{A: [4]byte{ipv4address[0], ipv4address[1], ipv4address[2], ipv4address[3]}},
|
||||||
|
}
|
||||||
|
}
|
||||||
return []dnsmessage.AResource{}
|
return []dnsmessage.AResource{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -198,8 +198,8 @@ var _ = Describe("Xip", func() {
|
|||||||
DescribeTable("when it succeeds",
|
DescribeTable("when it succeeds",
|
||||||
func(fqdn string, expectedA dnsmessage.AResource) {
|
func(fqdn string, expectedA dnsmessage.AResource) {
|
||||||
ipv4Answers := xip.NameToA(fqdn, true)
|
ipv4Answers := xip.NameToA(fqdn, true)
|
||||||
Expect(len(ipv4Answers)).To(Equal(1))
|
|
||||||
Expect(ipv4Answers[0]).To(Equal(expectedA))
|
Expect(ipv4Answers[0]).To(Equal(expectedA))
|
||||||
|
Expect(len(ipv4Answers)).To(Equal(1))
|
||||||
},
|
},
|
||||||
Entry("custom record", "CusTom.RecOrd.", dnsmessage.AResource{A: [4]byte{78, 46, 204, 247}}),
|
Entry("custom record", "CusTom.RecOrd.", dnsmessage.AResource{A: [4]byte{78, 46, 204, 247}}),
|
||||||
// dots
|
// dots
|
||||||
@@ -213,6 +213,18 @@ var _ = Describe("Xip", func() {
|
|||||||
Entry("IETF protocol assignments with domain and www", "www-192-0-0-1-com", dnsmessage.AResource{A: [4]byte{192, 0, 0, 1}}),
|
Entry("IETF protocol assignments with domain and www", "www-192-0-0-1-com", dnsmessage.AResource{A: [4]byte{192, 0, 0, 1}}),
|
||||||
// dots-and-dashes, mix-and-matches
|
// dots-and-dashes, mix-and-matches
|
||||||
Entry("Pandaxin's paradox", "minio-01.192-168-1-100.sslip.io", dnsmessage.AResource{A: [4]byte{192, 168, 1, 100}}),
|
Entry("Pandaxin's paradox", "minio-01.192-168-1-100.sslip.io", dnsmessage.AResource{A: [4]byte{192, 168, 1, 100}}),
|
||||||
|
Entry("Hexadecimal #0", "filer.7f000001.sslip.io", dnsmessage.AResource{A: [4]byte{127, 0, 0, 1}}),
|
||||||
|
Entry("Hexadecimal #1, TLD", "0A09091E", dnsmessage.AResource{A: [4]byte{10, 9, 9, 30}}),
|
||||||
|
Entry("Hexadecimal #1, TLD #2", "0A09091E.", dnsmessage.AResource{A: [4]byte{10, 9, 9, 30}}),
|
||||||
|
Entry("Hexadecimal #1, TLD #3", ".0A09091E.", dnsmessage.AResource{A: [4]byte{10, 9, 9, 30}}),
|
||||||
|
Entry("Hexadecimal #1, TLD #4", "www.0A09091E.", dnsmessage.AResource{A: [4]byte{10, 9, 9, 30}}),
|
||||||
|
Entry("Hexadecimal #2, mixed case", "ffffFFFF.nip.io", dnsmessage.AResource{A: [4]byte{255, 255, 255, 255}}),
|
||||||
|
Entry("Hexadecimal #3, different numbers", "www.fedcba98.nip.io", dnsmessage.AResource{A: [4]byte{254, 220, 186, 152}}),
|
||||||
|
Entry("Hexadecimal #3, different numbers #2", "www.76543210.nip.io", dnsmessage.AResource{A: [4]byte{118, 84, 50, 16}}),
|
||||||
|
Entry("Hexadecimal #4, dashes trump hex", "www.127-0-0-53.76543210.nip.io", dnsmessage.AResource{A: [4]byte{127, 0, 0, 53}}),
|
||||||
|
Entry("Hexadecimal #4, dashes trump hex #2", "www.76543210.127-0-0-53.nip.io", dnsmessage.AResource{A: [4]byte{127, 0, 0, 53}}),
|
||||||
|
Entry("Hexadecimal #4, dots trump hex", "www.127.0.0.53.76543210.nip.io", dnsmessage.AResource{A: [4]byte{127, 0, 0, 53}}),
|
||||||
|
Entry("Hexadecimal #4, dots trump hex #2", "www.76543210.127.0.0.53.nip.io", dnsmessage.AResource{A: [4]byte{127, 0, 0, 53}}),
|
||||||
)
|
)
|
||||||
DescribeTable("when it does NOT match an IP address",
|
DescribeTable("when it does NOT match an IP address",
|
||||||
func(fqdn string) {
|
func(fqdn string) {
|
||||||
@@ -228,6 +240,10 @@ var _ = Describe("Xip", func() {
|
|||||||
Entry("NS but no dot", "ns-hetzner.sslip.io"),
|
Entry("NS but no dot", "ns-hetzner.sslip.io"),
|
||||||
Entry("NS + cruft at beginning", "p-ns-hetzner.sslip.io"),
|
Entry("NS + cruft at beginning", "p-ns-hetzner.sslip.io"),
|
||||||
Entry("test-net address with dots-and-dashes mixed", "www-192.0-2.3.example-me.com"),
|
Entry("test-net address with dots-and-dashes mixed", "www-192.0-2.3.example-me.com"),
|
||||||
|
Entry("Hexadecimal with too many digits (9 instead of 8)", "www.0A09091E0.com"),
|
||||||
|
Entry("Hexadecimal with too few digits (7 instead of 8)", "www.0A09091.com"),
|
||||||
|
Entry("Hexadecimal with a dash instead of a .", "www-0A09091E.com"),
|
||||||
|
Entry("Hexadecimal with a dash instead of a . #2", "www.0A09091E-com"),
|
||||||
)
|
)
|
||||||
When("There is more than one A record", func() {
|
When("There is more than one A record", func() {
|
||||||
It("returns them all", func() {
|
It("returns them all", func() {
|
||||||
|
Reference in New Issue
Block a user