From 4e70bb799de393c4e70f9bc0f75479ab53af9ee0 Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Wed, 9 Aug 2023 18:33:16 -0400 Subject: [PATCH] add posix tun device --- x/outline-cli/main.go | 97 ++----------------------------- x/outline-cli/tun_device.go | 23 ++++++++ x/outline-cli/tun_device_posix.go | 89 ++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 91 deletions(-) create mode 100644 x/outline-cli/tun_device.go create mode 100644 x/outline-cli/tun_device_posix.go diff --git a/x/outline-cli/main.go b/x/outline-cli/main.go index 27efd91b..0d83b546 100644 --- a/x/outline-cli/main.go +++ b/x/outline-cli/main.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build linux + package main import ( @@ -22,7 +24,6 @@ import ( "strconv" "sync" - "github.com/songgao/water" "github.com/vishvananda/netlink" "golang.org/x/sys/unix" ) @@ -30,7 +31,7 @@ import ( const OUTLINE_TUN_NAME = "outline233" const OUTLINE_TUN_IP = "10.233.233.1" const OUTLINE_TUN_MTU = 1500 // todo: we can read this from netlink -const OUTLINE_TUN_SUBNET = "10.233.233.1/32" +// const OUTLINE_TUN_SUBNET = "10.233.233.1/32" const OUTLINE_GW_SUBNET = "10.233.233.2/32" const OUTLINE_GW_IP = "10.233.233.2" const OUTLINE_ROUTING_PRIORITY = 23333 @@ -60,21 +61,12 @@ func main() { bgWait := &sync.WaitGroup{} defer bgWait.Wait() - tun, err := setupTunDevice() + tun, err := NewTunDevice(OUTLINE_TUN_NAME, OUTLINE_TUN_IP) if err != nil { + fmt.Printf("fatal error: %v\n", err) return } - defer cleanUpTunDevice(tun) - - if err := showTunDevice(); err != nil { - return - } - if err := configureTunDevice(); err != nil { - return - } - if err := showTunDevice(); err != nil { - return - } + defer tun.Close() ss, err := NewOutlineDevice(&OutlineConfig{ Hostname: svrIp, @@ -124,83 +116,6 @@ func main() { fmt.Printf("\nReceived %v, cleaning up resources...\n", s) } -func showTunDevice() error { - l, err := netlink.LinkByName(OUTLINE_TUN_NAME) - if err != nil { - fmt.Printf("fatal error: %v\n", err) - return err - } - if tun, ok := l.(*netlink.Tuntap); ok { - mode := "unknown" - if tun.Mode == netlink.TUNTAP_MODE_TUN { - mode = "tun" - } else if tun.Mode == netlink.TUNTAP_MODE_TAP { - mode = "tap" - } - persist := "persist" - if tun.NonPersist { - persist = "non-persist" - } - fmt.Printf("\t%v %v %v mtu=%v attr=%v stat=%v\n", tun.Name, mode, persist, tun.MTU, tun.Attrs(), tun.Statistics) - return nil - } else { - fmt.Printf("fatal error: %v is not a tun device\n", OUTLINE_TUN_NAME) - return fmt.Errorf("tun device not found") - } -} - -func setupTunDevice() (*water.Interface, error) { - fmt.Println("setting up tun device...") - conf := water.Config{ - DeviceType: water.TUN, - PlatformSpecificParams: water.PlatformSpecificParams{ - Name: OUTLINE_TUN_NAME, - Persist: false, - }, - } - r, err := water.New(conf) - if err == nil { - fmt.Println("tun device created") - } else { - fmt.Printf("fatal error: %v\n", err) - } - return r, err -} - -func configureTunDevice() error { - fmt.Println("configuring tun device ip...") - tun, err := netlink.LinkByName(OUTLINE_TUN_NAME) - if err != nil { - fmt.Printf("fatal error: %v\n", err) - return err - } - addr, err := netlink.ParseAddr(OUTLINE_TUN_SUBNET) - if err != nil { - fmt.Printf("fatal error: %v\n", err) - return err - } - if err := netlink.AddrAdd(tun, addr); err != nil { - fmt.Printf("fatal error: %v\n", err) - return err - } - if err := netlink.LinkSetUp(tun); err != nil { - fmt.Printf("fatal error: %v\n", err) - return err - } - return nil -} - -func cleanUpTunDevice(tun *water.Interface) error { - fmt.Println("cleaning up tun device...") - err := tun.Close() - if err == nil { - fmt.Println("tun device deleted") - } else { - fmt.Printf("clean up error: %v\n", err) - } - return err -} - func showRouting() error { filter := netlink.Route{Table: OUTLINE_ROUTING_TABLE} routes, err := netlink.RouteListFiltered(netlink.FAMILY_V4, &filter, netlink.RT_FILTER_TABLE) diff --git a/x/outline-cli/tun_device.go b/x/outline-cli/tun_device.go new file mode 100644 index 00000000..d04bc399 --- /dev/null +++ b/x/outline-cli/tun_device.go @@ -0,0 +1,23 @@ +// Copyright 2023 Jigsaw Operations LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "github.com/Jigsaw-Code/outline-internal-sdk/network" +) + +type TunDevice interface { + network.IPDevice +} diff --git a/x/outline-cli/tun_device_posix.go b/x/outline-cli/tun_device_posix.go new file mode 100644 index 00000000..0b2ac8e7 --- /dev/null +++ b/x/outline-cli/tun_device_posix.go @@ -0,0 +1,89 @@ +// Copyright 2023 Jigsaw Operations LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build linux + +package main + +import ( + "errors" + "fmt" + + "github.com/songgao/water" + "github.com/vishvananda/netlink" +) + +type tunDevice struct { + *water.Interface +} + +var _ TunDevice = (*tunDevice)(nil) + +func NewTunDevice(name, ip string) (d TunDevice, err error) { + if len(name) == 0 { + return nil, errors.New("name is required for TUN/TAP device") + } + if len(ip) == 0 { + return nil, errors.New("ip is required for TUN/TAP device") + } + + tun, err := water.New(water.Config{ + DeviceType: water.TUN, + PlatformSpecificParams: water.PlatformSpecificParams{ + Name: name, + Persist: false, + }, + }) + if err != nil { + return nil, fmt.Errorf("failed to create TUN/TAP device: %w", err) + } + + defer func() { + if err != nil { + tun.Close() + } + }() + + tunDev := &tunDevice{tun} + if err := tunDev.configureSubnetAndBringUp(ip); err != nil { + return nil, fmt.Errorf("failed to configure TUN/TAP device: %w", err) + } + return tunDev, nil +} + +func (d *tunDevice) MTU() int { + // d.Interface. + // netlink.NewLinkAttrs().MTU + return 0 +} + +func (d *tunDevice) configureSubnetAndBringUp(ip string) error { + tunName := d.Interface.Name() + tunLink, err := netlink.LinkByName(tunName) + if err != nil { + return fmt.Errorf("TUN/TAP device '%s' not found: %w", tunName, err) + } + subnet := ip + "/32" + addr, err := netlink.ParseAddr(subnet) + if err != nil { + return fmt.Errorf("subnet address '%s' is not valid: %w", subnet, err) + } + if err := netlink.AddrAdd(tunLink, addr); err != nil { + return fmt.Errorf("failed to add subnet to TUN/TAP device '': %w", tunName, err) + } + if err := netlink.LinkSetUp(tunLink); err != nil { + return fmt.Errorf("failed to bring TUN/TAP device '%s' up: %w", tunName, err) + } + return nil +}