Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions infra/conf/freedom.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ func (c *FreedomConfig) Build() (proto.Message, error) {
var err, err2 error

switch strings.ToLower(c.Fragment.Packets) {
case "singletlshello":
// TLS Hello Fragmentation (into multiple handshake messages but one tcp segment)
config.Fragment.PacketsFrom = 1
config.Fragment.PacketsTo = 1
case "tlshello":
// TLS Hello Fragmentation (into multiple handshake messages)
config.Fragment.PacketsFrom = 0
Expand Down
25 changes: 25 additions & 0 deletions proxy/freedom/freedom.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,31 @@ type FragmentWriter struct {
func (f *FragmentWriter) Write(b []byte) (int, error) {
f.count++

if f.fragment.PacketsFrom == 1 && f.fragment.PacketsTo == 1 && f.count == 1 {
// TLS record layer fragments(for client hello)
// Note: TLS handshake doesn't check record layer, so it can be modified by us.
if f.count != 1 || len(b) <= 5 || b[0] != 22 {
return f.writer.Write(b)
}
recordLen := 5 + ((int(b[3]) << 8) | int(b[4]))
if len(b) < recordLen { // Size not match, maybe already fragmented somehow
return f.writer.Write(b)
}

// Build new fragmented client hello
p2 := b[5 : len(b)/2]
p1 := []byte{b[0], b[1], b[2], byte(len(p2) >> 8), byte(len(p2))}
p4 := b[len(b)/2:]
p3 := []byte{b[0], b[1], b[2], byte(len(p4) >> 8), byte(len(p4))}

// 😐 Concat requires go v1.22
x := append(p1, p2...)
x = append(x, p3...)
x = append(x, p4...)

return f.writer.Write(x)
Comment on lines +412 to +417
Copy link
Contributor

@mmmray mmmray Aug 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels wrong. has it been tested? You are splitting up the bytestring and then concatenate it again. And then write out the entire packet anyway. Normally they should be sent using individual Write calls, with Sleep inbetween. Take a look at the other fragment settings' code, where a for-loop is used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I tested and checked using Wireshark, and it works fine. I know it’s unusual, but as long as it works, it is useful. The tlshello fragmenting method generates fragments of a specified length, writes each fragment with one TCP segment, and then sleeps for the specified interval. However, this new method splits the TLS ClientHello into two halves, generates two fragments into one buffer, and sends both fragments using one TCP segment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh i misunderstood. I just realized you have some hardcoded bytes in there as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have observed that almost all TLS Client Hello messages start with [22, 3, 1], so I hardcoded this value. I don’t anticipate this causing any bugs, but I can make it dynamic if needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

话说这里为啥备注需要 Go 1.22?append 不是自古以来就有的吗

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need go 1.22 for Concat method. with Concat you can do this

slices.Concat(p1, p2, p3, p4)

}

if f.fragment.PacketsFrom == 0 && f.fragment.PacketsTo == 1 {
if f.count != 1 || len(b) <= 5 || b[0] != 22 {
return f.writer.Write(b)
Expand Down