-
Notifications
You must be signed in to change notification settings - Fork 2
/
adapter_linux.go
121 lines (106 loc) · 2.46 KB
/
adapter_linux.go
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
//build +linux
package adapter
import (
"encoding/binary"
"fmt"
"log"
"net"
"syscall"
"unsafe"
"github.com/arcpop/govpn/core"
"golang.org/x/sys/unix"
)
const (
IFF_TUN = 0x0001
IFF_TAP = 0x0002
IFF_NO_PI = 0x1000
)
type tapInterface struct {
fd, mtu int
name string
macAddr core.MacAddr
writeChannel, readChannel chan []byte
}
func newTAP(name string, mtu, queueSize int) (Instance, error) {
fd, err := unix.Open("/dev/net/tun", unix.O_RDWR, 0)
if err != nil {
return nil, fmt.Errorf("adapter: failed to open /dev/net/tun: " + err.Error())
}
var flags uint16 = IFF_TAP | IFF_NO_PI
var ifr_req [32]byte
b := syscall.StringByteSlice(name)
if name != "" && len(b) < 16 {
copy(ifr_req[0:15], b[:])
}
binary.LittleEndian.PutUint16(ifr_req[16:], flags)
err = unix.IoctlSetWinsize(fd, unix.TUNSETIFF, (*unix.Winsize)(unsafe.Pointer(&ifr_req[0])))
if err != nil {
unix.Close(fd)
return nil, fmt.Errorf("adapter: failed to set device to TAP mode: " + err.Error())
}
i := &tapInterface{
name: parseName(ifr_req[0:16]),
fd: fd,
writeChannel: make(chan []byte, queueSize),
readChannel: make(chan []byte, queueSize),
}
iface, err := net.InterfaceByName(i.name)
if err != nil {
unix.Close(fd)
return nil, fmt.Errorf("adapter: failed find interface: " + err.Error())
}
copy(i.macAddr[:], iface.HardwareAddr[:])
i.mtu = iface.MTU
go i.toTapWorker()
go i.fromTapWorker()
return i, nil
}
func (t *tapInterface) toTapWorker() {
for p, ok := <-t.writeChannel; ok; p, ok = <-t.writeChannel {
_, err := unix.Write(t.fd, p)
if err != nil {
log.Println("tap: error when writing to tap: " + err.Error())
}
}
}
func (t *tapInterface) fromTapWorker() {
for {
p := make([]byte, 1800)
n, err := unix.Read(t.fd, p)
if err != nil {
log.Println("tap: error when reading from tap: " + err.Error())
continue
}
p = p[:n]
t.readChannel <- p
}
}
func parseName(s []byte) string {
i := 0
for ; i < len(s); i++ {
if s[i] == 0 {
break
}
}
return string(s[0:i])
}
func (t *tapInterface) Close() error {
return unix.Close(t.fd)
}
func (t *tapInterface) GetName() string {
return t.name
}
func (t *tapInterface) ReceiveChannel() <-chan []byte {
return t.readChannel
}
func (t *tapInterface) TransmitChannel() chan<- []byte {
return t.writeChannel
}
func (t *tapInterface) GetMTU() int {
return t.mtu
}
func (t *tapInterface) GetMACAddress() *core.MacAddr {
var a core.MacAddr
copy(a[:], t.macAddr[:])
return &a
}