mirror of
https://github.com/tailscale/tailscale.git
synced 2026-05-08 21:56:48 +02:00
lanscaping: remove some localapi handlers, raw disco mode on linux
-rwxr-xr-x@ 1 bradfitz staff 10058498 Jan 11 11:45 /Users/bradfitz/bin/tailscaled.min -rwxr-xr-x@ 1 bradfitz staff 9961624 Jan 11 11:45 /Users/bradfitz/bin/tailscaled.minlinux Change-Id: I5c456b1f98144bd90eda699563773f02ad8b6580 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
23b3ebeaa9
commit
28a010dd4c
@ -8,7 +8,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
@ -22,8 +21,6 @@ import (
|
||||
"time"
|
||||
|
||||
"tailscale.com/client/tailscale/apitype"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/hostinfo"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/ipnauth"
|
||||
"tailscale.com/ipn/ipnlocal"
|
||||
@ -36,8 +33,6 @@ import (
|
||||
"tailscale.com/types/ptr"
|
||||
"tailscale.com/util/clientmetric"
|
||||
"tailscale.com/util/httpm"
|
||||
"tailscale.com/util/mak"
|
||||
"tailscale.com/util/rands"
|
||||
"tailscale.com/version"
|
||||
)
|
||||
|
||||
@ -52,25 +47,20 @@ var handler = map[string]localAPIHandler{
|
||||
|
||||
// The other /localapi/v0/NAME handlers are exact matches and contain only NAME
|
||||
// without a trailing slash:
|
||||
"alpha-set-device-attrs": (*Handler).serveSetDeviceAttrs, // see tailscale/corp#24690
|
||||
"bugreport": (*Handler).serveBugReport,
|
||||
"check-ip-forwarding": (*Handler).serveCheckIPForwarding,
|
||||
"check-prefs": (*Handler).serveCheckPrefs,
|
||||
"disconnect-control": (*Handler).disconnectControl,
|
||||
"goroutines": (*Handler).serveGoroutines,
|
||||
"id-token": (*Handler).serveIDToken,
|
||||
"login-interactive": (*Handler).serveLoginInteractive,
|
||||
"logout": (*Handler).serveLogout,
|
||||
"metrics": (*Handler).serveMetrics,
|
||||
"prefs": (*Handler).servePrefs,
|
||||
"query-feature": (*Handler).serveQueryFeature,
|
||||
"reload-config": (*Handler).reloadConfig,
|
||||
"reset-auth": (*Handler).serveResetAuth,
|
||||
"start": (*Handler).serveStart,
|
||||
"status": (*Handler).serveStatus,
|
||||
"suggest-exit-node": (*Handler).serveSuggestExitNode,
|
||||
"watch-ipn-bus": (*Handler).serveWatchIPNBus,
|
||||
"whois": (*Handler).serveWhoIs,
|
||||
"check-prefs": (*Handler).serveCheckPrefs,
|
||||
"disconnect-control": (*Handler).disconnectControl,
|
||||
"goroutines": (*Handler).serveGoroutines,
|
||||
"login-interactive": (*Handler).serveLoginInteractive,
|
||||
"logout": (*Handler).serveLogout,
|
||||
"metrics": (*Handler).serveMetrics,
|
||||
"prefs": (*Handler).servePrefs,
|
||||
"query-feature": (*Handler).serveQueryFeature,
|
||||
"reload-config": (*Handler).reloadConfig,
|
||||
"reset-auth": (*Handler).serveResetAuth,
|
||||
"start": (*Handler).serveStart,
|
||||
"status": (*Handler).serveStatus,
|
||||
"watch-ipn-bus": (*Handler).serveWatchIPNBus,
|
||||
"whois": (*Handler).serveWhoIs,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -209,183 +199,10 @@ func (*Handler) serveLocalAPIRoot(w http.ResponseWriter, r *http.Request) {
|
||||
io.WriteString(w, "tailscaled\n")
|
||||
}
|
||||
|
||||
// serveIDToken handles requests to get an OIDC ID token.
|
||||
func (h *Handler) serveIDToken(w http.ResponseWriter, r *http.Request) {
|
||||
if !h.PermitWrite {
|
||||
http.Error(w, "id-token access denied", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
nm := h.b.NetMap()
|
||||
if nm == nil {
|
||||
http.Error(w, "no netmap", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
aud := strings.TrimSpace(r.FormValue("aud"))
|
||||
if len(aud) == 0 {
|
||||
http.Error(w, "no audience requested", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
req := &tailcfg.TokenRequest{
|
||||
CapVersion: tailcfg.CurrentCapabilityVersion,
|
||||
Audience: aud,
|
||||
NodeKey: nm.NodeKey,
|
||||
}
|
||||
b, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
httpReq, err := http.NewRequest("POST", "https://unused/machine/id-token", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
resp, err := h.b.DoNoiseRequest(httpReq)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
w.WriteHeader(resp.StatusCode)
|
||||
if _, err := io.Copy(w, resp.Body); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) serveBugReport(w http.ResponseWriter, r *http.Request) {
|
||||
if !h.PermitRead {
|
||||
http.Error(w, "bugreport access denied", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
http.Error(w, "only POST allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
logMarker := func() string {
|
||||
return fmt.Sprintf("BUG-%v-%v-%v", h.backendLogID, h.clock.Now().UTC().Format("20060102150405Z"), rands.HexString(16))
|
||||
}
|
||||
if envknob.NoLogsNoSupport() {
|
||||
logMarker = func() string { return "BUG-NO-LOGS-NO-SUPPORT-this-node-has-had-its-logging-disabled" }
|
||||
}
|
||||
|
||||
startMarker := logMarker()
|
||||
h.logf("user bugreport: %s", startMarker)
|
||||
if note := r.URL.Query().Get("note"); len(note) > 0 {
|
||||
h.logf("user bugreport note: %s", note)
|
||||
}
|
||||
hi, _ := json.Marshal(hostinfo.New())
|
||||
h.logf("user bugreport hostinfo: %s", hi)
|
||||
if err := h.b.HealthTracker().OverallError(); err != nil {
|
||||
h.logf("user bugreport health: %s", err.Error())
|
||||
} else {
|
||||
h.logf("user bugreport health: ok")
|
||||
}
|
||||
|
||||
// Information about the current node from the netmap
|
||||
if nm := h.b.NetMap(); nm != nil {
|
||||
if self := nm.SelfNode; self.Valid() {
|
||||
h.logf("user bugreport node info: nodeid=%q stableid=%q expiry=%q", self.ID(), self.StableID(), self.KeyExpiry().Format(time.RFC3339))
|
||||
}
|
||||
h.logf("user bugreport public keys: machine=%q node=%q", nm.MachineKey, nm.NodeKey)
|
||||
} else {
|
||||
h.logf("user bugreport netmap: no active netmap")
|
||||
}
|
||||
|
||||
// Print all envknobs; we otherwise only print these on startup, and
|
||||
// printing them here ensures we don't have to go spelunking through
|
||||
// logs for them.
|
||||
envknob.LogCurrent(logger.WithPrefix(h.logf, "user bugreport: "))
|
||||
|
||||
if defBool(r.URL.Query().Get("diagnose"), false) {
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
fmt.Fprintln(w, startMarker)
|
||||
|
||||
// Nothing else to do if we're not in record mode; we wrote the marker
|
||||
// above, so we can just finish our response now.
|
||||
if !defBool(r.URL.Query().Get("record"), false) {
|
||||
return
|
||||
}
|
||||
|
||||
until := h.clock.Now().Add(12 * time.Hour)
|
||||
|
||||
var changed map[string]bool
|
||||
for _, component := range []string{"magicsock"} {
|
||||
if h.b.GetComponentDebugLogging(component).IsZero() {
|
||||
if err := h.b.SetComponentDebugLogging(component, until); err != nil {
|
||||
h.logf("bugreport: error setting component %q logging: %v", component, err)
|
||||
continue
|
||||
}
|
||||
|
||||
mak.Set(&changed, component, true)
|
||||
}
|
||||
}
|
||||
defer func() {
|
||||
for component := range changed {
|
||||
h.b.SetComponentDebugLogging(component, time.Time{})
|
||||
}
|
||||
}()
|
||||
|
||||
// NOTE(andrew): if we have anything else we want to do while recording
|
||||
// a bugreport, we can add it here.
|
||||
|
||||
// Read from the client; this will also return when the client closes
|
||||
// the connection.
|
||||
var buf [1]byte
|
||||
_, err := r.Body.Read(buf[:])
|
||||
|
||||
switch {
|
||||
case err == nil:
|
||||
// good
|
||||
case errors.Is(err, io.EOF):
|
||||
// good
|
||||
case errors.Is(err, io.ErrUnexpectedEOF):
|
||||
// this happens when Ctrl-C'ing the tailscale client; don't
|
||||
// bother logging an error
|
||||
default:
|
||||
// Log but continue anyway.
|
||||
h.logf("user bugreport: error reading body: %v", err)
|
||||
}
|
||||
|
||||
// Generate another log marker and return it to the client.
|
||||
endMarker := logMarker()
|
||||
h.logf("user bugreport end: %s", endMarker)
|
||||
fmt.Fprintln(w, endMarker)
|
||||
}
|
||||
|
||||
func (h *Handler) serveWhoIs(w http.ResponseWriter, r *http.Request) {
|
||||
h.serveWhoIsWithBackend(w, r, h.b)
|
||||
}
|
||||
|
||||
// serveSetDeviceAttrs is (as of 2024-12-30) an experimental LocalAPI handler to
|
||||
// set device attributes via the control plane.
|
||||
//
|
||||
// See tailscale/corp#24690.
|
||||
func (h *Handler) serveSetDeviceAttrs(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
if !h.PermitWrite {
|
||||
http.Error(w, "set-device-attrs access denied", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
if r.Method != "PATCH" {
|
||||
http.Error(w, "only PATCH allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
var req map[string]any
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if err := h.b.SetDeviceAttrs(ctx, req); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
io.WriteString(w, "{}\n")
|
||||
}
|
||||
|
||||
// localBackendWhoIsMethods is the subset of ipn.LocalBackend as needed
|
||||
// by the localapi WhoIs method.
|
||||
type localBackendWhoIsMethods interface {
|
||||
@ -560,23 +377,6 @@ func authorizeServeConfigForGOOSAndUserContext(goos string, configIn *ipn.ServeC
|
||||
|
||||
}
|
||||
|
||||
func (h *Handler) serveCheckIPForwarding(w http.ResponseWriter, r *http.Request) {
|
||||
if !h.PermitRead {
|
||||
http.Error(w, "IP forwarding check access denied", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
var warning string
|
||||
if err := h.b.CheckIPForwarding(); err != nil {
|
||||
warning = err.Error()
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(struct {
|
||||
Warning string
|
||||
}{
|
||||
Warning: warning,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) serveStatus(w http.ResponseWriter, r *http.Request) {
|
||||
if !h.PermitRead {
|
||||
http.Error(w, "status access denied", http.StatusForbidden)
|
||||
@ -997,18 +797,3 @@ var (
|
||||
metricDebugMetricsCalls = clientmetric.NewCounter("localapi_debugmetric_requests")
|
||||
metricUserMetricsCalls = clientmetric.NewCounter("localapi_usermetric_requests")
|
||||
)
|
||||
|
||||
// serveSuggestExitNode serves a POST endpoint for returning a suggested exit node.
|
||||
func (h *Handler) serveSuggestExitNode(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, "only GET allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
res, err := h.b.SuggestExitNode()
|
||||
if err != nil {
|
||||
writeErrorJSON(w, err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(res)
|
||||
}
|
||||
|
||||
@ -533,19 +533,6 @@ func NewConn(opts Options) (*Conn, error) {
|
||||
|
||||
c.metrics = registerMetrics(opts.Metrics)
|
||||
|
||||
if d4, err := c.listenRawDisco("ip4"); err == nil {
|
||||
c.logf("[v1] using BPF disco receiver for IPv4")
|
||||
c.closeDisco4 = d4
|
||||
} else if !errors.Is(err, errors.ErrUnsupported) {
|
||||
c.logf("[v1] couldn't create raw v4 disco listener, using regular listener instead: %v", err)
|
||||
}
|
||||
if d6, err := c.listenRawDisco("ip6"); err == nil {
|
||||
c.logf("[v1] using BPF disco receiver for IPv6")
|
||||
c.closeDisco6 = d6
|
||||
} else if !errors.Is(err, errors.ErrUnsupported) {
|
||||
c.logf("[v1] couldn't create raw v6 disco listener, using regular listener instead: %v", err)
|
||||
}
|
||||
|
||||
c.logf("magicsock: disco key = %v", c.discoShort)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
@ -4,17 +4,14 @@
|
||||
package magicsock
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/mdlayher/socket"
|
||||
"golang.org/x/net/bpf"
|
||||
@ -24,7 +21,6 @@ import (
|
||||
"golang.org/x/sys/unix"
|
||||
"tailscale.com/disco"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/net/netns"
|
||||
"tailscale.com/types/ipproto"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/logger"
|
||||
@ -164,117 +160,6 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// listenRawDisco starts listening for disco packets on the given
|
||||
// address family, which must be "ip4" or "ip6", using a raw socket
|
||||
// and BPF filter.
|
||||
// https://github.com/tailscale/tailscale/issues/3824
|
||||
func (c *Conn) listenRawDisco(family string) (io.Closer, error) {
|
||||
if !envknobEnableRawDisco() {
|
||||
// Return an 'errors.ErrUnsupported' to prevent the callee from
|
||||
// logging; when we switch this to an opt-out (vs. an opt-in),
|
||||
// drop the ErrUnsupported so that the callee logs that it was
|
||||
// disabled.
|
||||
return nil, fmt.Errorf("raw disco not enabled: %w", errors.ErrUnsupported)
|
||||
}
|
||||
|
||||
// https://github.com/tailscale/tailscale/issues/5607
|
||||
if !netns.UseSocketMark() {
|
||||
return nil, errors.New("raw disco listening disabled, SO_MARK unavailable")
|
||||
}
|
||||
|
||||
var (
|
||||
udpnet string
|
||||
addr string
|
||||
proto int
|
||||
testAddr netip.AddrPort
|
||||
prog []bpf.Instruction
|
||||
)
|
||||
switch family {
|
||||
case "ip4":
|
||||
udpnet = "udp4"
|
||||
addr = "0.0.0.0"
|
||||
proto = ethernetProtoIPv4()
|
||||
testAddr = netip.AddrPortFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), 1)
|
||||
prog = magicsockFilterV4
|
||||
case "ip6":
|
||||
udpnet = "udp6"
|
||||
addr = "::"
|
||||
proto = ethernetProtoIPv6()
|
||||
testAddr = netip.AddrPortFrom(netip.IPv6Loopback(), 1)
|
||||
prog = magicsockFilterV6
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported address family %q", family)
|
||||
}
|
||||
|
||||
asm, err := bpf.Assemble(prog)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("assembling filter: %w", err)
|
||||
}
|
||||
|
||||
sock, err := socket.Socket(
|
||||
unix.AF_PACKET,
|
||||
unix.SOCK_DGRAM,
|
||||
proto,
|
||||
"afpacket",
|
||||
nil, // no config
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating AF_PACKET socket: %w", err)
|
||||
}
|
||||
|
||||
if err := sock.SetBPF(asm); err != nil {
|
||||
sock.Close()
|
||||
return nil, fmt.Errorf("installing BPF filter: %w", err)
|
||||
}
|
||||
|
||||
// If all the above succeeds, we should be ready to receive. Just
|
||||
// out of paranoia, check that we do receive a well-formed disco
|
||||
// packet.
|
||||
tc, err := net.ListenPacket(udpnet, net.JoinHostPort(addr, "0"))
|
||||
if err != nil {
|
||||
sock.Close()
|
||||
return nil, fmt.Errorf("creating disco test socket: %w", err)
|
||||
}
|
||||
defer tc.Close()
|
||||
if _, err := tc.(*net.UDPConn).WriteToUDPAddrPort(testDiscoPacket, testAddr); err != nil {
|
||||
sock.Close()
|
||||
return nil, fmt.Errorf("writing disco test packet: %w", err)
|
||||
}
|
||||
|
||||
const selfTestTimeout = 100 * time.Millisecond
|
||||
if err := sock.SetReadDeadline(time.Now().Add(selfTestTimeout)); err != nil {
|
||||
sock.Close()
|
||||
return nil, fmt.Errorf("setting socket timeout: %w", err)
|
||||
}
|
||||
|
||||
var (
|
||||
ctx = context.Background()
|
||||
buf [1500]byte
|
||||
)
|
||||
for {
|
||||
n, _, err := sock.Recvfrom(ctx, buf[:], 0)
|
||||
if err != nil {
|
||||
sock.Close()
|
||||
return nil, fmt.Errorf("reading during raw disco self-test: %w", err)
|
||||
}
|
||||
|
||||
_ /* src */, _ /* dst */, payload := parseUDPPacket(buf[:n], family == "ip6")
|
||||
if payload == nil {
|
||||
continue
|
||||
}
|
||||
if !bytes.Equal(payload, testDiscoPacket) {
|
||||
c.discoLogf("listenRawDisco: self-test: received mismatched UDP packet of %d bytes", len(payload))
|
||||
continue
|
||||
}
|
||||
c.logf("[v1] listenRawDisco: self-test passed for %s", family)
|
||||
break
|
||||
}
|
||||
sock.SetReadDeadline(time.Time{})
|
||||
|
||||
go c.receiveDisco(sock, family == "ip6")
|
||||
return sock, nil
|
||||
}
|
||||
|
||||
// parseUDPPacket is a basic parser for UDP packets that returns the source and
|
||||
// destination addresses, and the payload. The returned payload is a sub-slice
|
||||
// of the input buffer.
|
||||
|
||||
@ -549,106 +549,6 @@ func (r *linuxRouter) setNetfilterMode(mode preftype.NetfilterMode) error {
|
||||
|
||||
switch mode {
|
||||
case netfilterOff:
|
||||
switch r.netfilterMode {
|
||||
case netfilterNoDivert:
|
||||
if err := r.nfr.DelBase(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.nfr.DelChains(); err != nil {
|
||||
r.logf("note: %v", err)
|
||||
// harmless, continue.
|
||||
// This can happen if someone left a ref to
|
||||
// this table somewhere else.
|
||||
}
|
||||
case netfilterOn:
|
||||
if err := r.nfr.DelHooks(r.logf); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.nfr.DelBase(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.nfr.DelChains(); err != nil {
|
||||
r.logf("note: %v", err)
|
||||
// harmless, continue.
|
||||
// This can happen if someone left a ref to
|
||||
// this table somewhere else.
|
||||
}
|
||||
}
|
||||
r.snatSubnetRoutes = false
|
||||
case netfilterNoDivert:
|
||||
switch r.netfilterMode {
|
||||
case netfilterOff:
|
||||
reprocess = true
|
||||
if err := r.nfr.AddChains(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.nfr.AddBase(r.tunname); err != nil {
|
||||
return err
|
||||
}
|
||||
if r.magicsockPortV4 != 0 {
|
||||
if err := r.nfr.AddMagicsockPortRule(r.magicsockPortV4, "udp4"); err != nil {
|
||||
return fmt.Errorf("could not add magicsock port rule v4: %w", err)
|
||||
}
|
||||
}
|
||||
if r.magicsockPortV6 != 0 && r.getV6FilteringAvailable() {
|
||||
if err := r.nfr.AddMagicsockPortRule(r.magicsockPortV6, "udp6"); err != nil {
|
||||
return fmt.Errorf("could not add magicsock port rule v6: %w", err)
|
||||
}
|
||||
}
|
||||
r.snatSubnetRoutes = false
|
||||
case netfilterOn:
|
||||
if err := r.nfr.DelHooks(r.logf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case netfilterOn:
|
||||
// Because of bugs in old version of iptables-compat,
|
||||
// we can't add a "-j ts-forward" rule to FORWARD
|
||||
// while ts-forward contains an "-m mark" rule. But
|
||||
// we can add the row *before* populating ts-forward.
|
||||
// So we have to delBase, then add the hooks,
|
||||
// then re-addBase, just in case.
|
||||
switch r.netfilterMode {
|
||||
case netfilterOff:
|
||||
reprocess = true
|
||||
if err := r.nfr.AddChains(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.nfr.DelBase(); err != nil {
|
||||
return err
|
||||
}
|
||||
// AddHooks adds the ts loopback rule.
|
||||
if err := r.nfr.AddHooks(); err != nil {
|
||||
return err
|
||||
}
|
||||
// AddBase adds base ts rules
|
||||
if err := r.nfr.AddBase(r.tunname); err != nil {
|
||||
return err
|
||||
}
|
||||
if r.magicsockPortV4 != 0 {
|
||||
if err := r.nfr.AddMagicsockPortRule(r.magicsockPortV4, "udp4"); err != nil {
|
||||
return fmt.Errorf("could not add magicsock port rule v4: %w", err)
|
||||
}
|
||||
}
|
||||
if r.magicsockPortV6 != 0 && r.getV6FilteringAvailable() {
|
||||
if err := r.nfr.AddMagicsockPortRule(r.magicsockPortV6, "udp6"); err != nil {
|
||||
return fmt.Errorf("could not add magicsock port rule v6: %w", err)
|
||||
}
|
||||
}
|
||||
r.snatSubnetRoutes = false
|
||||
case netfilterNoDivert:
|
||||
reprocess = true
|
||||
if err := r.nfr.DelBase(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.nfr.AddHooks(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.nfr.AddBase(r.tunname); err != nil {
|
||||
return err
|
||||
}
|
||||
r.snatSubnetRoutes = false
|
||||
}
|
||||
default:
|
||||
panic("unhandled netfilter mode")
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user