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  }