go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/network/resources/domain/name.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package domain 5 6 import ( 7 "net/url" 8 "strconv" 9 "strings" 10 11 "golang.org/x/net/publicsuffix" 12 ) 13 14 // Domain Names https://datatracker.ietf.org/doc/html/rfc1035 15 // Public Suffix List https://publicsuffix.org 16 // Reserved Top-Level Domains https://datatracker.ietf.org/doc/html/rfc2606 17 18 // Domain embeds net/url and adds extra fields ontop 19 type Name struct { 20 Host string 21 Port int 22 EffectiveTLDPlusOne string 23 TLD string 24 IcannManagedTLD bool 25 Labels []string 26 } 27 28 // Parse mirrors net/url.Parse except instead it returns 29 // a tld.URL, which contains extra fields. 30 func Parse(fqdn string) (Name, error) { 31 // check if fqdn has a scheme otherwise go does not parse the host properly 32 if !strings.Contains(fqdn, "//") { 33 fqdn = "//" + fqdn 34 } 35 36 url, err := url.Parse(fqdn) 37 if err != nil { 38 return Name{}, err 39 } 40 if url.Host == "" { 41 return Name{}, nil 42 } 43 host, port := SplitHostPort(url.Host) 44 45 // effective top-level domain + one label 46 etldplusone, err := publicsuffix.EffectiveTLDPlusOne(host) 47 if err != nil { 48 return Name{}, err 49 } 50 51 suffix, icann := publicsuffix.PublicSuffix(strings.ToLower(host)) 52 if err != nil { 53 return Name{}, err 54 } 55 56 return Name{ 57 Host: host, 58 Port: port, 59 EffectiveTLDPlusOne: etldplusone, 60 TLD: suffix, 61 IcannManagedTLD: icann, 62 Labels: strings.Split(host, "."), 63 }, nil 64 } 65 66 // SplitHostPort separates host and port. If the port is not valid, it returns 67 // the entire input as host, and it doesn't check the validity of the host. 68 // Unlike net.SplitHostPort, but per RFC 3986, it requires ports to be numeric. 69 // NOTE: method is copied from go package url under BSD license 70 func SplitHostPort(hostPort string) (host string, port int) { 71 host = hostPort 72 73 colon := strings.LastIndexByte(host, ':') 74 if colon != -1 && validOptionalPort(host[colon:]) { 75 var sPort string 76 host, sPort = host[:colon], host[colon+1:] 77 port, _ = strconv.Atoi(sPort) 78 } 79 80 if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") { 81 host = host[1 : len(host)-1] 82 } 83 84 return 85 } 86 87 // validOptionalPort reports whether port is either an empty string 88 // or matches /^:\d*$/ 89 // NOTE: method is copied from go package url under BSD license 90 func validOptionalPort(port string) bool { 91 if port == "" { 92 return true 93 } 94 if port[0] != ':' { 95 return false 96 } 97 for _, b := range port[1:] { 98 if b < '0' || b > '9' { 99 return false 100 } 101 } 102 return true 103 }