Skip to content

Commit 0759244

Browse files
Add shared FlagsToSet function in output.go (zmap#62)
* Add shared FlagsToSet function in output.go, use it in mysql. Add examples / tests. * Add utility functions to widen map keys
1 parent 2ec074a commit 0759244

File tree

3 files changed

+206
-17
lines changed

3 files changed

+206
-17
lines changed

lib/mysql/mysql.go

+5-17
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ import (
1717
"encoding/hex"
1818
"encoding/json"
1919
"fmt"
20-
"math"
2120
"net"
2221
"strings"
2322

2423
log "github.com/sirupsen/logrus"
24+
"github.com/zmap/zgrab2"
2525
)
2626

2727
const (
@@ -92,20 +92,6 @@ type Config struct {
9292
ReservedData []byte
9393
}
9494

95-
// flagsToSet() converts an integer flags variable to a set of consts corresponding to each bit.
96-
// The result is a map from the labels to bool (true).
97-
// Example: flagsToSet(0x12, { "a", "b", "c", "d", "e" }) returns { "b": true, "e": true }.
98-
func flagsToSet(flags uint64, consts []string) (ret map[string]bool) {
99-
ret = make(map[string]bool)
100-
for i, label := range consts {
101-
v := uint64(math.Pow(2, float64(i)))
102-
if uint64(flags)&v == v {
103-
ret[label] = true
104-
}
105-
}
106-
return ret
107-
}
108-
10995
// GetServerStatusFlags returns a map[string]bool representation of the
11096
// given flags. The keys are the constant names defined in the MySQL
11197
// docs, and the values are true (flags that are not set have no
@@ -127,7 +113,8 @@ func GetServerStatusFlags(flags uint16) map[string]bool {
127113
"SERVER_STATUS_IN_TRANS_READONLY",
128114
"SERVER_SESSION_STATE_CHANGED",
129115
}
130-
return flagsToSet(uint64(flags), consts)
116+
ret, _ := zgrab2.ListFlagsToSet(uint64(flags), consts)
117+
return ret
131118
}
132119

133120
// GetClientCapabilityFlags returns a map[string]bool representation of
@@ -162,7 +149,8 @@ func GetClientCapabilityFlags(flags uint32) map[string]bool {
162149
"CLIENT_SESSION_TRACK",
163150
"CLIENT_DEPRECATED_EOF",
164151
}
165-
return flagsToSet(uint64(flags), consts)
152+
ret, _ := zgrab2.ListFlagsToSet(uint64(flags), consts)
153+
return ret
166154
}
167155

168156
// InitConfig fills in a (possibly newly-created) Config instance with

