Compare commits

...
Author SHA1 Message Date
Leonid Bugaev dc385c31f7 Fix raw socket ipv6 support 2016-05-25 13:53:52 +05:00
Leonid Bugaev 18dbb7e8ab Disable hanging test 2016-05-24 20:45:45 +05:00
Leonid Bugaev 89d22e685a fix build tags 2016-05-24 20:37:15 +05:00
Leonid Bugaev 7deac8d02d Do not use libpcap for windows 2016-05-24 20:27:51 +05:00
5 changed files with 236 additions and 199 deletions
+3
View File
@@ -67,6 +67,9 @@ run-2:
run-3:
sudo -E go run $(SOURCE) --input-tcp :27001 --output-stdout
run-4:
sudo -E go run $(SOURCE) --input-http 127.0.0.1:8081 --input-raw 127.0.0.1:8081 --output-stdout --input-raw-engine raw_socket
record:
$(RUN) go run $(SOURCE) --input-dummy=0 --output-file=requests.gor --verbose --debug
+5
View File
@@ -14,6 +14,7 @@ import (
"sync"
"testing"
"time"
"runtime"
)
func TestHTTPClientURLPort(t *testing.T) {
@@ -202,6 +203,10 @@ func TestHTTPClientHTTPSSend(t *testing.T) {
}
func TestHTTPClientServerInstantDisconnect(t *testing.T) {
if runtime.GOOS == "windows" {
return
}
wg := new(sync.WaitGroup)
GETPayload := []byte("GET / HTTP/1.1\r\n\r\n")
+23 -199
View File
@@ -16,9 +16,6 @@ import (
"bytes"
"encoding/binary"
"fmt"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"io"
"log"
"net"
@@ -32,6 +29,17 @@ import (
var _ = fmt.Println
type wrongCloser interface {
Close()
}
type wrongCloserProxy struct {
w wrongCloser
}
func (c wrongCloserProxy) Close() error {
c.w.Close()
return nil
}
// Listener handle traffic capture
type Listener struct {
mu sync.Mutex
@@ -63,8 +71,7 @@ type Listener struct {
trackResponse bool
messageExpire time.Duration
conn net.PacketConn
pcapHandles []*pcap.Handle
connHandles []io.Closer
quit chan bool
readyCh chan bool
@@ -112,6 +119,10 @@ func NewListener(addr string, port string, engine int, trackResponse bool, expir
// Special case for testing
if l.port != 0 {
if runtime.GOOS == "windows" {
engine = EngineRawSocket
}
switch engine {
case EngineRawSocket:
go l.readRAWSocket()
@@ -131,9 +142,7 @@ func (t *Listener) listen() {
for {
select {
case <-t.quit:
if t.conn != nil {
t.conn.Close()
}
t.Close()
return
case data := <-t.packetsChan:
packet := ParseTCPPacket(data[:16], data[16:])
@@ -217,195 +226,15 @@ func (t *Listener) dispatchMessage(message *TCPMessage) {
t.messagesChan <- message
}
// DeviceNotFoundError raised if user specified wrong ip
type DeviceNotFoundError struct {
addr string
}
func (e *DeviceNotFoundError) Error() string {
devices, _ := pcap.FindAllDevs()
if len(devices) == 0 {
return "Can't get list of network interfaces, ensure that you running Gor as root user or sudo.\nTo run as non-root users see this docs https://github.com/buger/gor/wiki/Running-as-non-root-user"
}
var msg string
msg += "Can't find interfaces with addr: " + e.addr + ". Provide available IP for intercepting traffic: \n"
for _, device := range devices {
msg += "Name: " + device.Name + "\n"
if device.Description != "" {
msg += "Description: " + device.Description + "\n"
}
for _, address := range device.Addresses {
msg += "- IP address: " + address.IP.String() + "\n"
}
}
return msg
}
func findPcapDevices(addr string) (interfaces []pcap.Interface, err error) {
devices, err := pcap.FindAllDevs()
if err != nil {
log.Fatal(err)
}
for _, device := range devices {
if (addr == "" || addr == "0.0.0.0" || addr == "[::]" || addr == "::") && len(device.Addresses) > 0 {
interfaces = append(interfaces, device)
continue
}
for _, address := range device.Addresses {
if device.Name == addr || address.IP.String() == addr {
interfaces = append(interfaces, device)
return interfaces, nil
}
}
}
if len(interfaces) == 0 {
return nil, &DeviceNotFoundError{addr}
} else {
return interfaces, nil
}
}
func (t *Listener) readPcap() {
devices, err := findPcapDevices(t.addr)
if err != nil {
log.Fatal(err)
}
bpfSupported := true
if runtime.GOOS == "darwin" {
bpfSupported = false
}
var wg sync.WaitGroup
wg.Add(len(devices))
for _, d := range devices {
go func(device pcap.Interface) {
handle, err := pcap.OpenLive(device.Name, 65536, true, t.messageExpire)
if err != nil {
log.Println("Pcap Error while opening device", device.Name, err)
wg.Done()
return
}
defer handle.Close()
t.mu.Lock()
t.pcapHandles = append(t.pcapHandles, handle)
if bpfSupported {
var bpf string
if t.trackResponse {
bpf = "tcp port " + strconv.Itoa(int(t.port))
} else {
bpf = "tcp dst port " + strconv.Itoa(int(t.port))
}
if err := handle.SetBPFFilter(bpf); err != nil {
log.Println("BPF filter error:", err, "Device:", device.Name)
wg.Done()
return
}
}
t.mu.Unlock()
linkType := handle.LinkType()
source := gopacket.NewPacketSource(handle, linkType)
source.Lazy = true
source.NoCopy = true
wg.Done()
var data, srcIP []byte
for {
packet, err := source.NextPacket()
if err == io.EOF {
break
} else if err != nil {
continue
}
if linkType == layers.LinkTypeEthernet {
// Skip ethernet layer, 14 bytes
data = packet.Data()[14:]
} else if linkType == layers.LinkTypeNull || linkType == layers.LinkTypeLoop {
data = packet.Data()[4:]
}
version := uint8(data[0]) >> 4
if version == 4 {
ihl := uint8(data[0]) & 0x0F
// Truncated IP info
if len(data) < int(ihl*4) {
continue
}
srcIP = data[12:16]
data = data[ihl*4:]
} else {
// Truncated IP info
if len(data) < 40 {
continue
}
srcIP = data[8:24]
data = data[40:]
}
// Truncated TCP info
if len(data) < 13 {
continue
}
dataOffset := (data[12] & 0xF0) >> 4
// We need only packets with data inside
// Check that the buffer is larger than the size of the TCP header
if len(data) > int(dataOffset*4) {
if !bpfSupported {
destPort := binary.BigEndian.Uint16(data[2:4])
srcPort := binary.BigEndian.Uint16(data[0:2])
// log.Println(t.port, destPort, srcPort, packet)
if !(destPort == t.port || (t.trackResponse && srcPort == t.port)) {
continue
}
}
newBuf := make([]byte, len(data)+16)
copy(newBuf[:16], srcIP)
copy(newBuf[16:], data)
t.packetsChan <- newBuf
}
}
}(d)
}
wg.Wait()
t.readyCh <- true
}
func (t *Listener) readRAWSocket() {
conn, e := net.ListenPacket("ip4:tcp", t.addr)
t.conn = conn
conn, e := net.ListenPacket("ip:tcp", t.addr)
t.connHandles = append(t.connHandles, conn)
if e != nil {
log.Fatal(e)
}
defer t.conn.Close()
defer conn.Close()
buf := make([]byte, 64*1024) // 64kb
@@ -413,7 +242,7 @@ func (t *Listener) readRAWSocket() {
for {
// Note: ReadFrom receive messages without IP header
n, addr, err := t.conn.ReadFrom(buf)
n, addr, err := conn.ReadFrom(buf)
if err != nil {
if strings.HasSuffix(err.Error(), "closed network connection") {
@@ -425,7 +254,7 @@ func (t *Listener) readRAWSocket() {
if n > 0 {
if t.isValidPacket(buf[:n]) {
newBuf := make([]byte, n+4)
newBuf := make([]byte, n+16)
copy(newBuf[16:], buf[:n])
copy(newBuf[:16], []byte(addr.(*net.IPAddr).IP))
@@ -618,12 +447,7 @@ func (t *Listener) Receiver() chan *TCPMessage {
}
func (t *Listener) Close() {
close(t.quit)
if t.conn != nil {
t.conn.Close()
}
for _, h := range t.pcapHandles {
for _, h := range t.connHandles {
h.Close()
}
+196
View File
@@ -0,0 +1,196 @@
// +build !windows
package rawSocket
import (
"runtime"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"log"
"io"
"sync"
"strconv"
"encoding/binary"
)
// DeviceNotFoundError raised if user specified wrong ip
type DeviceNotFoundError struct {
addr string
}
func (e *DeviceNotFoundError) Error() string {
devices, _ := pcap.FindAllDevs()
if len(devices) == 0 {
return "Can't get list of network interfaces, ensure that you running Gor as root user or sudo.\nTo run as non-root users see this docs https://github.com/buger/gor/wiki/Running-as-non-root-user"
}
var msg string
msg += "Can't find interfaces with addr: " + e.addr + ". Provide available IP for intercepting traffic: \n"
for _, device := range devices {
msg += "Name: " + device.Name + "\n"
if device.Description != "" {
msg += "Description: " + device.Description + "\n"
}
for _, address := range device.Addresses {
msg += "- IP address: " + address.IP.String() + "\n"
}
}
return msg
}
func findPcapDevices(addr string) (interfaces []pcap.Interface, err error) {
devices, err := pcap.FindAllDevs()
if err != nil {
log.Fatal(err)
}
for _, device := range devices {
if (addr == "" || addr == "0.0.0.0" || addr == "[::]" || addr == "::") && len(device.Addresses) > 0 {
interfaces = append(interfaces, device)
continue
}
for _, address := range device.Addresses {
if device.Name == addr || address.IP.String() == addr {
interfaces = append(interfaces, device)
return interfaces, nil
}
}
}
if len(interfaces) == 0 {
return nil, &DeviceNotFoundError{addr}
} else {
return interfaces, nil
}
}
func (t *Listener) readPcap() {
devices, err := findPcapDevices(t.addr)
if err != nil {
log.Fatal(err)
}
bpfSupported := true
if runtime.GOOS == "darwin" {
bpfSupported = false
}
var wg sync.WaitGroup
wg.Add(len(devices))
for _, d := range devices {
go func(device pcap.Interface) {
handle, err := pcap.OpenLive(device.Name, 65536, true, t.messageExpire)
if err != nil {
log.Println("Pcap Error while opening device", device.Name, err)
wg.Done()
return
}
defer handle.Close()
t.mu.Lock()
t.connHandles = append(t.connHandles, wrongCloserProxy{handle})
if bpfSupported {
var bpf string
if t.trackResponse {
bpf = "tcp port " + strconv.Itoa(int(t.port))
} else {
bpf = "tcp dst port " + strconv.Itoa(int(t.port))
}
if err := handle.SetBPFFilter(bpf); err != nil {
log.Println("BPF filter error:", err, "Device:", device.Name)
wg.Done()
return
}
}
t.mu.Unlock()
linkType := handle.LinkType()
source := gopacket.NewPacketSource(handle, linkType)
source.Lazy = true
source.NoCopy = true
wg.Done()
var data, srcIP []byte
for {
packet, err := source.NextPacket()
if err == io.EOF {
break
} else if err != nil {
continue
}
if linkType == layers.LinkTypeEthernet {
// Skip ethernet layer, 14 bytes
data = packet.Data()[14:]
} else if linkType == layers.LinkTypeNull || linkType == layers.LinkTypeLoop {
data = packet.Data()[4:]
}
version := uint8(data[0]) >> 4
if version == 4 {
ihl := uint8(data[0]) & 0x0F
// Truncated IP info
if len(data) < int(ihl*4) {
continue
}
srcIP = data[12:16]
data = data[ihl*4:]
} else {
// Truncated IP info
if len(data) < 40 {
continue
}
srcIP = data[8:24]
data = data[40:]
}
// Truncated TCP info
if len(data) < 13 {
continue
}
dataOffset := (data[12] & 0xF0) >> 4
// We need only packets with data inside
// Check that the buffer is larger than the size of the TCP header
if len(data) > int(dataOffset*4) {
if !bpfSupported {
destPort := binary.BigEndian.Uint16(data[2:4])
srcPort := binary.BigEndian.Uint16(data[0:2])
// log.Println(t.port, destPort, srcPort, packet)
if !(destPort == t.port || (t.trackResponse && srcPort == t.port)) {
continue
}
}
newBuf := make([]byte, len(data)+16)
copy(newBuf[:16], srcIP)
copy(newBuf[16:], data)
t.packetsChan <- newBuf
}
}
}(d)
}
wg.Wait()
t.readyCh <- true
}
+9
View File
@@ -0,0 +1,9 @@
// +build windows
package rawSocket
func (t *Listener) readPcap() {
panic("libpcap not implemented for windows")
}