2020-11-25 13:01:53 +02:00
package freedom
2020-12-04 03:36:16 +02:00
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
2020-11-25 13:01:53 +02:00
import (
"context"
2023-05-22 05:59:58 +03:00
"crypto/rand"
"io"
"math/big"
2020-11-25 13:01:53 +02:00
"time"
2020-12-04 03:36:16 +02:00
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/net"
2023-05-04 05:21:45 +03:00
"github.com/xtls/xray-core/common/platform"
2020-12-04 03:36:16 +02:00
"github.com/xtls/xray-core/common/retry"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/policy"
2020-12-23 15:06:21 +02:00
"github.com/xtls/xray-core/features/stats"
2023-05-04 05:21:45 +03:00
"github.com/xtls/xray-core/proxy"
2020-12-04 03:36:16 +02:00
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
2021-12-15 02:28:47 +02:00
"github.com/xtls/xray-core/transport/internet/stat"
2020-11-25 13:01:53 +02:00
)
2023-05-04 05:21:45 +03:00
var useSplice bool
2020-11-25 13:01:53 +02:00
func init ( ) {
common . Must ( common . RegisterConfig ( ( * Config ) ( nil ) , func ( ctx context . Context , config interface { } ) ( interface { } , error ) {
h := new ( Handler )
if err := core . RequireFeatures ( ctx , func ( pm policy . Manager , d dns . Client ) error {
return h . Init ( config . ( * Config ) , pm , d )
} ) ; err != nil {
return nil , err
}
return h , nil
} ) )
2023-05-04 05:21:45 +03:00
const defaultFlagValue = "NOT_DEFINED_AT_ALL"
2023-11-18 17:25:58 +02:00
value := platform . NewEnvFlag ( platform . UseFreedomSplice ) . GetValue ( func ( ) string { return defaultFlagValue } )
2023-05-04 05:21:45 +03:00
switch value {
2023-11-18 17:25:58 +02:00
case defaultFlagValue , "auto" , "enable" :
2023-05-04 05:21:45 +03:00
useSplice = true
}
2020-11-25 13:01:53 +02:00
}
// Handler handles Freedom connections.
type Handler struct {
policyManager policy . Manager
dns dns . Client
config * Config
}
// Init initializes the Handler with necessary parameters.
func ( h * Handler ) Init ( config * Config , pm policy . Manager , d dns . Client ) error {
h . config = config
h . policyManager = pm
h . dns = d
return nil
}
func ( h * Handler ) policy ( ) policy . Session {
p := h . policyManager . ForLevel ( h . config . UserLevel )
if h . config . Timeout > 0 && h . config . UserLevel == 0 {
p . Timeouts . ConnectionIdle = time . Duration ( h . config . Timeout ) * time . Second
}
return p
}
func ( h * Handler ) resolveIP ( ctx context . Context , domain string , localAddr net . Address ) net . Address {
2023-11-18 17:25:58 +02:00
ips , err := h . dns . LookupIP ( domain , dns . IPOption {
IPv4Enable : ( localAddr == nil || localAddr . Family ( ) . IsIPv4 ( ) ) && h . config . preferIP4 ( ) ,
IPv6Enable : ( localAddr == nil || localAddr . Family ( ) . IsIPv6 ( ) ) && h . config . preferIP6 ( ) ,
} )
{ // Resolve fallback
if ( len ( ips ) == 0 || err != nil ) && h . config . hasFallback ( ) && localAddr == nil {
ips , err = h . dns . LookupIP ( domain , dns . IPOption {
IPv4Enable : h . config . fallbackIP4 ( ) ,
IPv6Enable : h . config . fallbackIP6 ( ) ,
} )
2020-11-25 13:01:53 +02:00
}
}
if err != nil {
newError ( "failed to get IP address for domain " , domain ) . Base ( err ) . WriteToLog ( session . ExportIDToError ( ctx ) )
}
if len ( ips ) == 0 {
return nil
}
return net . IPAddress ( ips [ dice . Roll ( len ( ips ) ) ] )
}
func isValidAddress ( addr * net . IPOrDomain ) bool {
if addr == nil {
return false
}
a := addr . AsAddress ( )
return a != net . AnyIP
}
// Process implements proxy.Outbound.
func ( h * Handler ) Process ( ctx context . Context , link * transport . Link , dialer internet . Dialer ) error {
outbound := session . OutboundFromContext ( ctx )
if outbound == nil || ! outbound . Target . IsValid ( ) {
return newError ( "target not specified." )
}
2023-05-04 05:21:45 +03:00
outbound . Name = "freedom"
inbound := session . InboundFromContext ( ctx )
if inbound != nil {
inbound . SetCanSpliceCopy ( 1 )
}
2020-11-25 13:01:53 +02:00
destination := outbound . Target
2021-02-17 15:37:55 +02:00
UDPOverride := net . UDPDestination ( nil , 0 )
2020-11-25 13:01:53 +02:00
if h . config . DestinationOverride != nil {
server := h . config . DestinationOverride . Server
if isValidAddress ( server . Address ) {
destination . Address = server . Address . AsAddress ( )
2021-02-17 15:37:55 +02:00
UDPOverride . Address = destination . Address
2020-11-25 13:01:53 +02:00
}
if server . Port != 0 {
destination . Port = net . Port ( server . Port )
2021-02-17 15:37:55 +02:00
UDPOverride . Port = destination . Port
2020-11-25 13:01:53 +02:00
}
}
input := link . Reader
output := link . Writer
2021-09-20 15:11:21 +03:00
var conn stat . Connection
2020-11-25 13:01:53 +02:00
err := retry . ExponentialBackoff ( 5 , 100 ) . On ( func ( ) error {
dialDest := destination
2023-11-18 17:25:58 +02:00
if h . config . hasStrategy ( ) && dialDest . Address . Family ( ) . IsDomain ( ) {
2020-11-25 13:01:53 +02:00
ip := h . resolveIP ( ctx , dialDest . Address . Domain ( ) , dialer . Address ( ) )
if ip != nil {
dialDest = net . Destination {
Network : dialDest . Network ,
Address : ip ,
Port : dialDest . Port ,
}
2021-03-07 06:39:50 +02:00
newError ( "dialing to " , dialDest ) . WriteToLog ( session . ExportIDToError ( ctx ) )
2023-11-18 17:25:58 +02:00
} else if h . config . forceIP ( ) {
return dns . ErrEmptyResponse
2020-11-25 13:01:53 +02:00
}
}
rawConn , err := dialer . Dial ( ctx , dialDest )
if err != nil {
return err
}
conn = rawConn
return nil
} )
if err != nil {
return newError ( "failed to open connection to " , destination ) . Base ( err )
}
defer conn . Close ( )
2023-04-09 03:56:54 +03:00
newError ( "connection opened to " , destination , ", local endpoint " , conn . LocalAddr ( ) , ", remote endpoint " , conn . RemoteAddr ( ) ) . WriteToLog ( session . ExportIDToError ( ctx ) )
2020-11-25 13:01:53 +02:00
2023-04-06 13:21:35 +03:00
var newCtx context . Context
var newCancel context . CancelFunc
if session . TimeoutOnlyFromContext ( ctx ) {
newCtx , newCancel = context . WithCancel ( context . Background ( ) )
}
2020-11-25 13:01:53 +02:00
plcy := h . policy ( )
ctx , cancel := context . WithCancel ( ctx )
2023-04-06 13:21:35 +03:00
timer := signal . CancelAfterInactivity ( ctx , func ( ) {
cancel ( )
if newCancel != nil {
newCancel ( )
}
} , plcy . Timeouts . ConnectionIdle )
2020-11-25 13:01:53 +02:00
requestDone := func ( ) error {
defer timer . SetTimeout ( plcy . Timeouts . DownlinkOnly )
var writer buf . Writer
if destination . Network == net . Network_TCP {
2023-05-22 05:59:58 +03:00
if h . config . Fragment != nil {
2023-07-06 19:30:39 +03:00
newError ( "FRAGMENT" , h . config . Fragment . PacketsFrom , h . config . Fragment . PacketsTo , h . config . Fragment . LengthMin , h . config . Fragment . LengthMax ,
h . config . Fragment . IntervalMin , h . config . Fragment . IntervalMax ) . AtDebug ( ) . WriteToLog ( session . ExportIDToError ( ctx ) )
writer = buf . NewWriter ( & FragmentWriter {
fragment : h . config . Fragment ,
writer : conn ,
} )
2023-05-22 05:59:58 +03:00
} else {
writer = buf . NewWriter ( conn )
}
2020-11-25 13:01:53 +02:00
} else {
2021-02-17 15:37:55 +02:00
writer = NewPacketWriter ( conn , h , ctx , UDPOverride )
2020-11-25 13:01:53 +02:00
}
if err := buf . Copy ( input , writer , buf . UpdateActivity ( timer ) ) ; err != nil {
return newError ( "failed to process request" ) . Base ( err )
}
return nil
}
responseDone := func ( ) error {
defer timer . SetTimeout ( plcy . Timeouts . UplinkOnly )
if destination . Network == net . Network_TCP {
2023-05-04 05:21:45 +03:00
var writeConn net . Conn
if inbound := session . InboundFromContext ( ctx ) ; inbound != nil && inbound . Conn != nil && useSplice {
writeConn = inbound . Conn
}
return proxy . CopyRawConnIfExist ( ctx , conn , writeConn , link . Writer , timer )
2020-11-25 13:01:53 +02:00
}
2023-05-04 05:21:45 +03:00
reader := NewPacketReader ( conn , UDPOverride )
2020-11-25 13:01:53 +02:00
if err := buf . Copy ( reader , output , buf . UpdateActivity ( timer ) ) ; err != nil {
return newError ( "failed to process response" ) . Base ( err )
}
return nil
}
2023-04-06 13:21:35 +03:00
if newCtx != nil {
ctx = newCtx
}
2020-11-25 13:01:53 +02:00
if err := task . Run ( ctx , requestDone , task . OnSuccess ( responseDone , task . Close ( output ) ) ) ; err != nil {
return newError ( "connection ends" ) . Base ( err )
}
return nil
}
2020-12-23 15:06:21 +02:00
2021-03-05 14:06:37 +02:00
func NewPacketReader ( conn net . Conn , UDPOverride net . Destination ) buf . Reader {
2020-12-23 15:06:21 +02:00
iConn := conn
2021-09-20 15:11:21 +03:00
statConn , ok := iConn . ( * stat . CounterConnection )
2020-12-23 15:06:21 +02:00
if ok {
iConn = statConn . Connection
}
var counter stats . Counter
if statConn != nil {
counter = statConn . ReadCounter
}
2021-03-06 09:19:09 +02:00
if c , ok := iConn . ( * internet . PacketConnWrapper ) ; ok && UDPOverride . Address == nil && UDPOverride . Port == 0 {
2020-12-23 15:06:21 +02:00
return & PacketReader {
PacketConnWrapper : c ,
Counter : counter ,
}
}
return & buf . PacketReader { Reader : conn }
}
type PacketReader struct {
* internet . PacketConnWrapper
stats . Counter
}
func ( r * PacketReader ) ReadMultiBuffer ( ) ( buf . MultiBuffer , error ) {
b := buf . New ( )
b . Resize ( 0 , buf . Size )
n , d , err := r . PacketConnWrapper . ReadFrom ( b . Bytes ( ) )
if err != nil {
b . Release ( )
return nil , err
}
b . Resize ( 0 , int32 ( n ) )
2020-12-28 11:40:28 +02:00
b . UDP = & net . Destination {
Address : net . IPAddress ( d . ( * net . UDPAddr ) . IP ) ,
Port : net . Port ( d . ( * net . UDPAddr ) . Port ) ,
Network : net . Network_UDP ,
}
2020-12-23 15:06:21 +02:00
if r . Counter != nil {
r . Counter . Add ( int64 ( n ) )
}
return buf . MultiBuffer { b } , nil
}
2021-02-17 15:37:55 +02:00
func NewPacketWriter ( conn net . Conn , h * Handler , ctx context . Context , UDPOverride net . Destination ) buf . Writer {
2020-12-23 15:06:21 +02:00
iConn := conn
2021-09-20 15:11:21 +03:00
statConn , ok := iConn . ( * stat . CounterConnection )
2020-12-23 15:06:21 +02:00
if ok {
iConn = statConn . Connection
}
var counter stats . Counter
if statConn != nil {
counter = statConn . WriteCounter
}
if c , ok := iConn . ( * internet . PacketConnWrapper ) ; ok {
return & PacketWriter {
PacketConnWrapper : c ,
Counter : counter ,
2020-12-28 11:40:28 +02:00
Handler : h ,
Context : ctx ,
2021-02-17 15:37:55 +02:00
UDPOverride : UDPOverride ,
2020-12-23 15:06:21 +02:00
}
}
return & buf . SequentialWriter { Writer : conn }
}
type PacketWriter struct {
* internet . PacketConnWrapper
stats . Counter
2020-12-28 11:40:28 +02:00
* Handler
context . Context
2021-02-17 15:37:55 +02:00
UDPOverride net . Destination
2020-12-23 15:06:21 +02:00
}
func ( w * PacketWriter ) WriteMultiBuffer ( mb buf . MultiBuffer ) error {
for {
mb2 , b := buf . SplitFirst ( mb )
mb = mb2
if b == nil {
break
}
var n int
var err error
if b . UDP != nil {
2021-02-17 15:37:55 +02:00
if w . UDPOverride . Address != nil {
b . UDP . Address = w . UDPOverride . Address
}
if w . UDPOverride . Port != 0 {
b . UDP . Port = w . UDPOverride . Port
}
2023-11-18 17:25:58 +02:00
if w . Handler . config . hasStrategy ( ) && b . UDP . Address . Family ( ) . IsDomain ( ) {
2020-12-28 11:40:28 +02:00
ip := w . Handler . resolveIP ( w . Context , b . UDP . Address . Domain ( ) , nil )
if ip != nil {
b . UDP . Address = ip
}
}
destAddr , _ := net . ResolveUDPAddr ( "udp" , b . UDP . NetAddr ( ) )
if destAddr == nil {
b . Release ( )
continue
}
n , err = w . PacketConnWrapper . WriteTo ( b . Bytes ( ) , destAddr )
2020-12-23 15:06:21 +02:00
} else {
n , err = w . PacketConnWrapper . Write ( b . Bytes ( ) )
}
b . Release ( )
if err != nil {
buf . ReleaseMulti ( mb )
return err
}
if w . Counter != nil {
w . Counter . Add ( int64 ( n ) )
}
}
return nil
}
2023-05-22 05:59:58 +03:00
type FragmentWriter struct {
2023-07-06 19:30:39 +03:00
fragment * Fragment
writer io . Writer
count uint64
2023-05-22 05:59:58 +03:00
}
2023-07-06 19:30:39 +03:00
func ( f * FragmentWriter ) Write ( b [ ] byte ) ( int , error ) {
f . count ++
if f . fragment . PacketsFrom == 0 && f . fragment . PacketsTo == 1 {
if f . count != 1 || len ( b ) <= 5 || b [ 0 ] != 22 {
return f . writer . Write ( b )
}
recordLen := 5 + ( ( int ( b [ 3 ] ) << 8 ) | int ( b [ 4 ] ) )
data := b [ 5 : recordLen ]
buf := make ( [ ] byte , 1024 )
for from := 0 ; ; {
to := from + int ( randBetween ( int64 ( f . fragment . LengthMin ) , int64 ( f . fragment . LengthMax ) ) )
if to > len ( data ) {
to = len ( data )
}
copy ( buf [ : 3 ] , b )
copy ( buf [ 5 : ] , data [ from : to ] )
l := to - from
from = to
buf [ 3 ] = byte ( l >> 8 )
buf [ 4 ] = byte ( l )
_ , err := f . writer . Write ( buf [ : 5 + l ] )
time . Sleep ( time . Duration ( randBetween ( int64 ( f . fragment . IntervalMin ) , int64 ( f . fragment . IntervalMax ) ) ) * time . Millisecond )
if err != nil {
return 0 , err
}
if from == len ( data ) {
if len ( b ) > recordLen {
n , err := f . writer . Write ( b [ recordLen : ] )
if err != nil {
return recordLen + n , err
}
}
return len ( b ) , nil
}
}
2023-05-22 05:59:58 +03:00
}
2023-07-06 19:30:39 +03:00
if f . fragment . PacketsFrom != 0 && ( f . count < f . fragment . PacketsFrom || f . count > f . fragment . PacketsTo ) {
return f . writer . Write ( b )
}
for from := 0 ; ; {
to := from + int ( randBetween ( int64 ( f . fragment . LengthMin ) , int64 ( f . fragment . LengthMax ) ) )
if to > len ( b ) {
to = len ( b )
2023-05-22 05:59:58 +03:00
}
2023-07-06 19:30:39 +03:00
n , err := f . writer . Write ( b [ from : to ] )
from += n
time . Sleep ( time . Duration ( randBetween ( int64 ( f . fragment . IntervalMin ) , int64 ( f . fragment . IntervalMax ) ) ) * time . Millisecond )
2023-05-22 05:59:58 +03:00
if err != nil {
2023-07-06 19:30:39 +03:00
return from , err
2023-05-22 05:59:58 +03:00
}
2023-07-06 19:30:39 +03:00
if from >= len ( b ) {
return from , nil
2023-05-22 05:59:58 +03:00
}
}
}
// stolen from github.com/xtls/xray-core/transport/internet/reality
func randBetween ( left int64 , right int64 ) int64 {
if left == right {
return left
}
bigInt , _ := rand . Int ( rand . Reader , big . NewInt ( right - left ) )
return left + bigInt . Int64 ( )
}