hysteria/app/internal/sockopts/sockopts.go
Haruue 3e34da1aa8
refactor: protect => quic.sockopts
Android's VpnService.protect() itself is confusing, so we rename the
"protect" feature with the name `fdControlUnixSocket` and make it a
sub-option under `quic.sockopts`.

A unit test is added to make sure the protect feature works.

I also added two other common options to `quic.sockopts` that I copied
from my other projects but did not fully test here.
2024-04-05 02:20:45 +08:00

76 lines
1.9 KiB
Go

package sockopts
import (
"fmt"
"net"
)
type SocketOptions struct {
BindInterface *string
FirewallMark *uint32
FdControlUnixSocket *string
}
// implemented in platform-specific files
var (
bindInterfaceFunc func(c *net.UDPConn, device string) error
firewallMarkFunc func(c *net.UDPConn, fwmark uint32) error
fdControlUnixSocketFunc func(c *net.UDPConn, path string) error
)
func (o *SocketOptions) CheckSupported() (err error) {
if o.BindInterface != nil && bindInterfaceFunc == nil {
return &UnsupportedError{"bindInterface"}
}
if o.FirewallMark != nil && firewallMarkFunc == nil {
return &UnsupportedError{"fwmark"}
}
if o.FdControlUnixSocket != nil && fdControlUnixSocketFunc == nil {
return &UnsupportedError{"fdControlUnixSocket"}
}
return nil
}
type UnsupportedError struct {
Field string
}
func (e *UnsupportedError) Error() string {
return fmt.Sprintf("%s is not supported on this platform", e.Field)
}
func (o *SocketOptions) ListenUDP() (uconn net.PacketConn, err error) {
uconn, err = net.ListenUDP("udp", nil)
if err != nil {
return
}
err = o.applyToUDPConn(uconn.(*net.UDPConn))
if err != nil {
uconn.Close()
uconn = nil
return
}
return
}
func (o *SocketOptions) applyToUDPConn(c *net.UDPConn) (err error) {
if o.BindInterface != nil && bindInterfaceFunc != nil {
err = bindInterfaceFunc(c, *o.BindInterface)
if err != nil {
err = fmt.Errorf("failed to bind to interface: %w", err)
}
}
if o.FirewallMark != nil && firewallMarkFunc != nil {
err = firewallMarkFunc(c, *o.FirewallMark)
if err != nil {
err = fmt.Errorf("failed to set fwmark: %w", err)
}
}
if o.FdControlUnixSocket != nil && fdControlUnixSocketFunc != nil {
err = fdControlUnixSocketFunc(c, *o.FdControlUnixSocket)
if err != nil {
err = fmt.Errorf("failed to send fd to control unix socket: %w", err)
}
}
return
}