sublinker / node /trojan.go
YimoEx
init
bb9df9e
package node
import (
"fmt"
"net/url"
"strconv"
"strings"
)
type Trojan struct {
Password string `json:"password"`
Hostname string `json:"hostname"`
Port int `json:"port"`
Query TrojanQuery `json:"query,omitempty"`
Name string `json:"name"`
Type string `json:"type"`
}
type TrojanQuery struct {
Peer string `json:"peer,omitempty"`
Type string `json:"type,omitempty"`
Path string `json:"path,omitempty"`
Security string `json:"security,omitempty"`
Fp string `json:"fp,omitempty"`
AllowInsecure int `json:"allowInsecure,omitempty"`
Alpn []string `json:"alpn,omitempty"`
Sni string `json:"sni,omitempty"`
Host string `json:"host,omitempty"`
Flow string `json:"flow,omitempty"`
}
// 开发者测试
func CallTrojan() {
trojan := Trojan{
Password: "4cf3ca26cf114871b3d186a361a3de3",
Hostname: "baidu.com",
Port: 443,
Query: TrojanQuery{
Peer: "",
Type: "tcp",
Path: "",
Security: "tls",
Fp: "",
AllowInsecure: 0,
Alpn: []string{"h2", "http/1.1"},
Sni: "baidu.com",
Host: "",
Flow: "",
},
}
fmt.Println(EncodeTrojanURL(trojan))
}
// trojan 编码
func EncodeTrojanURL(t Trojan) string {
/*
trojan://password@hostname:port?peer=example.com&allowInsecure=0&sni=example.com
*/
u := url.URL{
Scheme: "trojan",
User: url.User(t.Password),
Host: fmt.Sprintf("%s:%d", t.Hostname, t.Port),
}
q := u.Query()
q.Set("peer", t.Query.Peer)
q.Set("allowInsecure", fmt.Sprintf("%d", t.Query.AllowInsecure))
q.Set("sni", t.Query.Sni)
q.Set("type", t.Query.Type)
q.Set("path", t.Query.Path)
q.Set("security", t.Query.Security)
q.Set("fp", t.Query.Fp)
// q.Set("alpn", t.Query.Alpn)
q.Set("host", t.Query.Host)
q.Set("flow", t.Query.Flow)
// 检查query是否有空值,有的话删除
for k, v := range q {
if v[0] == "" {
delete(q, k)
// fmt.Printf("k: %v, v: %v\n", k, v)
}
}
// 如果没有设置name,则使用hostname:port
if t.Name == "" {
t.Name = t.Hostname + ":" + strconv.Itoa(t.Port)
}
u.Fragment = t.Name
u.RawQuery = q.Encode()
return u.String()
}
// trojan 解码
func DecodeTrojanURL(s string) (Trojan, error) {
/*
trojan://password@hostname:port?peer=example.com&allowInsecure=0&sni=example.com
*/
u, err := url.Parse(s)
if err != nil {
return Trojan{}, fmt.Errorf("url格式化失败:%s", s)
}
if u.Scheme != "trojan" {
return Trojan{}, fmt.Errorf("非trojan协议: %s", s)
}
password := u.User.Username()
hostname := u.Hostname()
port, _ := strconv.Atoi(u.Port())
peer := u.Query().Get("peer")
allowInsecure := u.Query().Get("allowInsecure")
sni := u.Query().Get("sni")
types := u.Query().Get("type")
path := u.Query().Get("path")
security := u.Query().Get("security")
fp := u.Query().Get("fp")
alpns := u.Query().Get("alpn")
alpn := strings.Split(alpns, ",")
if alpns == "" {
alpn = nil
}
host := u.Query().Get("host")
flow := u.Query().Get("flow")
name := u.Fragment
// 如果没有设置name,则使用hostname:port
if name == "" {
name = hostname + ":" + u.Port()
}
if CheckEnvironment() {
fmt.Println("password:", password)
fmt.Println("password:", u.User.Username())
fmt.Println("hostname:", hostname)
fmt.Println("port:", port)
fmt.Println("peer:", peer)
fmt.Println("allowInsecure:", allowInsecure)
fmt.Println("sni:", sni)
fmt.Println("type:", types)
fmt.Println("path:", path)
fmt.Println("security:", security)
fmt.Println("fp:", fp)
fmt.Println("alpn:", alpn)
fmt.Println("host:", host)
fmt.Println("flow:", flow)
fmt.Println("name:", name)
}
return Trojan{
Password: password,
Hostname: hostname,
Port: port,
Query: TrojanQuery{
Peer: peer,
Type: types,
Path: path,
Security: security,
Fp: fp,
AllowInsecure: 0,
Alpn: alpn,
Sni: sni,
Host: host,
Flow: flow,
},
Name: name,
Type: "trojan",
}, nil
}