mirror of https://github.com/ginuerzh/gost
15 changed files with 386 additions and 214 deletions
@ -1,139 +0,0 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"net" |
|||
"net/url" |
|||
"os" |
|||
"strings" |
|||
|
|||
"github.com/ginuerzh/gost/gost" |
|||
"github.com/go-log/log" |
|||
) |
|||
|
|||
type node struct { |
|||
Addr string |
|||
Protocol string // protocol: http/socks5/ss
|
|||
Transport string // transport: ws/wss/tls/http2/tcp/udp/rtcp/rudp
|
|||
Remote string // remote address, used by tcp/udp port forwarding
|
|||
Users []*url.Userinfo // authentication for proxy
|
|||
Whitelist *gost.Permissions |
|||
Blacklist *gost.Permissions |
|||
values url.Values |
|||
serverName string |
|||
} |
|||
|
|||
func parseNode(s string) (n node, err error) { |
|||
if !strings.Contains(s, "://") { |
|||
s = "gost://" + s |
|||
} |
|||
u, err := url.Parse(s) |
|||
if err != nil { |
|||
return |
|||
} |
|||
|
|||
query := u.Query() |
|||
|
|||
n = node{ |
|||
Addr: u.Host, |
|||
} |
|||
|
|||
if query.Get("whitelist") != "" { |
|||
if n.Whitelist, err = gost.ParsePermissions(query.Get("whitelist")); err != nil { |
|||
return |
|||
} |
|||
} else { |
|||
// By default allow for everyting
|
|||
n.Whitelist, _ = gost.ParsePermissions("*:*:*") |
|||
} |
|||
|
|||
if query.Get("blacklist") != "" { |
|||
if n.Blacklist, err = gost.ParsePermissions(query.Get("blacklist")); err != nil { |
|||
return |
|||
} |
|||
} else { |
|||
// By default block nothing
|
|||
n.Blacklist, _ = gost.ParsePermissions("") |
|||
} |
|||
|
|||
if u.User != nil { |
|||
n.Users = append(n.Users, u.User) |
|||
} |
|||
|
|||
users, er := parseUsers(n.values.Get("secrets")) |
|||
if users != nil { |
|||
n.Users = append(n.Users, users...) |
|||
} |
|||
if er != nil { |
|||
log.Log("load secrets:", er) |
|||
} |
|||
|
|||
if strings.Contains(u.Host, ":") { |
|||
n.serverName, _, _ = net.SplitHostPort(u.Host) |
|||
if n.serverName == "" { |
|||
n.serverName = "localhost" // default server name
|
|||
} |
|||
} |
|||
|
|||
schemes := strings.Split(u.Scheme, "+") |
|||
if len(schemes) == 1 { |
|||
n.Protocol = schemes[0] |
|||
n.Transport = schemes[0] |
|||
} |
|||
if len(schemes) == 2 { |
|||
n.Protocol = schemes[0] |
|||
n.Transport = schemes[1] |
|||
} |
|||
|
|||
switch n.Transport { |
|||
case "ws", "wss", "tls", "h2", "h2c", "quic", "kcp", "redirect", "ssu", "ssh": |
|||
case "https": |
|||
n.Protocol = "http" |
|||
n.Transport = "tls" |
|||
case "http2": // http2 -> http2+tls, h2c mode is http2+tcp
|
|||
n.Protocol = "http2" |
|||
n.Transport = "tls" |
|||
case "tcp", "udp": // started from v2.1, tcp and udp are for local port forwarding
|
|||
n.Remote = strings.Trim(u.EscapedPath(), "/") |
|||
case "rtcp", "rudp": // rtcp and rudp are for remote port forwarding
|
|||
n.Remote = strings.Trim(u.EscapedPath(), "/") |
|||
default: |
|||
n.Transport = "" |
|||
} |
|||
|
|||
switch n.Protocol { |
|||
case "http", "http2", "socks", "socks4", "socks4a", "socks5", "ss": |
|||
default: |
|||
n.Protocol = "" |
|||
} |
|||
|
|||
return |
|||
} |
|||
|
|||
func parseUsers(s string) (users []*url.Userinfo, err error) { |
|||
if s == "" { |
|||
return |
|||
} |
|||
|
|||
f, err := os.Open(s) |
|||
if err != nil { |
|||
return |
|||
} |
|||
scanner := bufio.NewScanner(f) |
|||
for scanner.Scan() { |
|||
line := strings.TrimSpace(scanner.Text()) |
|||
if line == "" || strings.HasPrefix(line, "#") { |
|||
continue |
|||
} |
|||
|
|||
s := strings.SplitN(line, " ", 2) |
|||
if len(s) == 1 { |
|||
users = append(users, url.User(strings.TrimSpace(s[0]))) |
|||
} else if len(s) == 2 { |
|||
users = append(users, url.UserPassword(strings.TrimSpace(s[0]), strings.TrimSpace(s[1]))) |
|||
} |
|||
} |
|||
|
|||
err = scanner.Err() |
|||
return |
|||
} |
|||
@ -1,15 +1,165 @@ |
|||
package gost |
|||
|
|||
import ( |
|||
"bufio" |
|||
"net" |
|||
"net/url" |
|||
"os" |
|||
"strconv" |
|||
"strings" |
|||
|
|||
"github.com/go-log/log" |
|||
) |
|||
|
|||
// Node is a proxy node, mainly used to construct a proxy chain.
|
|||
type Node struct { |
|||
Addr string |
|||
Protocol string |
|||
Transport string |
|||
User *url.Userinfo |
|||
Client *Client |
|||
Server *Server |
|||
Addr string |
|||
Protocol string |
|||
Transport string |
|||
Remote string // remote address, used by tcp/udp port forwarding
|
|||
User *url.Userinfo |
|||
users []*url.Userinfo // authentication or cipher for proxy
|
|||
Whitelist *Permissions |
|||
Blacklist *Permissions |
|||
values url.Values |
|||
serverName string |
|||
Client *Client |
|||
Server *Server |
|||
} |
|||
|
|||
func ParseNode(s string) (node Node, err error) { |
|||
if !strings.Contains(s, "://") { |
|||
s = "auto://" + s |
|||
} |
|||
u, err := url.Parse(s) |
|||
if err != nil { |
|||
return |
|||
} |
|||
|
|||
query := u.Query() |
|||
node = Node{ |
|||
Addr: u.Host, |
|||
values: query, |
|||
serverName: u.Host, |
|||
} |
|||
|
|||
if query.Get("whitelist") != "" { |
|||
if node.Whitelist, err = ParsePermissions(query.Get("whitelist")); err != nil { |
|||
return |
|||
} |
|||
} else { |
|||
// By default allow for everyting
|
|||
node.Whitelist, _ = ParsePermissions("*:*:*") |
|||
} |
|||
|
|||
if query.Get("blacklist") != "" { |
|||
if node.Blacklist, err = ParsePermissions(query.Get("blacklist")); err != nil { |
|||
return |
|||
} |
|||
} else { |
|||
// By default block nothing
|
|||
node.Blacklist, _ = ParsePermissions("") |
|||
} |
|||
|
|||
if u.User != nil { |
|||
node.User = u.User |
|||
node.users = append(node.users, u.User) |
|||
} |
|||
|
|||
users, er := parseUsers(node.values.Get("secrets")) |
|||
if users != nil { |
|||
node.users = append(node.users, users...) |
|||
} |
|||
if er != nil { |
|||
log.Log("load secrets:", er) |
|||
} |
|||
|
|||
if strings.Contains(u.Host, ":") { |
|||
node.serverName, _, _ = net.SplitHostPort(u.Host) |
|||
if node.serverName == "" { |
|||
node.serverName = "localhost" // default server name
|
|||
} |
|||
} |
|||
|
|||
schemes := strings.Split(u.Scheme, "+") |
|||
if len(schemes) == 1 { |
|||
node.Protocol = schemes[0] |
|||
node.Transport = schemes[0] |
|||
} |
|||
if len(schemes) == 2 { |
|||
node.Protocol = schemes[0] |
|||
node.Transport = schemes[1] |
|||
} |
|||
|
|||
switch node.Transport { |
|||
case "tls", "ws", "wss", "kcp", "ssh", "quic", "ssu", "http2", "h2", "h2c", "redirect": |
|||
case "https": |
|||
node.Protocol = "http" |
|||
node.Transport = "tls" |
|||
case "tcp", "udp": // started from v2.1, tcp and udp are for local port forwarding
|
|||
node.Remote = strings.Trim(u.EscapedPath(), "/") |
|||
case "rtcp", "rudp": // rtcp and rudp are for remote port forwarding
|
|||
node.Remote = strings.Trim(u.EscapedPath(), "/") |
|||
default: |
|||
node.Transport = "" |
|||
} |
|||
|
|||
switch node.Protocol { |
|||
case "http", "http2", "socks4", "socks4a", "socks", "socks5", "ss": |
|||
case "tcp", "udp", "rtcp", "rudp": // port forwarding
|
|||
case "direct", "remote": // SSH port forwarding
|
|||
default: |
|||
node.Protocol = "" |
|||
} |
|||
|
|||
return |
|||
} |
|||
|
|||
func parseUsers(authFile string) (users []*url.Userinfo, err error) { |
|||
if authFile == "" { |
|||
return |
|||
} |
|||
|
|||
file, err := os.Open(authFile) |
|||
if err != nil { |
|||
return |
|||
} |
|||
scanner := bufio.NewScanner(file) |
|||
for scanner.Scan() { |
|||
line := strings.TrimSpace(scanner.Text()) |
|||
if line == "" || strings.HasPrefix(line, "#") { |
|||
continue |
|||
} |
|||
|
|||
s := strings.SplitN(line, " ", 2) |
|||
if len(s) == 1 { |
|||
users = append(users, url.User(strings.TrimSpace(s[0]))) |
|||
} else if len(s) == 2 { |
|||
users = append(users, url.UserPassword(strings.TrimSpace(s[0]), strings.TrimSpace(s[1]))) |
|||
} |
|||
} |
|||
|
|||
err = scanner.Err() |
|||
return |
|||
} |
|||
|
|||
func Can(action string, addr string, whitelist, blacklist *Permissions) bool { |
|||
if !strings.Contains(addr, ":") { |
|||
addr = addr + ":80" |
|||
} |
|||
host, strport, err := net.SplitHostPort(addr) |
|||
|
|||
if err != nil { |
|||
return false |
|||
} |
|||
|
|||
port, err := strconv.Atoi(strport) |
|||
|
|||
if err != nil { |
|||
return false |
|||
} |
|||
|
|||
log.Logf("Can action: %s, host: %s, port %d", action, host, port) |
|||
|
|||
return whitelist.Can(action, host, port) && !blacklist.Can(action, host, port) |
|||
} |
|||
|
|||
Loading…
Reference in new issue