mirror of
https://github.com/Li4n0/revsuit.git
synced 2026-09-26 16:41:53 +08:00
Use golint to normalize the code (#1)
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
name: Go
|
name: Go
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ master,dev ]
|
||||||
paths:
|
paths:
|
||||||
- '**.go'
|
- '**.go'
|
||||||
- 'go.mod'
|
- 'go.mod'
|
||||||
@@ -21,10 +21,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
# Create frontend `dist` folder.
|
|
||||||
#
|
|
||||||
# - name: Create frontend dist folder
|
|
||||||
# run: mkdir frontend/dist/ && touch frontend/dist/1
|
|
||||||
- name: Run golangci-lint
|
- name: Run golangci-lint
|
||||||
uses: golangci/[email protected]
|
uses: golangci/[email protected]
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
linters-settings:
|
||||||
|
nakedret:
|
||||||
|
max-func-lines: 0
|
||||||
|
govet:
|
||||||
|
settings:
|
||||||
|
printf:
|
||||||
|
funcs:
|
||||||
|
- (unknwon.dev/clog/v2).Trace
|
||||||
|
- (unknwon.dev/clog/v2).Info
|
||||||
|
- (unknwon.dev/clog/v2).Warn
|
||||||
|
- (unknwon.dev/clog/v2).Error
|
||||||
|
- (unknwon.dev/clog/v2).ErrorDepth
|
||||||
|
- (unknwon.dev/clog/v2).Fatal
|
||||||
|
- (unknwon.dev/clog/v2).FatalDepth
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable:
|
||||||
|
- deadcode
|
||||||
|
- errcheck
|
||||||
|
- gosimple
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- staticcheck
|
||||||
|
- structcheck
|
||||||
|
- typecheck
|
||||||
|
- unused
|
||||||
|
- varcheck
|
||||||
|
- nakedret
|
||||||
|
- gofmt
|
||||||
|
- rowserrcheck
|
||||||
|
- unconvert
|
||||||
|
- goimports
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
import "math/rand"
|
|
||||||
|
|
||||||
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()"
|
|
||||||
|
|
||||||
func genToken() string {
|
|
||||||
b := make([]byte, 8)
|
|
||||||
for i := range b {
|
|
||||||
b[i] = letterBytes[rand.Intn(len(letterBytes))]
|
|
||||||
}
|
|
||||||
return string(b)
|
|
||||||
}
|
|
||||||
@@ -9,5 +9,5 @@ func InitDB(driver, dsn string) (err error) {
|
|||||||
case "sqlite":
|
case "sqlite":
|
||||||
DB, err = NewSqlite3(dsn)
|
DB, err = NewSqlite3(dsn)
|
||||||
}
|
}
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ func (f *MapField) Scan(data interface{}) error {
|
|||||||
return json.Unmarshal(data.([]byte), f)
|
return json.Unmarshal(data.([]byte), f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type ListField []string
|
type ListField []string
|
||||||
|
|
||||||
func (f ListField) Value() (driver.Value, error) {
|
func (f ListField) Value() (driver.Value, error) {
|
||||||
@@ -24,4 +23,4 @@ func (f ListField) Value() (driver.Value, error) {
|
|||||||
|
|
||||||
func (f *ListField) Scan(data interface{}) error {
|
func (f *ListField) Scan(data interface{}) error {
|
||||||
return json.Unmarshal(data.([]byte), f)
|
return json.Unmarshal(data.([]byte), f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ func Accept(logger Logger) dns.MsgAcceptFunc {
|
|||||||
return func(dh dns.Header) dns.MsgAcceptAction {
|
return func(dh dns.Header) dns.MsgAcceptAction {
|
||||||
// check if request
|
// check if request
|
||||||
if dh.Bits&(1<<15) != 0 {
|
if dh.Bits&(1<<15) != 0 {
|
||||||
log(logger, Ignored, nil, nil, fmt.Sprintf("not a request"))
|
log(logger, Ignored, nil, nil, "not a request")
|
||||||
return dns.MsgIgnore
|
return dns.MsgIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
// check opcode
|
// check opcode
|
||||||
if int(dh.Bits>>11)&0xF != dns.OpcodeQuery {
|
if int(dh.Bits>>11)&0xF != dns.OpcodeQuery {
|
||||||
log(logger, Ignored, nil, nil, fmt.Sprintf("not a query"))
|
log(logger, Ignored, nil, nil, "not a query")
|
||||||
return dns.MsgIgnore
|
return dns.MsgIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ func (s *Server) ServeDNS(w dns.ResponseWriter, req *dns.Msg) {
|
|||||||
|
|
||||||
// Close will close the server.
|
// Close will close the server.
|
||||||
func (s *Server) Close() {
|
func (s *Server) Close() {
|
||||||
defer func() { recover() }()
|
defer func() { recover() }() // nolint:errcheck
|
||||||
close(s.close)
|
close(s.close)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ func (z *Zone) Lookup(name, remoteAddr string, needle ...Type) ([]Set, bool, err
|
|||||||
|
|
||||||
for i := 0; ; i++ {
|
for i := 0; ; i++ {
|
||||||
// get sets
|
// get sets
|
||||||
sets, err := z.Handler(TrimZone(z.Name, name),remoteAddr)
|
sets, err := z.Handler(TrimZone(z.Name, name), remoteAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, errors.Wrap(err, "zone handler error")
|
return nil, false, errors.Wrap(err, "zone handler error")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ func TestZoneLookup(t *testing.T) {
|
|||||||
"ns1.example.com.",
|
"ns1.example.com.",
|
||||||
"ns2.example.com.",
|
"ns2.example.com.",
|
||||||
},
|
},
|
||||||
Handler: func(name,remoteAddr string) ([]Set, error) {
|
Handler: func(name, remoteAddr string) ([]Set, error) {
|
||||||
if name == "error" {
|
if name == "error" {
|
||||||
return nil, io.EOF
|
return nil, io.EOF
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/li4n0/revsuit/internal/record"
|
"github.com/li4n0/revsuit/internal/record"
|
||||||
)
|
)
|
||||||
|
|
||||||
func formatRecordField(r record.Record,fieldFormat string) (content string) {
|
func formatRecordField(r record.Record, fieldFormat string) (content string) {
|
||||||
structType := reflect.ValueOf(r)
|
structType := reflect.ValueOf(r)
|
||||||
for i := 0; i < structType.NumField(); i++ {
|
for i := 0; i < structType.NumField(); i++ {
|
||||||
structField := structType.Type().Field(i)
|
structField := structType.Type().Field(i)
|
||||||
@@ -27,6 +27,6 @@ func formatRecordField(r record.Record,fieldFormat string) (content string) {
|
|||||||
}
|
}
|
||||||
content += fmt.Sprintf(fieldFormat+"\n", strings.ToUpper(fieldName), value)
|
content += fmt.Sprintf(fieldFormat+"\n", strings.ToUpper(fieldName), value)
|
||||||
}
|
}
|
||||||
strings.TrimSuffix(content, "\n")
|
content = strings.TrimSuffix(content, "\n")
|
||||||
return
|
return content
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ type larkElement struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type larkCard struct {
|
type larkCard struct {
|
||||||
Header larkHeader `json:"header"`
|
Header larkHeader `json:"header"`
|
||||||
Elements []larkElement `json:"elements"`
|
Elements []larkElement `json:"elements"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,9 +44,9 @@ func (d *Lark) buildPayload(r record.Record) string {
|
|||||||
payload := larkPayload{
|
payload := larkPayload{
|
||||||
MsgType: "interactive",
|
MsgType: "interactive",
|
||||||
Card: larkCard{
|
Card: larkCard{
|
||||||
Header:larkHeader{
|
Header: larkHeader{
|
||||||
Title: larkText{
|
Title: larkText{
|
||||||
Tag: "plain_text",
|
Tag: "plain_text",
|
||||||
Content: "New Connection",
|
Content: "New Connection",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -55,7 +55,7 @@ func (d *Lark) buildPayload(r record.Record) string {
|
|||||||
Tag: "div",
|
Tag: "div",
|
||||||
Text: larkText{
|
Text: larkText{
|
||||||
Tag: "lark_md",
|
Tag: "lark_md",
|
||||||
Content: formatRecordField(r,"**%s**: %v"),
|
Content: formatRecordField(r, "**%s**: %v"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ type slackBlock struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type slackAttachments struct {
|
type slackAttachments struct {
|
||||||
Color string `json:"color"`
|
Color string `json:"color"`
|
||||||
Blocks []slackBlock `json:"blocks"`
|
Blocks []slackBlock `json:"blocks"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func get(url string) (b []byte, err error) {
|
|||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
b, err = ioutil.ReadAll(resp.Body)
|
b, err = ioutil.ReadAll(resp.Body)
|
||||||
return
|
return b, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getKey(b []byte) (key uint32, err error) {
|
func getKey(b []byte) (key uint32, err error) {
|
||||||
@@ -43,7 +43,7 @@ func getKey(b []byte) (key uint32, err error) {
|
|||||||
return 0, errors.New("copywrite.rar is corrupt")
|
return 0, errors.New("copywrite.rar is corrupt")
|
||||||
}
|
}
|
||||||
key = binary.LittleEndian.Uint32(b[20:])
|
key = binary.LittleEndian.Uint32(b[20:])
|
||||||
return
|
return key, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func decrypt(b []byte, key uint32) (_ []byte, err error) {
|
func decrypt(b []byte, key uint32) (_ []byte, err error) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func init() {
|
|||||||
log.Error("Download qqwry.dat failed, caused by:%v, recommend to download it by yourself otherwise the `IpArea` will be null", err.Error())
|
log.Error("Download qqwry.dat failed, caused by:%v, recommend to download it by yourself otherwise the `IpArea` will be null", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if info.ModTime().Sub(time.Now()) > 5*24*time.Hour {
|
} else if time.Until(info.ModTime()) > 5*24*time.Hour {
|
||||||
log.Info("Updating qqwry.dat...")
|
log.Info("Updating qqwry.dat...")
|
||||||
err := download()
|
err := download()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -61,5 +61,5 @@ func (br BaseRule) Match(s string) (flag, flagGroup string) {
|
|||||||
flagGroup = matched[1]
|
flagGroup = matched[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return flag, flagGroup
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Enable bool
|
Enable bool
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ func newRecord(rule *Rule, flag, domain, remoteIp, ipArea string) (r *Record, er
|
|||||||
Rule: *rule,
|
Rule: *rule,
|
||||||
}
|
}
|
||||||
err = database.DB.Create(r).Error
|
err = database.DB.Create(r).Error
|
||||||
return
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func List(c *gin.Context) {
|
func List(c *gin.Context) {
|
||||||
|
|||||||
+2
-3
@@ -59,7 +59,7 @@ func (r *Rule) CreateOrUpdate() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = GetServer().updateRules()
|
err = GetServer().updateRules()
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the dns rule in database and ruleSet
|
// Delete the dns rule in database and ruleSet
|
||||||
@@ -70,7 +70,7 @@ func (r *Rule) Delete() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = GetServer().updateRules()
|
err = GetServer().updateRules()
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// List all dns rules those satisfy the filter
|
// List all dns rules those satisfy the filter
|
||||||
@@ -194,5 +194,4 @@ func DeleteRules(c *gin.Context) {
|
|||||||
"error": nil,
|
"error": nil,
|
||||||
"data": nil,
|
"data": nil,
|
||||||
})
|
})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
package mysql
|
package mysql
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Enable bool
|
Enable bool
|
||||||
Addr string
|
Addr string
|
||||||
VersionString string `yaml:"version_string"`
|
VersionString string `yaml:"version_string"`
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -227,7 +227,7 @@ func (s *Server) ComQuery(c *vmysql.Conn, query string, callback func(*sqltypes.
|
|||||||
if c.Files[filename] == nil {
|
if c.Files[filename] == nil {
|
||||||
log.Trace("MySQL now try to read file [%s], ID [%d]", filename, c.ConnectionID)
|
log.Trace("MySQL now try to read file [%s], ID [%d]", filename, c.ConnectionID)
|
||||||
data := c.RequestFile(filename)
|
data := c.RequestFile(filename)
|
||||||
if data == nil || len(data) == 0 {
|
if len(data) == 0 {
|
||||||
log.Trace("MySQL file [%s] read failed, file may not exist in client [%d]", filename, c.ConnectionID)
|
log.Trace("MySQL file [%s] read failed, file may not exist in client [%d]", filename, c.ConnectionID)
|
||||||
c.Files[filename] = []byte{}
|
c.Files[filename] = []byte{}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -13,5 +13,6 @@ func TestServer_NewConnection(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
db.Exec("SELECT 1;")
|
|
||||||
|
_, _ = db.Exec("SELECT 1;")
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-8
@@ -14,13 +14,12 @@ var _ record.Record = (*Record)(nil)
|
|||||||
|
|
||||||
type Record struct {
|
type Record struct {
|
||||||
record.BaseRecord
|
record.BaseRecord
|
||||||
Username string `gorm:"index",form:"username" json:"username" notice:"username"`
|
Username string `gorm:"index" form:"username" json:"username" notice:"username"`
|
||||||
ClientName string `gorm:"index",form:"client_name" json:"client_name" notice:"client_name"`
|
ClientName string `gorm:"index" form:"client_name" json:"client_name" notice:"client_name"`
|
||||||
ClientOS string `gorm:"index",form:"client_os" json:"client_os" notice:"client_os"`
|
ClientOS string `gorm:"index" form:"client_os" json:"client_os" notice:"client_os"`
|
||||||
LoadLocalData bool `gorm:"index",form:"load_local_data" json:"load_local_data" notice:"load_local_data"`
|
LoadLocalData bool `gorm:"index" form:"load_local_data" json:"load_local_data" notice:"load_local_data"`
|
||||||
//FileID uint `form:"file_id" json:"file_id" notice:"file_id"`
|
Files []File `form:"-" json:"files" notice:"-"`
|
||||||
Files []File `form:"-" json:"files" notice:"-"`
|
Rule Rule `gorm:"foreignKey:RuleName;references:Name;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" form:"-" json:"-" notice:"-"`
|
||||||
Rule Rule `gorm:"foreignKey:RuleName;references:Name;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" form:"-" json:"-" notice:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Record) TableName() string {
|
func (Record) TableName() string {
|
||||||
@@ -47,7 +46,7 @@ func newRecord(rule *Rule, flag, username, clientName, clientOS, remoteIp, ipAre
|
|||||||
Rule: *rule,
|
Rule: *rule,
|
||||||
}
|
}
|
||||||
err = database.DB.Create(r).Error
|
err = database.DB.Create(r).Error
|
||||||
return
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func List(c *gin.Context) {
|
func List(c *gin.Context) {
|
||||||
|
|||||||
+3
-4
@@ -14,7 +14,7 @@ type Rule struct {
|
|||||||
rule.BaseRule
|
rule.BaseRule
|
||||||
Files string `form:"files" json:"files"`
|
Files string `form:"files" json:"files"`
|
||||||
ExploitJdbcClient bool `gorm:"exploit_jdbc_client" form:"exploit_jdbc_client" json:"exploit_jdbc_client"`
|
ExploitJdbcClient bool `gorm:"exploit_jdbc_client" form:"exploit_jdbc_client" json:"exploit_jdbc_client"`
|
||||||
Payloads database.MapField `json:"payloads" json:"payloads"`
|
Payloads database.MapField `json:"payloads" form:"payloads"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Rule) TableName() string {
|
func (Rule) TableName() string {
|
||||||
@@ -42,7 +42,7 @@ func (r *Rule) CreateOrUpdate() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = GetServer().updateRules()
|
err = GetServer().updateRules()
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the mysql rule in database and ruleSet
|
// Delete the mysql rule in database and ruleSet
|
||||||
@@ -53,7 +53,7 @@ func (r *Rule) Delete() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = GetServer().updateRules()
|
err = GetServer().updateRules()
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// List all mysql rules those satisfy the filter
|
// List all mysql rules those satisfy the filter
|
||||||
@@ -176,5 +176,4 @@ func DeleteRules(c *gin.Context) {
|
|||||||
"error": nil,
|
"error": nil,
|
||||||
"data": nil,
|
"data": nil,
|
||||||
})
|
})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,18 +117,18 @@ func ScramblePassword(salt, password []byte) []byte {
|
|||||||
|
|
||||||
// stage1Hash = SHA1(password)
|
// stage1Hash = SHA1(password)
|
||||||
crypt := sha1.New()
|
crypt := sha1.New()
|
||||||
crypt.Write(password)
|
_, _ = crypt.Write(password)
|
||||||
stage1 := crypt.Sum(nil)
|
stage1 := crypt.Sum(nil)
|
||||||
|
|
||||||
// scrambleHash = SHA1(salt + SHA1(stage1Hash))
|
// scrambleHash = SHA1(salt + SHA1(stage1Hash))
|
||||||
// inner Hash
|
// inner Hash
|
||||||
crypt.Reset()
|
crypt.Reset()
|
||||||
crypt.Write(stage1)
|
_, _ = crypt.Write(stage1)
|
||||||
hash := crypt.Sum(nil)
|
hash := crypt.Sum(nil)
|
||||||
// outer Hash
|
// outer Hash
|
||||||
crypt.Reset()
|
crypt.Reset()
|
||||||
crypt.Write(salt)
|
_, _ = crypt.Write(salt)
|
||||||
crypt.Write(hash)
|
_, _ = crypt.Write(hash)
|
||||||
scramble := crypt.Sum(nil)
|
scramble := crypt.Sum(nil)
|
||||||
|
|
||||||
// token = scrambleHash XOR stage1Hash
|
// token = scrambleHash XOR stage1Hash
|
||||||
@@ -164,8 +164,8 @@ func isPassScrambleMysqlNativePassword(reply, salt []byte, mysqlNativePassword s
|
|||||||
|
|
||||||
// scramble = SHA1(salt+hash)
|
// scramble = SHA1(salt+hash)
|
||||||
crypt := sha1.New()
|
crypt := sha1.New()
|
||||||
crypt.Write(salt)
|
_, _ = crypt.Write(salt)
|
||||||
crypt.Write(hash)
|
_, _ = crypt.Write(hash)
|
||||||
scramble := crypt.Sum(nil)
|
scramble := crypt.Sum(nil)
|
||||||
|
|
||||||
// token = scramble XOR stage1Hash
|
// token = scramble XOR stage1Hash
|
||||||
@@ -175,7 +175,7 @@ func isPassScrambleMysqlNativePassword(reply, salt []byte, mysqlNativePassword s
|
|||||||
hashStage1 := scramble
|
hashStage1 := scramble
|
||||||
|
|
||||||
crypt.Reset()
|
crypt.Reset()
|
||||||
crypt.Write(hashStage1)
|
_, _ = crypt.Write(hashStage1)
|
||||||
candidateHash2 := crypt.Sum(nil)
|
candidateHash2 := crypt.Sum(nil)
|
||||||
|
|
||||||
return bytes.Equal(candidateHash2, hash)
|
return bytes.Equal(candidateHash2, hash)
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ limitations under the License.
|
|||||||
package vmysql
|
package vmysql
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
querypb "vitess.io/vitess/go/vt/proto/query"
|
querypb "vitess.io/vitess/go/vt/proto/query"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AuthServerNone takes all comers.
|
// AuthServerNone takes all comers.
|
||||||
@@ -32,27 +32,27 @@ type AuthServerNone struct{}
|
|||||||
// AuthMethod is part of the AuthServer interface.
|
// AuthMethod is part of the AuthServer interface.
|
||||||
// We always return MysqlNativePassword.
|
// We always return MysqlNativePassword.
|
||||||
func (a *AuthServerNone) AuthMethod(user string) (string, error) {
|
func (a *AuthServerNone) AuthMethod(user string) (string, error) {
|
||||||
return MysqlNativePassword, nil
|
return MysqlNativePassword, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Salt makes salt
|
// Salt makes salt
|
||||||
func (a *AuthServerNone) Salt() ([]byte, error) {
|
func (a *AuthServerNone) Salt() ([]byte, error) {
|
||||||
return NewSalt()
|
return NewSalt()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateHash validates hash
|
// ValidateHash validates hash
|
||||||
func (a *AuthServerNone) ValidateHash(salt []byte, user string, authResponse []byte, remoteAddr net.Addr) (Getter, error) {
|
func (a *AuthServerNone) ValidateHash(salt []byte, user string, authResponse []byte, remoteAddr net.Addr) (Getter, error) {
|
||||||
return &NoneGetter{}, nil
|
return &NoneGetter{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Negotiate is part of the AuthServer interface.
|
// Negotiate is part of the AuthServer interface.
|
||||||
// It will never be called.
|
// It will never be called.
|
||||||
func (a *AuthServerNone) Negotiate(c *Conn, user string, remotAddr net.Addr) (Getter, error) {
|
func (a *AuthServerNone) Negotiate(c *Conn, user string, remotAddr net.Addr) (Getter, error) {
|
||||||
panic("Negotiate should not be called as AuthMethod returned mysql_native_password")
|
panic("Negotiate should not be called as AuthMethod returned mysql_native_password")
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
RegisterAuthServerImpl("none", &AuthServerNone{})
|
RegisterAuthServerImpl("none", &AuthServerNone{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoneGetter holds the empty string
|
// NoneGetter holds the empty string
|
||||||
@@ -60,5 +60,5 @@ type NoneGetter struct{}
|
|||||||
|
|
||||||
// Get returns the empty string
|
// Get returns the empty string
|
||||||
func (ng *NoneGetter) Get() *querypb.VTGateCallerID {
|
func (ng *NoneGetter) Get() *querypb.VTGateCallerID {
|
||||||
return &querypb.VTGateCallerID{Username: "userData1"}
|
return &querypb.VTGateCallerID{Username: "userData1"}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,142 +17,135 @@ limitations under the License.
|
|||||||
package vmysql
|
package vmysql
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"flag"
|
"net"
|
||||||
"net"
|
"sync"
|
||||||
"sync"
|
|
||||||
|
|
||||||
querypb "vitess.io/vitess/go/vt/proto/query"
|
querypb "vitess.io/vitess/go/vt/proto/query"
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
mysqlAuthServerStaticFile = flag.String("mysql_auth_server_static_file", "", "JSON File to read the users/passwords from.")
|
|
||||||
mysqlAuthServerStaticString = flag.String("mysql_auth_server_static_string", "", "JSON representation of the users/passwords config.")
|
|
||||||
mysqlAuthServerStaticReloadInterval = flag.Duration("mysql_auth_static_reload_interval", 0, "Ticker to reload credentials")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
localhostName = "localhost"
|
localhostName = "localhost"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AuthServerStatic implements AuthServer using a static configuration.
|
// AuthServerStatic implements AuthServer using a static configuration.
|
||||||
type AuthServerStatic struct {
|
type AuthServerStatic struct {
|
||||||
// Method can be set to:
|
// Method can be set to:
|
||||||
// - MysqlNativePassword
|
// - MysqlNativePassword
|
||||||
// - MysqlClearPassword
|
// - MysqlClearPassword
|
||||||
// - MysqlDialog
|
// - MysqlDialog
|
||||||
// It defaults to MysqlNativePassword.
|
// It defaults to MysqlNativePassword.
|
||||||
Method string
|
Method string
|
||||||
// This mutex helps us prevent data races between the multiple updates of Entries.
|
// This mutex helps us prevent data races between the multiple updates of Entries.
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
// Entries contains the users, passwords and user data.
|
// Entries contains the users, passwords and user data.
|
||||||
Entries map[string][]*AuthServerStaticEntry
|
Entries map[string][]*AuthServerStaticEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthServerStaticEntry stores the values for a given user.
|
// AuthServerStaticEntry stores the values for a given user.
|
||||||
type AuthServerStaticEntry struct {
|
type AuthServerStaticEntry struct {
|
||||||
// MysqlNativePassword is generated by password hashing methods in MySQL.
|
// MysqlNativePassword is generated by password hashing methods in MySQL.
|
||||||
// These changes are illustrated by changes in the result from the PASSWORD() function
|
// These changes are illustrated by changes in the result from the PASSWORD() function
|
||||||
// that computes password hash values and in the structure of the user table where passwords are stored.
|
// that computes password hash values and in the structure of the user table where passwords are stored.
|
||||||
// mysql> SELECT PASSWORD('mypass');
|
// mysql> SELECT PASSWORD('mypass');
|
||||||
// +-------------------------------------------+
|
// +-------------------------------------------+
|
||||||
// | PASSWORD('mypass') |
|
// | PASSWORD('mypass') |
|
||||||
// +-------------------------------------------+
|
// +-------------------------------------------+
|
||||||
// | *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 |
|
// | *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 |
|
||||||
// +-------------------------------------------+
|
// +-------------------------------------------+
|
||||||
// MysqlNativePassword's format looks like "*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4", it store a hashing value.
|
// MysqlNativePassword's format looks like "*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4", it store a hashing value.
|
||||||
// Use MysqlNativePassword in auth config, maybe more secure. After all, it is cryptographic storage.
|
// Use MysqlNativePassword in auth config, maybe more secure. After all, it is cryptographic storage.
|
||||||
MysqlNativePassword string
|
MysqlNativePassword string
|
||||||
Password string
|
Password string
|
||||||
UserData string
|
UserData string
|
||||||
SourceHost string
|
SourceHost string
|
||||||
Groups []string
|
Groups []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthMethod is part of the AuthServer interface.
|
// AuthMethod is part of the AuthServer interface.
|
||||||
func (a *AuthServerStatic) AuthMethod(user string) (string, error) {
|
func (a *AuthServerStatic) AuthMethod(user string) (string, error) {
|
||||||
return a.Method, nil
|
return a.Method, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Salt is part of the AuthServer interface.
|
// Salt is part of the AuthServer interface.
|
||||||
func (a *AuthServerStatic) Salt() ([]byte, error) {
|
func (a *AuthServerStatic) Salt() ([]byte, error) {
|
||||||
return NewSalt()
|
return NewSalt()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateHash is part of the AuthServer interface.
|
// ValidateHash is part of the AuthServer interface.
|
||||||
func (a *AuthServerStatic) ValidateHash(salt []byte, user string, authResponse []byte, remoteAddr net.Addr) (Getter, error) {
|
func (a *AuthServerStatic) ValidateHash(salt []byte, user string, authResponse []byte, remoteAddr net.Addr) (Getter, error) {
|
||||||
a.mu.Lock()
|
a.mu.Lock()
|
||||||
entries, ok := a.Entries[user]
|
entries, ok := a.Entries[user]
|
||||||
a.mu.Unlock()
|
a.mu.Unlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if entry.MysqlNativePassword != "" {
|
if entry.MysqlNativePassword != "" {
|
||||||
isPass := isPassScrambleMysqlNativePassword(authResponse, salt, entry.MysqlNativePassword)
|
isPass := isPassScrambleMysqlNativePassword(authResponse, salt, entry.MysqlNativePassword)
|
||||||
if matchSourceHost(remoteAddr, entry.SourceHost) && isPass {
|
if matchSourceHost(remoteAddr, entry.SourceHost) && isPass {
|
||||||
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
computedAuthResponse := ScramblePassword(salt, []byte(entry.Password))
|
computedAuthResponse := ScramblePassword(salt, []byte(entry.Password))
|
||||||
// Validate the password.
|
// Validate the password.
|
||||||
if matchSourceHost(remoteAddr, entry.SourceHost) && bytes.Equal(authResponse, computedAuthResponse) {
|
if matchSourceHost(remoteAddr, entry.SourceHost) && bytes.Equal(authResponse, computedAuthResponse) {
|
||||||
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Negotiate is part of the AuthServer interface.
|
// Negotiate is part of the AuthServer interface.
|
||||||
// It will be called if Method is anything else than MysqlNativePassword.
|
// It will be called if Method is anything else than MysqlNativePassword.
|
||||||
// We only recognize MysqlClearPassword and MysqlDialog here.
|
// We only recognize MysqlClearPassword and MysqlDialog here.
|
||||||
func (a *AuthServerStatic) Negotiate(c *Conn, user string, remoteAddr net.Addr) (Getter, error) {
|
func (a *AuthServerStatic) Negotiate(c *Conn, user string, remoteAddr net.Addr) (Getter, error) {
|
||||||
// Finish the negotiation.
|
// Finish the negotiation.
|
||||||
password, err := AuthServerNegotiateClearOrDialog(c, a.Method)
|
password, err := AuthServerNegotiateClearOrDialog(c, a.Method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
a.mu.Lock()
|
a.mu.Lock()
|
||||||
entries, ok := a.Entries[user]
|
entries, ok := a.Entries[user]
|
||||||
a.mu.Unlock()
|
a.mu.Unlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||||
}
|
}
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
// Validate the password.
|
// Validate the password.
|
||||||
if matchSourceHost(remoteAddr, entry.SourceHost) && entry.Password == password {
|
if matchSourceHost(remoteAddr, entry.SourceHost) && entry.Password == password {
|
||||||
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchSourceHost(remoteAddr net.Addr, targetSourceHost string) bool {
|
func matchSourceHost(remoteAddr net.Addr, targetSourceHost string) bool {
|
||||||
// Legacy support, there was not matcher defined default to true
|
// Legacy support, there was not matcher defined default to true
|
||||||
if targetSourceHost == "" {
|
if targetSourceHost == "" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
switch remoteAddr.(type) {
|
switch remoteAddr.(type) {
|
||||||
case *net.UnixAddr:
|
case *net.UnixAddr:
|
||||||
if targetSourceHost == localhostName {
|
if targetSourceHost == localhostName {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// StaticUserData holds the username and groups
|
// StaticUserData holds the username and groups
|
||||||
type StaticUserData struct {
|
type StaticUserData struct {
|
||||||
username string
|
username string
|
||||||
groups []string
|
groups []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the wrapped username and groups
|
// Get returns the wrapped username and groups
|
||||||
func (sud *StaticUserData) Get() *querypb.VTGateCallerID {
|
func (sud *StaticUserData) Get() *querypb.VTGateCallerID {
|
||||||
return &querypb.VTGateCallerID{Username: sud.username, Groups: sud.groups}
|
return &querypb.VTGateCallerID{Username: sud.username, Groups: sud.groups}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,13 +137,6 @@ type Conn struct {
|
|||||||
bufferedWriter *bufio.Writer
|
bufferedWriter *bufio.Writer
|
||||||
sequence uint8
|
sequence uint8
|
||||||
|
|
||||||
// fields contains the fields definitions for an on-going
|
|
||||||
// streaming query. It is set by ExecuteStreamFetch, and
|
|
||||||
// cleared by the last FetchNext(). It is nil if no streaming
|
|
||||||
// query is in progress. If the streaming query returned no
|
|
||||||
// fields, this is set to an empty array (but not nil).
|
|
||||||
fields []*querypb.Field
|
|
||||||
|
|
||||||
// Keep track of how and of the buffer we allocated for an
|
// Keep track of how and of the buffer we allocated for an
|
||||||
// ephemeral packet on the read and write sides.
|
// ephemeral packet on the read and write sides.
|
||||||
// These fields are used by:
|
// These fields are used by:
|
||||||
@@ -246,7 +239,7 @@ func (c *Conn) readHeaderFrom(r io.Reader) (int, error) {
|
|||||||
return 0, vterrors.Wrapf(err, "io.ReadFull(header size) failed")
|
return 0, vterrors.Wrapf(err, "io.ReadFull(header size) failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
sequence := uint8(header[3])
|
sequence := header[3]
|
||||||
if sequence != c.sequence {
|
if sequence != c.sequence {
|
||||||
return 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid sequence, expected %v got %v", c.sequence, sequence)
|
return 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid sequence, expected %v got %v", c.sequence, sequence)
|
||||||
}
|
}
|
||||||
@@ -429,30 +422,6 @@ func (c *Conn) readOnePacket() ([]byte, error) {
|
|||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) readOnePacketIgnoreSeq() ([]byte, error) {
|
|
||||||
r := c.getReader()
|
|
||||||
|
|
||||||
var header [4]byte
|
|
||||||
if _, err := io.ReadFull(r, header[:]); err != nil {
|
|
||||||
fmt.Println(fmt.Sprintf("Unexpected error, %s", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
length := int(uint32(header[0]) | uint32(header[1])<<8 | uint32(header[2])<<16)
|
|
||||||
c.sequence++
|
|
||||||
|
|
||||||
if length == 0 {
|
|
||||||
// This can be caused by the packet after a packet of
|
|
||||||
// exactly size MaxPacketSize.
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
data := make([]byte, length)
|
|
||||||
if _, err := io.ReadFull(r, data); err != nil {
|
|
||||||
return nil, vterrors.Wrapf(err, "io.ReadFull(packet body of length %v) failed", length)
|
|
||||||
}
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// readPacket reads a packet from the underlying connection.
|
// readPacket reads a packet from the underlying connection.
|
||||||
// It re-assembles packets that span more than one message.
|
// It re-assembles packets that span more than one message.
|
||||||
// This method returns a generic error, not a SQLError.
|
// This method returns a generic error, not a SQLError.
|
||||||
@@ -606,22 +575,6 @@ func (c *Conn) recycleWritePacket() {
|
|||||||
c.currentEphemeralPolicy = ephemeralUnused
|
c.currentEphemeralPolicy = ephemeralUnused
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeComQuit writes a Quit message for the server, to indicate we
|
|
||||||
// want to close the connection.
|
|
||||||
// Client -> Server.
|
|
||||||
// Returns SQLError(CRServerGone) if it can't.
|
|
||||||
func (c *Conn) writeComQuit() error {
|
|
||||||
// This is a new command, need to reset the sequence.
|
|
||||||
c.sequence = 0
|
|
||||||
|
|
||||||
data := c.startEphemeralPacket(1)
|
|
||||||
data[0] = ComQuit
|
|
||||||
if err := c.writeEphemeralPacket(); err != nil {
|
|
||||||
return NewSQLError(CRServerGone, SSUnknownSQLState, err.Error())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteAddr returns the underlying socket RemoteAddr().
|
// RemoteAddr returns the underlying socket RemoteAddr().
|
||||||
func (c *Conn) RemoteAddr() net.Addr {
|
func (c *Conn) RemoteAddr() net.Addr {
|
||||||
return c.conn.RemoteAddr()
|
return c.conn.RemoteAddr()
|
||||||
@@ -937,7 +890,7 @@ func (c *Conn) RequestFile(filename string) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) WriteErrorResponse(error string) {
|
func (c *Conn) WriteErrorResponse(error string) {
|
||||||
c.writeErrorPacketFromError(NewSQLError(ERParseError, "42000", error))
|
_ = c.writeErrorPacketFromError(NewSQLError(ERParseError, "42000", error))
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -18,43 +18,43 @@ package vmysql
|
|||||||
|
|
||||||
// ConnParams contains all the parameters to use to connect to mysql.
|
// ConnParams contains all the parameters to use to connect to mysql.
|
||||||
type ConnParams struct {
|
type ConnParams struct {
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
Port int `json:"port"`
|
Port int `json:"port"`
|
||||||
Uname string `json:"uname"`
|
Uname string `json:"uname"`
|
||||||
Pass string `json:"pass"`
|
Pass string `json:"pass"`
|
||||||
DbName string `json:"dbname"`
|
DbName string `json:"dbname"`
|
||||||
UnixSocket string `json:"unix_socket"`
|
UnixSocket string `json:"unix_socket"`
|
||||||
Charset string `json:"charset"`
|
Charset string `json:"charset"`
|
||||||
Flags uint64 `json:"flags"`
|
Flags uint64 `json:"flags"`
|
||||||
|
|
||||||
// The following SSL flags are only used when flags |= 2048
|
// The following SSL flags are only used when flags |= 2048
|
||||||
// is set (CapabilityClientSSL).
|
// is set (CapabilityClientSSL).
|
||||||
SslCa string `json:"ssl_ca"`
|
SslCa string `json:"ssl_ca"`
|
||||||
SslCaPath string `json:"ssl_ca_path"`
|
SslCaPath string `json:"ssl_ca_path"`
|
||||||
SslCert string `json:"ssl_cert"`
|
SslCert string `json:"ssl_cert"`
|
||||||
SslKey string `json:"ssl_key"`
|
SslKey string `json:"ssl_key"`
|
||||||
ServerName string `json:"server_name"`
|
ServerName string `json:"server_name"`
|
||||||
|
|
||||||
// The following is only set when the deprecated "dbname" flags are
|
// The following is only set when the deprecated "dbname" flags are
|
||||||
// supplied and will be removed.
|
// supplied and will be removed.
|
||||||
DeprecatedDBName string
|
DeprecatedDBName string
|
||||||
|
|
||||||
// The following is only set to force the client to connect without
|
// The following is only set to force the client to connect without
|
||||||
// using CapabilityClientDeprecateEOF
|
// using CapabilityClientDeprecateEOF
|
||||||
DisableClientDeprecateEOF bool
|
DisableClientDeprecateEOF bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableSSL will set the right flag on the parameters.
|
// EnableSSL will set the right flag on the parameters.
|
||||||
func (cp *ConnParams) EnableSSL() {
|
func (cp *ConnParams) EnableSSL() {
|
||||||
cp.Flags |= CapabilityClientSSL
|
cp.Flags |= CapabilityClientSSL
|
||||||
}
|
}
|
||||||
|
|
||||||
// SslEnabled returns if SSL is enabled.
|
// SslEnabled returns if SSL is enabled.
|
||||||
func (cp *ConnParams) SslEnabled() bool {
|
func (cp *ConnParams) SslEnabled() bool {
|
||||||
return (cp.Flags & CapabilityClientSSL) > 0
|
return (cp.Flags & CapabilityClientSSL) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableClientFoundRows sets the flag for CLIENT_FOUND_ROWS.
|
// EnableClientFoundRows sets the flag for CLIENT_FOUND_ROWS.
|
||||||
func (cp *ConnParams) EnableClientFoundRows() {
|
func (cp *ConnParams) EnableClientFoundRows() {
|
||||||
cp.Flags |= CapabilityClientFoundRows
|
cp.Flags |= CapabilityClientFoundRows
|
||||||
}
|
}
|
||||||
|
|||||||
+187
-195
@@ -17,193 +17,189 @@ limitations under the License.
|
|||||||
package vmysql
|
package vmysql
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// MaxPacketSize is the maximum payload length of a packet
|
// MaxPacketSize is the maximum payload length of a packet
|
||||||
// the server supports.
|
// the server supports.
|
||||||
MaxPacketSize = (1 << 24) - 1
|
MaxPacketSize = (1 << 24) - 1
|
||||||
|
|
||||||
// protocolVersion is the current version of the protocol.
|
// protocolVersion is the current version of the protocol.
|
||||||
// Always 10.
|
// Always 10.
|
||||||
protocolVersion = 10
|
protocolVersion = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
// Supported auth forms.
|
// Supported auth forms.
|
||||||
const (
|
const (
|
||||||
// MysqlNativePassword uses a salt and transmits a hash on the wire.
|
// MysqlNativePassword uses a salt and transmits a hash on the wire.
|
||||||
MysqlNativePassword = "mysql_native_password"
|
MysqlNativePassword = "mysql_native_password"
|
||||||
|
|
||||||
// MysqlClearPassword transmits the password in the clear.
|
// MysqlClearPassword transmits the password in the clear.
|
||||||
MysqlClearPassword = "mysql_clear_password"
|
MysqlClearPassword = "mysql_clear_password"
|
||||||
|
|
||||||
// MysqlDialog uses the dialog plugin on the client side.
|
// MysqlDialog uses the dialog plugin on the client side.
|
||||||
// It transmits data in the clear.
|
// It transmits data in the clear.
|
||||||
MysqlDialog = "dialog"
|
MysqlDialog = "dialog"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Capability flags.
|
// Capability flags.
|
||||||
// Originally found in include/mysql/mysql_com.h
|
// Originally found in include/mysql/mysql_com.h
|
||||||
const (
|
const (
|
||||||
// CapabilityClientLongPassword is CLIENT_LONG_PASSWORD.
|
// CapabilityClientLongPassword is CLIENT_LONG_PASSWORD.
|
||||||
// New more secure passwords. Assumed to be set since 4.1.1.
|
// New more secure passwords. Assumed to be set since 4.1.1.
|
||||||
// We do not check this anywhere.
|
// We do not check this anywhere.
|
||||||
CapabilityClientLongPassword = 1
|
CapabilityClientLongPassword = 1
|
||||||
|
|
||||||
// CapabilityClientFoundRows is CLIENT_FOUND_ROWS.
|
// CapabilityClientFoundRows is CLIENT_FOUND_ROWS.
|
||||||
CapabilityClientFoundRows = 1 << 1
|
CapabilityClientFoundRows = 1 << 1
|
||||||
|
|
||||||
// CapabilityClientLongFlag is CLIENT_LONG_FLAG.
|
// CapabilityClientLongFlag is CLIENT_LONG_FLAG.
|
||||||
// Longer flags in Protocol::ColumnDefinition320.
|
// Longer flags in Protocol::ColumnDefinition320.
|
||||||
// Set it everywhere, not used, as we use Protocol::ColumnDefinition41.
|
// Set it everywhere, not used, as we use Protocol::ColumnDefinition41.
|
||||||
CapabilityClientLongFlag = 1 << 2
|
CapabilityClientLongFlag = 1 << 2
|
||||||
|
|
||||||
// CapabilityClientConnectWithDB is CLIENT_CONNECT_WITH_DB.
|
// CapabilityClientConnectWithDB is CLIENT_CONNECT_WITH_DB.
|
||||||
// One can specify db on connect.
|
// One can specify db on connect.
|
||||||
CapabilityClientConnectWithDB = 1 << 3
|
CapabilityClientConnectWithDB = 1 << 3
|
||||||
|
|
||||||
// CLIENT_NO_SCHEMA 1 << 4
|
// CLIENT_NO_SCHEMA 1 << 4
|
||||||
// Do not permit database.table.column. We do permit it.
|
// Do not permit database.table.column. We do permit it.
|
||||||
|
|
||||||
// CLIENT_COMPRESS 1 << 5
|
// CLIENT_COMPRESS 1 << 5
|
||||||
// We do not support compression. CPU is usually our bottleneck.
|
// We do not support compression. CPU is usually our bottleneck.
|
||||||
|
|
||||||
// CLIENT_ODBC 1 << 6
|
// CLIENT_ODBC 1 << 6
|
||||||
// No special behavior since 3.22.
|
// No special behavior since 3.22.
|
||||||
|
|
||||||
// CLIENT_LOCAL_FILES 1 << 7
|
// CLIENT_LOCAL_FILES 1 << 7
|
||||||
// Client can use LOCAL INFILE request of LOAD DATA|XML.
|
// Client can use LOCAL INFILE request of LOAD DATA|XML.
|
||||||
// We do not set it.
|
// We do not set it.
|
||||||
CapabilityClientLoadDataLocal = 1 << 7
|
CapabilityClientLoadDataLocal = 1 << 7
|
||||||
|
|
||||||
// CLIENT_IGNORE_SPACE 1 << 8
|
// CLIENT_IGNORE_SPACE 1 << 8
|
||||||
// Parser can ignore spaces before '('.
|
// Parser can ignore spaces before '('.
|
||||||
// We ignore this.
|
// We ignore this.
|
||||||
|
|
||||||
// CapabilityClientProtocol41 is CLIENT_PROTOCOL_41.
|
// CapabilityClientProtocol41 is CLIENT_PROTOCOL_41.
|
||||||
// New 4.1 protocol. Enforced everywhere.
|
// New 4.1 protocol. Enforced everywhere.
|
||||||
CapabilityClientProtocol41 = 1 << 9
|
CapabilityClientProtocol41 = 1 << 9
|
||||||
|
|
||||||
// CLIENT_INTERACTIVE 1 << 10
|
// CLIENT_INTERACTIVE 1 << 10
|
||||||
// Not specified, ignored.
|
// Not specified, ignored.
|
||||||
|
|
||||||
// CapabilityClientSSL is CLIENT_SSL.
|
// CapabilityClientSSL is CLIENT_SSL.
|
||||||
// Switch to SSL after handshake.
|
// Switch to SSL after handshake.
|
||||||
CapabilityClientSSL = 1 << 11
|
CapabilityClientSSL = 1 << 11
|
||||||
|
|
||||||
// CLIENT_IGNORE_SIGPIPE 1 << 12
|
// CLIENT_IGNORE_SIGPIPE 1 << 12
|
||||||
// Do not issue SIGPIPE if network failures occur (libmysqlclient only).
|
// Do not issue SIGPIPE if network failures occur (libmysqlclient only).
|
||||||
|
|
||||||
// CapabilityClientTransactions is CLIENT_TRANSACTIONS.
|
// CapabilityClientTransactions is CLIENT_TRANSACTIONS.
|
||||||
// Can send status flags in EOF_Packet.
|
// Can send status flags in EOF_Packet.
|
||||||
// This flag is optional in 3.23, but always set by the server since 4.0.
|
// This flag is optional in 3.23, but always set by the server since 4.0.
|
||||||
// We just do it all the time.
|
// We just do it all the time.
|
||||||
CapabilityClientTransactions = 1 << 13
|
CapabilityClientTransactions = 1 << 13
|
||||||
|
|
||||||
// CLIENT_RESERVED 1 << 14
|
// CLIENT_RESERVED 1 << 14
|
||||||
|
|
||||||
// CapabilityClientSecureConnection is CLIENT_SECURE_CONNECTION.
|
// CapabilityClientSecureConnection is CLIENT_SECURE_CONNECTION.
|
||||||
// New 4.1 authentication. Always set, expected, never checked.
|
// New 4.1 authentication. Always set, expected, never checked.
|
||||||
CapabilityClientSecureConnection = 1 << 15
|
CapabilityClientSecureConnection = 1 << 15
|
||||||
|
|
||||||
// CapabilityClientMultiStatements is CLIENT_MULTI_STATEMENTS
|
// CapabilityClientMultiStatements is CLIENT_MULTI_STATEMENTS
|
||||||
// Can handle multiple statements per COM_QUERY and COM_STMT_PREPARE.
|
// Can handle multiple statements per COM_QUERY and COM_STMT_PREPARE.
|
||||||
CapabilityClientMultiStatements = 1 << 16
|
CapabilityClientMultiStatements = 1 << 16
|
||||||
|
|
||||||
// CapabilityClientMultiResults is CLIENT_MULTI_RESULTS
|
// CapabilityClientMultiResults is CLIENT_MULTI_RESULTS
|
||||||
// Can send multiple resultsets for COM_QUERY.
|
// Can send multiple resultsets for COM_QUERY.
|
||||||
CapabilityClientMultiResults = 1 << 17
|
CapabilityClientMultiResults = 1 << 17
|
||||||
|
|
||||||
// CapabilityClientPluginAuth is CLIENT_PLUGIN_AUTH.
|
// CapabilityClientPluginAuth is CLIENT_PLUGIN_AUTH.
|
||||||
// Client supports plugin authentication.
|
// Client supports plugin authentication.
|
||||||
CapabilityClientPluginAuth = 1 << 19
|
CapabilityClientPluginAuth = 1 << 19
|
||||||
|
|
||||||
// CapabilityClientConnAttr is CLIENT_CONNECT_ATTRS
|
// CapabilityClientConnAttr is CLIENT_CONNECT_ATTRS
|
||||||
// Permits connection attributes in Protocol::HandshakeResponse41.
|
// Permits connection attributes in Protocol::HandshakeResponse41.
|
||||||
CapabilityClientConnAttr = 1 << 20
|
CapabilityClientConnAttr = 1 << 20
|
||||||
|
|
||||||
// CapabilityClientPluginAuthLenencClientData is CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA
|
// CapabilityClientPluginAuthLenencClientData is CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA
|
||||||
CapabilityClientPluginAuthLenencClientData = 1 << 21
|
CapabilityClientPluginAuthLenencClientData = 1 << 21
|
||||||
|
|
||||||
// CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS 1 << 22
|
// CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS 1 << 22
|
||||||
// Announces support for expired password extension.
|
// Announces support for expired password extension.
|
||||||
// Not yet supported.
|
// Not yet supported.
|
||||||
|
|
||||||
// CLIENT_SESSION_TRACK 1 << 23
|
// CLIENT_SESSION_TRACK 1 << 23
|
||||||
// Can set SERVER_SESSION_STATE_CHANGED in the Status Flags
|
// Can set SERVER_SESSION_STATE_CHANGED in the Status Flags
|
||||||
// and send session-state change data after a OK packet.
|
// and send session-state change data after a OK packet.
|
||||||
// Not yet supported.
|
// Not yet supported.
|
||||||
|
|
||||||
// CapabilityClientDeprecateEOF is CLIENT_DEPRECATE_EOF
|
// CapabilityClientDeprecateEOF is CLIENT_DEPRECATE_EOF
|
||||||
// Expects an OK (instead of EOF) after the resultset rows of a Text Resultset.
|
// Expects an OK (instead of EOF) after the resultset rows of a Text Resultset.
|
||||||
CapabilityClientDeprecateEOF = 1 << 24
|
CapabilityClientDeprecateEOF = 1 << 24
|
||||||
)
|
)
|
||||||
|
|
||||||
// Packet types.
|
// Packet types.
|
||||||
// Originally found in include/mysql/mysql_com.h
|
// Originally found in include/mysql/mysql_com.h
|
||||||
const (
|
const (
|
||||||
// ComQuit is COM_QUIT.
|
// ComQuit is COM_QUIT.
|
||||||
ComQuit = 0x01
|
ComQuit = 0x01
|
||||||
|
|
||||||
// ComInitDB is COM_INIT_DB.
|
// ComInitDB is COM_INIT_DB.
|
||||||
ComInitDB = 0x02
|
ComInitDB = 0x02
|
||||||
|
|
||||||
// ComQuery is COM_QUERY.
|
// ComQuery is COM_QUERY.
|
||||||
ComQuery = 0x03
|
ComQuery = 0x03
|
||||||
|
|
||||||
// ComPing is COM_PING.
|
// ComPing is COM_PING.
|
||||||
ComPing = 0x0e
|
ComPing = 0x0e
|
||||||
|
|
||||||
|
// ComSetOption is COM_SET_OPTION
|
||||||
|
ComSetOption = 0x1b
|
||||||
|
|
||||||
// ComSetOption is COM_SET_OPTION
|
// OKPacket is the header of the OK packet.
|
||||||
ComSetOption = 0x1b
|
OKPacket = 0x00
|
||||||
|
|
||||||
|
// EOFPacket is the header of the EOF packet.
|
||||||
|
EOFPacket = 0xfe
|
||||||
|
|
||||||
// OKPacket is the header of the OK packet.
|
// AuthSwitchRequestPacket is used to switch auth method.
|
||||||
OKPacket = 0x00
|
AuthSwitchRequestPacket = 0xfe
|
||||||
|
|
||||||
// EOFPacket is the header of the EOF packet.
|
// ErrPacket is the header of the error packet.
|
||||||
EOFPacket = 0xfe
|
ErrPacket = 0xff
|
||||||
|
|
||||||
// AuthSwitchRequestPacket is used to switch auth method.
|
// NullValue is the encoded value of NULL.
|
||||||
AuthSwitchRequestPacket = 0xfe
|
NullValue = 0xfb
|
||||||
|
|
||||||
// ErrPacket is the header of the error packet.
|
|
||||||
ErrPacket = 0xff
|
|
||||||
|
|
||||||
// NullValue is the encoded value of NULL.
|
|
||||||
NullValue = 0xfb
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error codes for client-side errors.
|
// Error codes for client-side errors.
|
||||||
// Originally found in include/mysql/errmsg.h and
|
// Originally found in include/mysql/errmsg.h and
|
||||||
// https://dev.mysql.com/doc/refman/5.7/en/error-messages-client.html
|
// https://dev.mysql.com/doc/refman/5.7/en/error-messages-client.html
|
||||||
const (
|
const (
|
||||||
// CRUnknownError is CR_UNKNOWN_ERROR
|
// CRUnknownError is CR_UNKNOWN_ERROR
|
||||||
CRUnknownError = 2000
|
CRUnknownError = 2000
|
||||||
|
|
||||||
|
// CRServerGone is CR_SERVER_GONE_ERROR.
|
||||||
|
// This is returned if the client tries to send a command but it fails.
|
||||||
|
CRServerGone = 2006
|
||||||
|
|
||||||
// CRServerGone is CR_SERVER_GONE_ERROR.
|
// CRServerHandshakeErr is CR_SERVER_HANDSHAKE_ERR
|
||||||
// This is returned if the client tries to send a command but it fails.
|
CRServerHandshakeErr = 2012
|
||||||
CRServerGone = 2006
|
|
||||||
|
|
||||||
// CRServerHandshakeErr is CR_SERVER_HANDSHAKE_ERR
|
// CRServerLost is CR_SERVER_LOST.
|
||||||
CRServerHandshakeErr = 2012
|
// Used when:
|
||||||
|
// - the client cannot write an initial auth packet.
|
||||||
|
// - the client cannot read an initial auth packet.
|
||||||
|
// - the client cannot read a response from the server.
|
||||||
|
CRServerLost = 2013
|
||||||
|
|
||||||
// CRServerLost is CR_SERVER_LOST.
|
// CRMalformedPacket is CR_MALFORMED_PACKET
|
||||||
// Used when:
|
CRMalformedPacket = 2027
|
||||||
// - the client cannot write an initial auth packet.
|
|
||||||
// - the client cannot read an initial auth packet.
|
|
||||||
// - the client cannot read a response from the server.
|
|
||||||
CRServerLost = 2013
|
|
||||||
|
|
||||||
|
|
||||||
// CRMalformedPacket is CR_MALFORMED_PACKET
|
|
||||||
CRMalformedPacket = 2027
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error codes return in SQLErrors generated by vitess. These error codes
|
// Error codes return in SQLErrors generated by vitess. These error codes
|
||||||
// are in a high range to avoid conflicting with mysql error codes below.
|
// are in a high range to avoid conflicting with mysql error codes below.
|
||||||
const (
|
const (
|
||||||
// ERVitessMaxRowsExceeded is when a user tries to select more rows than the max rows as enforced by vitess.
|
// ERVitessMaxRowsExceeded is when a user tries to select more rows than the max rows as enforced by vitess.
|
||||||
ERVitessMaxRowsExceeded = 10001
|
ERVitessMaxRowsExceeded = 10001
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error codes for server-side errors.
|
// Error codes for server-side errors.
|
||||||
@@ -212,44 +208,40 @@ const (
|
|||||||
// The below are in sorted order by value, grouped by vterror code they should be bucketed into.
|
// The below are in sorted order by value, grouped by vterror code they should be bucketed into.
|
||||||
// See above reference for more information on each code.
|
// See above reference for more information on each code.
|
||||||
const (
|
const (
|
||||||
// unknown
|
// unknown
|
||||||
ERUnknownError = 1105
|
ERUnknownError = 1105
|
||||||
|
|
||||||
|
// unavailable
|
||||||
|
ERServerShutdown = 1053
|
||||||
|
|
||||||
// unavailable
|
// permissions
|
||||||
ERServerShutdown = 1053
|
ERAccessDeniedError = 1045
|
||||||
|
|
||||||
// permissions
|
// invalid arg
|
||||||
ERAccessDeniedError = 1045
|
ERUnknownComError = 1047
|
||||||
|
|
||||||
// invalid arg
|
ERParseError = 1064
|
||||||
ERUnknownComError = 1047
|
|
||||||
|
|
||||||
ERParseError = 1064
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Sql states for errors.
|
// Sql states for errors.
|
||||||
// Originally found in include/mysql/sql_state.h
|
// Originally found in include/mysql/sql_state.h
|
||||||
const (
|
const (
|
||||||
// SSUnknownSqlstate is ER_SIGNAL_EXCEPTION in
|
// SSUnknownSqlstate is ER_SIGNAL_EXCEPTION in
|
||||||
// include/mysql/sql_state.h, but:
|
// include/mysql/sql_state.h, but:
|
||||||
// const char *unknown_sqlstate= "HY000"
|
// const char *unknown_sqlstate= "HY000"
|
||||||
// in client.c. So using that one.
|
// in client.c. So using that one.
|
||||||
SSUnknownSQLState = "HY000"
|
SSUnknownSQLState = "HY000"
|
||||||
|
|
||||||
// SSUnknownComError is ER_UNKNOWN_COM_ERROR
|
// SSUnknownComError is ER_UNKNOWN_COM_ERROR
|
||||||
SSUnknownComError = "08S01"
|
SSUnknownComError = "08S01"
|
||||||
|
|
||||||
// SSHandshakeError is ER_HANDSHAKE_ERROR
|
// SSHandshakeError is ER_HANDSHAKE_ERROR
|
||||||
|
|
||||||
// SSServerShutdown is ER_SERVER_SHUTDOWN
|
// SSServerShutdown is ER_SERVER_SHUTDOWN
|
||||||
SSServerShutdown = "08S01"
|
SSServerShutdown = "08S01"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// SSAccessDeniedError is ER_ACCESS_DENIED_ERROR
|
|
||||||
SSAccessDeniedError = "28000"
|
|
||||||
|
|
||||||
|
// SSAccessDeniedError is ER_ACCESS_DENIED_ERROR
|
||||||
|
SSAccessDeniedError = "28000"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Status flags. They are returned by the server in a few cases.
|
// Status flags. They are returned by the server in a few cases.
|
||||||
@@ -257,63 +249,63 @@ const (
|
|||||||
// See http://dev.mysql.com/doc/internals/en/status-flags.html
|
// See http://dev.mysql.com/doc/internals/en/status-flags.html
|
||||||
const (
|
const (
|
||||||
|
|
||||||
// ServerMoreResultsExists is SERVER_MORE_RESULTS_EXISTS
|
// ServerMoreResultsExists is SERVER_MORE_RESULTS_EXISTS
|
||||||
ServerMoreResultsExists = 0x0008
|
ServerMoreResultsExists = 0x0008
|
||||||
)
|
)
|
||||||
|
|
||||||
// A few interesting character set values.
|
// A few interesting character set values.
|
||||||
// See http://dev.mysql.com/doc/internals/en/character-set.html#packet-Protocol::CharacterSet
|
// See http://dev.mysql.com/doc/internals/en/character-set.html#packet-Protocol::CharacterSet
|
||||||
const (
|
const (
|
||||||
// CharacterSetUtf8 is for UTF8. We use this by default.
|
// CharacterSetUtf8 is for UTF8. We use this by default.
|
||||||
CharacterSetUtf8 = 33
|
CharacterSetUtf8 = 33
|
||||||
|
|
||||||
// CharacterSetBinary is for binary. Use by integer fields for instance.
|
// CharacterSetBinary is for binary. Use by integer fields for instance.
|
||||||
CharacterSetBinary = 63
|
CharacterSetBinary = 63
|
||||||
)
|
)
|
||||||
|
|
||||||
// CharacterSetMap maps the charset name (used in ConnParams) to the
|
// CharacterSetMap maps the charset name (used in ConnParams) to the
|
||||||
// integer value. Interesting ones have their own constant above.
|
// integer value. Interesting ones have their own constant above.
|
||||||
var CharacterSetMap = map[string]uint8{
|
var CharacterSetMap = map[string]uint8{
|
||||||
"big5": 1,
|
"big5": 1,
|
||||||
"dec8": 3,
|
"dec8": 3,
|
||||||
"cp850": 4,
|
"cp850": 4,
|
||||||
"hp8": 6,
|
"hp8": 6,
|
||||||
"koi8r": 7,
|
"koi8r": 7,
|
||||||
"latin1": 8,
|
"latin1": 8,
|
||||||
"latin2": 9,
|
"latin2": 9,
|
||||||
"swe7": 10,
|
"swe7": 10,
|
||||||
"ascii": 11,
|
"ascii": 11,
|
||||||
"ujis": 12,
|
"ujis": 12,
|
||||||
"sjis": 13,
|
"sjis": 13,
|
||||||
"hebrew": 16,
|
"hebrew": 16,
|
||||||
"tis620": 18,
|
"tis620": 18,
|
||||||
"euckr": 19,
|
"euckr": 19,
|
||||||
"koi8u": 22,
|
"koi8u": 22,
|
||||||
"gb2312": 24,
|
"gb2312": 24,
|
||||||
"greek": 25,
|
"greek": 25,
|
||||||
"cp1250": 26,
|
"cp1250": 26,
|
||||||
"gbk": 28,
|
"gbk": 28,
|
||||||
"latin5": 30,
|
"latin5": 30,
|
||||||
"armscii8": 32,
|
"armscii8": 32,
|
||||||
"utf8": CharacterSetUtf8,
|
"utf8": CharacterSetUtf8,
|
||||||
"ucs2": 35,
|
"ucs2": 35,
|
||||||
"cp866": 36,
|
"cp866": 36,
|
||||||
"keybcs2": 37,
|
"keybcs2": 37,
|
||||||
"macce": 38,
|
"macce": 38,
|
||||||
"macroman": 39,
|
"macroman": 39,
|
||||||
"cp852": 40,
|
"cp852": 40,
|
||||||
"latin7": 41,
|
"latin7": 41,
|
||||||
"utf8mb4": 45,
|
"utf8mb4": 45,
|
||||||
"cp1251": 51,
|
"cp1251": 51,
|
||||||
"utf16": 54,
|
"utf16": 54,
|
||||||
"utf16le": 56,
|
"utf16le": 56,
|
||||||
"cp1256": 57,
|
"cp1256": 57,
|
||||||
"cp1257": 59,
|
"cp1257": 59,
|
||||||
"utf32": 60,
|
"utf32": 60,
|
||||||
"binary": CharacterSetBinary,
|
"binary": CharacterSetBinary,
|
||||||
"geostd8": 92,
|
"geostd8": 92,
|
||||||
"cp932": 95,
|
"cp932": 95,
|
||||||
"eucjpms": 97,
|
"eucjpms": 97,
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNum returns true if a MySQL type is a numeric value.
|
// IsNum returns true if a MySQL type is a numeric value.
|
||||||
@@ -322,5 +314,5 @@ var CharacterSetMap = map[string]uint8{
|
|||||||
// FIXME(alainjobart) This needs to use the constants in
|
// FIXME(alainjobart) This needs to use the constants in
|
||||||
// replication/constants.go, so we are using numerical values here.
|
// replication/constants.go, so we are using numerical values here.
|
||||||
func IsNum(typ uint8) bool {
|
func IsNum(typ uint8) bool {
|
||||||
return ((typ <= 9 /* MYSQL_TYPE_INT24 */ && typ != 7 /* MYSQL_TYPE_TIMESTAMP */) || typ == 13 /* MYSQL_TYPE_YEAR */ || typ == 246 /* MYSQL_TYPE_NEWDECIMAL */)
|
return ((typ <= 9 /* MYSQL_TYPE_INT24 */ && typ != 7 /* MYSQL_TYPE_TIMESTAMP */) || typ == 13 /* MYSQL_TYPE_YEAR */ || typ == 246 /* MYSQL_TYPE_NEWDECIMAL */)
|
||||||
}
|
}
|
||||||
|
|||||||
+151
-151
@@ -17,8 +17,8 @@ limitations under the License.
|
|||||||
package vmysql
|
package vmysql
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This file contains the data encoding and decoding functions.
|
// This file contains the data encoding and decoding functions.
|
||||||
@@ -34,97 +34,97 @@ import (
|
|||||||
// lenEncIntSize returns the number of bytes required to encode a
|
// lenEncIntSize returns the number of bytes required to encode a
|
||||||
// variable-length integer.
|
// variable-length integer.
|
||||||
func lenEncIntSize(i uint64) int {
|
func lenEncIntSize(i uint64) int {
|
||||||
switch {
|
switch {
|
||||||
case i < 251:
|
case i < 251:
|
||||||
return 1
|
return 1
|
||||||
case i < 1<<16:
|
case i < 1<<16:
|
||||||
return 3
|
return 3
|
||||||
case i < 1<<24:
|
case i < 1<<24:
|
||||||
return 4
|
return 4
|
||||||
default:
|
default:
|
||||||
return 9
|
return 9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeLenEncInt(data []byte, pos int, i uint64) int {
|
func writeLenEncInt(data []byte, pos int, i uint64) int {
|
||||||
switch {
|
switch {
|
||||||
case i < 251:
|
case i < 251:
|
||||||
data[pos] = byte(i)
|
data[pos] = byte(i)
|
||||||
return pos + 1
|
return pos + 1
|
||||||
case i < 1<<16:
|
case i < 1<<16:
|
||||||
data[pos] = 0xfc
|
data[pos] = 0xfc
|
||||||
data[pos+1] = byte(i)
|
data[pos+1] = byte(i)
|
||||||
data[pos+2] = byte(i >> 8)
|
data[pos+2] = byte(i >> 8)
|
||||||
return pos + 3
|
return pos + 3
|
||||||
case i < 1<<24:
|
case i < 1<<24:
|
||||||
data[pos] = 0xfd
|
data[pos] = 0xfd
|
||||||
data[pos+1] = byte(i)
|
data[pos+1] = byte(i)
|
||||||
data[pos+2] = byte(i >> 8)
|
data[pos+2] = byte(i >> 8)
|
||||||
data[pos+3] = byte(i >> 16)
|
data[pos+3] = byte(i >> 16)
|
||||||
return pos + 4
|
return pos + 4
|
||||||
default:
|
default:
|
||||||
data[pos] = 0xfe
|
data[pos] = 0xfe
|
||||||
data[pos+1] = byte(i)
|
data[pos+1] = byte(i)
|
||||||
data[pos+2] = byte(i >> 8)
|
data[pos+2] = byte(i >> 8)
|
||||||
data[pos+3] = byte(i >> 16)
|
data[pos+3] = byte(i >> 16)
|
||||||
data[pos+4] = byte(i >> 24)
|
data[pos+4] = byte(i >> 24)
|
||||||
data[pos+5] = byte(i >> 32)
|
data[pos+5] = byte(i >> 32)
|
||||||
data[pos+6] = byte(i >> 40)
|
data[pos+6] = byte(i >> 40)
|
||||||
data[pos+7] = byte(i >> 48)
|
data[pos+7] = byte(i >> 48)
|
||||||
data[pos+8] = byte(i >> 56)
|
data[pos+8] = byte(i >> 56)
|
||||||
return pos + 9
|
return pos + 9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func lenNullString(value string) int {
|
func lenNullString(value string) int {
|
||||||
return len(value) + 1
|
return len(value) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeNullString(data []byte, pos int, value string) int {
|
func writeNullString(data []byte, pos int, value string) int {
|
||||||
pos += copy(data[pos:], value)
|
pos += copy(data[pos:], value)
|
||||||
data[pos] = 0
|
data[pos] = 0
|
||||||
return pos + 1
|
return pos + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeEOFString(data []byte, pos int, value string) int {
|
func writeEOFString(data []byte, pos int, value string) int {
|
||||||
pos += copy(data[pos:], value)
|
pos += copy(data[pos:], value)
|
||||||
return pos
|
return pos
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeByte(data []byte, pos int, value byte) int {
|
func writeByte(data []byte, pos int, value byte) int {
|
||||||
data[pos] = value
|
data[pos] = value
|
||||||
return pos + 1
|
return pos + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeUint16(data []byte, pos int, value uint16) int {
|
func writeUint16(data []byte, pos int, value uint16) int {
|
||||||
data[pos] = byte(value)
|
data[pos] = byte(value)
|
||||||
data[pos+1] = byte(value >> 8)
|
data[pos+1] = byte(value >> 8)
|
||||||
return pos + 2
|
return pos + 2
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeUint32(data []byte, pos int, value uint32) int {
|
func writeUint32(data []byte, pos int, value uint32) int {
|
||||||
data[pos] = byte(value)
|
data[pos] = byte(value)
|
||||||
data[pos+1] = byte(value >> 8)
|
data[pos+1] = byte(value >> 8)
|
||||||
data[pos+2] = byte(value >> 16)
|
data[pos+2] = byte(value >> 16)
|
||||||
data[pos+3] = byte(value >> 24)
|
data[pos+3] = byte(value >> 24)
|
||||||
return pos + 4
|
return pos + 4
|
||||||
}
|
}
|
||||||
|
|
||||||
func lenEncStringSize(value string) int {
|
func lenEncStringSize(value string) int {
|
||||||
l := len(value)
|
l := len(value)
|
||||||
return lenEncIntSize(uint64(l)) + l
|
return lenEncIntSize(uint64(l)) + l
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeLenEncString(data []byte, pos int, value string) int {
|
func writeLenEncString(data []byte, pos int, value string) int {
|
||||||
pos = writeLenEncInt(data, pos, uint64(len(value)))
|
pos = writeLenEncInt(data, pos, uint64(len(value)))
|
||||||
return writeEOFString(data, pos, value)
|
return writeEOFString(data, pos, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeZeroes(data []byte, pos int, len int) int {
|
func writeZeroes(data []byte, pos int, len int) int {
|
||||||
for i := 0; i < len; i++ {
|
for i := 0; i < len; i++ {
|
||||||
data[pos+i] = 0
|
data[pos+i] = 0
|
||||||
}
|
}
|
||||||
return pos + len
|
return pos + len
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -136,121 +136,121 @@ func writeZeroes(data []byte, pos int, len int) int {
|
|||||||
//
|
//
|
||||||
|
|
||||||
func readByte(data []byte, pos int) (byte, int, bool) {
|
func readByte(data []byte, pos int) (byte, int, bool) {
|
||||||
if pos >= len(data) {
|
if pos >= len(data) {
|
||||||
return 0, 0, false
|
return 0, 0, false
|
||||||
}
|
}
|
||||||
return data[pos], pos + 1, true
|
return data[pos], pos + 1, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func readBytes(data []byte, pos int, size int) ([]byte, int, bool) {
|
func readBytes(data []byte, pos int, size int) ([]byte, int, bool) {
|
||||||
if pos+size-1 >= len(data) {
|
if pos+size-1 >= len(data) {
|
||||||
return nil, 0, false
|
return nil, 0, false
|
||||||
}
|
}
|
||||||
return data[pos : pos+size], pos + size, true
|
return data[pos : pos+size], pos + size, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// readBytesCopy returns a copy of the bytes in the packet.
|
// readBytesCopy returns a copy of the bytes in the packet.
|
||||||
// Useful to remember contents of ephemeral packets.
|
// Useful to remember contents of ephemeral packets.
|
||||||
func readBytesCopy(data []byte, pos int, size int) ([]byte, int, bool) {
|
func readBytesCopy(data []byte, pos int, size int) ([]byte, int, bool) {
|
||||||
if pos+size-1 >= len(data) {
|
if pos+size-1 >= len(data) {
|
||||||
return nil, 0, false
|
return nil, 0, false
|
||||||
}
|
}
|
||||||
result := make([]byte, size)
|
result := make([]byte, size)
|
||||||
copy(result, data[pos:pos+size])
|
copy(result, data[pos:pos+size])
|
||||||
return result, pos + size, true
|
return result, pos + size, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func readNullString(data []byte, pos int) (string, int, bool) {
|
func readNullString(data []byte, pos int) (string, int, bool) {
|
||||||
end := bytes.IndexByte(data[pos:], 0)
|
end := bytes.IndexByte(data[pos:], 0)
|
||||||
if end == -1 {
|
if end == -1 {
|
||||||
return "", 0, false
|
return "", 0, false
|
||||||
}
|
}
|
||||||
return string(data[pos : pos+end]), pos + end + 1, true
|
return string(data[pos : pos+end]), pos + end + 1, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func readUint16(data []byte, pos int) (uint16, int, bool) {
|
func readUint16(data []byte, pos int) (uint16, int, bool) {
|
||||||
if pos+1 >= len(data) {
|
if pos+1 >= len(data) {
|
||||||
return 0, 0, false
|
return 0, 0, false
|
||||||
}
|
}
|
||||||
return binary.LittleEndian.Uint16(data[pos : pos+2]), pos + 2, true
|
return binary.LittleEndian.Uint16(data[pos : pos+2]), pos + 2, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func readUint32(data []byte, pos int) (uint32, int, bool) {
|
func readUint32(data []byte, pos int) (uint32, int, bool) {
|
||||||
if pos+3 >= len(data) {
|
if pos+3 >= len(data) {
|
||||||
return 0, 0, false
|
return 0, 0, false
|
||||||
}
|
}
|
||||||
return binary.LittleEndian.Uint32(data[pos : pos+4]), pos + 4, true
|
return binary.LittleEndian.Uint32(data[pos : pos+4]), pos + 4, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func readLenEncInt(data []byte, pos int) (uint64, int, bool) {
|
func readLenEncInt(data []byte, pos int) (uint64, int, bool) {
|
||||||
if pos >= len(data) {
|
if pos >= len(data) {
|
||||||
return 0, 0, false
|
return 0, 0, false
|
||||||
}
|
}
|
||||||
switch data[pos] {
|
switch data[pos] {
|
||||||
case 0xfc:
|
case 0xfc:
|
||||||
// Encoded in the next 2 bytes.
|
// Encoded in the next 2 bytes.
|
||||||
if pos+2 >= len(data) {
|
if pos+2 >= len(data) {
|
||||||
return 0, 0, false
|
return 0, 0, false
|
||||||
}
|
}
|
||||||
return uint64(data[pos+1]) |
|
return uint64(data[pos+1]) |
|
||||||
uint64(data[pos+2])<<8, pos + 3, true
|
uint64(data[pos+2])<<8, pos + 3, true
|
||||||
case 0xfd:
|
case 0xfd:
|
||||||
// Encoded in the next 3 bytes.
|
// Encoded in the next 3 bytes.
|
||||||
if pos+3 >= len(data) {
|
if pos+3 >= len(data) {
|
||||||
return 0, 0, false
|
return 0, 0, false
|
||||||
}
|
}
|
||||||
return uint64(data[pos+1]) |
|
return uint64(data[pos+1]) |
|
||||||
uint64(data[pos+2])<<8 |
|
uint64(data[pos+2])<<8 |
|
||||||
uint64(data[pos+3])<<16, pos + 4, true
|
uint64(data[pos+3])<<16, pos + 4, true
|
||||||
case 0xfe:
|
case 0xfe:
|
||||||
// Encoded in the next 8 bytes.
|
// Encoded in the next 8 bytes.
|
||||||
if pos+8 >= len(data) {
|
if pos+8 >= len(data) {
|
||||||
return 0, 0, false
|
return 0, 0, false
|
||||||
}
|
}
|
||||||
return uint64(data[pos+1]) |
|
return uint64(data[pos+1]) |
|
||||||
uint64(data[pos+2])<<8 |
|
uint64(data[pos+2])<<8 |
|
||||||
uint64(data[pos+3])<<16 |
|
uint64(data[pos+3])<<16 |
|
||||||
uint64(data[pos+4])<<24 |
|
uint64(data[pos+4])<<24 |
|
||||||
uint64(data[pos+5])<<32 |
|
uint64(data[pos+5])<<32 |
|
||||||
uint64(data[pos+6])<<40 |
|
uint64(data[pos+6])<<40 |
|
||||||
uint64(data[pos+7])<<48 |
|
uint64(data[pos+7])<<48 |
|
||||||
uint64(data[pos+8])<<56, pos + 9, true
|
uint64(data[pos+8])<<56, pos + 9, true
|
||||||
}
|
}
|
||||||
return uint64(data[pos]), pos + 1, true
|
return uint64(data[pos]), pos + 1, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func readLenEncString(data []byte, pos int) (string, int, bool) {
|
func readLenEncString(data []byte, pos int) (string, int, bool) {
|
||||||
size, pos, ok := readLenEncInt(data, pos)
|
size, pos, ok := readLenEncInt(data, pos)
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", 0, false
|
return "", 0, false
|
||||||
}
|
}
|
||||||
s := int(size)
|
s := int(size)
|
||||||
if pos+s-1 >= len(data) {
|
if pos+s-1 >= len(data) {
|
||||||
return "", 0, false
|
return "", 0, false
|
||||||
}
|
}
|
||||||
return string(data[pos : pos+s]), pos + s, true
|
return string(data[pos : pos+s]), pos + s, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func skipLenEncString(data []byte, pos int) (int, bool) {
|
func skipLenEncString(data []byte, pos int) (int, bool) {
|
||||||
size, pos, ok := readLenEncInt(data, pos)
|
size, pos, ok := readLenEncInt(data, pos)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
s := int(size)
|
s := int(size)
|
||||||
if pos+s-1 >= len(data) {
|
if pos+s-1 >= len(data) {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
return pos + s, true
|
return pos + s, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func readLenEncStringAsBytes(data []byte, pos int) ([]byte, int, bool) {
|
func readLenEncStringAsBytes(data []byte, pos int) ([]byte, int, bool) {
|
||||||
size, pos, ok := readLenEncInt(data, pos)
|
size, pos, ok := readLenEncInt(data, pos)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, 0, false
|
return nil, 0, false
|
||||||
}
|
}
|
||||||
s := int(size)
|
s := int(size)
|
||||||
if pos+s-1 >= len(data) {
|
if pos+s-1 >= len(data) {
|
||||||
return nil, 0, false
|
return nil, 0, false
|
||||||
}
|
}
|
||||||
return data[pos : pos+s], pos + s, true
|
return data[pos : pos+s], pos + s, true
|
||||||
}
|
}
|
||||||
|
|||||||
+447
-472
File diff suppressed because it is too large
Load Diff
@@ -37,7 +37,6 @@ const (
|
|||||||
// timing metric keys
|
// timing metric keys
|
||||||
connectTimingKey = "Connect"
|
connectTimingKey = "Connect"
|
||||||
queryTimingKey = "Query"
|
queryTimingKey = "Query"
|
||||||
versionSSL30 = "SSL30"
|
|
||||||
versionTLS10 = "TLS10"
|
versionTLS10 = "TLS10"
|
||||||
versionTLS11 = "TLS11"
|
versionTLS11 = "TLS11"
|
||||||
versionTLS12 = "TLS12"
|
versionTLS12 = "TLS12"
|
||||||
@@ -322,7 +321,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if l.RequireSecureTransport {
|
if l.RequireSecureTransport {
|
||||||
c.writeErrorPacketFromError(vterrors.Errorf(vtrpc.Code_UNAVAILABLE, "server does not allow insecure connections, client must use SSL/TLS"))
|
_ = c.writeErrorPacketFromError(vterrors.Errorf(vtrpc.Code_UNAVAILABLE, "server does not allow insecure connections, client must use SSL/TLS"))
|
||||||
}
|
}
|
||||||
connCountByTLSVer.Add(versionNoTLS, 1)
|
connCountByTLSVer.Add(versionNoTLS, 1)
|
||||||
defer connCountByTLSVer.Add(versionNoTLS, -1)
|
defer connCountByTLSVer.Add(versionNoTLS, -1)
|
||||||
@@ -331,7 +330,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
|||||||
// See what auth method the AuthServer wants to use for that user.
|
// See what auth method the AuthServer wants to use for that user.
|
||||||
authServerMethod, err := l.authServer.AuthMethod(user)
|
authServerMethod, err := l.authServer.AuthMethod(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.writeErrorPacketFromError(err)
|
_ = c.writeErrorPacketFromError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,7 +343,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
|||||||
userData, err := l.authServer.ValidateHash(salt, user, authResponse, conn.RemoteAddr())
|
userData, err := l.authServer.ValidateHash(salt, user, authResponse, conn.RemoteAddr())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Trace("Error authenticating user using MySQL native password: %v", err)
|
log.Trace("Error authenticating user using MySQL native password: %v", err)
|
||||||
c.writeErrorPacketFromError(err)
|
_ = c.writeErrorPacketFromError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.User = user
|
c.User = user
|
||||||
@@ -358,8 +357,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//lint:ignore SA4006 This line is required because the binary protocol requires padding with 0
|
data := make([]byte, 21) //nolint:ineffassign,staticcheck // SA4006 This line is required because the binary protocol requires padding with 0
|
||||||
data := make([]byte, 21)
|
|
||||||
data = append(salt, byte(0x00))
|
data = append(salt, byte(0x00))
|
||||||
if err := c.writeAuthSwitchRequest(MysqlNativePassword, data); err != nil {
|
if err := c.writeAuthSwitchRequest(MysqlNativePassword, data); err != nil {
|
||||||
log.Error("Error writing auth switch packet for %s: %v", c, err)
|
log.Error("Error writing auth switch packet for %s: %v", c, err)
|
||||||
@@ -376,7 +374,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
|||||||
userData, err := l.authServer.ValidateHash(salt, user, response, conn.RemoteAddr())
|
userData, err := l.authServer.ValidateHash(salt, user, response, conn.RemoteAddr())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Trace("Error authenticating user using MySQL native password: %v", err)
|
log.Trace("Error authenticating user using MySQL native password: %v", err)
|
||||||
c.writeErrorPacketFromError(err)
|
_ = c.writeErrorPacketFromError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.User = user
|
c.User = user
|
||||||
@@ -387,7 +385,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
|||||||
|
|
||||||
// The negotiation happens in clear text. Let's check we can.
|
// The negotiation happens in clear text. Let's check we can.
|
||||||
if !l.AllowClearTextWithoutTLS && c.Capabilities&CapabilityClientSSL == 0 {
|
if !l.AllowClearTextWithoutTLS && c.Capabilities&CapabilityClientSSL == 0 {
|
||||||
c.writeErrorPacket(CRServerHandshakeErr, SSUnknownSQLState, "Cannot use clear text authentication over non-SSL connections.")
|
_ = c.writeErrorPacket(CRServerHandshakeErr, SSUnknownSQLState, "Cannot use clear text authentication over non-SSL connections.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +404,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
|||||||
// auth server.
|
// auth server.
|
||||||
userData, err := l.authServer.Negotiate(c, user, conn.RemoteAddr())
|
userData, err := l.authServer.Negotiate(c, user, conn.RemoteAddr())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.writeErrorPacketFromError(err)
|
_ = c.writeErrorPacketFromError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.User = user
|
c.User = user
|
||||||
@@ -770,8 +768,6 @@ func (c *Conn) writeAuthSwitchRequest(pluginName string, pluginData []byte) erro
|
|||||||
// Whenever we move to a new version of go, we will need add any new supported TLS versions here
|
// Whenever we move to a new version of go, we will need add any new supported TLS versions here
|
||||||
func tlsVersionToString(version uint16) string {
|
func tlsVersionToString(version uint16) string {
|
||||||
switch version {
|
switch version {
|
||||||
case tls.VersionSSL30:
|
|
||||||
return versionSSL30
|
|
||||||
case tls.VersionTLS10:
|
case tls.VersionTLS10:
|
||||||
return versionTLS10
|
return versionTLS10
|
||||||
case tls.VersionTLS11:
|
case tls.VersionTLS11:
|
||||||
|
|||||||
@@ -17,58 +17,58 @@ limitations under the License.
|
|||||||
package vmysql
|
package vmysql
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"vitess.io/vitess/go/vt/sqlparser"
|
"vitess.io/vitess/go/vt/sqlparser"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SQLError is the error structure returned from calling a db library function
|
// SQLError is the error structure returned from calling a db library function
|
||||||
type SQLError struct {
|
type SQLError struct {
|
||||||
Num int
|
Num int
|
||||||
State string
|
State string
|
||||||
Message string
|
Message string
|
||||||
Query string
|
Query string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSQLError creates a new SQLError.
|
// NewSQLError creates a new SQLError.
|
||||||
// If sqlState is left empty, it will default to "HY000" (general error).
|
// If sqlState is left empty, it will default to "HY000" (general error).
|
||||||
// TODO: Should be aligned with vterrors, stack traces and wrapping
|
// TODO: Should be aligned with vterrors, stack traces and wrapping
|
||||||
func NewSQLError(number int, sqlState string, format string, args ...interface{}) *SQLError {
|
func NewSQLError(number int, sqlState string, format string, args ...interface{}) *SQLError {
|
||||||
if sqlState == "" {
|
if sqlState == "" {
|
||||||
sqlState = SSUnknownSQLState
|
sqlState = SSUnknownSQLState
|
||||||
}
|
}
|
||||||
return &SQLError{
|
return &SQLError{
|
||||||
Num: number,
|
Num: number,
|
||||||
State: sqlState,
|
State: sqlState,
|
||||||
Message: fmt.Sprintf(format, args...),
|
Message: fmt.Sprintf(format, args...),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error implements the error interface
|
// Error implements the error interface
|
||||||
func (se *SQLError) Error() string {
|
func (se *SQLError) Error() string {
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
buf.WriteString(se.Message)
|
buf.WriteString(se.Message)
|
||||||
|
|
||||||
// Add MySQL errno and SQLSTATE in a format that we can later parse.
|
// Add MySQL errno and SQLSTATE in a format that we can later parse.
|
||||||
// There's no avoiding string parsing because all errors
|
// There's no avoiding string parsing because all errors
|
||||||
// are converted to strings anyway at RPC boundaries.
|
// are converted to strings anyway at RPC boundaries.
|
||||||
// See NewSQLErrorFromError.
|
// See NewSQLErrorFromError.
|
||||||
fmt.Fprintf(buf, " (errno %v) (sqlstate %v)", se.Num, se.State)
|
fmt.Fprintf(buf, " (errno %v) (sqlstate %v)", se.Num, se.State)
|
||||||
|
|
||||||
if se.Query != "" {
|
if se.Query != "" {
|
||||||
fmt.Fprintf(buf, " during query: %s", sqlparser.TruncateForLog(se.Query))
|
fmt.Fprintf(buf, " during query: %s", sqlparser.TruncateForLog(se.Query))
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number returns the internal MySQL error code.
|
// Number returns the internal MySQL error code.
|
||||||
func (se *SQLError) Number() int {
|
func (se *SQLError) Number() int {
|
||||||
return se.Num
|
return se.Num
|
||||||
}
|
}
|
||||||
|
|
||||||
// SQLState returns the SQLSTATE value.
|
// SQLState returns the SQLSTATE value.
|
||||||
func (se *SQLError) SQLState() string {
|
func (se *SQLError) SQLState() string {
|
||||||
return se.State
|
return se.State
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
package rhttp
|
package rhttp
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
IpHeader string
|
IpHeader string
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -119,7 +119,7 @@ func compileTpl(c *gin.Context, tpl string) (compiled string) {
|
|||||||
if headerVarMatcher.FindString(tpl) != "" {
|
if headerVarMatcher.FindString(tpl) != "" {
|
||||||
compiled = headerVarMatcher.ReplaceAllString(compiled, c.GetHeader(headerVarMatcher.FindStringSubmatch(tpl)[1]))
|
compiled = headerVarMatcher.ReplaceAllString(compiled, c.GetHeader(headerVarMatcher.FindStringSubmatch(tpl)[1]))
|
||||||
}
|
}
|
||||||
return
|
return compiled
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Receive(c *gin.Context) {
|
func (s *Server) Receive(c *gin.Context) {
|
||||||
|
|||||||
+2
-2
@@ -17,7 +17,7 @@ type Record struct {
|
|||||||
Path string `form:"path" json:"path"`
|
Path string `form:"path" json:"path"`
|
||||||
record.BaseRecord
|
record.BaseRecord
|
||||||
RawRequest string `json:"raw_request" notice:"-"`
|
RawRequest string `json:"raw_request" notice:"-"`
|
||||||
Rule Rule `gorm:"foreignKey:RuleName;references:Name;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" form:"-" json:"-" notice:"-"`
|
Rule Rule `gorm:"foreignKey:RuleName;references:Name;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" form:"-" json:"-" notice:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Record) TableName() string {
|
func (Record) TableName() string {
|
||||||
@@ -42,7 +42,7 @@ func NewRecord(rule *Rule, flag, method, url, ip, area, raw string) (r *Record,
|
|||||||
Rule: *rule,
|
Rule: *rule,
|
||||||
}
|
}
|
||||||
err = database.DB.Create(r).Error
|
err = database.DB.Create(r).Error
|
||||||
return
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListRecords(c *gin.Context) {
|
func ListRecords(c *gin.Context) {
|
||||||
|
|||||||
+4
-5
@@ -13,7 +13,7 @@ import (
|
|||||||
// Http rule struct
|
// Http rule struct
|
||||||
type Rule struct {
|
type Rule struct {
|
||||||
rule.BaseRule
|
rule.BaseRule
|
||||||
ResponseStatusCode string `gorm:"index;default:200;not null" form:"response_status_code" json:"response_status_code"`
|
ResponseStatusCode string `gorm:"index;default:200;not null" form:"response_status_code" json:"response_status_code"`
|
||||||
ResponseHeaders database.MapField `form:"response_headers" json:"response_headers"`
|
ResponseHeaders database.MapField `form:"response_headers" json:"response_headers"`
|
||||||
ResponseBody string `gorm:"default:Hello RevSuit!" form:"response_body" json:"response_body"`
|
ResponseBody string `gorm:"default:Hello RevSuit!" form:"response_body" json:"response_body"`
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ func (Rule) TableName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New http rule struct
|
// New http rule struct
|
||||||
func NewRule(name, flagFormat, responseBody string, pushToClient, notice bool, responseStatus string, responseHeaders database.MapField, ) *Rule {
|
func NewRule(name, flagFormat, responseBody string, pushToClient, notice bool, responseStatus string, responseHeaders database.MapField) *Rule {
|
||||||
return &Rule{
|
return &Rule{
|
||||||
BaseRule: rule.BaseRule{
|
BaseRule: rule.BaseRule{
|
||||||
Name: name,
|
Name: name,
|
||||||
@@ -59,7 +59,7 @@ func (r *Rule) CreateOrUpdate() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = GetServer().updateRules()
|
err = GetServer().updateRules()
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the http rule in database and ruleSet
|
// Delete the http rule in database and ruleSet
|
||||||
@@ -71,7 +71,7 @@ func (r *Rule) Delete() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = GetServer().updateRules()
|
err = GetServer().updateRules()
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// List all http rules those satisfy the filter
|
// List all http rules those satisfy the filter
|
||||||
@@ -195,5 +195,4 @@ func DeleteRules(c *gin.Context) {
|
|||||||
"error": nil,
|
"error": nil,
|
||||||
"data": nil,
|
"data": nil,
|
||||||
})
|
})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ func ping(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func events(c *gin.Context) {
|
func events(c *gin.Context) {
|
||||||
log.Info("Receive connection from ", c.Request.RemoteAddr)
|
log.Info("Receive connection from %v", c.Request.RemoteAddr)
|
||||||
c.Stream(func(w io.Writer) bool {
|
c.Stream(func(w io.Writer) bool {
|
||||||
c.SSEvent("message", "connect succeed")
|
c.SSEvent("message", "connect succeed")
|
||||||
select {
|
select {
|
||||||
|
|||||||
@@ -24,11 +24,29 @@ func initDatabase(dsn string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = database.DB.AutoMigrate(&http.Record{})
|
err = database.DB.AutoMigrate(&http.Record{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
err = database.DB.AutoMigrate(&dns.Record{})
|
err = database.DB.AutoMigrate(&dns.Record{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
err = database.DB.AutoMigrate(&mysql.Record{})
|
err = database.DB.AutoMigrate(&mysql.Record{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
err = database.DB.AutoMigrate(&http.Rule{})
|
err = database.DB.AutoMigrate(&http.Rule{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
err = database.DB.AutoMigrate(&dns.Rule{})
|
err = database.DB.AutoMigrate(&dns.Rule{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
err = database.DB.AutoMigrate(&mysql.Rule{})
|
err = database.DB.AutoMigrate(&mysql.Rule{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
err = database.DB.AutoMigrate(&mysql.File{})
|
err = database.DB.AutoMigrate(&mysql.File{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
|
|||||||
Reference in New Issue
Block a user