protobytes

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 8, 2024 License: MIT Imports: 7 Imported by: 9

README

Protobytes

Protobytes is a Go library inspired by Rust's crate bytes. It provides a series of methods for big-endian and little-endian number operations, as well as a helper for io.Reader.

Purpose

The goal of this library is to provide an easy-to-use bytes.Buffer. However, it has been split into BytesReader and BytesWriter, which perform similarly to using bytes.Buffer directly.

When using bytes.Buffer, binary.Write has poor performance and unnecessary allocation. Instead, you can use the methods provided by protobytes.

Usage

BytesReader and BytesWriter are similar to bytes.Buffer, but they are not thread-safe. bytes.Buffer, binary.Write and []byte conversion is very easy and cheap.

buf := make([]byte, 0, 1024)
w := BytesWriter(buf)
w.ReadFull(rand.Reader, 64)
w.PutUint8(0x01)
w.PutUint16be(0x0203)

r := BytesReader(w.Bytes())
randomBytes, r := r.SplitAt(64) // split to two BytesReader
r.ReadUint8() // auto step forward
r.ReadUint16be()

example for parse proxy protocol v2 using BytesReader:

hexStr := "0d0a0d0a000d0a515549540a20120c000c22384eac10000104d21f90"
buf, _ := hex.DecodeString(hexStr)

r := BytesReader(buf)

if r.Len() < 16 {
    panic("short buffer")
}

sign, r := r.SplitAt(12)
if !bytes.Equal(signature, sign) {
    panic("invalid signature")
}

header := &Header{}

switch command := r.ReadUint8(); command {
case LOCAL, PROXY:
    header.Command = command
default:
    panic(fmt.Errorf("invalid command %x", command))
}

switch protocol := r.ReadUint8(); protocol {
case UNSPEC, TCPOverIPv4, UDPOverIPv4, TCPOverIPv6, UDPOverIPv6, UNIXStream, UNIXDatagram:
    header.TransportProtocol = protocol
default:
    panic(fmt.Errorf("invalid protocol %x", protocol))
}

length := r.ReadUint16le()
switch length {
case lengthIPv4, lengthIPv6, lengthUnix:
default:
    panic(fmt.Errorf("invalid length %x", length))
}

if r.Len() < int(length) {
    panic("short buffer")
}

switch length {
case lengthIPv4:
    srcAddr := r.ReadIPv4()
    dstAddr := r.ReadIPv4()
    srcPort := r.ReadUint16be()
    dstPort := r.ReadUint16be()

    header.SourceAddr = netip.AddrPortFrom(srcAddr, srcPort)
    header.DestinationAddr = netip.AddrPortFrom(dstAddr, dstPort)
case lengthIPv6:
    srcAddr := r.ReadIPv6()
    dstAddr := r.ReadIPv6()
    srcPort := r.ReadUint16be()
    dstPort := r.ReadUint16be()

    header.SourceAddr = netip.AddrPortFrom(srcAddr, srcPort)
    header.DestinationAddr = netip.AddrPortFrom(dstAddr, dstPort)
default:
    panic(fmt.Errorf("unsupported protocol %x", length))
}

fmt.Printf("%+v\n", header)

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BytesReader

type BytesReader []byte

BytesReader is a wrapper for a byte slice that provides helper methods for reading various types of data from the slice.

Example
package main

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"net/netip"
)

var signature = []byte{0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A}

type Header struct {
	Command           byte
	TransportProtocol byte
	SourceAddr        netip.AddrPort
	DestinationAddr   netip.AddrPort
}

const (
	LOCAL byte = 0x20
	PROXY byte = 0x21
)

const (
	UNSPEC       = 0x00
	TCPOverIPv4  = 0x11
	UDPOverIPv4  = 0x12
	TCPOverIPv6  = 0x21
	UDPOverIPv6  = 0x22
	UNIXStream   = 0x31
	UNIXDatagram = 0x32
)

const (
	lengthIPv4 uint16 = 12
	lengthIPv6 uint16 = 36
	lengthUnix uint16 = 216
)

