pdns-auth-proxy/utils.go

200 lines
4.6 KiB
Go
Raw Normal View History

2023-11-17 05:55:06 +00:00
package main
import (
"encoding/json"
"fmt"
"math/big"
"net"
"sort"
"strconv"
"strings"
"github.com/pyke369/golang-support/rcache"
)
func stringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
// inArray checks if there is a member of "search" in "list". sort list to be more
// efficiant. adapt with sorting "search" too
func inArray(search, list []string) bool {
sort.Strings(list)
for _, g := range search {
i := sort.Search(len(list), func(i int) bool { return list[i] >= g })
if i < len(list) && list[i] == g {
return true
}
}
return false
}
// printJSON pretty print d
func printJSON(d interface{}) []byte {
ret, _ := json.MarshalIndent(d, " ", " ")
return ret
}
// reverse the part order on every member of the array
func reverse(s string) string {
part := strings.Split(s, ".")
for i, j := 0, len(part)-1; i < j; i, j = i+1, j-1 {
part[i], part[j] = part[j], part[i]
}
return strings.Join(part, ".")
}
// domainSort sort string by first reversing them
func domainSort(s []string) {
for i := range s {
s[i] = reverse(s[i])
}
sort.Strings(s)
for i := range s {
s[i] = reverse(s[i])
}
}
func ptrToIP(s string) string {
s = reverse(s)
count := 0
ip := ""
version := 4
for _, elt := range strings.Split(s, ".") {
switch elt {
case "":
case "ip6":
version = 6
case "in-addr":
case "arpa":
default:
count++
ip += elt
if version == 4 && count != 4 {
ip += "."
}
if version == 6 && count%4 == 0 && count != 32 {
ip += ":"
}
}
}
return ip
}
func ipToInt(ip string) *big.Int {
return big.NewInt(0).SetBytes([]byte(net.ParseIP(ip)))
}
// iPtoReverse calculate the reverse name associated with an IPv4 or v6
func iPtoReverse(ip net.IP) (arpa string) {
const hexDigit = "0123456789abcdef"
// code copied and adapted from the net library
// ip can be 4 or 16 bytes long
if ip.To4() != nil {
if len(ip) == 16 {
return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." + uitoa(uint(ip[12])) + ".in-addr.arpa."
}
return uitoa(uint(ip[3])) + "." + uitoa(uint(ip[2])) + "." + uitoa(uint(ip[1])) + "." + uitoa(uint(ip[0])) + ".in-addr.arpa."
}
// Must be IPv6
buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
// Add it, in reverse, to the buffer
for i := len(ip) - 1; i >= 0; i-- {
v := ip[i]
buf = append(buf, hexDigit[v&0xF])
buf = append(buf, '.')
buf = append(buf, hexDigit[v>>4])
buf = append(buf, '.')
}
// Append "ip6.arpa." and return (buf already has the final .)
buf = append(buf, "ip6.arpa."...)
return string(buf)
}
// Convert unsigned integer to decimal string.
// code copied from the net library
func uitoa(val uint) 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:])
}
func trimPoint(s string) string {
return strings.TrimRight(s, ".")
}
func addPoint(s string) string {
s = trimPoint(s)
if !strings.HasSuffix(s, ".") && !strings.HasSuffix(s, "*") {
s = s + "."
}
return s
}
// add double quotes at the begining and the end of the string.
func addQuotes(s string) string {
const q = "\""
s = strings.Trim(s, q)
s = strings.Replace(s, q, "\\\"", -1)
return q + s + q
}
func validSRVName(s string) bool {
return rcache.Get("^_[a-z0-9]+\\._(tcp|udp|tls)[^ ]+$").MatchString(s)
}
func validSRV(s string) string {
// _service._proto.name. TTL class SRV priority weight port target.
match := rcache.Get("^([0-9]+) +([0-9]+) +([0-9]+) +(.+)$").FindStringSubmatch(s)
if len(match) > 0 && validName(match[4], false) {
return match[4]
}
return ""
}
func validName(s string, wildcard bool) bool {
if !wildcard {
return rcache.Get(
"^(([a-z0-9]|[a-z0-9_][a-z0-9_\\-]*[a-z0-9])\\.)*([a-z0-9]|[a-z0-9][a-z0-9\\-]*[a-z0-9])\\.$").MatchString(s)
}
return rcache.Get(
"^(\\*\\.)?(([a-z0-9]|[a-z0-9_][a-z0-9_\\-]*[a-z0-9])\\.)*([a-z0-9]|[a-z0-9][a-z0-9\\-]*[a-z0-9])\\.$").MatchString(s)
}
func validMX(s string) string {
match := rcache.Get("^([0-9]+) +(.+)$").FindStringSubmatch(s)
if len(match) > 0 && validName(match[2], false) {
return match[2]
}
return ""
}
func validCAA(s string) string {
match := rcache.Get("^([0-9]+) +(issue|issuewild|iodef) +(.+)$").FindStringSubmatch(s)
if len(match) == 0 {
return ""
}
i, _ := strconv.Atoi(match[1])
if i < 0 || i > 255 {
return ""
}
return fmt.Sprintf("%s %s %s", match[1], match[2], addQuotes(match[3]))
}