mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-07-13 23:28:46 +00:00
Xray-core: Forbid unencrypted outbounds on public Internet for VLESS and Trojan; Remove "none/zero/plain" for VMess and Shadowsocks (#6303)
https://github.com/XTLS/Xray-core/pull/5640#issuecomment-4611416512 https://github.com/XTLS/Xray-core/pull/6303#issuecomment-4668055274 --------- Co-authored-by: Meow <197331664+Meo597@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
|||||||
|
package geodata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
var privateIPMatcher = sync.OnceValue(func() IPMatcher {
|
||||||
|
return common.Must2(IPReg.BuildIPMatcher(common.Must2(ParseIPRules([]string{
|
||||||
|
"0.0.0.0/8",
|
||||||
|
"10.0.0.0/8",
|
||||||
|
"100.64.0.0/10",
|
||||||
|
"127.0.0.0/8",
|
||||||
|
"169.254.0.0/16",
|
||||||
|
"172.16.0.0/12",
|
||||||
|
"192.0.0.0/24",
|
||||||
|
"192.0.2.0/24",
|
||||||
|
"192.88.99.0/24",
|
||||||
|
"192.168.0.0/16",
|
||||||
|
"198.18.0.0/15",
|
||||||
|
"198.51.100.0/24",
|
||||||
|
"203.0.113.0/24",
|
||||||
|
"224.0.0.0/3",
|
||||||
|
"::/127",
|
||||||
|
"fc00::/7",
|
||||||
|
"fe80::/10",
|
||||||
|
"ff00::/8",
|
||||||
|
}))))
|
||||||
|
})
|
||||||
|
|
||||||
|
func GetPrivateIPMatcher() IPMatcher { return privateIPMatcher() }
|
||||||
|
|
||||||
|
var privateDomainMatcher = sync.OnceValue(func() DomainMatcher {
|
||||||
|
return common.Must2(DomainReg.BuildDomainMatcher(common.Must2(ParseDomainRules([]string{
|
||||||
|
"lan",
|
||||||
|
"localdomain",
|
||||||
|
"example",
|
||||||
|
"invalid",
|
||||||
|
"localhost",
|
||||||
|
"test",
|
||||||
|
"local",
|
||||||
|
"home.arpa",
|
||||||
|
"internal",
|
||||||
|
"regexp:^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$", // Dotless domains
|
||||||
|
}, Domain_Domain))))
|
||||||
|
})
|
||||||
|
|
||||||
|
func GetPrivateDomainMatcher() DomainMatcher { return privateDomainMatcher() }
|
||||||
@@ -28,8 +28,6 @@ const (
|
|||||||
SecurityType_AUTO SecurityType = 2
|
SecurityType_AUTO SecurityType = 2
|
||||||
SecurityType_AES128_GCM SecurityType = 3
|
SecurityType_AES128_GCM SecurityType = 3
|
||||||
SecurityType_CHACHA20_POLY1305 SecurityType = 4
|
SecurityType_CHACHA20_POLY1305 SecurityType = 4
|
||||||
SecurityType_NONE SecurityType = 5 // [DEPRECATED 2023-06]
|
|
||||||
SecurityType_ZERO SecurityType = 6
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Enum value maps for SecurityType.
|
// Enum value maps for SecurityType.
|
||||||
@@ -39,16 +37,12 @@ var (
|
|||||||
2: "AUTO",
|
2: "AUTO",
|
||||||
3: "AES128_GCM",
|
3: "AES128_GCM",
|
||||||
4: "CHACHA20_POLY1305",
|
4: "CHACHA20_POLY1305",
|
||||||
5: "NONE",
|
|
||||||
6: "ZERO",
|
|
||||||
}
|
}
|
||||||
SecurityType_value = map[string]int32{
|
SecurityType_value = map[string]int32{
|
||||||
"UNKNOWN": 0,
|
"UNKNOWN": 0,
|
||||||
"AUTO": 2,
|
"AUTO": 2,
|
||||||
"AES128_GCM": 3,
|
"AES128_GCM": 3,
|
||||||
"CHACHA20_POLY1305": 4,
|
"CHACHA20_POLY1305": 4,
|
||||||
"NONE": 5,
|
|
||||||
"ZERO": 6,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -129,15 +123,13 @@ const file_common_protocol_headers_proto_rawDesc = "" +
|
|||||||
"\n" +
|
"\n" +
|
||||||
"\x1dcommon/protocol/headers.proto\x12\x14xray.common.protocol\"H\n" +
|
"\x1dcommon/protocol/headers.proto\x12\x14xray.common.protocol\"H\n" +
|
||||||
"\x0eSecurityConfig\x126\n" +
|
"\x0eSecurityConfig\x126\n" +
|
||||||
"\x04type\x18\x01 \x01(\x0e2\".xray.common.protocol.SecurityTypeR\x04type*`\n" +
|
"\x04type\x18\x01 \x01(\x0e2\".xray.common.protocol.SecurityTypeR\x04type*L\n" +
|
||||||
"\fSecurityType\x12\v\n" +
|
"\fSecurityType\x12\v\n" +
|
||||||
"\aUNKNOWN\x10\x00\x12\b\n" +
|
"\aUNKNOWN\x10\x00\x12\b\n" +
|
||||||
"\x04AUTO\x10\x02\x12\x0e\n" +
|
"\x04AUTO\x10\x02\x12\x0e\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"AES128_GCM\x10\x03\x12\x15\n" +
|
"AES128_GCM\x10\x03\x12\x15\n" +
|
||||||
"\x11CHACHA20_POLY1305\x10\x04\x12\b\n" +
|
"\x11CHACHA20_POLY1305\x10\x04B^\n" +
|
||||||
"\x04NONE\x10\x05\x12\b\n" +
|
|
||||||
"\x04ZERO\x10\x06B^\n" +
|
|
||||||
"\x18com.xray.common.protocolP\x01Z)github.com/xtls/xray-core/common/protocol\xaa\x02\x14Xray.Common.Protocolb\x06proto3"
|
"\x18com.xray.common.protocolP\x01Z)github.com/xtls/xray-core/common/protocol\xaa\x02\x14Xray.Common.Protocolb\x06proto3"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ enum SecurityType {
|
|||||||
AUTO = 2;
|
AUTO = 2;
|
||||||
AES128_GCM = 3;
|
AES128_GCM = 3;
|
||||||
CHACHA20_POLY1305 = 4;
|
CHACHA20_POLY1305 = 4;
|
||||||
NONE = 5; // [DEPRECATED 2023-06]
|
|
||||||
ZERO = 6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message SecurityConfig {
|
message SecurityConfig {
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ func cipherFromString(c string) shadowsocks.CipherType {
|
|||||||
return shadowsocks.CipherType_CHACHA20_POLY1305
|
return shadowsocks.CipherType_CHACHA20_POLY1305
|
||||||
case "xchacha20-poly1305", "aead_xchacha20_poly1305", "xchacha20-ietf-poly1305":
|
case "xchacha20-poly1305", "aead_xchacha20_poly1305", "xchacha20-ietf-poly1305":
|
||||||
return shadowsocks.CipherType_XCHACHA20_POLY1305
|
return shadowsocks.CipherType_XCHACHA20_POLY1305
|
||||||
case "none", "plain":
|
|
||||||
return shadowsocks.CipherType_NONE
|
|
||||||
default:
|
default:
|
||||||
return shadowsocks.CipherType_UNKNOWN
|
return shadowsocks.CipherType_UNKNOWN
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,6 @@ func (a *VMessAccount) Build() *vmess.Account {
|
|||||||
st = protocol.SecurityType_CHACHA20_POLY1305
|
st = protocol.SecurityType_CHACHA20_POLY1305
|
||||||
case "auto":
|
case "auto":
|
||||||
st = protocol.SecurityType_AUTO
|
st = protocol.SecurityType_AUTO
|
||||||
case "none":
|
|
||||||
st = protocol.SecurityType_NONE
|
|
||||||
case "zero":
|
|
||||||
st = protocol.SecurityType_ZERO
|
|
||||||
default:
|
default:
|
||||||
st = protocol.SecurityType_AUTO
|
st = protocol.SecurityType_AUTO
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -230,6 +230,40 @@ func (c *OutboundDetourConfig) checkChainProxyConfig() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func requiresTransportSecurity(address *Address) bool {
|
||||||
|
if address == nil || address.Address == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if address.Family().IsIP() {
|
||||||
|
return !geodata.GetPrivateIPMatcher().Match(address.IP())
|
||||||
|
}
|
||||||
|
domain := strings.TrimSuffix(strings.ToLower(address.Domain()), ".")
|
||||||
|
return !geodata.GetPrivateDomainMatcher().MatchAny(domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateOutboundTransportSecurity(rawConfig interface{}, senderSettings *proxyman.SenderConfig) error {
|
||||||
|
if senderSettings.StreamSettings != nil && senderSettings.StreamSettings.GetSecurityType() != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if vlessCfg, ok := rawConfig.(*VLessOutboundConfig); ok {
|
||||||
|
if vlessCfg.Encryption != "" && vlessCfg.Encryption != "none" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if requiresTransportSecurity(vlessCfg.Address) {
|
||||||
|
return errors.New("vless without TLS or other encryption is prohibited unless the server address is a private IP or domain")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tjCfg, ok := rawConfig.(*TrojanClientConfig); ok {
|
||||||
|
if requiresTransportSecurity(tjCfg.Address) {
|
||||||
|
return errors.New("trojan without TLS is prohibited unless the server address is a private IP or domain")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Build implements Buildable.
|
// Build implements Buildable.
|
||||||
func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
||||||
senderSettings := &proxyman.SenderConfig{}
|
senderSettings := &proxyman.SenderConfig{}
|
||||||
@@ -323,6 +357,9 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to load outbound detour config for protocol ", c.Protocol).Base(err)
|
return nil, errors.New("failed to load outbound detour config for protocol ", c.Protocol).Base(err)
|
||||||
}
|
}
|
||||||
|
if err := validateOutboundTransportSecurity(rawConfig, senderSettings); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
ts, err := rawConfig.(Buildable).Build()
|
ts, err := rawConfig.(Buildable).Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to build outbound handler for protocol ", c.Protocol).Base(err)
|
return nil, errors.New("failed to build outbound handler for protocol ", c.Protocol).Base(err)
|
||||||
|
|||||||
@@ -62,26 +62,7 @@ func init() {
|
|||||||
defaultBlockPrivateRule = &FinalRule{
|
defaultBlockPrivateRule = &FinalRule{
|
||||||
action: RuleAction_Block,
|
action: RuleAction_Block,
|
||||||
network: allNetworks,
|
network: allNetworks,
|
||||||
ip: common.Must2(geodata.IPReg.BuildIPMatcher(common.Must2(geodata.ParseIPRules([]string{
|
ip: geodata.GetPrivateIPMatcher(),
|
||||||
"0.0.0.0/8",
|
|
||||||
"10.0.0.0/8",
|
|
||||||
"100.64.0.0/10",
|
|
||||||
"127.0.0.0/8",
|
|
||||||
"169.254.0.0/16",
|
|
||||||
"172.16.0.0/12",
|
|
||||||
"192.0.0.0/24",
|
|
||||||
"192.0.2.0/24",
|
|
||||||
"192.88.99.0/24",
|
|
||||||
"192.168.0.0/16",
|
|
||||||
"198.18.0.0/15",
|
|
||||||
"198.51.100.0/24",
|
|
||||||
"203.0.113.0/24",
|
|
||||||
"224.0.0.0/3",
|
|
||||||
"::/127",
|
|
||||||
"fc00::/7",
|
|
||||||
"fe80::/10",
|
|
||||||
"ff00::/8",
|
|
||||||
})))),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultBlockAllRule = &FinalRule{
|
defaultBlockAllRule = &FinalRule{
|
||||||
|
|||||||
@@ -85,8 +85,6 @@ func (a *Account) getCipher() (Cipher, error) {
|
|||||||
IVBytes: 32,
|
IVBytes: 32,
|
||||||
AEADAuthCreator: createXChaCha20Poly1305,
|
AEADAuthCreator: createXChaCha20Poly1305,
|
||||||
}, nil
|
}, nil
|
||||||
case CipherType_NONE:
|
|
||||||
return NoneCipher{}, nil
|
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("Unsupported cipher.")
|
return nil, errors.New("Unsupported cipher.")
|
||||||
}
|
}
|
||||||
@@ -186,30 +184,6 @@ func (c *AEADCipher) DecodePacket(key []byte, b *buf.Buffer) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type NoneCipher struct{}
|
|
||||||
|
|
||||||
func (NoneCipher) KeySize() int32 { return 0 }
|
|
||||||
func (NoneCipher) IVSize() int32 { return 0 }
|
|
||||||
func (NoneCipher) IsAEAD() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NoneCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
|
|
||||||
return buf.NewReader(reader), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NoneCipher) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
|
|
||||||
return buf.NewWriter(writer), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NoneCipher) EncodePacket(key []byte, b *buf.Buffer) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NoneCipher) DecodePacket(key []byte, b *buf.Buffer) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func passwordToCipherKey(password []byte, keySize int32) []byte {
|
func passwordToCipherKey(password []byte, keySize int32) []byte {
|
||||||
key := make([]byte, 0, keySize)
|
key := make([]byte, 0, keySize)
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ const (
|
|||||||
CipherType_AES_256_GCM CipherType = 6
|
CipherType_AES_256_GCM CipherType = 6
|
||||||
CipherType_CHACHA20_POLY1305 CipherType = 7
|
CipherType_CHACHA20_POLY1305 CipherType = 7
|
||||||
CipherType_XCHACHA20_POLY1305 CipherType = 8
|
CipherType_XCHACHA20_POLY1305 CipherType = 8
|
||||||
CipherType_NONE CipherType = 9
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Enum value maps for CipherType.
|
// Enum value maps for CipherType.
|
||||||
@@ -42,7 +41,6 @@ var (
|
|||||||
6: "AES_256_GCM",
|
6: "AES_256_GCM",
|
||||||
7: "CHACHA20_POLY1305",
|
7: "CHACHA20_POLY1305",
|
||||||
8: "XCHACHA20_POLY1305",
|
8: "XCHACHA20_POLY1305",
|
||||||
9: "NONE",
|
|
||||||
}
|
}
|
||||||
CipherType_value = map[string]int32{
|
CipherType_value = map[string]int32{
|
||||||
"UNKNOWN": 0,
|
"UNKNOWN": 0,
|
||||||
@@ -50,7 +48,6 @@ var (
|
|||||||
"AES_256_GCM": 6,
|
"AES_256_GCM": 6,
|
||||||
"CHACHA20_POLY1305": 7,
|
"CHACHA20_POLY1305": 7,
|
||||||
"XCHACHA20_POLY1305": 8,
|
"XCHACHA20_POLY1305": 8,
|
||||||
"NONE": 9,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -251,15 +248,14 @@ const file_proxy_shadowsocks_config_proto_rawDesc = "" +
|
|||||||
"\x05users\x18\x01 \x03(\v2\x1a.xray.common.protocol.UserR\x05users\x122\n" +
|
"\x05users\x18\x01 \x03(\v2\x1a.xray.common.protocol.UserR\x05users\x122\n" +
|
||||||
"\anetwork\x18\x02 \x03(\x0e2\x18.xray.common.net.NetworkR\anetwork\"L\n" +
|
"\anetwork\x18\x02 \x03(\x0e2\x18.xray.common.net.NetworkR\anetwork\"L\n" +
|
||||||
"\fClientConfig\x12<\n" +
|
"\fClientConfig\x12<\n" +
|
||||||
"\x06server\x18\x01 \x01(\v2$.xray.common.protocol.ServerEndpointR\x06server*t\n" +
|
"\x06server\x18\x01 \x01(\v2$.xray.common.protocol.ServerEndpointR\x06server*j\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"CipherType\x12\v\n" +
|
"CipherType\x12\v\n" +
|
||||||
"\aUNKNOWN\x10\x00\x12\x0f\n" +
|
"\aUNKNOWN\x10\x00\x12\x0f\n" +
|
||||||
"\vAES_128_GCM\x10\x05\x12\x0f\n" +
|
"\vAES_128_GCM\x10\x05\x12\x0f\n" +
|
||||||
"\vAES_256_GCM\x10\x06\x12\x15\n" +
|
"\vAES_256_GCM\x10\x06\x12\x15\n" +
|
||||||
"\x11CHACHA20_POLY1305\x10\a\x12\x16\n" +
|
"\x11CHACHA20_POLY1305\x10\a\x12\x16\n" +
|
||||||
"\x12XCHACHA20_POLY1305\x10\b\x12\b\n" +
|
"\x12XCHACHA20_POLY1305\x10\bBd\n" +
|
||||||
"\x04NONE\x10\tBd\n" +
|
|
||||||
"\x1acom.xray.proxy.shadowsocksP\x01Z+github.com/xtls/xray-core/proxy/shadowsocks\xaa\x02\x16Xray.Proxy.Shadowsocksb\x06proto3"
|
"\x1acom.xray.proxy.shadowsocksP\x01Z+github.com/xtls/xray-core/proxy/shadowsocks\xaa\x02\x16Xray.Proxy.Shadowsocksb\x06proto3"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ enum CipherType {
|
|||||||
AES_256_GCM = 6;
|
AES_256_GCM = 6;
|
||||||
CHACHA20_POLY1305 = 7;
|
CHACHA20_POLY1305 = 7;
|
||||||
XCHACHA20_POLY1305 = 8;
|
XCHACHA20_POLY1305 = 8;
|
||||||
NONE = 9;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message ServerConfig {
|
message ServerConfig {
|
||||||
|
|||||||
@@ -38,19 +38,6 @@ func TestUDPEncodingDecoding(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Version: Version,
|
|
||||||
Command: protocol.RequestCommandUDP,
|
|
||||||
Address: net.LocalHostIP,
|
|
||||||
Port: 1234,
|
|
||||||
User: &protocol.MemoryUser{
|
|
||||||
Email: "love@example.com",
|
|
||||||
Account: toAccount(&Account{
|
|
||||||
Password: "123",
|
|
||||||
CipherType: CipherType_NONE,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, request := range testRequests {
|
for _, request := range testRequests {
|
||||||
@@ -80,10 +67,6 @@ func TestUDPDecodingWithPayloadTooShort(t *testing.T) {
|
|||||||
Password: "password",
|
Password: "password",
|
||||||
CipherType: CipherType_AES_128_GCM,
|
CipherType: CipherType_AES_128_GCM,
|
||||||
}),
|
}),
|
||||||
toAccount(&Account{
|
|
||||||
Password: "password",
|
|
||||||
CipherType: CipherType_NONE,
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, account := range testAccounts {
|
for _, account := range testAccounts {
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ func (v *Validator) Get(bs []byte, command protocol.RequestCommand) (u *protocol
|
|||||||
} else {
|
} else {
|
||||||
u = user
|
u = user
|
||||||
ivLen = user.Account.(*MemoryAccount).Cipher.IVSize()
|
ivLen = user.Account.(*MemoryAccount).Cipher.IVSize()
|
||||||
// err = user.Account.(*MemoryAccount).CheckIV(bs[:ivLen]) // The IV size of None Cipher is 0.
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,27 +17,6 @@ func Authenticate(b []byte) uint32 {
|
|||||||
return fnv1hash.Sum32()
|
return fnv1hash.Sum32()
|
||||||
}
|
}
|
||||||
|
|
||||||
// [DEPRECATED 2023-06]
|
|
||||||
type NoOpAuthenticator struct{}
|
|
||||||
|
|
||||||
func (NoOpAuthenticator) NonceSize() int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NoOpAuthenticator) Overhead() int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Seal implements AEAD.Seal().
|
|
||||||
func (NoOpAuthenticator) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
|
||||||
return append(dst[:0], plaintext...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open implements AEAD.Open().
|
|
||||||
func (NoOpAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
|
||||||
return append(dst[:0], ciphertext...), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateChacha20Poly1305Key generates a 32-byte key from a given 16-byte array.
|
// GenerateChacha20Poly1305Key generates a 32-byte key from a given 16-byte array.
|
||||||
func GenerateChacha20Poly1305Key(b []byte) []byte {
|
func GenerateChacha20Poly1305Key(b []byte) []byte {
|
||||||
key := make([]byte, 32)
|
key := make([]byte, 32)
|
||||||
|
|||||||
@@ -116,20 +116,6 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch request.Security {
|
switch request.Security {
|
||||||
case protocol.SecurityType_NONE:
|
|
||||||
if request.Option.Has(protocol.RequestOptionChunkStream) {
|
|
||||||
if request.Command.TransferType() == protocol.TransferTypeStream {
|
|
||||||
return crypto.NewChunkStreamWriter(sizeParser, writer), nil
|
|
||||||
}
|
|
||||||
auth := &crypto.AEADAuthenticator{
|
|
||||||
AEAD: new(NoOpAuthenticator),
|
|
||||||
NonceGenerator: crypto.GenerateEmptyBytes(),
|
|
||||||
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
|
||||||
}
|
|
||||||
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, protocol.TransferTypePacket, padding), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.NewWriter(writer), nil
|
|
||||||
case protocol.SecurityType_AES128_GCM:
|
case protocol.SecurityType_AES128_GCM:
|
||||||
aead := crypto.NewAesGcm(c.requestBodyKey[:])
|
aead := crypto.NewAesGcm(c.requestBodyKey[:])
|
||||||
auth := &crypto.AEADAuthenticator{
|
auth := &crypto.AEADAuthenticator{
|
||||||
@@ -267,22 +253,6 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch request.Security {
|
switch request.Security {
|
||||||
case protocol.SecurityType_NONE:
|
|
||||||
if request.Option.Has(protocol.RequestOptionChunkStream) {
|
|
||||||
if request.Command.TransferType() == protocol.TransferTypeStream {
|
|
||||||
return crypto.NewChunkStreamReader(sizeParser, reader), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
auth := &crypto.AEADAuthenticator{
|
|
||||||
AEAD: new(NoOpAuthenticator),
|
|
||||||
NonceGenerator: crypto.GenerateEmptyBytes(),
|
|
||||||
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
|
||||||
}
|
|
||||||
|
|
||||||
return crypto.NewAuthenticationReader(auth, sizeParser, reader, protocol.TransferTypePacket, padding), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.NewReader(reader), nil
|
|
||||||
case protocol.SecurityType_AES128_GCM:
|
case protocol.SecurityType_AES128_GCM:
|
||||||
aead := crypto.NewAesGcm(c.responseBodyKey[:])
|
aead := crypto.NewAesGcm(c.responseBodyKey[:])
|
||||||
|
|
||||||
|
|||||||
@@ -262,21 +262,6 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch request.Security {
|
switch request.Security {
|
||||||
case protocol.SecurityType_NONE:
|
|
||||||
if request.Option.Has(protocol.RequestOptionChunkStream) {
|
|
||||||
if request.Command.TransferType() == protocol.TransferTypeStream {
|
|
||||||
return crypto.NewChunkStreamReader(sizeParser, reader), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
auth := &crypto.AEADAuthenticator{
|
|
||||||
AEAD: new(NoOpAuthenticator),
|
|
||||||
NonceGenerator: crypto.GenerateEmptyBytes(),
|
|
||||||
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
|
||||||
}
|
|
||||||
return crypto.NewAuthenticationReader(auth, sizeParser, reader, protocol.TransferTypePacket, padding), nil
|
|
||||||
}
|
|
||||||
return buf.NewReader(reader), nil
|
|
||||||
|
|
||||||
case protocol.SecurityType_AES128_GCM:
|
case protocol.SecurityType_AES128_GCM:
|
||||||
aead := crypto.NewAesGcm(s.requestBodyKey[:])
|
aead := crypto.NewAesGcm(s.requestBodyKey[:])
|
||||||
auth := &crypto.AEADAuthenticator{
|
auth := &crypto.AEADAuthenticator{
|
||||||
@@ -384,21 +369,6 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch request.Security {
|
switch request.Security {
|
||||||
case protocol.SecurityType_NONE:
|
|
||||||
if request.Option.Has(protocol.RequestOptionChunkStream) {
|
|
||||||
if request.Command.TransferType() == protocol.TransferTypeStream {
|
|
||||||
return crypto.NewChunkStreamWriter(sizeParser, writer), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
auth := &crypto.AEADAuthenticator{
|
|
||||||
AEAD: new(NoOpAuthenticator),
|
|
||||||
NonceGenerator: crypto.GenerateEmptyBytes(),
|
|
||||||
AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
|
|
||||||
}
|
|
||||||
return crypto.NewAuthenticationWriter(auth, sizeParser, writer, protocol.TransferTypePacket, padding), nil
|
|
||||||
}
|
|
||||||
return buf.NewWriter(writer), nil
|
|
||||||
|
|
||||||
case protocol.SecurityType_AES128_GCM:
|
case protocol.SecurityType_AES128_GCM:
|
||||||
aead := crypto.NewAesGcm(s.responseBodyKey[:])
|
aead := crypto.NewAesGcm(s.responseBodyKey[:])
|
||||||
auth := &crypto.AEADAuthenticator{
|
auth := &crypto.AEADAuthenticator{
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
account := request.User.Account.(*vmess.MemoryAccount)
|
account := request.User.Account.(*vmess.MemoryAccount)
|
||||||
request.Security = account.Security
|
request.Security = account.Security
|
||||||
|
|
||||||
if request.Security == protocol.SecurityType_AES128_GCM || request.Security == protocol.SecurityType_NONE || request.Security == protocol.SecurityType_CHACHA20_POLY1305 {
|
if request.Security == protocol.SecurityType_AES128_GCM || request.Security == protocol.SecurityType_CHACHA20_POLY1305 {
|
||||||
request.Option.Set(protocol.RequestOptionChunkMasking)
|
request.Option.Set(protocol.RequestOptionChunkMasking)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,12 +113,6 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
request.Option.Set(protocol.RequestOptionGlobalPadding)
|
request.Option.Set(protocol.RequestOptionGlobalPadding)
|
||||||
}
|
}
|
||||||
|
|
||||||
if request.Security == protocol.SecurityType_ZERO {
|
|
||||||
request.Security = protocol.SecurityType_NONE
|
|
||||||
request.Option.Clear(protocol.RequestOptionChunkStream)
|
|
||||||
request.Option.Clear(protocol.RequestOptionChunkMasking)
|
|
||||||
}
|
|
||||||
|
|
||||||
if account.AuthenticatedLengthExperiment {
|
if account.AuthenticatedLengthExperiment {
|
||||||
request.Option.Set(protocol.RequestOptionAuthenticatedLength)
|
request.Option.Set(protocol.RequestOptionAuthenticatedLength)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -390,88 +390,3 @@ func TestShadowsocksAES128GCMUDPMux(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShadowsocksNone(t *testing.T) {
|
|
||||||
tcpServer := tcp.Server{
|
|
||||||
MsgProcessor: xor,
|
|
||||||
}
|
|
||||||
dest, err := tcpServer.Start()
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
defer tcpServer.Close()
|
|
||||||
|
|
||||||
account := serial.ToTypedMessage(&shadowsocks.Account{
|
|
||||||
Password: "shadowsocks-password",
|
|
||||||
CipherType: shadowsocks.CipherType_NONE,
|
|
||||||
})
|
|
||||||
|
|
||||||
serverPort := tcp.PickPort()
|
|
||||||
serverConfig := &core.Config{
|
|
||||||
Inbound: []*core.InboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
|
||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{
|
|
||||||
Users: []*protocol.User{{
|
|
||||||
Account: account,
|
|
||||||
Level: 1,
|
|
||||||
}},
|
|
||||||
Network: []net.Network{net.Network_TCP},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
|
||||||
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
clientPort := tcp.PickPort()
|
|
||||||
clientConfig := &core.Config{
|
|
||||||
Inbound: []*core.InboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
|
|
||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
|
||||||
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
|
||||||
RewritePort: uint32(dest.Port),
|
|
||||||
AllowedNetworks: []net.Network{net.Network_TCP},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{
|
|
||||||
Server: &protocol.ServerEndpoint{
|
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
Port: uint32(serverPort),
|
|
||||||
User: &protocol.User{
|
|
||||||
Account: account,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
|
|
||||||
common.Must(err)
|
|
||||||
|
|
||||||
defer CloseAllServers(servers)
|
|
||||||
|
|
||||||
var errGroup errgroup.Group
|
|
||||||
for range 3 {
|
|
||||||
errGroup.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := errGroup.Wait(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -423,103 +423,6 @@ func TestVMessChacha20(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVMessNone(t *testing.T) {
|
|
||||||
tcpServer := tcp.Server{
|
|
||||||
MsgProcessor: xor,
|
|
||||||
}
|
|
||||||
dest, err := tcpServer.Start()
|
|
||||||
common.Must(err)
|
|
||||||
defer tcpServer.Close()
|
|
||||||
|
|
||||||
userID := protocol.NewID(uuid.New())
|
|
||||||
serverPort := tcp.PickPort()
|
|
||||||
serverConfig := &core.Config{
|
|
||||||
App: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(&log.Config{
|
|
||||||
ErrorLogLevel: clog.Severity_Debug,
|
|
||||||
ErrorLogType: log.LogType_Console,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
Inbound: []*core.InboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
|
||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
|
||||||
User: []*protocol.User{
|
|
||||||
{
|
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
|
||||||
Id: userID.String(),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
|
||||||
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
clientPort := tcp.PickPort()
|
|
||||||
clientConfig := &core.Config{
|
|
||||||
App: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(&log.Config{
|
|
||||||
ErrorLogLevel: clog.Severity_Debug,
|
|
||||||
ErrorLogType: log.LogType_Console,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
Inbound: []*core.InboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
|
|
||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
|
||||||
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
|
||||||
RewritePort: uint32(dest.Port),
|
|
||||||
AllowedNetworks: []net.Network{net.Network_TCP},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
|
||||||
Receiver: &protocol.ServerEndpoint{
|
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
Port: uint32(serverPort),
|
|
||||||
User: &protocol.User{
|
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
|
||||||
Id: userID.String(),
|
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
|
||||||
Type: protocol.SecurityType_NONE,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
|
|
||||||
common.Must(err)
|
|
||||||
defer CloseAllServers(servers)
|
|
||||||
|
|
||||||
var errg errgroup.Group
|
|
||||||
for range 3 {
|
|
||||||
errg.Go(testTCPConn(clientPort, 1024*1024, time.Second*30))
|
|
||||||
}
|
|
||||||
if err := errg.Wait(); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVMessKCP(t *testing.T) {
|
func TestVMessKCP(t *testing.T) {
|
||||||
tcpServer := tcp.Server{
|
tcpServer := tcp.Server{
|
||||||
MsgProcessor: xor,
|
MsgProcessor: xor,
|
||||||
@@ -970,103 +873,6 @@ func TestVMessGCMMuxUDP(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVMessZero(t *testing.T) {
|
|
||||||
tcpServer := tcp.Server{
|
|
||||||
MsgProcessor: xor,
|
|
||||||
}
|
|
||||||
dest, err := tcpServer.Start()
|
|
||||||
common.Must(err)
|
|
||||||
defer tcpServer.Close()
|
|
||||||
|
|
||||||
userID := protocol.NewID(uuid.New())
|
|
||||||
serverPort := tcp.PickPort()
|
|
||||||
serverConfig := &core.Config{
|
|
||||||
App: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(&log.Config{
|
|
||||||
ErrorLogLevel: clog.Severity_Debug,
|
|
||||||
ErrorLogType: log.LogType_Console,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
Inbound: []*core.InboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
|
||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
|
||||||
User: []*protocol.User{
|
|
||||||
{
|
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
|
||||||
Id: userID.String(),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
|
||||||
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
clientPort := tcp.PickPort()
|
|
||||||
clientConfig := &core.Config{
|
|
||||||
App: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(&log.Config{
|
|
||||||
ErrorLogLevel: clog.Severity_Debug,
|
|
||||||
ErrorLogType: log.LogType_Console,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
Inbound: []*core.InboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
|
|
||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
|
||||||
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
|
||||||
RewritePort: uint32(dest.Port),
|
|
||||||
AllowedNetworks: []net.Network{net.Network_TCP},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
|
||||||
Receiver: &protocol.ServerEndpoint{
|
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
Port: uint32(serverPort),
|
|
||||||
User: &protocol.User{
|
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
|
||||||
Id: userID.String(),
|
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
|
||||||
Type: protocol.SecurityType_ZERO,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
|
|
||||||
common.Must(err)
|
|
||||||
defer CloseAllServers(servers)
|
|
||||||
|
|
||||||
var errg errgroup.Group
|
|
||||||
for range 3 {
|
|
||||||
errg.Go(testTCPConn(clientPort, 1024*1024, time.Second*30))
|
|
||||||
}
|
|
||||||
if err := errg.Wait(); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVMessGCMLengthAuth(t *testing.T) {
|
func TestVMessGCMLengthAuth(t *testing.T) {
|
||||||
tcpServer := tcp.Server{
|
tcpServer := tcp.Server{
|
||||||
MsgProcessor: xor,
|
MsgProcessor: xor,
|
||||||
|
|||||||
Reference in New Issue
Block a user