Closed zz5678 closed 1 year ago
这个格式需要问「世界」
这个格式需要问「世界」
就算暗网的世界也应该有个 url 吧?
这个格式是沿用世界 SagerNet 的,具体实现在 kyro 库中。我无法提供其中的实现细节。
我看了一眼代码,随手糊了一个python的生成:
def encode_sn_str(s: str) -> bytes:
if not s:
return b'\x81'
if len(s) == 1:
return b'\x82' + s.encode()
ret = s.encode()
ret = ret[:-1] + (ret[-1] | 0x80).to_bytes(1, 'little')
return ret
def p32(n: int):
return n.to_bytes(4, 'little')
def p8(n: int):
return n.to_bytes(1, 'little')
# https://github.com/MatsuriDayo/NekoBoxForAndroid/blob/main/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java
@dataclass(init=True, repr=True)
class SnBase:
def serlize(self) -> bytes:
ret = b''
for _, v in self.__dict__.items():
ret += self.obj_serlize(v)
return ret
@classmethod
def obj_serlize(cls, obj) -> bytes:
ret = b''
match type(obj):
case __builtins__.str:
ret += encode_sn_str(obj)
case __builtins__.bool:
ret += p8(int(obj))
case __builtins__.int:
ret += p32(obj)
case _:
if (isinstance(obj, SnBase)):
ret += obj.serlize()
return ret
@dataclass(init=True, repr=True)
class SnServer(SnBase):
server_address: str = ''
server_port: int = 0
@dataclass(init=True, repr=True)
class SnMeta(SnBase):
# abstract bean
extra_version: int = 1
name: str = ''
custom_outbound: str = ''
custom_config: str = ''
@dataclass(init=True, repr=True)
class Tls(SnBase):
sni: str = ''
alpn: str = ''
certificates: str = ''
allow_insecure: bool = False
utls_fingerprint: str = ''
reality_pubkey: str = ''
reality_short_id: str = ''
@dataclass(init=True, repr=True)
class Websocket(SnBase):
host: str = ''
path: str = ''
max_early_data: int = 0
early_data_header_name: str = ''
@dataclass(init=True, repr=True)
class V2ray(SnBase):
version: int = 0
server: SnServer = field(default_factory=SnServer)
uuid: str = ''
encryption: str = ''
transport_type: str = ''
transport: Any = None
tls: Optional[Tls] = None
# 1 packet 2: xudp
packet_encoding: int = 0
def serlize(self) -> bytes:
ret = b''
ret += self.obj_serlize(self.version)
ret += self.obj_serlize(self.server)
ret += self.obj_serlize(self.uuid)
ret += self.obj_serlize(self.encryption)
ret += self.obj_serlize(self.transport_type)
match self.transport_type:
case 'ws':
assert (isinstance(self.transport, Websocket))
ret += self.transport.serlize()
ret += self.obj_serlize('tls' if self.tls else 'none')
if self.tls:
ret += self.tls.serlize()
ret += self.obj_serlize(self.packet_encoding)
return ret
@dataclass(init=True, repr=True)
class Trojan(SnBase):
version: int = 2
v2ray: V2ray = field(default_factory=V2ray)
password: str = ''
sn_meta: SnMeta = field(default_factory=SnMeta)
def __str__(self) -> str:
print(self.serlize())
return f'sn://trojan?{base64.urlsafe_b64encode(zlib.compress(self.serlize())).decode()}'
v2ray = V2ray(server = SnServer('1.1.1.1', 443),
transport_type = 'ws',
transport = Websocket('abc', '/plusls', 2048, 'Sec-WebSocket-Protocol'),
tls = Tls('aa', 'bb', 'cc', True, 'chrome', 'd'))
trojan = Trojan(v2ray=v2ray, password='plusls', sn_meta = SnMeta(name='fuck', custom_outbound='{"a": 1}'))
print(trojan)
这个 sn://wg? 其后的编码方式到底是怎样的? 用NekoBox导出的 sn link 去掉头部 base64 无论那种都根本无法解码,无法逆向还原,通过下面提示源码只能看到去掉空格[ ],编码 base64而已,原始数据格式到底是什么?
比如 wireguard 的原始数据是这样的吗? ''' {name:CFWarp-A,type:wireguard,server:123.123.123.123,port:8854,ip:172.16.0.2,private-key:STH=,public-key:STH=,remote-dns-resolve:false,udp:true} '''
请给出原始规范文档
Originally posted by @arm64v8a in https://github.com/MatsuriDayo/NekoBoxForAndroid/issues/270#issuecomment-1669132449