mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-06-29 05:15:31 +03:00
Compare commits
4 Commits
v1.11.11-e
...
main-next
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc5eb1e1a5 | ||
|
|
995267a042 | ||
|
|
41226a6075 | ||
|
|
81d32181ce |
@@ -35,6 +35,7 @@ func NewManager(logger log.ContextLogger, registry adapter.EndpointRegistry) *Ma
|
||||
|
||||
func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
if m.started && m.stage >= stage {
|
||||
panic("already started")
|
||||
}
|
||||
@@ -42,12 +43,9 @@ func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
m.stage = stage
|
||||
if stage == adapter.StartStateStart {
|
||||
// started with outbound manager
|
||||
m.access.Unlock()
|
||||
return nil
|
||||
}
|
||||
endpoints := m.endpoints
|
||||
m.access.Unlock()
|
||||
for _, endpoint := range endpoints {
|
||||
for _, endpoint := range m.endpoints {
|
||||
err := adapter.LegacyStart(endpoint, stage)
|
||||
if err != nil {
|
||||
return E.Cause(err, stage, " endpoint/", endpoint.Type(), "[", endpoint.Tag(), "]")
|
||||
|
||||
@@ -41,8 +41,6 @@ type CacheFile interface {
|
||||
StoreGroupExpand(group string, expand bool) error
|
||||
LoadRuleSet(tag string) *SavedBinary
|
||||
SaveRuleSet(tag string, set *SavedBinary) error
|
||||
LoadCloudflareProfile(tag string) *SavedBinary
|
||||
SaveCloudflareProfile(tag string, set *SavedBinary) error
|
||||
}
|
||||
|
||||
type SavedBinary struct {
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
type CloudeflareApi struct {
|
||||
client http.Client
|
||||
}
|
||||
|
||||
func NewCloudeflareApi(opts ...CloudflareApiOption) *CloudeflareApi {
|
||||
api := &CloudeflareApi{http.Client{Timeout: 30 * time.Second}}
|
||||
for _, opt := range opts {
|
||||
opt(api)
|
||||
}
|
||||
return api
|
||||
}
|
||||
|
||||
func (api *CloudeflareApi) CreateProfile(ctx context.Context) (*CloudflareProfile, error) {
|
||||
privateKey, err := wgtypes.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request, err := http.NewRequest("POST", "https://api.cloudflareclient.com/v0i1909051800/reg", strings.NewReader(
|
||||
fmt.Sprintf(
|
||||
"{\"install_id\":\"\",\"tos\":\"%s\",\"key\":\"%s\",\"fcm_token\":\"\",\"type\":\"ios\",\"locale\":\"en_US\"}",
|
||||
time.Now().Format("2006-01-02T15:04:05.000Z"),
|
||||
privateKey.PublicKey().String(),
|
||||
),
|
||||
))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := api.client.Do(request.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
if response.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("status code is not 200")
|
||||
}
|
||||
content, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
profile := new(CloudflareProfile)
|
||||
profile.Config.PrivateKey = privateKey.String()
|
||||
return profile, json.NewDecoder(strings.NewReader(gjson.Get(string(content), "result").Raw)).Decode(profile)
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type CloudflareApiOption func(api *CloudeflareApi)
|
||||
|
||||
func WithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) CloudflareApiOption {
|
||||
return func(api *CloudeflareApi) {
|
||||
api.client.Transport = &http.Transport{
|
||||
DialContext: dialContext,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package cloudflare
|
||||
|
||||
import "time"
|
||||
|
||||
type CloudflareProfile struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
Account struct {
|
||||
ID string `json:"id"`
|
||||
AccountType string `json:"account_type"`
|
||||
Created time.Time `json:"created"`
|
||||
Updated time.Time `json:"updated"`
|
||||
PremiumData int `json:"premium_data"`
|
||||
Quota int `json:"quota"`
|
||||
Usage int `json:"usage"`
|
||||
WarpPlus bool `json:"warp_plus"`
|
||||
ReferralCount int `json:"referral_count"`
|
||||
ReferralRenewalCountdown int `json:"referral_renewal_countdown"`
|
||||
Role string `json:"role"`
|
||||
License string `json:"license"`
|
||||
TTL time.Time `json:"ttl"`
|
||||
} `json:"account"`
|
||||
Config struct {
|
||||
ClientID string `json:"client_id"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
Peers []struct {
|
||||
PublicKey string `json:"public_key"`
|
||||
Endpoint struct {
|
||||
V4 string `json:"v4"`
|
||||
V6 string `json:"v6"`
|
||||
Host string `json:"host"`
|
||||
Ports []int `json:"ports"`
|
||||
} `json:"endpoint"`
|
||||
} `json:"peers"`
|
||||
Interface struct {
|
||||
Addresses struct {
|
||||
V4 string `json:"v4"`
|
||||
V6 string `json:"v6"`
|
||||
} `json:"addresses"`
|
||||
} `json:"interface"`
|
||||
Services struct {
|
||||
HTTPProxy string `json:"http_proxy"`
|
||||
} `json:"services"`
|
||||
Metrics struct {
|
||||
Ping int `json:"ping"`
|
||||
Report int `json:"report"`
|
||||
} `json:"metrics"`
|
||||
} `json:"config"`
|
||||
Token string `json:"token"`
|
||||
WarpEnabled bool `json:"warp_enabled"`
|
||||
WaitlistEnabled bool `json:"waitlist_enabled"`
|
||||
Created time.Time `json:"created"`
|
||||
Updated time.Time `json:"updated"`
|
||||
Tos time.Time `json:"tos"`
|
||||
Place int `json:"place"`
|
||||
Locale string `json:"locale"`
|
||||
Enabled bool `json:"enabled"`
|
||||
InstallID string `json:"install_id"`
|
||||
FcmToken string `json:"fcm_token"`
|
||||
Policy struct {
|
||||
TunnelProtocol string `json:"tunnel_protocol"`
|
||||
} `json:"policy"`
|
||||
}
|
||||
@@ -15,7 +15,6 @@ const (
|
||||
TypeTrojan = "trojan"
|
||||
TypeNaive = "naive"
|
||||
TypeWireGuard = "wireguard"
|
||||
TypeWARP = "warp"
|
||||
TypeHysteria = "hysteria"
|
||||
TypeTor = "tor"
|
||||
TypeSSH = "ssh"
|
||||
@@ -61,8 +60,6 @@ func ProxyDisplayName(proxyType string) string {
|
||||
return "Naive"
|
||||
case TypeWireGuard:
|
||||
return "WireGuard"
|
||||
case TypeWARP:
|
||||
return "WARP"
|
||||
case TypeHysteria:
|
||||
return "Hysteria"
|
||||
case TypeTor:
|
||||
|
||||
@@ -316,36 +316,3 @@ func (c *CacheFile) SaveRuleSet(tag string, set *adapter.SavedBinary) error {
|
||||
return bucket.Put([]byte(tag), setBinary)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CacheFile) LoadCloudflareProfile(tag string) *adapter.SavedBinary {
|
||||
var savedProfile adapter.SavedBinary
|
||||
err := c.DB.View(func(t *bbolt.Tx) error {
|
||||
bucket := c.bucket(t, bucketRuleSet)
|
||||
if bucket == nil {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
profileBinary := bucket.Get([]byte(tag))
|
||||
if len(profileBinary) == 0 {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
return savedProfile.UnmarshalBinary(profileBinary)
|
||||
})
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &savedProfile
|
||||
}
|
||||
|
||||
func (c *CacheFile) SaveCloudflareProfile(tag string, set *adapter.SavedBinary) error {
|
||||
return c.DB.Batch(func(t *bbolt.Tx) error {
|
||||
bucket, err := c.createBucket(t, bucketRuleSet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
profileBinary, err := set.MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return bucket.Put([]byte(tag), profileBinary)
|
||||
})
|
||||
}
|
||||
|
||||
17
go.mod
17
go.mod
@@ -1,8 +1,6 @@
|
||||
module github.com/sagernet/sing-box
|
||||
|
||||
go 1.23.6
|
||||
|
||||
toolchain go1.24.3
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/caddyserver/certmagic v0.20.0
|
||||
@@ -28,8 +26,8 @@ require (
|
||||
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff
|
||||
github.com/sagernet/quic-go v0.49.0-beta.1
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||
github.com/sagernet/sing v0.6.9
|
||||
github.com/sagernet/sing-dns v0.4.3
|
||||
github.com/sagernet/sing v0.6.10
|
||||
github.com/sagernet/sing-dns v0.4.5
|
||||
github.com/sagernet/sing-mux v0.3.2
|
||||
github.com/sagernet/sing-quic v0.4.1-0.20250423030647-0eb05f373a76
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||
@@ -56,11 +54,6 @@ require (
|
||||
howett.net/plist v1.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
)
|
||||
|
||||
//replace github.com/sagernet/sing => ../sing
|
||||
|
||||
require (
|
||||
@@ -95,8 +88,6 @@ require (
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/tevino/abool/v2 v2.1.0 // indirect
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
@@ -111,5 +102,3 @@ require (
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/blake3 v1.3.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/sagernet/wireguard-go => github.com/getlantern/wireguard-go v0.0.1-beta.5.0.20250303165430-793006c422ec
|
||||
|
||||
25
go.sum
25
go.sum
@@ -18,14 +18,11 @@ github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbY
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/getlantern/wireguard-go v0.0.1-beta.5.0.20250303165430-793006c422ec h1:jXekDkSozctYj5JQlV1mCsIW+qHpIkgSFhOIpgRSB1I=
|
||||
github.com/getlantern/wireguard-go v0.0.1-beta.5.0.20250303165430-793006c422ec/go.mod h1:akc2Wh+rX9bFFNnHJGsQ8VIV3eJI1LXJYgx2Y+8lcW8=
|
||||
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
|
||||
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
@@ -37,7 +34,6 @@ github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm
|
||||
github.com/gofrs/uuid/v5 v5.3.2 h1:2jfO8j3XgSwlz/wHqemAEugfnTlikAYHhnqQ8Xh4fE0=
|
||||
github.com/gofrs/uuid/v5 v5.3.2/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
@@ -65,7 +61,6 @@ github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/libdns/alidns v1.0.3 h1:LFHuGnbseq5+HCeGa1aW8awyX/4M2psB9962fdD2+yQ=
|
||||
github.com/libdns/alidns v1.0.3/go.mod h1:e18uAG6GanfRhcJj6/tps2rCMzQJaYVcGKT+ELjdjGE=
|
||||
github.com/libdns/cloudflare v0.1.1 h1:FVPfWwP8zZCqj268LZjmkDleXlHPlFU9KC4OJ3yn054=
|
||||
@@ -90,7 +85,6 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
|
||||
github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
|
||||
github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
|
||||
github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
|
||||
github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
@@ -124,10 +118,11 @@ github.com/sagernet/quic-go v0.49.0-beta.1 h1:3LdoCzVVfYRibZns1tYWSIoB65fpTmrwy+
|
||||
github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8WHNsRs71b3Lt1+p/U=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||
github.com/sagernet/sing v0.6.9 h1:y/XJH17oyBd6hxgQtKnIdLXu7TsOHxO5i1JeVfVmjXw=
|
||||
github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-dns v0.4.3 h1:R6X9oWYbdZ0Mm+8PkdqrBkqx3JwiAbnETUZGOpEdY4E=
|
||||
github.com/sagernet/sing-dns v0.4.3/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8=
|
||||
github.com/sagernet/sing v0.6.10 h1:Jey1tePgH9bjFuK1fQI3D9T+bPOQ4SdHMjuS4sYjDv4=
|
||||
github.com/sagernet/sing v0.6.10/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-dns v0.4.5 h1:D9REN14qx2FTrZRBrtFLL99f2CuFzQ9S7mIf8uV5hZI=
|
||||
github.com/sagernet/sing-dns v0.4.5/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8=
|
||||
github.com/sagernet/sing-mux v0.3.2 h1:meZVFiiStvHThb/trcpAkCrmtJOuItG5Dzl1RRP5/NE=
|
||||
github.com/sagernet/sing-mux v0.3.2/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
|
||||
github.com/sagernet/sing-quic v0.4.1-0.20250423030647-0eb05f373a76 h1:iwpCX6H3nZEOGUGwx0q5azcgYOA9f6v9YssihXoRKHk=
|
||||
@@ -146,6 +141,8 @@ github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2Wk
|
||||
github.com/sagernet/smux v1.5.34-mod.2/go.mod h1:0KW0+R+ycvA2INW4gbsd7BNyg+HEfLIAxa5N02/28Zc=
|
||||
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
|
||||
github.com/sagernet/utls v1.6.7/go.mod h1:Uua1TKO/FFuAhLr9rkaVnnrTmmiItzDjv1BUb2+ERwM=
|
||||
github.com/sagernet/wireguard-go v0.0.1-beta.7 h1:ltgBwYHfr+9Wz1eG59NiWnHrYEkDKHG7otNZvu85DXI=
|
||||
github.com/sagernet/wireguard-go v0.0.1-beta.7/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
@@ -164,14 +161,6 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tevino/abool/v2 v2.1.0 h1:7w+Vf9f/5gmKT4m4qkayb33/92M+Um45F2BkHOR+L/c=
|
||||
github.com/tevino/abool/v2 v2.1.0/go.mod h1:+Lmlqk6bHDWHqN1cbxqhwEAwMPXgc8I1SDEamtseuXY=
|
||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA=
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
|
||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||
@@ -183,7 +172,6 @@ github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvv
|
||||
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
@@ -214,7 +202,6 @@ golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
|
||||
@@ -14,5 +14,4 @@ func registerWireGuardOutbound(registry *outbound.Registry) {
|
||||
|
||||
func registerWireGuardEndpoint(registry *endpoint.Registry) {
|
||||
wireguard.RegisterEndpoint(registry)
|
||||
wireguard.RegisterWarpEndpoint(registry)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ type WireGuardEndpointOptions struct {
|
||||
Peers []WireGuardPeer `json:"peers,omitempty"`
|
||||
UDPTimeout badoption.Duration `json:"udp_timeout,omitempty"`
|
||||
Workers int `json:"workers,omitempty"`
|
||||
Amnezia *WireGuardAmnezia `json:"amnezia,omitempty"`
|
||||
DialerOptions
|
||||
}
|
||||
|
||||
@@ -30,22 +29,6 @@ type WireGuardPeer struct {
|
||||
Reserved []uint8 `json:"reserved,omitempty"`
|
||||
}
|
||||
|
||||
type WireGuardWarpEndpointOptions struct {
|
||||
System bool `json:"system,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
ListenPort uint16 `json:"listen_port,omitempty"`
|
||||
UDPTimeout badoption.Duration `json:"udp_timeout,omitempty"`
|
||||
Workers int `json:"workers,omitempty"`
|
||||
Amnezia *WireGuardAmnezia `json:"amnezia,omitempty"`
|
||||
Profile *WireGuardWarpProfile `json:"profile,omitempty"`
|
||||
DialerOptions
|
||||
}
|
||||
|
||||
type WireGuardWarpProfile struct {
|
||||
Detour string `json:"detour,omitempty"`
|
||||
Recreate bool `json:"recreate,omitempty"`
|
||||
}
|
||||
|
||||
type LegacyWireGuardOutboundOptions struct {
|
||||
DialerOptions
|
||||
SystemInterface bool `json:"system_interface,omitempty"`
|
||||
@@ -55,13 +38,12 @@ type LegacyWireGuardOutboundOptions struct {
|
||||
PrivateKey string `json:"private_key"`
|
||||
Peers []LegacyWireGuardPeer `json:"peers,omitempty"`
|
||||
ServerOptions
|
||||
PeerPublicKey string `json:"peer_public_key"`
|
||||
PreSharedKey string `json:"pre_shared_key,omitempty"`
|
||||
Reserved []uint8 `json:"reserved,omitempty"`
|
||||
Workers int `json:"workers,omitempty"`
|
||||
MTU uint32 `json:"mtu,omitempty"`
|
||||
Network NetworkList `json:"network,omitempty"`
|
||||
Amnezia *WireGuardAmnezia `json:"amnezia,omitempty"`
|
||||
PeerPublicKey string `json:"peer_public_key"`
|
||||
PreSharedKey string `json:"pre_shared_key,omitempty"`
|
||||
Reserved []uint8 `json:"reserved,omitempty"`
|
||||
Workers int `json:"workers,omitempty"`
|
||||
MTU uint32 `json:"mtu,omitempty"`
|
||||
Network NetworkList `json:"network,omitempty"`
|
||||
}
|
||||
|
||||
type LegacyWireGuardPeer struct {
|
||||
@@ -71,15 +53,3 @@ type LegacyWireGuardPeer struct {
|
||||
AllowedIPs badoption.Listable[netip.Prefix] `json:"allowed_ips,omitempty"`
|
||||
Reserved []uint8 `json:"reserved,omitempty"`
|
||||
}
|
||||
|
||||
type WireGuardAmnezia struct {
|
||||
JC int `json:"jc,omitempty"`
|
||||
JMin int `json:"jmin,omitempty"`
|
||||
JMax int `json:"jmax,omitempty"`
|
||||
S1 int `json:"s1,omitempty"`
|
||||
S2 int `json:"s2,omitempty"`
|
||||
H1 uint32 `json:"h1,omitempty"`
|
||||
H2 uint32 `json:"h2,omitempty"`
|
||||
H3 uint32 `json:"h3,omitempty"`
|
||||
H4 uint32 `json:"h4,omitempty"`
|
||||
}
|
||||
|
||||
@@ -214,7 +214,6 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
if !loaded {
|
||||
return nil, E.New("parse route_address_set: rule-set not found: ", routeAddressSet)
|
||||
}
|
||||
ruleSet.IncRef()
|
||||
inbound.routeRuleSet = append(inbound.routeRuleSet, ruleSet)
|
||||
}
|
||||
for _, routeExcludeAddressSet := range options.RouteExcludeAddressSet {
|
||||
@@ -222,7 +221,6 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
if !loaded {
|
||||
return nil, E.New("parse route_exclude_address_set: rule-set not found: ", routeExcludeAddressSet)
|
||||
}
|
||||
ruleSet.IncRef()
|
||||
inbound.routeExcludeRuleSet = append(inbound.routeExcludeRuleSet, ruleSet)
|
||||
}
|
||||
if options.AutoRedirect {
|
||||
@@ -312,7 +310,7 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
|
||||
if len(ipSets) == 0 {
|
||||
t.logger.Warn("route_address_set: no destination IP CIDR rules found in rule-set: ", routeRuleSet.Name())
|
||||
}
|
||||
routeRuleSet.DecRef()
|
||||
routeRuleSet.IncRef()
|
||||
t.routeAddressSet = append(t.routeAddressSet, ipSets...)
|
||||
if t.autoRedirect != nil {
|
||||
t.routeRuleSetCallback = append(t.routeRuleSetCallback, routeRuleSet.RegisterCallback(t.updateRouteAddressSet))
|
||||
@@ -324,7 +322,7 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
|
||||
if len(ipSets) == 0 {
|
||||
t.logger.Warn("route_address_set: no destination IP CIDR rules found in rule-set: ", routeExcludeRuleSet.Name())
|
||||
}
|
||||
routeExcludeRuleSet.DecRef()
|
||||
routeExcludeRuleSet.IncRef()
|
||||
t.routeExcludeAddressSet = append(t.routeExcludeAddressSet, ipSets...)
|
||||
if t.autoRedirect != nil {
|
||||
t.routeExcludeRuleSetCallback = append(t.routeExcludeRuleSetCallback, routeExcludeRuleSet.RegisterCallback(t.updateRouteAddressSet))
|
||||
|
||||
@@ -56,20 +56,6 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
} else {
|
||||
udpTimeout = C.UDPTimeout
|
||||
}
|
||||
var amnezia *wireguard.AmneziaOptions
|
||||
if options.Amnezia != nil {
|
||||
amnezia = &wireguard.AmneziaOptions{
|
||||
JC: options.Amnezia.JC,
|
||||
JMin: options.Amnezia.JMin,
|
||||
JMax: options.Amnezia.JMax,
|
||||
S1: options.Amnezia.S1,
|
||||
S2: options.Amnezia.S2,
|
||||
H1: options.Amnezia.H1,
|
||||
H2: options.Amnezia.H2,
|
||||
H3: options.Amnezia.H3,
|
||||
H4: options.Amnezia.H4,
|
||||
}
|
||||
}
|
||||
wgEndpoint, err := wireguard.NewEndpoint(wireguard.EndpointOptions{
|
||||
Context: ctx,
|
||||
Logger: logger,
|
||||
@@ -105,7 +91,6 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
}
|
||||
}),
|
||||
Workers: options.Workers,
|
||||
Amnezia: amnezia,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/adapter/endpoint"
|
||||
"github.com/sagernet/sing-box/common/cloudflare"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
||||
func RegisterWarpEndpoint(registry *endpoint.Registry) {
|
||||
endpoint.Register[option.WireGuardWarpEndpointOptions](registry, C.TypeWARP, NewWarpEndpoint)
|
||||
}
|
||||
|
||||
type WarpEndpoint struct {
|
||||
endpoint.Adapter
|
||||
endpoint adapter.Endpoint
|
||||
ctx context.Context
|
||||
router adapter.Router
|
||||
logger log.ContextLogger
|
||||
tag string
|
||||
options option.WireGuardWarpEndpointOptions
|
||||
}
|
||||
|
||||
func NewWarpEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.WireGuardWarpEndpointOptions) (adapter.Endpoint, error) {
|
||||
var dependencies []string
|
||||
if options.Detour != "" {
|
||||
dependencies = append(dependencies, options.Detour)
|
||||
}
|
||||
if options.Profile != nil {
|
||||
if options.Profile.Detour != "" {
|
||||
dependencies = append(dependencies, options.Profile.Detour)
|
||||
}
|
||||
}
|
||||
return &WarpEndpoint{
|
||||
Adapter: endpoint.NewAdapter(C.TypeWARP, tag, []string{N.NetworkTCP, N.NetworkUDP}, dependencies),
|
||||
ctx: ctx,
|
||||
router: router,
|
||||
logger: logger,
|
||||
tag: tag,
|
||||
options: options,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *WarpEndpoint) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStatePostStart {
|
||||
return nil
|
||||
}
|
||||
cacheFile := service.FromContext[adapter.CacheFile](w.ctx)
|
||||
var profile *cloudflare.CloudflareProfile
|
||||
var err error
|
||||
if !w.options.Profile.Recreate {
|
||||
if cacheFile != nil {
|
||||
savedProfile := cacheFile.LoadCloudflareProfile(w.tag)
|
||||
if savedProfile != nil {
|
||||
err := json.Unmarshal(savedProfile.Content, &profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if profile == nil {
|
||||
opts := make([]cloudflare.CloudflareApiOption, 0, 1)
|
||||
if w.options.Profile != nil {
|
||||
if w.options.Profile.Detour != "" {
|
||||
detour, ok := service.FromContext[adapter.OutboundManager](w.ctx).Outbound(w.options.Profile.Detour)
|
||||
if !ok {
|
||||
return E.New("outbound detour not found: ", w.options.Profile.Detour)
|
||||
}
|
||||
opts = append(opts, cloudflare.WithDialContext(func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return detour.DialContext(ctx, network, M.ParseSocksaddr(addr))
|
||||
}))
|
||||
}
|
||||
}
|
||||
api := cloudflare.NewCloudeflareApi(opts...)
|
||||
profile, err = api.CreateProfile(w.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cacheFile != nil {
|
||||
content, err := json.Marshal(profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cacheFile.SaveCloudflareProfile(w.tag, &adapter.SavedBinary{
|
||||
LastUpdated: time.Now(),
|
||||
Content: content,
|
||||
LastEtag: "",
|
||||
})
|
||||
}
|
||||
}
|
||||
peer := profile.Config.Peers[0]
|
||||
hostParts := strings.Split(peer.Endpoint.Host, ":")
|
||||
w.endpoint, err = NewEndpoint(
|
||||
w.ctx,
|
||||
w.router,
|
||||
w.logger,
|
||||
w.tag,
|
||||
option.WireGuardEndpointOptions{
|
||||
System: w.options.System,
|
||||
Name: w.options.Name,
|
||||
ListenPort: w.options.ListenPort,
|
||||
UDPTimeout: w.options.UDPTimeout,
|
||||
Workers: w.options.Workers,
|
||||
Amnezia: w.options.Amnezia,
|
||||
DialerOptions: w.options.DialerOptions,
|
||||
|
||||
Address: badoption.Listable[netip.Prefix]{
|
||||
netip.MustParsePrefix(profile.Config.Interface.Addresses.V4 + "/32"),
|
||||
netip.MustParsePrefix(profile.Config.Interface.Addresses.V6 + "/128"),
|
||||
},
|
||||
PrivateKey: profile.Config.PrivateKey,
|
||||
Peers: []option.WireGuardPeer{
|
||||
{
|
||||
Address: hostParts[0],
|
||||
Port: uint16(peer.Endpoint.Ports[rand.Intn(len(peer.Endpoint.Ports))]),
|
||||
PublicKey: peer.PublicKey,
|
||||
AllowedIPs: badoption.Listable[netip.Prefix]{
|
||||
netip.MustParsePrefix("0.0.0.0/0"),
|
||||
netip.MustParsePrefix("::/0"),
|
||||
},
|
||||
},
|
||||
},
|
||||
MTU: 1280,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.endpoint.Start(adapter.StartStateStart); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.endpoint.Start(adapter.StartStatePostStart); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WarpEndpoint) Close() error {
|
||||
if w.endpoint == nil {
|
||||
return E.New("endpoint not initialized")
|
||||
}
|
||||
return w.endpoint.Close()
|
||||
}
|
||||
|
||||
func (w *WarpEndpoint) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
if w.endpoint == nil {
|
||||
return nil, E.New("endpoint not initialized")
|
||||
}
|
||||
return w.endpoint.DialContext(ctx, network, destination)
|
||||
}
|
||||
|
||||
func (w *WarpEndpoint) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
if w.endpoint == nil {
|
||||
return nil, E.New("endpoint not initialized")
|
||||
}
|
||||
return w.endpoint.ListenPacket(ctx, destination)
|
||||
}
|
||||
@@ -74,20 +74,6 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
Reserved: options.Reserved,
|
||||
}}
|
||||
}
|
||||
var amnezia *wireguard.AmneziaOptions
|
||||
if options.Amnezia != nil {
|
||||
amnezia = &wireguard.AmneziaOptions{
|
||||
JC: options.Amnezia.JC,
|
||||
JMin: options.Amnezia.JMin,
|
||||
JMax: options.Amnezia.JMax,
|
||||
S1: options.Amnezia.S1,
|
||||
S2: options.Amnezia.S2,
|
||||
H1: options.Amnezia.H1,
|
||||
H2: options.Amnezia.H2,
|
||||
H3: options.Amnezia.H3,
|
||||
H4: options.Amnezia.H4,
|
||||
}
|
||||
}
|
||||
wgEndpoint, err := wireguard.NewEndpoint(wireguard.EndpointOptions{
|
||||
Context: ctx,
|
||||
Logger: logger,
|
||||
@@ -111,7 +97,6 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
},
|
||||
Peers: peers,
|
||||
Workers: options.Workers,
|
||||
Amnezia: amnezia,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -176,8 +176,6 @@ func (r *Router) RoutePacketConnectionEx(ctx context.Context, conn N.PacketConn,
|
||||
} else {
|
||||
r.logger.ErrorContext(ctx, err)
|
||||
}
|
||||
} else if onClose != nil {
|
||||
onClose(nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing/common"
|
||||
@@ -180,17 +179,6 @@ func (e *Endpoint) Start(resolve bool) error {
|
||||
wgDevice := device.NewDevice(e.options.Context, e.tunDevice, bind, logger, e.options.Workers)
|
||||
e.tunDevice.SetDevice(wgDevice)
|
||||
ipcConf := e.ipcConf
|
||||
if e.options.Amnezia != nil {
|
||||
ipcConf += "\njc=" + strconv.Itoa(e.options.Amnezia.JC) + "\n"
|
||||
ipcConf += "jmin=" + strconv.Itoa(e.options.Amnezia.JMin) + "\n"
|
||||
ipcConf += "jmax=" + strconv.Itoa(e.options.Amnezia.JMax) + "\n"
|
||||
ipcConf += "s1=" + strconv.Itoa(e.options.Amnezia.S1) + "\n"
|
||||
ipcConf += "s2=" + strconv.Itoa(e.options.Amnezia.S2) + "\n"
|
||||
ipcConf += "h1=" + strconv.FormatUint(uint64(e.options.Amnezia.H1), 10) + "\n"
|
||||
ipcConf += "h2=" + strconv.FormatUint(uint64(e.options.Amnezia.H2), 10) + "\n"
|
||||
ipcConf += "h3=" + strconv.FormatUint(uint64(e.options.Amnezia.H3), 10) + "\n"
|
||||
ipcConf += "h4=" + strconv.FormatUint(uint64(e.options.Amnezia.H4), 10)
|
||||
}
|
||||
for _, peer := range e.peers {
|
||||
ipcConf += peer.GenerateIpcLines()
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ type EndpointOptions struct {
|
||||
ResolvePeer func(domain string) (netip.Addr, error)
|
||||
Peers []PeerOptions
|
||||
Workers int
|
||||
Amnezia *AmneziaOptions
|
||||
}
|
||||
|
||||
type PeerOptions struct {
|
||||
@@ -38,15 +37,3 @@ type PeerOptions struct {
|
||||
PersistentKeepaliveInterval uint16
|
||||
Reserved []uint8
|
||||
}
|
||||
|
||||
type AmneziaOptions struct {
|
||||
JC int
|
||||
JMin int
|
||||
JMax int
|
||||
S1 int
|
||||
S2 int
|
||||
H1 uint32
|
||||
H2 uint32
|
||||
H3 uint32
|
||||
H4 uint32
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user