Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lima-vm
GitHub Repository: lima-vm/lima
Path: blob/master/pkg/portfwd/client.go
2608 views
1
// SPDX-FileCopyrightText: Copyright The Lima Authors
2
// SPDX-License-Identifier: Apache-2.0
3
4
package portfwd
5
6
import (
7
"context"
8
"fmt"
9
"net"
10
"sync/atomic"
11
"time"
12
13
"github.com/containers/gvisor-tap-vsock/pkg/services/forwarder"
14
"github.com/containers/gvisor-tap-vsock/pkg/tcpproxy"
15
"github.com/sirupsen/logrus"
16
17
"github.com/lima-vm/lima/v2/pkg/guestagent/api"
18
guestagentclient "github.com/lima-vm/lima/v2/pkg/guestagent/api/client"
19
)
20
21
func HandleTCPConnection(_ context.Context, dialContext func(ctx context.Context, network string, addr string) (net.Conn, error), conn net.Conn, guestAddr string) {
22
proxy := tcpproxy.DialProxy{Addr: guestAddr, DialContext: dialContext}
23
proxy.HandleConn(conn)
24
logrus.Debugf("tcp proxy for guestAddr: %s closed", guestAddr)
25
}
26
27
func HandleUDPConnection(ctx context.Context, dialContext func(ctx context.Context, network string, addr string) (net.Conn, error), conn net.PacketConn, guestAddr string) {
28
proxy, err := forwarder.NewUDPProxy(conn, func() (net.Conn, error) {
29
return dialContext(ctx, "udp", guestAddr)
30
})
31
if err != nil {
32
logrus.WithError(err).Error("error in udp tunnel proxy")
33
return
34
}
35
36
defer func() {
37
err := proxy.Close()
38
if err != nil {
39
logrus.WithError(err).Error("error in closing udp tunnel proxy")
40
}
41
}()
42
proxy.Run()
43
logrus.Debugf("udp proxy for guestAddr: %s closed", guestAddr)
44
}
45
46
func DialContextToGRPCTunnel(client *guestagentclient.GuestAgentClient) func(ctx context.Context, network, addr string) (net.Conn, error) {
47
// gvisor-tap-vsock's UDPProxy demultiplexes client connections internally based on their source address.
48
// It calls this dialer function only when it receives a datagram from a new, unrecognized client.
49
// For each new client, we must return a new net.Conn, which in our case is a new gRPC stream.
50
// The atomic counter ensures that each stream has a unique ID to distinguish them on the server side.
51
var connectionCounter atomic.Uint32
52
return func(_ context.Context, network, addr string) (net.Conn, error) {
53
// Passed context.Context is used for timeout on initiate connection, not for the lifetime of the connection.
54
// We use context.Background() here to avoid unexpected cancellation.
55
stream, err := client.Tunnel(context.Background())
56
if err != nil {
57
return nil, fmt.Errorf("could not open tunnel for addr: %s error:%w", addr, err)
58
}
59
// Handshake message to start tunnel
60
id := fmt.Sprintf("%s-%s-%d", network, addr, connectionCounter.Add(1))
61
if err := stream.Send(&api.TunnelMessage{Id: id, Protocol: network, GuestAddr: addr}); err != nil {
62
return nil, fmt.Errorf("could not start tunnel for id: %s addr: %s error:%w", id, addr, err)
63
}
64
rw := &GrpcClientRW{stream: stream, id: id, addr: addr, protocol: network}
65
return rw, nil
66
}
67
}
68
69
type GrpcClientRW struct {
70
id string
71
addr string
72
73
protocol string
74
stream api.GuestService_TunnelClient
75
}
76
77
var _ net.Conn = (*GrpcClientRW)(nil)
78
79
func (g *GrpcClientRW) Write(p []byte) (n int, err error) {
80
err = g.stream.Send(&api.TunnelMessage{
81
Id: g.id,
82
GuestAddr: g.addr,
83
Data: p,
84
Protocol: g.protocol,
85
})
86
if err != nil {
87
return 0, err
88
}
89
return len(p), nil
90
}
91
92
func (g *GrpcClientRW) Read(p []byte) (n int, err error) {
93
in, err := g.stream.Recv()
94
if err != nil {
95
return 0, err
96
}
97
copy(p, in.Data)
98
return len(in.Data), nil
99
}
100
101
func (g *GrpcClientRW) Close() error {
102
logrus.Debugf("closing GrpcClientRW for id: %s", g.id)
103
return g.stream.CloseSend()
104
}
105
106
func (g *GrpcClientRW) LocalAddr() net.Addr {
107
return &net.UnixAddr{Name: "grpc", Net: "unixpacket"}
108
}
109
110
func (g *GrpcClientRW) RemoteAddr() net.Addr {
111
return &net.UnixAddr{Name: "grpc", Net: "unixpacket"}
112
}
113
114
func (g *GrpcClientRW) SetDeadline(_ time.Time) error {
115
return nil
116
}
117
118
func (g *GrpcClientRW) SetReadDeadline(_ time.Time) error {
119
return nil
120
}
121
122
func (g *GrpcClientRW) SetWriteDeadline(_ time.Time) error {
123
return nil
124
}
125
126