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 }