mirror of
https://github.com/buger/goreplay.git
synced 2024-04-21 12:32:02 +00:00
Added support for capturing virtualized traffic. ## VXLAN https://en.wikipedia.org/wiki/Virtual_Extensible_LAN VXLAN implemented as separate engine, which opens UDP socket and awaits traffic. This approach is made to work with AWS Traffic Mirroring. In order to enable VXLAN set `--input-raw-engine vxlan` Example: ``` gor --input-raw :80 --input-raw-engine vxlan --output-stdout` ``` By default, it looks for vxlan traffic on the standard 4789 port, but you can override it with `--input-raw-vxlan-port`. Additionally, you can allow only specific VNIs using `--input-raw-vxlan-vni`, or disallow by using the same option, but by adding "minus" sign to the value: `--input-raw-vxlan-vni -2`. Example with all options: ``` gor --input-raw :80 --input-raw-engine vxlan --input-raw-vxlan-vni 1 --input-raw-vxlan-vni 2 --input-raw-vxlan-port 2222 --output-stdout ``` # VLAN https://en.wikipedia.org/wiki/IEEE_802.1Q VLAN protocol enabled using `--input-raw-vlan` argument, and you can filter for specific VLAN VIDs using `--input-raw-vlan-vid`. VLAN filtering happens on BPF level. Example: ``` gor --input-raw :80 --input-raw-vlan --input-raw-vlan-vid 1 --output-stdout` ``` ## Notes Did a refactoring of RAW Input options, so it will be easy to extend in future.
101 lines
2.0 KiB
Go
101 lines
2.0 KiB
Go
package capture
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"github.com/google/gopacket"
|
|
"github.com/google/gopacket/layers"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
const VxLanPacketSize = 1526 //vxlan 8 B + ethernet II 1518 B
|
|
|
|
type vxlanHandle struct {
|
|
connection *net.UDPConn
|
|
packetChannel chan gopacket.Packet
|
|
vnis []int
|
|
}
|
|
|
|
func newVXLANHandler(port int, vnis []int) (*vxlanHandle, error) {
|
|
if port == 0 {
|
|
port = 4789
|
|
}
|
|
|
|
addr := net.UDPAddr{
|
|
Port: port,
|
|
IP: net.ParseIP("0.0.0.0"),
|
|
}
|
|
|
|
vxlanHandle := &vxlanHandle{}
|
|
con, err := net.ListenUDP("udp", &addr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf(err.Error())
|
|
}
|
|
vxlanHandle.connection = con
|
|
vxlanHandle.packetChannel = make(chan gopacket.Packet, 1000)
|
|
vxlanHandle.vnis = vnis
|
|
go vxlanHandle.reader()
|
|
|
|
return vxlanHandle, nil
|
|
}
|
|
|
|
func (v *vxlanHandle) reader() {
|
|
for {
|
|
inputBytes := make([]byte, VxLanPacketSize)
|
|
length, _, err := v.connection.ReadFromUDP(inputBytes)
|
|
if err != nil {
|
|
if errors.Is(err, net.ErrClosed) {
|
|
return
|
|
}
|
|
continue
|
|
}
|
|
packet := gopacket.NewPacket(inputBytes[:length], layers.LayerTypeVXLAN, gopacket.NoCopy)
|
|
ci := packet.Metadata()
|
|
ci.Timestamp = time.Now()
|
|
ci.CaptureLength = length
|
|
ci.Length = length
|
|
|
|
if len(v.vnis) > 0 && !v.vniIsAllowed(packet) {
|
|
continue
|
|
}
|
|
|
|
v.packetChannel <- packet
|
|
}
|
|
}
|
|
|
|
func (v *vxlanHandle) vniIsAllowed(packet gopacket.Packet) bool {
|
|
defaultState := false
|
|
if layer := packet.Layer(layers.LayerTypeVXLAN); layer != nil {
|
|
vxlan, _ := layer.(*layers.VXLAN)
|
|
for _, vn := range v.vnis {
|
|
if vn > 0 && int(vxlan.VNI) == vn {
|
|
return true
|
|
}
|
|
|
|
if vn < 0 {
|
|
if int(vxlan.VNI) == -vn {
|
|
return false
|
|
}
|
|
defaultState = true
|
|
}
|
|
}
|
|
}
|
|
return defaultState
|
|
}
|
|
|
|
func (v *vxlanHandle) ReadPacketData() ([]byte, gopacket.CaptureInfo, error) {
|
|
packet := <-v.packetChannel
|
|
layer := packet.Layer(layers.LayerTypeVXLAN)
|
|
bytes := layer.LayerPayload()
|
|
|
|
return bytes, packet.Metadata().CaptureInfo, nil
|
|
}
|
|
|
|
func (v *vxlanHandle) Close() error {
|
|
if v.connection != nil {
|
|
return v.connection.Close()
|
|
}
|
|
return nil
|
|
}
|