Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/magiconair/properties v1.8.10
github.com/spf13/pflag v1.0.10
github.com/spf13/viper v1.21.0
golang.org/x/sys v0.29.0
)

require (
Expand All @@ -22,6 +23,5 @@ require (
github.com/spf13/cast v1.10.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.28.0 // indirect
)
1 change: 1 addition & 0 deletions frontend/lgproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type channelData struct {
func createConnectionTimeoutRoundTripper(timeout int) http.RoundTripper {
context := net.Dialer{
Timeout: time.Duration(timeout) * time.Second,
Control: vrfControl(setting.vrf),
}

// Prefer httpmock's transport if activated, so unit tests can work
Expand Down
5 changes: 4 additions & 1 deletion frontend/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"net"
"os"
"strings"
Expand All @@ -27,6 +28,7 @@ type settingType struct {
timeOut int
connectionTimeOut int
trustProxyHeaders bool
vrf string
}

var setting settingType
Expand All @@ -48,7 +50,8 @@ func main() {
if !strings.Contains(listenAddr, ":") {
listenAddr = ":" + listenAddr
}
l, err = net.Listen("tcp", listenAddr)
lc := net.ListenConfig{Control: vrfControl(setting.vrf)}
l, err = lc.Listen(context.Background(), "tcp", listenAddr)
}

if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions frontend/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type viperSettingType struct {
TimeOut int `mapstructure:"timeout"`
ConnectionTimeOut int `mapstructure:"connection_timeout"`
TrustProxyHeaders bool `mapstructure:"trust_proxy_headers"`
Vrf string `mapstructure:"vrf"`
}

// Parse settings with viper, and convert to legacy setting format
Expand Down Expand Up @@ -104,6 +105,9 @@ func parseSettings() {
pflag.Bool("trust-proxy-headers", false, "Trust X-Forwared-For, X-Real-IP, X-Forwarded-Proto, X-Forwarded-Scheme and X-Forwarded-Host sent by the client")
viper.BindPFlag("trust_proxy_headers", pflag.Lookup("trust-proxy-headers"))

pflag.String("vrf", "", "VRF device to bind TCP sockets to (Linux only)")
viper.BindPFlag("vrf", pflag.Lookup("vrf"))

pflag.Parse()

if err := viper.ReadInConfig(); err != nil {
Expand Down Expand Up @@ -155,6 +159,7 @@ func parseSettings() {
setting.timeOut = viperSettings.TimeOut
setting.connectionTimeOut = viperSettings.ConnectionTimeOut
setting.trustProxyHeaders = viperSettings.TrustProxyHeaders
setting.vrf = viperSettings.Vrf

fmt.Printf("%#v\n", setting)
}
27 changes: 27 additions & 0 deletions frontend/vrf_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//go:build linux

package main

import (
"syscall"

"golang.org/x/sys/unix"
)

// vrfControl returns a Control function that binds sockets to a VRF device
// via SO_BINDTODEVICE. Returns nil when vrfName is empty.
func vrfControl(vrfName string) func(network, address string, c syscall.RawConn) error {
if vrfName == "" {
return nil
}
return func(network, address string, c syscall.RawConn) error {
var sysErr error
err := c.Control(func(fd uintptr) {
sysErr = unix.SetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_BINDTODEVICE, vrfName)
})
if err != nil {
return err
}
return sysErr
}
}
14 changes: 14 additions & 0 deletions frontend/vrf_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build !linux

package main

import "syscall"

// vrfControl returns a Control function that binds sockets to a VRF device.
// On non-Linux platforms, VRF is not supported; panics if vrfName is non-empty.
func vrfControl(vrfName string) func(network, address string, c syscall.RawConn) error {
if vrfName == "" {
return nil
}
panic("VRF binding is only supported on Linux")
}
2 changes: 1 addition & 1 deletion frontend/whois.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func whois(s string) string {

whoisServer := addDefaultWhoisPort(setting.whoisServer)

conn, err := net.DialTimeout("tcp", whoisServer, 5*time.Second)
conn, err := (&net.Dialer{Timeout: 5 * time.Second, Control: vrfControl(setting.vrf)}).Dial("tcp", whoisServer)
if err != nil {
return err.Error()
}
Expand Down
2 changes: 1 addition & 1 deletion proxy/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/magiconair/properties v1.8.10
github.com/spf13/pflag v1.0.10
github.com/spf13/viper v1.21.0
golang.org/x/sys v0.29.0
)

require (
Expand All @@ -21,6 +22,5 @@ require (
github.com/spf13/cast v1.10.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.28.0 // indirect
)
5 changes: 4 additions & 1 deletion proxy/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"fmt"
"net"
"net/http"
Expand Down Expand Up @@ -69,6 +70,7 @@ type settingType struct {
tr_flags []string
tr_raw bool
tr_max_concurrent int
vrf string
}

var setting settingType
Expand Down Expand Up @@ -103,7 +105,8 @@ func main() {
if !strings.Contains(addr, ":") {
addr = ":" + addr
}
l, err = net.Listen("tcp", addr)
lc := net.ListenConfig{Control: vrfControl(setting.vrf)}
l, err = lc.Listen(context.Background(), "tcp", addr)
}

if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions proxy/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type viperSettingType struct {
TracerouteFlags string `mapstructure:"traceroute_flags"`
TracerouteRaw bool `mapstructure:"traceroute_raw"`
TracerouteMaxConcurrent int `mapstructure:"traceroute_max_concurrent"`
Vrf string `mapstructure:"vrf"`
}

// Parse settings with viper, and convert to legacy setting format
Expand Down Expand Up @@ -66,6 +67,9 @@ func parseSettings() {
pflag.Bool("bird-restrict-cmds", true, "restrict bird commands to 'show protocols' and 'show route' only")
viper.BindPFlag("bird_restrict_cmds", pflag.Lookup("bird-restrict-cmds"))

pflag.String("vrf", "", "VRF device to bind TCP sockets to (Linux only)")
viper.BindPFlag("vrf", pflag.Lookup("vrf"))

pflag.Parse()

if err := viper.ReadInConfig(); err != nil {
Expand Down Expand Up @@ -117,6 +121,7 @@ func parseSettings() {

setting.tr_raw = viperSettings.TracerouteRaw
setting.tr_max_concurrent = viperSettings.TracerouteMaxConcurrent
setting.vrf = viperSettings.Vrf

fmt.Printf("%#v\n", setting)
}
27 changes: 27 additions & 0 deletions proxy/vrf_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//go:build linux

package main

import (
"syscall"

"golang.org/x/sys/unix"
)

// vrfControl returns a Control function that binds sockets to a VRF device
// via SO_BINDTODEVICE. Returns nil when vrfName is empty.
func vrfControl(vrfName string) func(network, address string, c syscall.RawConn) error {
if vrfName == "" {
return nil
}
return func(network, address string, c syscall.RawConn) error {
var sysErr error
err := c.Control(func(fd uintptr) {
sysErr = unix.SetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_BINDTODEVICE, vrfName)
})
if err != nil {
return err
}
return sysErr
}
}
14 changes: 14 additions & 0 deletions proxy/vrf_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build !linux

package main

import "syscall"

// vrfControl returns a Control function that binds sockets to a VRF device.
// On non-Linux platforms, VRF is not supported; panics if vrfName is non-empty.
func vrfControl(vrfName string) func(network, address string, c syscall.RawConn) error {
if vrfName == "" {
return nil
}
panic("VRF binding is only supported on Linux")
}
Loading