Skip to content

Commit

Permalink
Merge pull request #5 from v-byte-cpu/Integrate_golang_linters
Browse files Browse the repository at this point in the history
Integrate golang linters
  • Loading branch information
v-byte-cpu committed Mar 10, 2021
2 parents fe0399c + 8151f29 commit 18567d6
Show file tree
Hide file tree
Showing 17 changed files with 289 additions and 219 deletions.
10 changes: 10 additions & 0 deletions .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ clone:
depth: 1

steps:
- name: lint
image: golangci/golangci-lint:v1.38
commands:
- apt-get update
- apt-get install -y libpcap-dev
- golangci-lint run -v
# go 1.16 install doesn't modify go.mod and go.sum
- go install github.com/mgechev/revive@v1.0.3
- revive -config .revive.toml -formatter friendly ./...

- name: test
image: golang:1.16
commands:
Expand Down
31 changes: 31 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
linters:
enable:
- dogsled
- exportloopref
- funlen
- gocognit
- goconst
- gocritic
- gocyclo
- gofmt
- goimports
- golint
- gosec
- govet
- misspell
- nestif
- prealloc
- unconvert
- unparam

run:
timeout: 3m

issues:
exclude-rules:
- linters:
- gosec
text: "G404"
- linters:
- funlen
path: _test\.go
45 changes: 45 additions & 0 deletions .revive.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 1
warningCode = 1

#Recommended rules
[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.error-return]
[rule.error-strings]
[rule.error-naming]
[rule.if-return]
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]
[rule.unexported-return]
[rule.indent-error-flow]
[rule.errorf]
[rule.empty-block]
[rule.superfluous-else]
[rule.unused-parameter]
[rule.unreachable-code]
[rule.redefines-builtin-id]

#Custom rules
[rule.modifies-parameter]
[rule.unnecessary-stmt]
[rule.confusing-naming]
[rule.modifies-value-receiver]
[rule.range-val-in-closure]
[rule.range-val-address]
[rule.waitgroup-by-value]
[rule.atomic]
[rule.unused-receiver]
[rule.early-return]
[rule.unconditional-recursion]
[rule.identical-branches]
[rule.defer]
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# sx

