-
Notifications
You must be signed in to change notification settings - Fork 9
/
proxy.go
181 lines (162 loc) · 4.77 KB
/
proxy.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package main
// Code mostly taken from:
// https://github.com/containers/gvisor-tap-vsock/blob/main/cmd/vm/main_linux.go
import (
"encoding/binary"
"fmt"
"io"
"net"
"net/http"
"time"
"github.com/containers/gvisor-tap-vsock/pkg/transport"
"github.com/songgao/water"
"github.com/vishvananda/netlink"
)
var (
frameLen = 0xffff
frameSizeLen = 2
)
// runNetworking calls the function that sets up our networking environment.
// If anything fails, we try again after a brief wait period.
func runNetworking(c *Config, stop chan struct{}) {
var err error
for {
if err = setupNetworking(c, stop); err == nil {
return
}
time.Sleep(time.Second)
}
}
// setupNetworking sets up the enclave's networking environment. In
// particular, this function:
//
// 1. Creates a TAP device.
// 2. Set up networking links.
// 3. Establish a connection with the proxy running on the host.
// 4. Spawn goroutines to forward traffic between the TAP device and the proxy
// running on the host.
func setupNetworking(c *Config, stop chan struct{}) error {
// Establish connection with the proxy running on the EC2 host.
endpoint := fmt.Sprintf("vsock://%d:%d/connect", parentCID, c.HostProxyPort)
conn, path, err := transport.Dial(endpoint)
if err != nil {
return fmt.Errorf("failed to connect to host: %w", err)
}
defer conn.Close()
elog.Println("Established connection with EC2 host.")
req, err := http.NewRequest(http.MethodPost, path, nil)
if err != nil {
return fmt.Errorf("failed to create POST request: %w", err)
}
if err := req.Write(conn); err != nil {
return fmt.Errorf("failed to send POST request to host: %w", err)
}
elog.Println("Sent HTTP request to EC2 host.")
// Create a TAP interface.
tap, err := water.New(water.Config{
DeviceType: water.TAP,
PlatformSpecificParams: ourWaterParams,
})
if err != nil {
return fmt.Errorf("failed to create tap device: %w", err)
}
defer tap.Close()
elog.Println("Created TAP device.")
// Configure IP address, MAC address, MTU, default gateway, and DNS.
if err = configureTapIface(); err != nil {
return fmt.Errorf("failed to configure tap interface: %w", err)
}
if err = writeResolvconf(); err != nil {
return fmt.Errorf("failed to create resolv.conf: %w", err)
}
// Set up networking links.
if err := linkUp(); err != nil {
return fmt.Errorf("failed to set MAC address: %w", err)
}
elog.Println("Created networking link.")
// Spawn goroutines that forward traffic.
errCh := make(chan error, 1)
go tx(conn, tap, errCh)
go rx(conn, tap, errCh)
elog.Println("Started goroutines to forward traffic.")
select {
case err := <-errCh:
return err
case <-stop:
elog.Printf("Shutting down networking.")
return nil
}
}
func linkUp() error {
link, err := netlink.LinkByName(ifaceTap)
if err != nil {
return err
}
if mac == "" {
return netlink.LinkSetUp(link)
}
hw, err := net.ParseMAC(mac)
if err != nil {
return err
}
if err := netlink.LinkSetHardwareAddr(link, hw); err != nil {
return err
}
return netlink.LinkSetUp(link)
}
func rx(conn io.Writer, tap io.Reader, errCh chan error) {
elog.Println("Waiting for frames from enclave application.")
buf := make([]byte, frameSizeLen+frameLen) // Two bytes for the frame length plus the frame itself
for {
n, err := tap.Read([]byte(buf[frameSizeLen:]))
if err != nil {
errCh <- fmt.Errorf("failed to read payload from enclave application: %w", err)
return
}
binary.LittleEndian.PutUint16(buf[:frameSizeLen], uint16(n))
m, err := conn.Write(buf[:frameSizeLen+n])
if err != nil {
errCh <- fmt.Errorf("failed to write payload to host: %w", err)
return
}
m = m - frameSizeLen
if m != n {
errCh <- fmt.Errorf("wrote %d instead of %d bytes to host", m, n)
return
}
}
}
func tx(conn io.Reader, tap io.Writer, errCh chan error) {
elog.Println("Waiting for frames from host.")
buf := make([]byte, frameSizeLen+frameLen) // Two bytes for the frame length plus the frame itself
for {
n, err := io.ReadFull(conn, buf[:frameSizeLen])
if err != nil {
errCh <- fmt.Errorf("failed to read length from host: %w", err)
return
}
if n != frameSizeLen {
errCh <- fmt.Errorf("received unexpected length %d", n)
return
}
size := int(binary.LittleEndian.Uint16(buf[:frameSizeLen]))
n, err = io.ReadFull(conn, buf[frameSizeLen:size+frameSizeLen])
if err != nil {
errCh <- fmt.Errorf("failed to read payload from host: %w", err)
return
}
if n == 0 || n != size {
errCh <- fmt.Errorf("expected payload of size %d but got %d", size, n)
return
}
m, err := tap.Write(buf[frameSizeLen : n+frameSizeLen])
if err != nil {
errCh <- fmt.Errorf("failed to write payload to enclave application: %w", err)
return
}
if m != n {
errCh <- fmt.Errorf("wrote %d instead of %d bytes to host", m, n)
return
}
}
}