| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- // 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
- }
|