Skip to content

Commit e75f9ff

Browse files
authored
feature: randomized port iterator (#90)
1 parent c3c93c7 commit e75f9ff

File tree

5 files changed

+248
-249
lines changed

5 files changed

+248
-249
lines changed

pkg/ip/ip.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,6 @@ import (
88

99
var ErrInvalidAddr = errors.New("invalid IP subnet/host")
1010

11-
func Inc(ip net.IP) {
12-
for j := len(ip) - 1; j >= 0; j-- {
13-
ip[j]++
14-
if ip[j] > 0 {
15-
break
16-
}
17-
}
18-
}
19-
20-
func DupIP(ip net.IP) net.IP {
21-
dup := make([]byte, 4)
22-
copy(dup, ip.To4())
23-
return dup
24-
}
25-
2611
func ParseIPNet(subnet string) (*net.IPNet, error) {
2712
_, result, err := net.ParseCIDR(subnet)
2813
if err == nil {

pkg/ip/ip_test.go

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,56 +7,6 @@ import (
77
"github.com/stretchr/testify/assert"
88
)
99

10-
func TestInc(t *testing.T) {
11-
t.Parallel()
12-
tests := []struct {
13-
name string
14-
input net.IP
15-
expected net.IP
16-
}{
17-
{
18-
name: "ZeroNet",
19-
input: net.IPv4(0, 0, 0, 0),
20-
expected: net.IPv4(0, 0, 0, 1),
21-
},
22-
{
23-
name: "Inc3rd",
24-
input: net.IPv4(1, 1, 0, 255),
25-
expected: net.IPv4(1, 1, 1, 0),
26-
},
27-
{
28-
name: "Inc2nd",
29-
input: net.IPv4(1, 1, 255, 255),
30-
expected: net.IPv4(1, 2, 0, 0),
31-
},
32-
{
33-
name: "Inc1st",
34-
input: net.IPv4(1, 255, 255, 255),
35-
expected: net.IPv4(2, 0, 0, 0),
36-
},
37-
}
38-
39-
for _, vtt := range tests {
40-
tt := vtt
41-
t.Run(tt.name, func(t *testing.T) {
42-
t.Parallel()
43-
Inc(tt.input)
44-
assert.Equal(t, tt.expected, tt.input)
45-
})
46-
}
47-
}
48-
49-
func TestDupIP(t *testing.T) {
50-
t.Parallel()
51-
ipAddr := net.IPv4(192, 168, 0, 1).To4()
52-
53-
dupAddr := DupIP(ipAddr)
54-
assert.Equal(t, ipAddr, dupAddr)
55-
56-
dupAddr[3]++
57-
assert.Equal(t, net.IPv4(192, 168, 0, 1).To4(), ipAddr)
58-
}
59-
6010
func TestParseIPNetWithError(t *testing.T) {
6111
t.Parallel()
6212
_, err := ParseIPNet("")

pkg/scan/mock_request_test.go

Lines changed: 18 additions & 56 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/scan/request.go

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:generate mockgen -package scan -destination=mock_request_test.go -source request.go
1+
//go:generate mockgen -package scan -destination=mock_request_test.go . PortGenerator,IPGenerator,RequestGenerator,IPContainer
22
//go:generate easyjson -output_filename request_easyjson.go request.go
33

44
package scan
@@ -31,37 +31,67 @@ type Request struct {
3131
Err error
3232
}
3333

34+
type PortGetter interface {
35+
GetPort() (uint16, error)
36+
}
37+
38+
type WrapPort uint16
39+
40+
func (p WrapPort) GetPort() (uint16, error) {
41+
return uint16(p), nil
42+
}
43+
44+
type portError struct {
45+
error
46+
}
47+
48+
func (err *portError) GetPort() (uint16, error) {
49+
return 0, err
50+
}
51+
3452
type PortGenerator interface {
35-
Ports(ctx context.Context, r *Range) (<-chan uint16, error)
53+
Ports(ctx context.Context, r *Range) (<-chan PortGetter, error)
3654
}
3755

3856
func NewPortGenerator() PortGenerator {
3957
return &portGenerator{}
4058
}
4159

42-
// TODO randomizedPortGenerator
4360
type portGenerator struct{}
4461

45-
func (*portGenerator) Ports(ctx context.Context, r *Range) (<-chan uint16, error) {
62+
func (*portGenerator) Ports(ctx context.Context, r *Range) (<-chan PortGetter, error) {
4663
if err := validatePorts(r.Ports); err != nil {
4764
return nil, err
4865
}
49-
out := make(chan uint16, 100)
66+
out := make(chan PortGetter, 100)
5067
go func() {
5168
defer close(out)
5269
for _, portRange := range r.Ports {
53-
for port := int(portRange.StartPort); port <= int(portRange.EndPort); port++ {
54-
select {
55-
case <-ctx.Done():
56-
return
57-
case out <- uint16(port):
70+
it, err := newRangeIterator(int64(portRange.EndPort) - int64(portRange.StartPort) + 1)
71+
if err != nil {
72+
writePort(ctx, out, &portError{err})
73+
continue
74+
}
75+
basePort := int64(portRange.StartPort) - 1
76+
for {
77+
writePort(ctx, out, WrapPort(basePort+it.Int().Int64()))
78+
if !it.Next() {
79+
break
5880
}
5981
}
6082
}
6183
}()
6284
return out, nil
6385
}
6486

87+
func writePort(ctx context.Context, out chan<- PortGetter, port PortGetter) {
88+
select {
89+
case <-ctx.Done():
90+
return
91+
case out <- port:
92+
}
93+
}
94+
6595
func validatePorts(ports []*PortRange) error {
6696
if len(ports) == 0 {
6797
return ErrPortRange
@@ -153,7 +183,12 @@ func (rg *ipPortGenerator) GenerateRequests(ctx context.Context, r *Range) (<-ch
153183
out := make(chan *Request, 100)
154184
go func() {
155185
defer close(out)
156-
for port := range ports {
186+
for p := range ports {
187+
port, err := p.GetPort()
188+
if err != nil {
189+
writeRequest(ctx, out, &Request{Err: err})
190+
continue
191+
}
157192
for ipaddr := range ips {
158193
dstip, err := ipaddr.GetIP()
159194
writeRequest(ctx, out, &Request{

0 commit comments

Comments
 (0)