| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | package reverse
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							| 
									
										
										
										
											2017-02-10 12:48:51 +00:00
										 |  |  | 	"bytes"
 | 
					
						
							| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | 	"net"
 | 
					
						
							|  |  |  | 	"regexp"
 | 
					
						
							|  |  |  | 	"strings"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type network struct {
 | 
					
						
							|  |  |  | 	IPnet        *net.IPNet
 | 
					
						
							| 
									
										
										
										
											2017-02-10 12:48:51 +00:00
										 |  |  | 	Zone         string // forward lookup zone
 | 
					
						
							| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | 	Template     string
 | 
					
						
							|  |  |  | 	TTL          uint32
 | 
					
						
							|  |  |  | 	RegexMatchIP *regexp.Regexp
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-10 12:48:51 +00:00
										 |  |  | // TODO: we might want to get rid of these regexes.
 | 
					
						
							| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | 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})"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-10 12:48:51 +00:00
										 |  |  | // hostnameToIP converts the hostname back to an ip, based on the template
 | 
					
						
							|  |  |  | // returns nil if there is no IP found.
 | 
					
						
							| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | func (network *network) hostnameToIP(rname string) net.IP {
 | 
					
						
							|  |  |  | 	var matchedIP net.IP
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	match := network.RegexMatchIP.FindStringSubmatch(rname)
 | 
					
						
							| 
									
										
										
										
											2017-02-10 12:48:51 +00:00
										 |  |  | 	if len(match) != 2 {
 | 
					
						
							| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | 		return nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if network.IPnet.IP.To4() != nil {
 | 
					
						
							|  |  |  | 		matchedIP = net.ParseIP(strings.Replace(match[1], "-", ".", 4))
 | 
					
						
							|  |  |  | 	} else {
 | 
					
						
							| 
									
										
										
										
											2017-02-10 12:48:51 +00:00
										 |  |  | 		// TODO: can probably just allocate a []byte and use that.
 | 
					
						
							| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | 		var buf bytes.Buffer
 | 
					
						
							|  |  |  | 		// convert back to an valid ipv6 string with colons
 | 
					
						
							| 
									
										
										
										
											2017-02-10 12:48:51 +00:00
										 |  |  | 		for i := 0; i < 8*4; i += 4 {
 | 
					
						
							|  |  |  | 			buf.WriteString(match[1][i : i+4])
 | 
					
						
							|  |  |  | 			if i < 28 {
 | 
					
						
							| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | 				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
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-10 12:48:51 +00:00
										 |  |  | // ipToHostname converts an IP to an DNS compatible hostname and injects it into the template.domain.
 | 
					
						
							|  |  |  | func (network *network) ipToHostname(ip net.IP) (name string) {
 | 
					
						
							|  |  |  | 	if ipv4 := ip.To4(); ipv4 != nil {
 | 
					
						
							| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | 		// replace . to -
 | 
					
						
							|  |  |  | 		name = uitoa(ipv4[0]) + "-" +
 | 
					
						
							|  |  |  | 			uitoa(ipv4[1]) + "-" +
 | 
					
						
							|  |  |  | 			uitoa(ipv4[2]) + "-" +
 | 
					
						
							|  |  |  | 			uitoa(ipv4[3])
 | 
					
						
							|  |  |  | 	} else {
 | 
					
						
							|  |  |  | 		// assume v6
 | 
					
						
							|  |  |  | 		// ensure zeros are present in string
 | 
					
						
							| 
									
										
										
										
											2017-02-10 12:48:51 +00:00
										 |  |  | 		buf := make([]byte, 0, len(ip)*4)
 | 
					
						
							| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | 		for i := 0; i < len(ip); i++ {
 | 
					
						
							|  |  |  | 			v := ip[i]
 | 
					
						
							| 
									
										
										
										
											2017-02-10 12:48:51 +00:00
										 |  |  | 			buf = append(buf, hexDigit[v>>4])
 | 
					
						
							|  |  |  | 			buf = append(buf, hexDigit[v&0xF])
 | 
					
						
							| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | 		}
 | 
					
						
							|  |  |  | 		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
 | 
					
						
							| 
									
										
										
										
											2017-02-10 12:48:51 +00:00
										 |  |  | 		buf[i] = byte('0' + val - q*10)
 | 
					
						
							| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | 		i--
 | 
					
						
							|  |  |  | 		val = q
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	// val < 10
 | 
					
						
							|  |  |  | 	buf[i] = byte('0' + val)
 | 
					
						
							|  |  |  | 	return string(buf[i:])
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type networks []network
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-10 12:48:51 +00:00
										 |  |  | func (n networks) Len() int      { return len(n) }
 | 
					
						
							|  |  |  | func (n networks) Swap(i, j int) { n[i], n[j] = n[j], n[i] }
 | 
					
						
							| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // cidr closer to the ip wins (by netmask)
 | 
					
						
							| 
									
										
										
										
											2017-02-10 12:48:51 +00:00
										 |  |  | func (n networks) Less(i, j int) bool {
 | 
					
						
							|  |  |  | 	isize, _ := n[i].IPnet.Mask.Size()
 | 
					
						
							|  |  |  | 	jsize, _ := n[j].IPnet.Mask.Size()
 | 
					
						
							| 
									
										
										
										
											2017-02-09 20:39:48 +01:00
										 |  |  | 	return isize > jsize
 | 
					
						
							|  |  |  | }
 |