Use golint to normalize the code (#1)

This commit is contained in:
Li4n0
2021-04-21 22:08:29 +08:00
committed by GitHub
parent d4a47aebca
commit 960b2ab5ea
39 changed files with 1046 additions and 1108 deletions
+1 -5
View File
@@ -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:
+32
View File
@@ -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
-13
View File
@@ -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)
}
+1 -1
View File
@@ -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
} }
+1 -2
View File
@@ -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)
} }
+2 -2
View File
@@ -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
} }
+1 -1
View File
@@ -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)
} }
+1 -1
View File
@@ -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")
} }
+1 -1
View File
@@ -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
} }
+3 -3
View File
@@ -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
} }
+4 -4
View File
@@ -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"),
}, },
}, },
}, },
+1 -1
View File
@@ -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"`
} }
+2 -2
View File
@@ -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) {
+1 -1
View File
@@ -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 {
+1 -1
View File
@@ -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
View File
@@ -1,5 +1,5 @@
package dns package dns
type Config struct { type Config struct {
Enable bool Enable bool
} }
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
} }
+7 -7
View File
@@ -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)
+8 -8
View File
@@ -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"}
} }
+86 -93
View File
@@ -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}
} }
+2 -49
View File
@@ -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))
} }
// //
+24 -24
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+7 -11
View File
@@ -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:
+29 -29
View File
@@ -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
View File
@@ -1,5 +1,5 @@
package rhttp package rhttp
type Config struct { type Config struct {
IpHeader string IpHeader string
} }
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
} }
+1 -1
View File
@@ -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 {
+18
View File
@@ -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())