mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-16 07:16:38 +00:00
Support client default routes for Linux (#1667)
All routes are now installed in a custom netbird routing table. Management and wireguard traffic is now marked with a custom fwmark. When the mark is present the traffic is routed via the main routing table, bypassing the VPN. When the mark is absent the traffic is routed via the netbird routing table, if: - there's no match in the main routing table - it would match the default route in the routing table IPv6 traffic is blocked when a default route IPv4 route is configured to avoid leakage.
This commit is contained in:
9
util/grpc/dialer_generic.go
Normal file
9
util/grpc/dialer_generic.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build !linux || android
|
||||
|
||||
package grpc
|
||||
|
||||
import "google.golang.org/grpc"
|
||||
|
||||
func WithCustomDialer() grpc.DialOption {
|
||||
return grpc.EmptyDialOption{}
|
||||
}
|
||||
18
util/grpc/dialer_linux.go
Normal file
18
util/grpc/dialer_linux.go
Normal file
@@ -0,0 +1,18 @@
|
||||
//go:build !android
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
nbnet "github.com/netbirdio/netbird/util/net"
|
||||
)
|
||||
|
||||
func WithCustomDialer() grpc.DialOption {
|
||||
return grpc.WithContextDialer(func(ctx context.Context, addr string) (net.Conn, error) {
|
||||
return nbnet.NewDialer().DialContext(ctx, "tcp", addr)
|
||||
})
|
||||
}
|
||||
19
util/net/dialer_generic.go
Normal file
19
util/net/dialer_generic.go
Normal file
@@ -0,0 +1,19 @@
|
||||
//go:build !linux || android
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func NewDialer() *net.Dialer {
|
||||
return &net.Dialer{}
|
||||
}
|
||||
|
||||
func DialUDP(network string, laddr, raddr *net.UDPAddr) (*net.UDPConn, error) {
|
||||
return net.DialUDP(network, laddr, raddr)
|
||||
}
|
||||
|
||||
func DialTCP(network string, laddr, raddr *net.TCPAddr) (*net.TCPConn, error) {
|
||||
return net.DialTCP(network, laddr, raddr)
|
||||
}
|
||||
60
util/net/dialer_linux.go
Normal file
60
util/net/dialer_linux.go
Normal file
@@ -0,0 +1,60 @@
|
||||
//go:build !android
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func NewDialer() *net.Dialer {
|
||||
return &net.Dialer{
|
||||
Control: func(network, address string, c syscall.RawConn) error {
|
||||
return SetRawSocketMark(c)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func DialUDP(network string, laddr, raddr *net.UDPAddr) (*net.UDPConn, error) {
|
||||
dialer := NewDialer()
|
||||
dialer.LocalAddr = laddr
|
||||
|
||||
conn, err := dialer.DialContext(context.Background(), network, raddr.String())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dialing UDP %s: %w", raddr.String(), err)
|
||||
}
|
||||
|
||||
udpConn, ok := conn.(*net.UDPConn)
|
||||
if !ok {
|
||||
if err := conn.Close(); err != nil {
|
||||
log.Errorf("Failed to close connection: %v", err)
|
||||
}
|
||||
return nil, fmt.Errorf("expected UDP connection, got different type")
|
||||
}
|
||||
|
||||
return udpConn, nil
|
||||
}
|
||||
|
||||
func DialTCP(network string, laddr, raddr *net.TCPAddr) (*net.TCPConn, error) {
|
||||
dialer := NewDialer()
|
||||
dialer.LocalAddr = laddr
|
||||
|
||||
conn, err := dialer.DialContext(context.Background(), network, raddr.String())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dialing TCP %s: %w", raddr.String(), err)
|
||||
}
|
||||
|
||||
tcpConn, ok := conn.(*net.TCPConn)
|
||||
if !ok {
|
||||
if err := conn.Close(); err != nil {
|
||||
log.Errorf("Failed to close connection: %v", err)
|
||||
}
|
||||
return nil, fmt.Errorf("expected TCP connection, got different type")
|
||||
}
|
||||
|
||||
return tcpConn, nil
|
||||
}
|
||||
13
util/net/listener_generic.go
Normal file
13
util/net/listener_generic.go
Normal file
@@ -0,0 +1,13 @@
|
||||
//go:build !linux || android
|
||||
|
||||
package net
|
||||
|
||||
import "net"
|
||||
|
||||
func NewListener() *net.ListenConfig {
|
||||
return &net.ListenConfig{}
|
||||
}
|
||||
|
||||
func ListenUDP(network string, locAddr *net.UDPAddr) (*net.UDPConn, error) {
|
||||
return net.ListenUDP(network, locAddr)
|
||||
}
|
||||
30
util/net/listener_linux.go
Normal file
30
util/net/listener_linux.go
Normal file
@@ -0,0 +1,30 @@
|
||||
//go:build !android
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func NewListener() *net.ListenConfig {
|
||||
return &net.ListenConfig{
|
||||
Control: func(network, address string, c syscall.RawConn) error {
|
||||
return SetRawSocketMark(c)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ListenUDP(network string, laddr *net.UDPAddr) (*net.UDPConn, error) {
|
||||
pc, err := NewListener().ListenPacket(context.Background(), network, laddr.String())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listening on %s:%s with fwmark: %w", network, laddr, err)
|
||||
}
|
||||
udpConn, ok := pc.(*net.UDPConn)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("packetConn is not a *net.UDPConn")
|
||||
}
|
||||
return udpConn, nil
|
||||
}
|
||||
6
util/net/net.go
Normal file
6
util/net/net.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package net
|
||||
|
||||
const (
|
||||
// NetbirdFwmark is the fwmark value used by Netbird via wireguard
|
||||
NetbirdFwmark = 0x1BD00
|
||||
)
|
||||
35
util/net/net_linux.go
Normal file
35
util/net/net_linux.go
Normal file
@@ -0,0 +1,35 @@
|
||||
//go:build !android
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// SetSocketMark sets the SO_MARK option on the given socket connection
|
||||
func SetSocketMark(conn syscall.Conn) error {
|
||||
sysconn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return fmt.Errorf("get raw conn: %w", err)
|
||||
}
|
||||
|
||||
return SetRawSocketMark(sysconn)
|
||||
}
|
||||
|
||||
func SetRawSocketMark(conn syscall.RawConn) error {
|
||||
var setErr error
|
||||
|
||||
err := conn.Control(func(fd uintptr) {
|
||||
setErr = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, NetbirdFwmark)
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("control: %w", err)
|
||||
}
|
||||
|
||||
if setErr != nil {
|
||||
return fmt.Errorf("set SO_MARK: %w", setErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user