github.com/zmap/zlint@v1.1.0/util/fqdn.go (about) 1 /* 2 * ZLint Copyright 2018 Regents of the University of Michigan 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy 6 * of the License at http://www.apache.org/licenses/LICENSE-2.0 7 * 8 * Unless required by applicable law or agreed to in writing, software 9 * distributed under the License is distributed on an "AS IS" BASIS, 10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 11 * implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package util 16 17 import ( 18 "net" 19 "net/url" 20 "strings" 21 22 "github.com/weppos/publicsuffix-go/publicsuffix" 23 zcutil "github.com/zmap/zcrypto/util" 24 "github.com/zmap/zcrypto/x509" 25 ) 26 27 func RemovePrependedQuestionMarks(domain string) string { 28 for strings.HasPrefix(domain, "?.") { 29 domain = domain[2:] 30 } 31 return domain 32 } 33 34 func RemovePrependedWildcard(domain string) string { 35 if strings.HasPrefix(domain, "*.") { 36 domain = domain[2:] 37 } 38 return domain 39 } 40 41 func IsFQDN(domain string) bool { 42 domain = RemovePrependedWildcard(domain) 43 domain = RemovePrependedQuestionMarks(domain) 44 return zcutil.IsURL(domain) 45 } 46 47 func GetAuthority(uri string) string { 48 parsed, err := url.Parse(uri) 49 if err != nil { 50 return "" 51 } 52 if parsed.Opaque != "" { 53 // non-empty Opaque means that there is no authority 54 return "" 55 } 56 if len(uri) < 4 { 57 return "" 58 } 59 // https://tools.ietf.org/html/rfc3986#section-3 60 // The only time an authority is present is if there is a // after the scheme. 61 firstColon := strings.Index(uri, ":") 62 postScheme := uri[firstColon+1:] 63 // After the scheme, there is the hier-part, optionally followed by a query or fragment. 64 if !strings.HasPrefix(postScheme, "//") { 65 // authority is always prefixed by // 66 return "" 67 } 68 for i := 2; i < len(postScheme); i++ { 69 // in the hier-part, the authority is followed by either an absolute path, or the empty string. 70 // So, the authority is terminated by the start of an absolute path (/), the start of a fragment (#) or the start of a query(?) 71 if postScheme[i] == '/' || postScheme[i] == '#' || postScheme[i] == '?' { 72 return postScheme[2:i] 73 } 74 } 75 // Found no absolute path, fragment or query -- so the authority is the only data after the scheme:// 76 return postScheme[2:] 77 } 78 79 func GetHost(auth string) string { 80 begin := strings.Index(auth, "@") 81 if begin == len(auth)-1 { 82 begin = -1 83 } 84 end := strings.Index(auth, ":") 85 if end == -1 { 86 end = len(auth) 87 } 88 if end < begin { 89 return "" 90 } 91 return auth[begin+1 : end] 92 } 93 94 func AuthIsFQDNOrIP(auth string) bool { 95 return IsFQDNOrIP(GetHost(auth)) 96 } 97 98 func IsFQDNOrIP(host string) bool { 99 if IsFQDN(host) { 100 return true 101 } 102 if net.ParseIP(host) != nil { 103 return true 104 } 105 return false 106 } 107 108 func DNSNamesExist(cert *x509.Certificate) bool { 109 if cert.Subject.CommonName == "" && len(cert.DNSNames) == 0 { 110 return false 111 } else { 112 return true 113 } 114 } 115 116 func ICANNPublicSuffixParse(domain string) (*publicsuffix.DomainName, error) { 117 return publicsuffix.ParseFromListWithOptions(publicsuffix.DefaultList, domain, &publicsuffix.FindOptions{IgnorePrivate: true, DefaultRule: publicsuffix.DefaultRule}) 118 } 119 120 func CommonNameIsIP(cert *x509.Certificate) bool { 121 ip := net.ParseIP(cert.Subject.CommonName) 122 if ip == nil { 123 return false 124 } else { 125 return true 126 } 127 }