package outbounds import ( "errors" "net" "syscall" ) // NewDirectOutboundBindToDevice creates a new directOutbound with the given mode, // and binds to the given device. Only works on Linux. func NewDirectOutboundBindToDevice(mode DirectOutboundMode, deviceName string) (PluggableOutbound, error) { if err := verifyDeviceName(deviceName); err != nil { return nil, err } d := &net.Dialer{ Timeout: defaultDialerTimeout, Control: func(network, address string, c syscall.RawConn) error { var errBind error err := c.Control(func(fd uintptr) { errBind = syscall.BindToDevice(int(fd), deviceName) }) if err != nil { return err } return errBind }, } return &directOutbound{ Mode: mode, Dialer4: d, Dialer6: d, DeviceName: deviceName, }, nil } func verifyDeviceName(deviceName string) error { if deviceName == "" { return errors.New("device name cannot be empty") } _, err := net.InterfaceByName(deviceName) return err } func udpConnBindToDevice(conn *net.UDPConn, deviceName string) error { sc, err := conn.SyscallConn() if err != nil { return err } var errBind error err = sc.Control(func(fd uintptr) { errBind = syscall.BindToDevice(int(fd), deviceName) }) if err != nil { return err } return errBind }