[![Build Status](https://cloud.drone.io/api/badges/v-byte-cpu/sx/status.svg)](https://cloud.drone.io/v-byte-cpu/sx)
[![GoReportCard Status](https://goreportcard.com/badge/github.com/v-byte-cpu/sx)](https://goreportcard.com/report/github.com/v-byte-cpu/sx)

The goal of this project is to create the fastest network scanner with clean and simple code.

Expand Down
43 changes: 28 additions & 15 deletions command/arp.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,39 @@ var arpCmd = &cobra.Command{
}
}

r := &scan.Range{Subnet: dstSubnet, Interface: iface, SrcIP: srcIP, SrcMAC: srcMAC}
r := &scan.Range{Subnet: dstSubnet, Interface: iface, SrcIP: srcIP.To4(), SrcMAC: srcMAC}
return startEngine(r)
},
}

func startEngine(r *scan.Range) error {
func logResults(logger *zap.Logger, results <-chan *arp.ScanResult) {
bw := bufio.NewWriter(os.Stdout)
defer bw.Flush()
for result := range results {
// TODO refactor it using logger facade interface
if jsonFlag {
data, err := result.MarshalJSON()
if err != nil {
logger.Error("arp", zap.Error(err))
}
_, err = bw.Write(data)
if err != nil {
logger.Error("arp", zap.Error(err))
}
} else {
_, err := bw.WriteString(result.String())
if err != nil {
logger.Error("arp", zap.Error(err))
}
}
err := bw.WriteByte('\n')
if err != nil {
logger.Error("arp", zap.Error(err))
}
}
}

func startEngine(r *scan.Range) error {
logger, err := zap.NewProduction()
if err != nil {
return err
Expand All @@ -108,19 +133,7 @@ func startEngine(r *scan.Range) error {
wg.Add(1)
go func() {
defer wg.Done()
for result := range m.Results() {
// TODO extract it
if jsonFlag {
data, err := result.MarshalJSON()
if err != nil {
logger.Error("arp", zap.Error(err))
}
bw.Write(data)
} else {
bw.WriteString(result.String())
}
bw.WriteByte('\n')
}
logResults(logger, m.Results())
}()

// start scan
Expand Down
16 changes: 8 additions & 8 deletions pkg/packet/afpacket/readwriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,25 @@ import (
"golang.org/x/net/bpf"
)

type AfPacketSource struct {
type Source struct {
handle *afp.TPacket
}

// Assert that AfPacketSource conforms to the packet.ReadWriter interface
var _ packet.ReadWriter = (*AfPacketSource)(nil)
var _ packet.ReadWriter = (*Source)(nil)

func NewPacketSource(iface string) (*AfPacketSource, error) {
func NewPacketSource(iface string) (*Source, error) {
handle, err := afp.NewTPacket(afp.SocketRaw, afp.OptInterface(iface))
if err != nil {
return nil, err
}
return &AfPacketSource{handle}, nil
return &Source{handle}, nil
}

// maxPacketLength is the maximum size of packets to capture in bytes.
// pcap calls it "snaplen" and default value used in tcpdump is 262144 bytes,
// that is redundant for most scans, see pcap(3) and tcpdump(1) for more info
func (s *AfPacketSource) SetBPFFilter(bpfFilter string, maxPacketLength int) error {
func (s *Source) SetBPFFilter(bpfFilter string, maxPacketLength int) error {
pcapBPF, err := pcap.CompileBPFFilter(layers.LinkTypeEthernet, maxPacketLength, bpfFilter)
if err != nil {
return err
Expand All @@ -45,15 +45,15 @@ func (s *AfPacketSource) SetBPFFilter(bpfFilter string, maxPacketLength int) err
return s.handle.SetBPF(bpfIns)
}

func (s *AfPacketSource) Close() {
func (s *Source) Close() {
s.handle.Close()
}

func (s *AfPacketSource) ReadPacketData() ([]byte, *gopacket.CaptureInfo, error) {
func (s *Source) ReadPacketData() ([]byte, *gopacket.CaptureInfo, error) {
data, ci, err := s.handle.ZeroCopyReadPacketData()
return data, &ci, err
}

func (s *AfPacketSource) WritePacketData(pkt []byte) error {
func (s *Source) WritePacketData(pkt []byte) error {
return s.handle.WritePacketData(pkt)
}
46 changes: 23 additions & 23 deletions pkg/packet/receiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,31 +61,31 @@ func (r *receiver) ReceivePackets(ctx context.Context) <-chan error {
case <-ctx.Done():
return
default:
data, ci, err := r.sr.ReadPacketData()
if err != nil {
// Immediately retry for temporary errors
if isTemporaryError(err) {
continue
}
if isUnrecoverableError(err) {
return
}
// Log unknown error
select {
case <-ctx.Done():
return
case errc <- err:
}
// Sleep briefly and try again
time.Sleep(time.Millisecond * time.Duration(5))
}
data, ci, err := r.sr.ReadPacketData()
if err != nil {
// Immediately retry for temporary errors
if isTemporaryError(err) {
continue
}
if err := r.p.ProcessPacketData(data, ci); err != nil {
select {
case <-ctx.Done():
return
case errc <- err:
}
if isUnrecoverableError(err) {
return
}
// Log unknown error
select {
case <-ctx.Done():
return
case errc <- err:
}
// Sleep briefly and try again
time.Sleep(5 * time.Millisecond)
continue
}
if err := r.p.ProcessPacketData(data, ci); err != nil {
select {
case <-ctx.Done():
return
case errc <- err:
}
}
}
Expand Down
25 changes: 12 additions & 13 deletions pkg/packet/receiver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"net"
"syscall"
"testing"
"time"

"github.com/golang/mock/gomock"
"github.com/google/gopacket"
Expand Down Expand Up @@ -64,8 +63,8 @@ func TestReceivePacketsWithUnrecoverableError(t *testing.T) {
p := NewMockProcessor(ctrl)
r := NewReceiver(sr, p)

out := chanErrToGeneric(r.ReceivePackets(context.Background()))
result := chanToSlice(t, out, 0, 3*time.Second)
out := r.ReceivePackets(context.Background())
result := chanToSlice(t, chanErrToGeneric(out), 0)
assert.Equal(t, 0, len(result), "error slice is not empty")
})
}
Expand All @@ -90,8 +89,8 @@ func TestReceivePacketsOnePacket(t *testing.T) {
ProcessPacketData(expectedData, newCaptureInfo()).Return(nil)
r := NewReceiver(sr, p)

out := chanErrToGeneric(r.ReceivePackets(context.Background()))
result := chanToSlice(t, out, 0, 3*time.Second)
out := r.ReceivePackets(context.Background())
result := chanToSlice(t, chanErrToGeneric(out), 0)
assert.Equal(t, 0, len(result), "error slice is not empty")
}

Expand All @@ -113,8 +112,8 @@ func TestReceivePacketsOnePacketWithProcessError(t *testing.T) {
ProcessPacketData(notNil, notNil).Return(errors.New("process error"))
r := NewReceiver(sr, p)

out := chanErrToGeneric(r.ReceivePackets(context.Background()))
result := chanToSlice(t, out, 1, 3*time.Second)
out := r.ReceivePackets(context.Background())
result := chanToSlice(t, chanErrToGeneric(out), 1)
assert.Equal(t, 1, len(result), "error slice is invalid")
assert.Error(t, result[0].(error))
}
Expand Down Expand Up @@ -157,8 +156,8 @@ func TestReceivePacketsOnePacketWithRetryError(t *testing.T) {
ProcessPacketData(expectedData, newCaptureInfo()).Return(nil)
r := NewReceiver(sr, p)

out := chanErrToGeneric(r.ReceivePackets(context.Background()))
result := chanToSlice(t, out, 0, 3*time.Second)
out := r.ReceivePackets(context.Background())
result := chanToSlice(t, chanErrToGeneric(out), 0)
assert.Equal(t, 0, len(result), "error slice is not empty")
})
}
Expand All @@ -184,8 +183,8 @@ func TestReceivePacketsOnePacketWithUnknownError(t *testing.T) {
ProcessPacketData(expectedData, newCaptureInfo()).Return(nil)
r := NewReceiver(sr, p)

out := chanErrToGeneric(r.ReceivePackets(context.Background()))
result := chanToSlice(t, out, 1, 3*time.Second)
out := r.ReceivePackets(context.Background())
result := chanToSlice(t, chanErrToGeneric(out), 1)
assert.Equal(t, 1, len(result), "error slice length is invalid")
assert.Error(t, result[0].(error))
}
Expand All @@ -211,7 +210,7 @@ func TestReceivePacketsOnePacketWithContextCancel(t *testing.T) {
})
r := NewReceiver(sr, p)

out := chanErrToGeneric(r.ReceivePackets(ctx))
result := chanToSlice(t, out, 0, 3*time.Second)
out := r.ReceivePackets(ctx)
result := chanToSlice(t, chanErrToGeneric(out), 0)
assert.Equal(t, 0, len(result), "error slice is not empty")
}
Loading

0 comments on commit 18567d6

Please sign in to comment.