mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-10-26 13:06:56 +00:00
Add openvpn and openconnect
This commit is contained in:
@@ -0,0 +1,571 @@
|
||||
package openvpn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/adapter/endpoint"
|
||||
"github.com/sagernet/sing-box/common/dialer"
|
||||
"github.com/sagernet/sing-box/common/listener"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
ovpntransport "github.com/sagernet/sing-box/transport/openvpn"
|
||||
ovpn "github.com/sagernet/sing-openvpn"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
||||
var (
|
||||
_ adapter.FlowOutbound = (*ServerEndpoint)(nil)
|
||||
_ dialer.PacketDialerWithDestination = (*ServerEndpoint)(nil)
|
||||
)
|
||||
|
||||
type ServerEndpoint struct {
|
||||
endpointBase
|
||||
ctx context.Context
|
||||
loopContext context.Context
|
||||
cancelLoop context.CancelFunc
|
||||
options option.OpenVPNServerEndpointOptions
|
||||
serverOptions ovpn.ServerOptions
|
||||
dnsRouter adapter.DNSRouter
|
||||
listener *listener.Listener
|
||||
server *ovpn.Server
|
||||
device ovpntransport.Device
|
||||
localAddresses []netip.Prefix
|
||||
started atomic.Bool
|
||||
readLoopDone chan struct{}
|
||||
}
|
||||
|
||||
type udpEgressPacketConn struct {
|
||||
*tun.UDPEgressConn
|
||||
}
|
||||
|
||||
func (c *udpEgressPacketConn) ReadFrom(buffer []byte) (int, net.Addr, error) {
|
||||
dataLength, source, err := c.ReadFromUDPAddrPort(buffer)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
return dataLength, net.UDPAddrFromAddrPort(source), nil
|
||||
}
|
||||
|
||||
func (c *udpEgressPacketConn) WriteTo(buffer []byte, destination net.Addr) (int, error) {
|
||||
destinationAddress := M.SocksaddrFromNet(destination)
|
||||
if !destinationAddress.IsIP() {
|
||||
return 0, E.New("invalid UDP destination: ", destination)
|
||||
}
|
||||
return c.WriteToUDPAddrPort(buffer, destinationAddress.AddrPort())
|
||||
}
|
||||
|
||||
func NewServerEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.OpenVPNServerEndpointOptions) (adapter.Endpoint, error) {
|
||||
if options.MTU == 0 {
|
||||
options.MTU = ovpntransport.DefaultMTU
|
||||
}
|
||||
loopContext, cancelLoop := context.WithCancel(ctx)
|
||||
serverEndpoint := &ServerEndpoint{
|
||||
endpointBase: endpointBase{
|
||||
Adapter: endpoint.NewAdapter(C.TypeOpenVPNServer, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, nil),
|
||||
router: router,
|
||||
logger: logger,
|
||||
},
|
||||
ctx: ctx,
|
||||
loopContext: loopContext,
|
||||
cancelLoop: cancelLoop,
|
||||
options: options,
|
||||
dnsRouter: service.FromContext[adapter.DNSRouter](ctx),
|
||||
localAddresses: options.Address,
|
||||
}
|
||||
serverOptions, err := buildServerOptions(options)
|
||||
if err != nil {
|
||||
cancelLoop()
|
||||
return nil, err
|
||||
}
|
||||
serverOptions.Context = loopContext
|
||||
serverOptions.Authentication.Authenticator = authenticatorFromUsers(options.Users)
|
||||
serverOptions.Logger = logger
|
||||
serverEndpoint.serverOptions = serverOptions
|
||||
udpTimeout := C.UDPTimeout
|
||||
if options.UDPTimeout != 0 {
|
||||
udpTimeout = time.Duration(options.UDPTimeout)
|
||||
}
|
||||
deviceRoutes := make([]ovpntransport.Route, 0, len(options.Address))
|
||||
for _, prefix := range options.Address {
|
||||
deviceRoutes = append(deviceRoutes, ovpntransport.Route{Prefix: prefix.Masked()})
|
||||
}
|
||||
device, err := ovpntransport.NewDevice(ovpntransport.DeviceOptions{
|
||||
Context: ctx,
|
||||
Logger: logger,
|
||||
System: options.System,
|
||||
Handler: serverEndpoint,
|
||||
UDPTimeout: udpTimeout,
|
||||
ICMPTimeout: C.ICMPTimeout,
|
||||
Name: options.Name,
|
||||
MTU: options.MTU,
|
||||
Configuration: ovpntransport.Configuration{
|
||||
MTU: options.MTU,
|
||||
Address: options.Address,
|
||||
Routes: deviceRoutes,
|
||||
Topology: options.Topology,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
cancelLoop()
|
||||
return nil, err
|
||||
}
|
||||
serverEndpoint.device = device
|
||||
device.SetPacketWriter(serverEndpoint.writePacketBuffersByDestination)
|
||||
return serverEndpoint, nil
|
||||
}
|
||||
|
||||
func validateServerAddresses(addresses []netip.Prefix) error {
|
||||
var hasIPv4 bool
|
||||
var hasIPv6 bool
|
||||
for _, prefix := range addresses {
|
||||
if prefix.Addr().Is4() {
|
||||
if hasIPv4 {
|
||||
return E.New("multiple IPv4 OpenVPN server address pools are not supported")
|
||||
}
|
||||
hasIPv4 = true
|
||||
} else {
|
||||
if hasIPv6 {
|
||||
return E.New("multiple IPv6 OpenVPN server address pools are not supported")
|
||||
}
|
||||
hasIPv6 = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateServerTopology(topology string) error {
|
||||
switch topology {
|
||||
case "", "subnet", "p2p", "net30":
|
||||
return nil
|
||||
default:
|
||||
return E.New("invalid OpenVPN topology ", topology, ", allowed values: subnet, p2p, net30")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
protocol := s.serverOptions.Transport.Protocol
|
||||
s.listener = listener.New(listener.Options{
|
||||
Context: s.ctx,
|
||||
Logger: s.logger,
|
||||
Network: []string{protocol},
|
||||
Listen: s.options.ListenOptions,
|
||||
})
|
||||
var (
|
||||
streamListener net.Listener
|
||||
packetConn net.PacketConn
|
||||
err error
|
||||
)
|
||||
if protocol == N.NetworkTCP {
|
||||
streamListener, err = s.listener.ListenTCP()
|
||||
} else {
|
||||
var listenConfig net.ListenConfig
|
||||
var egressEnabled bool
|
||||
listenAddress := s.options.Listen.Build(netip.AddrFrom4([4]byte{127, 0, 0, 1}))
|
||||
if listenAddress.IsUnspecified() && s.options.BindInterface == "" && s.options.RoutingMark == 0 && s.options.NetNs == "" {
|
||||
udpDialer, dialerErr := dialer.NewDefault(s.ctx, option.DialerOptions{
|
||||
ReuseAddr: s.options.ReuseAddr,
|
||||
UDPFragment: s.options.UDPFragment,
|
||||
UDPFragmentDefault: s.options.UDPFragmentDefault,
|
||||
})
|
||||
if dialerErr != nil {
|
||||
return dialerErr
|
||||
}
|
||||
listenConfig.Control, egressEnabled = udpDialer.UDPListenerControl()
|
||||
}
|
||||
packetConn, err = s.listener.ListenUDPWithConfig(listenConfig)
|
||||
if err == nil {
|
||||
tuneOpenVPNUDPSocket(packetConn)
|
||||
if egressEnabled {
|
||||
udpConn := packetConn.(*net.UDPConn)
|
||||
networkManager := service.FromContext[adapter.NetworkManager](s.ctx)
|
||||
egressPool := tun.NewUDPEgressPool(tun.UDPEgressPoolOptions{
|
||||
Logger: s.logger,
|
||||
Network: M.NetworkFromNetAddr(N.NetworkUDP, listenAddress),
|
||||
Control: listenConfig.Control,
|
||||
InterfaceFinder: networkManager.InterfaceFinder(),
|
||||
InterfaceMonitor: networkManager.InterfaceMonitor(),
|
||||
ExcludeInterface: s.options.Name,
|
||||
IsExempt: func() bool {
|
||||
return networkManager.AutoRedirectOutputMark() != 0
|
||||
},
|
||||
})
|
||||
listenPort := udpConn.LocalAddr().(*net.UDPAddr).AddrPort().Port()
|
||||
if egressPool.SetEgressPort(listenPort) {
|
||||
packetConn = &udpEgressPacketConn{tun.NewUDPEgressConn(udpConn, egressPool)}
|
||||
} else {
|
||||
egressPool.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
serverOptions := s.serverOptions
|
||||
if streamListener != nil {
|
||||
serverOptions.Transport.ListenAddress = streamListener.Addr().String()
|
||||
} else if packetConn != nil {
|
||||
serverOptions.Transport.ListenAddress = packetConn.LocalAddr().String()
|
||||
}
|
||||
serverOptions.Transport.Listener = streamListener
|
||||
serverOptions.Transport.PacketConn = packetConn
|
||||
server, err := ovpn.NewServer(serverOptions)
|
||||
if err != nil {
|
||||
if packetConn != nil {
|
||||
_ = packetConn.Close()
|
||||
}
|
||||
s.listener.Close()
|
||||
return err
|
||||
}
|
||||
s.server = server
|
||||
err = s.device.Start()
|
||||
if err != nil {
|
||||
s.listener.Close()
|
||||
server.Close()
|
||||
return err
|
||||
}
|
||||
err = server.Start()
|
||||
if err != nil {
|
||||
s.device.Close()
|
||||
s.listener.Close()
|
||||
server.Close()
|
||||
return err
|
||||
}
|
||||
s.started.Store(true)
|
||||
s.readLoopDone = make(chan struct{})
|
||||
go s.readLoop()
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildServerOptions(options option.OpenVPNServerEndpointOptions) (ovpn.ServerOptions, error) {
|
||||
if len(options.Address) == 0 {
|
||||
return ovpn.ServerOptions{}, E.New("missing OpenVPN server address")
|
||||
}
|
||||
if options.TLS == nil {
|
||||
return ovpn.ServerOptions{}, E.New("missing `tls` options")
|
||||
}
|
||||
err := validateServerAddresses(options.Address)
|
||||
if err != nil {
|
||||
return ovpn.ServerOptions{}, err
|
||||
}
|
||||
err = validateServerTopology(options.Topology)
|
||||
if err != nil {
|
||||
return ovpn.ServerOptions{}, err
|
||||
}
|
||||
protocol := options.Network
|
||||
if protocol == "" {
|
||||
protocol = N.NetworkUDP
|
||||
}
|
||||
switch protocol {
|
||||
case N.NetworkTCP, N.NetworkUDP:
|
||||
default:
|
||||
return ovpn.ServerOptions{}, E.New("unsupported OpenVPN network: ", protocol)
|
||||
}
|
||||
tlsOptions, keyDirection, err := buildServerTLSOptions(*options.TLS)
|
||||
if err != nil {
|
||||
return ovpn.ServerOptions{}, err
|
||||
}
|
||||
serverOptions := ovpn.ServerOptions{
|
||||
Mode: ovpn.ModeTLS,
|
||||
KeyDirection: keyDirection,
|
||||
Transport: ovpn.ServerTransportOptions{
|
||||
Protocol: protocol,
|
||||
},
|
||||
Resources: ovpn.ServerResourceOptions{
|
||||
MaxClients: options.MaxClients,
|
||||
},
|
||||
DataChannel: ovpn.ServerDataChannelOptions{
|
||||
MTU: options.MTU,
|
||||
Ciphers: []string(options.DataCiphers),
|
||||
FallbackCipher: options.DataCiphersFallback,
|
||||
Auth: options.Auth,
|
||||
PacketHeadroom: ovpntransport.PacketHeadroom,
|
||||
},
|
||||
TLS: tlsOptions,
|
||||
Timing: ovpn.ServerTimingOptions{
|
||||
RenegotiationInterval: time.Duration(options.RenegotiateInterval),
|
||||
},
|
||||
}
|
||||
applyServerPushOptions(&serverOptions, options)
|
||||
return serverOptions, nil
|
||||
}
|
||||
|
||||
func buildServerTLSOptions(options option.OpenVPNInboundTLSOptions) (ovpn.ServerTLSOptions, int, error) {
|
||||
switch options.VerifyClientCertificate {
|
||||
case "", "require", "optional", "none":
|
||||
default:
|
||||
return ovpn.ServerTLSOptions{}, 0, E.New("invalid OpenVPN client certificate policy ", options.VerifyClientCertificate, ", allowed values: require, optional, none")
|
||||
}
|
||||
certificate, err := requiredMaterialSource("tls.certificate", options.Certificate, options.CertificatePath)
|
||||
if err != nil {
|
||||
return ovpn.ServerTLSOptions{}, 0, err
|
||||
}
|
||||
key, err := requiredMaterialSource("tls.key", options.Key, options.KeyPath)
|
||||
if err != nil {
|
||||
return ovpn.ServerTLSOptions{}, 0, err
|
||||
}
|
||||
certificateAuthority, err := requiredMaterialSource("tls.client_certificate", options.ClientCertificate, options.ClientCertificatePath)
|
||||
if err != nil {
|
||||
return ovpn.ServerTLSOptions{}, 0, err
|
||||
}
|
||||
tlsOptions := ovpn.ServerTLSOptions{
|
||||
CertificateAuthority: certificateAuthority,
|
||||
Certificate: certificate,
|
||||
Key: key,
|
||||
VerifyClientCertificate: options.VerifyClientCertificate,
|
||||
}
|
||||
keyDirection := -1
|
||||
controlWrap := options.ControlWrap
|
||||
if controlWrap != nil && (controlWrap.Type != "" || len(controlWrap.Key) > 0 || controlWrap.KeyPath != "" || controlWrap.Direction != "") {
|
||||
wrapKey, wrapErr := requiredMaterialSource("tls.control_wrap.key", controlWrap.Key, controlWrap.KeyPath)
|
||||
if wrapErr != nil {
|
||||
return ovpn.ServerTLSOptions{}, 0, wrapErr
|
||||
}
|
||||
switch controlWrap.Type {
|
||||
case "tls_auth":
|
||||
keyDirection, err = keyDirectionValue(controlWrap.Direction)
|
||||
if err != nil {
|
||||
return ovpn.ServerTLSOptions{}, 0, err
|
||||
}
|
||||
tlsOptions.Auth = wrapKey
|
||||
case "tls_crypt", "tls_crypt_v2":
|
||||
if controlWrap.Direction != "" {
|
||||
return ovpn.ServerTLSOptions{}, 0, E.New("`tls.control_wrap.direction` is only supported by `tls_auth`")
|
||||
}
|
||||
if controlWrap.Type == "tls_crypt" {
|
||||
tlsOptions.Crypt = wrapKey
|
||||
} else {
|
||||
tlsOptions.CryptV2 = wrapKey
|
||||
}
|
||||
case "":
|
||||
return ovpn.ServerTLSOptions{}, 0, E.New("missing OpenVPN control wrap type")
|
||||
default:
|
||||
return ovpn.ServerTLSOptions{}, 0, E.New("unknown OpenVPN control wrap type: ", controlWrap.Type)
|
||||
}
|
||||
}
|
||||
return tlsOptions, keyDirection, nil
|
||||
}
|
||||
|
||||
func applyServerPushOptions(serverOptions *ovpn.ServerOptions, options option.OpenVPNServerEndpointOptions) {
|
||||
topology := options.Topology
|
||||
if topology == "" {
|
||||
topology = "subnet"
|
||||
}
|
||||
localAddresses := make([]netip.Prefix, 0, len(options.Address))
|
||||
for _, prefix := range options.Address {
|
||||
if !prefix.IsValid() {
|
||||
continue
|
||||
}
|
||||
if prefix.Addr().Is4() {
|
||||
localAddresses = append(localAddresses, netip.PrefixFrom(prefix.Addr(), 32))
|
||||
} else {
|
||||
localAddresses = append(localAddresses, netip.PrefixFrom(prefix.Addr(), 128))
|
||||
}
|
||||
}
|
||||
serverOptions.Tunnel = ovpn.ServerTunnelOptions{
|
||||
AddressPools: slices.Clone(options.Address),
|
||||
Topology: topology,
|
||||
LocalAddress: localAddresses,
|
||||
}
|
||||
serverOptions.Push = ovpn.ServerPushOptions{
|
||||
PingInterval: time.Duration(options.KeepaliveInterval),
|
||||
PingRestart: time.Duration(options.KeepaliveTimeout),
|
||||
}
|
||||
if options.Push == nil {
|
||||
return
|
||||
}
|
||||
serverOptions.Push.Routes = slices.Clone(options.Push.Routes)
|
||||
serverOptions.Push.DNS = slices.Clone(options.Push.DNS)
|
||||
serverOptions.Push.BlockOutsideDNS = options.Push.BlockOutsideDNS
|
||||
if options.Push.RedirectGateway {
|
||||
serverOptions.Push.RedirectGateway = true
|
||||
if len(options.Push.RedirectGatewayFlags) > 0 {
|
||||
serverOptions.Push.RedirectGatewayFlags = slices.Clone(options.Push.RedirectGatewayFlags)
|
||||
} else {
|
||||
serverOptions.Push.RedirectGatewayFlags = []string{"def1"}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) readLoop() {
|
||||
defer close(s.readLoopDone)
|
||||
for {
|
||||
serverPacketBuffers, err := s.server.ReadDataPackets(s.loopContext)
|
||||
if err != nil {
|
||||
if E.IsClosedOrCanceled(err) || s.loopContext.Err() != nil {
|
||||
return
|
||||
}
|
||||
s.logger.Error(E.Cause(err, "OpenVPN server terminated"))
|
||||
return
|
||||
}
|
||||
packetBuffers := make([]*buf.Buffer, len(serverPacketBuffers))
|
||||
for i, packetBuffer := range serverPacketBuffers {
|
||||
packetBuffers[i] = packetBuffer.Buffer
|
||||
}
|
||||
err = s.device.WriteInboundBuffers(packetBuffers)
|
||||
buf.ReleaseMulti(packetBuffers)
|
||||
if err != nil {
|
||||
s.logger.Error(E.Cause(err, "write OpenVPN packet to device"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) Close() error {
|
||||
s.started.Store(false)
|
||||
s.cancelLoop()
|
||||
var serverErr error
|
||||
if s.server != nil {
|
||||
serverErr = s.server.Close()
|
||||
}
|
||||
if s.readLoopDone != nil {
|
||||
<-s.readLoopDone
|
||||
}
|
||||
var deviceErr error
|
||||
if s.device != nil {
|
||||
deviceErr = s.device.Close()
|
||||
}
|
||||
var listenerErr error
|
||||
if s.listener != nil {
|
||||
listenerErr = s.listener.Close()
|
||||
}
|
||||
return E.Errors(serverErr, deviceErr, listenerErr)
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) PreMatchFlow(network string, destination netip.Addr) adapter.PreMatchAction {
|
||||
return adapter.PreMatchFlow
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) PortAddresses() (netip.Addr, netip.Addr) {
|
||||
return s.device.PortAddresses()
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) PortMTU() uint32 {
|
||||
return s.device.PortMTU()
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) AttachReturn(returnPath tun.Return) error {
|
||||
return s.device.AttachReturn(returnPath)
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) DetachReturn(returnPath tun.Return) error {
|
||||
return s.device.DetachReturn(returnPath)
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) JudgeFlow(network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
return judgeOpenVPNFlow(s.router, s.Tag(), s.Type(), s.localAddresses, network, source, destination, firstPacket)
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) WritePackets(packets [][]byte) error {
|
||||
if !s.started.Load() {
|
||||
return E.New("OpenVPN server is not ready yet")
|
||||
}
|
||||
packetBuffers := make([]*buf.Buffer, len(packets))
|
||||
for i, packet := range packets {
|
||||
packetBuffers[i] = buf.As(packet)
|
||||
}
|
||||
routeMisses, err := s.server.WriteDataPacketBuffersByDestination(packetBuffers)
|
||||
if len(routeMisses) > 0 {
|
||||
s.writeRouteMisses(routeMisses)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) writePacketBuffersByDestination(packetBuffers []*buf.Buffer) error {
|
||||
routeMisses, err := s.server.WriteDataPacketBuffersByDestination(packetBuffers)
|
||||
if len(routeMisses) > 0 {
|
||||
s.writeRouteMisses(routeMisses)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) writeRouteMisses(routeMisses []*ovpn.RouteMissError) {
|
||||
returnPath, headroom := s.device.ReturnPath()
|
||||
if returnPath == nil {
|
||||
return
|
||||
}
|
||||
inet4Address, inet6Address := s.PortAddresses()
|
||||
replies := make([][]byte, 0, len(routeMisses))
|
||||
for _, routeMiss := range routeMisses {
|
||||
sourceAddress := packetSourceAddress(routeMiss.Packet, inet4Address, inet6Address)
|
||||
reply, built := tun.BuildUnreachable(routeMiss.Packet, sourceAddress, headroom)
|
||||
if built {
|
||||
replies = append(replies, reply)
|
||||
}
|
||||
}
|
||||
if len(replies) > 0 {
|
||||
returnPath.ReturnPackets(replies)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
|
||||
s.newConnection(ctx, s, s.localAddresses, conn, source, destination, onClose)
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
|
||||
s.newPacketConnection(ctx, s, s.localAddresses, conn, source, destination, onClose)
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
switch network {
|
||||
case N.NetworkTCP:
|
||||
s.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||
case N.NetworkUDP:
|
||||
s.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||
}
|
||||
if !s.started.Load() {
|
||||
return nil, E.New("OpenVPN server is not ready yet")
|
||||
}
|
||||
if destination.IsDomain() {
|
||||
destinationAddresses, err := s.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return N.DialSerial(ctx, s.device, network, destination, destinationAddresses)
|
||||
}
|
||||
if !destination.Addr.IsValid() {
|
||||
return nil, E.New("invalid destination: ", destination)
|
||||
}
|
||||
return s.device.DialContext(ctx, network, destination)
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) ListenPacketWithDestination(ctx context.Context, destination M.Socksaddr) (net.PacketConn, netip.Addr, error) {
|
||||
s.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||
if !s.started.Load() {
|
||||
return nil, netip.Addr{}, E.New("OpenVPN server is not ready yet")
|
||||
}
|
||||
if destination.IsDomain() {
|
||||
destinationAddresses, err := s.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{})
|
||||
if err != nil {
|
||||
return nil, netip.Addr{}, err
|
||||
}
|
||||
return N.ListenSerial(ctx, s.device, destination, destinationAddresses)
|
||||
}
|
||||
packetConn, err := s.device.ListenPacket(ctx, destination)
|
||||
if err != nil {
|
||||
return nil, netip.Addr{}, err
|
||||
}
|
||||
if destination.IsIP() {
|
||||
return packetConn, destination.Addr, nil
|
||||
}
|
||||
return packetConn, netip.Addr{}, nil
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
packetConn, _, err := s.ListenPacketWithDestination(ctx, destination)
|
||||
return packetConn, err
|
||||
}
|
||||
Reference in New Issue
Block a user