summaryrefslogtreecommitdiff
path: root/pkg/server/socket/tun.go
blob: c14125b3e7e23a6457db8c71e19616bedcb606e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package socket

import (
	"errors"
	"fmt"
	"golang.org/x/sys/unix"
	"log"
	"os"
	"strings"
	"sync"
	"tunnel/pkg/pack"
	"tunnel/pkg/server/env"
	"tunnel/pkg/server/queue"
	"unsafe"
)

const maxTunBufSize = 65535

var errPartialWrite = errors.New("partial write")

type ifReq struct {
	name  [unix.IFNAMSIZ]uint8
	flags uint16
}

type tunSocket struct {
	name string
}

type tunConn struct {
	name string
	s    *tunSocket
	fp   *os.File
	once sync.Once
}

func ioctl(fd int, req uintptr, ptr unsafe.Pointer) error {
	_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), req, uintptr(ptr))
	if errno != 0 {
		return errno
	}

	return nil
}

func newTunSocket(name string) (S, error) {
	return &tunSocket{name: name}, nil

}

func (s *tunSocket) String() string {
	return fmt.Sprintf("tun/%s", s.name)
}

func (s *tunSocket) Open(env.Env) (Conn, error) {
	fd, err := unix.Open("/dev/net/tun", unix.O_RDWR, 0)
	if err != nil {
		return nil, err
	}

	ifr := &ifReq{}
	copy(ifr.name[:], s.name)
	ifr.flags = unix.IFF_TUN | unix.IFF_NO_PI

	if err := ioctl(fd, unix.TUNSETIFF, unsafe.Pointer(ifr)); err != nil {
		unix.Close(fd)
		return nil, fmt.Errorf("ioctl TUNSETIFF %s: %w", s.name, err)
	}

	if err := unix.SetNonblock(fd, true); err != nil {
		unix.Close(fd)
		return nil, fmt.Errorf("set nonblock %s: %w", s.name, err)
	}

	c := &tunConn{
		name: strings.Trim(string(ifr.name[:]), "\x00"),
		fp:   os.NewFile(uintptr(fd), "tun"),
	}

	return c, nil
}

func (s *tunSocket) Close() {
}

func (c *tunConn) Send(wq queue.Q) error {
	buf := make([]byte, maxTunBufSize)
	enc := pack.NewEncoder(wq.Writer())

	for {
		n, err := c.fp.Read(buf)
		if err != nil {
			return err
		}

		enc.Lps(buf[0:n])
	}
}

func (c *tunConn) Recv(rq queue.Q) error {
	dec := pack.NewDecoder(rq.Reader())

	for {
		b, err := dec.Lps()
		if err != nil {
			return err
		}

		n, err := c.fp.Write(b)
		if err != nil {
			return err
		}

		if n != len(b) {
			return errPartialWrite
		}
	}
}

func (c *tunConn) String() string {
	return "tun/" + c.name
}

func (c *tunConn) Close() error {
	err := ErrAlreadyClosed

	c.once.Do(func() {
		log.Println("close", c)
		err = c.fp.Close()
	})

	return err
}