diff --git a/README.md b/README.md index f4cf77d..68dbe14 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,50 @@ ## SQLfuzz +[![Go Report Card](https://goreportcard.com/badge/github.com/PumpkinSeed/sqlfuzz)](https://goreportcard.com/report/github.com/PumpkinSeed/sqlfuzz) [![GoDoc](https://godoc.org/github.com/PumpkinSeed/sqlfuzz?status.svg)](https://godoc.org/github.com/PumpkinSeed/sqlfuzz) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![made-with-Go](https://img.shields.io/badge/Made%20with-Go-1f425f.svg)](http://golang.org) ![sqlfuzz test workflow](https://github.com/PumpkinSeed/sqlfuzz/actions/workflows/test.yml/badge.svg) + Load random data into SQL tables for testing purposes. The tool can get the layout of the SQL table and fill it up with random data. -#### Usage +- [Installation](#installation) +- [Usage](#usage) +- [Flags](#flags) +- [Package usage](#package-usage) + +### Installation + +#### MacOS ``` -go install github.com/PumpkinSeed/sqlfuzz +wget https://github.com/PumpkinSeed/sqlfuzz/releases/download/{RELEASE}/sqlfuzz_darwin_amd64 -O /usr/local/bin/sqlfuzz +chmod +x /usr/local/bin/sqlfuzz ``` +#### Linux + +``` +# amd64 build +wget https://github.com/PumpkinSeed/sqlfuzz/releases/download/{RELEASE}/sqlfuzz_linux_amd64 -O /usr/local/bin/sqlfuzz +chmod +x /usr/local/bin/sqlfuzz + +# arm64 build +wget https://github.com/PumpkinSeed/sqlfuzz/releases/download/{RELEASE}/sqlfuzz_linux_arm64 -O /usr/local/bin/sqlfuzz +chmod +x /usr/local/bin/sqlfuzz +``` + +#### Windows + +You can download the Windows build [here](https://github.com/PumpkinSeed/sqlfuzz/releases/download/v0.3.0/sqlfuzz_windows_amd64.exe) + +#### Build from source + +``` +wget https://github.com/PumpkinSeed/sqlfuzz/archive/{RELEASE}.zip +# unzip +# cd into dir +go install main.go +``` + +### Usage + ``` sqlfuzz -u username -p password -d database -h 127.0.0.1 -t table -n 100000 -w 100 ``` @@ -22,4 +59,8 @@ sqlfuzz -u username -p password -d database -h 127.0.0.1 -t table -n 100000 -w 1 - `D`: Driver for database connection (currently only `mysql`) - `t`: Table for fuzzing - `n`: Number of rows to fuzz -- `w`: Concurrent workers to work on fuzzing \ No newline at end of file +- `w`: Concurrent workers to work on fuzzing + +### Package usage + +TODO: Write package \ No newline at end of file diff --git a/drivers/entry.go b/drivers/entry.go index f8ece0b..99d516f 100644 --- a/drivers/entry.go +++ b/drivers/entry.go @@ -19,21 +19,24 @@ const ( Unknown ) +// Flags needed by the driver type Flags struct { Username string Password string Database string - Host string - Port string - Driver string + Host string + Port string + Driver string } +// Field is the possible field definition type Field struct { - Type Type + Type Type Length int16 - Enum []string + Enum []string } +// Driver is the interface should satisfied by a certain driver type Driver interface { Connection() string Driver() string @@ -41,10 +44,11 @@ type Driver interface { MapField(string) Field } +// New creates a new driver instance based on the flags func New(f Flags) Driver { switch f.Driver { case "mysql": - return MySQL{f:f} + return MySQL{f: f} default: log.Fatal("Driver not implemented") return nil diff --git a/drivers/helpers.go b/drivers/helpers.go index 4f170c2..0e4190d 100644 --- a/drivers/helpers.go +++ b/drivers/helpers.go @@ -26,13 +26,10 @@ func length(field string, t string) []int16 { result = append(result, int16(data)) } return result - } else { - v, err := strconv.Atoi(str) - if err != nil { - panic(err) - } - return []int16{int16(v)} } - - return nil -} \ No newline at end of file + v, err := strconv.Atoi(str) + if err != nil { + panic(err) + } + return []int16{int16(v)} +} diff --git a/drivers/mysql.go b/drivers/mysql.go index 9e53545..6d4b853 100644 --- a/drivers/mysql.go +++ b/drivers/mysql.go @@ -5,23 +5,28 @@ import ( "strings" ) +// MySQL implementation of the Driver type MySQL struct { f Flags } +// Connection returns the specific connection string func (m MySQL) Connection() string { return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", m.f.Username, m.f.Password, m.f.Host, m.f.Port, m.f.Database) } +// Driver returns the name of the driver func (m MySQL) Driver() string { return m.f.Driver } +// Insert inserts the data into func (m MySQL) Insert(fields []string, table string) string { var template = "INSERT INTO %s(`%s`) VALUES(%s)" return fmt.Sprintf(template, table, strings.Join(fields, "`,`"), questionMarks(len(fields))) } +// MapField returns the actual fields func (m MySQL) MapField(field string) Field { field = strings.ToLower(field) // String types @@ -64,7 +69,7 @@ func (m MySQL) MapField(field string) Field { if strings.HasPrefix(field, "mediumint") { return Field{Type: Int16, Length: -1} } - if strings.HasPrefix(field, "int") || strings.HasPrefix(field, "bigint"){ + if strings.HasPrefix(field, "int") || strings.HasPrefix(field, "bigint") { return Field{Type: Int32, Length: -1} } diff --git a/drivers/mysql_test.go b/drivers/mysql_test.go index 899062b..45c0d8a 100644 --- a/drivers/mysql_test.go +++ b/drivers/mysql_test.go @@ -7,95 +7,95 @@ import ( func TestMapField(t *testing.T) { var scenarios = []struct { - input string + input string output Field }{ { - input:"varchar(12)", + input: "varchar(12)", output: Field{Type: String, Length: 12}, }, { - input:"char(100)", + input: "char(100)", output: Field{Type: String, Length: 100}, }, { - input:"varbinary(100)", + input: "varbinary(100)", output: Field{Type: String, Length: 100}, }, { - input:"binary(100)", + input: "binary(100)", output: Field{Type: String, Length: 100}, }, { - input:"tinyint", + input: "tinyint", output: Field{Type: Bool, Length: -1}, }, { - input:"smallint", + input: "smallint", output: Field{Type: Int16, Length: -1}, }, { - input:"mediumint", + input: "mediumint", output: Field{Type: Int16, Length: -1}, }, { - input:"int", + input: "int", output: Field{Type: Int32, Length: -1}, }, { - input:"bigint", + input: "bigint", output: Field{Type: Int32, Length: -1}, }, { - input:"decimal(12, 4)", + input: "decimal(12, 4)", output: Field{Type: Float, Length: 8}, }, { - input:"float(12, 5)", + input: "float(12, 5)", output: Field{Type: Float, Length: 7}, }, { - input:"double(20,5)", + input: "double(20,5)", output: Field{Type: Float, Length: 15}, }, { - input:"blob", + input: "blob", output: Field{Type: Blob, Length: -1}, }, { - input:"tinyblob", + input: "tinyblob", output: Field{Type: Blob, Length: -1}, }, { - input:"mediumblob", + input: "mediumblob", output: Field{Type: Blob, Length: -1}, }, { - input:"longblob", + input: "longblob", output: Field{Type: Blob, Length: -1}, }, { - input:"text", + input: "text", output: Field{Type: Text, Length: -1}, }, { - input:"tinytext", + input: "tinytext", output: Field{Type: Text, Length: -1}, }, { - input:"mediumtext", + input: "mediumtext", output: Field{Type: Text, Length: -1}, }, { - input:"longtext", + input: "longtext", output: Field{Type: Text, Length: -1}, }, { - input:"json", + input: "json", output: Field{Type: Json, Length: -1}, }, { - input:"enum(test, this, data)", + input: "enum(test, this, data)", output: Field{Type: Enum, Length: -1, Enum: []string{"test", "this", "data"}}, }, } @@ -107,4 +107,4 @@ func TestMapField(t *testing.T) { t.Errorf("Invalid output for %s, out: %+v", scenario.input, output) } } -} \ No newline at end of file +} diff --git a/main_test.go b/main_test.go index b70d7f4..e2fc8a3 100644 --- a/main_test.go +++ b/main_test.go @@ -17,9 +17,9 @@ func TestFuzz(t *testing.T) { Username: "mysql", Password: "mysql", Database: "mysql", - Host: "127.0.0.1", - Port: "3306", - Driver:"mysql", + Host: "127.0.0.1", + Port: "3306", + Driver: "mysql", } f.Table = "Persons" f.Parsed = true diff --git a/pkg/descriptor/tables.go b/pkg/descriptor/tables.go index b9efb2e..cdb7b1e 100644 --- a/pkg/descriptor/tables.go +++ b/pkg/descriptor/tables.go @@ -4,6 +4,7 @@ import ( "database/sql" ) +// ShowTables queries the available tables of the database func ShowTables(db *sql.DB) ([]string, error) { results, err := db.Query("SHOW TABLES;") if err != nil {