func main() {
	hexStr := "0d0a0d0a000d0a515549540a20120c000c22384eac10000104d21f90"
	buf, _ := hex.DecodeString(hexStr)

	r := BytesReader(buf)

	if r.Len() < 16 {
		panic("short buffer")
	}

	sign, r := r.SplitAt(12)
	if !bytes.Equal(signature, sign) {
		panic("invalid signature")
	}

	header := &Header{}

	switch command := r.ReadUint8(); command {
	case LOCAL, PROXY:
		header.Command = command
	default:
		panic(fmt.Errorf("invalid command %x", command))
	}

	switch protocol := r.ReadUint8(); protocol {
	case UNSPEC, TCPOverIPv4, UDPOverIPv4, TCPOverIPv6, UDPOverIPv6, UNIXStream, UNIXDatagram:
		header.TransportProtocol = protocol
	default:
		panic(fmt.Errorf("invalid protocol %x", protocol))
	}

	length := r.ReadUint16le()
	switch length {
	case lengthIPv4, lengthIPv6, lengthUnix:
	default:
		panic(fmt.Errorf("invalid length %x", length))
	}

	if r.Len() < int(length) {
		panic("short buffer")
	}

	switch length {
	case lengthIPv4:
		srcAddr := r.ReadIPv4()
		dstAddr := r.ReadIPv4()
		srcPort := r.ReadUint16be()
		dstPort := r.ReadUint16be()

		header.SourceAddr = netip.AddrPortFrom(srcAddr, srcPort)
		header.DestinationAddr = netip.AddrPortFrom(dstAddr, dstPort)
	case lengthIPv6:
		srcAddr := r.ReadIPv6()
		dstAddr := r.ReadIPv6()
		srcPort := r.ReadUint16be()
		dstPort := r.ReadUint16be()

		header.SourceAddr = netip.AddrPortFrom(srcAddr, srcPort)
		header.DestinationAddr = netip.AddrPortFrom(dstAddr, dstPort)
	default:
		panic(fmt.Errorf("unsupported protocol %x", length))
	}

	fmt.Printf("%+v\n", header)
}
Output:

func (*BytesReader) Cap

func (b *BytesReader) Cap() int

Cap returns the capacity of the byte slice.

func (*BytesReader) IsEmpty

func (b *BytesReader) IsEmpty() bool

IsEmpty checks if the byte slice is empty.

func (*BytesReader) Len

func (b *BytesReader) Len() int

Len returns the length of the byte slice.

func (*BytesReader) Read

func (b *BytesReader) Read(p []byte) (n int, err error)

Read reads up to len(p) bytes from the byte slice and skips len(p) bytes. implements io.Reader. If the buffer has no data to return, err is io.EOF (unless len(p) is zero); otherwise it is nil.

func (*BytesReader) ReadByte

func (b *BytesReader) ReadByte() (byte, error)

ReadByte implements io.ByteReader.

func (*BytesReader) ReadIPv4

func (b *BytesReader) ReadIPv4() netip.Addr

ReadIPv4 reads a net.IPAddr with an IPv4 address.

func (*BytesReader) ReadIPv6

func (b *BytesReader) ReadIPv6() netip.Addr

ReadIPv6 reads a net.IPAddr with an IPv6 address.

func (*BytesReader) ReadUint16be

func (b *BytesReader) ReadUint16be() uint16

ReadUint16be reads a uint16 value in big endian from the byte slice and skips 2 bytes.

func (*BytesReader) ReadUint16le

func (b *BytesReader) ReadUint16le() uint16

ReadUint16le reads a uint16 value in little endian from the byte slice and skips 2 bytes.

func (*BytesReader) ReadUint32be

func (b *BytesReader) ReadUint32be() uint32

ReadUint32be reads a uint32 value in big endian from the byte slice and skips 4 bytes.

func (*BytesReader) ReadUint32le

func (b *BytesReader) ReadUint32le() uint32

ReadUint32le reads a uint32 value in little endian from the byte slice and skips 4 bytes.

func (*BytesReader) ReadUint64be

func (b *BytesReader) ReadUint64be() uint64

ReadUint64be reads a uint64 value in big endian from the byte slice and skips 8 bytes.

func (*BytesReader) ReadUint64le

func (b *BytesReader) ReadUint64le() uint64

ReadUint64le reads a uint64 value in little endian from the byte slice and skips 8 bytes.

func (*BytesReader) ReadUint8

func (b *BytesReader) ReadUint8() uint8

ReadUint8 reads a uint8 value from the byte slice and skips 1 byte.

func (*BytesReader) ReadUvarint

func (b *BytesReader) ReadUvarint() (uint64, error)

ReadUvarint read Uvarint from the byte slice. it return error because of the length of the byte slice can't be sure.

func (*BytesReader) ReadVarint

func (b *BytesReader) ReadVarint() (int64, error)

ReadVarint read Varint from the byte slice. it return error because of the length of the byte slice can't be sure.

func (*BytesReader) Skip

func (b *BytesReader) Skip(n int)

Skip skips the given number of bytes.

func (*BytesReader) SplitAt

func (b *BytesReader) SplitAt(n int) (BytesReader, BytesReader)

