mirror of
https://github.com/wyx2685/V2bX.git
synced 2026-02-04 12:40:11 +00:00
support hysteria for sing, remove hy core
This commit is contained in:
@@ -1,26 +0,0 @@
|
||||
package hy
|
||||
|
||||
const (
|
||||
mbpsToBps = 125000
|
||||
minSpeedBPS = 16384
|
||||
|
||||
DefaultALPN = "hysteria"
|
||||
|
||||
DefaultStreamReceiveWindow = 16777216 // 16 MB
|
||||
DefaultConnectionReceiveWindow = DefaultStreamReceiveWindow * 5 / 2 // 40 MB
|
||||
|
||||
DefaultMaxIncomingStreams = 1024
|
||||
|
||||
DefaultMMDBFilename = "GeoLite2-Country.mmdb"
|
||||
|
||||
ServerMaxIdleTimeoutSec = 60
|
||||
DefaultClientIdleTimeoutSec = 20
|
||||
|
||||
DefaultClientHopIntervalSec = 10
|
||||
)
|
||||
|
||||
func SpeedTrans(upM, downM int) (uint64, uint64) {
|
||||
up := uint64(upM) * mbpsToBps
|
||||
down := uint64(downM) * mbpsToBps
|
||||
return up, down
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package hy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/InazumaV/V2bX/conf"
|
||||
vCore "github.com/InazumaV/V2bX/core"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
)
|
||||
|
||||
func init() {
|
||||
vCore.RegisterCore("hy", NewHy)
|
||||
}
|
||||
|
||||
type Hy struct {
|
||||
servers sync.Map
|
||||
}
|
||||
|
||||
func NewHy(_ *conf.CoreConfig) (vCore.Core, error) {
|
||||
return &Hy{
|
||||
servers: sync.Map{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *Hy) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Hy) Close() error {
|
||||
var errs error
|
||||
h.servers.Range(func(tag, s any) bool {
|
||||
err := s.(*Server).Close()
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("close %s error: %s", tag, err))
|
||||
}
|
||||
return true
|
||||
})
|
||||
if errs != nil {
|
||||
return errs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Hy) Protocols() []string {
|
||||
return []string{
|
||||
"hysteria",
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package hy
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
type ipMasker struct {
|
||||
IPv4Mask net.IPMask
|
||||
IPv6Mask net.IPMask
|
||||
}
|
||||
|
||||
// Mask masks an address with the configured CIDR.
|
||||
// addr can be "host:port" or just host.
|
||||
func (m *ipMasker) Mask(addr string) string {
|
||||
if m.IPv4Mask == nil && m.IPv6Mask == nil {
|
||||
return addr
|
||||
}
|
||||
|
||||
host, port, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
// just host
|
||||
host, port = addr, ""
|
||||
}
|
||||
ip := net.ParseIP(host)
|
||||
if ip == nil {
|
||||
// not an IP address, return as is
|
||||
return addr
|
||||
}
|
||||
if ip4 := ip.To4(); ip4 != nil && m.IPv4Mask != nil {
|
||||
// IPv4
|
||||
host = ip4.Mask(m.IPv4Mask).String()
|
||||
} else if ip6 := ip.To16(); ip6 != nil && m.IPv6Mask != nil {
|
||||
// IPv6
|
||||
host = ip6.Mask(m.IPv6Mask).String()
|
||||
}
|
||||
if port != "" {
|
||||
return net.JoinHostPort(host, port)
|
||||
} else {
|
||||
return host
|
||||
}
|
||||
}
|
||||
|
||||
var defaultIPMasker = &ipMasker{}
|
||||
@@ -1,95 +0,0 @@
|
||||
package hy
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"sync"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type keypairLoader struct {
|
||||
certMu sync.RWMutex
|
||||
cert *tls.Certificate
|
||||
certPath string
|
||||
keyPath string
|
||||
}
|
||||
|
||||
func newKeypairLoader(certPath, keyPath string) (*keypairLoader, error) {
|
||||
loader := &keypairLoader{
|
||||
certPath: certPath,
|
||||
keyPath: keyPath,
|
||||
}
|
||||
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
loader.cert = &cert
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
switch event.Op {
|
||||
case fsnotify.Create, fsnotify.Write, fsnotify.Rename, fsnotify.Chmod:
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"file": event.Name,
|
||||
}).Info("Keypair change detected, reloading...")
|
||||
if err := loader.load(); err != nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Error("Failed to reload keypair")
|
||||
} else {
|
||||
logrus.Info("Keypair successfully reloaded")
|
||||
}
|
||||
case fsnotify.Remove:
|
||||
_ = watcher.Add(event.Name) // Workaround for vim
|
||||
// https://github.com/fsnotify/fsnotify/issues/92
|
||||
}
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Error("Failed to watch keypair files for changes")
|
||||
}
|
||||
}
|
||||
}()
|
||||
err = watcher.Add(certPath)
|
||||
if err != nil {
|
||||
_ = watcher.Close()
|
||||
return nil, err
|
||||
}
|
||||
err = watcher.Add(keyPath)
|
||||
if err != nil {
|
||||
_ = watcher.Close()
|
||||
return nil, err
|
||||
}
|
||||
return loader, nil
|
||||
}
|
||||
|
||||
func (kpr *keypairLoader) load() error {
|
||||
cert, err := tls.LoadX509KeyPair(kpr.certPath, kpr.keyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kpr.certMu.Lock()
|
||||
kpr.cert = &cert
|
||||
kpr.certMu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kpr *keypairLoader) GetCertificateFunc() func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
return func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
kpr.certMu.RLock()
|
||||
defer kpr.certMu.RUnlock()
|
||||
return kpr.cert, nil
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package hy
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/oschwald/geoip2-golang"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func loadMMDBReader(filename string) (*geoip2.Reader, error) {
|
||||
if _, err := os.Stat(filename); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
logrus.Info("GeoLite2 database not found, downloading...")
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"file": filename,
|
||||
}).Info("GeoLite2 database downloaded")
|
||||
return geoip2.Open(filename)
|
||||
} else {
|
||||
// some other error
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// file exists, just open it
|
||||
return geoip2.Open(filename)
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package hy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/InazumaV/V2bX/api/panel"
|
||||
"github.com/InazumaV/V2bX/conf"
|
||||
"github.com/InazumaV/V2bX/limiter"
|
||||
)
|
||||
|
||||
func (h *Hy) AddNode(tag string, info *panel.NodeInfo, c *conf.Options) error {
|
||||
if info.Type != "hysteria" {
|
||||
return errors.New("the core not support " + info.Type)
|
||||
}
|
||||
switch c.CertConfig.CertMode {
|
||||
case "reality", "none", "":
|
||||
return errors.New("hysteria need normal tls cert")
|
||||
}
|
||||
l, err := limiter.GetLimiter(tag)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get limiter error: %s", err)
|
||||
}
|
||||
s := NewServer(tag, l)
|
||||
err = s.runServer(info, c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("run hy server error: %s", err)
|
||||
}
|
||||
h.servers.Store(tag, s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Hy) DelNode(tag string) error {
|
||||
if s, e := h.servers.Load(tag); e {
|
||||
err := s.(*Server).Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.servers.Delete(tag)
|
||||
return nil
|
||||
}
|
||||
return errors.New("the node is not have")
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
package hy
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/Yuzuki616/hysteria/core/utils"
|
||||
rdns "github.com/folbricht/routedns"
|
||||
)
|
||||
|
||||
var errInvalidSyntax = errors.New("invalid syntax")
|
||||
|
||||
func setResolver(dns string) error {
|
||||
if net.ParseIP(dns) != nil {
|
||||
// Just an IP address, treat as UDP 53
|
||||
dns = "udp://" + net.JoinHostPort(dns, "53")
|
||||
}
|
||||
var r rdns.Resolver
|
||||
if strings.HasPrefix(dns, "udp://") {
|
||||
// Standard UDP DNS resolver
|
||||
dns = strings.TrimPrefix(dns, "udp://")
|
||||
if dns == "" {
|
||||
return errInvalidSyntax
|
||||
}
|
||||
if _, _, err := utils.SplitHostPort(dns); err != nil {
|
||||
// Append the default DNS port
|
||||
dns = net.JoinHostPort(dns, "53")
|
||||
}
|
||||
client, err := rdns.NewDNSClient("dns-udp", dns, "udp", rdns.DNSClientOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r = client
|
||||
} else if strings.HasPrefix(dns, "tcp://") {
|
||||
// Standard TCP DNS resolver
|
||||
dns = strings.TrimPrefix(dns, "tcp://")
|
||||
if dns == "" {
|
||||
return errInvalidSyntax
|
||||
}
|
||||
if _, _, err := utils.SplitHostPort(dns); err != nil {
|
||||
// Append the default DNS port
|
||||
dns = net.JoinHostPort(dns, "53")
|
||||
}
|
||||
client, err := rdns.NewDNSClient("dns-tcp", dns, "tcp", rdns.DNSClientOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r = client
|
||||
} else if strings.HasPrefix(dns, "https://") {
|
||||
// DoH resolver
|
||||
if dohURL, err := url.Parse(dns); err != nil {
|
||||
return err
|
||||
} else {
|
||||
// Need to set bootstrap address to avoid loopback DNS lookup
|
||||
dohIPAddr, err := net.ResolveIPAddr("ip", dohURL.Hostname())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := rdns.NewDoHClient("doh", dns, rdns.DoHClientOptions{
|
||||
BootstrapAddr: dohIPAddr.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r = client
|
||||
}
|
||||
} else if strings.HasPrefix(dns, "tls://") {
|
||||
// DoT resolver
|
||||
dns = strings.TrimPrefix(dns, "tls://")
|
||||
if dns == "" {
|
||||
return errInvalidSyntax
|
||||
}
|
||||
dotHost, _, err := utils.SplitHostPort(dns)
|
||||
if err != nil {
|
||||
// Append the default DNS port
|
||||
dns = net.JoinHostPort(dns, "853")
|
||||
}
|
||||
// Need to set bootstrap address to avoid loopback DNS lookup
|
||||
dotIPAddr, err := net.ResolveIPAddr("ip", dotHost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := rdns.NewDoTClient("dot", dns, rdns.DoTClientOptions{
|
||||
BootstrapAddr: dotIPAddr.String(),
|
||||
TLSConfig: new(tls.Config),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r = client
|
||||
} else if strings.HasPrefix(dns, "quic://") {
|
||||
// DoQ resolver
|
||||
dns = strings.TrimPrefix(dns, "quic://")
|
||||
if dns == "" {
|
||||
return errInvalidSyntax
|
||||
}
|
||||
doqHost, _, err := utils.SplitHostPort(dns)
|
||||
if err != nil {
|
||||
// Append the default DNS port
|
||||
dns = net.JoinHostPort(dns, "853")
|
||||
}
|
||||
// Need to set bootstrap address to avoid loopback DNS lookup
|
||||
doqIPAddr, err := net.ResolveIPAddr("ip", doqHost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := rdns.NewDoQClient("doq", dns, rdns.DoQClientOptions{
|
||||
BootstrapAddr: doqIPAddr.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r = client
|
||||
} else {
|
||||
return errInvalidSyntax
|
||||
}
|
||||
cache := rdns.NewCache("cache", r, rdns.CacheOptions{})
|
||||
net.DefaultResolver = rdns.NewNetResolver(cache)
|
||||
return nil
|
||||
}
|
||||
@@ -1,257 +0,0 @@
|
||||
package hy
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/InazumaV/V2bX/common/counter"
|
||||
|
||||
"github.com/InazumaV/V2bX/api/panel"
|
||||
"github.com/InazumaV/V2bX/conf"
|
||||
"github.com/InazumaV/V2bX/limiter"
|
||||
"github.com/Yuzuki616/hysteria/core/sockopt"
|
||||
"github.com/Yuzuki616/quic-go"
|
||||
|
||||
"github.com/Yuzuki616/hysteria/core/acl"
|
||||
"github.com/Yuzuki616/hysteria/core/cs"
|
||||
"github.com/Yuzuki616/hysteria/core/pktconns"
|
||||
"github.com/Yuzuki616/hysteria/core/pmtud"
|
||||
"github.com/Yuzuki616/hysteria/core/transport"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var serverPacketConnFuncFactoryMap = map[string]pktconns.ServerPacketConnFuncFactory{
|
||||
"": pktconns.NewServerUDPConnFunc,
|
||||
"udp": pktconns.NewServerUDPConnFunc,
|
||||
"wechat": pktconns.NewServerWeChatConnFunc,
|
||||
"wechat-video": pktconns.NewServerWeChatConnFunc,
|
||||
"faketcp": pktconns.NewServerFakeTCPConnFunc,
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
tag string
|
||||
l *limiter.Limiter
|
||||
counter *counter.TrafficCounter
|
||||
users sync.Map
|
||||
running atomic.Bool
|
||||
*cs.Server
|
||||
}
|
||||
|
||||
func NewServer(tag string, l *limiter.Limiter) *Server {
|
||||
return &Server{
|
||||
tag: tag,
|
||||
l: l,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) runServer(node *panel.NodeInfo, c *conf.Options) error {
|
||||
/*if c.HyOptions == nil {
|
||||
return errors.New("hy options is not vail")
|
||||
}*/
|
||||
// Resolver
|
||||
if len(c.HyOptions.Resolver) > 0 {
|
||||
err := setResolver(c.HyOptions.Resolver)
|
||||
if err != nil {
|
||||
return fmt.Errorf("set resolver error: %s", err)
|
||||
}
|
||||
}
|
||||
// tls config
|
||||
kpl, err := newKeypairLoader(c.CertConfig.CertFile, c.CertConfig.KeyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load cert error: %s", err)
|
||||
}
|
||||
tlsConfig := &tls.Config{
|
||||
GetCertificate: kpl.GetCertificateFunc(),
|
||||
NextProtos: []string{DefaultALPN},
|
||||
MinVersion: tls.VersionTLS13,
|
||||
}
|
||||
// QUIC config
|
||||
quicConfig := &quic.Config{
|
||||
InitialStreamReceiveWindow: DefaultStreamReceiveWindow,
|
||||
MaxStreamReceiveWindow: DefaultStreamReceiveWindow,
|
||||
InitialConnectionReceiveWindow: DefaultConnectionReceiveWindow,
|
||||
MaxConnectionReceiveWindow: DefaultConnectionReceiveWindow,
|
||||
MaxIncomingStreams: int64(DefaultMaxIncomingStreams),
|
||||
MaxIdleTimeout: ServerMaxIdleTimeoutSec * time.Second,
|
||||
KeepAlivePeriod: 0, // Keep alive should solely be client's responsibility
|
||||
DisablePathMTUDiscovery: false,
|
||||
EnableDatagrams: true,
|
||||
}
|
||||
if !quicConfig.DisablePathMTUDiscovery && pmtud.DisablePathMTUDiscovery {
|
||||
logrus.Info("Path MTU Discovery is not yet supported on this platform")
|
||||
}
|
||||
// Resolve preference
|
||||
if len(c.HyOptions.ResolvePreference) > 0 {
|
||||
pref, err := transport.ResolvePreferenceFromString(c.HyOptions.Resolver)
|
||||
if err != nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Fatal("Failed to parse the resolve preference")
|
||||
}
|
||||
transport.DefaultServerTransport.ResolvePreference = pref
|
||||
}
|
||||
/*// SOCKS5 outbound
|
||||
if config.SOCKS5Outbound.Server != "" {
|
||||
transport.DefaultServerTransport.SOCKS5Client = transport.NewSOCKS5Client(config.SOCKS5Outbound.Server,
|
||||
config.SOCKS5Outbound.User, config.SOCKS5Outbound.Password)
|
||||
}*/
|
||||
// Bind outbound
|
||||
if c.HyOptions.SendDevice != "" {
|
||||
iface, err := net.InterfaceByName(c.HyOptions.SendDevice)
|
||||
if err != nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Fatal("Failed to find the interface")
|
||||
}
|
||||
transport.DefaultServerTransport.LocalUDPIntf = iface
|
||||
sockopt.BindDialer(transport.DefaultServerTransport.Dialer, iface)
|
||||
}
|
||||
if c.SendIP != "" {
|
||||
ip := net.ParseIP(c.SendIP)
|
||||
if ip == nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Fatal("Failed to parse the address")
|
||||
}
|
||||
transport.DefaultServerTransport.Dialer.LocalAddr = &net.TCPAddr{IP: ip}
|
||||
transport.DefaultServerTransport.LocalUDPAddr = &net.UDPAddr{IP: ip}
|
||||
}
|
||||
// ACL
|
||||
var aclEngine *acl.Engine
|
||||
// Prometheus
|
||||
s.counter = counter.NewTrafficCounter()
|
||||
// Packet conn
|
||||
pktConnFuncFactory := serverPacketConnFuncFactoryMap[""]
|
||||
if pktConnFuncFactory == nil {
|
||||
return fmt.Errorf("unsopport protocol")
|
||||
}
|
||||
pktConnFunc := pktConnFuncFactory(node.HyObfs)
|
||||
addr := fmt.Sprintf("%s:%d", c.ListenIP, node.Port)
|
||||
pktConn, err := pktConnFunc(addr)
|
||||
if err != nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"addr": addr,
|
||||
}).Fatal("Failed to listen on the UDP address")
|
||||
}
|
||||
// Server
|
||||
up, down := SpeedTrans(node.UpMbps, node.DownMbps)
|
||||
s.Server, err = cs.NewServer(tlsConfig, quicConfig, pktConn,
|
||||
transport.DefaultServerTransport, up, down, false, aclEngine,
|
||||
s.connectFunc, s.disconnectFunc, tcpRequestFunc, tcpErrorFunc, udpRequestFunc, udpErrorFunc, s.counter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("new server error: %s", err)
|
||||
}
|
||||
logrus.WithField("addr", addr).Info("Server up and running")
|
||||
go func() {
|
||||
s.running.Store(true)
|
||||
defer func() {
|
||||
s.running.Store(false)
|
||||
}()
|
||||
err = s.Server.Serve()
|
||||
if err != nil {
|
||||
logrus.WithField("addr", addr).Errorf("serve error: %s", err)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) authByUser(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) {
|
||||
if _, r := s.l.CheckLimit(string(auth), addr.String(), false); r {
|
||||
return false, "device limited"
|
||||
}
|
||||
if _, ok := s.users.Load(string(auth)); ok {
|
||||
return true, "Done"
|
||||
}
|
||||
return false, "Failed"
|
||||
}
|
||||
|
||||
func (s *Server) connectFunc(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) {
|
||||
s.l.ConnLimiter.AddConnCount(addr.String(), string(auth), false)
|
||||
ok, msg := s.authByUser(addr, auth, sSend, sRecv)
|
||||
if !ok {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"src": defaultIPMasker.Mask(addr.String()),
|
||||
}).Info("Authentication failed, client rejected")
|
||||
return false, msg
|
||||
}
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"src": defaultIPMasker.Mask(addr.String()),
|
||||
"Uuid": string(auth),
|
||||
"Tag": s.tag,
|
||||
}).Info("Client connected")
|
||||
return ok, msg
|
||||
}
|
||||
|
||||
func (s *Server) disconnectFunc(addr net.Addr, auth []byte, err error) {
|
||||
s.l.ConnLimiter.DelConnCount(addr.String(), string(auth))
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"src": defaultIPMasker.Mask(addr.String()),
|
||||
"error": err,
|
||||
}).Info("Client disconnected")
|
||||
}
|
||||
|
||||
func tcpRequestFunc(addr net.Addr, auth []byte, reqAddr string, action acl.Action, arg string) {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"src": defaultIPMasker.Mask(addr.String()),
|
||||
"dst": defaultIPMasker.Mask(reqAddr),
|
||||
"action": actionToString(action, arg),
|
||||
}).Debug("TCP request")
|
||||
}
|
||||
|
||||
func tcpErrorFunc(addr net.Addr, auth []byte, reqAddr string, err error) {
|
||||
if err != io.EOF {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"src": defaultIPMasker.Mask(addr.String()),
|
||||
"dst": defaultIPMasker.Mask(reqAddr),
|
||||
"error": err,
|
||||
}).Info("TCP error")
|
||||
} else {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"src": defaultIPMasker.Mask(addr.String()),
|
||||
"dst": defaultIPMasker.Mask(reqAddr),
|
||||
}).Debug("TCP EOF")
|
||||
}
|
||||
}
|
||||
|
||||
func udpRequestFunc(addr net.Addr, auth []byte, sessionID uint32) {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"src": defaultIPMasker.Mask(addr.String()),
|
||||
"session": sessionID,
|
||||
}).Debug("UDP request")
|
||||
}
|
||||
|
||||
func udpErrorFunc(addr net.Addr, auth []byte, sessionID uint32, err error) {
|
||||
if err != io.EOF {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"src": defaultIPMasker.Mask(addr.String()),
|
||||
"session": sessionID,
|
||||
"error": err,
|
||||
}).Info("UDP error")
|
||||
} else {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"src": defaultIPMasker.Mask(addr.String()),
|
||||
"session": sessionID,
|
||||
}).Debug("UDP EOF")
|
||||
}
|
||||
}
|
||||
|
||||
func actionToString(action acl.Action, arg string) string {
|
||||
switch action {
|
||||
case acl.ActionDirect:
|
||||
return "Direct"
|
||||
case acl.ActionProxy:
|
||||
return "Proxy"
|
||||
case acl.ActionBlock:
|
||||
return "Block"
|
||||
case acl.ActionHijack:
|
||||
return "Hijack to " + arg
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package hy
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"log"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/InazumaV/V2bX/api/panel"
|
||||
"github.com/InazumaV/V2bX/conf"
|
||||
"github.com/InazumaV/V2bX/limiter"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func TestServer(t *testing.T) {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
limiter.Init()
|
||||
l := limiter.AddLimiter("test", &conf.LimitConfig{}, nil)
|
||||
s := NewServer("test", l)
|
||||
t.Log(s.runServer(&panel.NodeInfo{
|
||||
Port: 1145,
|
||||
UpMbps: 100,
|
||||
DownMbps: 100,
|
||||
HyObfs: "atresssdaaaadd",
|
||||
}, &conf.Options{
|
||||
ListenIP: "127.0.0.1",
|
||||
HyOptions: conf.HyOptions{},
|
||||
CertConfig: &conf.CertConfig{
|
||||
CertFile: "../../test_data/1.pem",
|
||||
KeyFile: "../../test_data/1.key",
|
||||
},
|
||||
}))
|
||||
s.users.Store("test1111", struct{}{})
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(10 * time.Second)
|
||||
auth := base64.StdEncoding.EncodeToString([]byte("test1111"))
|
||||
log.Println(auth)
|
||||
log.Println(s.counter.GetUpCount(auth))
|
||||
}
|
||||
}()
|
||||
select {}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package hy
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
|
||||
"github.com/InazumaV/V2bX/api/panel"
|
||||
"github.com/InazumaV/V2bX/core"
|
||||
)
|
||||
|
||||
func (h *Hy) AddUsers(p *core.AddUsersParams) (int, error) {
|
||||
s, ok := h.servers.Load(p.Tag)
|
||||
if !ok {
|
||||
return 0, errors.New("the node not have")
|
||||
}
|
||||
u := &s.(*Server).users
|
||||
for i := range p.UserInfo {
|
||||
u.Store(p.UserInfo[i].Uuid, struct{}{})
|
||||
}
|
||||
return len(p.UserInfo), nil
|
||||
}
|
||||
|
||||
func (h *Hy) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) {
|
||||
v, _ := h.servers.Load(tag)
|
||||
s := v.(*Server)
|
||||
auth := base64.StdEncoding.EncodeToString([]byte(uuid))
|
||||
up = s.counter.GetCounter(auth).UpCounter.Load()
|
||||
down = s.counter.GetCounter(auth).DownCounter.Load()
|
||||
if reset {
|
||||
s.counter.Reset(auth)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (h *Hy) DelUsers(users []panel.UserInfo, tag string) error {
|
||||
v, e := h.servers.Load(tag)
|
||||
if !e {
|
||||
return errors.New("the node is not have")
|
||||
}
|
||||
s := v.(*Server)
|
||||
for i := range users {
|
||||
s.users.Delete(users[i].Uuid)
|
||||
s.counter.Delete(base64.StdEncoding.EncodeToString([]byte(users[i].Uuid)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
//go:build hy
|
||||
|
||||
package imports
|
||||
|
||||
import _ "github.com/InazumaV/V2bX/core/hy"
|
||||
@@ -226,6 +226,15 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
|
||||
in.TrojanOptions.FallbackForALPN = fallbackForALPN
|
||||
}
|
||||
}
|
||||
case "hysteria":
|
||||
in.Type = "hysteria"
|
||||
in.HysteriaOptions = option.HysteriaInboundOptions{
|
||||
ListenOptions: listen,
|
||||
UpMbps: info.UpMbps,
|
||||
DownMbps: info.DownMbps,
|
||||
Obfs: info.HyObfs,
|
||||
TLS: &tls,
|
||||
}
|
||||
}
|
||||
return in, nil
|
||||
}
|
||||
|
||||
@@ -265,5 +265,7 @@ func (b *Box) Protocols() []string {
|
||||
return []string{
|
||||
"v2ray",
|
||||
"shadowsocks",
|
||||
"trojan",
|
||||
"hysteria",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,15 @@ func (b *Box) AddUsers(p *core.AddUsersParams) (added int, err error) {
|
||||
}
|
||||
}
|
||||
err = b.inbounds[p.Tag].(*inbound.Trojan).AddUsers(us)
|
||||
case "hysteria":
|
||||
us := make([]option.HysteriaUser, len(p.UserInfo))
|
||||
for i := range p.UserInfo {
|
||||
us[i] = option.HysteriaUser{
|
||||
Name: p.UserInfo[i].Uuid,
|
||||
AuthString: p.UserInfo[i].Uuid,
|
||||
}
|
||||
}
|
||||
err = b.inbounds[p.Tag].(*inbound.Hysteria).AddUsers(us)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -91,6 +100,10 @@ func (b *Box) DelUsers(users []panel.UserInfo, tag string) error {
|
||||
del = i.(*inbound.VMess)
|
||||
case "shadowsocks":
|
||||
del = i.(*inbound.ShadowsocksMulti)
|
||||
case "trojan":
|
||||
del = i.(*inbound.Trojan)
|
||||
case "hysteria":
|
||||
del = i.(*inbound.Hysteria)
|
||||
}
|
||||
} else {
|
||||
return errors.New("the inbound not found")
|
||||
|
||||
Reference in New Issue
Block a user