github.com/teknogeek/dnscontrol/v2@v2.10.1-0.20200227202244-ae299b55ba42/pkg/transform/transform.go (about) 1 package transform 2 3 import ( 4 "fmt" 5 "net" 6 "strings" 7 ) 8 9 // IpConversion describes an IP conversion. 10 type IpConversion struct { 11 Low, High net.IP 12 NewBases []net.IP 13 NewIPs []net.IP 14 } 15 16 func ipToUint(i net.IP) (uint32, error) { 17 parts := i.To4() 18 if parts == nil || len(parts) != 4 { 19 return 0, fmt.Errorf("%s is not an ipv4 address", parts.String()) 20 } 21 r := uint32(parts[0])<<24 | uint32(parts[1])<<16 | uint32(parts[2])<<8 | uint32(parts[3]) 22 return r, nil 23 } 24 25 // UintToIP convert a 32-bit into into a net.IP. 26 func UintToIP(u uint32) net.IP { 27 return net.IPv4( 28 byte((u>>24)&255), 29 byte((u>>16)&255), 30 byte((u>>8)&255), 31 byte((u)&255)) 32 } 33 34 // DecodeTransformTable turns a string-encoded table into a list of conversions. 35 func DecodeTransformTable(transforms string) ([]IpConversion, error) { 36 result := []IpConversion{} 37 rows := strings.Split(transforms, ";") 38 for ri, row := range rows { 39 items := strings.Split(row, "~") 40 if len(items) != 4 { 41 return nil, fmt.Errorf("transform_table rows should have 4 elements. (%v) found in row (%v) of %#v", len(items), ri, transforms) 42 } 43 for i, item := range items { 44 items[i] = strings.TrimSpace(item) 45 } 46 47 con := IpConversion{ 48 Low: net.ParseIP(items[0]), 49 High: net.ParseIP(items[1]), 50 } 51 parseList := func(s string) ([]net.IP, error) { 52 ips := []net.IP{} 53 for _, ip := range strings.Split(s, ",") { 54 55 if ip == "" { 56 continue 57 } 58 addr := net.ParseIP(ip) 59 if addr == nil { 60 return nil, fmt.Errorf("%s is not a valid ip address", ip) 61 } 62 ips = append(ips, addr) 63 } 64 return ips, nil 65 } 66 var err error 67 if con.NewBases, err = parseList(items[2]); err != nil { 68 return nil, err 69 } 70 if con.NewIPs, err = parseList(items[3]); err != nil { 71 return nil, err 72 } 73 74 low, _ := ipToUint(con.Low) 75 high, _ := ipToUint(con.High) 76 if low > high { 77 return nil, fmt.Errorf("transform_table Low should be less than High. row (%v) %v>%v (%v)", ri, con.Low, con.High, transforms) 78 } 79 if len(con.NewBases) > 0 && len(con.NewIPs) > 0 { 80 return nil, fmt.Errorf("transform_table_rows should only specify one of NewBases or NewIPs, Not both") 81 } 82 result = append(result, con) 83 } 84 85 return result, nil 86 } 87 88 // TransformIP transforms a single ip address. If the transform results in multiple new targets, an error will be returned. 89 func TransformIP(address net.IP, transforms []IpConversion) (net.IP, error) { 90 ips, err := TransformIPToList(address, transforms) 91 if err != nil { 92 return nil, err 93 } 94 if len(ips) != 1 { 95 return nil, fmt.Errorf("Expect exactly one ip for TransformIP result. Got: %s", ips) 96 } 97 return ips[0], err 98 } 99 100 // TransformIPToList manipulates an net.IP based on a list of IpConversions. It can potentially expand one ip address into multiple addresses. 101 func TransformIPToList(address net.IP, transforms []IpConversion) ([]net.IP, error) { 102 thisIP, err := ipToUint(address) 103 if err != nil { 104 return nil, err 105 } 106 for _, conv := range transforms { 107 min, err := ipToUint(conv.Low) 108 if err != nil { 109 return nil, err 110 } 111 max, err := ipToUint(conv.High) 112 if err != nil { 113 return nil, err 114 } 115 if (thisIP >= min) && (thisIP <= max) { 116 if len(conv.NewIPs) > 0 { 117 return conv.NewIPs, nil 118 } 119 list := []net.IP{} 120 for _, nb := range conv.NewBases { 121 newbase, err := ipToUint(nb) 122 if err != nil { 123 return nil, err 124 } 125 list = append(list, UintToIP(newbase+(thisIP-min))) 126 } 127 return list, nil 128 } 129 } 130 return []net.IP{address}, nil 131 }