output.go

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package zgrab2
2+
3+
import "fmt"
4+
5+
// FlagMap is a function that maps a single-bit bitmask (i.e. a number of the
6+
// form (1 << x)) to a string representing that bit.
7+
// If the input is not valid / recognized, it should return a non-nil error,
8+
// which will cause the flag to be added to the "unknowns" list.
9+
type FlagMap func(uint64) (string, error)
10+
11+
// MapFlagsToSet gets the "set" (map of strings to true) of values corresponding
12+
// to the bits in flags. For each bit i set in flags, the result will have
13+
// result[mapping(i << i)] = true.
14+
// Any bits for which the mapping returns a non-nil error are instead appended
15+
// to the unknowns list.
16+
func MapFlagsToSet(flags uint64, mapping FlagMap) (map[string]bool, []uint64) {
17+
ret := make(map[string]bool)
18+
unknowns := []uint64{}
19+
for i := uint8(0); i < 64; i++ {
20+
if flags == 0 {
21+
break
22+
}
23+
bit := (flags & 1) << i
24+
if bit > 0 {
25+
str, err := mapping(bit)
26+
if err != nil {
27+
unknowns = append(unknowns, bit)
28+
} else {
29+
ret[str] = true
30+
}
31+
}
32+
flags >>= 1
33+
}
34+
return ret, unknowns
35+
}
36+
37+
// GetFlagMapFromMap returns a FlagMap function that uses mapping to do the
38+
// mapping. Values not present in the map are treated as unknown, and a non-nil
39+
// error is returned in those cases.
40+
func GetFlagMapFromMap(mapping map[uint64]string) FlagMap {
41+
return func(bit uint64) (string, error) {
42+
ret, ok := mapping[bit]
43+
if ok {
44+
return ret, nil
45+
}
46+
return "", fmt.Errorf("Unknown flag 0x%x", bit)
47+
}
48+
}
49+
50+
// GetFlagMapFromList returns a FlagMap function mapping the ith bit to the
51+
// ith entry of bits.
52+
// bits is a list of labels for the corresponding bits; any empty strings (and
53+
// bits beyond the end of the list) are treated as unknown.
54+
func GetFlagMapFromList(bits []string) FlagMap {
55+
mapping := make(map[uint64]string)
56+
for i, v := range bits {
57+
if v != "" {
58+
mapping[uint64(1)<<uint8(i)] = v
59+
}
60+
}
61+
return GetFlagMapFromMap(mapping)
62+
}
63+
64+
// FlagsToSet converts an integer flags variable to a set of string labels
65+
// corresponding to each bit, in the format described by the wiki (see
66+
// https://github.com/zmap/zgrab2/wiki/Scanner-details).
67+
// The mapping maps the bit mask value (i.e. a number of the form (1 << x)) to
68+
// the label for that bit.
69+
// Flags not present in mapping are appended to the unknown list.
70+
func FlagsToSet(flags uint64, mapping map[uint64]string) (map[string]bool, []uint64) {
71+
mapper := GetFlagMapFromMap(mapping)
72+
return MapFlagsToSet(flags, mapper)
73+
}
74+
75+
// ListFlagsToSet converts an integer flags variable to a set of string labels
76+
// corresponding to each bit, in the format described by the wiki (see
77+
// https://github.com/zmap/zgrab2/wiki/Scanner-details).
78+
// The ith entry of labels gives the label for the ith bit (i.e. flags & (1<<i)).
79+
// Empty strings in labels are treated as unknown, as are bits beyond the end
80+
// of the list. Unknown flags are appended to the unknown list.
81+
func ListFlagsToSet(flags uint64, labels []string) (map[string]bool, []uint64) {
82+
mapper := GetFlagMapFromList(labels)
83+
return MapFlagsToSet(flags, mapper)
84+
}
85+
86+
// WidenMapKeys8 copies a map with uint8 keys into an equivalent map with uint64
87+
// keys for use in the FlagsToSet function.
88+
func WidenMapKeys8(input map[uint8]string) map[uint64]string {
89+
ret := make(map[uint64]string, len(input))
90+
for k, v := range input {
91+
ret[uint64(k)] = v
92+
}
93+
return ret
94+
}
95+
96+
// WidenMapKeys16 copies a map with uint8 keys into an equivalent map with
97+
// uint64 keys for use in the FlagsToSet function.
98+
func WidenMapKeys16(input map[uint16]string) map[uint64]string {
99+
ret := make(map[uint64]string, len(input))
100+
for k, v := range input {
101+
ret[uint64(k)] = v
102+
}
103+
return ret
104+
}
105+
106+
// WidenMapKeys32 copies a map with uint8 keys into an equivalent map with
107+
// uint64 keys for use in the FlagsToSet function.
108+
func WidenMapKeys32(input map[uint32]string) map[uint64]string {
109+
ret := make(map[uint64]string, len(input))
110+
for k, v := range input {
111+
ret[uint64(k)] = v
112+
}
113+
return ret
114+
}
115+
116+
// WidenMapKeys copies a map with int keys into an equivalent map with uint64
117+
// keys for use in the FlagsToSet function.
118+
func WidenMapKeys(input map[int]string) map[uint64]string {
119+
ret := make(map[uint64]string, len(input))
120+
for k, v := range input {
121+
ret[uint64(k)] = v
122+
}
123+
return ret
124+
}

output_test.go

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package zgrab2
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
func ExampleMapFlagsToSet_success() {
8+
output, unknowns := MapFlagsToSet(0xb, func(bit uint64) (string, error) {
9+
return fmt.Sprintf("bit0x%01x", bit), nil
10+
})
11+
for k, v := range output {
12+
fmt.Printf("%s: %v\n", k, v)
13+
}
14+
for _, v := range unknowns {
15+
fmt.Printf("Unknown: 0x%01x", v)
16+
}
17+
// Unordered Output:
18+
// bit0x1: true
19+
// bit0x2: true
20+
// bit0x8: true
21+
}
22+
23+
func ExampleMapFlagsToSet_error() {
24+
output, unknowns := MapFlagsToSet(0x1b, func(bit uint64) (string, error) {
25+
if bit < 0x10 {
26+
return fmt.Sprintf("bit0x%01x", bit), nil
27+
} else {
28+
return "", fmt.Errorf("Unrecognized flag 0x%02x", bit)
29+
}
30+
})
31+
for k, v := range output {
32+
fmt.Printf("%s: %v\n", k, v)
33+
}
34+
for _, v := range unknowns {
35+
fmt.Printf("Unknown: 0x%02x", v)
36+
}
37+
// Unordered Output:
38+
// bit0x1: true
39+
// bit0x2: true
40+
// bit0x8: true
41+
// Unknown: 0x10
42+
}
43+
44+
func ExampleFlagsToSet() {
45+
output, unknowns := FlagsToSet(0x5, WidenMapKeys(map[int]string{
46+
0x1: "bit0",
47+
0x2: "bit1",
48+
0x8: "bit3",
49+
}))
50+
for k, v := range output {
51+
fmt.Printf("%s: %v\n", k, v)
52+
}
53+
for _, v := range unknowns {
54+
fmt.Printf("Unknown: 0x%01x", v)
55+
}
56+
// Unordered Output:
57+
// bit0: true
58+
// Unknown: 0x4
59+
}
60+
61+
func ExampleListFlagsToSet() {
62+
output, unknowns := ListFlagsToSet(0x5, []string{
63+
"bit0",
64+
"bit1",
65+
"",
66+
"bit3",
67+
})
68+
for k, v := range output {
69+
fmt.Printf("%s: %v\n", k, v)
70+
}
71+
for _, v := range unknowns {
72+
fmt.Printf("Unknown: 0x%01x", v)
73+
}
74+
// Unordered Output:
75+
// bit0: true
76+
// Unknown: 0x4
77+
}

0 commit comments

Comments
 (0)