-
Notifications
You must be signed in to change notification settings - Fork 15
/
scan_unix.go
173 lines (142 loc) · 3.77 KB
/
scan_unix.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//go:build linux || darwin
package gomasscan
import (
"fmt"
"io"
"net"
"sync"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/phayes/freeport"
)
func init() {
newScannerCallback = newScannerUnix
setupHandlerCallback = setupHandlerUnix
tcpReadWorkerPCAPCallback = tcpReadWorkerPCAPUnix
cleanupHandlersCallback = cleanupHandlersUnix
}
type Handlers struct {
Active []*pcap.Handle
Inactive []*pcap.InactiveHandle
}
func newScannerUnix(scanner *Scanner) error {
rawPort, err := freeport.GetFreePort()
if err != nil {
return err
}
scanner.listenPort = rawPort
tcpConn, err := net.ListenIP("ip4:tcp", &net.IPAddr{IP: net.ParseIP(fmt.Sprintf("0.0.0.0:%d", rawPort))})
if err != nil {
return err
}
scanner.tcpPacketListener = tcpConn
var handlers Handlers
scanner.handlers = handlers
scanner.tcpResultChan = make(chan *PkgResult, chanSize)
scanner.tcpPacketSend = make(chan *PkgSend, packetSendSize)
return nil
}
func setupHandlerUnix(s *Scanner, interfaceName string) error {
inactive, err := pcap.NewInactiveHandle(interfaceName)
if err != nil {
return err
}
err = inactive.SetSnapLen(snapLength)
if err != nil {
return err
}
readTimeout := time.Duration(readTimeout) * time.Millisecond
if err = inactive.SetTimeout(readTimeout); err != nil {
s.cleanupHandlers()
return err
}
err = inactive.SetImmediateMode(true)
if err != nil {
return err
}
handlers := s.handlers
handlers.Inactive = append(handlers.Inactive, inactive)
handle, err := inactive.Activate()
if err != nil {
s.cleanupHandlers()
return err
}
handlers.Active = append(handlers.Active, handle)
// Strict BPF filter
// + Packets coming from target ip
// + Destination port equals to sender socket source port
err = handle.SetBPFFilter(fmt.Sprintf("tcp and dst port %d and tcp[13]=18", s.listenPort))
if err != nil {
s.cleanupHandlers()
return err
}
s.handlers = handlers
return nil
}
func tcpReadWorkerPCAPUnix(s *Scanner) {
defer s.cleanupHandlers()
var wgread sync.WaitGroup
handlers := s.handlers
for _, handler := range handlers.Active {
wgread.Add(1)
go func(handler *pcap.Handle) {
defer wgread.Done()
var (
eth layers.Ethernet
ip4 layers.IPv4
tcp layers.TCP
)
// Interfaces with MAC (Physical + Virtualized)
parserMac := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, ð, &ip4, &tcp)
// Interfaces without MAC (TUN/TAP)
parserNoMac := gopacket.NewDecodingLayerParser(layers.LayerTypeIPv4, &ip4, &tcp)
var parsers []*gopacket.DecodingLayerParser
parsers = append(parsers, parserMac, parserNoMac)
var decoded []gopacket.LayerType
for {
data, _, err := handler.ReadPacketData()
if err != nil {
if err == io.EOF {
break
}
continue
}
for _, parser := range parsers {
if err := parser.DecodeLayers(data, &decoded); err != nil {
continue
}
for _, layerType := range decoded {
if layerType != layers.LayerTypeTCP {
continue
}
if s.ipRanger.Contains(ip4.SrcIP.String()) == false {
//gologger.Debug().Msgf("Discarding TCP packet from non target ip %s\n", ip4.SrcIP.String())
continue
}
if tcp.DstPort != layers.TCPPort(s.listenPort) {
continue
}
// We consider only incoming packets
if tcp.ACK == false || tcp.SYN == false {
continue
}
s.tcpResultChan <- &PkgResult{ip: ip4.SrcIP.String(), port: int(tcp.SrcPort)}
}
}
}
}(handler)
}
wgread.Wait()
}
// cleanupHandlers for all interfaces
func cleanupHandlersUnix(s *Scanner) {
handler := s.handlers
for _, handler := range handler.Active {
handler.Close()
}
for _, inactiveHandler := range handler.Inactive {
inactiveHandler.CleanUp()
}
}