// Saves stats from the socket to the TPacket instance func (h *TPacket) SocketStats() (SocketStats, SocketStatsV3, error) { h.mu.Lock() defer h.mu.Unlock() // We need to save the counters since asking for the stats will clear them if h.tpVersion == TPacketVersion3 { prevStats := h.socketStatsV3 socklen := unsafe.Sizeof(h.socketStatsV3) var slt C.socklen_t = C.socklen_t(socklen) _, err := C.getsockopt(h.fd, C.SOL_PACKET, C.PACKET_STATISTICS, unsafe.Pointer(&h.socketStatsV3), &slt) if err != nil { return SocketStats{}, SocketStatsV3{}, err } h.socketStatsV3.tp_packets += prevStats.tp_packets h.socketStatsV3.tp_drops += prevStats.tp_drops h.socketStatsV3.tp_freeze_q_cnt += prevStats.tp_freeze_q_cnt return h.socketStats, h.socketStatsV3, nil } else { prevStats := h.socketStats socklen := unsafe.Sizeof(h.socketStats) var slt C.socklen_t = C.socklen_t(socklen) _, err := C.getsockopt(h.fd, C.SOL_PACKET, C.PACKET_STATISTICS, unsafe.Pointer(&h.socketStats), &slt) if err != nil { return SocketStats{}, SocketStatsV3{}, err } h.socketStats.tp_packets += prevStats.tp_packets h.socketStats.tp_drops += prevStats.tp_drops return h.socketStats, h.socketStatsV3, nil } }
func cgoSockaddr(ip IP, zone string) (*C.struct_sockaddr, C.socklen_t) { if ip4 := ip.To4(); ip4 != nil { return cgoSockaddrInet4(ip4), C.socklen_t(syscall.SizeofSockaddrInet4) } if ip6 := ip.To16(); ip6 != nil { return cgoSockaddrInet6(ip6, zoneToInt(zone)), C.socklen_t(syscall.SizeofSockaddrInet6) } return nil, 0 }
func (sock fd) accept() (nfd fd, addr ax25Addr, err error) { addrLen := C.socklen_t(unsafe.Sizeof(addr)) n, err := C.accept( C.int(sock), (*C.struct_sockaddr)(unsafe.Pointer(&addr)), &addrLen) if addrLen != C.socklen_t(unsafe.Sizeof(addr)) { panic("unexpected socklet_t") } return fd(n), addr, err }
func newAfalg() (a *afalg, err error) { a = &afalg{tfm_fd: -1, op_fd: -1} runtime.SetFinalizer(a, func(a *afalg) { a.Close() }) a.tfm_fd, err = syscall.Socket(syscall.AF_ALG, syscall.SOCK_SEQPACKET, 0) if err != nil || a.tfm_fd == -1 { a.Close() return nil, fmt.Errorf("failed creating af_alg socket: %v", err) } // rats, we can't call Bind with a sockaddr_alg. There's no sockaddr_alg // in the go stdlib, nor can i make up my own byte array that matches // the required sockaddr interface in the bind call. have to use cgo. if C.bind(C.int(a.tfm_fd), (*C.struct_sockaddr)(unsafe.Pointer(&C.sha1_sa)), C.socklen_t(unsafe.Sizeof(C.sha1_sa))) != 0 { a.Close() return nil, fmt.Errorf("failed binding af_alg connection") } // can't call Accept with go's stdlib, cause it's going to make up and // pass a sockaddr to fill in. not only do we not care about the sockaddr, // the sockaddr type is sockaddr_alg, and go doesn't understand that. nfd, _, e := syscall.Syscall(syscall.SYS_ACCEPT, uintptr(a.tfm_fd), 0, 0) a.op_fd = int(nfd) if e != 0 || a.op_fd == -1 { a.Close() return nil, fmt.Errorf("failed accepting af_alg connection: %v", e) } return a, nil }
func (b *ax25Beacon) Now() error { // Create file descriptor //REVIEW: Should we keep it for next beacon? var socket fd if f, err := syscall.Socket(syscall.AF_AX25, syscall.SOCK_DGRAM, 0); err != nil { return err } else { socket = fd(f) } defer socket.close() if err := socket.bind(b.localAddr); err != nil { return fmt.Errorf("bind: %s", err) } msg := C.CString(b.message) _, err := C.sendto( C.int(socket), unsafe.Pointer(msg), C.size_t(len(b.message)), 0, (*C.struct_sockaddr)(unsafe.Pointer(&b.remoteAddr)), C.socklen_t(unsafe.Sizeof(b.remoteAddr)), ) return err }
func (sock fd) bind(addr ax25Addr) (err error) { _, err = C.bind( C.int(sock), (*C.struct_sockaddr)(unsafe.Pointer(&addr)), C.socklen_t(unsafe.Sizeof(addr))) return }
// setTPacketVersion asks the kernel to set TPacket to a particular version, and returns an error on failure. func (h *TPacket) setTPacketVersion(version OptTPacketVersion) error { val := C.int(version) _, err := C.setsockopt(h.fd, C.SOL_PACKET, C.PACKET_VERSION, unsafe.Pointer(&val), C.socklen_t(unsafe.Sizeof(val))) if err != nil { return fmt.Errorf("setsockopt packet_version: %v", err) } return nil }
// Processes a UDP packet. For when you're handling UDP yourself. func (c *UTPContext) ProcessUDP(buf []byte, len int, to *syscall.RawSockaddr, tolen int) int { bufptr := (*C.byte)(unsafe.Pointer(&buf[0])) adrptr := (*C.struct_sockaddr)(unsafe.Pointer(to)) return int(C.utp_process_udp(c.raw, bufptr, C.size_t(len), adrptr, C.socklen_t(tolen))) }
// SetFanout activates TPacket's fanout ability. // Use of Fanout requires creating multiple TPacket objects and the same id/type to // a SetFanout call on each. Note that this can be done cross-process, so if two // different processes both call SetFanout with the same type/id, they'll share // packets between them. The same should work for multiple TPacket objects within // the same process. func (h *TPacket) SetFanout(t FanoutType, id uint16) error { h.mu.Lock() defer h.mu.Unlock() arg := C.int(t) << 16 arg |= C.int(id) _, err := C.setsockopt(h.fd, C.SOL_PACKET, C.PACKET_FANOUT, unsafe.Pointer(&arg), C.socklen_t(unsafe.Sizeof(arg))) return err }
// Clear socket counters and return empty stats func (h *TPacket) InitSocketStats() error { if h.tpVersion == TPacketVersion3 { socklen := unsafe.Sizeof(h.socketStatsV3) var slt C.socklen_t = C.socklen_t(socklen) _, err := C.getsockopt(h.fd, C.SOL_PACKET, C.PACKET_STATISTICS, unsafe.Pointer(&h.socketStatsV3), &slt) if err != nil { return err } h.socketStatsV3 = SocketStatsV3{} } else { socklen := unsafe.Sizeof(h.socketStats) var slt C.socklen_t = C.socklen_t(socklen) _, err := C.getsockopt(h.fd, C.SOL_PACKET, C.PACKET_STATISTICS, unsafe.Pointer(&h.socketStats), &slt) if err != nil { return err } h.socketStats = SocketStats{} } return nil }
func NewInterfaces() ([]InterfaceTotal, string) { var ifaces *C.struct_ifaddrs if getrc, _ := C.getifaddrs(&ifaces); getrc != 0 { return []InterfaceTotal{}, "" } defer C.freeifaddrs(ifaces) ifs := []InterfaceTotal{} IP := "" for fi := ifaces; fi != nil; fi = fi.ifa_next { if fi.ifa_addr == nil { continue } ifa_name := C.GoString(fi.ifa_name) if IP == "" && fi.ifa_addr.sa_family == C.AF_INET && ifa_name != "lo" && !rx_lo.Match([]byte(ifa_name)) && realInterfaceName(ifa_name) { sa_in := (*C.struct_sockaddr_in)(unsafe.Pointer(fi.ifa_addr)) if C.inet_ntop( C.int(fi.ifa_addr.sa_family), // C.AF_INET, unsafe.Pointer(&sa_in.sin_addr), &C.ADDR[0], C.socklen_t(unsafe.Sizeof(C.ADDR))) != nil { IP = C.GoString((*C.char)(unsafe.Pointer(&C.ADDR))) } } if fi.ifa_addr.sa_family != C.AF_LINK { continue } data := fi.ifa_data if C.Ibytes(data) == 0 && C.Obytes(data) == 0 { continue } ifs = append(ifs, InterfaceTotal{ Name: ifa_name, In: uint(C.Ibytes(data)), Out: uint(C.Obytes(data)), }) } return ifs, IP }
// bindToInterface binds the TPacket socket to a particular named interface. func (h *TPacket) bindToInterface(ifaceName string) error { iface, err := net.InterfaceByName(ifaceName) if err != nil { return fmt.Errorf("InterfaceByName: %v", err) } var ll C.struct_sockaddr_ll ll.sll_family = C.AF_PACKET ll.sll_protocol = C.__be16(C.htons(C.ETH_P_ALL)) ll.sll_ifindex = C.int(iface.Index) if _, err := C.bind(h.fd, (*C.struct_sockaddr)(unsafe.Pointer(&ll)), C.socklen_t(unsafe.Sizeof(ll))); err != nil { return fmt.Errorf("bindToInterface: %v", err) } return nil }
func ntop(fi *C.struct_ifaddrs) (string, bool) { if fi.ifa_addr == nil { return "", false } if fi.ifa_addr.sa_family != C.AF_INET { return "", false } saIn := (*C.struct_sockaddr_in)(unsafe.Pointer(fi.ifa_addr)) if nil == C.inet_ntop( C.int(fi.ifa_addr.sa_family), // C.AF_INET, unsafe.Pointer(&saIn.sin_addr), &C.ADDR[0], C.socklen_t(unsafe.Sizeof(C.ADDR))) { return "", false } return C.GoString((*C.char)(unsafe.Pointer(&C.ADDR))), true }
func (s *UTPSocket) Connect(addr *UTPAddr) (int, error) { // func (s *UTPSocket) Connect(to *syscall.RawSockaddr, tolen int) int { if addr == nil { return 0, net.InvalidAddrError("No address given.") } sa, err := addr.Sockaddr() if err != nil { return 0, err } rsa, err := sockaddr.NewRawSockaddr(&sa) if err != nil { return 0, err } ptr := (*C.struct_sockaddr)(unsafe.Pointer(&rsa.Raw)) ret := int(C.utp_connect(s.raw, ptr, C.socklen_t(rsa.Len))) return ret, nil }
// SetBPFFilter compiles and sets a BPF filter for the TPacket handle. func (h *TPacket) SetBPFFilter(expr string) (err error) { // Open a dummy pcap handle p, err := pcap.OpenDead(layers.LinkTypeEthernet, int32(h.opts.frameSize)) if err != nil { return fmt.Errorf("OpenDead: %s", err) } bpf, err := p.NewBPF(expr) if err != nil { return fmt.Errorf("NewBPF: %s", err) } program := bpf.BPF() _, err = C.setsockopt(h.fd, C.SOL_SOCKET, C.SO_ATTACH_FILTER, unsafe.Pointer(&program), C.socklen_t(unsafe.Sizeof(program))) if err != nil { return fmt.Errorf("setsockopt: %s", err) } return nil }
func NewInterfaces(CH chan InterfacesInfo) { var ifaces *C.struct_ifaddrs if getrc, _ := C.getifaddrs(&ifaces); getrc != 0 { CH <- InterfacesInfo{} return } defer C.freeifaddrs(ifaces) ifs := []InterfaceInfo{} IP := "" for fi := ifaces; fi != nil; fi = fi.ifa_next { if fi.ifa_addr == nil { continue } ifa_name := C.GoString(fi.ifa_name) if IP == "" && fi.ifa_addr.sa_family == C.AF_INET && !rx_lo.Match([]byte(ifa_name)) && realInterfaceName(ifa_name) { sa_in := (*C.struct_sockaddr_in)(unsafe.Pointer(fi.ifa_addr)) if C.inet_ntop( C.int(fi.ifa_addr.sa_family), // C.AF_INET, unsafe.Pointer(&sa_in.sin_addr), &C.ADDR[0], C.socklen_t(unsafe.Sizeof(C.ADDR))) != nil { IP = C.GoString((*C.char)(unsafe.Pointer(&C.ADDR))) } } if fi.ifa_addr.sa_family != C.AF_LINK { continue } data := fi.ifa_data it := InterfaceInfo{ Name: ifa_name, InBytes: uint(C.Ibytes(data)), OutBytes: uint(C.Obytes(data)), InPackets: uint(C.Ipackets(data)), OutPackets: uint(C.Opackets(data)), InErrors: uint(C.Ierrors(data)), OutErrors: uint(C.Oerrors(data)), } if it.InBytes == 0 && it.OutBytes == 0 && it.InPackets == 0 && it.OutPackets == 0 && it.InErrors == 0 && it.OutErrors == 0 { continue } ifs = append(ifs, it) } CH <- InterfacesInfo{ List: ifs, IP: IP, } }
// setUpRing sets up the shared-memory ring buffer between the user process and the kernel. func (h *TPacket) setUpRing() (err error) { totalSize := C.uint(h.opts.framesPerBlock * h.opts.numBlocks * h.opts.frameSize) switch h.tpVersion { case TPacketVersion1, TPacketVersion2: var tp C.struct_tpacket_req tp.tp_block_size = C.uint(h.opts.blockSize) tp.tp_block_nr = C.uint(h.opts.numBlocks) tp.tp_frame_size = C.uint(h.opts.frameSize) tp.tp_frame_nr = C.uint(h.opts.framesPerBlock * h.opts.numBlocks) if _, err := C.setsockopt(h.fd, C.SOL_PACKET, C.PACKET_RX_RING, unsafe.Pointer(&tp), C.socklen_t(unsafe.Sizeof(tp))); err != nil { return fmt.Errorf("setsockopt packet_rx_ring: %v", err) } case TPacketVersion3: var tp C.struct_tpacket_req3 tp.tp_block_size = C.uint(h.opts.blockSize) tp.tp_block_nr = C.uint(h.opts.numBlocks) tp.tp_frame_size = C.uint(h.opts.frameSize) tp.tp_frame_nr = C.uint(h.opts.framesPerBlock * h.opts.numBlocks) tp.tp_retire_blk_tov = C.uint(h.opts.blockTimeout / time.Millisecond) if _, err := C.setsockopt(h.fd, C.SOL_PACKET, C.PACKET_RX_RING, unsafe.Pointer(&tp), C.socklen_t(unsafe.Sizeof(tp))); err != nil { return fmt.Errorf("setsockopt packet_rx_ring v3: %v", err) } default: return errors.New("invalid tpVersion") } if h.ring, err = C.mmap(nil, C.size_t(totalSize), C.PROT_READ|C.PROT_WRITE, C.MAP_SHARED, C.int(h.fd), 0); err != nil { return } if h.ring == nil { return errors.New("no ring") } return nil }
func cgoNameinfoPTR(b []byte, sa *C.struct_sockaddr, salen C.socklen_t) (int, error) { gerrno, err := C.getnameinfo(sa, salen, (*C.char)(unsafe.Pointer(&b[0])), C.socklen_t(len(b)), nil, 0, C.NI_NAMEREQD) return int(gerrno), err }