1
1
package main
2
2
3
3
import (
4
+ "encoding/binary"
4
5
"net"
5
- "strings"
6
6
"sync"
7
7
"time"
8
8
@@ -16,15 +16,16 @@ const SendBufferSize = 100
16
16
17
17
// Struct containing everything for an interface
18
18
type Listen struct {
19
- iname string // interface to use
20
- iface * net.Interface // interface descriptor
21
- filter string // bpf filter string to listen on
22
- ports []int32 // port(s) we listen for packets
23
- ipaddr string // dstip we send packets to
24
- promisc bool // do we enable promisc on this interface?
25
- handle * pcap.Handle
26
- timeout time.Duration
27
- sendpkt chan Send // channel used to recieve packets we need to send
19
+ iname string // interface to use
20
+ netif * net.Interface // interface descriptor
21
+ ports []int32 // port(s) we listen for packets
22
+ ipaddr string // dstip we send packets to
23
+ promisc bool // do we enable promisc on this interface?
24
+ handle * pcap.Handle // gopacket.pcap handle
25
+ timeout time.Duration // timeout for loop
26
+ clientTTL time.Duration // ttl for client cache
27
+ sendpkt chan Send // channel used to recieve packets we need to send
28
+ clients map [string ]time.Time // keep track of clients for non-promisc interfaces
28
29
}
29
30
30
31
// List of LayerTypes we support in sendPacket()
@@ -34,61 +35,52 @@ var validLinkTypes = []layers.LinkType{
34
35
layers .LinkTypeNull ,
35
36
}
36
37
37
- // takes the list of listen or promisc and returns a list of Listen
38
- // which then can be initialized
39
- func processListener (interfaces * []string , lp []string , bpf_filter string , ports []int32 , to time.Duration ) []Listen {
40
- var ret = []Listen {}
41
- for _ , i := range lp {
42
- s := strings .Split (i , "@" )
43
- if len (s ) != 2 {
44
- log .Fatalf ("%s is invalid. Expected: <interface>@<ipaddr>" , i )
45
- }
46
- iname := s [0 ]
47
- ipaddr := s [1 ]
48
-
49
- iname_prefix := iname + "@"
50
- if stringPrefixInSlice (iname_prefix , * interfaces ) {
51
- log .Fatalf ("Can't specify the same interface (%s) multiple times" , iname )
52
- }
53
- * interfaces = append (* interfaces , iname )
54
-
55
- netif , err := net .InterfaceByName (iname )
38
+ // Creates a Listen struct for the given interface, promisc mode, udp sniff ports and timeout
39
+ func newListener (netif * net.Interface , promisc bool , ports []int32 , to time.Duration ) Listen {
40
+ log .Debugf ("%s: ifIndex: %d" , netif .Name , netif .Index )
41
+ addrs , err := netif .Addrs ()
42
+ if err != nil {
43
+ log .Fatalf ("Unable to obtain addresses for %s" , netif .Name )
44
+ }
45
+ var bcastaddr string = ""
46
+ // only calc the broadcast address on promiscuous interfaces
47
+ // for non-promisc, we use our clients
48
+ if ! promisc {
49
+ for _ , addr := range addrs {
50
+ log .Debugf ("%s network: %s\t \t string: %s" , netif .Name , addr .Network (), addr .String ())
56
51
57
- if err != nil {
58
- log .Fatalf ("Unable to get network index for %s: %s" , iname , err )
52
+ _ , ipNet , err := net .ParseCIDR (addr .String ())
53
+ if err != nil {
54
+ log .Debugf ("%s: Unable to parse CIDR: %s (%s)" , netif .Name , addr .String (), addr .Network ())
55
+ continue
56
+ }
57
+ if ipNet .IP .To4 () == nil {
58
+ continue // Skip non-IPv4 addresses
59
+ }
60
+ // calc broadcast
61
+ ip := make (net.IP , len (ipNet .IP .To4 ()))
62
+ bcastbin := binary .BigEndian .Uint32 (ipNet .IP .To4 ()) | ^ binary .BigEndian .Uint32 (net .IP (ipNet .Mask ).To4 ())
63
+ binary .BigEndian .PutUint32 (ip , bcastbin )
64
+ bcastaddr = ip .String ()
59
65
}
60
- log .Debugf ("%s: ifIndex: %d" , iname , netif .Index )
61
-
62
- // check if interface has broadcast capabilities, when yes promisc = true
63
- hasBroadcast := (netif .Flags & net .FlagBroadcast ) != 0
64
-
65
- new := Listen {
66
- iname : iname ,
67
- iface : netif ,
68
- filter : bpf_filter ,
69
- ports : ports ,
70
- ipaddr : ipaddr ,
71
- timeout : to ,
72
- promisc : hasBroadcast ,
73
- handle : nil ,
74
- sendpkt : make (chan Send , SendBufferSize ),
66
+ // promisc interfaces should have a bcast/ipv4 config
67
+ if len (bcastaddr ) == 0 && promisc {
68
+ log .Fatalf ("%s does not have a valid IPv4 configuration" , netif .Name )
75
69
}
76
- ret = append (ret , new )
77
70
}
78
- return ret
79
- }
80
-
81
- // takes list of interfaces to listen on, if we should listen promiscuously,
82
- // the BPF filter, list of ports and timeout and returns a list of processListener
83
- func initializeListeners (inames []string , bpf_filter string , ports []int32 , timeout time.Duration ) []Listen {
84
- // process our promisc and listen interfaces
85
- var interfaces = []string {}
86
- var listeners []Listen
87
- a := processListener (& interfaces , inames , bpf_filter , ports , timeout )
88
- for _ , x := range a {
89
- listeners = append (listeners , x )
71
+ new := Listen {
72
+ iname : netif .Name ,
73
+ netif : netif ,
74
+ ports : ports ,
75
+ ipaddr : bcastaddr ,
76
+ timeout : to ,
77
+ promisc : promisc ,
78
+ handle : nil ,
79
+ sendpkt : make (chan Send , SendBufferSize ),
80
+ clients : make (map [string ]time.Time ),
90
81
}
91
- return listeners
82
+ log .Debugf ("Listen: %v" , new )
83
+ return new
92
84
}
93
85
94
86
// Our goroutine for processing packets
@@ -108,7 +100,7 @@ func (l *Listen) handlePackets(s *SendPktFeed, wg *sync.WaitGroup) {
108
100
for {
109
101
select {
110
102
case s := <- l .sendpkt : // packet arrived from another interface
111
- l .sendPacket (s )
103
+ l .sendPackets (s )
112
104
case packet := <- packets : // packet arrived on this interfaces
113
105
// is it legit?
114
106
if packet .NetworkLayer () == nil || packet .TransportLayer () == nil || packet .TransportLayer ().LayerType () != layers .LayerTypeUDP {
@@ -118,16 +110,28 @@ func (l *Listen) handlePackets(s *SendPktFeed, wg *sync.WaitGroup) {
118
110
log .Errorf ("%s: Unable to decode: %s" , l .iname , errx .Error ())
119
111
}
120
112
113
+ // if our interface is non-promisc, learn the client IP
114
+ if l .promisc {
115
+ l .learnClientIP (packet )
116
+ }
117
+
121
118
log .Debugf ("%s: received packet and fowarding onto other interfaces" , l .iname )
122
119
s .Send (packet , l .iname , l .handle .LinkType ())
123
120
case <- ticker : // our timer
124
121
log .Debugf ("handlePackets(%s) ticker" , l .iname )
122
+ // clean client cache
123
+ for k , v := range l .clients {
124
+ if v .Before (time .Now ()) {
125
+ log .Debugf ("%s removing %s after %dsec" , l .iname , k , l .clientTTL )
126
+ delete (l .clients , k )
127
+ }
128
+ }
125
129
}
126
130
}
127
131
}
128
132
129
133
// Does the heavy lifting of editing & sending the packet onwards
130
- func (l * Listen ) sendPacket (sndpkt Send ) {
134
+ func (l * Listen ) sendPackets (sndpkt Send ) {
131
135
var eth layers.Ethernet
132
136
var loop layers.Loopback // BSD NULL/Loopback used for OpenVPN tunnels/etc
133
137
var ip4 layers.IPv4 // we only support v4
@@ -146,7 +150,6 @@ func (l *Listen) sendPacket(sndpkt Send) {
146
150
parser = gopacket .NewDecodingLayerParser (layers .LayerTypeEthernet , & eth , & ip4 , & udp , & payload )
147
151
default :
148
152
log .Fatalf ("Unsupported source linktype: 0x%02x" , sndpkt .linkType )
149
- return
150
153
}
151
154
152
155
// try decoding our packet
@@ -156,7 +159,7 @@ func (l *Listen) sendPacket(sndpkt Send) {
156
159
return
157
160
}
158
161
159
- // packet was decoded
162
+ // was packet decoded? In theory, this should never happen because our BPF filter...
160
163
found_udp := false
161
164
found_ipv4 := false
162
165
for _ , layerType := range decoded {
@@ -172,6 +175,27 @@ func (l *Listen) sendPacket(sndpkt Send) {
172
175
return
173
176
}
174
177
178
+ if ! l .promisc {
179
+ // send one packet to broadcast IP
180
+ dstip := net .ParseIP (l .ipaddr ).To4 ()
181
+ if err , bytes := l .sendPacket (dstip , eth , loop , ip4 , udp , payload ); err != nil {
182
+ log .Warnf ("Unable to send %d bytes from %s out %s: %s" ,
183
+ bytes , sndpkt .srcif , l .iname , err )
184
+ }
185
+ } else {
186
+ // sent packet to every client
187
+ for ip , _ := range l .clients {
188
+ dstip := net .ParseIP (ip ).To4 ()
189
+ if err , bytes := l .sendPacket (dstip , eth , loop , ip4 , udp , payload ); err != nil {
190
+ log .Warnf ("Unable to send %d bytes from %s out %s: %s" ,
191
+ bytes , sndpkt .srcif , l .iname , err )
192
+ }
193
+ }
194
+ }
195
+ }
196
+
197
+ func (l * Listen ) sendPacket (dstip net.IP , eth layers.Ethernet , loop layers.Loopback ,
198
+ ip4 layers.IPv4 , udp layers.UDP , payload gopacket.Payload ) (error , int ) {
175
199
// Build our packet to send
176
200
buffer := gopacket .NewSerializeBuffer ()
177
201
csum_opts := gopacket.SerializeOptions {
@@ -215,15 +239,15 @@ func (l *Listen) sendPacket(sndpkt Send) {
215
239
Protocol : ip4 .Protocol ,
216
240
Checksum : 0 , // reset to calc checksums
217
241
SrcIP : ip4 .SrcIP ,
218
- DstIP : net . ParseIP ( l . ipaddr ). To4 () ,
242
+ DstIP : dstip ,
219
243
Options : ip4 .Options ,
220
244
}
221
245
if err := new_ip4 .SerializeTo (buffer , csum_opts ); err != nil {
222
246
log .Fatalf ("can't serialize IP header: %v" , new_ip4 )
223
247
}
224
248
225
249
// Loopback or Ethernet
226
- if (l .iface .Flags & net .FlagLoopback ) > 0 {
250
+ if (l .netif .Flags & net .FlagLoopback ) > 0 {
227
251
loop := layers.Loopback {
228
252
Family : layers .ProtocolFamilyIPv4 ,
229
253
}
@@ -235,7 +259,7 @@ func (l *Listen) sendPacket(sndpkt Send) {
235
259
new_eth := layers.Ethernet {
236
260
BaseLayer : layers.BaseLayer {},
237
261
DstMAC : net.HardwareAddr {0xff , 0xff , 0xff , 0xff , 0xff , 0xff },
238
- SrcMAC : l .iface .HardwareAddr ,
262
+ SrcMAC : l .netif .HardwareAddr ,
239
263
EthernetType : layers .EthernetTypeIPv4 ,
240
264
}
241
265
if err := new_eth .SerializeTo (buffer , opts ); err != nil {
@@ -244,11 +268,45 @@ func (l *Listen) sendPacket(sndpkt Send) {
244
268
}
245
269
246
270
outgoingPacket := buffer .Bytes ()
247
- log .Debugf ("%s: packet len: %d: %v" , l .iname , len (outgoingPacket ), outgoingPacket )
248
- err := l .handle .WritePacketData (outgoingPacket )
249
- if err != nil {
250
- log .Warnf ("Unable to send %d bytes from %s out %s: %s" ,
251
- len (outgoingPacket ), sndpkt .srcif , l .iname , err )
271
+ log .Debugf ("%s => %s: packet len: %d: %v" , l .iname , dstip .String (), len (outgoingPacket ), outgoingPacket )
272
+ return l .handle .WritePacketData (outgoingPacket ), len (outgoingPacket )
273
+ }
274
+
275
+ func (l * Listen ) learnClientIP (packet gopacket.Packet ) {
276
+ var eth layers.Ethernet
277
+ var loop layers.Loopback
278
+ var ip4 layers.IPv4
279
+ var udp layers.UDP
280
+ var payload gopacket.Payload
281
+ var parser * gopacket.DecodingLayerParser
282
+
283
+ switch l .handle .LinkType () {
284
+ case layers .LinkTypeNull :
285
+ parser = gopacket .NewDecodingLayerParser (layers .LayerTypeLoopback , & loop , & ip4 , & udp , & payload )
286
+ case layers .LinkTypeLoop :
287
+ parser = gopacket .NewDecodingLayerParser (layers .LayerTypeLoopback , & loop , & ip4 , & udp , & payload )
288
+ case layers .LinkTypeEthernet :
289
+ parser = gopacket .NewDecodingLayerParser (layers .LayerTypeEthernet , & eth , & ip4 , & udp , & payload )
290
+ default :
291
+ log .Fatalf ("Unsupported source linktype: 0x%02x" , l .handle .LinkType ())
292
+ }
293
+
294
+ decoded := []gopacket.LayerType {}
295
+ if err := parser .DecodeLayers (packet .Data (), & decoded ); err != nil {
296
+ log .Debugf ("Unable to decoded client IP on %s: %s" , l .iname , err )
297
+ }
298
+
299
+ found_ipv4 := false
300
+ for _ , layerType := range decoded {
301
+ switch layerType {
302
+ case layers .LayerTypeIPv4 :
303
+ // found our v4 header
304
+ found_ipv4 = true
305
+ }
306
+ }
307
+
308
+ if found_ipv4 {
309
+ l .clients [ip4 .SrcIP .String ()] = time .Now ().Add (l .clientTTL )
252
310
}
253
311
}
254
312
0 commit comments