mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-14 05:11:19 -04:00
Add packet padding container for packet length shaping
This commit is contained in:
parent
c1ac2aa577
commit
9e1cc35878
3 changed files with 194 additions and 0 deletions
47
common/packetPaddingContainer/container.go
Normal file
47
common/packetPaddingContainer/container.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package packetPaddingContainer
|
||||||
|
|
||||||
|
import "encoding/binary"
|
||||||
|
|
||||||
|
func New() PacketPaddingContainer {
|
||||||
|
return packetPaddingContainer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type packetPaddingContainer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c packetPaddingContainer) Pack(data_OWNERSHIP_RELINQUISHED []byte, padding int) []byte {
|
||||||
|
data := append(data_OWNERSHIP_RELINQUISHED, make([]byte, padding)...)
|
||||||
|
data_length := len(data_OWNERSHIP_RELINQUISHED)
|
||||||
|
data = append(data, byte(data_length>>8), byte(data_length))
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c packetPaddingContainer) Pad(padding int) []byte {
|
||||||
|
if assertPaddingLengthIsNotNegative := padding < 0; assertPaddingLengthIsNotNegative {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch padding {
|
||||||
|
case 0:
|
||||||
|
return []byte{}
|
||||||
|
case 1:
|
||||||
|
return []byte{0}
|
||||||
|
case 2:
|
||||||
|
return []byte{0, 0}
|
||||||
|
default:
|
||||||
|
return append(make([]byte, padding-2), byte(padding>>8), byte(padding))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c packetPaddingContainer) Unpack(wrappedData_OWNERSHIP_RELINQUISHED []byte) ([]byte, int) {
|
||||||
|
if len(wrappedData_OWNERSHIP_RELINQUISHED) < 2 {
|
||||||
|
return nil, len(wrappedData_OWNERSHIP_RELINQUISHED)
|
||||||
|
}
|
||||||
|
wrappedData_tail := wrappedData_OWNERSHIP_RELINQUISHED[len(wrappedData_OWNERSHIP_RELINQUISHED)-2:]
|
||||||
|
dataLength := int(binary.BigEndian.Uint16(wrappedData_tail))
|
||||||
|
paddingLength := len(wrappedData_OWNERSHIP_RELINQUISHED) - dataLength - 2
|
||||||
|
if paddingLength < 0 {
|
||||||
|
return nil, paddingLength
|
||||||
|
}
|
||||||
|
return wrappedData_OWNERSHIP_RELINQUISHED[:dataLength], paddingLength
|
||||||
|
}
|
34
common/packetPaddingContainer/containerIfce.go
Normal file
34
common/packetPaddingContainer/containerIfce.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package packetPaddingContainer
|
||||||
|
|
||||||
|
// PacketPaddingContainer is an interface that defines methods to pad packets
|
||||||
|
// with a given number of bytes, and to unpack the padding from a padded packet.
|
||||||
|
// The packet format is as follows if the desired output length is greater than
|
||||||
|
// 2 bytes:
|
||||||
|
// | data | padding | data length |
|
||||||
|
// The data length is a 16-bit big-endian integer that represents the length of
|
||||||
|
// the data in bytes.
|
||||||
|
// If the desired output length is 2 bytes or less, the packet format is as
|
||||||
|
// follows:
|
||||||
|
// | padding |
|
||||||
|
// No payload will be included in the packet.
|
||||||
|
type PacketPaddingContainer interface {
|
||||||
|
// Pack pads the given data with the given number of bytes, and appends the
|
||||||
|
// length of the data to the end of the data. The returned byte slice
|
||||||
|
// contains the padded data.
|
||||||
|
// This generates a packet with a length of
|
||||||
|
// len(data_OWNERSHIP_RELINQUISHED) + padding + 2
|
||||||
|
// @param data_OWNERSHIP_RELINQUISHED - The payload, this reference is consumed and should not be used after this call.
|
||||||
|
// @param padding - The number of padding bytes to add to the data.
|
||||||
|
Pack(data_OWNERSHIP_RELINQUISHED []byte, padding int) []byte
|
||||||
|
|
||||||
|
// Unpack extracts the data and padding from the given padded data. It
|
||||||
|
// returns the data and the number of padding bytes.
|
||||||
|
// the data may be nil.
|
||||||
|
// @param wrappedData_OWNERSHIP_RELINQUISHED - The packet, this reference is consumed and should not be used after this call.
|
||||||
|
Unpack(wrappedData_OWNERSHIP_RELINQUISHED []byte) ([]byte, int)
|
||||||
|
|
||||||
|
// Pad returns a padding packet of padding length.
|
||||||
|
// If the padding length is less than 0, nil is returned.
|
||||||
|
// @param padding - The number of padding bytes to add to the data.
|
||||||
|
Pad(padding int) []byte
|
||||||
|
}
|
113
common/packetPaddingContainer/container_test.go
Normal file
113
common/packetPaddingContainer/container_test.go
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
package packetPaddingContainer_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
|
||||||
|
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/packetPaddingContainer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPacketPaddingContainer(t *testing.T) {
|
||||||
|
Convey("Given a PacketPaddingContainer", t, func() {
|
||||||
|
container := packetPaddingContainer.New()
|
||||||
|
|
||||||
|
Convey("When packing data with padding", func() {
|
||||||
|
data := []byte("testdata")
|
||||||
|
padding := 4
|
||||||
|
packedData := container.Pack(data, padding)
|
||||||
|
|
||||||
|
Convey("The packed data should have the correct length", func() {
|
||||||
|
expectedLength := len(data) + padding + 2
|
||||||
|
So(len(packedData), ShouldEqual, expectedLength)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When unpacking the packed data", func() {
|
||||||
|
unpackedData, unpackedPadding := container.Unpack(packedData)
|
||||||
|
|
||||||
|
Convey("The unpacked data should match the original data", func() {
|
||||||
|
So(string(unpackedData), ShouldEqual, string(data))
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("The unpacked padding should match the original padding", func() {
|
||||||
|
So(unpackedPadding, ShouldEqual, padding)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When packing empty data with padding", func() {
|
||||||
|
data := []byte("")
|
||||||
|
padding := 4
|
||||||
|
packedData := container.Pack(data, padding)
|
||||||
|
|
||||||
|
Convey("The packed data should have the correct length", func() {
|
||||||
|
expectedLength := len(data) + padding + 2
|
||||||
|
So(len(packedData), ShouldEqual, expectedLength)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When unpacking the packed data", func() {
|
||||||
|
unpackedData, unpackedPadding := container.Unpack(packedData)
|
||||||
|
|
||||||
|
Convey("The unpacked data should match the original data", func() {
|
||||||
|
So(string(unpackedData), ShouldEqual, string(data))
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("The unpacked padding should match the original padding", func() {
|
||||||
|
So(unpackedPadding, ShouldEqual, padding)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When packing data with zero padding", func() {
|
||||||
|
data := []byte("testdata")
|
||||||
|
padding := 0
|
||||||
|
packedData := container.Pack(data, padding)
|
||||||
|
|
||||||
|
Convey("The packed data should have the correct length", func() {
|
||||||
|
expectedLength := len(data) + padding + 2
|
||||||
|
So(len(packedData), ShouldEqual, expectedLength)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When unpacking the packed data", func() {
|
||||||
|
unpackedData, unpackedPadding := container.Unpack(packedData)
|
||||||
|
|
||||||
|
Convey("The unpacked data should match the original data", func() {
|
||||||
|
So(string(unpackedData), ShouldEqual, string(data))
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("The unpacked padding should match the original padding", func() {
|
||||||
|
So(unpackedPadding, ShouldEqual, padding)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When padding data", func() {
|
||||||
|
Convey("With a positive padding length", func() {
|
||||||
|
padLength := 3
|
||||||
|
padData := container.Pad(padLength)
|
||||||
|
|
||||||
|
Convey("The padded data should have the correct length", func() {
|
||||||
|
So(len(padData), ShouldEqual, padLength)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("With a zero padding length", func() {
|
||||||
|
padLength := 0
|
||||||
|
padData := container.Pad(padLength)
|
||||||
|
|
||||||
|
Convey("The padded data should be empty", func() {
|
||||||
|
So(len(padData), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("With a negative padding length", func() {
|
||||||
|
padLength := -1
|
||||||
|
padData := container.Pad(padLength)
|
||||||
|
|
||||||
|
Convey("The padded data should be nil", func() {
|
||||||
|
So(padData, ShouldBeNil)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue