mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
AF_PACKET support for netstack (aka epsocket).
Like (AF_INET, SOCK_RAW) sockets, AF_PACKET sockets require CAP_NET_RAW. With runsc, you'll need to pass `--net-raw=true` to enable them. Binding isn't supported yet. PiperOrigin-RevId: 275909366
This commit is contained in:
committed by
gVisor bot
parent
652f7b1d0f
commit
12235d533a
@@ -53,6 +53,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
|
||||
@@ -296,6 +297,7 @@ func New(t *kernel.Task, family int, skType linux.SockType, protocol int, queue
|
||||
|
||||
var sockAddrInetSize = int(binary.Size(linux.SockAddrInet{}))
|
||||
var sockAddrInet6Size = int(binary.Size(linux.SockAddrInet6{}))
|
||||
var sockAddrLinkSize = int(binary.Size(linux.SockAddrLink{}))
|
||||
|
||||
// bytesToIPAddress converts an IPv4 or IPv6 address from the user to the
|
||||
// netstack representation taking any addresses into account.
|
||||
@@ -307,12 +309,12 @@ func bytesToIPAddress(addr []byte) tcpip.Address {
|
||||
}
|
||||
|
||||
// AddressAndFamily reads an sockaddr struct from the given address and
|
||||
// converts it to the FullAddress format. It supports AF_UNIX, AF_INET and
|
||||
// AF_INET6 addresses.
|
||||
// converts it to the FullAddress format. It supports AF_UNIX, AF_INET,
|
||||
// AF_INET6, and AF_PACKET addresses.
|
||||
//
|
||||
// strict indicates whether addresses with the AF_UNSPEC family are accepted of not.
|
||||
//
|
||||
// AddressAndFamily returns an address, its family.
|
||||
// AddressAndFamily returns an address and its family.
|
||||
func AddressAndFamily(sfamily int, addr []byte, strict bool) (tcpip.FullAddress, uint16, *syserr.Error) {
|
||||
// Make sure we have at least 2 bytes for the address family.
|
||||
if len(addr) < 2 {
|
||||
@@ -371,6 +373,22 @@ func AddressAndFamily(sfamily int, addr []byte, strict bool) (tcpip.FullAddress,
|
||||
}
|
||||
return out, family, nil
|
||||
|
||||
case linux.AF_PACKET:
|
||||
var a linux.SockAddrLink
|
||||
if len(addr) < sockAddrLinkSize {
|
||||
return tcpip.FullAddress{}, family, syserr.ErrInvalidArgument
|
||||
}
|
||||
binary.Unmarshal(addr[:sockAddrLinkSize], usermem.ByteOrder, &a)
|
||||
if a.Family != linux.AF_PACKET || a.HardwareAddrLen != header.EthernetAddressSize {
|
||||
return tcpip.FullAddress{}, family, syserr.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// TODO(b/129292371): Return protocol too.
|
||||
return tcpip.FullAddress{
|
||||
NIC: tcpip.NICID(a.InterfaceIndex),
|
||||
Addr: tcpip.Address(a.HardwareAddr[:header.EthernetAddressSize]),
|
||||
}, family, nil
|
||||
|
||||
case linux.AF_UNSPEC:
|
||||
return tcpip.FullAddress{}, family, nil
|
||||
|
||||
@@ -1951,12 +1969,14 @@ func ConvertAddress(family int, addr tcpip.FullAddress) (linux.SockAddr, uint32)
|
||||
return &out, uint32(2 + l)
|
||||
}
|
||||
return &out, uint32(3 + l)
|
||||
|
||||
case linux.AF_INET:
|
||||
var out linux.SockAddrInet
|
||||
copy(out.Addr[:], addr.Addr)
|
||||
out.Family = linux.AF_INET
|
||||
out.Port = htons(addr.Port)
|
||||
return &out, uint32(binary.Size(out))
|
||||
return &out, uint32(sockAddrInetSize)
|
||||
|
||||
case linux.AF_INET6:
|
||||
var out linux.SockAddrInet6
|
||||
if len(addr.Addr) == 4 {
|
||||
@@ -1972,7 +1992,17 @@ func ConvertAddress(family int, addr tcpip.FullAddress) (linux.SockAddr, uint32)
|
||||
if isLinkLocal(addr.Addr) {
|
||||
out.Scope_id = uint32(addr.NIC)
|
||||
}
|
||||
return &out, uint32(binary.Size(out))
|
||||
return &out, uint32(sockAddrInet6Size)
|
||||
|
||||
case linux.AF_PACKET:
|
||||
// TODO(b/129292371): Return protocol too.
|
||||
var out linux.SockAddrLink
|
||||
out.Family = linux.AF_PACKET
|
||||
out.InterfaceIndex = int32(addr.NIC)
|
||||
out.HardwareAddrLen = header.EthernetAddressSize
|
||||
copy(out.HardwareAddr[:], addr.Addr)
|
||||
return &out, uint32(sockAddrLinkSize)
|
||||
|
||||
default:
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
@@ -62,6 +62,10 @@ func getTransportProtocol(ctx context.Context, stype linux.SockType, protocol in
|
||||
}
|
||||
|
||||
case linux.SOCK_RAW:
|
||||
// TODO(b/142504697): "In order to create a raw socket, a
|
||||
// process must have the CAP_NET_RAW capability in the user
|
||||
// namespace that governs its network namespace." - raw(7)
|
||||
|
||||
// Raw sockets require CAP_NET_RAW.
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
if !creds.HasCapability(linux.CAP_NET_RAW) {
|
||||
@@ -85,7 +89,8 @@ func getTransportProtocol(ctx context.Context, stype linux.SockType, protocol in
|
||||
return 0, true, syserr.ErrProtocolNotSupported
|
||||
}
|
||||
|
||||
// Socket creates a new socket object for the AF_INET or AF_INET6 family.
|
||||
// Socket creates a new socket object for the AF_INET, AF_INET6, or AF_PACKET
|
||||
// family.
|
||||
func (p *provider) Socket(t *kernel.Task, stype linux.SockType, protocol int) (*fs.File, *syserr.Error) {
|
||||
// Fail right away if we don't have a stack.
|
||||
stack := t.NetworkContext()
|
||||
@@ -99,6 +104,12 @@ func (p *provider) Socket(t *kernel.Task, stype linux.SockType, protocol int) (*
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Packet sockets are handled separately, since they are neither INET
|
||||
// nor INET6 specific.
|
||||
if p.family == linux.AF_PACKET {
|
||||
return packetSocket(t, eps, stype, protocol)
|
||||
}
|
||||
|
||||
// Figure out the transport protocol.
|
||||
transProto, associated, err := getTransportProtocol(t, stype, protocol)
|
||||
if err != nil {
|
||||
@@ -121,12 +132,47 @@ func (p *provider) Socket(t *kernel.Task, stype linux.SockType, protocol int) (*
|
||||
return New(t, p.family, stype, int(transProto), wq, ep)
|
||||
}
|
||||
|
||||
func packetSocket(t *kernel.Task, epStack *Stack, stype linux.SockType, protocol int) (*fs.File, *syserr.Error) {
|
||||
// TODO(b/142504697): "In order to create a packet socket, a process
|
||||
// must have the CAP_NET_RAW capability in the user namespace that
|
||||
// governs its network namespace." - packet(7)
|
||||
|
||||
// Packet sockets require CAP_NET_RAW.
|
||||
creds := auth.CredentialsFromContext(t)
|
||||
if !creds.HasCapability(linux.CAP_NET_RAW) {
|
||||
return nil, syserr.ErrNotPermitted
|
||||
}
|
||||
|
||||
// "cooked" packets don't contain link layer information.
|
||||
var cooked bool
|
||||
switch stype {
|
||||
case linux.SOCK_DGRAM:
|
||||
cooked = true
|
||||
case linux.SOCK_RAW:
|
||||
cooked = false
|
||||
default:
|
||||
return nil, syserr.ErrProtocolNotSupported
|
||||
}
|
||||
|
||||
// protocol is passed in network byte order, but netstack wants it in
|
||||
// host order.
|
||||
netProto := tcpip.NetworkProtocolNumber(ntohs(uint16(protocol)))
|
||||
|
||||
wq := &waiter.Queue{}
|
||||
ep, err := epStack.Stack.NewPacketEndpoint(cooked, netProto, wq)
|
||||
if err != nil {
|
||||
return nil, syserr.TranslateNetstackError(err)
|
||||
}
|
||||
|
||||
return New(t, linux.AF_PACKET, stype, protocol, wq, ep)
|
||||
}
|
||||
|
||||
// Pair just returns nil sockets (not supported).
|
||||
func (*provider) Pair(*kernel.Task, linux.SockType, int) (*fs.File, *fs.File, *syserr.Error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
// init registers socket providers for AF_INET and AF_INET6.
|
||||
// init registers socket providers for AF_INET, AF_INET6, and AF_PACKET.
|
||||
func init() {
|
||||
// Providers backed by netstack.
|
||||
p := []provider{
|
||||
@@ -138,6 +184,9 @@ func init() {
|
||||
family: linux.AF_INET6,
|
||||
netProto: ipv6.ProtocolNumber,
|
||||
},
|
||||
{
|
||||
family: linux.AF_PACKET,
|
||||
},
|
||||
}
|
||||
|
||||
for i := range p {
|
||||
|
||||
Reference in New Issue
Block a user