Skip to content

Commit 061966e

Browse files
committed
chore: OpenVPN no longer relies on the underlying conn deadline functions
1 parent 99c4978 commit 061966e

8 files changed

Lines changed: 1969 additions & 731 deletions

File tree

transport/openvpn/client.go

Lines changed: 108 additions & 108 deletions
Large diffs are not rendered by default.

transport/openvpn/control.go

Lines changed: 92 additions & 336 deletions
Large diffs are not rendered by default.

transport/openvpn/control_test.go

Lines changed: 243 additions & 153 deletions
Large diffs are not rendered by default.

transport/openvpn/mux.go

Lines changed: 338 additions & 36 deletions
Large diffs are not rendered by default.

transport/openvpn/packetio.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package openvpn
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"io"
7+
"net"
8+
"os"
9+
"syscall"
10+
11+
"github.com/metacubex/mihomo/common/pool"
12+
)
13+
14+
// connIO deliberately excludes net.Conn's deadline methods. Physical OpenVPN
15+
// I/O can only be interrupted by closing the connection.
16+
type connIO interface {
17+
io.ReadWriteCloser
18+
LocalAddr() net.Addr
19+
RemoteAddr() net.Addr
20+
}
21+
22+
type PacketIO interface {
23+
// ReadPacket and WritePacket must not depend on deadline methods. Close
24+
// must unblock any ReadPacket or WritePacket currently in progress.
25+
// ReadPacket may return a complete packet and a non-nil error together;
26+
// the packet precedes the error and must remain valid.
27+
ReadPacket() ([]byte, error)
28+
WritePacket(packet []byte) error
29+
Close() error
30+
LocalAddr() net.Addr
31+
RemoteAddr() net.Addr
32+
}
33+
34+
var errPacketDropped = errors.New("openvpn packet dropped")
35+
36+
type packetDroppedError struct {
37+
cause error
38+
}
39+
40+
func (e *packetDroppedError) Error() string {
41+
return fmt.Sprintf("%v: %v", errPacketDropped, e.cause)
42+
}
43+
44+
func (e *packetDroppedError) Unwrap() error {
45+
return e.cause
46+
}
47+
48+
func (e *packetDroppedError) Is(target error) bool {
49+
return target == errPacketDropped
50+
}
51+
52+
type streamPacketIO struct {
53+
conn connIO
54+
}
55+
56+
type datagramPacketIO struct {
57+
conn connIO
58+
recoverableUDP bool
59+
}
60+
61+
func NewDatagramPacketIO(conn connIO) PacketIO {
62+
_, recoverableUDP := conn.(syscall.Conn)
63+
return &datagramPacketIO{conn: conn, recoverableUDP: recoverableUDP}
64+
}
65+
66+
func (d *datagramPacketIO) ReadPacket() ([]byte, error) {
67+
buf := make([]byte, 64*1024)
68+
n, err := d.conn.Read(buf)
69+
return buf[:n], err
70+
}
71+
72+
func (d *datagramPacketIO) WritePacket(packet []byte) error {
73+
n, err := d.conn.Write(packet)
74+
if err == nil {
75+
return nil
76+
}
77+
if n != 0 || !d.recoverableUDP || terminalPacketIOError(err) {
78+
return err
79+
}
80+
return &packetDroppedError{cause: err}
81+
}
82+
83+
func (d *datagramPacketIO) Close() error {
84+
return d.conn.Close()
85+
}
86+
87+
func (d *datagramPacketIO) LocalAddr() net.Addr {
88+
return d.conn.LocalAddr()
89+
}
90+
91+
func (d *datagramPacketIO) RemoteAddr() net.Addr {
92+
return d.conn.RemoteAddr()
93+
}
94+
95+
func NewTCPPacketIO(conn connIO) PacketIO {
96+
return &streamPacketIO{conn: conn}
97+
}
98+
99+
func (s *streamPacketIO) ReadPacket() ([]byte, error) {
100+
var length [2]byte
101+
if _, err := io.ReadFull(s.conn, length[:]); err != nil {
102+
return nil, err
103+
}
104+
size := int(length[0])<<8 | int(length[1])
105+
if size == 0 {
106+
return nil, errors.New("empty openvpn TCP packet")
107+
}
108+
packet := make([]byte, size)
109+
if _, err := io.ReadFull(s.conn, packet); err != nil {
110+
return nil, err
111+
}
112+
return packet, nil
113+
}
114+
115+
func (s *streamPacketIO) WritePacket(packet []byte) error {
116+
if len(packet) > 0xffff {
117+
return fmt.Errorf("openvpn TCP packet too large: %d", len(packet))
118+
}
119+
frame := pool.Get(2 + len(packet))
120+
defer pool.Put(frame)
121+
frame[0] = byte(len(packet) >> 8)
122+
frame[1] = byte(len(packet))
123+
copy(frame[2:], packet)
124+
_, err := s.conn.Write(frame)
125+
return err
126+
}
127+
128+
func (s *streamPacketIO) Close() error {
129+
return s.conn.Close()
130+
}
131+
132+
func (s *streamPacketIO) LocalAddr() net.Addr {
133+
return s.conn.LocalAddr()
134+
}
135+
136+
func (s *streamPacketIO) RemoteAddr() net.Addr {
137+
return s.conn.RemoteAddr()
138+
}
139+
140+
func terminalPacketIOError(err error) bool {
141+
if errors.Is(err, net.ErrClosed) || errors.Is(err, os.ErrClosed) ||
142+
errors.Is(err, os.ErrDeadlineExceeded) {
143+
return true
144+
}
145+
var netErr net.Error
146+
return errors.As(err, &netErr) && netErr.Timeout()
147+
}

0 commit comments

Comments
 (0)