mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-29 16:58:34 +00:00
Added tcp fragmentation for freedom outbound (#2021)
* Added tcp fragmentation for freedom outbound * Added TCP_NODELAY to outbound sockopt * Changed fragment parameters to accept ranges and changed strategy to use length * Changed packetNumber to packets, supporting range. * Refactored the freedom fragment logic * Refine Write() --------- Co-authored-by: RPRX <63339210+RPRX@users.noreply.github.com>
This commit is contained in:
parent
c80646a045
commit
5f5ae37571
10 changed files with 392 additions and 71 deletions
|
@ -2,6 +2,7 @@ package conf
|
|||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
@ -11,10 +12,17 @@ import (
|
|||
)
|
||||
|
||||
type FreedomConfig struct {
|
||||
DomainStrategy string `json:"domainStrategy"`
|
||||
Timeout *uint32 `json:"timeout"`
|
||||
Redirect string `json:"redirect"`
|
||||
UserLevel uint32 `json:"userLevel"`
|
||||
DomainStrategy string `json:"domainStrategy"`
|
||||
Timeout *uint32 `json:"timeout"`
|
||||
Redirect string `json:"redirect"`
|
||||
UserLevel uint32 `json:"userLevel"`
|
||||
Fragment *Fragment `json:"fragment"`
|
||||
}
|
||||
|
||||
type Fragment struct {
|
||||
Packets string `json:"packets"`
|
||||
Length string `json:"length"`
|
||||
Interval string `json:"interval"`
|
||||
}
|
||||
|
||||
// Build implements Buildable
|
||||
|
@ -30,6 +38,88 @@ func (c *FreedomConfig) Build() (proto.Message, error) {
|
|||
config.DomainStrategy = freedom.Config_USE_IP6
|
||||
}
|
||||
|
||||
if c.Fragment != nil {
|
||||
if len(c.Fragment.Interval) == 0 || len(c.Fragment.Length) == 0 {
|
||||
return nil, newError("Invalid interval or length")
|
||||
}
|
||||
intervalMinMax := strings.Split(c.Fragment.Interval, "-")
|
||||
var minInterval, maxInterval int64
|
||||
var err, err2 error
|
||||
if len(intervalMinMax) == 2 {
|
||||
minInterval, err = strconv.ParseInt(intervalMinMax[0], 10, 64)
|
||||
maxInterval, err2 = strconv.ParseInt(intervalMinMax[1], 10, 64)
|
||||
} else {
|
||||
minInterval, err = strconv.ParseInt(intervalMinMax[0], 10, 64)
|
||||
maxInterval = minInterval
|
||||
}
|
||||
if err != nil {
|
||||
return nil, newError("Invalid minimum interval: ", err).Base(err)
|
||||
}
|
||||
if err2 != nil {
|
||||
return nil, newError("Invalid maximum interval: ", err2).Base(err2)
|
||||
}
|
||||
|
||||
lengthMinMax := strings.Split(c.Fragment.Length, "-")
|
||||
var minLength, maxLength int64
|
||||
if len(lengthMinMax) == 2 {
|
||||
minLength, err = strconv.ParseInt(lengthMinMax[0], 10, 64)
|
||||
maxLength, err2 = strconv.ParseInt(lengthMinMax[1], 10, 64)
|
||||
|
||||
} else {
|
||||
minLength, err = strconv.ParseInt(lengthMinMax[0], 10, 64)
|
||||
maxLength = minLength
|
||||
}
|
||||
if err != nil {
|
||||
return nil, newError("Invalid minimum length: ", err).Base(err)
|
||||
}
|
||||
if err2 != nil {
|
||||
return nil, newError("Invalid maximum length: ", err2).Base(err2)
|
||||
}
|
||||
|
||||
if minInterval > maxInterval {
|
||||
minInterval, maxInterval = maxInterval, minInterval
|
||||
}
|
||||
if minLength > maxLength {
|
||||
minLength, maxLength = maxLength, minLength
|
||||
}
|
||||
|
||||
config.Fragment = &freedom.Fragment{
|
||||
MinInterval: int32(minInterval),
|
||||
MaxInterval: int32(maxInterval),
|
||||
MinLength: int32(minLength),
|
||||
MaxLength: int32(maxLength),
|
||||
}
|
||||
|
||||
if len(c.Fragment.Packets) > 0 {
|
||||
packetRange := strings.Split(c.Fragment.Packets, "-")
|
||||
var startPacket, endPacket int64
|
||||
if len(packetRange) == 2 {
|
||||
startPacket, err = strconv.ParseInt(packetRange[0], 10, 64)
|
||||
endPacket, err2 = strconv.ParseInt(packetRange[1], 10, 64)
|
||||
} else {
|
||||
startPacket, err = strconv.ParseInt(packetRange[0], 10, 64)
|
||||
endPacket = startPacket
|
||||
}
|
||||
if err != nil {
|
||||
return nil, newError("Invalid start packet: ", err).Base(err)
|
||||
}
|
||||
if err2 != nil {
|
||||
return nil, newError("Invalid end packet: ", err2).Base(err2)
|
||||
}
|
||||
if startPacket > endPacket {
|
||||
return nil, newError("Invalid packet range: ", c.Fragment.Packets)
|
||||
}
|
||||
if startPacket < 1 {
|
||||
return nil, newError("Cannot start from packet 0")
|
||||
}
|
||||
config.Fragment.StartPacket = int32(startPacket)
|
||||
config.Fragment.EndPacket = int32(endPacket)
|
||||
} else {
|
||||
config.Fragment.StartPacket = 0
|
||||
config.Fragment.EndPacket = 0
|
||||
}
|
||||
}
|
||||
|
||||
if c.Timeout != nil {
|
||||
config.Timeout = *c.Timeout
|
||||
}
|
||||
|
|
|
@ -617,7 +617,8 @@ type SocketConfig struct {
|
|||
TCPKeepAliveIdle int32 `json:"tcpKeepAliveIdle"`
|
||||
TCPCongestion string `json:"tcpCongestion"`
|
||||
TCPWindowClamp int32 `json:"tcpWindowClamp"`
|
||||
TCPMaxSeg int32 `json:"tcpMaxSeg"`
|
||||
TCPMaxSeg int32 `json:"tcpMaxSeg"`
|
||||
TcpNoDelay bool `json:"tcpNoDelay"`
|
||||
TCPUserTimeout int32 `json:"tcpUserTimeout"`
|
||||
V6only bool `json:"v6only"`
|
||||
Interface string `json:"interface"`
|
||||
|
@ -671,7 +672,8 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
|||
TcpKeepAliveIdle: c.TCPKeepAliveIdle,
|
||||
TcpCongestion: c.TCPCongestion,
|
||||
TcpWindowClamp: c.TCPWindowClamp,
|
||||
TcpMaxSeg: c.TCPMaxSeg,
|
||||
TcpMaxSeg: c.TCPMaxSeg,
|
||||
TcpNoDelay: c.TcpNoDelay,
|
||||
TcpUserTimeout: c.TCPUserTimeout,
|
||||
V6Only: c.V6only,
|
||||
Interface: c.Interface,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue