2020-11-25 14:01:53 +03:00
package freedom
2020-12-04 04:36:16 +03:00
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
2020-11-25 14:01:53 +03:00
import (
"context"
"time"
2020-12-04 04:36:16 +03: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"
"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 16:06:21 +03:00
"github.com/xtls/xray-core/features/stats"
2020-12-04 04:36:16 +03:00
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
2021-12-15 03:28:47 +03:00
"github.com/xtls/xray-core/transport/internet/stat"
2020-11-25 14:01:53 +03: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
} ) )
}
// 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 {
2021-03-07 07:39:50 +03:00
var option dns . IPOption = dns . IPOption {
IPv4Enable : true ,
IPv6Enable : true ,
FakeEnable : false ,
}
2020-11-25 14:01:53 +03:00
if h . config . DomainStrategy == Config_USE_IP4 || ( localAddr != nil && localAddr . Family ( ) . IsIPv4 ( ) ) {
2021-03-07 07:39:50 +03:00
option = dns . IPOption {
IPv4Enable : true ,
IPv6Enable : false ,
FakeEnable : false ,
2020-11-25 14:01:53 +03:00
}
} else if h . config . DomainStrategy == Config_USE_IP6 || ( localAddr != nil && localAddr . Family ( ) . IsIPv6 ( ) ) {
2021-03-07 07:39:50 +03:00
option = dns . IPOption {
IPv4Enable : false ,
IPv6Enable : true ,
FakeEnable : false ,
2020-11-25 14:01:53 +03:00
}
}
2021-03-07 07:39:50 +03:00
ips , err := h . dns . LookupIP ( domain , option )
2020-11-25 14:01:53 +03: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." )
}
destination := outbound . Target
2021-02-17 16:37:55 +03:00
UDPOverride := net . UDPDestination ( nil , 0 )
2020-11-25 14:01:53 +03:00
if h . config . DestinationOverride != nil {
server := h . config . DestinationOverride . Server
if isValidAddress ( server . Address ) {
destination . Address = server . Address . AsAddress ( )
2021-02-17 16:37:55 +03:00
UDPOverride . Address = destination . Address
2020-11-25 14:01:53 +03:00
}
if server . Port != 0 {
destination . Port = net . Port ( server . Port )
2021-02-17 16:37:55 +03:00
UDPOverride . Port = destination . Port
2020-11-25 14:01:53 +03:00
}
}
input := link . Reader
output := link . Writer
2021-09-20 15:11:21 +03:00
var conn stat . Connection
2020-11-25 14:01:53 +03:00
err := retry . ExponentialBackoff ( 5 , 100 ) . On ( func ( ) error {
dialDest := destination
if h . config . useIP ( ) && dialDest . Address . Family ( ) . IsDomain ( ) {
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 07:39:50 +03:00
newError ( "dialing to " , dialDest ) . WriteToLog ( session . ExportIDToError ( ctx ) )
2020-11-25 14:01:53 +03: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 14:01:53 +03: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 14:01:53 +03: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 14:01:53 +03:00
requestDone := func ( ) error {
defer timer . SetTimeout ( plcy . Timeouts . DownlinkOnly )
var writer buf . Writer
if destination . Network == net . Network_TCP {
writer = buf . NewWriter ( conn )
} else {
2021-02-17 16:37:55 +03:00
writer = NewPacketWriter ( conn , h , ctx , UDPOverride )
2020-11-25 14:01:53 +03: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 )
var reader buf . Reader
if destination . Network == net . Network_TCP {
reader = buf . NewReader ( conn )
} else {
2021-03-05 15:06:37 +03:00
reader = NewPacketReader ( conn , UDPOverride )
2020-11-25 14:01:53 +03: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 14:01:53 +03: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 16:06:21 +03:00
2021-03-05 15:06:37 +03:00
func NewPacketReader ( conn net . Conn , UDPOverride net . Destination ) buf . Reader {
2020-12-23 16:06:21 +03:00
iConn := conn
2021-09-20 15:11:21 +03:00
statConn , ok := iConn . ( * stat . CounterConnection )
2020-12-23 16:06:21 +03:00
if ok {
iConn = statConn . Connection
}
var counter stats . Counter
if statConn != nil {
counter = statConn . ReadCounter
}
2021-03-06 10:19:09 +03:00
if c , ok := iConn . ( * internet . PacketConnWrapper ) ; ok && UDPOverride . Address == nil && UDPOverride . Port == 0 {
2020-12-23 16:06:21 +03: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 12:40:28 +03: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 16:06:21 +03:00
if r . Counter != nil {
r . Counter . Add ( int64 ( n ) )
}
return buf . MultiBuffer { b } , nil
}
2021-02-17 16:37:55 +03:00
func NewPacketWriter ( conn net . Conn , h * Handler , ctx context . Context , UDPOverride net . Destination ) buf . Writer {
2020-12-23 16:06:21 +03:00
iConn := conn
2021-09-20 15:11:21 +03:00
statConn , ok := iConn . ( * stat . CounterConnection )
2020-12-23 16:06:21 +03: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 12:40:28 +03:00
Handler : h ,
Context : ctx ,
2021-02-17 16:37:55 +03:00
UDPOverride : UDPOverride ,
2020-12-23 16:06:21 +03:00
}
}
return & buf . SequentialWriter { Writer : conn }
}
type PacketWriter struct {
* internet . PacketConnWrapper
stats . Counter
2020-12-28 12:40:28 +03:00
* Handler
context . Context
2021-02-17 16:37:55 +03:00
UDPOverride net . Destination
2020-12-23 16:06:21 +03: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 16:37:55 +03:00
if w . UDPOverride . Address != nil {
b . UDP . Address = w . UDPOverride . Address
}
if w . UDPOverride . Port != 0 {
b . UDP . Port = w . UDPOverride . Port
}
2020-12-28 12:40:28 +03:00
if w . Handler . config . useIP ( ) && b . UDP . Address . Family ( ) . IsDomain ( ) {
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 16:06:21 +03: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
}