mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Internal change.
PiperOrigin-RevId: 294952610
This commit is contained in:
@@ -411,6 +411,15 @@ type ControlMessageCredentials struct {
|
||||
GID uint32
|
||||
}
|
||||
|
||||
// A ControlMessageIPPacketInfo is IP_PKTINFO socket control message.
|
||||
//
|
||||
// ControlMessageIPPacketInfo represents struct in_pktinfo from linux/in.h.
|
||||
type ControlMessageIPPacketInfo struct {
|
||||
NIC int32
|
||||
LocalAddr InetAddr
|
||||
DestinationAddr InetAddr
|
||||
}
|
||||
|
||||
// SizeOfControlMessageCredentials is the binary size of a
|
||||
// ControlMessageCredentials struct.
|
||||
var SizeOfControlMessageCredentials = int(binary.Size(ControlMessageCredentials{}))
|
||||
@@ -431,6 +440,10 @@ const SizeOfControlMessageTOS = 1
|
||||
// SizeOfControlMessageTClass is the size of an IPV6_TCLASS control message.
|
||||
const SizeOfControlMessageTClass = 4
|
||||
|
||||
// SizeOfControlMessageIPPacketInfo is the size of an IP_PKTINFO
|
||||
// control message.
|
||||
const SizeOfControlMessageIPPacketInfo = 12
|
||||
|
||||
// SCM_MAX_FD is the maximum number of FDs accepted in a single sendmsg call.
|
||||
// From net/scm.h.
|
||||
const SCM_MAX_FD = 253
|
||||
|
||||
@@ -19,6 +19,7 @@ go_library(
|
||||
"//pkg/sentry/socket",
|
||||
"//pkg/sentry/socket/unix/transport",
|
||||
"//pkg/syserror",
|
||||
"//pkg/tcpip",
|
||||
"//pkg/usermem",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/unix/transport"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
@@ -338,6 +339,22 @@ func PackTClass(t *kernel.Task, tClass int32, buf []byte) []byte {
|
||||
)
|
||||
}
|
||||
|
||||
// PackIPPacketInfo packs an IP_PKTINFO socket control message.
|
||||
func PackIPPacketInfo(t *kernel.Task, packetInfo tcpip.IPPacketInfo, buf []byte) []byte {
|
||||
var p linux.ControlMessageIPPacketInfo
|
||||
p.NIC = int32(packetInfo.NIC)
|
||||
copy(p.LocalAddr[:], []byte(packetInfo.LocalAddr))
|
||||
copy(p.DestinationAddr[:], []byte(packetInfo.DestinationAddr))
|
||||
|
||||
return putCmsgStruct(
|
||||
buf,
|
||||
linux.SOL_IP,
|
||||
linux.IP_PKTINFO,
|
||||
t.Arch().Width(),
|
||||
p,
|
||||
)
|
||||
}
|
||||
|
||||
// PackControlMessages packs control messages into the given buffer.
|
||||
//
|
||||
// We skip control messages specific to Unix domain sockets.
|
||||
@@ -362,6 +379,10 @@ func PackControlMessages(t *kernel.Task, cmsgs socket.ControlMessages, buf []byt
|
||||
buf = PackTClass(t, cmsgs.IP.TClass, buf)
|
||||
}
|
||||
|
||||
if cmsgs.IP.HasIPPacketInfo {
|
||||
buf = PackIPPacketInfo(t, cmsgs.IP.PacketInfo, buf)
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
@@ -394,6 +415,16 @@ func CmsgsSpace(t *kernel.Task, cmsgs socket.ControlMessages) int {
|
||||
return space
|
||||
}
|
||||
|
||||
// NewIPPacketInfo returns the IPPacketInfo struct.
|
||||
func NewIPPacketInfo(packetInfo linux.ControlMessageIPPacketInfo) tcpip.IPPacketInfo {
|
||||
var p tcpip.IPPacketInfo
|
||||
p.NIC = tcpip.NICID(packetInfo.NIC)
|
||||
copy([]byte(p.LocalAddr), packetInfo.LocalAddr[:])
|
||||
copy([]byte(p.DestinationAddr), packetInfo.DestinationAddr[:])
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// Parse parses a raw socket control message into portable objects.
|
||||
func Parse(t *kernel.Task, socketOrEndpoint interface{}, buf []byte) (socket.ControlMessages, error) {
|
||||
var (
|
||||
@@ -468,6 +499,18 @@ func Parse(t *kernel.Task, socketOrEndpoint interface{}, buf []byte) (socket.Con
|
||||
binary.Unmarshal(buf[i:i+linux.SizeOfControlMessageTOS], usermem.ByteOrder, &cmsgs.IP.TOS)
|
||||
i += binary.AlignUp(length, width)
|
||||
|
||||
case linux.IP_PKTINFO:
|
||||
if length < linux.SizeOfControlMessageIPPacketInfo {
|
||||
return socket.ControlMessages{}, syserror.EINVAL
|
||||
}
|
||||
|
||||
cmsgs.IP.HasIPPacketInfo = true
|
||||
var packetInfo linux.ControlMessageIPPacketInfo
|
||||
binary.Unmarshal(buf[i:i+linux.SizeOfControlMessageIPPacketInfo], usermem.ByteOrder, &packetInfo)
|
||||
|
||||
cmsgs.IP.PacketInfo = NewIPPacketInfo(packetInfo)
|
||||
i += binary.AlignUp(length, width)
|
||||
|
||||
default:
|
||||
return socket.ControlMessages{}, syserror.EINVAL
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ func (s *socketOperations) GetSockOpt(t *kernel.Task, level int, name int, outPt
|
||||
switch level {
|
||||
case linux.SOL_IP:
|
||||
switch name {
|
||||
case linux.IP_TOS, linux.IP_RECVTOS:
|
||||
case linux.IP_TOS, linux.IP_RECVTOS, linux.IP_PKTINFO:
|
||||
optlen = sizeofInt32
|
||||
}
|
||||
case linux.SOL_IPV6:
|
||||
@@ -336,6 +336,8 @@ func (s *socketOperations) SetSockOpt(t *kernel.Task, level int, name int, opt [
|
||||
switch name {
|
||||
case linux.IP_TOS, linux.IP_RECVTOS:
|
||||
optlen = sizeofInt32
|
||||
case linux.IP_PKTINFO:
|
||||
optlen = linux.SizeOfControlMessageIPPacketInfo
|
||||
}
|
||||
case linux.SOL_IPV6:
|
||||
switch name {
|
||||
@@ -473,7 +475,14 @@ func (s *socketOperations) RecvMsg(t *kernel.Task, dst usermem.IOSequence, flags
|
||||
case syscall.IP_TOS:
|
||||
controlMessages.IP.HasTOS = true
|
||||
binary.Unmarshal(unixCmsg.Data[:linux.SizeOfControlMessageTOS], usermem.ByteOrder, &controlMessages.IP.TOS)
|
||||
|
||||
case syscall.IP_PKTINFO:
|
||||
controlMessages.IP.HasIPPacketInfo = true
|
||||
var packetInfo linux.ControlMessageIPPacketInfo
|
||||
binary.Unmarshal(unixCmsg.Data[:linux.SizeOfControlMessageIPPacketInfo], usermem.ByteOrder, &packetInfo)
|
||||
controlMessages.IP.PacketInfo = control.NewIPPacketInfo(packetInfo)
|
||||
}
|
||||
|
||||
case syscall.SOL_IPV6:
|
||||
switch unixCmsg.Header.Type {
|
||||
case syscall.IPV6_TCLASS:
|
||||
|
||||
@@ -1414,6 +1414,21 @@ func getSockOptIP(t *kernel.Task, ep commonEndpoint, name, outLen int, family in
|
||||
}
|
||||
return o, nil
|
||||
|
||||
case linux.IP_PKTINFO:
|
||||
if outLen < sizeOfInt32 {
|
||||
return nil, syserr.ErrInvalidArgument
|
||||
}
|
||||
|
||||
v, err := ep.GetSockOptBool(tcpip.ReceiveIPPacketInfoOption)
|
||||
if err != nil {
|
||||
return nil, syserr.TranslateNetstackError(err)
|
||||
}
|
||||
var o int32
|
||||
if v {
|
||||
o = 1
|
||||
}
|
||||
return o, nil
|
||||
|
||||
default:
|
||||
emitUnimplementedEventIP(t, name)
|
||||
}
|
||||
@@ -1762,6 +1777,7 @@ func setSockOptIPv6(t *kernel.Task, ep commonEndpoint, name int, optVal []byte)
|
||||
linux.IPV6_IPSEC_POLICY,
|
||||
linux.IPV6_JOIN_ANYCAST,
|
||||
linux.IPV6_LEAVE_ANYCAST,
|
||||
// TODO(b/148887420): Add support for IPV6_PKTINFO.
|
||||
linux.IPV6_PKTINFO,
|
||||
linux.IPV6_ROUTER_ALERT,
|
||||
linux.IPV6_XFRM_POLICY,
|
||||
@@ -1949,6 +1965,16 @@ func setSockOptIP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *s
|
||||
}
|
||||
return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.ReceiveTOSOption, v != 0))
|
||||
|
||||
case linux.IP_PKTINFO:
|
||||
if len(optVal) == 0 {
|
||||
return nil
|
||||
}
|
||||
v, err := parseIntOrChar(optVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.ReceiveIPPacketInfoOption, v != 0))
|
||||
|
||||
case linux.IP_ADD_SOURCE_MEMBERSHIP,
|
||||
linux.IP_BIND_ADDRESS_NO_PORT,
|
||||
linux.IP_BLOCK_SOURCE,
|
||||
@@ -1964,7 +1990,6 @@ func setSockOptIP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *s
|
||||
linux.IP_NODEFRAG,
|
||||
linux.IP_OPTIONS,
|
||||
linux.IP_PASSSEC,
|
||||
linux.IP_PKTINFO,
|
||||
linux.IP_RECVERR,
|
||||
linux.IP_RECVFRAGSIZE,
|
||||
linux.IP_RECVOPTS,
|
||||
@@ -2395,10 +2420,12 @@ func (s *SocketOperations) nonBlockingRead(ctx context.Context, dst usermem.IOSe
|
||||
func (s *SocketOperations) controlMessages() socket.ControlMessages {
|
||||
return socket.ControlMessages{
|
||||
IP: tcpip.ControlMessages{
|
||||
HasTimestamp: s.readCM.HasTimestamp && s.sockOptTimestamp,
|
||||
Timestamp: s.readCM.Timestamp,
|
||||
HasTOS: s.readCM.HasTOS,
|
||||
TOS: s.readCM.TOS,
|
||||
HasTimestamp: s.readCM.HasTimestamp && s.sockOptTimestamp,
|
||||
Timestamp: s.readCM.Timestamp,
|
||||
HasTOS: s.readCM.HasTOS,
|
||||
TOS: s.readCM.TOS,
|
||||
HasIPPacketInfo: s.readCM.HasIPPacketInfo,
|
||||
PacketInfo: s.readCM.PacketInfo,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,6 +328,12 @@ type ControlMessages struct {
|
||||
|
||||
// Tclass is the IPv6 traffic class of the associated packet.
|
||||
TClass int32
|
||||
|
||||
// HasIPPacketInfo indicates whether PacketInfo is set.
|
||||
HasIPPacketInfo bool
|
||||
|
||||
// PacketInfo holds interface and address data on an incoming packet.
|
||||
PacketInfo IPPacketInfo
|
||||
}
|
||||
|
||||
// Endpoint is the interface implemented by transport protocols (e.g., tcp, udp)
|
||||
@@ -503,6 +509,11 @@ const (
|
||||
// V6OnlyOption is used by {G,S}etSockOptBool to specify whether an IPv6
|
||||
// socket is to be restricted to sending and receiving IPv6 packets only.
|
||||
V6OnlyOption
|
||||
|
||||
// ReceiveIPPacketInfoOption is used by {G,S}etSockOptBool to specify
|
||||
// if more inforamtion is provided with incoming packets such
|
||||
// as interface index and address.
|
||||
ReceiveIPPacketInfoOption
|
||||
)
|
||||
|
||||
// SockOptInt represents socket options which values have the int type.
|
||||
@@ -685,6 +696,20 @@ type IPv4TOSOption uint8
|
||||
// for all subsequent outgoing IPv6 packets from the endpoint.
|
||||
type IPv6TrafficClassOption uint8
|
||||
|
||||
// IPPacketInfo is the message struture for IP_PKTINFO.
|
||||
//
|
||||
// +stateify savable
|
||||
type IPPacketInfo struct {
|
||||
// NIC is the ID of the NIC to be used.
|
||||
NIC NICID
|
||||
|
||||
// LocalAddr is the local address.
|
||||
LocalAddr Address
|
||||
|
||||
// DestinationAddr is the destination address.
|
||||
DestinationAddr Address
|
||||
}
|
||||
|
||||
// Route is a row in the routing table. It specifies through which NIC (and
|
||||
// gateway) sets of packets should be routed. A row is considered viable if the
|
||||
// masked target address matches the destination address in the row.
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
type udpPacket struct {
|
||||
udpPacketEntry
|
||||
senderAddress tcpip.FullAddress
|
||||
packetInfo tcpip.IPPacketInfo
|
||||
data buffer.VectorisedView `state:".(buffer.VectorisedView)"`
|
||||
timestamp int64
|
||||
tos uint8
|
||||
@@ -118,6 +119,9 @@ type endpoint struct {
|
||||
// as ancillary data to ControlMessages on Read.
|
||||
receiveTOS bool
|
||||
|
||||
// receiveIPPacketInfo determines if the packet info is returned by Read.
|
||||
receiveIPPacketInfo bool
|
||||
|
||||
// shutdownFlags represent the current shutdown state of the endpoint.
|
||||
shutdownFlags tcpip.ShutdownFlags
|
||||
|
||||
@@ -254,11 +258,17 @@ func (e *endpoint) Read(addr *tcpip.FullAddress) (buffer.View, tcpip.ControlMess
|
||||
}
|
||||
e.mu.RLock()
|
||||
receiveTOS := e.receiveTOS
|
||||
receiveIPPacketInfo := e.receiveIPPacketInfo
|
||||
e.mu.RUnlock()
|
||||
if receiveTOS {
|
||||
cm.HasTOS = true
|
||||
cm.TOS = p.tos
|
||||
}
|
||||
|
||||
if receiveIPPacketInfo {
|
||||
cm.HasIPPacketInfo = true
|
||||
cm.PacketInfo = p.packetInfo
|
||||
}
|
||||
return p.data.ToView(), cm, nil
|
||||
}
|
||||
|
||||
@@ -495,6 +505,13 @@ func (e *endpoint) SetSockOptBool(opt tcpip.SockOptBool, v bool) *tcpip.Error {
|
||||
}
|
||||
|
||||
e.v6only = v
|
||||
return nil
|
||||
|
||||
case tcpip.ReceiveIPPacketInfoOption:
|
||||
e.mu.Lock()
|
||||
e.receiveIPPacketInfo = v
|
||||
e.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -703,6 +720,12 @@ func (e *endpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
|
||||
e.mu.RUnlock()
|
||||
|
||||
return v, nil
|
||||
|
||||
case tcpip.ReceiveIPPacketInfoOption:
|
||||
e.mu.RLock()
|
||||
v := e.receiveIPPacketInfo
|
||||
e.mu.RUnlock()
|
||||
return v, nil
|
||||
}
|
||||
|
||||
return false, tcpip.ErrUnknownProtocolOption
|
||||
@@ -1247,6 +1270,9 @@ func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, pk
|
||||
switch r.NetProto {
|
||||
case header.IPv4ProtocolNumber:
|
||||
packet.tos, _ = header.IPv4(pkt.NetworkHeader).TOS()
|
||||
packet.packetInfo.LocalAddr = r.LocalAddress
|
||||
packet.packetInfo.DestinationAddr = r.RemoteAddress
|
||||
packet.packetInfo.NIC = r.NICID()
|
||||
}
|
||||
|
||||
packet.timestamp = e.stack.NowNanoseconds()
|
||||
|
||||
@@ -357,5 +357,49 @@ TEST_P(UDPSocketPairTest, SetReuseAddrReusePort) {
|
||||
EXPECT_EQ(get, kSockOptOn);
|
||||
}
|
||||
|
||||
// Test getsockopt for a socket which is not set with IP_PKTINFO option.
|
||||
TEST_P(UDPSocketPairTest, IPPKTINFODefault) {
|
||||
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
|
||||
|
||||
int get = -1;
|
||||
socklen_t get_len = sizeof(get);
|
||||
|
||||
ASSERT_THAT(
|
||||
getsockopt(sockets->first_fd(), SOL_IP, IP_PKTINFO, &get, &get_len),
|
||||
SyscallSucceedsWithValue(0));
|
||||
EXPECT_EQ(get_len, sizeof(get));
|
||||
EXPECT_EQ(get, kSockOptOff);
|
||||
}
|
||||
|
||||
// Test setsockopt and getsockopt for a socket with IP_PKTINFO option.
|
||||
TEST_P(UDPSocketPairTest, SetAndGetIPPKTINFO) {
|
||||
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
|
||||
|
||||
int level = SOL_IP;
|
||||
int type = IP_PKTINFO;
|
||||
|
||||
// Check getsockopt before IP_PKTINFO is set.
|
||||
int get = -1;
|
||||
socklen_t get_len = sizeof(get);
|
||||
|
||||
ASSERT_THAT(setsockopt(sockets->first_fd(), level, type, &kSockOptOn,
|
||||
sizeof(kSockOptOn)),
|
||||
SyscallSucceedsWithValue(0));
|
||||
|
||||
ASSERT_THAT(getsockopt(sockets->first_fd(), level, type, &get, &get_len),
|
||||
SyscallSucceedsWithValue(0));
|
||||
EXPECT_EQ(get, kSockOptOn);
|
||||
EXPECT_EQ(get_len, sizeof(get));
|
||||
|
||||
ASSERT_THAT(setsockopt(sockets->first_fd(), level, type, &kSockOptOff,
|
||||
sizeof(kSockOptOff)),
|
||||
SyscallSucceedsWithValue(0));
|
||||
|
||||
ASSERT_THAT(getsockopt(sockets->first_fd(), level, type, &get, &get_len),
|
||||
SyscallSucceedsWithValue(0));
|
||||
EXPECT_EQ(get, kSockOptOff);
|
||||
EXPECT_EQ(get_len, sizeof(get));
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "test/syscalls/linux/socket_ipv4_udp_unbound.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
@@ -2128,5 +2129,88 @@ TEST_P(IPv4UDPUnboundSocketTest, ReuseAddrReusePortDistribution) {
|
||||
SyscallSucceedsWithValue(kMessageSize));
|
||||
}
|
||||
|
||||
// Test that socket will receive packet info control message.
|
||||
TEST_P(IPv4UDPUnboundSocketTest, SetAndReceiveIPPKTINFO) {
|
||||
// TODO(gvisor.dev/issue/1202): ioctl() is not supported by hostinet.
|
||||
SKIP_IF((IsRunningWithHostinet()));
|
||||
|
||||
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
|
||||
auto receiver = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
|
||||
auto sender_addr = V4Loopback();
|
||||
int level = SOL_IP;
|
||||
int type = IP_PKTINFO;
|
||||
|
||||
ASSERT_THAT(
|
||||
bind(receiver->get(), reinterpret_cast<sockaddr*>(&sender_addr.addr),
|
||||
sender_addr.addr_len),
|
||||
SyscallSucceeds());
|
||||
socklen_t sender_addr_len = sender_addr.addr_len;
|
||||
ASSERT_THAT(getsockname(receiver->get(),
|
||||
reinterpret_cast<sockaddr*>(&sender_addr.addr),
|
||||
&sender_addr_len),
|
||||
SyscallSucceeds());
|
||||
EXPECT_EQ(sender_addr_len, sender_addr.addr_len);
|
||||
|
||||
auto receiver_addr = V4Loopback();
|
||||
reinterpret_cast<sockaddr_in*>(&receiver_addr.addr)->sin_port =
|
||||
reinterpret_cast<sockaddr_in*>(&sender_addr.addr)->sin_port;
|
||||
ASSERT_THAT(
|
||||
connect(sender->get(), reinterpret_cast<sockaddr*>(&receiver_addr.addr),
|
||||
receiver_addr.addr_len),
|
||||
SyscallSucceeds());
|
||||
|
||||
// Allow socket to receive control message.
|
||||
ASSERT_THAT(
|
||||
setsockopt(receiver->get(), level, type, &kSockOptOn, sizeof(kSockOptOn)),
|
||||
SyscallSucceeds());
|
||||
|
||||
// Prepare message to send.
|
||||
constexpr size_t kDataLength = 1024;
|
||||
msghdr sent_msg = {};
|
||||
iovec sent_iov = {};
|
||||
char sent_data[kDataLength];
|
||||
sent_iov.iov_base = sent_data;
|
||||
sent_iov.iov_len = kDataLength;
|
||||
sent_msg.msg_iov = &sent_iov;
|
||||
sent_msg.msg_iovlen = 1;
|
||||
sent_msg.msg_flags = 0;
|
||||
|
||||
ASSERT_THAT(RetryEINTR(sendmsg)(sender->get(), &sent_msg, 0),
|
||||
SyscallSucceedsWithValue(kDataLength));
|
||||
|
||||
msghdr received_msg = {};
|
||||
iovec received_iov = {};
|
||||
char received_data[kDataLength];
|
||||
char received_cmsg_buf[CMSG_SPACE(sizeof(in_pktinfo))] = {};
|
||||
size_t cmsg_data_len = sizeof(in_pktinfo);
|
||||
received_iov.iov_base = received_data;
|
||||
received_iov.iov_len = kDataLength;
|
||||
received_msg.msg_iov = &received_iov;
|
||||
received_msg.msg_iovlen = 1;
|
||||
received_msg.msg_controllen = CMSG_LEN(cmsg_data_len);
|
||||
received_msg.msg_control = received_cmsg_buf;
|
||||
|
||||
ASSERT_THAT(RetryEINTR(recvmsg)(receiver->get(), &received_msg, 0),
|
||||
SyscallSucceedsWithValue(kDataLength));
|
||||
|
||||
cmsghdr* cmsg = CMSG_FIRSTHDR(&received_msg);
|
||||
ASSERT_NE(cmsg, nullptr);
|
||||
EXPECT_EQ(cmsg->cmsg_len, CMSG_LEN(cmsg_data_len));
|
||||
EXPECT_EQ(cmsg->cmsg_level, level);
|
||||
EXPECT_EQ(cmsg->cmsg_type, type);
|
||||
|
||||
// Get loopback index.
|
||||
ifreq ifr = {};
|
||||
absl::SNPrintF(ifr.ifr_name, IFNAMSIZ, "lo");
|
||||
ASSERT_THAT(ioctl(sender->get(), SIOCGIFINDEX, &ifr), SyscallSucceeds());
|
||||
ASSERT_NE(ifr.ifr_ifindex, 0);
|
||||
|
||||
// Check the data
|
||||
in_pktinfo received_pktinfo = {};
|
||||
memcpy(&received_pktinfo, CMSG_DATA(cmsg), sizeof(in_pktinfo));
|
||||
EXPECT_EQ(received_pktinfo.ipi_ifindex, ifr.ifr_ifindex);
|
||||
EXPECT_EQ(received_pktinfo.ipi_spec_dst.s_addr, htonl(INADDR_LOOPBACK));
|
||||
EXPECT_EQ(received_pktinfo.ipi_addr.s_addr, htonl(INADDR_LOOPBACK));
|
||||
}
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
||||
|
||||
@@ -1495,6 +1495,5 @@ TEST_P(UdpSocketTest, SendAndReceiveTOS) {
|
||||
memcpy(&received_tos, CMSG_DATA(cmsg), sizeof(received_tos));
|
||||
EXPECT_EQ(received_tos, sent_tos);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
||||
|
||||
Reference in New Issue
Block a user