diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/abi/linux/socket.go | 21 | ||||
-rw-r--r-- | pkg/sentry/socket/epsocket/epsocket.go | 46 | ||||
-rw-r--r-- | pkg/tcpip/stack/stack.go | 7 | ||||
-rw-r--r-- | pkg/tcpip/transport/udp/endpoint.go | 16 | ||||
-rw-r--r-- | pkg/tcpip/transport/udp/endpoint_state.go | 6 |
5 files changed, 86 insertions, 10 deletions
diff --git a/pkg/abi/linux/socket.go b/pkg/abi/linux/socket.go index a5f78506a..906776525 100644 --- a/pkg/abi/linux/socket.go +++ b/pkg/abi/linux/socket.go @@ -204,15 +204,30 @@ const ( // uapi/linux/socket.h. const SockAddrMax = 128 -// SockAddrInt is struct sockaddr_in, from uapi/linux/in.h. +// InetAddr is struct in_addr, from uapi/linux/in.h. +type InetAddr [4]byte + +// SockAddrInet is struct sockaddr_in, from uapi/linux/in.h. type SockAddrInet struct { Family uint16 Port uint16 - Addr [4]byte + Addr InetAddr Zero [8]uint8 // pad to sizeof(struct sockaddr). } -// SockAddrInt6 is struct sockaddr_in6, from uapi/linux/in6.h. +// InetMulticastRequest is struct ip_mreq, from uapi/linux/in.h. +type InetMulticastRequest struct { + MulticastAddr InetAddr + InterfaceAddr InetAddr +} + +// InetMulticastRequestWithNIC is struct ip_mreqn, from uapi/linux/in.h. +type InetMulticastRequestWithNIC struct { + InetMulticastRequest + InterfaceIndex int32 +} + +// SockAddrInet6 is struct sockaddr_in6, from uapi/linux/in6.h. type SockAddrInet6 struct { Family uint16 Port uint16 diff --git a/pkg/sentry/socket/epsocket/epsocket.go b/pkg/sentry/socket/epsocket/epsocket.go index ca865b111..16720456a 100644 --- a/pkg/sentry/socket/epsocket/epsocket.go +++ b/pkg/sentry/socket/epsocket/epsocket.go @@ -1078,6 +1078,25 @@ func setSockOptIPv6(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) return syserr.TranslateNetstackError(ep.SetSockOpt(struct{}{})) } +var ( + inetMulticastRequestSize = int(binary.Size(linux.InetMulticastRequest{})) + inetMulticastRequestWithNICSize = int(binary.Size(linux.InetMulticastRequestWithNIC{})) +) + +func copyInMulticastRequest(optVal []byte) (linux.InetMulticastRequestWithNIC, *syserr.Error) { + if len(optVal) < inetMulticastRequestSize { + return linux.InetMulticastRequestWithNIC{}, syserr.ErrInvalidArgument + } + + var req linux.InetMulticastRequestWithNIC + if len(optVal) >= inetMulticastRequestWithNICSize { + binary.Unmarshal(optVal[:inetMulticastRequestWithNICSize], usermem.ByteOrder, &req) + } else { + binary.Unmarshal(optVal[:inetMulticastRequestSize], usermem.ByteOrder, &req.InetMulticastRequest) + } + return req, nil +} + // setSockOptIP implements SetSockOpt when level is SOL_IP. func setSockOptIP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *syserr.Error { switch name { @@ -1096,7 +1115,31 @@ func setSockOptIP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *s } return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.MulticastTTLOption(v))) - case linux.IP_ADD_MEMBERSHIP, linux.MCAST_JOIN_GROUP, linux.IP_MULTICAST_IF: + case linux.IP_ADD_MEMBERSHIP: + req, err := copyInMulticastRequest(optVal) + if err != nil { + return err + } + + return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.AddMembershipOption{ + NIC: tcpip.NICID(req.InterfaceIndex), + InterfaceAddr: tcpip.Address(req.InterfaceAddr[:]), + MulticastAddr: tcpip.Address(req.MulticastAddr[:]), + })) + + case linux.IP_DROP_MEMBERSHIP: + req, err := copyInMulticastRequest(optVal) + if err != nil { + return err + } + + return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.RemoveMembershipOption{ + NIC: tcpip.NICID(req.InterfaceIndex), + InterfaceAddr: tcpip.Address(req.InterfaceAddr[:]), + MulticastAddr: tcpip.Address(req.MulticastAddr[:]), + })) + + case linux.MCAST_JOIN_GROUP, linux.IP_MULTICAST_IF: // FIXME: Disallow IP-level multicast group options by // default. These will need to be supported by appropriately plumbing // the level through to the network stack (if at all). However, we @@ -1108,7 +1151,6 @@ func setSockOptIP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *s linux.IP_BIND_ADDRESS_NO_PORT, linux.IP_BLOCK_SOURCE, linux.IP_CHECKSUM, - linux.IP_DROP_MEMBERSHIP, linux.IP_DROP_SOURCE_MEMBERSHIP, linux.IP_FREEBIND, linux.IP_HDRINCL, diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index 7aa9dbd46..854ebe1bb 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -742,6 +742,9 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n return Route{}, tcpip.ErrNoRoute } + // TODO: Route multicast packets with no specified local + // address or NIC. + for i := range s.routeTable { if (id != 0 && id != s.routeTable[i].NIC) || (len(remoteAddr) != 0 && !s.routeTable[i].Match(remoteAddr)) { continue @@ -768,6 +771,10 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n return r, nil } + if isMulticast { + return Route{}, tcpip.ErrNetworkUnreachable + } + return Route{}, tcpip.ErrNoRoute } diff --git a/pkg/tcpip/transport/udp/endpoint.go b/pkg/tcpip/transport/udp/endpoint.go index b2a27a7cb..d46bf0ade 100644 --- a/pkg/tcpip/transport/udp/endpoint.go +++ b/pkg/tcpip/transport/udp/endpoint.go @@ -99,6 +99,7 @@ type endpoint struct { effectiveNetProtos []tcpip.NetworkProtocolNumber } +// +stateify savable type multicastMembership struct { nicID tcpip.NICID multicastAddr tcpip.Address @@ -412,6 +413,8 @@ func (e *endpoint) SetSockOpt(opt interface{}) *tcpip.Error { nicID = e.stack.CheckLocalAddress(nicID, e.netProto, v.InterfaceAddr) } if nicID == 0 { + // TODO: Allow adding memberships without + // specifing an interface. return tcpip.ErrNoRoute } @@ -766,9 +769,11 @@ func (e *endpoint) bindLocked(addr tcpip.FullAddress, commit func() *tcpip.Error } } + nicid := addr.NIC if len(addr.Addr) != 0 { // A local address was specified, verify that it's valid. - if e.stack.CheckLocalAddress(addr.NIC, netProto, addr.Addr) == 0 { + nicid = e.stack.CheckLocalAddress(addr.NIC, netProto, addr.Addr) + if nicid == 0 { return tcpip.ErrBadLocalAddress } } @@ -777,21 +782,21 @@ func (e *endpoint) bindLocked(addr tcpip.FullAddress, commit func() *tcpip.Error LocalPort: addr.Port, LocalAddress: addr.Addr, } - id, err = e.registerWithStack(addr.NIC, netProtos, id) + id, err = e.registerWithStack(nicid, netProtos, id) if err != nil { return err } if commit != nil { if err := commit(); err != nil { // Unregister, the commit failed. - e.stack.UnregisterTransportEndpoint(addr.NIC, netProtos, ProtocolNumber, id, e) + e.stack.UnregisterTransportEndpoint(nicid, netProtos, ProtocolNumber, id, e) e.stack.ReleasePort(netProtos, ProtocolNumber, id.LocalAddress, id.LocalPort) return err } } e.id = id - e.regNICID = addr.NIC + e.regNICID = nicid e.effectiveNetProtos = netProtos // Mark endpoint as bound. @@ -815,7 +820,8 @@ func (e *endpoint) Bind(addr tcpip.FullAddress, commit func() *tcpip.Error) *tcp return err } - e.bindNICID = addr.NIC + // Save the effective NICID generated by bindLocked. + e.bindNICID = e.regNICID return nil } diff --git a/pkg/tcpip/transport/udp/endpoint_state.go b/pkg/tcpip/transport/udp/endpoint_state.go index db1e281ad..4d8210294 100644 --- a/pkg/tcpip/transport/udp/endpoint_state.go +++ b/pkg/tcpip/transport/udp/endpoint_state.go @@ -103,4 +103,10 @@ func (e *endpoint) afterLoad() { if err != nil { panic(*err) } + + for _, m := range e.multicastMemberships { + if err := e.stack.JoinGroup(e.netProto, m.nicID, m.multicastAddr); err != nil { + panic(err) + } + } } |