From cb2cdc90cc75e790ad57d4cd9e859f5df46a2782 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Wed, 20 Aug 2014 11:18:12 +0100 Subject: [PATCH] introduce abstraction for packet i/o --- ethernet_decoder.go | 5 ++--- pcap.go | 49 +++++++++++++++++++++++++++++++++++++++++++++ router.go | 44 +++++++++++++--------------------------- types.go | 13 ++++++++++++ 4 files changed, 78 insertions(+), 33 deletions(-) create mode 100644 pcap.go diff --git a/ethernet_decoder.go b/ethernet_decoder.go index ae8754a7..e9aaee24 100644 --- a/ethernet_decoder.go +++ b/ethernet_decoder.go @@ -4,7 +4,6 @@ import ( "bytes" "code.google.com/p/gopacket" "code.google.com/p/gopacket/layers" - "code.google.com/p/gopacket/pcap" "log" "net" ) @@ -19,7 +18,7 @@ func (dec *EthernetDecoder) DecodeLayers(data []byte) error { return dec.parser.DecodeLayers(data, &dec.decoded) } -func (dec *EthernetDecoder) CheckFrameTooBigFunc(handle *pcap.Handle) func(error) error { +func (dec *EthernetDecoder) CheckFrameTooBigFunc(po PacketSink) func(error) error { return func(err error) error { if ftbe, ok := err.(FrameTooBigError); ok { // we know: 1. ip is valid, 2. it was ip and DF was set @@ -28,7 +27,7 @@ func (dec *EthernetDecoder) CheckFrameTooBigFunc(handle *pcap.Handle) func(error return err } log.Printf("Injecting ICMP 3,4 (%v -> %v): PMTU= %v\n", dec.ip.DstIP, dec.ip.SrcIP, ftbe.PMTU) - return handle.WritePacketData(icmpFrame) + return po.WritePacket(icmpFrame) } else { return err } diff --git a/pcap.go b/pcap.go new file mode 100644 index 00000000..472db718 --- /dev/null +++ b/pcap.go @@ -0,0 +1,49 @@ +package weave + +import ( + "code.google.com/p/gopacket/pcap" +) + +type PcapIO struct { + handle *pcap.Handle +} + +func NewPcapIO(ifName string, bufSz int) (handle *PcapIO, err error) { + inactive, err := pcap.NewInactiveHandle(ifName) + if err != nil { + return + } + defer inactive.CleanUp() + if inactive.SetPromisc(true) != nil { + return + } + if inactive.SetSnapLen(65535) != nil { + return + } + if inactive.SetTimeout(-1) != nil { + return + } + if inactive.SetImmediateMode(true) != nil { + return + } + if inactive.SetBufferSize(bufSz) != nil { + return + } + active, err := inactive.Activate() + if err != nil { + return + } + if active.SetDirection(pcap.DirectionIn) != nil { + return + } + return &PcapIO{handle: active}, nil +} + +func (pi *PcapIO) ReadPacket() (data []byte, err error) { + data, _, err = pi.handle.ReadPacketData() + return +} + +func (po *PcapIO) WritePacket(data []byte) error { + return po.handle.WritePacketData(data) +} diff --git a/router.go b/router.go index 51074430..046f9ca0 100644 --- a/router.go +++ b/router.go @@ -3,7 +3,6 @@ package weave import ( "bytes" "code.google.com/p/gopacket/layers" - "code.google.com/p/gopacket/pcap" "encoding/binary" "fmt" "io" @@ -39,12 +38,13 @@ func (router *Router) UsingPassword() bool { } func (router *Router) Start() { - handle := router.createPCap(true, 65535, router.BufSz) + pio, err := NewPcapIO(router.Iface.Name, router.BufSz) + checkFatal(err) router.ConnectionMaker = StartConnectionMaker(router) router.Topology = StartTopology(router) - router.UDPListener = router.listenUDP(Port, handle) + router.UDPListener = router.listenUDP(Port, pio) router.listenTCP(Port) - router.sniff(handle) + router.sniff(pio) } func (router *Router) Status() string { @@ -58,19 +58,18 @@ func (router *Router) Status() string { return buf.String() } -func (router *Router) sniff(handle *pcap.Handle) { +func (router *Router) sniff(pio PacketSourceSink) { log.Println("Sniffing traffic on", router.Iface) dec := NewEthernetDecoder() - checkFrameTooBig := dec.CheckFrameTooBigFunc(handle) + checkFrameTooBig := dec.CheckFrameTooBigFunc(pio) mac := router.Iface.HardwareAddr if router.Macs.Enter(mac, router.Ourself) { log.Println("Discovered our MAC", mac) } go func() { - defer handle.Close() for { - pkt, _, err := handle.ReadPacketData() + pkt, err := pio.ReadPacket() checkFatal(err) router.LogFrame("Sniffed", pkt, nil) checkWarn(router.handleCapturedPacket(pkt, dec, checkFrameTooBig)) @@ -142,7 +141,7 @@ func (router *Router) acceptTCP(tcpConn *net.TCPConn) { NewLocalConnection(connRemote, UnknownPeerName, tcpConn, nil, router) } -func (router *Router) listenUDP(localPort int, handle *pcap.Handle) *net.UDPConn { +func (router *Router) listenUDP(localPort int, po PacketSink) *net.UDPConn { localAddr, err := net.ResolveUDPAddr("udp4", fmt.Sprint(":", localPort)) checkFatal(err) conn, err := net.ListenUDP("udp4", localAddr) @@ -154,14 +153,14 @@ func (router *Router) listenUDP(localPort int, handle *pcap.Handle) *net.UDPConn // This one makes sure all packets we send out do not have DF set on them. err = syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_DONT) checkFatal(err) - go router.udpReader(conn, handle) + go router.udpReader(conn, po) return conn } -func (router *Router) udpReader(conn *net.UDPConn, handle *pcap.Handle) { +func (router *Router) udpReader(conn *net.UDPConn, po PacketSink) { defer conn.Close() dec := NewEthernetDecoder() - handleUDPPacket := router.handleUDPPacketFunc(dec, handle) + handleUDPPacket := router.handleUDPPacketFunc(dec, po) buf := make([]byte, MaxUDPPacketSize) for { n, sender, err := conn.ReadFromUDP(buf) @@ -193,8 +192,8 @@ func (router *Router) udpReader(conn *net.UDPConn, handle *pcap.Handle) { } } -func (router *Router) handleUDPPacketFunc(dec *EthernetDecoder, handle *pcap.Handle) FrameConsumer { - checkFrameTooBig := dec.CheckFrameTooBigFunc(handle) +func (router *Router) handleUDPPacketFunc(dec *EthernetDecoder, po PacketSink) FrameConsumer { + checkFrameTooBig := dec.CheckFrameTooBigFunc(po) return func(relayConn *LocalConnection, sender *net.UDPAddr, srcNameByte, dstNameByte []byte, frameLen uint16, frame []byte) error { srcName := PeerNameFromBin(srcNameByte) @@ -251,7 +250,7 @@ func (router *Router) handleUDPPacketFunc(dec *EthernetDecoder, handle *pcap.Han log.Println("Discovered remote MAC", srcMac, "at", srcPeer.Name) } router.LogFrame("Injecting", frame, &dec.eth) - checkWarn(handle.WritePacketData(frame)) + checkWarn(po.WritePacket(frame)) dstPeer, found = router.Macs.Lookup(dec.eth.DstMAC) if !found || dec.BroadcastFrame() || dstPeer != router.Ourself { df := decodedLen == 2 && (dec.ip.Flags&layers.IPv4DontFragment != 0) @@ -260,18 +259,3 @@ func (router *Router) handleUDPPacketFunc(dec *EthernetDecoder, handle *pcap.Han return nil } } - -func (router *Router) createPCap(promisc bool, snaplen int, buffSize int) *pcap.Handle { - inactive, err := pcap.NewInactiveHandle(router.Iface.Name) - checkFatal(err) - defer inactive.CleanUp() - checkFatal(inactive.SetPromisc(promisc)) - checkFatal(inactive.SetSnapLen(snaplen)) - checkFatal(inactive.SetTimeout(-1)) - checkFatal(inactive.SetImmediateMode(true)) - checkFatal(inactive.SetBufferSize(buffSize)) - active, err := inactive.Activate() - checkFatal(err) - checkFatal(active.SetDirection(pcap.DirectionIn)) - return active -} diff --git a/types.go b/types.go index f206b48d..5b613bde 100644 --- a/types.go +++ b/types.go @@ -272,3 +272,16 @@ type NaClDecryptorInstance struct { highestOffsetSeen uint16 nonceChan chan *[24]byte } + +type PacketSource interface { + ReadPacket() ([]byte, error) +} + +type PacketSink interface { + WritePacket([]byte) error +} + +type PacketSourceSink interface { + PacketSource + PacketSink +}