Introduce VSOCK link type

This address family is used in communication between virtual machines
and their hosts. Advantages include that no virtual ethernet adapter
and their respective address configuration and routing need to be
setup. Rather, with this new link type, only a single yggdrasil
interface can exist inside of the virtual machine.

It can also be used inside of containers. There, the advantage over
existing link types like unix sockets include, that no mount point
need to be shared with the host and container. This provides more
isolation.

More information:

https://man7.org/linux/man-pages/man7/vsock.7.html

https://gist.github.com/nrdmn/7971be650919b112343b1cb2757a3fe6
This commit is contained in:
Daniel Nagy 2025-01-02 21:45:00 +01:00
parent 73705ff09d
commit 7ad7eb05d4
No known key found for this signature in database
5 changed files with 88 additions and 0 deletions

69
src/core/link_vsock.go Normal file
View file

@ -0,0 +1,69 @@
package core
import (
"context"
"fmt"
"net"
"net/url"
"strconv"
"strings"
"github.com/Arceliar/phony"
"github.com/mdlayher/vsock"
)
type linkVSOCK struct {
phony.Inbox
*links
}
func (l *links) newLinkVSOCK() *linkVSOCK {
lt := &linkVSOCK{
links: l,
}
return lt
}
func (l *linkVSOCK) dial(ctx context.Context, url *url.URL, info linkInfo, options linkOptions) (net.Conn, error) {
localPort, err := strconv.ParseUint(url.Port(), 10, 32)
if err != nil {
return nil, fmt.Errorf("no VSOCK port specified: %w", err)
}
contextID, err := urlParseContextID(url)
if err != nil {
return nil, fmt.Errorf("Unknown VSOCK host and cannot parse as numerical contextID: %w", err)
}
return vsock.Dial(contextID, uint32(localPort), nil)
}
func (l *linkVSOCK) listen(ctx context.Context, url *url.URL, _ string) (net.Listener, error) {
localPort, err := strconv.ParseUint(url.Port(), 10, 32)
if err != nil {
return nil, fmt.Errorf("no VSOCK port specified: %w", err)
}
contextID, err := urlParseContextID(url)
if err != nil {
return nil, fmt.Errorf("Unknown VSOCK host and cannot parse as numerical contextID: %w", err)
}
return vsock.ListenContextID(contextID, uint32(localPort), nil)
}
func urlParseContextID(u *url.URL) (uint32, error) {
var contextID uint32
switch strings.ToLower(u.Hostname()) {
case "hypervisor":
contextID = vsock.Hypervisor
case "local":
contextID = vsock.Local
case "host":
contextID = vsock.Host
default:
parsedHost, err := strconv.ParseUint(u.Hostname(), 10, 32)
if err != nil {
return 0, err
}
contextID = uint32(parsedHost)
}
return contextID, nil
}