2021-06-10 14:05:56 +08:00
package adapter
2018-12-22 23:56:42 +08:00
import (
2019-07-02 19:18:03 +08:00
"context"
2024-05-12 19:34:25 +08:00
"crypto/tls"
2018-12-22 23:56:42 +08:00
"encoding/json"
2021-06-10 14:05:56 +08:00
"fmt"
2019-03-16 00:43:16 +08:00
"net"
"net/http"
2022-04-20 01:52:51 +08:00
"net/netip"
2021-06-10 14:05:56 +08:00
"net/url"
2023-08-09 13:51:02 +08:00
"strconv"
2024-10-01 11:14:37 +08:00
"strings"
2019-03-16 00:43:16 +08:00
"time"
2018-12-22 23:56:42 +08:00
2023-11-03 21:01:45 +08:00
"github.com/metacubex/mihomo/common/atomic"
"github.com/metacubex/mihomo/common/queue"
"github.com/metacubex/mihomo/common/utils"
2024-05-12 19:34:25 +08:00
"github.com/metacubex/mihomo/component/ca"
2023-11-03 21:01:45 +08:00
"github.com/metacubex/mihomo/component/dialer"
C "github.com/metacubex/mihomo/constant"
2024-10-01 11:14:37 +08:00
"github.com/metacubex/mihomo/log"
2023-11-23 10:24:01 +08:00
"github.com/puzpuzpuz/xsync/v3"
2018-12-22 23:56:42 +08:00
)
2021-12-26 21:20:41 +08:00
var UnifiedDelay = atomic . NewBool ( false )
2023-06-04 11:51:30 +08:00
const (
defaultHistoriesNum = 10
)
2023-12-06 17:11:24 +08:00
type internalProxyState struct {
2023-10-10 16:34:33 +08:00
alive atomic . Bool
2023-12-06 17:11:24 +08:00
history * queue . Queue [ C . DelayHistory ]
2023-06-04 11:51:30 +08:00
}
2019-03-16 00:43:16 +08:00
type Proxy struct {
C . ProxyAdapter
2023-10-10 16:34:33 +08:00
alive atomic . Bool
2023-12-22 21:18:17 +08:00
history * queue . Queue [ C . DelayHistory ]
2023-12-06 17:11:24 +08:00
extra * xsync . MapOf [ string , * internalProxyState ]
2019-03-16 00:43:16 +08:00
}
2024-09-27 21:33:37 +08:00
// Adapter implements C.Proxy
func ( p * Proxy ) Adapter ( ) C . ProxyAdapter {
return p . ProxyAdapter
}
2023-12-22 21:18:17 +08:00
// AliveForTestUrl implements C.Proxy
func ( p * Proxy ) AliveForTestUrl ( url string ) bool {
2023-08-31 19:56:20 +08:00
if state , ok := p . extra . Load ( url ) ; ok {
2023-09-02 16:54:35 +08:00
return state . alive . Load ( )
2023-06-04 11:51:30 +08:00
}
return p . alive . Load ( )
}
2021-04-29 11:23:14 +08:00
// Dial implements C.Proxy
2019-08-09 01:28:37 +08:00
func ( p * Proxy ) Dial ( metadata * C . Metadata ) ( C . Conn , error ) {
2021-06-10 14:05:56 +08:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , C . DefaultTCPTimeout )
2019-10-12 23:55:39 +08:00
defer cancel ( )
return p . DialContext ( ctx , metadata )
}
2021-04-29 11:23:14 +08:00
// DialContext implements C.ProxyAdapter
2021-11-07 16:48:51 +08:00
func ( p * Proxy ) DialContext ( ctx context . Context , metadata * C . Metadata , opts ... dialer . Option ) ( C . Conn , error ) {
conn , err := p . ProxyAdapter . DialContext ( ctx , metadata , opts ... )
2019-03-16 00:43:16 +08:00
return conn , err
}
2021-10-15 21:44:53 +08:00
// DialUDP implements C.ProxyAdapter
func ( p * Proxy ) DialUDP ( metadata * C . Metadata ) ( C . PacketConn , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , C . DefaultUDPTimeout )
defer cancel ( )
return p . ListenPacketContext ( ctx , metadata )
}
// ListenPacketContext implements C.ProxyAdapter
2021-11-07 16:48:51 +08:00
func ( p * Proxy ) ListenPacketContext ( ctx context . Context , metadata * C . Metadata , opts ... dialer . Option ) ( C . PacketConn , error ) {
pc , err := p . ProxyAdapter . ListenPacketContext ( ctx , metadata , opts ... )
2021-10-15 21:44:53 +08:00
return pc , err
}
2021-04-29 11:23:14 +08:00
// DelayHistory implements C.Proxy
2019-03-17 14:52:39 +08:00
func ( p * Proxy ) DelayHistory ( ) [ ] C . DelayHistory {
2022-04-20 01:52:51 +08:00
queueM := p . history . Copy ( )
2023-12-23 13:10:29 +08:00
histories := [ ] C . DelayHistory { }
2022-04-20 01:52:51 +08:00
for _ , item := range queueM {
2022-04-06 01:07:08 +08:00
histories = append ( histories , item )
2019-03-17 14:52:39 +08:00
}
return histories
}
2023-06-04 11:51:30 +08:00
// DelayHistoryForTestUrl implements C.Proxy
func ( p * Proxy ) DelayHistoryForTestUrl ( url string ) [ ] C . DelayHistory {
var queueM [ ] C . DelayHistory
2023-08-31 19:56:20 +08:00
if state , ok := p . extra . Load ( url ) ; ok {
2023-09-02 16:54:35 +08:00
queueM = state . history . Copy ( )
2023-06-04 11:51:30 +08:00
}
2023-12-23 13:10:29 +08:00
histories := [ ] C . DelayHistory { }
2023-06-04 11:51:30 +08:00
for _ , item := range queueM {
histories = append ( histories , item )
}
return histories
}
2023-12-06 17:11:24 +08:00
// ExtraDelayHistories return all delay histories for each test URL
// implements C.Proxy
func ( p * Proxy ) ExtraDelayHistories ( ) map [ string ] C . ProxyState {
histories := map [ string ] C . ProxyState { }
2023-06-04 11:51:30 +08:00
2023-12-06 17:11:24 +08:00
p . extra . Range ( func ( k string , v * internalProxyState ) bool {
2023-09-02 16:54:35 +08:00
testUrl := k
state := v
2023-08-31 19:56:20 +08:00
queueM := state . history . Copy ( )
2023-12-06 17:11:24 +08:00
var history [ ] C . DelayHistory
2023-08-31 19:56:20 +08:00
for _ , item := range queueM {
2023-12-06 17:11:24 +08:00
history = append ( history , item )
2023-06-04 11:51:30 +08:00
}
2023-08-31 19:56:20 +08:00
2023-12-06 17:11:24 +08:00
histories [ testUrl ] = C . ProxyState {
Alive : state . alive . Load ( ) ,
History : history ,
}
2023-08-31 19:56:20 +08:00
return true
} )
2023-12-06 17:11:24 +08:00
return histories
2023-06-04 11:51:30 +08:00
}
2023-12-06 17:11:24 +08:00
// LastDelayForTestUrl return last history record of the specified URL. if proxy is not alive, return the max value of uint16.
2021-04-29 11:23:14 +08:00
// implements C.Proxy
2023-06-04 11:51:30 +08:00
func ( p * Proxy ) LastDelayForTestUrl ( url string ) ( delay uint16 ) {
2023-12-22 21:18:17 +08:00
var maxDelay uint16 = 0xffff
2023-06-04 11:51:30 +08:00
2023-12-06 17:11:24 +08:00
alive := false
var history C . DelayHistory
2023-06-04 11:51:30 +08:00
2023-08-31 19:56:20 +08:00
if state , ok := p . extra . Load ( url ) ; ok {
2023-09-02 16:54:35 +08:00
alive = state . alive . Load ( )
history = state . history . Last ( )
2023-06-04 11:51:30 +08:00
}
2023-12-06 17:11:24 +08:00
if ! alive || history . Delay == 0 {
2023-12-22 21:18:17 +08:00
return maxDelay
2023-06-04 11:51:30 +08:00
}
return history . Delay
}
2021-04-29 11:23:14 +08:00
// MarshalJSON implements C.ProxyAdapter
2019-03-17 14:52:39 +08:00
func ( p * Proxy ) MarshalJSON ( ) ( [ ] byte , error ) {
inner , err := p . ProxyAdapter . MarshalJSON ( )
if err != nil {
return inner , err
}
2022-03-16 12:10:13 +08:00
mapping := map [ string ] any { }
2022-04-20 01:52:51 +08:00
_ = json . Unmarshal ( inner , & mapping )
2019-03-17 14:52:39 +08:00
mapping [ "history" ] = p . DelayHistory ( )
2023-12-06 17:11:24 +08:00
mapping [ "extra" ] = p . ExtraDelayHistories ( )
mapping [ "alive" ] = p . alive . Load ( )
2019-12-13 00:29:24 +08:00
mapping [ "name" ] = p . Name ( )
2021-06-10 15:08:33 +08:00
mapping [ "udp" ] = p . SupportUDP ( )
2023-01-28 00:07:20 +08:00
mapping [ "xudp" ] = p . SupportXUDP ( )
2022-11-28 19:52:55 +08:00
mapping [ "tfo" ] = p . SupportTFO ( )
2019-03-17 14:52:39 +08:00
return json . Marshal ( mapping )
}
2019-03-16 00:43:16 +08:00
// URLTest get the delay for the specified URL
2021-04-29 11:23:14 +08:00
// implements C.Proxy
2023-12-01 16:44:30 +08:00
func ( p * Proxy ) URLTest ( ctx context . Context , url string , expectedStatus utils . IntRanges [ uint16 ] ) ( t uint16 , err error ) {
2024-01-30 15:51:12 +08:00
var satisfied bool
2019-03-17 14:52:39 +08:00
defer func ( ) {
2023-06-04 11:51:30 +08:00
alive := err == nil
2023-12-06 17:11:24 +08:00
record := C . DelayHistory { Time : time . Now ( ) }
if alive {
record . Delay = t
}
2023-06-07 11:04:03 +08:00
2023-12-06 17:11:24 +08:00
p . alive . Store ( alive )
p . history . Put ( record )
if p . history . Len ( ) > defaultHistoriesNum {
p . history . Pop ( )
}
2023-06-04 11:51:30 +08:00
2023-12-06 17:11:24 +08:00
state , ok := p . extra . Load ( url )
if ! ok {
state = & internalProxyState {
history : queue . New [ C . DelayHistory ] ( defaultHistoriesNum ) ,
alive : atomic . NewBool ( true ) ,
2023-06-04 11:51:30 +08:00
}
2023-12-06 17:11:24 +08:00
p . extra . Store ( url , state )
}
2023-06-04 11:51:30 +08:00
2024-01-30 15:51:12 +08:00
if ! satisfied {
record . Delay = 0
alive = false
}
2023-12-06 17:11:24 +08:00
state . alive . Store ( alive )
state . history . Put ( record )
if state . history . Len ( ) > defaultHistoriesNum {
state . history . Pop ( )
2019-03-17 14:52:39 +08:00
}
2023-12-06 17:11:24 +08:00
2019-03-17 14:52:39 +08:00
} ( )
2021-12-26 21:20:41 +08:00
unifiedDelay := UnifiedDelay . Load ( )
2019-03-16 00:43:16 +08:00
addr , err := urlToMetadata ( url )
if err != nil {
return
}
start := time . Now ( )
2019-10-12 23:55:39 +08:00
instance , err := p . DialContext ( ctx , & addr )
2019-03-16 00:43:16 +08:00
if err != nil {
return
}
2022-04-20 01:52:51 +08:00
defer func ( ) {
_ = instance . Close ( )
} ( )
2019-07-02 19:18:03 +08:00
2019-08-09 15:39:13 +08:00
req , err := http . NewRequest ( http . MethodHead , url , nil )
2019-07-02 19:18:03 +08:00
if err != nil {
return
}
req = req . WithContext ( ctx )
2019-03-16 00:43:16 +08:00
transport := & http . Transport {
2022-04-20 01:52:51 +08:00
DialContext : func ( context . Context , string , string ) ( net . Conn , error ) {
2019-03-16 00:43:16 +08:00
return instance , nil
} ,
// from http.DefaultTransport
MaxIdleConns : 100 ,
IdleConnTimeout : 90 * time . Second ,
TLSHandshakeTimeout : 10 * time . Second ,
ExpectContinueTimeout : 1 * time . Second ,
2024-05-12 19:34:25 +08:00
TLSClientConfig : ca . GetGlobalTLSConfig ( & tls . Config { } ) ,
2019-03-16 00:43:16 +08:00
}
2019-07-02 19:18:03 +08:00
2020-02-25 16:08:13 +08:00
client := http . Client {
2022-06-25 09:16:28 +08:00
Timeout : 30 * time . Second ,
2020-02-25 16:08:13 +08:00
Transport : transport ,
CheckRedirect : func ( req * http . Request , via [ ] * http . Request ) error {
return http . ErrUseLastResponse
} ,
}
2022-06-19 17:29:46 +08:00
2021-07-21 17:01:02 +08:00
defer client . CloseIdleConnections ( )
2022-06-19 17:29:46 +08:00
2019-07-02 19:18:03 +08:00
resp , err := client . Do ( req )
2022-06-19 17:29:46 +08:00
2019-03-16 00:43:16 +08:00
if err != nil {
return
}
2021-12-26 21:20:41 +08:00
2022-06-19 17:29:46 +08:00
_ = resp . Body . Close ( )
2021-12-26 21:20:41 +08:00
if unifiedDelay {
2022-06-25 09:16:28 +08:00
second := time . Now ( )
2024-10-01 11:14:37 +08:00
var ignoredErr error
var secondResp * http . Response
secondResp , ignoredErr = client . Do ( req )
if ignoredErr == nil {
resp = secondResp
2022-06-25 09:16:28 +08:00
_ = resp . Body . Close ( )
start = second
2024-10-01 11:14:37 +08:00
} else {
if strings . HasPrefix ( url , "http://" ) {
log . Errorln ( "%s failed to get the second response from %s: %v" , p . Name ( ) , url , ignoredErr )
log . Warnln ( "It is recommended to use HTTPS for provider.health-check.url and group.url to ensure better reliability. Due to some proxy providers hijacking test addresses and not being compatible with repeated HEAD requests, using HTTP may result in failed tests." )
}
2021-12-26 21:20:41 +08:00
}
}
2022-06-19 17:29:46 +08:00
2024-01-30 15:51:12 +08:00
satisfied = resp != nil && ( expectedStatus == nil || expectedStatus . Check ( uint16 ( resp . StatusCode ) ) )
2019-03-17 14:52:39 +08:00
t = uint16 ( time . Since ( start ) / time . Millisecond )
2019-03-16 00:43:16 +08:00
return
}
func NewProxy ( adapter C . ProxyAdapter ) * Proxy {
2023-08-31 19:56:20 +08:00
return & Proxy {
ProxyAdapter : adapter ,
history : queue . New [ C . DelayHistory ] ( defaultHistoriesNum ) ,
alive : atomic . NewBool ( true ) ,
2023-12-06 17:11:24 +08:00
extra : xsync . NewMapOf [ string , * internalProxyState ] ( ) }
2019-03-16 00:43:16 +08:00
}
2021-06-10 14:05:56 +08:00
func urlToMetadata ( rawURL string ) ( addr C . Metadata , err error ) {
u , err := url . Parse ( rawURL )
if err != nil {
return
}
port := u . Port ( )
if port == "" {
switch u . Scheme {
case "https" :
port = "443"
case "http" :
port = "80"
default :
err = fmt . Errorf ( "%s scheme not Support" , rawURL )
return
}
}
2023-08-09 13:51:02 +08:00
uintPort , err := strconv . ParseUint ( port , 10 , 16 )
if err != nil {
return
}
2021-06-10 14:05:56 +08:00
addr = C . Metadata {
2022-11-11 09:19:28 +08:00
Host : u . Hostname ( ) ,
DstIP : netip . Addr { } ,
2023-08-09 13:51:02 +08:00
DstPort : uint16 ( uintPort ) ,
2021-06-10 14:05:56 +08:00
}
return
}