Skip to content

Commit 91a0587

Browse files
committed
tun: add plan9 support
Reviewed-by: James Tucker <[email protected]>
1 parent 0b8b355 commit 91a0587

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed

tun/tun_plan9.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/* SPDX-License-Identifier: MIT
2+
*
3+
* Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved.
4+
*/
5+
6+
package tun
7+
8+
import (
9+
"fmt"
10+
"io"
11+
"os"
12+
"strconv"
13+
"strings"
14+
"sync"
15+
)
16+
17+
type NativeTun struct {
18+
name string // "/net/ipifc/2"
19+
ctlFile *os.File
20+
dataFile *os.File
21+
events chan Event
22+
errors chan error
23+
closeOnce sync.Once
24+
}
25+
26+
func CreateTUN(_ string, mtu int) (Device, error) {
27+
ctl, err := os.OpenFile("/net/ipifc/clone", os.O_RDWR, 0)
28+
if err != nil {
29+
return nil, err
30+
}
31+
nbuf := make([]byte, 5)
32+
n, err := ctl.Read(nbuf)
33+
if err != nil {
34+
ctl.Close()
35+
return nil, fmt.Errorf("error reading from clone file: %w", err)
36+
}
37+
ifn, err := strconv.Atoi(strings.TrimSpace(string(nbuf[:n])))
38+
if err != nil {
39+
ctl.Close()
40+
return nil, fmt.Errorf("error converting clone result %q to int: %w", nbuf[:n], err)
41+
}
42+
43+
if _, err := fmt.Fprintf(ctl, "bind pkt\n"); err != nil {
44+
ctl.Close()
45+
return nil, fmt.Errorf("error binding to pkt: %w", err)
46+
}
47+
if mtu > 0 {
48+
if _, err := fmt.Fprintf(ctl, "mtu %d\n", mtu); err != nil {
49+
ctl.Close()
50+
return nil, fmt.Errorf("error setting MTU: %w", err)
51+
}
52+
}
53+
54+
dataFile, err := os.OpenFile(fmt.Sprintf("/net/ipifc/%d/data", ifn), os.O_RDWR, 0)
55+
if err != nil {
56+
ctl.Close()
57+
return nil, err
58+
}
59+
60+
tun := &NativeTun{
61+
ctlFile: ctl,
62+
dataFile: dataFile,
63+
name: fmt.Sprintf("/net/ipifc/%d", ifn),
64+
events: make(chan Event, 10),
65+
errors: make(chan error, 5),
66+
}
67+
tun.events <- EventUp
68+
69+
return tun, nil
70+
}
71+
72+
func (tun *NativeTun) Name() (string, error) {
73+
return tun.name, nil
74+
}
75+
76+
func (tun *NativeTun) File() *os.File {
77+
return tun.ctlFile
78+
}
79+
80+
func (tun *NativeTun) Events() <-chan Event {
81+
return tun.events
82+
}
83+
84+
func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error) {
85+
select {
86+
case err := <-tun.errors:
87+
return 0, err
88+
default:
89+
n, err := tun.dataFile.Read(bufs[0][offset:])
90+
if n == 1 && bufs[0][offset] == 0 {
91+
// EOF
92+
err = io.EOF
93+
n = 0
94+
}
95+
sizes[0] = n
96+
return 1, err
97+
}
98+
}
99+
100+
func (tun *NativeTun) Write(bufs [][]byte, offset int) (int, error) {
101+
for i, buf := range bufs {
102+
if _, err := tun.dataFile.Write(buf[offset:]); err != nil {
103+
return i, err
104+
}
105+
}
106+
return len(bufs), nil
107+
}
108+
109+
func (tun *NativeTun) Close() error {
110+
var err1, err2 error
111+
tun.closeOnce.Do(func() {
112+
_, err1 := fmt.Fprintf(tun.ctlFile, "unbind\n")
113+
if err := tun.ctlFile.Close(); err != nil && err1 == nil {
114+
err1 = err
115+
}
116+
err2 = tun.dataFile.Close()
117+
})
118+
if err1 != nil {
119+
return err1
120+
}
121+
return err2
122+
}
123+
124+
func (tun *NativeTun) MTU() (int, error) {
125+
var buf [100]byte
126+
f, err := os.Open(tun.name + "/status")
127+
if err != nil {
128+
return 0, err
129+
}
130+
defer f.Close()
131+
n, err := f.Read(buf[:])
132+
_, res, ok := strings.Cut(string(buf[:n]), " maxtu ")
133+
if ok {
134+
if mtus, _, ok := strings.Cut(res, " "); ok {
135+
mtu, err := strconv.Atoi(mtus)
136+
if err != nil {
137+
return 0, fmt.Errorf("error converting mtu %q to int: %w", mtus, err)
138+
}
139+
return mtu, nil
140+
}
141+
}
142+
return 0, fmt.Errorf("no 'maxtu' field found in %s/status", tun.name)
143+
}
144+
145+
func (tun *NativeTun) BatchSize() int {
146+
return 1
147+
}

0 commit comments

Comments
 (0)