diff options
-rw-r--r-- | pkg/sentry/socket/netstack/netstack.go | 11 | ||||
-rw-r--r-- | pkg/tcpip/tcpip.go | 5 | ||||
-rw-r--r-- | pkg/tcpip/transport/raw/endpoint.go | 34 | ||||
-rw-r--r-- | pkg/tcpip/transport/raw/raw_state_autogen.go | 43 |
4 files changed, 64 insertions, 29 deletions
diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go index e7d2c83d7..3b248a953 100644 --- a/pkg/sentry/socket/netstack/netstack.go +++ b/pkg/sentry/socket/netstack/netstack.go @@ -2112,13 +2112,22 @@ func setSockOptIP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *s } return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.ReceiveIPPacketInfoOption, v != 0)) + case linux.IP_HDRINCL: + if len(optVal) == 0 { + return nil + } + v, err := parseIntOrChar(optVal) + if err != nil { + return err + } + return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.IPHdrIncludedOption, v != 0)) + case linux.IP_ADD_SOURCE_MEMBERSHIP, linux.IP_BIND_ADDRESS_NO_PORT, linux.IP_BLOCK_SOURCE, linux.IP_CHECKSUM, linux.IP_DROP_SOURCE_MEMBERSHIP, linux.IP_FREEBIND, - linux.IP_HDRINCL, linux.IP_IPSEC_POLICY, linux.IP_MINTTL, linux.IP_MSFILTER, diff --git a/pkg/tcpip/tcpip.go b/pkg/tcpip/tcpip.go index 2f9872dc6..25534a10d 100644 --- a/pkg/tcpip/tcpip.go +++ b/pkg/tcpip/tcpip.go @@ -648,6 +648,11 @@ const ( // whether an IPv6 socket is to be restricted to sending and receiving // IPv6 packets only. V6OnlyOption + + // IPHdrIncludedOption is used by SetSockOpt to indicate for a raw + // endpoint that all packets being written have an IP header and the + // endpoint should not attach an IP header. + IPHdrIncludedOption ) // SockOptInt represents socket options which values have the int type. diff --git a/pkg/tcpip/transport/raw/endpoint.go b/pkg/tcpip/transport/raw/endpoint.go index 766c7648e..5b6e7d102 100644 --- a/pkg/tcpip/transport/raw/endpoint.go +++ b/pkg/tcpip/transport/raw/endpoint.go @@ -63,6 +63,7 @@ type endpoint struct { stack *stack.Stack `state:"manual"` waiterQueue *waiter.Queue associated bool + hdrIncluded bool // The following fields are used to manage the receive queue and are // protected by rcvMu. @@ -108,6 +109,7 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProt rcvBufSizeMax: 32 * 1024, sndBufSizeMax: 32 * 1024, associated: associated, + hdrIncluded: !associated, } // Override with stack defaults. @@ -182,10 +184,6 @@ func (e *endpoint) SetOwner(owner tcpip.PacketOwner) { // Read implements tcpip.Endpoint.Read. func (e *endpoint) Read(addr *tcpip.FullAddress) (buffer.View, tcpip.ControlMessages, *tcpip.Error) { - if !e.associated { - return buffer.View{}, tcpip.ControlMessages{}, tcpip.ErrInvalidOptionValue - } - e.rcvMu.Lock() // If there's no data to read, return that read would block or that the @@ -263,7 +261,7 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-c // If this is an unassociated socket and callee provided a nonzero // destination address, route using that address. - if !e.associated { + if e.hdrIncluded { ip := header.IPv4(payloadBytes) if !ip.IsValid(len(payloadBytes)) { e.mu.RUnlock() @@ -353,7 +351,7 @@ func (e *endpoint) finishWrite(payloadBytes []byte, route *stack.Route) (int64, } } - if !e.associated { + if e.hdrIncluded { if err := route.WriteHeaderIncludedPacket(&stack.PacketBuffer{ Data: buffer.View(payloadBytes).ToVectorisedView(), }); err != nil { @@ -513,6 +511,13 @@ func (e *endpoint) SetSockOpt(opt interface{}) *tcpip.Error { // SetSockOptBool implements tcpip.Endpoint.SetSockOptBool. func (e *endpoint) SetSockOptBool(opt tcpip.SockOptBool, v bool) *tcpip.Error { + switch opt { + case tcpip.IPHdrIncludedOption: + e.mu.Lock() + e.hdrIncluded = v + e.mu.Unlock() + return nil + } return tcpip.ErrUnknownProtocolOption } @@ -577,6 +582,12 @@ func (e *endpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) { case tcpip.KeepaliveEnabledOption: return false, nil + case tcpip.IPHdrIncludedOption: + e.mu.Lock() + v := e.hdrIncluded + e.mu.Unlock() + return v, nil + default: return false, tcpip.ErrUnknownProtocolOption } @@ -616,8 +627,15 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) { func (e *endpoint) HandlePacket(route *stack.Route, pkt *stack.PacketBuffer) { e.rcvMu.Lock() - // Drop the packet if our buffer is currently full. - if e.rcvClosed { + // Drop the packet if our buffer is currently full or if this is an unassociated + // endpoint (i.e endpoint created w/ IPPROTO_RAW). Such endpoints are send only + // See: https://man7.org/linux/man-pages/man7/raw.7.html + // + // An IPPROTO_RAW socket is send only. If you really want to receive + // all IP packets, use a packet(7) socket with the ETH_P_IP protocol. + // Note that packet sockets don't reassemble IP fragments, unlike raw + // sockets. + if e.rcvClosed || !e.associated { e.rcvMu.Unlock() e.stack.Stats().DroppedPackets.Increment() e.stats.ReceiveErrors.ClosedReceiver.Increment() diff --git a/pkg/tcpip/transport/raw/raw_state_autogen.go b/pkg/tcpip/transport/raw/raw_state_autogen.go index 669477cf9..853d60959 100644 --- a/pkg/tcpip/transport/raw/raw_state_autogen.go +++ b/pkg/tcpip/transport/raw/raw_state_autogen.go @@ -49,6 +49,7 @@ func (x *endpoint) StateFields() []string { "TransportEndpointInfo", "waiterQueue", "associated", + "hdrIncluded", "rcvList", "rcvBufSize", "rcvBufSizeMax", @@ -65,35 +66,37 @@ func (x *endpoint) StateFields() []string { func (x *endpoint) StateSave(m state.Sink) { x.beforeSave() var rcvBufSizeMax int = x.saveRcvBufSizeMax() - m.SaveValue(5, rcvBufSizeMax) + m.SaveValue(6, rcvBufSizeMax) m.Save(0, &x.TransportEndpointInfo) m.Save(1, &x.waiterQueue) m.Save(2, &x.associated) - m.Save(3, &x.rcvList) - m.Save(4, &x.rcvBufSize) - m.Save(6, &x.rcvClosed) - m.Save(7, &x.sndBufSize) - m.Save(8, &x.sndBufSizeMax) - m.Save(9, &x.closed) - m.Save(10, &x.connected) - m.Save(11, &x.bound) - m.Save(12, &x.owner) + m.Save(3, &x.hdrIncluded) + m.Save(4, &x.rcvList) + m.Save(5, &x.rcvBufSize) + m.Save(7, &x.rcvClosed) + m.Save(8, &x.sndBufSize) + m.Save(9, &x.sndBufSizeMax) + m.Save(10, &x.closed) + m.Save(11, &x.connected) + m.Save(12, &x.bound) + m.Save(13, &x.owner) } func (x *endpoint) StateLoad(m state.Source) { m.Load(0, &x.TransportEndpointInfo) m.Load(1, &x.waiterQueue) m.Load(2, &x.associated) - m.Load(3, &x.rcvList) - m.Load(4, &x.rcvBufSize) - m.Load(6, &x.rcvClosed) - m.Load(7, &x.sndBufSize) - m.Load(8, &x.sndBufSizeMax) - m.Load(9, &x.closed) - m.Load(10, &x.connected) - m.Load(11, &x.bound) - m.Load(12, &x.owner) - m.LoadValue(5, new(int), func(y interface{}) { x.loadRcvBufSizeMax(y.(int)) }) + m.Load(3, &x.hdrIncluded) + m.Load(4, &x.rcvList) + m.Load(5, &x.rcvBufSize) + m.Load(7, &x.rcvClosed) + m.Load(8, &x.sndBufSize) + m.Load(9, &x.sndBufSizeMax) + m.Load(10, &x.closed) + m.Load(11, &x.connected) + m.Load(12, &x.bound) + m.Load(13, &x.owner) + m.LoadValue(6, new(int), func(y interface{}) { x.loadRcvBufSizeMax(y.(int)) }) m.AfterLoad(x.afterLoad) } |