src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

sa1020.go (2378B)


      1 package sa1020
      2 
      3 import (
      4 	"go/constant"
      5 	"net"
      6 	"strconv"
      7 	"strings"
      8 
      9 	"honnef.co/go/tools/analysis/callcheck"
     10 	"honnef.co/go/tools/analysis/lint"
     11 	"honnef.co/go/tools/internal/passes/buildir"
     12 
     13 	"golang.org/x/tools/go/analysis"
     14 )
     15 
     16 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
     17 	Analyzer: &analysis.Analyzer{
     18 		Name:     "SA1020",
     19 		Requires: []*analysis.Analyzer{buildir.Analyzer},
     20 		Run:      callcheck.Analyzer(checkListenAddressRules),
     21 	},
     22 	Doc: &lint.RawDocumentation{
     23 		Title: `Using an invalid host:port pair with a \'net.Listen\'-related function`,
     24 		Text: `Functions such as \'net.Listen\', \'net.ListenTCP\', and similar,
     25 expect a valid network address in the form of host:port. The host, the port,
     26 or both, can be omitted, e.g. \'localhost:8080\', \':8080\' or \':\' are valid
     27 host:port pairs.
     28 See https://pkg.go.dev/net#Listen for the full documentation.`,
     29 		Since:    "2017.1",
     30 		Severity: lint.SeverityError,
     31 		MergeIf:  lint.MergeIfAny,
     32 	},
     33 })
     34 
     35 var Analyzer = SCAnalyzer.Analyzer
     36 
     37 var checkListenAddressRules = map[string]callcheck.Check{
     38 	"net/http.ListenAndServe":    checkValidHostPort(0),
     39 	"net/http.ListenAndServeTLS": checkValidHostPort(0),
     40 }
     41 
     42 func checkValidHostPort(arg int) callcheck.Check {
     43 	return func(call *callcheck.Call) {
     44 		if !ValidHostPort(call.Args[arg].Value) {
     45 			const MsgInvalidHostPort = "invalid port or service name in host:port pair"
     46 			call.Args[arg].Invalid(MsgInvalidHostPort)
     47 		}
     48 	}
     49 }
     50 
     51 func ValidHostPort(v callcheck.Value) bool {
     52 	if k := callcheck.ExtractConstExpectKind(v, constant.String); k != nil {
     53 		s := constant.StringVal(k.Value)
     54 		if s == "" {
     55 			return true
     56 		}
     57 		_, port, err := net.SplitHostPort(s)
     58 		if err != nil {
     59 			return false
     60 		}
     61 		// TODO(dh): check hostname
     62 		if !validatePort(port) {
     63 			return false
     64 		}
     65 	}
     66 	return true
     67 }
     68 
     69 func validateServiceName(s string) bool {
     70 	if len(s) < 1 || len(s) > 15 {
     71 		return false
     72 	}
     73 	if s[0] == '-' || s[len(s)-1] == '-' {
     74 		return false
     75 	}
     76 	if strings.Contains(s, "--") {
     77 		return false
     78 	}
     79 	hasLetter := false
     80 	for _, r := range s {
     81 		if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') {
     82 			hasLetter = true
     83 			continue
     84 		}
     85 		if r >= '0' && r <= '9' {
     86 			continue
     87 		}
     88 		return false
     89 	}
     90 	return hasLetter
     91 }
     92 
     93 func validatePort(s string) bool {
     94 	n, err := strconv.ParseInt(s, 10, 64)
     95 	if err != nil {
     96 		return validateServiceName(s)
     97 	}
     98 	return n >= 0 && n <= 65535
     99 }