github.com/tommi2day/gomodules@v1.13.2-0.20240423190010-b7d55d252a27/dblib/tns_dns.go (about) 1 package dblib 2 3 import ( 4 "fmt" 5 "net" 6 "strings" 7 8 log "github.com/sirupsen/logrus" 9 "github.com/tommi2day/gomodules/netlib" 10 "gopkg.in/ini.v1" 11 ) 12 13 // ServiceEntryType holds host/ip/port of a tns address section 14 type ServiceEntryType struct { 15 Host string 16 IP string 17 Port string 18 Address string 19 } 20 21 // ServiceEntries List of Map of service entries 22 type ServiceEntries []ServiceEntryType 23 24 // IgnoreDNSLookup if true, no oracle-dns lookup is done 25 var IgnoreDNSLookup = false 26 27 // IPv4Only if true, only IPv4 addresses are returned 28 var IPv4Only = true 29 30 // DNSConfig holds the netlib DNS object 31 var DNSConfig *netlib.DNSconfig 32 33 // GetRacAdresses reads racinfo.ini or DNS SRV and returns all IP addresses for given rac 34 func GetRacAdresses(rachost string, racini string) (services ServiceEntries) { 35 if racini != "" { 36 services = getRACAddressesFromRacInfo(rachost, racini) 37 log.Debugf("add %d rac addresses for %s from file %s", len(services), rachost, racini) 38 } 39 if len(services) == 0 { 40 services = getRACAddressesFromDNSSrv(rachost) 41 log.Debugf("add %d rac addresses for %s from DNS SRV records", len(services), rachost) 42 } 43 return 44 } 45 46 // getRACAddressesFromDNSSrv returns a list of RAC IP addresses for given tnshost using DNS SRV lookup 47 // SRV Entry format for rachost=rac.example.com: 48 // _rac._tcp.example.com 10 5 80 racscan.example.com. 49 // _rac._tcp.example.com 10 5 80 rac-vip1.example.com. 50 // _rac._tcp.example.com 10 5 80 rac-vip2.example.com. 51 func getRACAddressesFromDNSSrv(rachost string) (services ServiceEntries) { 52 if IgnoreDNSLookup { 53 log.Infof("DNSSrv: Skip SRV, Ignore DNS is set") 54 return 55 } 56 // check if host contains only digits 57 if netlib.IsValidIP(rachost) { 58 log.Debugf("DNSSrv: %s is an IP address, skip", rachost) 59 return 60 } 61 62 // configure resolver 63 if DNSConfig == nil { 64 // set default resolver 65 DNSConfig = netlib.NewResolver("", 0, false) 66 } 67 // split host and domain 68 domain := "" 69 parts := strings.Split(rachost, ".") 70 host := parts[0] 71 if len(parts) > 1 { 72 domain = strings.Join(parts[1:], ".") 73 } 74 // create SRV record query 75 srvList, err := DNSConfig.LookupSrv(host, domain) 76 if err != nil { 77 log.Warnf("DNSSrv: cannot resolve %s:%s", host, err) 78 return 79 } 80 81 // process returned addresses 82 for _, srv := range srvList { 83 host = srv.Target 84 // delete trailing dot 85 host = strings.TrimSuffix(host, ".") 86 port := srv.Port 87 services = append(services, getServiceList(host, fmt.Sprintf("%v", port))...) 88 } 89 log.Debugf("DNSSrv: Rac %s Add %d adresses", rachost, len(services)) 90 return 91 } 92 93 // getRACAddressesFromRacInfo returns a list of RAC IP addresses from inifile (default: racinfo.ini) 94 func getRACAddressesFromRacInfo(rachost string, filename string) (services ServiceEntries) { 95 cfg, err := ini.InsensitiveLoad(filename) 96 if err != nil { 97 log.Debugf("RacInfo: cannot Read %s:%s", filename, err) 98 return 99 } 100 // all keys are lowwer case 101 entries := cfg.Section(strings.ToLower(rachost)).Keys() 102 if len(entries) == 0 { 103 log.Debugf("RacInfo: no entries for %s in %s", rachost, filename) 104 return 105 } 106 for _, e := range entries { 107 if strings.HasPrefix(strings.ToLower(e.Name()), "vip") || strings.HasPrefix(strings.ToLower(e.Name()), "scan") { 108 a := e.Value() 109 host, port, err := net.SplitHostPort(a) 110 if err != nil { 111 log.Warnf("RacInfo: cannot parse %s:%s", a, err) 112 continue 113 } 114 services = append(services, getServiceList(host, fmt.Sprintf("%v", port))...) 115 } 116 } 117 log.Debugf("RacInfo: Rac %s Add %d adresses", rachost, len(services)) 118 return 119 } 120 121 // getServiceList returns a list of IP addresses for given tnshost and port 122 func getServiceList(host string, port string) (services ServiceEntries) { 123 // configure resolver 124 // configure resolver 125 if DNSConfig == nil { 126 // set default resolver 127 DNSConfig = netlib.NewResolver("", 0, false) 128 } 129 130 // set resolver network ip =ipv4+ipv6 or ip4 only 131 if IPv4Only { 132 DNSConfig.IPv4Only = true 133 } 134 135 ips, err := DNSConfig.LookupIP(host) 136 if err != nil || len(ips) == 0 { 137 if IgnoreDNSLookup { 138 log.Debugf("getServiceList: cannot resolve %s", host) 139 service := ServiceEntryType{Host: host, Port: port, IP: "", Address: fmt.Sprintf("%s:%v", host, port)} 140 services = append(services, service) 141 return 142 } 143 log.Warnf("cannot resolve %s, skipped", host) 144 return 145 } 146 for _, ip := range ips { 147 hostip := ip.String() 148 if IPv4Only && !netlib.IsIPv4(hostip) { 149 log.Debugf("getServiceList: skip non ipv4 %s", hostip) 150 continue 151 } 152 service := ServiceEntryType{Host: host, Port: port} 153 if len(hostip) > 0 { 154 service.IP = hostip 155 service.Address = fmt.Sprintf("%s:%v", hostip, port) 156 } else { 157 service.IP = "" 158 service.Address = fmt.Sprintf("%s:%v", host, port) 159 } 160 services = append(services, service) 161 } 162 log.Debugf("add %d Services for %s:%s", len(services), host, port) 163 return 164 }