Skip to content

Commit

Permalink
add posix tun device
Browse files Browse the repository at this point in the history
  • Loading branch information
jyyi1 committed Aug 9, 2023
1 parent 466cc9d commit 4e70bb7
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 91 deletions.
97 changes: 6 additions & 91 deletions x/outline-cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build linux

package main

import (
Expand All @@ -22,15 +24,14 @@ import (
"strconv"
"sync"

"github.com/songgao/water"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
)

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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
23 changes: 23 additions & 0 deletions x/outline-cli/tun_device.go
Original file line number Diff line number Diff line change
@@ -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
}
89 changes: 89 additions & 0 deletions x/outline-cli/tun_device_posix.go
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 4e70bb7

Please sign in to comment.