Commits

Anonymous committed e6e959f

转移至bitbucket

  • Participants

Comments (0)

Files changed (7)

+# This file is used to ignore files which are generated in the Qt build system
+# ----------------------------------------------------------------------------
+^.git/
+/bin/
+
+syntax:glob
+callgrind.out.*
+pcviewer.cfg
+
+*.cxx
+*~
+*.exe
+*.pyc
+*.a
+*.8
+*.dat
+*.la
+*.core
+*.moc
+*.o
+*.obj
+*.orig
+*.swp
+*.rej
+*.so
+*.bak
+*.mode1
+*.mode1v3
+*_pch.h.cpp
+*_resource.rc
+.qmake.cache
+.qmake.vars
+*.prl
+*.tar 
+*.gz
+
+#项目专用排除文件
+_desktop.ini
+SS_Server/SS_Server
+UP_Server/UP_Server
+DB_Reader/DB_Reader
+DB_Reader_Multi/DB_Reader_Multi
+Data_Server/Data_Server
+Analysis_Data_Store/Analysis_Data_Store
+Analysis_Data_Store_Pipe/Analysis_Data_Store_Pipe
+Server_TS/DB_Reader
+[paths]
+default = http://bitbucket.org/sungo/gopcap
+default-push = ssh://hg@bitbucket.org/sungo/gopcap
+[ui]
+username=sungo
+include $(GOROOT)/src/Make.$(GOARCH)
+
+TARG=pcap
+GOFILES=decode.go
+CGOFILES=pcap.go
+CGO_LDFLAGS=-lpcap
+CLEANFILES=pcaptest tcpdump
+
+include $(GOROOT)/src/Make.pkg
+
+pcaptest: pcaptest.go install
+	$(GC) pcaptest.go
+	$(LD) -o $@ pcaptest.$(O)
+
+tcpdump: tcpdump.go install
+	$(GC) tcpdump.go
+	$(LD) -o $@ tcpdump.$(O)
+package pcap
+
+import (
+	"fmt"
+	"bufio"
+	"os"
+	"time"
+)
+
+const (
+	TYPE_IP  = 0x0800
+	TYPE_ARP = 0x0806
+	TYPE_IP6 = 0x86DD
+	IP_ICMP  = 1
+	IP_INIP  = 4
+	IP_TCP   = 6
+	IP_UDP   = 17
+)
+
+var out *bufio.Writer
+var errout *bufio.Writer
+
+func init() {
+    out = bufio.NewWriter(os.Stdout)
+    errout = bufio.NewWriter(os.Stderr)
+}
+
+func DecodeEthernetPkt(pkt *Packet) (packet *DecodedPkt) {
+
+	packet = new(DecodedPkt)
+
+	packet.PcapPktHdr = pkt
+	packet.EthernetHeader = DecodeEther(pkt.Data)
+
+	switch packet.EthernetHeader.Type {
+	case TYPE_IP:
+		packet.IpHeader, packet.UdpHeader, packet.TcpHeader, packet.IcmpHeader = Decodeip(pkt.Data[14:])
+	case TYPE_ARP:
+		packet.ArpHeader = Decodearp(pkt.Data[14:])
+		// 	case TYPE_IP6:
+		// 		Decodeip6(pkt.Data[14:])
+// 	default:
+// 		Unsupported(packet.EthernetHeader.Type)
+	}
+
+	return
+}
+
+type DecodedPkt struct {
+	PcapPktHdr     *Packet
+	EthernetHeader *EtherHdr
+	ArpHeader      *Arphdr
+	IpHeader       *Iphdr
+	TcpHeader      *Tcphdr
+	UdpHeader      *Udphdr
+	IcmpHeader     *Icmphdr
+	Data           []byte
+}
+
+type EtherHdr struct {
+	DestMacAddress uint64
+	SrcMacAddress  uint64
+	Type           uint16
+	Data           []byte
+}
+
+
+func DecodeEther(pkt []byte) (hdr *EtherHdr) {
+
+	hdr = new(EtherHdr)
+
+	hdr.DestMacAddress = Decodemac(pkt[0:6])
+	hdr.SrcMacAddress = Decodemac(pkt[6:12])
+	hdr.Type = Decodeuint16(pkt[12:14])
+	hdr.Data = pkt[14:]
+
+	return
+}
+
+func Decodemac(pkt []byte) uint64 {
+	mac := uint64(0)
+	for i := uint(0); i < 6; i++ {
+		mac = (mac << 8) + uint64(pkt[i])
+	}
+	return mac
+}
+
+func Decodeuint16(pkt []byte) uint16 {
+	return uint16(pkt[0])<<8 + uint16(pkt[1])
+}
+
+func Decodeuint32(pkt []byte) uint32 {
+	return uint32(pkt[0])<<24 + uint32(pkt[1])<<16 + uint32(pkt[2])<<8 + uint32(pkt[3])
+}
+
+func Unsupported(pkttype uint16) {
+	fmt.Printf("unsupported protocol %d\n", int(pkttype))
+}
+
+type Arphdr struct {
+	Addrtype          uint16
+	Protocol          uint16
+	HwAddressSize     uint8
+	ProtAddressSize   uint8
+	Operation         uint16
+	SourceHwAddress   []byte
+	SourceProtAddress []byte
+	DestHwAddress     []byte
+	DestProtAddress   []byte
+	Data    []byte
+}
+
+func Decodearp(pkt []byte) (arp *Arphdr) {
+	arp = new(Arphdr)
+	arp.Addrtype = Decodeuint16(pkt[0:2])
+	arp.Protocol = Decodeuint16(pkt[2:4])
+	arp.HwAddressSize = pkt[4]
+	arp.ProtAddressSize = pkt[5]
+	arp.Operation = Decodeuint16(pkt[6:8])
+	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]
+    arp.Data = pkt[8+2*arp.HwAddressSize+2*arp.ProtAddressSize:]
+	return
+}
+
+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
+}
+
+type INIPHdr struct {
+	Iphdr
+}
+
+func Decodeip(pkt []byte) (ip *Iphdr, udphdr *Udphdr, tcphdr *Tcphdr, icmphdr *Icmphdr) {
+	ip = new(Iphdr)
+	udphdr = new(Udphdr)
+	tcphdr = new(Tcphdr)
+	icmphdr = new(Icmphdr)
+
+	ip.Version = uint8(pkt[0]) >> 4
+	ip.Ihl = uint8(pkt[0]) & 0x0F
+	ip.Tos = pkt[1]
+	ip.Length = Decodeuint16(pkt[2:4])
+	ip.Id = Decodeuint16(pkt[4:6])
+	flagsfrags := Decodeuint16(pkt[6:8])
+	ip.Flags = uint8(flagsfrags >> 13)
+	ip.FragOffset = flagsfrags & 0x1FFF
+	ip.Ttl = pkt[8]
+	ip.Protocol = pkt[9]
+	ip.Checksum = Decodeuint16(pkt[10:12])
+	ip.SrcIp = pkt[12:16]
+	ip.DestIp = pkt[16:20]
+	
+
+	switch ip.Protocol {
+	case IP_TCP:
+		tcphdr = Decodetcp(ip, pkt[ip.Ihl*4:])
+		udphdr = nil
+        icmphdr = nil
+	case IP_UDP:
+		udphdr = Decodeudp(ip, pkt[ip.Ihl*4:])
+		tcphdr = nil
+        icmphdr = nil
+	case IP_ICMP:
+		icmphdr = Decodeicmp(ip, pkt[ip.Ihl*4:])
+		tcphdr = nil
+        udphdr = nil
+	case IP_INIP:
+		_, _, _, _ = Decodeip(pkt[ip.Ihl*4:])
+	default:
+		fmt.Printf(" unsupported protocol %d", int(ip.Protocol))
+	}
+
+	return
+}
+
+type Tcphdr struct {
+	SrcPort    uint16
+	DestPort   uint16
+	Seq        uint32
+	Ack        uint32
+	DataOffset uint8
+	Flags      uint8
+	Window     uint16
+	Checksum   uint16
+	Urgent     uint16
+	Data       []byte
+}
+
+const (
+	TCP_FIN = 1 << iota
+	TCP_SYN
+	TCP_RST
+	TCP_PSH
+	TCP_ACK
+	TCP_URG
+)
+
+func Decodetcp(ip *Iphdr, pkt []byte) (tcp *Tcphdr) {
+	tcp = new(Tcphdr)
+	tcp.SrcPort = Decodeuint16(pkt[0:2])
+	tcp.DestPort = Decodeuint16(pkt[2:4])
+	tcp.Seq = Decodeuint32(pkt[4:8])
+	tcp.Ack = Decodeuint32(pkt[8:12])
+	tcp.DataOffset = pkt[12] & 0x0F
+	tcp.Flags = uint8(Decodeuint16(pkt[12:14]) & 0x3F)
+	tcp.Window = Decodeuint16(pkt[14:16])
+	tcp.Checksum = Decodeuint16(pkt[16:18])
+	tcp.Urgent = Decodeuint16(pkt[18:20])
+	tcp.Data = pkt[tcp.DataOffset*4:]
+
+	return
+}
+
+type Udphdr struct {
+	SrcPort  uint16
+	DestPort uint16
+	Length   uint16
+	Checksum uint16
+	Data    []byte
+}
+
+func Decodeudp(ip *Iphdr, pkt []byte) (udp *Udphdr) {
+	udp = new(Udphdr)
+
+	udp.SrcPort = Decodeuint16(pkt[0:2])
+	udp.DestPort = Decodeuint16(pkt[2:4])
+	udp.Length = Decodeuint16(pkt[4:6])
+	udp.Checksum = Decodeuint16(pkt[6:8])
+	udp.Data = pkt[8:]
+	return
+}
+
+type Icmphdr struct {
+	Type     uint8
+	Code     uint8
+	Checksum uint16
+	Id       uint16
+	Seq      uint16
+	Data     []byte
+}
+
+func Decodeicmp(ip *Iphdr, pkt []byte) (icmp *Icmphdr) {
+	icmp = new(Icmphdr)
+	icmp.Type = pkt[0]
+	icmp.Code = pkt[1]
+	icmp.Checksum = Decodeuint16(pkt[2:4])
+	icmp.Id = Decodeuint16(pkt[4:6])
+	icmp.Seq = Decodeuint16(pkt[6:8])
+	icmp.Data = pkt[8:]
+	return
+}
+
+func PrintDecodedPkt(packet *DecodedPkt) {
+    t := time.SecondsToLocalTime(int64(packet.PcapPktHdr.Time.Sec))
+    fmt.Fprintf(out, "%02d:%02d:%02d.%06d ", t.Hour, t.Minute, t.Second, packet.PcapPktHdr.Time.Usec)   
+    switch {
+    case packet.ArpHeader != nil:
+        Printarp(packet.ArpHeader)
+    case packet.IpHeader != nil:
+        switch {
+        case packet.TcpHeader != nil:
+            Printtcp(packet.IpHeader, packet.TcpHeader)
+        case packet.UdpHeader != nil:
+            Printudp(packet.IpHeader, packet.UdpHeader)
+        case packet.IcmpHeader != nil:
+            Printicmp(packet.IpHeader, packet.IcmpHeader)
+        }
+    }
+    out.WriteString("\n")
+    out.Flush()
+}
+
+func Arpop(op uint16) string {
+    switch op {
+    case 1:
+        return "Request"
+    case 2:
+        return "Reply"
+    }
+    return ""
+}
+
+func Printarp(arp *Arphdr) {
+    fmt.Fprintf(out, "ARP, %s ", Arpop(arp.Operation))
+
+    if arp.Addrtype == LINKTYPE_ETHERNET && arp.Protocol == TYPE_IP {
+        fmt.Fprintf(out, "%012x (", Decodemac(arp.SourceHwAddress))
+        Printip(arp.SourceProtAddress)
+        fmt.Fprintf(out, ") > %012x (", Decodemac(arp.DestHwAddress))
+        Printip(arp.DestProtAddress)
+        fmt.Fprintf(out, ")")
+    } else {
+        fmt.Fprintf(out, "addrtype = %d protocol = %d", arp.Addrtype, arp.Protocol)
+    }
+}
+
+
+func Printflags(flags uint8) {
+    out.WriteString("[ ")
+    if 0 != (flags & TCP_SYN) {
+        out.WriteString("syn ")
+    }
+    if 0 != (flags & TCP_FIN) {
+        out.WriteString("fin ")
+    }
+    if 0 != (flags & TCP_ACK) {
+        out.WriteString("ack ")
+    }
+    if 0 != (flags & TCP_PSH) {
+        out.WriteString("psh ")
+    }
+    if 0 != (flags & TCP_RST) {
+        out.WriteString("rst ")
+    }
+    if 0 != (flags & TCP_URG) {
+        out.WriteString("urg ")
+    }
+    out.WriteString("]")
+}
+
+
+func Printip(ip []byte) {
+    for i := 0; i < 4; i++ {
+        fmt.Fprintf(out, "%d", int(ip[i]))
+        if i < 3 {
+            out.WriteString(".")
+        }
+    }
+}
+
+func Printtcp(ip *Iphdr, tcp *Tcphdr) {
+    out.WriteString("TCP, ")
+    Printip(ip.SrcIp)
+    fmt.Fprintf(out, ":%d > ", int(tcp.SrcPort))
+    Printip(ip.DestIp)
+    fmt.Fprintf(out, ":%d ", int(tcp.DestPort))
+    Printflags(tcp.Flags)
+    fmt.Fprintf(out, " SEQ=%d ACK=%d WIN=%d LEN=%d", 
+                int64(tcp.Seq), int64(tcp.Ack),int64(tcp.Window),int64(len(tcp.Data)))
+}
+
+func Printudp(ip *Iphdr, udp *Udphdr) {
+    out.WriteString("UDP, ")
+    Printip(ip.SrcIp)
+    fmt.Fprintf(out, ":%d > ", udp.SrcPort)
+    Printip(ip.DestIp)
+    fmt.Fprintf(out, ":%d LEN=%d CHKSUM=%d", int(udp.DestPort), int(udp.Length), int(udp.Checksum))
+}
+
+func Printicmp(ip *Iphdr, icmp *Icmphdr) {
+    out.WriteString("ICMP, ")
+    Printip(ip.SrcIp)
+    out.WriteString(" > ")
+    Printip(ip.DestIp)
+    fmt.Fprintf(out, " Type = %d Code = %d ", icmp.Type, icmp.Code)
+    switch icmp.Type {
+    case 0:
+        fmt.Fprintf(out, "Echo reply ttl=%d seq=%d len=%d", ip.Ttl, icmp.Seq,len(icmp.Data))
+    case 3:
+        switch icmp.Code {
+        case 0:
+            out.WriteString("Network unreachable")
+        case 1:
+            out.WriteString("Host unreachable")
+        case 2:
+            out.WriteString("Protocol unreachable")
+        case 3:
+            out.WriteString("Port unreachable")
+        default:
+            out.WriteString("Destination unreachable")
+        }
+    case 8:
+        fmt.Fprintf(out, "Echo request ttl=%d seq=%d", ip.Ttl, icmp.Seq)
+    case 30:
+        out.WriteString("Traceroute")
+    }
+}
+
+func min(a, b int) int {
+    if a < b {
+        return a
+    }
+    return b
+}
+
+func Hexdump(pkt *Packet) {
+    for i := 0; i < len(pkt.Data); i += 16 {
+        Dumpline(uint32(i), pkt.Data[i:min(i+16, len(pkt.Data))])
+    }
+}
+
+func Dumpline(addr uint32, line []byte) {
+    fmt.Fprintf(out, "\t0x%04x: ", int32(addr))
+    var i uint16
+    for i = 0; i < 16 && i < uint16(len(line)); i++ {
+        if i%2 == 0 {
+            out.WriteString(" ")
+        }
+        fmt.Fprintf(out, "%02x", line[i])
+    }
+    for j := i; j <= 16; j++ {
+        if j%2 == 0 {
+            out.WriteString(" ")
+        }
+        out.WriteString("  ")
+    }
+    out.WriteString("  ")
+    for i = 0; i < 16 && i < uint16(len(line)); i++ {
+        if line[i] >= 32 && line[i] <= 126 {
+            fmt.Fprintf(out, "%c", line[i])
+        } else {
+            out.WriteString(".")
+        }
+    }
+    out.WriteString("\n")
+}
+
+func Decodeip6(pkt []byte) {
+    out.WriteString("TODO: IPv6")
+}
+package pcap
+
+/*
+struct pcap { int dummy; };
+#include <stdlib.h>
+#include <pcap.h>
+*/
+import "C"
+import (
+	"unsafe"
+)
+
+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 Pcap struct {
+	cptr *C.pcap_t
+}
+
+type Packet struct {
+	Time struct { 
+		Sec int32
+		Usec int32 
+	}
+	Caplen uint32
+	Len uint32
+	Data []byte
+}
+
+type Stat struct {
+	PacketsReceived uint32
+	PacketsDropped uint32
+	PacketsIfDropped uint32
+}
+
+type Interface struct {
+	Name string
+	Description string
+	// TODO: add more elements
+}
+
+func Openlive(device string, snaplen int32, promisc bool, timeout_ms int32) (handle *Pcap, err string) {
+	var buf *C.char
+	buf = (*C.char)(C.calloc(ERRBUF_SIZE, 1))
+	h := new(Pcap)
+	var pro int32
+	if promisc { 
+		pro = 1 
+	} else { 
+		pro = 0 
+	}
+	h.cptr = C.pcap_open_live(C.CString(device), C.int(snaplen), C.int(pro), C.int(timeout_ms), buf)
+	if nil == h.cptr {
+		handle = nil
+		err = C.GoString(buf)
+	} else {
+		handle = h
+	}
+	C.free(unsafe.Pointer(buf))
+	return
+}
+
+func Openoffline(file string) (handle *Pcap, err string) {
+	var buf *C.char
+	buf = (*C.char)(C.calloc(ERRBUF_SIZE, 1))
+	h := new(Pcap)
+	h.cptr = C.pcap_open_offline(C.CString(file), buf)
+	if nil == h.cptr {
+		handle = nil
+		err = C.GoString(buf)
+	} else {
+		handle = h
+	}
+	C.free(unsafe.Pointer(buf))
+	return
+}
+
+func(p *Pcap) Next() (pkt *Packet) {
+	var pkthdr C.struct_pcap_pkthdr
+	var buf unsafe.Pointer
+	buf = unsafe.Pointer(C.pcap_next(p.cptr, &pkthdr))
+	if nil == buf {
+		return nil
+	}
+	pkt = new(Packet)
+	pkt.Time.Sec = int32(pkthdr.ts.tv_sec)
+	pkt.Time.Usec = int32(pkthdr.ts.tv_usec)
+	pkt.Caplen = uint32(pkthdr.caplen)
+	pkt.Len = uint32(pkthdr.len)
+	pkt.Data = make([]byte, pkthdr.caplen)
+
+	for i := uint32(0) ; i < pkt.Caplen ; i++ {
+		pkt.Data[i] = *(*byte)(unsafe.Pointer(uintptr(buf) + uintptr(i)))
+	}
+
+	return
+}
+
+func(p *Pcap) Geterror() string {
+	return C.GoString(C.pcap_geterr(p.cptr))
+}
+
+func(p *Pcap) Getstats() (stat *Stat, err string) {
+	var cstats C.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, ""
+}
+
+func(p *Pcap) Setfilter(expr string) (err string) {
+	var bpf C.struct_bpf_program
+
+	if -1 == C.pcap_compile(p.cptr, &bpf, C.CString(expr), 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 ""
+}
+
+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) string {
+	if -1 == C.pcap_set_datalink(p.cptr, C.int(dlt)) {
+		return p.Geterror()
+	}
+	return ""
+}
+
+func DatalinkValueToName(dlt int) string {
+	name := C.pcap_datalink_val_to_name(C.int(dlt))
+	if nil != name {
+		return C.GoString(name)
+	}
+	return ""
+}
+
+func DatalinkValueToDescription(dlt int) string {
+	desc := C.pcap_datalink_val_to_description(C.int(dlt))
+	if nil != desc {
+		return C.GoString(desc)
+	}
+	return ""
+}
+
+func Findalldevs() (ifs []Interface, err string) {
+	var buf *C.char
+	buf = (*C.char)(C.calloc(ERRBUF_SIZE, 1))
+	var alldevsp *C.struct_pcap_if
+
+	if -1 == C.pcap_findalldevs( (**C.pcap_if_t)(unsafe.Pointer(&alldevsp)), buf ) {
+		ifs = nil
+		err = C.GoString(buf)
+	} else {
+		dev := alldevsp
+		var i uint32
+		for i = 0; dev != nil ; dev = dev.next {
+			i++
+		}
+		ifs = make([]Interface, i)
+		dev = alldevsp
+		for j := uint32(0) ; dev != nil ; dev = dev.next {
+			var iface Interface
+			iface.Name = C.GoString(dev.name)
+			iface.Description = C.GoString(dev.description)
+			// TODO: add more elements
+			ifs[j] = iface
+			j++
+		}
+		C.pcap_freealldevs((*C.pcap_if_t)(alldevsp))
+	}
+	C.free(unsafe.Pointer(buf))
+	return
+}
+
+func(p *Pcap)  Inject(data []byte) (err string) {
+	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_inject(p.cptr, unsafe.Pointer(buf), (C.size_t)(len(data))) {
+		err = p.Geterror()
+	}
+	C.free(unsafe.Pointer(buf))
+	return
+}
+
+type PcapDumper struct {
+    cptr *C.pcap_dumper_t
+}
+
+func NewPcapDumper(p *Pcap, filename string) (pd *PcapDumper) {
+    pd = new(PcapDumper)
+    pd.cptr = C.pcap_dump_open(p.cptr,C.CString(filename))
+    return
+}
+
+func (pd *PcapDumper) Dump(pkt *Packet){
+    var pkthdr C.struct_pcap_pkthdr
+    pkthdr.ts.tv_sec = (C.__time_t)(pkt.Time.Sec)
+    pkthdr.ts.tv_usec = (C.__suseconds_t)(pkt.Time.Usec)
+    pkthdr.caplen = (C.bpf_u_int32)(pkt.Caplen)
+    pkthdr.len = (C.bpf_u_int32)(pkt.Len)
+    
+    buf := (*C.char)(C.malloc((C.size_t)(len(pkt.Data))))
+
+    for i:=0 ; i < len(pkt.Data) ; i++ {
+        *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(buf)) + uintptr(i))) = pkt.Data[i]
+    }
+    
+    C.pcap_dump((*C.u_char)(unsafe.Pointer(pd.cptr)),&pkthdr,(*C.u_char)(unsafe.Pointer(buf)))
+}
+package main
+
+import (
+	"pcap"
+	"fmt"
+	"flag"
+	"time"
+)
+
+func min(x uint32, y uint32) uint32 {
+	if x < y {
+		return x
+	}
+	return y
+}
+
+func main() {
+	var device *string = flag.String("d", "", "device")
+	var file *string = flag.String("r", "", "file")
+	var expr *string = flag.String("e", "", "filter expression")
+
+	flag.Parse()
+	
+	var h *pcap.Pcap
+	var err string
+
+	ifs, err := pcap.Findalldevs()
+	if len(ifs) == 0 {
+		fmt.Printf("Warning: no devices found : %s\n", err)
+	} else {
+		for i := 0 ; i < len(ifs) ; i++ {
+			fmt.Printf("dev %d: %s (%s)\n", i+1, ifs[i].Name, ifs[i].Description)
+		}
+	}
+
+	if *device != "" {
+		h, err = pcap.Openlive(*device, 65535, true, 0)
+		if h == nil {
+			fmt.Printf("Openlive(%s) failed: %s\n", *device, err)
+			return
+		}
+	} else if *file != "" {
+		h, err = pcap.Openoffline(*file)
+		if h == nil {
+			fmt.Printf("Openoffline(%s) failed: %s\n", *file, err)
+			return
+		}
+	} else {
+		fmt.Printf("usage: pcaptest [-d <device> | -r <file>]\n")
+		return
+	}
+
+	fmt.Printf("pcap version: %s\n", pcap.Version())
+
+	if *expr != "" {
+		fmt.Printf("Setting filter: %s\n", *expr)
+		err := h.Setfilter(*expr)
+		if err != "" {
+			fmt.Printf("Warning: setting filter failed: %s\n", err)
+		}
+	}
+
+	for pkt := h.Next() ; pkt != nil ; pkt = h.Next() {
+		fmt.Printf("time: %d.%06d (%s) caplen: %d len: %d\nData:", 
+				int64(pkt.Time.Sec), int64(pkt.Time.Usec), 
+				time.SecondsToLocalTime(int64(pkt.Time.Sec)).String(), int64(pkt.Caplen), int64(pkt.Len))
+		for i:=uint32(0) ; i<pkt.Caplen ; i++ {
+			if i % 32 == 0 {
+				fmt.Printf("\n")
+			}
+			if 32 <= pkt.Data[i] && pkt.Data[i] <= 126 {
+				fmt.Printf("%c", pkt.Data[i])
+			} else {
+				fmt.Printf(".")
+			}
+		}
+		fmt.Printf("\n\n")
+	}
+
+}
+package main
+
+import (
+	"pcap"
+	"fmt"
+	"os"
+	"flag"
+)
+
+var device *string
+var snaplen *int
+var hexdump *bool
+var expr    string
+var offlinefn   *string
+var writefile   *string
+
+func init(){
+    device = flag.String("i", "eth0", "interface")
+    snaplen = flag.Int("s", 65535, "snaplen")
+    hexdump = flag.Bool("X", false, "hexdump")
+    offlinefn = flag.String("r", "", "the tcpdump file to open")
+    writefile = flag.String("w", "", "the tcpdump filename to write")
+
+    flag.Usage = func() {
+        fmt.Printf("usage: %s [ -i interface ] [ -f dumpfile ] [ -s snaplen ] [ -X ] [ expression ]\n", os.Args[0])
+        flag.PrintDefaults()
+    }
+
+    flag.Parse()
+
+    if (len(flag.Args()) > 0) {
+        expr = flag.Arg(0)
+    }
+}
+
+func main() {
+    var h *pcap.Pcap
+    var err string
+    var dumper *pcap.PcapDumper
+    
+    if *offlinefn == "" {
+        h, err = pcap.Openlive(*device, 1500, true, 0)
+    }else{
+        h, err = pcap.Openoffline(*offlinefn)
+    }
+    
+    if *writefile != "" {
+        dumper = pcap.NewPcapDumper(h,*writefile)
+    }
+    
+	if h == nil {
+		fmt.Printf("Warning: no devices found : %s\n", err)
+		os.Exit(-1)
+	}
+	
+	h.Setfilter(expr)
+
+	for pkt := h.Next(); pkt != nil; pkt = h.Next() {
+		packet := pcap.DecodeEthernetPkt(pkt)
+        if dumper==nil {
+            pcap.PrintDecodedPkt(packet)
+        }else{
+            dumper.Dump(packet.PcapPktHdr)
+        }
+	}
+}