Files
gvisor-tap-vsock/pkg/virtualnetwork/services.go
T
Yevhen Vydolob cf0e470794 Add ICMP forwarding support
The current implementation supports forwarding only ICMP Echo(ping) packets, as OS not allow to send arbitrary packets without escalating privileges.  All other ICMP packets are dropped(ignored)

Changes in 'icmp_packet.go' and 'icmp.go' was mostly maded by cursor.

Signed-off-by: Yevhen Vydolob <yvydolob@redhat.com>
2026-04-16 15:59:10 +02:00

127 lines
3.7 KiB
Go

package virtualnetwork
import (
"net"
"net/http"
"strings"
"sync"
"github.com/containers/gvisor-tap-vsock/pkg/services/dhcp"
"github.com/containers/gvisor-tap-vsock/pkg/services/dns"
"github.com/containers/gvisor-tap-vsock/pkg/services/forwarder"
"github.com/containers/gvisor-tap-vsock/pkg/tap"
"github.com/containers/gvisor-tap-vsock/pkg/types"
log "github.com/sirupsen/logrus"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
)
func addServices(configuration *types.Configuration, s *stack.Stack, ipPool *tap.IPPool) (http.Handler, error) {
var natLock sync.Mutex
translation := parseNATTable(configuration)
tcpForwarder := forwarder.TCP(s, translation, &natLock, configuration.Ec2MetadataAccess)
s.SetTransportProtocolHandler(tcp.ProtocolNumber, tcpForwarder.HandlePacket)
udpForwarder := forwarder.UDP(s, translation, &natLock)
s.SetTransportProtocolHandler(udp.ProtocolNumber, udpForwarder.HandlePacket)
icmpForwarder := forwarder.ICMP(s, translation, &natLock)
s.SetTransportProtocolHandler(icmp.ProtocolNumber4, icmpForwarder.HandlePacket)
dnsMux, err := dnsServer(configuration, s)
if err != nil {
return nil, err
}
dhcpMux, err := dhcpServer(configuration, s, ipPool)
if err != nil {
return nil, err
}
forwarderMux, err := forwardHostVM(configuration, s)
if err != nil {
return nil, err
}
mux := http.NewServeMux()
mux.Handle("/forwarder/", http.StripPrefix("/forwarder", forwarderMux))
mux.Handle("/dhcp/", http.StripPrefix("/dhcp", dhcpMux))
mux.Handle("/dns/", http.StripPrefix("/dns", dnsMux))
return mux, nil
}
func parseNATTable(configuration *types.Configuration) map[tcpip.Address]tcpip.Address {
translation := make(map[tcpip.Address]tcpip.Address)
for source, destination := range configuration.NAT {
translation[tcpip.AddrFrom4Slice(net.ParseIP(source).To4())] = tcpip.AddrFrom4Slice(net.ParseIP(destination).To4())
}
return translation
}
func dnsServer(configuration *types.Configuration, s *stack.Stack) (http.Handler, error) {
udpConn, err := gonet.DialUDP(s, &tcpip.FullAddress{
NIC: 1,
Addr: tcpip.AddrFrom4Slice(net.ParseIP(configuration.GatewayIP).To4()),
Port: uint16(53),
}, nil, ipv4.ProtocolNumber)
if err != nil {
return nil, err
}
tcpLn, err := gonet.ListenTCP(s, tcpip.FullAddress{
NIC: 1,
Addr: tcpip.AddrFrom4Slice(net.ParseIP(configuration.GatewayIP).To4()),
Port: uint16(53),
}, ipv4.ProtocolNumber)
if err != nil {
return nil, err
}
server, err := dns.New(udpConn, tcpLn, configuration.DNS)
if err != nil {
return nil, err
}
go func() {
if err := server.Serve(); err != nil {
log.Error(err)
}
}()
go func() {
if err := server.ServeTCP(); err != nil {
log.Error(err)
}
}()
return server.Mux(), nil
}
func dhcpServer(configuration *types.Configuration, s *stack.Stack, ipPool *tap.IPPool) (http.Handler, error) {
server, err := dhcp.New(configuration, s, ipPool)
if err != nil {
return nil, err
}
go func() {
log.Error(server.Serve())
}()
return server.Mux(), nil
}
func forwardHostVM(configuration *types.Configuration, s *stack.Stack) (http.Handler, error) {
fw := forwarder.NewPortsForwarder(s)
for local, remote := range configuration.Forwards {
if strings.HasPrefix(local, "udp:") {
if err := fw.Expose(types.UDP, strings.TrimPrefix(local, "udp:"), remote); err != nil {
return nil, err
}
} else {
if err := fw.Expose(types.TCP, local, remote); err != nil {
return nil, err
}
}
}
return fw.Mux(), nil
}