summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry')
-rw-r--r--pkg/sentry/inet/inet.go14
-rw-r--r--pkg/sentry/socket/hostinet/stack.go15
-rw-r--r--pkg/sentry/socket/netlink/route/protocol.go130
-rw-r--r--pkg/sentry/socket/netstack/stack.go93
4 files changed, 252 insertions, 0 deletions
diff --git a/pkg/sentry/inet/inet.go b/pkg/sentry/inet/inet.go
index b121fc1b4..f92706ab7 100644
--- a/pkg/sentry/inet/inet.go
+++ b/pkg/sentry/inet/inet.go
@@ -42,6 +42,12 @@ type Stack interface {
// identified by idx.
RemoveInterfaceAddr(idx int32, addr InterfaceAddr) error
+ AddNeighbor(neighbor Neighbor) error
+
+ RemoveNeighbor(neighbor Neighbor) error
+
+ Neighbors() ([]Neighbor, error)
+
// SupportsIPv6 returns true if the stack supports IPv6 connectivity.
SupportsIPv6() bool
@@ -137,6 +143,14 @@ type InterfaceAddr struct {
Addr []byte
}
+type Neighbor struct {
+ Family uint8
+ Idx int32
+ State uint16
+ Addr []byte
+ LinkAddr []byte
+}
+
// TCPBufferSize contains settings controlling TCP buffer sizing.
//
// +stateify savable
diff --git a/pkg/sentry/socket/hostinet/stack.go b/pkg/sentry/socket/hostinet/stack.go
index 61111ac6c..b80d64c9a 100644
--- a/pkg/sentry/socket/hostinet/stack.go
+++ b/pkg/sentry/socket/hostinet/stack.go
@@ -333,6 +333,21 @@ func (*Stack) RemoveInterfaceAddr(int32, inet.InterfaceAddr) error {
return linuxerr.EACCES
}
+// Neighbors implements inet.Stack.Neighbors.
+func (s *Stack) Neighbors() ([]inet.Neighbor, error) {
+ return nil, linuxerr.EACCES
+}
+
+// AddNeighbor implements inet.Stack.AddNeighbor.
+func (s *Stack) AddNeighbor(inet.Neighbor) error {
+ return linuxerr.EACCES
+}
+
+// RemoveNeighbor implements inet.Stack.RemoveNeighbor.
+func (s *Stack) RemoveNeighbor(inet.Neighbor) error {
+ return linuxerr.EACCES
+}
+
// SupportsIPv6 implements inet.Stack.SupportsIPv6.
func (s *Stack) SupportsIPv6() bool {
return s.supportsIPv6
diff --git a/pkg/sentry/socket/netlink/route/protocol.go b/pkg/sentry/socket/netlink/route/protocol.go
index d526acb73..38f714c48 100644
--- a/pkg/sentry/socket/netlink/route/protocol.go
+++ b/pkg/sentry/socket/netlink/route/protocol.go
@@ -275,6 +275,130 @@ func (p *Protocol) dumpAddrs(ctx context.Context, msg *netlink.Message, ms *netl
return nil
}
+// dumpNeighbors handles RTM_GETNEIGH dump requests.
+func (p *Protocol) dumpNeighbors(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
+ // RTM_GETNEIGH dump requests need not contain anything more than the
+ // netlink header and 1 byte protocol family common to all
+ // NETLINK_ROUTE requests.
+
+ // The RTM_GETNEIGH dump response is a set of RTM_NEWNEIGH messages each
+ // containing an NeighborMessage followed by a set of netlink
+ // attributes.
+
+ // We always send back an NLMSG_DONE.
+ ms.Multi = true
+
+ stack := inet.StackFromContext(ctx)
+ if stack == nil {
+ // No network devices.
+ return nil
+ }
+
+ nas, err := stack.Neighbors(); if err != nil {
+ return syserr.FromError(err)
+ }
+
+ for _, na := range nas {
+ m := ms.AddMessage(linux.NetlinkMessageHeader{
+ Type: linux.RTM_NEWNEIGH,
+ })
+
+ m.Put(&linux.NeighborMessage{
+ Family: na.Family,
+ IfIndex: na.Idx,
+ State: na.State,
+ })
+
+ m.PutAttr(linux.NDA_DST, primitive.AsByteSlice(na.Addr))
+ if len(na.LinkAddr) > 0 {
+ m.PutAttr(linux.NDA_LLADDR, primitive.AsByteSlice(na.LinkAddr))
+ }
+ }
+
+ return nil
+}
+
+// newNeigh handles RTM_NEWNEIGH requests.
+func (p *Protocol) newNeigh(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
+ stack := inet.StackFromContext(ctx)
+ if stack == nil {
+ // No network stack.
+ return syserr.ErrProtocolNotSupported
+ }
+
+ var nm linux.NeighborMessage
+ attrs, ok := msg.GetData(&nm)
+ if !ok {
+ return syserr.ErrInvalidArgument
+ }
+
+ var addr []byte
+ var llAddr []byte
+
+ for !attrs.Empty() {
+ ahdr, value, rest, ok := attrs.ParseFirst()
+ if !ok {
+ return syserr.ErrInvalidArgument
+ }
+ attrs = rest
+
+ switch ahdr.Type {
+ case linux.NDA_DST:
+ addr = value
+ case linux.NDA_LLADDR:
+ llAddr = value
+ default:
+ return syserr.ErrNotSupported
+ }
+ }
+
+ return syserr.FromError(stack.AddNeighbor(inet.Neighbor{
+ Family: nm.Family,
+ Idx: nm.IfIndex,
+ Addr: addr,
+ State: nm.State,
+ LinkAddr: llAddr,
+ }))
+}
+
+// delNeigh handles RTM_DELNEIGH requests.
+func (p *Protocol) delNeigh(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
+ stack := inet.StackFromContext(ctx)
+ if stack == nil {
+ // No network stack.
+ return syserr.ErrProtocolNotSupported
+ }
+
+ var nm linux.NeighborMessage
+ attrs, ok := msg.GetData(&nm)
+ if !ok {
+ return syserr.ErrInvalidArgument
+ }
+
+ var addr []byte
+
+ for !attrs.Empty() {
+ ahdr, value, rest, ok := attrs.ParseFirst()
+ if !ok {
+ return syserr.ErrInvalidArgument
+ }
+ attrs = rest
+
+ switch ahdr.Type {
+ case linux.NDA_DST:
+ addr = value
+ default:
+ return syserr.ErrNotSupported
+ }
+ }
+
+ return syserr.FromError(stack.RemoveNeighbor(inet.Neighbor{
+ Family: nm.Family,
+ Idx: nm.IfIndex,
+ Addr: addr,
+ }))
+}
+
// commonPrefixLen reports the length of the longest IP address prefix.
// This is a simplied version from Golang's src/net/addrselect.go.
func commonPrefixLen(a, b []byte) (cpl int) {
@@ -571,6 +695,8 @@ func (p *Protocol) ProcessMessage(ctx context.Context, msg *netlink.Message, ms
return p.dumpAddrs(ctx, msg, ms)
case linux.RTM_GETROUTE:
return p.dumpRoutes(ctx, msg, ms)
+ case linux.RTM_GETNEIGH:
+ return p.dumpNeighbors(ctx, msg, ms)
default:
return syserr.ErrNotSupported
}
@@ -586,6 +712,10 @@ func (p *Protocol) ProcessMessage(ctx context.Context, msg *netlink.Message, ms
return p.newAddr(ctx, msg, ms)
case linux.RTM_DELADDR:
return p.delAddr(ctx, msg, ms)
+ case linux.RTM_NEWNEIGH:
+ return p.newNeigh(ctx, msg, ms)
+ case linux.RTM_DELNEIGH:
+ return p.delNeigh(ctx, msg, ms)
default:
return syserr.ErrNotSupported
}
diff --git a/pkg/sentry/socket/netstack/stack.go b/pkg/sentry/socket/netstack/stack.go
index ea199f223..3fceb4cd5 100644
--- a/pkg/sentry/socket/netstack/stack.go
+++ b/pkg/sentry/socket/netstack/stack.go
@@ -204,6 +204,99 @@ func (s *Stack) RemoveInterfaceAddr(idx int32, addr inet.InterfaceAddr) error {
return nil
}
+func (s *Stack) appendNeighbor(ns []inet.Neighbor, id tcpip.NICID, family uint8, protocol tcpip.NetworkProtocolNumber) ([]inet.Neighbor, error) {
+ ne, err := s.Stack.Neighbors(id, protocol); if _, ok := err.(*tcpip.ErrNotSupported); ok {
+ return ns, nil
+ } else if err != nil {
+ return ns, syserr.TranslateNetstackError(err).ToError()
+ }
+
+ for _, ni := range ne {
+ var State uint16 = 0
+
+ switch ni.State {
+ case stack.Unknown:
+ State = linux.NUD_NONE
+ case stack.Incomplete:
+ State = linux.NUD_INCOMPLETE
+ case stack.Reachable:
+ State = linux.NUD_REACHABLE
+ case stack.Stale:
+ State = linux.NUD_STALE
+ case stack.Delay:
+ State = linux.NUD_DELAY
+ case stack.Probe:
+ State = linux.NUD_PROBE
+ case stack.Static:
+ State = linux.NUD_PERMANENT
+ case stack.Unreachable:
+ State = linux.NUD_FAILED
+ }
+
+ ns = append(ns, inet.Neighbor{
+ Family: family,
+ Idx: int32(id),
+ Addr: []byte(ni.Addr),
+ LinkAddr: []byte(ni.LinkAddr),
+ State: State,
+ })
+ }
+
+ return ns, nil
+}
+
+// Neighbors implements inet.Stack.Neighbors.
+func (s *Stack) Neighbors() ([]inet.Neighbor, error) {
+ var err error
+ ns := []inet.Neighbor{}
+ for id, _ := range s.Stack.NICInfo() {
+ ns, err = s.appendNeighbor(ns, id, linux.AF_INET, ipv4.ProtocolNumber); if err != nil {
+ return nil, err
+ }
+ ns, err = s.appendNeighbor(ns, id, linux.AF_INET6, ipv6.ProtocolNumber); if err != nil {
+ return nil, err
+ }
+ }
+
+ return ns, nil
+}
+
+func (s *Stack) AddNeighbor(n inet.Neighbor) error {
+ var protocol tcpip.NetworkProtocolNumber
+
+ switch n.Family {
+ case linux.AF_INET:
+ protocol = ipv4.ProtocolNumber
+ case linux.AF_INET6:
+ protocol = ipv6.ProtocolNumber
+ default:
+ panic(fmt.Sprintf("AddStaticNeighbor(%v) failed: unsupported family", n.Family))
+ }
+
+ if n.State != linux.NUD_PERMANENT {
+ return syserr.ErrInvalidArgument.ToError()
+ }
+
+ err := s.Stack.AddStaticNeighbor(tcpip.NICID(n.Idx), protocol, tcpip.Address(n.Addr), tcpip.LinkAddress(n.LinkAddr))
+ return syserr.TranslateNetstackError(err).ToError()
+}
+
+func (s *Stack) RemoveNeighbor(n inet.Neighbor) error {
+ var protocol tcpip.NetworkProtocolNumber
+
+ switch n.Family {
+ case linux.AF_INET:
+ protocol = ipv4.ProtocolNumber
+ case linux.AF_INET6:
+ protocol = ipv6.ProtocolNumber
+ default:
+ panic(fmt.Sprintf("RemoveNeighbor(%v) failed: unsupported family", n.Family))
+ }
+
+ err := s.Stack.RemoveNeighbor(tcpip.NICID(n.Idx), protocol, tcpip.Address(n.Addr))
+ return syserr.TranslateNetstackError(err).ToError()
+}
+
// TCPReceiveBufferSize implements inet.Stack.TCPReceiveBufferSize.
func (s *Stack) TCPReceiveBufferSize() (inet.TCPBufferSize, error) {
var rs tcpip.TCPReceiveBufferSizeRangeOption