Du kannst nicht mehr als 25 Themen auswählen
Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
209 Zeilen
6.7 KiB
Go
209 Zeilen
6.7 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"flag"
|
|
"fmt"
|
|
"github.com/google/gopacket"
|
|
"github.com/google/gopacket/layers"
|
|
log "github.com/sirupsen/logrus"
|
|
"io"
|
|
"net"
|
|
"proxy/cmd"
|
|
"proxy/util"
|
|
"time"
|
|
)
|
|
|
|
var OldMac net.HardwareAddr
|
|
var NewMac net.HardwareAddr
|
|
var OldIP net.IP
|
|
var NewIP net.IP
|
|
|
|
// Start the two plugs and run two concurrent forward methods
|
|
func main() {
|
|
// Get command line arguments
|
|
logLvl := flag.Int("log", 4, "allowed: 5 (debug), 4 (info), 3 (warning), 2 (error), 1 (fatal)")
|
|
oldip := flag.String("oldip", "10.0.0.11", "IP before change")
|
|
newip := flag.String("newip", "10.0.0.15", "IP after change")
|
|
oldmac := flag.String("oldmac", "52:54:00:12:34:56", "MAC before change")
|
|
newmac := flag.String("newmac", "52:54:00:12:34:aa", "MAC after change")
|
|
passthrough := flag.Bool("passthrough", false, "Whether to pass every traffic through")
|
|
proxy := flag.String("proxy", "1", "Number of the proxy switch")
|
|
flag.Parse()
|
|
log.SetLevel(log.Level(*logLvl))
|
|
OldMac, _ = net.ParseMAC(*oldmac)
|
|
NewMac, _ = net.ParseMAC(*newmac)
|
|
OldIP = net.ParseIP(*oldip).To4()
|
|
NewIP = net.ParseIP(*newip).To4()
|
|
log.SetFormatter(&log.TextFormatter{
|
|
DisableTimestamp: true,
|
|
})
|
|
c1 := cmd.New("vde_plug", "/run/vde/sw_main.sock")
|
|
c2 := cmd.New("vde_plug", "/run/vde/sw_proxy"+*proxy+".sock")
|
|
c1.Execute()
|
|
c2.Execute()
|
|
go pipeForward(c1.OutReader, c2.InWriter, cmd.In, *passthrough)
|
|
go pipeForward(c2.OutReader, c1.InWriter, cmd.Out, *passthrough)
|
|
c1.WaitH()
|
|
c2.WaitH()
|
|
}
|
|
|
|
// Reads from an input and writes to and output,
|
|
// do things to the content in between.
|
|
// Is meant to be run concurrently with "go pipeForward(...)"
|
|
func pipeForward(reader io.Reader, writer io.Writer, prefix string, passthrough bool) {
|
|
for {
|
|
// Read frame length
|
|
frameLength := make([]byte, 2)
|
|
if _, err := reader.Read(frameLength); err == io.EOF {
|
|
log.Fatal(prefix, "Error reading frame length")
|
|
}
|
|
|
|
// Read actual frame
|
|
frameBytes := make([]byte, int(binary.BigEndian.Uint16(frameLength)))
|
|
if _, err := reader.Read(frameBytes); err == io.EOF {
|
|
log.Fatal(prefix, "Error reading frame data")
|
|
}
|
|
|
|
// Convert frame to full stack packet
|
|
packet := gopacket.NewPacket(frameBytes, layers.LayerTypeEthernet, gopacket.Default)
|
|
isInteresting := false // Debug Help
|
|
|
|
// Handle Ethernet frame
|
|
frame := packet.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
|
|
log.Debug("Start packet")
|
|
filterMAC(prefix, &frame.DstMAC, &frame.SrcMAC, frame.LayerType())
|
|
|
|
// Handle IPv6 packet
|
|
if ipv4layer := packet.Layer(layers.LayerTypeIPv4); ipv4layer != nil {
|
|
ipv4Packet, _ := ipv4layer.(*layers.IPv4)
|
|
log.Debug("IP Protocol", ipv4Packet.Protocol)
|
|
filterIP(prefix, &ipv4Packet.DstIP, &ipv4Packet.SrcIP, ipv4Packet.LayerType())
|
|
|
|
// Handle ICMP packet (based on IPv4)
|
|
if icmpLayer := packet.Layer(layers.LayerTypeICMPv4); icmpLayer != nil {
|
|
icmpPacket, _ := icmpLayer.(*layers.ICMPv4)
|
|
log.Debug(prefix, "ICMP Type ", icmpPacket.TypeCode)
|
|
}
|
|
|
|
// Handle DHCP packet (based on IPv4) - drop for now
|
|
if dhcpLayer := packet.Layer(layers.LayerTypeDHCPv4); dhcpLayer != nil && !passthrough {
|
|
//dhcpPacket, _ := dhcpLayer.(*layers.DHCPv4)
|
|
log.Info(prefix, "DHCP packet dropped")
|
|
continue
|
|
}
|
|
|
|
// Handle TCP packet
|
|
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
|
|
tcpPacket, _ := tcpLayer.(*layers.TCP)
|
|
if err := tcpPacket.SetNetworkLayerForChecksum(ipv4Packet); err != nil {
|
|
log.Error(prefix, "Error setting network layer for checksum", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Drop IPv6 packets
|
|
if ipv6layer := packet.Layer(layers.LayerTypeIPv6); ipv6layer != nil && !passthrough {
|
|
log.Info(prefix, "IPv6 packet dropped")
|
|
continue
|
|
}
|
|
|
|
// Handle ARP packet
|
|
if frame.EthernetType == layers.EthernetTypeARP {
|
|
arpPacket := packet.Layer(layers.LayerTypeARP).(*layers.ARP)
|
|
log.Debug(prefix, "ARP Type ", arpPacket.Operation)
|
|
filterIP(prefix, &arpPacket.DstProtAddress, &arpPacket.SourceProtAddress, arpPacket.LayerType())
|
|
filterMAC(prefix, &arpPacket.DstHwAddress, &arpPacket.SourceHwAddress, arpPacket.LayerType())
|
|
}
|
|
|
|
log.Debug("End packet")
|
|
|
|
// Forward original frame to other plug
|
|
if passthrough {
|
|
writer.Write(frameLength)
|
|
writer.Write(frameBytes)
|
|
continue
|
|
}
|
|
|
|
// Serialize packet back to binary
|
|
buf := gopacket.NewSerializeBuffer()
|
|
opts := gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}
|
|
if err := gopacket.SerializePacket(buf, opts, packet); err != nil {
|
|
log.Errorf("%s Error serializing packet to send\n%s\nSrc:\t%s\nDst:\t%s\n", prefix, err, frame.SrcMAC, frame.DstMAC)
|
|
continue
|
|
}
|
|
newFrameBytes := buf.Bytes()
|
|
newFrameLength := make([]byte, 2)
|
|
binary.BigEndian.PutUint16(newFrameLength, uint16(len(newFrameBytes)))
|
|
|
|
// Write interesting things to debug file
|
|
if isInteresting {
|
|
util.WriteBinary(fmt.Sprintf("/tmp/pck_%di.dat", time.Now().Unix()), frameBytes)
|
|
util.WriteBinary(fmt.Sprintf("/tmp/pck_%do.dat", time.Now().Unix()), newFrameBytes)
|
|
//util.WritePcap("xyz.pcap", packet.Data(), packet.Metadata().CaptureInfo)
|
|
}
|
|
|
|
// Forward modified frame to other plug
|
|
writer.Write(newFrameLength)
|
|
writer.Write(newFrameBytes)
|
|
}
|
|
}
|
|
|
|
// filterIP checks whether an IP target selected from src and dst equals a given value. If yes, it is changed
|
|
func filterIP(prefix string, dst interface{}, src interface{}, context gopacket.LayerType) {
|
|
var target interface{}
|
|
var condVal net.IP
|
|
var newVal net.IP
|
|
var which string
|
|
if prefix == cmd.In {
|
|
target = dst
|
|
which = "dst"
|
|
condVal = NewIP
|
|
newVal = OldIP
|
|
} else if prefix == cmd.Out {
|
|
target = src
|
|
which = "src"
|
|
condVal = OldIP
|
|
newVal = NewIP
|
|
}
|
|
ip, isIp := target.(*net.IP)
|
|
bs, isBs := target.(*[]byte)
|
|
if isIp && bytes.Equal(*ip, condVal) {
|
|
*ip = newVal
|
|
log.Debugf("%s%s %s IP %s changed to %s", prefix, context, which, condVal, newVal)
|
|
}
|
|
if isBs && bytes.Equal(*bs, condVal) {
|
|
*bs = newVal
|
|
log.Debugf("%s%s %s IP %s changed to %s", prefix, context, which, condVal, newVal)
|
|
}
|
|
}
|
|
|
|
// filterMAC checks whether a MAC target selected from src and dst equals a given value. If yes, it is changed
|
|
func filterMAC(prefix string, dst interface{}, src interface{}, context gopacket.LayerType) {
|
|
var target interface{}
|
|
var condVal net.HardwareAddr
|
|
var newVal net.HardwareAddr
|
|
var which string
|
|
if prefix == cmd.In {
|
|
target = dst
|
|
which = "dst"
|
|
condVal = NewMac
|
|
newVal = OldMac
|
|
} else if prefix == cmd.Out {
|
|
target = src
|
|
which = "src"
|
|
condVal = OldMac
|
|
newVal = NewMac
|
|
}
|
|
mac, isMac := target.(*net.HardwareAddr)
|
|
bs, isBs := target.(*[]byte)
|
|
if isMac && bytes.Equal(*mac, condVal) {
|
|
*mac = newVal
|
|
log.Debugf("%s%s %s MAC %s changed to %s", prefix, context, which, condVal, newVal)
|
|
}
|
|
if isBs && bytes.Equal(*bs, condVal) {
|
|
*bs = newVal
|
|
log.Debugf("%s%s %s MAC %s changed to %s", prefix, context, which, condVal, newVal)
|
|
}
|
|
} |