aboutsummaryrefslogtreecommitdiff
path: root/middleware/reverse/network.go
diff options
context:
space:
mode:
Diffstat (limited to 'middleware/reverse/network.go')
-rw-r--r--middleware/reverse/network.go123
1 files changed, 123 insertions, 0 deletions
diff --git a/middleware/reverse/network.go b/middleware/reverse/network.go
new file mode 100644
index 000000000..7f408326b
--- /dev/null
+++ b/middleware/reverse/network.go
@@ -0,0 +1,123 @@
+package reverse
+
+import (
+ "net"
+ "regexp"
+ "bytes"
+ "strings"
+)
+
+type network struct {
+ IPnet *net.IPNet
+ Zone string // forward lookup zone
+ Template string
+ TTL uint32
+ RegexMatchIP *regexp.Regexp
+ Fallthrough bool
+}
+
+const hexDigit = "0123456789abcdef"
+const templateNameIP = "{ip}"
+const regexMatchV4 = "((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\-){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))"
+const regexMatchV6 = "([0-9a-fA-F]{32})"
+
+// For forward lookup
+// converts the hostname back to an ip, based on the template
+// returns nil if there is no ip found
+func (network *network) hostnameToIP(rname string) net.IP {
+ var matchedIP net.IP
+
+ // use precompiled regex by setup
+ match := network.RegexMatchIP.FindStringSubmatch(rname)
+ // regex did not matched
+ if (len(match) != 2) {
+ return nil
+ }
+
+ if network.IPnet.IP.To4() != nil {
+ matchedIP = net.ParseIP(strings.Replace(match[1], "-", ".", 4))
+ } else {
+ var buf bytes.Buffer
+ // convert back to an valid ipv6 string with colons
+ for i := 0; i < 8 * 4; i += 4 {
+ buf.WriteString(match[1][i:i + 4])
+ if (i < 28) {
+ buf.WriteString(":")
+ }
+ }
+ matchedIP = net.ParseIP(buf.String())
+ }
+
+ // No valid ip or it does not belong to this network
+ if matchedIP == nil || !network.IPnet.Contains(matchedIP) {
+ return nil
+ }
+
+ return matchedIP
+}
+
+// For reverse lookup
+// Converts an Ip to an dns compatible hostname and injects it into the template.domain
+func (network *network) ipToHostname(ip net.IP) string {
+ var name string
+
+ ipv4 := ip.To4()
+ if ipv4 != nil {
+ // replace . to -
+ name = uitoa(ipv4[0]) + "-" +
+ uitoa(ipv4[1]) + "-" +
+ uitoa(ipv4[2]) + "-" +
+ uitoa(ipv4[3])
+ } else {
+ // assume v6
+ // ensure zeros are present in string
+ buf := make([]byte, 0, len(ip) * 4)
+ for i := 0; i < len(ip); i++ {
+ v := ip[i]
+ buf = append(buf, hexDigit[v >> 4])
+ buf = append(buf, hexDigit[v & 0xF])
+ }
+ name = string(buf)
+ }
+ // inject the converted ip into the fqdn template
+ return strings.Replace(network.Template, templateNameIP, name, 1)
+}
+
+// just the same from net.ip package, but with uint8
+func uitoa(val uint8) string {
+ if val == 0 {
+ // avoid string allocation
+ return "0"
+ }
+ var buf [20]byte // big enough for 64bit value base 10
+ i := len(buf) - 1
+ for val >= 10 {
+ q := val / 10
+ buf[i] = byte('0' + val - q * 10)
+ i--
+ val = q
+ }
+ // val < 10
+ buf[i] = byte('0' + val)
+ return string(buf[i:])
+}
+
+type networks []network
+
+// implements the sort interface
+func (slice networks) Len() int {
+ return len(slice)
+}
+
+// implements the sort interface
+// cidr closer to the ip wins (by netmask)
+func (slice networks) Less(i, j int) bool {
+ isize, _ := slice[i].IPnet.Mask.Size()
+ jsize, _ := slice[j].IPnet.Mask.Size()
+ return isize > jsize
+}
+
+// implements the sort interface
+func (slice networks) Swap(i, j int) {
+ slice[i], slice[j] = slice[j], slice[i]
+} \ No newline at end of file