github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/tcpip/stack/packet_buffer.go (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at //
     6  //     http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package stack
    15  
    16  import (
    17  	"fmt"
    18  	"io"
    19  
    20  	"github.com/ttpreport/gvisor-ligolo/pkg/buffer"
    21  	"github.com/ttpreport/gvisor-ligolo/pkg/sync"
    22  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip"
    23  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/header"
    24  )
    25  
    26  type headerType int
    27  
    28  const (
    29  	virtioNetHeader headerType = iota
    30  	linkHeader
    31  	networkHeader
    32  	transportHeader
    33  	numHeaderType
    34  )
    35  
    36  var pkPool = sync.Pool{
    37  	New: func() any {
    38  		return &PacketBuffer{}
    39  	},
    40  }
    41  
    42  // PacketBufferOptions specifies options for PacketBuffer creation.
    43  type PacketBufferOptions struct {
    44  	// ReserveHeaderBytes is the number of bytes to reserve for headers. Total
    45  	// number of bytes pushed onto the headers must not exceed this value.
    46  	ReserveHeaderBytes int
    47  
    48  	// Payload is the initial unparsed data for the new packet. If set, it will
    49  	// be owned by the new packet.
    50  	Payload buffer.Buffer
    51  
    52  	// IsForwardedPacket identifies that the PacketBuffer being created is for a
    53  	// forwarded packet.
    54  	IsForwardedPacket bool
    55  
    56  	// OnRelease is a function to be run when the packet buffer is no longer
    57  	// referenced (released back to the pool).
    58  	OnRelease func()
    59  }
    60  
    61  // PacketBufferPtr is a pointer to a PacketBuffer.
    62  type PacketBufferPtr = *PacketBuffer
    63  
    64  // A PacketBuffer contains all the data of a network packet.
    65  //
    66  // As a PacketBuffer traverses up the stack, it may be necessary to pass it to
    67  // multiple endpoints.
    68  //
    69  // The whole packet is expected to be a series of bytes in the following order:
    70  // LinkHeader, NetworkHeader, TransportHeader, and Data. Any of them can be
    71  // empty. Use of PacketBuffer in any other order is unsupported.
    72  //
    73  // PacketBuffer must be created with NewPacketBuffer, which sets the initial
    74  // reference count to 1. Owners should call `DecRef()` when they are finished
    75  // with the buffer to return it to the pool.
    76  //
    77  // Internal structure: A PacketBuffer holds a pointer to buffer.Buffer, which
    78  // exposes a logically-contiguous byte storage. The underlying storage structure
    79  // is abstracted out, and should not be a concern here for most of the time.
    80  //
    81  //	|- reserved ->|
    82  //								|--->| consumed (incoming)
    83  //	0             V    V
    84  //	+--------+----+----+--------------------+
    85  //	|        |    |    | current data ...   | (buf)
    86  //	+--------+----+----+--------------------+
    87  //					 ^    |
    88  //					 |<---| pushed (outgoing)
    89  //
    90  // When a PacketBuffer is created, a `reserved` header region can be specified,
    91  // which stack pushes headers in this region for an outgoing packet. There could
    92  // be no such region for an incoming packet, and `reserved` is 0. The value of
    93  // `reserved` never changes in the entire lifetime of the packet.
    94  //
    95  // Outgoing Packet: When a header is pushed, `pushed` gets incremented by the
    96  // pushed length, and the current value is stored for each header. PacketBuffer
    97  // substracts this value from `reserved` to compute the starting offset of each
    98  // header in `buf`.
    99  //
   100  // Incoming Packet: When a header is consumed (a.k.a. parsed), the current
   101  // `consumed` value is stored for each header, and it gets incremented by the
   102  // consumed length. PacketBuffer adds this value to `reserved` to compute the
   103  // starting offset of each header in `buf`.
   104  //
   105  // +stateify savable
   106  type PacketBuffer struct {
   107  	_ sync.NoCopy
   108  
   109  	packetBufferRefs
   110  
   111  	// buf is the underlying buffer for the packet. See struct level docs for
   112  	// details.
   113  	buf      buffer.Buffer
   114  	reserved int
   115  	pushed   int
   116  	consumed int
   117  
   118  	// headers stores metadata about each header.
   119  	headers [numHeaderType]headerInfo
   120  
   121  	// NetworkProtocolNumber is only valid when NetworkHeader().View().IsEmpty()
   122  	// returns false.
   123  	// TODO(gvisor.dev/issue/3574): Remove the separately passed protocol
   124  	// numbers in registration APIs that take a PacketBuffer.
   125  	NetworkProtocolNumber tcpip.NetworkProtocolNumber
   126  
   127  	// TransportProtocol is only valid if it is non zero.
   128  	// TODO(gvisor.dev/issue/3810): This and the network protocol number should
   129  	// be moved into the headerinfo. This should resolve the validity issue.
   130  	TransportProtocolNumber tcpip.TransportProtocolNumber
   131  
   132  	// Hash is the transport layer hash of this packet. A value of zero
   133  	// indicates no valid hash has been set.
   134  	Hash uint32
   135  
   136  	// Owner is implemented by task to get the uid and gid.
   137  	// Only set for locally generated packets.
   138  	Owner tcpip.PacketOwner
   139  
   140  	// The following fields are only set by the qdisc layer when the packet
   141  	// is added to a queue.
   142  	EgressRoute RouteInfo
   143  	GSOOptions  GSO
   144  
   145  	// snatDone indicates if the packet's source has been manipulated as per
   146  	// iptables NAT table.
   147  	snatDone bool
   148  
   149  	// dnatDone indicates if the packet's destination has been manipulated as per
   150  	// iptables NAT table.
   151  	dnatDone bool
   152  
   153  	// PktType indicates the SockAddrLink.PacketType of the packet as defined in
   154  	// https://www.man7.org/linux/man-pages/man7/packet.7.html.
   155  	PktType tcpip.PacketType
   156  
   157  	// NICID is the ID of the last interface the network packet was handled at.
   158  	NICID tcpip.NICID
   159  
   160  	// RXChecksumValidated indicates that checksum verification may be
   161  	// safely skipped.
   162  	RXChecksumValidated bool
   163  
   164  	// NetworkPacketInfo holds an incoming packet's network-layer information.
   165  	NetworkPacketInfo NetworkPacketInfo
   166  
   167  	tuple *tuple
   168  
   169  	// onRelease is a function to be run when the packet buffer is no longer
   170  	// referenced (released back to the pool).
   171  	onRelease func() `state:"nosave"`
   172  }
   173  
   174  // NewPacketBuffer creates a new PacketBuffer with opts.
   175  func NewPacketBuffer(opts PacketBufferOptions) PacketBufferPtr {
   176  	pk := pkPool.Get().(*PacketBuffer)
   177  	pk.reset()
   178  	if opts.ReserveHeaderBytes != 0 {
   179  		v := buffer.NewViewSize(opts.ReserveHeaderBytes)
   180  		pk.buf.Append(v)
   181  		pk.reserved = opts.ReserveHeaderBytes
   182  	}
   183  	if opts.Payload.Size() > 0 {
   184  		pk.buf.Merge(&opts.Payload)
   185  	}
   186  	pk.NetworkPacketInfo.IsForwardedPacket = opts.IsForwardedPacket
   187  	pk.onRelease = opts.OnRelease
   188  	pk.InitRefs()
   189  	return pk
   190  }
   191  
   192  // IncRef increments the PacketBuffer's refcount.
   193  func (pk PacketBufferPtr) IncRef() PacketBufferPtr {
   194  	pk.packetBufferRefs.IncRef()
   195  	return pk
   196  }
   197  
   198  // DecRef decrements the PacketBuffer's refcount. If the refcount is
   199  // decremented to zero, the PacketBuffer is returned to the PacketBuffer
   200  // pool.
   201  func (pk PacketBufferPtr) DecRef() {
   202  	pk.packetBufferRefs.DecRef(func() {
   203  		if pk.onRelease != nil {
   204  			pk.onRelease()
   205  		}
   206  
   207  		pk.buf.Release()
   208  		pkPool.Put(pk)
   209  	})
   210  }
   211  
   212  func (pk PacketBufferPtr) reset() {
   213  	*pk = PacketBuffer{}
   214  }
   215  
   216  // ReservedHeaderBytes returns the number of bytes initially reserved for
   217  // headers.
   218  func (pk PacketBufferPtr) ReservedHeaderBytes() int {
   219  	return pk.reserved
   220  }
   221  
   222  // AvailableHeaderBytes returns the number of bytes currently available for
   223  // headers. This is relevant to PacketHeader.Push method only.
   224  func (pk PacketBufferPtr) AvailableHeaderBytes() int {
   225  	return pk.reserved - pk.pushed
   226  }
   227  
   228  // VirtioNetHeader returns the handle to virtio-layer header.
   229  func (pk PacketBufferPtr) VirtioNetHeader() PacketHeader {
   230  	return PacketHeader{
   231  		pk:  pk,
   232  		typ: virtioNetHeader,
   233  	}
   234  }
   235  
   236  // LinkHeader returns the handle to link-layer header.
   237  func (pk PacketBufferPtr) LinkHeader() PacketHeader {
   238  	return PacketHeader{
   239  		pk:  pk,
   240  		typ: linkHeader,
   241  	}
   242  }
   243  
   244  // NetworkHeader returns the handle to network-layer header.
   245  func (pk PacketBufferPtr) NetworkHeader() PacketHeader {
   246  	return PacketHeader{
   247  		pk:  pk,
   248  		typ: networkHeader,
   249  	}
   250  }
   251  
   252  // TransportHeader returns the handle to transport-layer header.
   253  func (pk PacketBufferPtr) TransportHeader() PacketHeader {
   254  	return PacketHeader{
   255  		pk:  pk,
   256  		typ: transportHeader,
   257  	}
   258  }
   259  
   260  // HeaderSize returns the total size of all headers in bytes.
   261  func (pk PacketBufferPtr) HeaderSize() int {
   262  	return pk.pushed + pk.consumed
   263  }
   264  
   265  // Size returns the size of packet in bytes.
   266  func (pk PacketBufferPtr) Size() int {
   267  	return int(pk.buf.Size()) - pk.headerOffset()
   268  }
   269  
   270  // MemSize returns the estimation size of the pk in memory, including backing
   271  // buffer data.
   272  func (pk PacketBufferPtr) MemSize() int {
   273  	return int(pk.buf.Size()) + PacketBufferStructSize
   274  }
   275  
   276  // Data returns the handle to data portion of pk.
   277  func (pk PacketBufferPtr) Data() PacketData {
   278  	return PacketData{pk: pk}
   279  }
   280  
   281  // AsSlices returns the underlying storage of the whole packet.
   282  func (pk PacketBufferPtr) AsSlices() [][]byte {
   283  	var views [][]byte
   284  	offset := pk.headerOffset()
   285  	pk.buf.SubApply(offset, int(pk.buf.Size())-offset, func(v *buffer.View) {
   286  		views = append(views, v.AsSlice())
   287  	})
   288  	return views
   289  }
   290  
   291  // ToBuffer returns a caller-owned copy of the underlying storage of the whole
   292  // packet.
   293  func (pk PacketBufferPtr) ToBuffer() buffer.Buffer {
   294  	b := pk.buf.Clone()
   295  	b.TrimFront(int64(pk.headerOffset()))
   296  	return b
   297  }
   298  
   299  // ToView returns a caller-owned copy of the underlying storage of the whole
   300  // packet as a view.
   301  func (pk PacketBufferPtr) ToView() *buffer.View {
   302  	p := buffer.NewView(int(pk.buf.Size()))
   303  	offset := pk.headerOffset()
   304  	pk.buf.SubApply(offset, int(pk.buf.Size())-offset, func(v *buffer.View) {
   305  		p.Write(v.AsSlice())
   306  	})
   307  	return p
   308  }
   309  
   310  func (pk PacketBufferPtr) headerOffset() int {
   311  	return pk.reserved - pk.pushed
   312  }
   313  
   314  func (pk PacketBufferPtr) headerOffsetOf(typ headerType) int {
   315  	return pk.reserved + pk.headers[typ].offset
   316  }
   317  
   318  func (pk PacketBufferPtr) dataOffset() int {
   319  	return pk.reserved + pk.consumed
   320  }
   321  
   322  func (pk PacketBufferPtr) push(typ headerType, size int) []byte {
   323  	h := &pk.headers[typ]
   324  	if h.length > 0 {
   325  		panic(fmt.Sprintf("push(%s, %d) called after previous push", typ, size))
   326  	}
   327  	if pk.pushed+size > pk.reserved {
   328  		panic(fmt.Sprintf("push(%s, %d) overflows; pushed=%d reserved=%d", typ, size, pk.pushed, pk.reserved))
   329  	}
   330  	pk.pushed += size
   331  	h.offset = -pk.pushed
   332  	h.length = size
   333  	view := pk.headerView(typ)
   334  	return view.AsSlice()
   335  }
   336  
   337  func (pk PacketBufferPtr) consume(typ headerType, size int) (v []byte, consumed bool) {
   338  	h := &pk.headers[typ]
   339  	if h.length > 0 {
   340  		panic(fmt.Sprintf("consume must not be called twice: type %s", typ))
   341  	}
   342  	if pk.reserved+pk.consumed+size > int(pk.buf.Size()) {
   343  		return nil, false
   344  	}
   345  	h.offset = pk.consumed
   346  	h.length = size
   347  	pk.consumed += size
   348  	view := pk.headerView(typ)
   349  	return view.AsSlice(), true
   350  }
   351  
   352  func (pk PacketBufferPtr) headerView(typ headerType) buffer.View {
   353  	h := &pk.headers[typ]
   354  	if h.length == 0 {
   355  		return buffer.View{}
   356  	}
   357  	v, ok := pk.buf.PullUp(pk.headerOffsetOf(typ), h.length)
   358  	if !ok {
   359  		panic("PullUp failed")
   360  	}
   361  	return v
   362  }
   363  
   364  // Clone makes a semi-deep copy of pk. The underlying packet payload is
   365  // shared. Hence, no modifications is done to underlying packet payload.
   366  func (pk PacketBufferPtr) Clone() PacketBufferPtr {
   367  	newPk := pkPool.Get().(*PacketBuffer)
   368  	newPk.reset()
   369  	newPk.buf = pk.buf.Clone()
   370  	newPk.reserved = pk.reserved
   371  	newPk.pushed = pk.pushed
   372  	newPk.consumed = pk.consumed
   373  	newPk.headers = pk.headers
   374  	newPk.Hash = pk.Hash
   375  	newPk.Owner = pk.Owner
   376  	newPk.GSOOptions = pk.GSOOptions
   377  	newPk.NetworkProtocolNumber = pk.NetworkProtocolNumber
   378  	newPk.dnatDone = pk.dnatDone
   379  	newPk.snatDone = pk.snatDone
   380  	newPk.TransportProtocolNumber = pk.TransportProtocolNumber
   381  	newPk.PktType = pk.PktType
   382  	newPk.NICID = pk.NICID
   383  	newPk.RXChecksumValidated = pk.RXChecksumValidated
   384  	newPk.NetworkPacketInfo = pk.NetworkPacketInfo
   385  	newPk.tuple = pk.tuple
   386  	newPk.InitRefs()
   387  	return newPk
   388  }
   389  
   390  // ReserveHeaderBytes prepends reserved space for headers at the front
   391  // of the underlying buf. Can only be called once per packet.
   392  func (pk PacketBufferPtr) ReserveHeaderBytes(reserved int) {
   393  	if pk.reserved != 0 {
   394  		panic(fmt.Sprintf("ReserveHeaderBytes(...) called on packet with reserved=%d, want reserved=0", pk.reserved))
   395  	}
   396  	pk.reserved = reserved
   397  	pk.buf.Prepend(buffer.NewViewSize(reserved))
   398  }
   399  
   400  // Network returns the network header as a header.Network.
   401  //
   402  // Network should only be called when NetworkHeader has been set.
   403  func (pk PacketBufferPtr) Network() header.Network {
   404  	switch netProto := pk.NetworkProtocolNumber; netProto {
   405  	case header.IPv4ProtocolNumber:
   406  		return header.IPv4(pk.NetworkHeader().Slice())
   407  	case header.IPv6ProtocolNumber:
   408  		return header.IPv6(pk.NetworkHeader().Slice())
   409  	default:
   410  		panic(fmt.Sprintf("unknown network protocol number %d", netProto))
   411  	}
   412  }
   413  
   414  // CloneToInbound makes a semi-deep copy of the packet buffer (similar to
   415  // Clone) to be used as an inbound packet.
   416  //
   417  // See PacketBuffer.Data for details about how a packet buffer holds an inbound
   418  // packet.
   419  func (pk PacketBufferPtr) CloneToInbound() PacketBufferPtr {
   420  	newPk := pkPool.Get().(*PacketBuffer)
   421  	newPk.reset()
   422  	newPk.buf = pk.buf.Clone()
   423  	newPk.InitRefs()
   424  	// Treat unfilled header portion as reserved.
   425  	newPk.reserved = pk.AvailableHeaderBytes()
   426  	newPk.tuple = pk.tuple
   427  	return newPk
   428  }
   429  
   430  // DeepCopyForForwarding creates a deep copy of the packet buffer for
   431  // forwarding.
   432  //
   433  // The returned packet buffer will have the network and transport headers
   434  // set if the original packet buffer did.
   435  func (pk PacketBufferPtr) DeepCopyForForwarding(reservedHeaderBytes int) PacketBufferPtr {
   436  	payload := BufferSince(pk.NetworkHeader())
   437  	defer payload.Release()
   438  	newPk := NewPacketBuffer(PacketBufferOptions{
   439  		ReserveHeaderBytes: reservedHeaderBytes,
   440  		Payload:            payload.DeepClone(),
   441  		IsForwardedPacket:  true,
   442  	})
   443  
   444  	{
   445  		consumeBytes := len(pk.NetworkHeader().Slice())
   446  		if _, consumed := newPk.NetworkHeader().Consume(consumeBytes); !consumed {
   447  			panic(fmt.Sprintf("expected to consume network header %d bytes from new packet", consumeBytes))
   448  		}
   449  		newPk.NetworkProtocolNumber = pk.NetworkProtocolNumber
   450  	}
   451  
   452  	{
   453  		consumeBytes := len(pk.TransportHeader().Slice())
   454  		if _, consumed := newPk.TransportHeader().Consume(consumeBytes); !consumed {
   455  			panic(fmt.Sprintf("expected to consume transport header %d bytes from new packet", consumeBytes))
   456  		}
   457  		newPk.TransportProtocolNumber = pk.TransportProtocolNumber
   458  	}
   459  
   460  	newPk.tuple = pk.tuple
   461  
   462  	return newPk
   463  }
   464  
   465  // IsNil returns whether the pointer is logically nil.
   466  func (pk PacketBufferPtr) IsNil() bool {
   467  	return pk == nil
   468  }
   469  
   470  // headerInfo stores metadata about a header in a packet.
   471  //
   472  // +stateify savable
   473  type headerInfo struct {
   474  	// offset is the offset of the header in pk.buf relative to
   475  	// pk.buf[pk.reserved]. See the PacketBuffer struct for details.
   476  	offset int
   477  
   478  	// length is the length of this header.
   479  	length int
   480  }
   481  
   482  // PacketHeader is a handle object to a header in the underlying packet.
   483  type PacketHeader struct {
   484  	pk  PacketBufferPtr
   485  	typ headerType
   486  }
   487  
   488  // View returns an caller-owned copy of the underlying storage of h as a
   489  // *buffer.View.
   490  func (h PacketHeader) View() *buffer.View {
   491  	view := h.pk.headerView(h.typ)
   492  	if view.Size() == 0 {
   493  		return nil
   494  	}
   495  	return view.Clone()
   496  }
   497  
   498  // Slice returns the underlying storage of h as a []byte. The returned slice
   499  // should not be modified if the underlying packet could be shared, cloned, or
   500  // borrowed.
   501  func (h PacketHeader) Slice() []byte {
   502  	view := h.pk.headerView(h.typ)
   503  	return view.AsSlice()
   504  }
   505  
   506  // Push pushes size bytes in the front of its residing packet, and returns the
   507  // backing storage. Callers may only call one of Push or Consume once on each
   508  // header in the lifetime of the underlying packet.
   509  func (h PacketHeader) Push(size int) []byte {
   510  	return h.pk.push(h.typ, size)
   511  }
   512  
   513  // Consume moves the first size bytes of the unparsed data portion in the packet
   514  // to h, and returns the backing storage. In the case of data is shorter than
   515  // size, consumed will be false, and the state of h will not be affected.
   516  // Callers may only call one of Push or Consume once on each header in the
   517  // lifetime of the underlying packet.
   518  func (h PacketHeader) Consume(size int) (v []byte, consumed bool) {
   519  	return h.pk.consume(h.typ, size)
   520  }
   521  
   522  // PacketData represents the data portion of a PacketBuffer.
   523  //
   524  // +stateify savable
   525  type PacketData struct {
   526  	pk PacketBufferPtr
   527  }
   528  
   529  // PullUp returns a contiguous slice of size bytes from the beginning of d.
   530  // Callers should not keep the view for later use. Callers can write to the
   531  // returned slice if they have singular ownership over the underlying
   532  // Buffer.
   533  func (d PacketData) PullUp(size int) (b []byte, ok bool) {
   534  	view, ok := d.pk.buf.PullUp(d.pk.dataOffset(), size)
   535  	return view.AsSlice(), ok
   536  }
   537  
   538  // Consume is the same as PullUp except that is additionally consumes the
   539  // returned bytes. Subsequent PullUp or Consume will not return these bytes.
   540  func (d PacketData) Consume(size int) ([]byte, bool) {
   541  	v, ok := d.PullUp(size)
   542  	if ok {
   543  		d.pk.consumed += size
   544  	}
   545  	return v, ok
   546  }
   547  
   548  // ReadTo reads bytes from d to dst. It also removes these bytes from d
   549  // unless peek is true.
   550  func (d PacketData) ReadTo(dst io.Writer, peek bool) (int, error) {
   551  	var (
   552  		err  error
   553  		done int
   554  	)
   555  	offset := d.pk.dataOffset()
   556  	d.pk.buf.SubApply(offset, int(d.pk.buf.Size())-offset, func(v *buffer.View) {
   557  		if err != nil {
   558  			return
   559  		}
   560  		var n int
   561  		n, err = dst.Write(v.AsSlice())
   562  		done += n
   563  		if err != nil {
   564  			return
   565  		}
   566  		if n != v.Size() {
   567  			panic(fmt.Sprintf("io.Writer.Write succeeded with incomplete write: %d != %d", n, v.Size()))
   568  		}
   569  	})
   570  	if !peek {
   571  		d.pk.buf.TrimFront(int64(done))
   572  	}
   573  	return done, err
   574  }
   575  
   576  // CapLength reduces d to at most length bytes.
   577  func (d PacketData) CapLength(length int) {
   578  	if length < 0 {
   579  		panic("length < 0")
   580  	}
   581  	d.pk.buf.Truncate(int64(length + d.pk.dataOffset()))
   582  }
   583  
   584  // ToBuffer returns the underlying storage of d in a buffer.Buffer.
   585  func (d PacketData) ToBuffer() buffer.Buffer {
   586  	buf := d.pk.buf.Clone()
   587  	offset := d.pk.dataOffset()
   588  	buf.TrimFront(int64(offset))
   589  	return buf
   590  }
   591  
   592  // AppendView appends v into d, taking the ownership of v.
   593  func (d PacketData) AppendView(v *buffer.View) {
   594  	d.pk.buf.Append(v)
   595  }
   596  
   597  // MergeBuffer merges b into d and clears b.
   598  func (d PacketData) MergeBuffer(b *buffer.Buffer) {
   599  	d.pk.buf.Merge(b)
   600  }
   601  
   602  // MergeFragment appends the data portion of frag to dst. It modifies
   603  // frag and frag should not be used again.
   604  func MergeFragment(dst, frag PacketBufferPtr) {
   605  	frag.buf.TrimFront(int64(frag.dataOffset()))
   606  	dst.buf.Merge(&frag.buf)
   607  }
   608  
   609  // ReadFrom moves at most count bytes from the beginning of src to the end
   610  // of d and returns the number of bytes moved.
   611  func (d PacketData) ReadFrom(src *buffer.Buffer, count int) int {
   612  	toRead := int64(count)
   613  	if toRead > src.Size() {
   614  		toRead = src.Size()
   615  	}
   616  	clone := src.Clone()
   617  	clone.Truncate(toRead)
   618  	d.pk.buf.Merge(&clone)
   619  	src.TrimFront(toRead)
   620  	return int(toRead)
   621  }
   622  
   623  // ReadFromPacketData moves count bytes from the beginning of oth to the end of
   624  // d.
   625  func (d PacketData) ReadFromPacketData(oth PacketData, count int) {
   626  	buf := oth.ToBuffer()
   627  	buf.Truncate(int64(count))
   628  	d.MergeBuffer(&buf)
   629  	oth.TrimFront(count)
   630  	buf.Release()
   631  }
   632  
   633  // Merge clears headers in oth and merges its data with d.
   634  func (d PacketData) Merge(oth PacketData) {
   635  	oth.pk.buf.TrimFront(int64(oth.pk.dataOffset()))
   636  	d.pk.buf.Merge(&oth.pk.buf)
   637  }
   638  
   639  // TrimFront removes up to count bytes from the front of d's payload.
   640  func (d PacketData) TrimFront(count int) {
   641  	if count > d.Size() {
   642  		count = d.Size()
   643  	}
   644  	buf := d.pk.Data().ToBuffer()
   645  	buf.TrimFront(int64(count))
   646  	d.pk.buf.Truncate(int64(d.pk.dataOffset()))
   647  	d.pk.buf.Merge(&buf)
   648  }
   649  
   650  // Size returns the number of bytes in the data payload of the packet.
   651  func (d PacketData) Size() int {
   652  	return int(d.pk.buf.Size()) - d.pk.dataOffset()
   653  }
   654  
   655  // AsRange returns a Range representing the current data payload of the packet.
   656  func (d PacketData) AsRange() Range {
   657  	return Range{
   658  		pk:     d.pk,
   659  		offset: d.pk.dataOffset(),
   660  		length: d.Size(),
   661  	}
   662  }
   663  
   664  // Checksum returns a checksum over the data payload of the packet.
   665  func (d PacketData) Checksum() uint16 {
   666  	return d.pk.buf.Checksum(d.pk.dataOffset())
   667  }
   668  
   669  // ChecksumAtOffset returns a checksum over the data payload of the packet
   670  // starting from offset.
   671  func (d PacketData) ChecksumAtOffset(offset int) uint16 {
   672  	return d.pk.buf.Checksum(offset)
   673  }
   674  
   675  // Range represents a contiguous subportion of a PacketBuffer.
   676  type Range struct {
   677  	pk     PacketBufferPtr
   678  	offset int
   679  	length int
   680  }
   681  
   682  // Size returns the number of bytes in r.
   683  func (r Range) Size() int {
   684  	return r.length
   685  }
   686  
   687  // SubRange returns a new Range starting at off bytes of r. It returns an empty
   688  // range if off is out-of-bounds.
   689  func (r Range) SubRange(off int) Range {
   690  	if off > r.length {
   691  		return Range{pk: r.pk}
   692  	}
   693  	return Range{
   694  		pk:     r.pk,
   695  		offset: r.offset + off,
   696  		length: r.length - off,
   697  	}
   698  }
   699  
   700  // Capped returns a new Range with the same starting point of r and length
   701  // capped at max.
   702  func (r Range) Capped(max int) Range {
   703  	if r.length <= max {
   704  		return r
   705  	}
   706  	return Range{
   707  		pk:     r.pk,
   708  		offset: r.offset,
   709  		length: max,
   710  	}
   711  }
   712  
   713  // ToSlice returns a caller-owned copy of data in r.
   714  func (r Range) ToSlice() []byte {
   715  	if r.length == 0 {
   716  		return nil
   717  	}
   718  	all := make([]byte, 0, r.length)
   719  	r.iterate(func(v *buffer.View) {
   720  		all = append(all, v.AsSlice()...)
   721  	})
   722  	return all
   723  }
   724  
   725  // ToView returns a caller-owned copy of data in r.
   726  func (r Range) ToView() *buffer.View {
   727  	if r.length == 0 {
   728  		return nil
   729  	}
   730  	newV := buffer.NewView(r.length)
   731  	r.iterate(func(v *buffer.View) {
   732  		newV.Write(v.AsSlice())
   733  	})
   734  	return newV
   735  }
   736  
   737  // iterate calls fn for each piece in r. fn is always called with a non-empty
   738  // slice.
   739  func (r Range) iterate(fn func(*buffer.View)) {
   740  	r.pk.buf.SubApply(r.offset, r.length, fn)
   741  }
   742  
   743  // PayloadSince returns a caller-owned view containing the payload starting from
   744  // and including a particular header.
   745  func PayloadSince(h PacketHeader) *buffer.View {
   746  	offset := h.pk.headerOffset()
   747  	for i := headerType(0); i < h.typ; i++ {
   748  		offset += h.pk.headers[i].length
   749  	}
   750  	return Range{
   751  		pk:     h.pk,
   752  		offset: offset,
   753  		length: int(h.pk.buf.Size()) - offset,
   754  	}.ToView()
   755  }
   756  
   757  // BufferSince returns a caller-owned view containing the packet payload
   758  // starting from and including a particular header.
   759  func BufferSince(h PacketHeader) buffer.Buffer {
   760  	offset := h.pk.headerOffset()
   761  	for i := headerType(0); i < h.typ; i++ {
   762  		offset += h.pk.headers[i].length
   763  	}
   764  	clone := h.pk.buf.Clone()
   765  	clone.TrimFront(int64(offset))
   766  	return clone
   767  }