SplitAt splits the byte slice at the given index and returns two new BytesReader.

func (*BytesReader) SplitBy

func (b *BytesReader) SplitBy(f func(byte) bool) (BytesReader, BytesReader)

SplitBy splits the byte slice by a given function and returns two new BytesReader.

type BytesWriter

type BytesWriter []byte

func (*BytesWriter) Bytes

func (b *BytesWriter) Bytes() []byte

func (*BytesWriter) Cap

func (b *BytesWriter) Cap() int

Cap returns the capacity of the byte slice.

func (*BytesWriter) Grow

func (b *BytesWriter) Grow(n int) int

Grow grows the buffer's capacity. It returns the index where bytes should be written.

func (*BytesWriter) Len

func (b *BytesWriter) Len() int

func (*BytesWriter) PutRune

func (b *BytesWriter) PutRune(r rune)

func (*BytesWriter) PutSlice

func (b *BytesWriter) PutSlice(p []byte)

func (*BytesWriter) PutString

func (b *BytesWriter) PutString(s string)

func (*BytesWriter) PutUint16be

func (b *BytesWriter) PutUint16be(v uint16)

func (*BytesWriter) PutUint16le

func (b *BytesWriter) PutUint16le(v uint16)

func (*BytesWriter) PutUint32be

func (b *BytesWriter) PutUint32be(v uint32)

func (*BytesWriter) PutUint32le

func (b *BytesWriter) PutUint32le(v uint32)

func (*BytesWriter) PutUint64be

func (b *BytesWriter) PutUint64be(v uint64)

func (*BytesWriter) PutUint64le

func (b *BytesWriter) PutUint64le(v uint64)

func (*BytesWriter) PutUint8

func (b *BytesWriter) PutUint8(v uint8)

func (*BytesWriter) PutUvarint

func (b *BytesWriter) PutUvarint(v uint64)

func (*BytesWriter) PutVarint

func (b *BytesWriter) PutVarint(v int64)

func (*BytesWriter) ReadFull

func (b *BytesWriter) ReadFull(reader io.Reader, n int) error

func (*BytesWriter) Reset

func (b *BytesWriter) Reset()

func (*BytesWriter) Slice

func (b *BytesWriter) Slice(start, end int) BytesWriter

func (*BytesWriter) Write

func (b *BytesWriter) Write(p []byte) (n int, err error)

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

func New

func New(reader io.Reader) *Reader

func (*Reader) Buffered

func (p *Reader) Buffered() int

func (*Reader) Error

func (p *Reader) Error() error

func (*Reader) Next

func (p *Reader) Next(n int) (BytesReader, error)

func (*Reader) Read

func (p *Reader) Read(buf []byte) (n int, err error)

func (*Reader) ReadFull

func (p *Reader) ReadFull(buf []byte) (err error)

func (*Reader) Reset

func (p *Reader) Reset(reader io.Reader)

func (*Reader) TryByte

func (p *Reader) TryByte() (b byte)

func (*Reader) TryNext

func (p *Reader) TryNext(n int) BytesReader

func (*Reader) TryPeekUint16be

func (p *Reader) TryPeekUint16be() (i uint16)

func (*Reader) TryPeekUint16le

func (p *Reader) TryPeekUint16le() (i uint16)

func (*Reader) TryPeekUint32be

func (p *Reader) TryPeekUint32be() (i uint32)

func (*Reader) TryPeekUint32le

func (p *Reader) TryPeekUint32le() (i uint32)

func (*Reader) TryPeekUint64be

func (p *Reader) TryPeekUint64be() (i uint64)

func (*Reader) TryPeekUint64le

func (p *Reader) TryPeekUint64le() (i uint64)

func (*Reader) TryPeekUint8

func (p *Reader) TryPeekUint8() (i uint8)

func (*Reader) TryReadFull

func (p *Reader) TryReadFull(buf []byte)

func (*Reader) TryReadUint16be

func (p *Reader) TryReadUint16be() (i uint16)

func (*Reader) TryReadUint16le

func (p *Reader) TryReadUint16le() (i uint16)

func (*Reader) TryReadUint32be

func (p *Reader) TryReadUint32be() (i uint32)

func (*Reader) TryReadUint32le

func (p *Reader) TryReadUint32le() (i uint32)

func (*Reader) TryReadUint64be

func (p *Reader) TryReadUint64be() (i uint64)

func (*Reader) TryReadUint64le

func (p *Reader) TryReadUint64le() (i uint64)

func (*Reader) TryReadUint8

func (p *Reader) TryReadUint8() (i uint8)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL