dae/component/outbound/dialer/socks/socks.go

98 lines
2.4 KiB
Go
Raw Normal View History

2023-01-23 18:54:21 +07:00
package socks
import (
"fmt"
"github.com/mzz2017/softwind/protocol/direct"
2023-01-23 19:01:24 +07:00
"github.com/v2rayA/dae/component/outbound/dialer"
2023-01-24 14:28:39 +07:00
//"github.com/mzz2017/softwind/protocol/socks4"
"github.com/mzz2017/softwind/protocol/socks5"
2023-01-23 18:54:21 +07:00
"net"
"net/url"
"strconv"
)
func init() {
dialer.FromLinkRegister("socks", NewSocks) // socks -> socks5
2023-01-24 14:28:39 +07:00
//dialer.FromLinkRegister("socks4", NewSocks)
//dialer.FromLinkRegister("socks4a", NewSocks)
2023-01-23 18:54:21 +07:00
dialer.FromLinkRegister("socks5", NewSocks)
}
type Socks struct {
Name string `json:"name"`
Server string `json:"server"`
Port int `json:"port"`
Username string `json:"username"`
Password string `json:"password"`
Protocol string `json:"protocol"`
}
2023-01-28 14:47:43 +07:00
func NewSocks(option *dialer.GlobalOption, iOption dialer.InstanceOption, link string) (*dialer.Dialer, error) {
2023-01-23 18:54:21 +07:00
s, err := ParseSocksURL(link)
if err != nil {
return nil, dialer.InvalidParameterErr
}
2023-01-28 14:47:43 +07:00
return s.Dialer(option, iOption)
2023-01-23 18:54:21 +07:00
}
2023-01-28 14:47:43 +07:00
func (s *Socks) Dialer(option *dialer.GlobalOption, iOption dialer.InstanceOption) (*dialer.Dialer, error) {
2023-01-23 18:54:21 +07:00
link := s.ExportToURL()
switch s.Protocol {
case "", "socks", "socks5":
d, err := socks5.NewSocks5Dialer(link, direct.FullconeDirect) // Socks5 Proxy supports full-cone.
2023-01-23 18:54:21 +07:00
if err != nil {
return nil, err
}
return dialer.NewDialer(d, option, iOption, s.Name, s.Protocol, link), nil
2023-01-24 14:28:39 +07:00
//case "socks4", "socks4a":
// d, err := socks4.NewSocks4Dialer(link, &proxy.Direct{})
// if err != nil {
// return nil, err
// }
// return dialer.NewDialer(d, false, s.Name, s.Protocol, link), nil
2023-01-23 18:54:21 +07:00
default:
return nil, fmt.Errorf("unexpected protocol: %v", s.Protocol)
}
}
func ParseSocksURL(link string) (data *Socks, err error) {
u, err := url.Parse(link)
if err != nil {
return nil, dialer.InvalidParameterErr
}
pwd, _ := u.User.Password()
strPort := u.Port()
port, err := strconv.Atoi(strPort)
if err != nil {
return nil, err
}
// socks -> socks5
if u.Scheme == "socks" {
u.Scheme = "socks5"
}
return &Socks{
Name: u.Fragment,
Server: u.Hostname(),
Port: port,
Username: u.User.Username(),
Password: pwd,
Protocol: u.Scheme,
}, nil
}
func (s *Socks) ExportToURL() string {
var user *url.Userinfo
if s.Password != "" {
user = url.UserPassword(s.Username, s.Password)
} else {
user = url.User(s.Username)
}
u := url.URL{
Scheme: s.Protocol,
User: user,
Host: net.JoinHostPort(s.Server, strconv.Itoa(s.Port)),
Fragment: s.Name,
}
return u.String()
}