From a6c20ba7f67257995db86f800bb726f57f2b2053 Mon Sep 17 00:00:00 2001 From: Ahmadreza Dorkhah Date: Fri, 9 Aug 2024 01:06:21 +0330 Subject: [PATCH 1/4] add single tls hello fragmenting method --- infra/conf/freedom.go | 4 ++++ proxy/freedom/freedom.go | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/infra/conf/freedom.go b/infra/conf/freedom.go index d90b7c2d6ee7..8752b228c8a4 100644 --- a/infra/conf/freedom.go +++ b/infra/conf/freedom.go @@ -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 (two TLS Hello Fragments into one tcp segment) + config.Fragment.PacketsFrom = 1 + config.Fragment.PacketsTo = 1 case "tlshello": // TLS Hello Fragmentation (into multiple handshake messages) config.Fragment.PacketsFrom = 0 diff --git a/proxy/freedom/freedom.go b/proxy/freedom/freedom.go index 55ad353d0cd1..233afdd44098 100644 --- a/proxy/freedom/freedom.go +++ b/proxy/freedom/freedom.go @@ -392,6 +392,29 @@ 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 { + // two TLS Hello Fragments into one tcp segment + 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 { // maybe already fragmented somehow + return f.writer.Write(b) + } + + p2 := b[5 : len(b)/2] + p1 := []byte{22, 3, 1, byte(len(p2) >> 8), byte(len(p2))} + p4 := b[len(b)/2:] + p3 := []byte{22, 3, 1, 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) + } + if f.fragment.PacketsFrom == 0 && f.fragment.PacketsTo == 1 { if f.count != 1 || len(b) <= 5 || b[0] != 22 { return f.writer.Write(b) From 28564136b4174a722598fbd1dee18629ba79e1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E6=89=87=E6=BB=91=E7=BF=94=E7=BF=BC?= Date: Fri, 9 Aug 2024 13:16:55 +0800 Subject: [PATCH 2/4] Rename --- infra/conf/freedom.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/conf/freedom.go b/infra/conf/freedom.go index 8752b228c8a4..9489a04cd0b5 100644 --- a/infra/conf/freedom.go +++ b/infra/conf/freedom.go @@ -62,8 +62,8 @@ func (c *FreedomConfig) Build() (proto.Message, error) { var err, err2 error switch strings.ToLower(c.Fragment.Packets) { - case "singletlshello": - // TLS Hello Fragmentation (two TLS Hello Fragments into one tcp segment) + case "recordlayer": + // TLS Hello Fragmentation (into two record layer fragments) config.Fragment.PacketsFrom = 1 config.Fragment.PacketsTo = 1 case "tlshello": From 7c898f93dbd8d61b2c8e214903b93530c985a6a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E6=89=87=E6=BB=91=E7=BF=94=E7=BF=BC?= Date: Fri, 9 Aug 2024 15:17:48 +0800 Subject: [PATCH 3/4] Use actual record header version --- proxy/freedom/freedom.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/proxy/freedom/freedom.go b/proxy/freedom/freedom.go index 233afdd44098..3afa05deb4a8 100644 --- a/proxy/freedom/freedom.go +++ b/proxy/freedom/freedom.go @@ -393,19 +393,21 @@ func (f *FragmentWriter) Write(b []byte) (int, error) { f.count++ if f.fragment.PacketsFrom == 1 && f.fragment.PacketsTo == 1 && f.count == 1 { - // two TLS Hello Fragments into one tcp segment + // 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 { // maybe already fragmented somehow + 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{22, 3, 1, byte(len(p2) >> 8), byte(len(p2))} + p1 := []byte{b[0], b[1], b[2], byte(len(p2) >> 8), byte(len(p2))} p4 := b[len(b)/2:] - p3 := []byte{22, 3, 1, byte(len(p4) >> 8), byte(len(p4))} + p3 := []byte{b[0], b[1], b[2], byte(len(p4) >> 8), byte(len(p4))} // 😐 Concat requires go v1.22 x := append(p1, p2...) From 2cfeef313e92f4a843b94238e4769c2f8ed154f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E6=89=87=E6=BB=91=E7=BF=94=E7=BF=BC?= Date: Fri, 9 Aug 2024 17:18:02 +0800 Subject: [PATCH 4/4] Revert --- infra/conf/freedom.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/conf/freedom.go b/infra/conf/freedom.go index 9489a04cd0b5..4df6b15cc740 100644 --- a/infra/conf/freedom.go +++ b/infra/conf/freedom.go @@ -62,8 +62,8 @@ func (c *FreedomConfig) Build() (proto.Message, error) { var err, err2 error switch strings.ToLower(c.Fragment.Packets) { - case "recordlayer": - // TLS Hello Fragmentation (into two record layer fragments) + case "singletlshello": + // TLS Hello Fragmentation (into multiple handshake messages but one tcp segment) config.Fragment.PacketsFrom = 1 config.Fragment.PacketsTo = 1 case "tlshello":