// NewRing creates a new PFRing. Note that when the ring is initially created, // it is disabled. The caller must call Enable to start receiving packets. // The caller should call Close on the given ring when finished with it. func NewRing(device string, snaplen uint32, flags Flag) (ring *Ring, _ error) { dev := C.CString(device) defer C.free(unsafe.Pointer(dev)) cptr, err := C.pfring_open(dev, C.u_int32_t(snaplen), C.u_int32_t(flags)) if cptr == nil || err != nil { return nil, fmt.Errorf("pfring NewRing error: %v", err) } ring = &Ring{cptr: cptr, snaplen: int(snaplen)} ring.SetApplicationName(os.Args[0]) return }
func OpenBDB(env Environment, txn Transaction, file string, database *string, dbtype DbType, flags DbFlag, mode int) (*BerkeleyDB, error) { cFile := C.CString(file) defer C.free(unsafe.Pointer(cFile)) var cDatabase *C.char if database != nil { cDatabase = C.CString(*database) defer C.free(unsafe.Pointer(cDatabase)) } var db *BerkeleyDB = new(BerkeleyDB) //The flags parameter is currently unused, and must be set to 0. // https://docs.oracle.com/cd/E17276_01/html/api_reference/C/dbcreate.html err := Err(C.db_create(&db.ptr, env.ptr, 0)) if err != nil { return nil, err } err = Err(C.db_open(db.ptr, txn.ptr, cFile, cDatabase, C.DBTYPE(dbtype), C.u_int32_t(flags), C.int(mode))) if err != nil { db.Close(0) return nil, err } return db, ok }
func (db BerkeleyDB) Put(txn Transaction, key, val []byte, flags DbFlag) error { cKey := AllocDBT(key) defer cKey.Free() cVal := AllocDBT(val) defer cVal.Free() return Err(C.db_put(db.ptr, txn.ptr, cKey, cVal, C.u_int32_t(flags))) }
func (db BerkeleyDB) NewCursor(txn Transaction, flags DbFlag) (*Cursor, error) { ret := new(Cursor) err := Err(C.db_cursor(db.ptr, txn.ptr, &ret.ptr, C.u_int32_t(flags))) if err != nil { return nil, err } return ret, ok }
func AllocDBT(val []byte) *C.DBT { return &C.DBT{ // someday we will be able to use C.CBytes() for this purpose // https://github.com/golang/go/issues/14838 data: unsafe.Pointer(C.CString(string(val))), size: C.u_int32_t(len(val)), flags: C.DB_DBT_USERMEM, } }
// NewRing creates a new PFRing. Note that when the ring is initially created, // it is disabled. The caller must call Enable to start receiving packets. // The caller should call Close on the given ring when finished with it. func NewRing(device string, snaplen uint32, flags Flag) (ring *Ring, _ error) { dev := C.CString(device) defer C.free(unsafe.Pointer(dev)) cptr, err := C.pfring_open(dev, C.u_int32_t(snaplen), C.u_int32_t(flags)) if cptr == nil || err != nil { return nil, fmt.Errorf("pfring NewRing error: %v", err) } ring = &Ring{cptr: cptr, snaplen: int(snaplen)} if flags&FlagLongHeader == FlagLongHeader { ring.useExtendedPacketHeader = true } else { ifc, err := net.InterfaceByName(device) if err == nil { ring.interfaceIndex = ifc.Index } } ring.SetApplicationName(os.Args[0]) return }
func (cursor Cursor) CursorGetRaw(flags DbFlag) ([]byte, []byte, error) { key := C.DBT{flags: C.DB_DBT_REALLOC} defer C.free(key.data) val := C.DBT{flags: C.DB_DBT_REALLOC} defer C.free(val.data) err := Err(C.db_cursor_get(cursor.ptr, &key, &val, C.u_int32_t(flags))) if err != nil { return nil, nil, err } return cloneToBytes(&key), cloneToBytes(&val), ok }
func (env Environment) Close(flags DbFlag) error { if env.ptr == nil { return ok } err := Err(C.db_env_close(env.ptr, C.u_int32_t(flags))) if err != nil { return err } env.ptr = nil return ok }
func (db BerkeleyDB) Close(flags DbFlag) error { if db.ptr == nil { return ok } err := Err(C.db_close(db.ptr, C.u_int32_t(flags))) if err != nil { return err } db.ptr = nil return ok }
func (db BerkeleyDB) Get(txn Transaction, key []byte, flags DbFlag) ([]byte, error) { data := &C.DBT{flags: C.DB_DBT_REALLOC} defer data.Free() cKey := AllocDBT(key) defer cKey.Free() err := Err(C.db_get(db.ptr, txn.ptr, cKey, data, C.u_int32_t(flags))) if err != nil { return nil, err } return cloneToBytes(data), ok }
// Queues returns all queues in pf. func (p *OpenPf) Queues() ([]Queue, error) { pq := &C.struct_pfioc_queue{} pqs := &C.struct_pfioc_qstats{} hfscstats := &C.struct_hfsc_class_stats{} err := ioctl(p.fd.Fd(), DIOCGETQUEUES, uintptr(unsafe.Pointer(pq))) if err != nil { return nil, err } queues := make([]Queue, 0) n := int(pq.nr) for i := 0; i < n; i++ { pqs.nr = C.u_int32_t(i) pqs.ticket = pq.ticket pqs.buf = unsafe.Pointer(hfscstats) pqs.nbytes = C.int(unsafe.Sizeof(C.struct_hfsc_class_stats{})) err := ioctl(p.fd.Fd(), DIOCGETQSTATS, uintptr(unsafe.Pointer(pqs))) if err != nil { return nil, err } qname := C.GoString(&pqs.queue.qname[0]) if qname[0] == '_' { continue } qparent := C.GoString(&pqs.queue.parent[0]) qifname := C.GoString(&pqs.queue.ifname[0]) queue := Queue{ Name: qname, Parent: qparent, IfName: qifname, Stats: QueueStats{ TransmitPackets: uint64(hfscstats.xmit_cnt.packets), TransmitBytes: uint64(hfscstats.xmit_cnt.bytes), DroppedPackets: uint64(hfscstats.drop_cnt.packets), DroppedBytes: uint64(hfscstats.drop_cnt.bytes), }, } queues = append(queues, queue) } return queues, nil }
// Perform an operation within a transaction. The transaction is // automatically committed if the action doesn't return an error. If // an error occurs, the transaction is automatically aborted. Any // error is passed through to the caller. func (env Environment) WithTransaction(config *TransactionConfig, action func(Transaction) error) (err error) { var parent *C.DB_TXN var flags C.u_int32_t = C.DB_READ_COMMITTED if config != nil { if config.Parent != NoTransaction { parent = config.Parent.ptr } if config.Isolation != 0 { flags = C.u_int32_t(config.Isolation) } if config.Bulk { flags |= C.DB_TXN_BULK } if config.NoWait { flags |= C.DB_TXN_NOWAIT } if config.NoSync { flags |= C.DB_TXN_NOSYNC } if config.WriteNoSync { flags |= C.DB_TXN_WRITE_NOSYNC } } var txn Transaction err = check(C.db_env_txn_begin(env.ptr, parent, &txn.ptr, flags)) if err == nil { defer func() { if err != nil && txn.ptr != nil { C.db_txn_abort(txn.ptr) txn.ptr = nil } }() } else { return } err = action(txn) if err == nil { err = check(C.db_txn_commit(txn.ptr, 0)) txn.ptr = nil } else { return } return }
// Marshal a protobuf struct into a database thang. func marshalDBT(dbt *C.DBT, val proto.Message) (err error) { buf, err := proto.Marshal(val) if err != nil { return } if len(buf) > 0 { dbt.data = unsafe.Pointer(&buf[0]) dbt.size = C.u_int32_t(len(buf)) } else { dbt.data = nil dbt.size = 0 } return }
//Create and bind to queue specified by queueId func NewNFQueue(queueId uint16, maxPacketsInQueue uint32, packetSize uint32) (*NFQueue, error) { var nfq = NFQueue{} var err error var ret C.int if nfq.h, err = C.nfq_open(); err != nil { return nil, fmt.Errorf("Error opening NFQueue handle: %v\n", err) } if ret, err = C.nfq_unbind_pf(nfq.h, AF_INET); err != nil || ret < 0 { return nil, fmt.Errorf("Error unbinding existing NFQ handler from AF_INET protocol family: %v\n", err) } if ret, err := C.nfq_bind_pf(nfq.h, AF_INET); err != nil || ret < 0 { return nil, fmt.Errorf("Error binding to AF_INET protocol family: %v\n", err) } nfq.packets = make(chan NFPacket) if nfq.qh, err = C.CreateQueue(nfq.h, C.u_int16_t(queueId), unsafe.Pointer(&nfq.packets)); err != nil || nfq.qh == nil { C.nfq_close(nfq.h) return nil, fmt.Errorf("Error binding to queue: %v\n", err) } if ret, err = C.nfq_set_queue_maxlen(nfq.qh, C.u_int32_t(maxPacketsInQueue)); err != nil || ret < 0 { C.nfq_destroy_queue(nfq.qh) C.nfq_close(nfq.h) return nil, fmt.Errorf("Unable to set max packets in queue: %v\n", err) } if C.nfq_set_mode(nfq.qh, C.u_int8_t(2), C.uint(packetSize)) < 0 { C.nfq_destroy_queue(nfq.qh) C.nfq_close(nfq.h) return nil, fmt.Errorf("Unable to set packets copy mode: %v\n", err) } if nfq.fd, err = C.nfq_fd(nfq.h); err != nil { C.nfq_destroy_queue(nfq.qh) C.nfq_close(nfq.h) return nil, fmt.Errorf("Unable to get queue file-descriptor. %v", err) } go nfq.run() return &nfq, nil }
func NewEnvironment(home string, flags DbFlag, mode int) (*Environment, error) { ret := new(Environment) err := Err(C.db_env_create(&ret.ptr, 0)) if err != nil { return nil, err } cHome := C.CString(home) defer C.free(unsafe.Pointer(cHome)) err = Err(C.db_env_open(ret.ptr, cHome, C.u_int32_t(flags), C.int(mode))) if err != nil { ret.Close(0) return nil, err } return ret, ok }
func (p *OpenPf) Anchors() ([]string, error) { pr := &C.struct_pfioc_ruleset{} err := ioctl(p.fd.Fd(), DIOCGETRULESETS, uintptr(unsafe.Pointer(pr))) if err != nil { return nil, err } anchors := make([]string, 0) n := int(pr.nr) for i := 0; i < n; i++ { pr.nr = C.u_int32_t(i) err := ioctl(p.fd.Fd(), DIOCGETRULESET, uintptr(unsafe.Pointer(pr))) if err != nil { return nil, err } anchor := "" if pr.path[0] != '\x00' { anchor += C.GoString(&pr.path[0]) + "/" } name := C.GoString(&pr.name[0]) if name == PF_RESERVED_ANCHOR { continue } anchor += name anchors = append(anchors, anchor) } return anchors, nil }
func (a *OpenAnchor) DeleteIndex(nr int) error { rule := C.struct_pfioc_rule{ action: PF_CHANGE_GET_TICKET, nr: C.u_int32_t(nr), } aname := C.CString(a.name) C.strlcpy(&rule.anchor[0], aname, C.size_t(unsafe.Sizeof(rule.anchor))) C.free(unsafe.Pointer(aname)) err := ioctl(a.pf.fd.Fd(), DIOCCHANGERULE, uintptr(unsafe.Pointer(&rule))) if err != nil { return err } rule.action = PF_CHANGE_REMOVE err = ioctl(a.pf.fd.Fd(), DIOCCHANGERULE, uintptr(unsafe.Pointer(&rule))) if err != nil { return err } return nil }
func (a *OpenAnchor) Rules() ([]Rule, error) { pr := &C.struct_pfioc_rule{} aname := C.CString(a.name) defer C.free(unsafe.Pointer(aname)) C.strlcpy(&pr.anchor[0], aname, C.size_t(unsafe.Sizeof(pr.anchor))) err := ioctl(a.pf.fd.Fd(), DIOCGETRULES, uintptr(unsafe.Pointer(pr))) if err != nil { return nil, err } count := int(pr.nr) rules := make([]Rule, 0) for i := 0; i < count; i++ { pr.nr = C.u_int32_t(i) err := ioctl(a.pf.fd.Fd(), DIOCGETRULE, uintptr(unsafe.Pointer(pr))) if err != nil { return nil, err } if pr.anchor_call[0] != 0 { continue } r := Rule{Nr: uint32(pr.nr)} switch pr.rule.action { case PF_PASS: r.Action = Pass case PF_BLOCK: r.Action = Block case PF_MATCH: r.Action = Match default: panic("bad action") } switch pr.rule.direction { case PF_INOUT: r.Direction = InOut case PF_IN: r.Direction = In case PF_OUT: r.Direction = Out default: panic("bad direction") } if pr.rule.log != 0 { r.Log = true } if pr.rule.quick != 0 { r.Quick = true } r.Interface = C.GoString(&pr.rule.ifname[0]) r.Tag = C.GoString(&pr.rule.tagname[0]) r.Src = Target{Port: ntohs((uint16(pr.rule.src.port[0])))} switch pr.rule.src.addr._type { case PF_ADDR_ADDRMASK: _, net, err := net.ParseCIDR(addrwrapstr(&pr.rule.src.addr, int(pr.rule.af))) if err != nil { panic(err) } r.Src.Addr = AddrIPMask{*net} case PF_ADDR_DYNIFTL: r.Src.Addr = AddrDynIf{addrwrapstr(&pr.rule.src.addr, int(pr.rule.af))} default: panic("bad src") } r.Dst = Target{Port: ntohs((uint16(pr.rule.dst.port[0])))} switch pr.rule.dst.addr._type { case PF_ADDR_ADDRMASK: _, net, err := net.ParseCIDR(addrwrapstr(&pr.rule.dst.addr, int(pr.rule.af))) if err != nil { panic(err) } r.Dst.Addr = AddrIPMask{*net} case PF_ADDR_DYNIFTL: r.Dst.Addr = AddrDynIf{addrwrapstr(&pr.rule.dst.addr, int(pr.rule.af))} default: panic("bad dst") } if pr.rule.rdr.addr._type != PF_ADDR_NONE { r.Rdr = &Target{Port: uint16(pr.rule.rdr.proxy_port[0])} switch pr.rule.rdr.addr._type { case PF_ADDR_ADDRMASK: _, net, err := net.ParseCIDR(addrwrapstr(&pr.rule.rdr.addr, int(pr.rule.af))) if err != nil { panic(err) } r.Rdr.Addr = AddrIPMask{*net} case PF_ADDR_DYNIFTL: r.Rdr.Addr = AddrDynIf{addrwrapstr(&pr.rule.rdr.addr, int(pr.rule.af))} } } rules = append(rules, r) } return rules, nil }
func (db BerkeleyDB) Del(txn Transaction, key []byte, flags DbFlag) error { cKey := AllocDBT(key) defer cKey.Free() return Err(C.db_del(db.ptr, txn.ptr, cKey, C.u_int32_t(flags))) }
// Close the environment. func (env Environment) Close() (err error) { err = check(C.db_env_close(env.ptr, C.u_int32_t(C.DB_FORCESYNC))) return }
// SetSamplingRate sets the sampling rate to 1/<rate>. func (r *Ring) SetSamplingRate(rate int) error { if rv := C.pfring_set_sampling_rate(r.cptr, C.u_int32_t(rate)); rv != 0 { return fmt.Errorf("Unable to set sampling rate, got error code %d", rv) } return nil }