mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
*: remove 'tools/etcd-top' to drop pcap.h
This commit is contained in:
parent
41e329cd35
commit
a9e2d3d4d3
4
cmd/Godeps/Godeps.json
generated
4
cmd/Godeps/Godeps.json
generated
@ -11,10 +11,6 @@
|
|||||||
"Comment": "null-5",
|
"Comment": "null-5",
|
||||||
"Rev": "'75cd24fc2f2c2a2088577d12123ddee5f54e0675'"
|
"Rev": "'75cd24fc2f2c2a2088577d12123ddee5f54e0675'"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"ImportPath": "github.com/akrennmair/gopcap",
|
|
||||||
"Rev": "00e11033259acb75598ba416495bb708d864a010"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/beorn7/perks/quantile",
|
"ImportPath": "github.com/beorn7/perks/quantile",
|
||||||
"Rev": "b965b613227fddccbfffe13eae360ed3fa822f8d"
|
"Rev": "b965b613227fddccbfffe13eae360ed3fa822f8d"
|
||||||
|
5
cmd/vendor/github.com/akrennmair/gopcap/.gitignore
generated
vendored
5
cmd/vendor/github.com/akrennmair/gopcap/.gitignore
generated
vendored
@ -1,5 +0,0 @@
|
|||||||
#*
|
|
||||||
*~
|
|
||||||
/tools/pass/pass
|
|
||||||
/tools/pcaptest/pcaptest
|
|
||||||
/tools/tcpdump/tcpdump
|
|
27
cmd/vendor/github.com/akrennmair/gopcap/LICENSE
generated
vendored
27
cmd/vendor/github.com/akrennmair/gopcap/LICENSE
generated
vendored
@ -1,27 +0,0 @@
|
|||||||
Copyright (c) 2009-2011 Andreas Krennmair. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Andreas Krennmair nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
11
cmd/vendor/github.com/akrennmair/gopcap/README.mkd
generated
vendored
11
cmd/vendor/github.com/akrennmair/gopcap/README.mkd
generated
vendored
@ -1,11 +0,0 @@
|
|||||||
# PCAP
|
|
||||||
|
|
||||||
This is a simple wrapper around libpcap for Go. Originally written by Andreas
|
|
||||||
Krennmair <ak@synflood.at> and only minorly touched up by Mark Smith <mark@qq.is>.
|
|
||||||
|
|
||||||
Please see the included pcaptest.go and tcpdump.go programs for instructions on
|
|
||||||
how to use this library.
|
|
||||||
|
|
||||||
Miek Gieben <miek@miek.nl> has created a more Go-like package and replaced functionality
|
|
||||||
with standard functions from the standard library. The package has also been renamed to
|
|
||||||
pcap.
|
|
527
cmd/vendor/github.com/akrennmair/gopcap/decode.go
generated
vendored
527
cmd/vendor/github.com/akrennmair/gopcap/decode.go
generated
vendored
@ -1,527 +0,0 @@
|
|||||||
package pcap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
TYPE_IP = 0x0800
|
|
||||||
TYPE_ARP = 0x0806
|
|
||||||
TYPE_IP6 = 0x86DD
|
|
||||||
TYPE_VLAN = 0x8100
|
|
||||||
|
|
||||||
IP_ICMP = 1
|
|
||||||
IP_INIP = 4
|
|
||||||
IP_TCP = 6
|
|
||||||
IP_UDP = 17
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ERRBUF_SIZE = 256
|
|
||||||
|
|
||||||
// According to pcap-linktype(7).
|
|
||||||
LINKTYPE_NULL = 0
|
|
||||||
LINKTYPE_ETHERNET = 1
|
|
||||||
LINKTYPE_TOKEN_RING = 6
|
|
||||||
LINKTYPE_ARCNET = 7
|
|
||||||
LINKTYPE_SLIP = 8
|
|
||||||
LINKTYPE_PPP = 9
|
|
||||||
LINKTYPE_FDDI = 10
|
|
||||||
LINKTYPE_ATM_RFC1483 = 100
|
|
||||||
LINKTYPE_RAW = 101
|
|
||||||
LINKTYPE_PPP_HDLC = 50
|
|
||||||
LINKTYPE_PPP_ETHER = 51
|
|
||||||
LINKTYPE_C_HDLC = 104
|
|
||||||
LINKTYPE_IEEE802_11 = 105
|
|
||||||
LINKTYPE_FRELAY = 107
|
|
||||||
LINKTYPE_LOOP = 108
|
|
||||||
LINKTYPE_LINUX_SLL = 113
|
|
||||||
LINKTYPE_LTALK = 104
|
|
||||||
LINKTYPE_PFLOG = 117
|
|
||||||
LINKTYPE_PRISM_HEADER = 119
|
|
||||||
LINKTYPE_IP_OVER_FC = 122
|
|
||||||
LINKTYPE_SUNATM = 123
|
|
||||||
LINKTYPE_IEEE802_11_RADIO = 127
|
|
||||||
LINKTYPE_ARCNET_LINUX = 129
|
|
||||||
LINKTYPE_LINUX_IRDA = 144
|
|
||||||
LINKTYPE_LINUX_LAPD = 177
|
|
||||||
)
|
|
||||||
|
|
||||||
type addrHdr interface {
|
|
||||||
SrcAddr() string
|
|
||||||
DestAddr() string
|
|
||||||
Len() int
|
|
||||||
}
|
|
||||||
|
|
||||||
type addrStringer interface {
|
|
||||||
String(addr addrHdr) string
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodemac(pkt []byte) uint64 {
|
|
||||||
mac := uint64(0)
|
|
||||||
for i := uint(0); i < 6; i++ {
|
|
||||||
mac = (mac << 8) + uint64(pkt[i])
|
|
||||||
}
|
|
||||||
return mac
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode decodes the headers of a Packet.
|
|
||||||
func (p *Packet) Decode() {
|
|
||||||
if len(p.Data) <= 14 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
p.Type = int(binary.BigEndian.Uint16(p.Data[12:14]))
|
|
||||||
p.DestMac = decodemac(p.Data[0:6])
|
|
||||||
p.SrcMac = decodemac(p.Data[6:12])
|
|
||||||
|
|
||||||
if len(p.Data) >= 15 {
|
|
||||||
p.Payload = p.Data[14:]
|
|
||||||
}
|
|
||||||
|
|
||||||
switch p.Type {
|
|
||||||
case TYPE_IP:
|
|
||||||
p.decodeIp()
|
|
||||||
case TYPE_IP6:
|
|
||||||
p.decodeIp6()
|
|
||||||
case TYPE_ARP:
|
|
||||||
p.decodeArp()
|
|
||||||
case TYPE_VLAN:
|
|
||||||
p.decodeVlan()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Packet) headerString(headers []interface{}) string {
|
|
||||||
// If there's just one header, return that.
|
|
||||||
if len(headers) == 1 {
|
|
||||||
if hdr, ok := headers[0].(fmt.Stringer); ok {
|
|
||||||
return hdr.String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If there are two headers (IPv4/IPv6 -> TCP/UDP/IP..)
|
|
||||||
if len(headers) == 2 {
|
|
||||||
// Commonly the first header is an address.
|
|
||||||
if addr, ok := p.Headers[0].(addrHdr); ok {
|
|
||||||
if hdr, ok := p.Headers[1].(addrStringer); ok {
|
|
||||||
return fmt.Sprintf("%s %s", p.Time, hdr.String(addr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For IP in IP, we do a recursive call.
|
|
||||||
if len(headers) >= 2 {
|
|
||||||
if addr, ok := headers[0].(addrHdr); ok {
|
|
||||||
if _, ok := headers[1].(addrHdr); ok {
|
|
||||||
return fmt.Sprintf("%s > %s IP in IP: ",
|
|
||||||
addr.SrcAddr(), addr.DestAddr(), p.headerString(headers[1:]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var typeNames []string
|
|
||||||
for _, hdr := range headers {
|
|
||||||
typeNames = append(typeNames, reflect.TypeOf(hdr).String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("unknown [%s]", strings.Join(typeNames, ","))
|
|
||||||
}
|
|
||||||
|
|
||||||
// String prints a one-line representation of the packet header.
|
|
||||||
// The output is suitable for use in a tcpdump program.
|
|
||||||
func (p *Packet) String() string {
|
|
||||||
// If there are no headers, print "unsupported protocol".
|
|
||||||
if len(p.Headers) == 0 {
|
|
||||||
return fmt.Sprintf("%s unsupported protocol %d", p.Time, int(p.Type))
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s %s", p.Time, p.headerString(p.Headers))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Arphdr is a ARP packet header.
|
|
||||||
type Arphdr struct {
|
|
||||||
Addrtype uint16
|
|
||||||
Protocol uint16
|
|
||||||
HwAddressSize uint8
|
|
||||||
ProtAddressSize uint8
|
|
||||||
Operation uint16
|
|
||||||
SourceHwAddress []byte
|
|
||||||
SourceProtAddress []byte
|
|
||||||
DestHwAddress []byte
|
|
||||||
DestProtAddress []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (arp *Arphdr) String() (s string) {
|
|
||||||
switch arp.Operation {
|
|
||||||
case 1:
|
|
||||||
s = "ARP request"
|
|
||||||
case 2:
|
|
||||||
s = "ARP Reply"
|
|
||||||
}
|
|
||||||
if arp.Addrtype == LINKTYPE_ETHERNET && arp.Protocol == TYPE_IP {
|
|
||||||
s = fmt.Sprintf("%012x (%s) > %012x (%s)",
|
|
||||||
decodemac(arp.SourceHwAddress), arp.SourceProtAddress,
|
|
||||||
decodemac(arp.DestHwAddress), arp.DestProtAddress)
|
|
||||||
} else {
|
|
||||||
s = fmt.Sprintf("addrtype = %d protocol = %d", arp.Addrtype, arp.Protocol)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Packet) decodeArp() {
|
|
||||||
if len(p.Payload) < 8 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt := p.Payload
|
|
||||||
arp := new(Arphdr)
|
|
||||||
arp.Addrtype = binary.BigEndian.Uint16(pkt[0:2])
|
|
||||||
arp.Protocol = binary.BigEndian.Uint16(pkt[2:4])
|
|
||||||
arp.HwAddressSize = pkt[4]
|
|
||||||
arp.ProtAddressSize = pkt[5]
|
|
||||||
arp.Operation = binary.BigEndian.Uint16(pkt[6:8])
|
|
||||||
|
|
||||||
if len(pkt) < int(8+2*arp.HwAddressSize+2*arp.ProtAddressSize) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
arp.SourceHwAddress = pkt[8 : 8+arp.HwAddressSize]
|
|
||||||
arp.SourceProtAddress = pkt[8+arp.HwAddressSize : 8+arp.HwAddressSize+arp.ProtAddressSize]
|
|
||||||
arp.DestHwAddress = pkt[8+arp.HwAddressSize+arp.ProtAddressSize : 8+2*arp.HwAddressSize+arp.ProtAddressSize]
|
|
||||||
arp.DestProtAddress = pkt[8+2*arp.HwAddressSize+arp.ProtAddressSize : 8+2*arp.HwAddressSize+2*arp.ProtAddressSize]
|
|
||||||
|
|
||||||
p.Headers = append(p.Headers, arp)
|
|
||||||
|
|
||||||
if len(pkt) >= int(8+2*arp.HwAddressSize+2*arp.ProtAddressSize) {
|
|
||||||
p.Payload = p.Payload[8+2*arp.HwAddressSize+2*arp.ProtAddressSize:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IPadr is the header of an IP packet.
|
|
||||||
type Iphdr struct {
|
|
||||||
Version uint8
|
|
||||||
Ihl uint8
|
|
||||||
Tos uint8
|
|
||||||
Length uint16
|
|
||||||
Id uint16
|
|
||||||
Flags uint8
|
|
||||||
FragOffset uint16
|
|
||||||
Ttl uint8
|
|
||||||
Protocol uint8
|
|
||||||
Checksum uint16
|
|
||||||
SrcIp []byte
|
|
||||||
DestIp []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Packet) decodeIp() {
|
|
||||||
if len(p.Payload) < 20 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt := p.Payload
|
|
||||||
ip := new(Iphdr)
|
|
||||||
|
|
||||||
ip.Version = uint8(pkt[0]) >> 4
|
|
||||||
ip.Ihl = uint8(pkt[0]) & 0x0F
|
|
||||||
ip.Tos = pkt[1]
|
|
||||||
ip.Length = binary.BigEndian.Uint16(pkt[2:4])
|
|
||||||
ip.Id = binary.BigEndian.Uint16(pkt[4:6])
|
|
||||||
flagsfrags := binary.BigEndian.Uint16(pkt[6:8])
|
|
||||||
ip.Flags = uint8(flagsfrags >> 13)
|
|
||||||
ip.FragOffset = flagsfrags & 0x1FFF
|
|
||||||
ip.Ttl = pkt[8]
|
|
||||||
ip.Protocol = pkt[9]
|
|
||||||
ip.Checksum = binary.BigEndian.Uint16(pkt[10:12])
|
|
||||||
ip.SrcIp = pkt[12:16]
|
|
||||||
ip.DestIp = pkt[16:20]
|
|
||||||
|
|
||||||
pEnd := int(ip.Length)
|
|
||||||
if pEnd > len(pkt) {
|
|
||||||
pEnd = len(pkt)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(pkt) >= pEnd && int(ip.Ihl*4) < pEnd {
|
|
||||||
p.Payload = pkt[ip.Ihl*4 : pEnd]
|
|
||||||
} else {
|
|
||||||
p.Payload = []byte{}
|
|
||||||
}
|
|
||||||
|
|
||||||
p.Headers = append(p.Headers, ip)
|
|
||||||
p.IP = ip
|
|
||||||
|
|
||||||
switch ip.Protocol {
|
|
||||||
case IP_TCP:
|
|
||||||
p.decodeTcp()
|
|
||||||
case IP_UDP:
|
|
||||||
p.decodeUdp()
|
|
||||||
case IP_ICMP:
|
|
||||||
p.decodeIcmp()
|
|
||||||
case IP_INIP:
|
|
||||||
p.decodeIp()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ip *Iphdr) SrcAddr() string { return net.IP(ip.SrcIp).String() }
|
|
||||||
func (ip *Iphdr) DestAddr() string { return net.IP(ip.DestIp).String() }
|
|
||||||
func (ip *Iphdr) Len() int { return int(ip.Length) }
|
|
||||||
|
|
||||||
type Vlanhdr struct {
|
|
||||||
Priority byte
|
|
||||||
DropEligible bool
|
|
||||||
VlanIdentifier int
|
|
||||||
Type int // Not actually part of the vlan header, but the type of the actual packet
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Vlanhdr) String() {
|
|
||||||
fmt.Sprintf("VLAN Priority:%d Drop:%v Tag:%d", v.Priority, v.DropEligible, v.VlanIdentifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Packet) decodeVlan() {
|
|
||||||
pkt := p.Payload
|
|
||||||
vlan := new(Vlanhdr)
|
|
||||||
if len(pkt) < 4 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
vlan.Priority = (pkt[2] & 0xE0) >> 13
|
|
||||||
vlan.DropEligible = pkt[2]&0x10 != 0
|
|
||||||
vlan.VlanIdentifier = int(binary.BigEndian.Uint16(pkt[:2])) & 0x0FFF
|
|
||||||
vlan.Type = int(binary.BigEndian.Uint16(p.Payload[2:4]))
|
|
||||||
p.Headers = append(p.Headers, vlan)
|
|
||||||
|
|
||||||
if len(pkt) >= 5 {
|
|
||||||
p.Payload = p.Payload[4:]
|
|
||||||
}
|
|
||||||
|
|
||||||
switch vlan.Type {
|
|
||||||
case TYPE_IP:
|
|
||||||
p.decodeIp()
|
|
||||||
case TYPE_IP6:
|
|
||||||
p.decodeIp6()
|
|
||||||
case TYPE_ARP:
|
|
||||||
p.decodeArp()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Tcphdr struct {
|
|
||||||
SrcPort uint16
|
|
||||||
DestPort uint16
|
|
||||||
Seq uint32
|
|
||||||
Ack uint32
|
|
||||||
DataOffset uint8
|
|
||||||
Flags uint16
|
|
||||||
Window uint16
|
|
||||||
Checksum uint16
|
|
||||||
Urgent uint16
|
|
||||||
Data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
TCP_FIN = 1 << iota
|
|
||||||
TCP_SYN
|
|
||||||
TCP_RST
|
|
||||||
TCP_PSH
|
|
||||||
TCP_ACK
|
|
||||||
TCP_URG
|
|
||||||
TCP_ECE
|
|
||||||
TCP_CWR
|
|
||||||
TCP_NS
|
|
||||||
)
|
|
||||||
|
|
||||||
func (p *Packet) decodeTcp() {
|
|
||||||
if len(p.Payload) < 20 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt := p.Payload
|
|
||||||
tcp := new(Tcphdr)
|
|
||||||
tcp.SrcPort = binary.BigEndian.Uint16(pkt[0:2])
|
|
||||||
tcp.DestPort = binary.BigEndian.Uint16(pkt[2:4])
|
|
||||||
tcp.Seq = binary.BigEndian.Uint32(pkt[4:8])
|
|
||||||
tcp.Ack = binary.BigEndian.Uint32(pkt[8:12])
|
|
||||||
tcp.DataOffset = (pkt[12] & 0xF0) >> 4
|
|
||||||
tcp.Flags = binary.BigEndian.Uint16(pkt[12:14]) & 0x1FF
|
|
||||||
tcp.Window = binary.BigEndian.Uint16(pkt[14:16])
|
|
||||||
tcp.Checksum = binary.BigEndian.Uint16(pkt[16:18])
|
|
||||||
tcp.Urgent = binary.BigEndian.Uint16(pkt[18:20])
|
|
||||||
if len(pkt) >= int(tcp.DataOffset*4) {
|
|
||||||
p.Payload = pkt[tcp.DataOffset*4:]
|
|
||||||
}
|
|
||||||
p.Headers = append(p.Headers, tcp)
|
|
||||||
p.TCP = tcp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tcp *Tcphdr) String(hdr addrHdr) string {
|
|
||||||
return fmt.Sprintf("TCP %s:%d > %s:%d %s SEQ=%d ACK=%d LEN=%d",
|
|
||||||
hdr.SrcAddr(), int(tcp.SrcPort), hdr.DestAddr(), int(tcp.DestPort),
|
|
||||||
tcp.FlagsString(), int64(tcp.Seq), int64(tcp.Ack), hdr.Len())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tcp *Tcphdr) FlagsString() string {
|
|
||||||
var sflags []string
|
|
||||||
if 0 != (tcp.Flags & TCP_SYN) {
|
|
||||||
sflags = append(sflags, "syn")
|
|
||||||
}
|
|
||||||
if 0 != (tcp.Flags & TCP_FIN) {
|
|
||||||
sflags = append(sflags, "fin")
|
|
||||||
}
|
|
||||||
if 0 != (tcp.Flags & TCP_ACK) {
|
|
||||||
sflags = append(sflags, "ack")
|
|
||||||
}
|
|
||||||
if 0 != (tcp.Flags & TCP_PSH) {
|
|
||||||
sflags = append(sflags, "psh")
|
|
||||||
}
|
|
||||||
if 0 != (tcp.Flags & TCP_RST) {
|
|
||||||
sflags = append(sflags, "rst")
|
|
||||||
}
|
|
||||||
if 0 != (tcp.Flags & TCP_URG) {
|
|
||||||
sflags = append(sflags, "urg")
|
|
||||||
}
|
|
||||||
if 0 != (tcp.Flags & TCP_NS) {
|
|
||||||
sflags = append(sflags, "ns")
|
|
||||||
}
|
|
||||||
if 0 != (tcp.Flags & TCP_CWR) {
|
|
||||||
sflags = append(sflags, "cwr")
|
|
||||||
}
|
|
||||||
if 0 != (tcp.Flags & TCP_ECE) {
|
|
||||||
sflags = append(sflags, "ece")
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("[%s]", strings.Join(sflags, " "))
|
|
||||||
}
|
|
||||||
|
|
||||||
type Udphdr struct {
|
|
||||||
SrcPort uint16
|
|
||||||
DestPort uint16
|
|
||||||
Length uint16
|
|
||||||
Checksum uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Packet) decodeUdp() {
|
|
||||||
if len(p.Payload) < 8 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt := p.Payload
|
|
||||||
udp := new(Udphdr)
|
|
||||||
udp.SrcPort = binary.BigEndian.Uint16(pkt[0:2])
|
|
||||||
udp.DestPort = binary.BigEndian.Uint16(pkt[2:4])
|
|
||||||
udp.Length = binary.BigEndian.Uint16(pkt[4:6])
|
|
||||||
udp.Checksum = binary.BigEndian.Uint16(pkt[6:8])
|
|
||||||
p.Headers = append(p.Headers, udp)
|
|
||||||
p.UDP = udp
|
|
||||||
if len(p.Payload) >= 8 {
|
|
||||||
p.Payload = pkt[8:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (udp *Udphdr) String(hdr addrHdr) string {
|
|
||||||
return fmt.Sprintf("UDP %s:%d > %s:%d LEN=%d CHKSUM=%d",
|
|
||||||
hdr.SrcAddr(), int(udp.SrcPort), hdr.DestAddr(), int(udp.DestPort),
|
|
||||||
int(udp.Length), int(udp.Checksum))
|
|
||||||
}
|
|
||||||
|
|
||||||
type Icmphdr struct {
|
|
||||||
Type uint8
|
|
||||||
Code uint8
|
|
||||||
Checksum uint16
|
|
||||||
Id uint16
|
|
||||||
Seq uint16
|
|
||||||
Data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Packet) decodeIcmp() *Icmphdr {
|
|
||||||
if len(p.Payload) < 8 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt := p.Payload
|
|
||||||
icmp := new(Icmphdr)
|
|
||||||
icmp.Type = pkt[0]
|
|
||||||
icmp.Code = pkt[1]
|
|
||||||
icmp.Checksum = binary.BigEndian.Uint16(pkt[2:4])
|
|
||||||
icmp.Id = binary.BigEndian.Uint16(pkt[4:6])
|
|
||||||
icmp.Seq = binary.BigEndian.Uint16(pkt[6:8])
|
|
||||||
p.Payload = pkt[8:]
|
|
||||||
p.Headers = append(p.Headers, icmp)
|
|
||||||
return icmp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (icmp *Icmphdr) String(hdr addrHdr) string {
|
|
||||||
return fmt.Sprintf("ICMP %s > %s Type = %d Code = %d ",
|
|
||||||
hdr.SrcAddr(), hdr.DestAddr(), icmp.Type, icmp.Code)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (icmp *Icmphdr) TypeString() (result string) {
|
|
||||||
switch icmp.Type {
|
|
||||||
case 0:
|
|
||||||
result = fmt.Sprintf("Echo reply seq=%d", icmp.Seq)
|
|
||||||
case 3:
|
|
||||||
switch icmp.Code {
|
|
||||||
case 0:
|
|
||||||
result = "Network unreachable"
|
|
||||||
case 1:
|
|
||||||
result = "Host unreachable"
|
|
||||||
case 2:
|
|
||||||
result = "Protocol unreachable"
|
|
||||||
case 3:
|
|
||||||
result = "Port unreachable"
|
|
||||||
default:
|
|
||||||
result = "Destination unreachable"
|
|
||||||
}
|
|
||||||
case 8:
|
|
||||||
result = fmt.Sprintf("Echo request seq=%d", icmp.Seq)
|
|
||||||
case 30:
|
|
||||||
result = "Traceroute"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type Ip6hdr struct {
|
|
||||||
// http://www.networksorcery.com/enp/protocol/ipv6.htm
|
|
||||||
Version uint8 // 4 bits
|
|
||||||
TrafficClass uint8 // 8 bits
|
|
||||||
FlowLabel uint32 // 20 bits
|
|
||||||
Length uint16 // 16 bits
|
|
||||||
NextHeader uint8 // 8 bits, same as Protocol in Iphdr
|
|
||||||
HopLimit uint8 // 8 bits
|
|
||||||
SrcIp []byte // 16 bytes
|
|
||||||
DestIp []byte // 16 bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Packet) decodeIp6() {
|
|
||||||
if len(p.Payload) < 40 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt := p.Payload
|
|
||||||
ip6 := new(Ip6hdr)
|
|
||||||
ip6.Version = uint8(pkt[0]) >> 4
|
|
||||||
ip6.TrafficClass = uint8((binary.BigEndian.Uint16(pkt[0:2]) >> 4) & 0x00FF)
|
|
||||||
ip6.FlowLabel = binary.BigEndian.Uint32(pkt[0:4]) & 0x000FFFFF
|
|
||||||
ip6.Length = binary.BigEndian.Uint16(pkt[4:6])
|
|
||||||
ip6.NextHeader = pkt[6]
|
|
||||||
ip6.HopLimit = pkt[7]
|
|
||||||
ip6.SrcIp = pkt[8:24]
|
|
||||||
ip6.DestIp = pkt[24:40]
|
|
||||||
|
|
||||||
if len(p.Payload) >= 40 {
|
|
||||||
p.Payload = pkt[40:]
|
|
||||||
}
|
|
||||||
|
|
||||||
p.Headers = append(p.Headers, ip6)
|
|
||||||
|
|
||||||
switch ip6.NextHeader {
|
|
||||||
case IP_TCP:
|
|
||||||
p.decodeTcp()
|
|
||||||
case IP_UDP:
|
|
||||||
p.decodeUdp()
|
|
||||||
case IP_ICMP:
|
|
||||||
p.decodeIcmp()
|
|
||||||
case IP_INIP:
|
|
||||||
p.decodeIp()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ip6 *Ip6hdr) SrcAddr() string { return net.IP(ip6.SrcIp).String() }
|
|
||||||
func (ip6 *Ip6hdr) DestAddr() string { return net.IP(ip6.DestIp).String() }
|
|
||||||
func (ip6 *Ip6hdr) Len() int { return int(ip6.Length) }
|
|
206
cmd/vendor/github.com/akrennmair/gopcap/io.go
generated
vendored
206
cmd/vendor/github.com/akrennmair/gopcap/io.go
generated
vendored
@ -1,206 +0,0 @@
|
|||||||
package pcap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FileHeader is the parsed header of a pcap file.
|
|
||||||
// http://wiki.wireshark.org/Development/LibpcapFileFormat
|
|
||||||
type FileHeader struct {
|
|
||||||
MagicNumber uint32
|
|
||||||
VersionMajor uint16
|
|
||||||
VersionMinor uint16
|
|
||||||
TimeZone int32
|
|
||||||
SigFigs uint32
|
|
||||||
SnapLen uint32
|
|
||||||
Network uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type PacketTime struct {
|
|
||||||
Sec int32
|
|
||||||
Usec int32
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the PacketTime to a go Time struct.
|
|
||||||
func (p *PacketTime) Time() time.Time {
|
|
||||||
return time.Unix(int64(p.Sec), int64(p.Usec)*1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Packet is a single packet parsed from a pcap file.
|
|
||||||
//
|
|
||||||
// Convenient access to IP, TCP, and UDP headers is provided after Decode()
|
|
||||||
// is called if the packet is of the appropriate type.
|
|
||||||
type Packet struct {
|
|
||||||
Time time.Time // packet send/receive time
|
|
||||||
Caplen uint32 // bytes stored in the file (caplen <= len)
|
|
||||||
Len uint32 // bytes sent/received
|
|
||||||
Data []byte // packet data
|
|
||||||
|
|
||||||
Type int // protocol type, see LINKTYPE_*
|
|
||||||
DestMac uint64
|
|
||||||
SrcMac uint64
|
|
||||||
|
|
||||||
Headers []interface{} // decoded headers, in order
|
|
||||||
Payload []byte // remaining non-header bytes
|
|
||||||
|
|
||||||
IP *Iphdr // IP header (for IP packets, after decoding)
|
|
||||||
TCP *Tcphdr // TCP header (for TCP packets, after decoding)
|
|
||||||
UDP *Udphdr // UDP header (for UDP packets after decoding)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reader parses pcap files.
|
|
||||||
type Reader struct {
|
|
||||||
flip bool
|
|
||||||
buf io.Reader
|
|
||||||
err error
|
|
||||||
fourBytes []byte
|
|
||||||
twoBytes []byte
|
|
||||||
sixteenBytes []byte
|
|
||||||
Header FileHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReader reads pcap data from an io.Reader.
|
|
||||||
func NewReader(reader io.Reader) (*Reader, error) {
|
|
||||||
r := &Reader{
|
|
||||||
buf: reader,
|
|
||||||
fourBytes: make([]byte, 4),
|
|
||||||
twoBytes: make([]byte, 2),
|
|
||||||
sixteenBytes: make([]byte, 16),
|
|
||||||
}
|
|
||||||
switch magic := r.readUint32(); magic {
|
|
||||||
case 0xa1b2c3d4:
|
|
||||||
r.flip = false
|
|
||||||
case 0xd4c3b2a1:
|
|
||||||
r.flip = true
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("pcap: bad magic number: %0x", magic)
|
|
||||||
}
|
|
||||||
r.Header = FileHeader{
|
|
||||||
MagicNumber: 0xa1b2c3d4,
|
|
||||||
VersionMajor: r.readUint16(),
|
|
||||||
VersionMinor: r.readUint16(),
|
|
||||||
TimeZone: r.readInt32(),
|
|
||||||
SigFigs: r.readUint32(),
|
|
||||||
SnapLen: r.readUint32(),
|
|
||||||
Network: r.readUint32(),
|
|
||||||
}
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next returns the next packet or nil if no more packets can be read.
|
|
||||||
func (r *Reader) Next() *Packet {
|
|
||||||
d := r.sixteenBytes
|
|
||||||
r.err = r.read(d)
|
|
||||||
if r.err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
timeSec := asUint32(d[0:4], r.flip)
|
|
||||||
timeUsec := asUint32(d[4:8], r.flip)
|
|
||||||
capLen := asUint32(d[8:12], r.flip)
|
|
||||||
origLen := asUint32(d[12:16], r.flip)
|
|
||||||
|
|
||||||
data := make([]byte, capLen)
|
|
||||||
if r.err = r.read(data); r.err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &Packet{
|
|
||||||
Time: time.Unix(int64(timeSec), int64(timeUsec)),
|
|
||||||
Caplen: capLen,
|
|
||||||
Len: origLen,
|
|
||||||
Data: data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Reader) read(data []byte) error {
|
|
||||||
var err error
|
|
||||||
n, err := r.buf.Read(data)
|
|
||||||
for err == nil && n != len(data) {
|
|
||||||
var chunk int
|
|
||||||
chunk, err = r.buf.Read(data[n:])
|
|
||||||
n += chunk
|
|
||||||
}
|
|
||||||
if len(data) == n {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Reader) readUint32() uint32 {
|
|
||||||
data := r.fourBytes
|
|
||||||
if r.err = r.read(data); r.err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return asUint32(data, r.flip)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Reader) readInt32() int32 {
|
|
||||||
data := r.fourBytes
|
|
||||||
if r.err = r.read(data); r.err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return int32(asUint32(data, r.flip))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Reader) readUint16() uint16 {
|
|
||||||
data := r.twoBytes
|
|
||||||
if r.err = r.read(data); r.err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return asUint16(data, r.flip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writer writes a pcap file.
|
|
||||||
type Writer struct {
|
|
||||||
writer io.Writer
|
|
||||||
buf []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWriter creates a Writer that stores output in an io.Writer.
|
|
||||||
// The FileHeader is written immediately.
|
|
||||||
func NewWriter(writer io.Writer, header *FileHeader) (*Writer, error) {
|
|
||||||
w := &Writer{
|
|
||||||
writer: writer,
|
|
||||||
buf: make([]byte, 24),
|
|
||||||
}
|
|
||||||
binary.LittleEndian.PutUint32(w.buf, header.MagicNumber)
|
|
||||||
binary.LittleEndian.PutUint16(w.buf[4:], header.VersionMajor)
|
|
||||||
binary.LittleEndian.PutUint16(w.buf[6:], header.VersionMinor)
|
|
||||||
binary.LittleEndian.PutUint32(w.buf[8:], uint32(header.TimeZone))
|
|
||||||
binary.LittleEndian.PutUint32(w.buf[12:], header.SigFigs)
|
|
||||||
binary.LittleEndian.PutUint32(w.buf[16:], header.SnapLen)
|
|
||||||
binary.LittleEndian.PutUint32(w.buf[20:], header.Network)
|
|
||||||
if _, err := writer.Write(w.buf); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return w, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writer writes a packet to the underlying writer.
|
|
||||||
func (w *Writer) Write(pkt *Packet) error {
|
|
||||||
binary.LittleEndian.PutUint32(w.buf, uint32(pkt.Time.Unix()))
|
|
||||||
binary.LittleEndian.PutUint32(w.buf[4:], uint32(pkt.Time.Nanosecond()))
|
|
||||||
binary.LittleEndian.PutUint32(w.buf[8:], uint32(pkt.Time.Unix()))
|
|
||||||
binary.LittleEndian.PutUint32(w.buf[12:], pkt.Len)
|
|
||||||
if _, err := w.writer.Write(w.buf[:16]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err := w.writer.Write(pkt.Data)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func asUint32(data []byte, flip bool) uint32 {
|
|
||||||
if flip {
|
|
||||||
return binary.BigEndian.Uint32(data)
|
|
||||||
}
|
|
||||||
return binary.LittleEndian.Uint32(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func asUint16(data []byte, flip bool) uint16 {
|
|
||||||
if flip {
|
|
||||||
return binary.BigEndian.Uint16(data)
|
|
||||||
}
|
|
||||||
return binary.LittleEndian.Uint16(data)
|
|
||||||
}
|
|
266
cmd/vendor/github.com/akrennmair/gopcap/pcap.go
generated
vendored
266
cmd/vendor/github.com/akrennmair/gopcap/pcap.go
generated
vendored
@ -1,266 +0,0 @@
|
|||||||
// Interface to both live and offline pcap parsing.
|
|
||||||
package pcap
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo linux LDFLAGS: -lpcap
|
|
||||||
#cgo freebsd LDFLAGS: -lpcap
|
|
||||||
#cgo darwin LDFLAGS: -lpcap
|
|
||||||
#cgo windows CFLAGS: -I C:/WpdPack/Include
|
|
||||||
#cgo windows,386 LDFLAGS: -L C:/WpdPack/Lib -lwpcap
|
|
||||||
#cgo windows,amd64 LDFLAGS: -L C:/WpdPack/Lib/x64 -lwpcap
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <pcap.h>
|
|
||||||
|
|
||||||
// Workaround for not knowing how to cast to const u_char**
|
|
||||||
int hack_pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header,
|
|
||||||
u_char **pkt_data) {
|
|
||||||
return pcap_next_ex(p, pkt_header, (const u_char **)pkt_data);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Pcap struct {
|
|
||||||
cptr *C.pcap_t
|
|
||||||
}
|
|
||||||
|
|
||||||
type Stat struct {
|
|
||||||
PacketsReceived uint32
|
|
||||||
PacketsDropped uint32
|
|
||||||
PacketsIfDropped uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type Interface struct {
|
|
||||||
Name string
|
|
||||||
Description string
|
|
||||||
Addresses []IFAddress
|
|
||||||
// TODO: add more elements
|
|
||||||
}
|
|
||||||
|
|
||||||
type IFAddress struct {
|
|
||||||
IP net.IP
|
|
||||||
Netmask net.IPMask
|
|
||||||
// TODO: add broadcast + PtP dst ?
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pcap) Next() (pkt *Packet) {
|
|
||||||
rv, _ := p.NextEx()
|
|
||||||
return rv
|
|
||||||
}
|
|
||||||
|
|
||||||
// Openlive opens a device and returns a *Pcap handler
|
|
||||||
func Openlive(device string, snaplen int32, promisc bool, timeout_ms int32) (handle *Pcap, err error) {
|
|
||||||
var buf *C.char
|
|
||||||
buf = (*C.char)(C.calloc(ERRBUF_SIZE, 1))
|
|
||||||
h := new(Pcap)
|
|
||||||
var pro int32
|
|
||||||
if promisc {
|
|
||||||
pro = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
dev := C.CString(device)
|
|
||||||
defer C.free(unsafe.Pointer(dev))
|
|
||||||
|
|
||||||
h.cptr = C.pcap_open_live(dev, C.int(snaplen), C.int(pro), C.int(timeout_ms), buf)
|
|
||||||
if nil == h.cptr {
|
|
||||||
handle = nil
|
|
||||||
err = errors.New(C.GoString(buf))
|
|
||||||
} else {
|
|
||||||
handle = h
|
|
||||||
}
|
|
||||||
C.free(unsafe.Pointer(buf))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func Openoffline(file string) (handle *Pcap, err error) {
|
|
||||||
var buf *C.char
|
|
||||||
buf = (*C.char)(C.calloc(ERRBUF_SIZE, 1))
|
|
||||||
h := new(Pcap)
|
|
||||||
|
|
||||||
cf := C.CString(file)
|
|
||||||
defer C.free(unsafe.Pointer(cf))
|
|
||||||
|
|
||||||
h.cptr = C.pcap_open_offline(cf, buf)
|
|
||||||
if nil == h.cptr {
|
|
||||||
handle = nil
|
|
||||||
err = errors.New(C.GoString(buf))
|
|
||||||
} else {
|
|
||||||
handle = h
|
|
||||||
}
|
|
||||||
C.free(unsafe.Pointer(buf))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pcap) NextEx() (pkt *Packet, result int32) {
|
|
||||||
var pkthdr *C.struct_pcap_pkthdr
|
|
||||||
|
|
||||||
var buf_ptr *C.u_char
|
|
||||||
var buf unsafe.Pointer
|
|
||||||
result = int32(C.hack_pcap_next_ex(p.cptr, &pkthdr, &buf_ptr))
|
|
||||||
|
|
||||||
buf = unsafe.Pointer(buf_ptr)
|
|
||||||
if nil == buf {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt = new(Packet)
|
|
||||||
pkt.Time = time.Unix(int64(pkthdr.ts.tv_sec), int64(pkthdr.ts.tv_usec)*1000)
|
|
||||||
pkt.Caplen = uint32(pkthdr.caplen)
|
|
||||||
pkt.Len = uint32(pkthdr.len)
|
|
||||||
pkt.Data = C.GoBytes(buf, C.int(pkthdr.caplen))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pcap) Close() {
|
|
||||||
C.pcap_close(p.cptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pcap) Geterror() error {
|
|
||||||
return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pcap) Getstats() (stat *Stat, err error) {
|
|
||||||
var cstats _Ctype_struct_pcap_stat
|
|
||||||
if -1 == C.pcap_stats(p.cptr, &cstats) {
|
|
||||||
return nil, p.Geterror()
|
|
||||||
}
|
|
||||||
stats := new(Stat)
|
|
||||||
stats.PacketsReceived = uint32(cstats.ps_recv)
|
|
||||||
stats.PacketsDropped = uint32(cstats.ps_drop)
|
|
||||||
stats.PacketsIfDropped = uint32(cstats.ps_ifdrop)
|
|
||||||
|
|
||||||
return stats, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pcap) Setfilter(expr string) (err error) {
|
|
||||||
var bpf _Ctype_struct_bpf_program
|
|
||||||
cexpr := C.CString(expr)
|
|
||||||
defer C.free(unsafe.Pointer(cexpr))
|
|
||||||
|
|
||||||
if -1 == C.pcap_compile(p.cptr, &bpf, cexpr, 1, 0) {
|
|
||||||
return p.Geterror()
|
|
||||||
}
|
|
||||||
|
|
||||||
if -1 == C.pcap_setfilter(p.cptr, &bpf) {
|
|
||||||
C.pcap_freecode(&bpf)
|
|
||||||
return p.Geterror()
|
|
||||||
}
|
|
||||||
C.pcap_freecode(&bpf)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Version() string {
|
|
||||||
return C.GoString(C.pcap_lib_version())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pcap) Datalink() int {
|
|
||||||
return int(C.pcap_datalink(p.cptr))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pcap) Setdatalink(dlt int) error {
|
|
||||||
if -1 == C.pcap_set_datalink(p.cptr, C.int(dlt)) {
|
|
||||||
return p.Geterror()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DatalinkValueToName(dlt int) string {
|
|
||||||
if name := C.pcap_datalink_val_to_name(C.int(dlt)); name != nil {
|
|
||||||
return C.GoString(name)
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func DatalinkValueToDescription(dlt int) string {
|
|
||||||
if desc := C.pcap_datalink_val_to_description(C.int(dlt)); desc != nil {
|
|
||||||
return C.GoString(desc)
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func Findalldevs() (ifs []Interface, err error) {
|
|
||||||
var buf *C.char
|
|
||||||
buf = (*C.char)(C.calloc(ERRBUF_SIZE, 1))
|
|
||||||
defer C.free(unsafe.Pointer(buf))
|
|
||||||
var alldevsp *C.pcap_if_t
|
|
||||||
|
|
||||||
if -1 == C.pcap_findalldevs((**C.pcap_if_t)(&alldevsp), buf) {
|
|
||||||
return nil, errors.New(C.GoString(buf))
|
|
||||||
}
|
|
||||||
defer C.pcap_freealldevs((*C.pcap_if_t)(alldevsp))
|
|
||||||
dev := alldevsp
|
|
||||||
var i uint32
|
|
||||||
for i = 0; dev != nil; dev = (*C.pcap_if_t)(dev.next) {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
ifs = make([]Interface, i)
|
|
||||||
dev = alldevsp
|
|
||||||
for j := uint32(0); dev != nil; dev = (*C.pcap_if_t)(dev.next) {
|
|
||||||
var iface Interface
|
|
||||||
iface.Name = C.GoString(dev.name)
|
|
||||||
iface.Description = C.GoString(dev.description)
|
|
||||||
iface.Addresses = findalladdresses(dev.addresses)
|
|
||||||
// TODO: add more elements
|
|
||||||
ifs[j] = iface
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func findalladdresses(addresses *_Ctype_struct_pcap_addr) (retval []IFAddress) {
|
|
||||||
// TODO - make it support more than IPv4 and IPv6?
|
|
||||||
retval = make([]IFAddress, 0, 1)
|
|
||||||
for curaddr := addresses; curaddr != nil; curaddr = (*_Ctype_struct_pcap_addr)(curaddr.next) {
|
|
||||||
var a IFAddress
|
|
||||||
var err error
|
|
||||||
if a.IP, err = sockaddr_to_IP((*syscall.RawSockaddr)(unsafe.Pointer(curaddr.addr))); err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if a.Netmask, err = sockaddr_to_IP((*syscall.RawSockaddr)(unsafe.Pointer(curaddr.addr))); err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
retval = append(retval, a)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func sockaddr_to_IP(rsa *syscall.RawSockaddr) (IP []byte, err error) {
|
|
||||||
switch rsa.Family {
|
|
||||||
case syscall.AF_INET:
|
|
||||||
pp := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa))
|
|
||||||
IP = make([]byte, 4)
|
|
||||||
for i := 0; i < len(IP); i++ {
|
|
||||||
IP[i] = pp.Addr[i]
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case syscall.AF_INET6:
|
|
||||||
pp := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa))
|
|
||||||
IP = make([]byte, 16)
|
|
||||||
for i := 0; i < len(IP); i++ {
|
|
||||||
IP[i] = pp.Addr[i]
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = errors.New("Unsupported address type")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pcap) Inject(data []byte) (err error) {
|
|
||||||
buf := (*C.char)(C.malloc((C.size_t)(len(data))))
|
|
||||||
|
|
||||||
for i := 0; i < len(data); i++ {
|
|
||||||
*(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(buf)) + uintptr(i))) = data[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
if -1 == C.pcap_sendpacket(p.cptr, (*C.u_char)(unsafe.Pointer(buf)), (C.int)(len(data))) {
|
|
||||||
err = p.Geterror()
|
|
||||||
}
|
|
||||||
C.free(unsafe.Pointer(buf))
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
# etcd-top
|
|
||||||
etcd realtime workload analyzer. Useful for rapid diagnosis of production usage issues and analysis of production request distributions.
|
|
||||||
|
|
||||||
usage:
|
|
||||||
```
|
|
||||||
-iface="eth0": interface for sniffing traffic on
|
|
||||||
-period=1: seconds between submissions
|
|
||||||
-ports="2379": etcd listening ports
|
|
||||||
-promiscuous=true: whether to perform promiscuous sniffing or not.
|
|
||||||
-topk=10: submit stats for the top <K> sniffed paths
|
|
||||||
```
|
|
||||||
|
|
||||||
result:
|
|
||||||
```
|
|
||||||
go run etcd-top.go --period=1 -topk=3
|
|
||||||
1440035702 sniffed 1074 requests over last 1 seconds
|
|
||||||
|
|
||||||
Top 3 most popular http requests:
|
|
||||||
Sum Rate Verb Path
|
|
||||||
1305 22 GET /v2/keys/c
|
|
||||||
1302 8 GET /v2/keys/S
|
|
||||||
1297 10 GET /v2/keys/h
|
|
||||||
```
|
|
@ -1,16 +0,0 @@
|
|||||||
// Copyright 2016 The etcd Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// etcd-top is a utility for analyzing etcd v2 API workload traffic.
|
|
||||||
package main
|
|
@ -1,229 +0,0 @@
|
|||||||
// Copyright 2015 The etcd Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/akrennmair/gopcap"
|
|
||||||
"github.com/spacejam/loghisto"
|
|
||||||
)
|
|
||||||
|
|
||||||
type nameSum struct {
|
|
||||||
Name string
|
|
||||||
Sum float64
|
|
||||||
Rate float64
|
|
||||||
}
|
|
||||||
|
|
||||||
type nameSums []nameSum
|
|
||||||
|
|
||||||
func (n nameSums) Len() int {
|
|
||||||
return len(n)
|
|
||||||
}
|
|
||||||
func (n nameSums) Less(i, j int) bool {
|
|
||||||
return n[i].Sum > n[j].Sum
|
|
||||||
}
|
|
||||||
func (n nameSums) Swap(i, j int) {
|
|
||||||
n[i], n[j] = n[j], n[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function listens for periodic metrics from the loghisto metric system,
|
|
||||||
// and upon receipt of a batch of them it will print out the desired topK.
|
|
||||||
func statPrinter(metricStream chan *loghisto.ProcessedMetricSet, topK, period uint) {
|
|
||||||
for m := range metricStream {
|
|
||||||
requestCounter := float64(0)
|
|
||||||
nvs := nameSums{}
|
|
||||||
for k, v := range m.Metrics {
|
|
||||||
// loghisto adds _rate suffixed metrics for counters and histograms
|
|
||||||
if strings.HasSuffix(k, "_rate") && !strings.HasSuffix(k, "_rate_rate") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
nvs = append(nvs, nameSum{
|
|
||||||
Name: k,
|
|
||||||
Sum: v,
|
|
||||||
Rate: m.Metrics[k+"_rate"],
|
|
||||||
})
|
|
||||||
requestCounter += m.Metrics[k+"_rate"]
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("\n%d sniffed %d requests over last %d seconds\n\n", time.Now().Unix(),
|
|
||||||
uint(requestCounter), period)
|
|
||||||
if len(nvs) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
sort.Sort(nvs)
|
|
||||||
fmt.Printf("Top %d most popular http requests:\n", topK)
|
|
||||||
fmt.Println("Total Sum Period Sum Verb Path")
|
|
||||||
for _, nv := range nvs[0:int(math.Min(float64(len(nvs)), float64(topK)))] {
|
|
||||||
fmt.Printf("%9.1d %7.1d %s\n", int(nv.Sum), int(nv.Rate), nv.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// packetDecoder decodes packets and hands them off to the streamRouter
|
|
||||||
func packetDecoder(packetsIn chan *pcap.Packet, packetsOut chan *pcap.Packet) {
|
|
||||||
for pkt := range packetsIn {
|
|
||||||
pkt.Decode()
|
|
||||||
select {
|
|
||||||
case packetsOut <- pkt:
|
|
||||||
default:
|
|
||||||
fmt.Fprint(os.Stderr, "shedding at decoder!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// processor tries to parse an http request from each packet, and if
|
|
||||||
// successful it records metrics about it in the loghisto metric system.
|
|
||||||
func processor(ms *loghisto.MetricSystem, packetsIn chan *pcap.Packet) {
|
|
||||||
for pkt := range packetsIn {
|
|
||||||
req, reqErr := http.ReadRequest(bufio.NewReader(bytes.NewReader(pkt.Payload)))
|
|
||||||
if reqErr == nil {
|
|
||||||
ms.Counter(req.Method+" "+req.URL.Path, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// streamRouter takes a decoded packet and routes it to a processor that can deal with all requests
|
|
||||||
// and responses for this particular TCP connection. This allows the processor to own a local map
|
|
||||||
// of requests so that it can avoid coordinating with other goroutines to perform analysis.
|
|
||||||
func streamRouter(ports []uint16, parsedPackets chan *pcap.Packet, processors []chan *pcap.Packet) {
|
|
||||||
for pkt := range parsedPackets {
|
|
||||||
if pkt.TCP == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
clientPort := uint16(0)
|
|
||||||
for _, p := range ports {
|
|
||||||
if pkt.TCP.SrcPort == p {
|
|
||||||
clientPort = pkt.TCP.DestPort
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if pkt.TCP.DestPort == p {
|
|
||||||
clientPort = pkt.TCP.SrcPort
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if clientPort != 0 {
|
|
||||||
// client Port can be assumed to have sufficient entropy for
|
|
||||||
// distribution among processors, and we want the same
|
|
||||||
// tcp stream to go to the same processor every time
|
|
||||||
// so that if we do proper packet reconstruction it will
|
|
||||||
// be easier.
|
|
||||||
select {
|
|
||||||
case processors[int(clientPort)%len(processors)] <- pkt:
|
|
||||||
default:
|
|
||||||
fmt.Fprint(os.Stderr, "Shedding load at router!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. parse args
|
|
||||||
// 2. start the loghisto metric system
|
|
||||||
// 3. start the processing and printing goroutines
|
|
||||||
// 4. open the pcap handler
|
|
||||||
// 5. hand off packets from the handler to the decoder
|
|
||||||
func main() {
|
|
||||||
portsArg := flag.String("ports", "2379", "etcd listening ports")
|
|
||||||
iface := flag.String("iface", "eth0", "interface for sniffing traffic on")
|
|
||||||
promisc := flag.Bool("promiscuous", true, "promiscuous mode")
|
|
||||||
period := flag.Uint("period", 1, "seconds between submissions")
|
|
||||||
topK := flag.Uint("topk", 10, "submit stats for the top <K> sniffed paths")
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
numCPU := runtime.NumCPU()
|
|
||||||
runtime.GOMAXPROCS(numCPU)
|
|
||||||
|
|
||||||
ms := loghisto.NewMetricSystem(time.Duration(*period)*time.Second, false)
|
|
||||||
ms.Start()
|
|
||||||
metricStream := make(chan *loghisto.ProcessedMetricSet, 2)
|
|
||||||
ms.SubscribeToProcessedMetrics(metricStream)
|
|
||||||
defer ms.UnsubscribeFromProcessedMetrics(metricStream)
|
|
||||||
|
|
||||||
go statPrinter(metricStream, *topK, *period)
|
|
||||||
|
|
||||||
ports := []uint16{}
|
|
||||||
for _, p := range strings.Split(*portsArg, ",") {
|
|
||||||
port, err := strconv.Atoi(p)
|
|
||||||
if err == nil {
|
|
||||||
ports = append(ports, uint16(port))
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to parse port \"%s\": %v\n", p, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ports) == 0 {
|
|
||||||
fmt.Fprint(os.Stderr, "No ports given! Exiting.\n")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We choose 1518 for the snaplen because it's the default
|
|
||||||
// ethernet MTU at the link layer. We choose 1000 for the
|
|
||||||
// timeout based on a measurement for its impact on latency
|
|
||||||
// impact, but it is less precise.
|
|
||||||
h, err := pcap.Openlive(*iface, 1518, *promisc, 1000)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
defer h.Close()
|
|
||||||
|
|
||||||
portArray := strings.Split(*portsArg, ",")
|
|
||||||
dst := strings.Join(portArray, " or dst port ")
|
|
||||||
src := strings.Join(portArray, " or src port ")
|
|
||||||
filter := fmt.Sprintf("tcp and (dst port %s or src port %s)", dst, src)
|
|
||||||
fmt.Println("using bpf filter: ", filter)
|
|
||||||
if err := h.Setfilter(filter); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
unparsedPackets := make(chan *pcap.Packet, 16384)
|
|
||||||
parsedPackets := make(chan *pcap.Packet, 16384)
|
|
||||||
for i := 0; i < int(math.Max(2, float64(numCPU/4))); i++ {
|
|
||||||
go packetDecoder(unparsedPackets, parsedPackets)
|
|
||||||
}
|
|
||||||
|
|
||||||
processors := []chan *pcap.Packet{}
|
|
||||||
for i := 0; i < int(math.Max(2, float64(numCPU/4))); i++ {
|
|
||||||
p := make(chan *pcap.Packet, 16384)
|
|
||||||
processors = append(processors, p)
|
|
||||||
go processor(ms, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
go streamRouter(ports, parsedPackets, processors)
|
|
||||||
|
|
||||||
for {
|
|
||||||
pkt := h.Next()
|
|
||||||
if pkt != nil {
|
|
||||||
select {
|
|
||||||
case unparsedPackets <- pkt:
|
|
||||||
default:
|
|
||||||
fmt.Fprint(os.Stderr, "SHEDDING IN MAIN")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user