github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/staticcheck/sa1020/sa1020.go (about)

     1  package sa1020
     2  
     3  import (
     4  	"go/constant"
     5  	"net"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/amarpal/go-tools/analysis/callcheck"
    10  	"github.com/amarpal/go-tools/analysis/lint"
    11  	"github.com/amarpal/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.Documentation{
    23  		Title:    `Using an invalid host:port pair with a \'net.Listen\'-related function`,
    24  		Since:    "2017.1",
    25  		Severity: lint.SeverityError,
    26  		MergeIf:  lint.MergeIfAny,
    27  	},
    28  })
    29  
    30  var Analyzer = SCAnalyzer.Analyzer
    31  
    32  var checkListenAddressRules = map[string]callcheck.Check{
    33  	"net/http.ListenAndServe":    checkValidHostPort(0),
    34  	"net/http.ListenAndServeTLS": checkValidHostPort(0),
    35  }
    36  
    37  func checkValidHostPort(arg int) callcheck.Check {
    38  	return func(call *callcheck.Call) {
    39  		if !ValidHostPort(call.Args[arg].Value) {
    40  			const MsgInvalidHostPort = "invalid port or service name in host:port pair"
    41  			call.Args[arg].Invalid(MsgInvalidHostPort)
    42  		}
    43  	}
    44  }
    45  
    46  func ValidHostPort(v callcheck.Value) bool {
    47  	if k := callcheck.ExtractConstExpectKind(v, constant.String); k != nil {
    48  		s := constant.StringVal(k.Value)
    49  		if s == "" {
    50  			return true
    51  		}
    52  		_, port, err := net.SplitHostPort(s)
    53  		if err != nil {
    54  			return false
    55  		}
    56  		// TODO(dh): check hostname
    57  		if !validatePort(port) {
    58  			return false
    59  		}
    60  	}
    61  	return true
    62  }
    63  
    64  func validateServiceName(s string) bool {
    65  	if len(s) < 1 || len(s) > 15 {
    66  		return false
    67  	}
    68  	if s[0] == '-' || s[len(s)-1] == '-' {
    69  		return false
    70  	}
    71  	if strings.Contains(s, "--") {
    72  		return false
    73  	}
    74  	hasLetter := false
    75  	for _, r := range s {
    76  		if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') {
    77  			hasLetter = true
    78  			continue
    79  		}
    80  		if r >= '0' && r <= '9' {
    81  			continue
    82  		}
    83  		return false
    84  	}
    85  	return hasLetter
    86  }
    87  
    88  func validatePort(s string) bool {
    89  	n, err := strconv.ParseInt(s, 10, 64)
    90  	if err != nil {
    91  		return validateServiceName(s)
    92  	}
    93  	return n >= 0 && n <= 65535
    94  }