summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorKevin Krakauer <krakauer@google.com>2019-05-05 16:06:11 -0700
committerShentubot <shentubot@google.com>2019-05-05 16:07:25 -0700
commitff8ed5e6a5a391c5465230121af09afa5d1906e9 (patch)
tree7ce5c0fc2db7745ac102e23c7fa2b657f556949e
parentebe2f78d9bc8639f0967c08777a3c9431ac44700 (diff)
Fix raw socket behavior and tests.
Some behavior was broken due to the difficulty of running automated raw socket tests. Change-Id: I152ca53916bb24a0208f2dc1c4f5bc87f4724ff6 PiperOrigin-RevId: 246747067
-rw-r--r--pkg/tcpip/network/ipv4/icmp.go17
-rw-r--r--pkg/tcpip/transport/icmp/endpoint.go16
-rw-r--r--pkg/tcpip/transport/raw/endpoint.go45
-rw-r--r--test/syscalls/linux/raw_socket_ipv4.cc208
-rw-r--r--test/syscalls/syscall_test_runner.go1
5 files changed, 176 insertions, 111 deletions
diff --git a/pkg/tcpip/network/ipv4/icmp.go b/pkg/tcpip/network/ipv4/icmp.go
index 9cb81245a..770f56c3d 100644
--- a/pkg/tcpip/network/ipv4/icmp.go
+++ b/pkg/tcpip/network/ipv4/icmp.go
@@ -72,7 +72,24 @@ func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, vv buffer.V
received.Invalid.Increment()
return
}
+
+ // Only send a reply if the checksum is valid.
+ wantChecksum := h.Checksum()
+ // Reset the checksum field to 0 to can calculate the proper
+ // checksum. We'll have to reset this before we hand the packet
+ // off.
+ h.SetChecksum(0)
+ gotChecksum := ^header.ChecksumVV(vv, 0 /* initial */)
+ if gotChecksum != wantChecksum {
+ // It's possible that a raw socket expects to receive this.
+ h.SetChecksum(wantChecksum)
+ e.dispatcher.DeliverTransportPacket(r, header.ICMPv4ProtocolNumber, netHeader, vv)
+ received.Invalid.Increment()
+ return
+ }
+
// It's possible that a raw socket expects to receive this.
+ h.SetChecksum(wantChecksum)
e.dispatcher.DeliverTransportPacket(r, header.ICMPv4ProtocolNumber, netHeader, vv)
vv := vv.Clone(nil)
diff --git a/pkg/tcpip/transport/icmp/endpoint.go b/pkg/tcpip/transport/icmp/endpoint.go
index 00840cfcf..cc384dd3d 100644
--- a/pkg/tcpip/transport/icmp/endpoint.go
+++ b/pkg/tcpip/transport/icmp/endpoint.go
@@ -661,6 +661,22 @@ func (e *endpoint) Readiness(mask waiter.EventMask) waiter.EventMask {
// HandlePacket is called by the stack when new packets arrive to this transport
// endpoint.
func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, vv buffer.VectorisedView) {
+ // Only accept echo replies.
+ switch e.netProto {
+ case header.IPv4ProtocolNumber:
+ h := header.ICMPv4(vv.First())
+ if h.Type() != header.ICMPv4EchoReply {
+ e.stack.Stats().DroppedPackets.Increment()
+ return
+ }
+ case header.IPv6ProtocolNumber:
+ h := header.ICMPv6(vv.First())
+ if h.Type() != header.ICMPv6EchoReply {
+ e.stack.Stats().DroppedPackets.Increment()
+ return
+ }
+ }
+
e.rcvMu.Lock()
// Drop the packet if our buffer is currently full.
diff --git a/pkg/tcpip/transport/raw/endpoint.go b/pkg/tcpip/transport/raw/endpoint.go
index 7004c7ff4..1a16a3607 100644
--- a/pkg/tcpip/transport/raw/endpoint.go
+++ b/pkg/tcpip/transport/raw/endpoint.go
@@ -80,11 +80,9 @@ type endpoint struct {
// The following fields are protected by mu.
mu sync.RWMutex `state:"nosave"`
sndBufSize int
- // shutdownFlags represent the current shutdown state of the endpoint.
- shutdownFlags tcpip.ShutdownFlags
- closed bool
- connected bool
- bound bool
+ closed bool
+ connected bool
+ bound bool
// registeredNIC is the NIC to which th endpoint is explicitly
// registered. Is set when Connect or Bind are used to specify a NIC.
registeredNIC tcpip.NICID
@@ -192,12 +190,6 @@ func (ep *endpoint) Write(payload tcpip.Payload, opts tcpip.WriteOptions) (uintp
return 0, nil, tcpip.ErrInvalidEndpointState
}
- // Check whether we've shutdown writing.
- if ep.shutdownFlags&tcpip.ShutdownWrite != 0 {
- ep.mu.RUnlock()
- return 0, nil, tcpip.ErrClosedForSend
- }
-
// Did the user caller provide a destination? If not, use the connected
// destination.
if opts.To == nil {
@@ -205,7 +197,7 @@ func (ep *endpoint) Write(payload tcpip.Payload, opts tcpip.WriteOptions) (uintp
// connected to another address.
if !ep.connected {
ep.mu.RUnlock()
- return 0, nil, tcpip.ErrNotConnected
+ return 0, nil, tcpip.ErrDestinationRequired
}
if ep.route.IsResolutionRequired() {
@@ -355,7 +347,7 @@ func (ep *endpoint) Connect(addr tcpip.FullAddress) *tcpip.Error {
return nil
}
-// Shutdown implements tcpip.Endpoint.Shutdown.
+// Shutdown implements tcpip.Endpoint.Shutdown. It's a noop for raw sockets.
func (ep *endpoint) Shutdown(flags tcpip.ShutdownFlags) *tcpip.Error {
ep.mu.Lock()
defer ep.mu.Unlock()
@@ -363,20 +355,6 @@ func (ep *endpoint) Shutdown(flags tcpip.ShutdownFlags) *tcpip.Error {
if !ep.connected {
return tcpip.ErrNotConnected
}
-
- ep.shutdownFlags |= flags
-
- if flags&tcpip.ShutdownRead != 0 {
- ep.rcvMu.Lock()
- wasClosed := ep.rcvClosed
- ep.rcvClosed = true
- ep.rcvMu.Unlock()
-
- if !wasClosed {
- ep.waiterQueue.Notify(waiter.EventIn)
- }
- }
-
return nil
}
@@ -427,17 +405,8 @@ func (ep *endpoint) GetLocalAddress() (tcpip.FullAddress, *tcpip.Error) {
// GetRemoteAddress implements tcpip.Endpoint.GetRemoteAddress.
func (ep *endpoint) GetRemoteAddress() (tcpip.FullAddress, *tcpip.Error) {
- ep.mu.RLock()
- defer ep.mu.RUnlock()
-
- if !ep.connected {
- return tcpip.FullAddress{}, tcpip.ErrNotConnected
- }
-
- return tcpip.FullAddress{
- NIC: ep.registeredNIC,
- Addr: ep.route.RemoteAddress,
- }, nil
+ // Even a connected socket doesn't return a remote address.
+ return tcpip.FullAddress{}, tcpip.ErrNotConnected
}
// Readiness implements tcpip.Endpoint.Readiness.
diff --git a/test/syscalls/linux/raw_socket_ipv4.cc b/test/syscalls/linux/raw_socket_ipv4.cc
index e20b5cb50..f30fb8fe3 100644
--- a/test/syscalls/linux/raw_socket_ipv4.cc
+++ b/test/syscalls/linux/raw_socket_ipv4.cc
@@ -29,6 +29,9 @@
#include "test/util/file_descriptor.h"
#include "test/util/test_util.h"
+// Note: in order to run these tests, /proc/sys/net/ipv4/ping_group_range will
+// need to be configured to let the superuser create ping sockets (see icmp(7)).
+
namespace gvisor {
namespace testing {
@@ -58,6 +61,9 @@ class RawSocketTest : public ::testing::Test {
void ReceiveICMPFrom(char* recv_buf, size_t recv_buf_len,
size_t expected_size, struct sockaddr_in* src, int sock);
+ // Compute the internet checksum of the ICMP header (assuming no payload).
+ unsigned short Checksum(struct icmphdr* icmp);
+
// The socket used for both reading and writing.
int s_;
@@ -95,8 +101,9 @@ TEST_F(RawSocketTest, MultipleCreation) {
ASSERT_THAT(close(s2), SyscallSucceeds());
}
-// Send and receive an ICMP packet.
-TEST_F(RawSocketTest, SendAndReceive) {
+// We'll only read an echo in this case, as the kernel won't respond to the
+// malformed ICMP checksum.
+TEST_F(RawSocketTest, SendAndReceiveBadChecksum) {
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
// Prepare and send an ICMP packet. Use arbitrary junk for checksum, sequence,
@@ -105,11 +112,41 @@ TEST_F(RawSocketTest, SendAndReceive) {
struct icmphdr icmp;
icmp.type = ICMP_ECHO;
icmp.code = 0;
- icmp.checksum = 2011;
+ icmp.checksum = 0;
icmp.un.echo.sequence = 2012;
icmp.un.echo.id = 2014;
ASSERT_NO_FATAL_FAILURE(SendEmptyICMP(icmp));
+ // Veryify that we get the echo, then that there's nothing else to read.
+ char recv_buf[sizeof(icmp) + sizeof(struct iphdr)];
+ struct sockaddr_in src;
+ ASSERT_NO_FATAL_FAILURE(
+ ReceiveICMP(recv_buf, sizeof(recv_buf), sizeof(struct icmphdr), &src));
+ EXPECT_EQ(memcmp(&src, &addr_, sizeof(src)), 0);
+ // The packet should be identical to what we sent.
+ EXPECT_EQ(memcmp(recv_buf + sizeof(struct iphdr), &icmp, sizeof(icmp)), 0);
+
+ // And there should be nothing left to read.
+ EXPECT_THAT(RetryEINTR(recv)(s_, recv_buf, sizeof(recv_buf), MSG_DONTWAIT),
+ SyscallFailsWithErrno(EAGAIN));
+}
+
+// Send and receive an ICMP packet.
+TEST_F(RawSocketTest, SendAndReceive) {
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+
+ // Prepare and send an ICMP packet. Use arbitrary junk for sequence and ID.
+ // None of that should matter for raw sockets - the kernel should still give
+ // us the packet.
+ struct icmphdr icmp;
+ icmp.type = ICMP_ECHO;
+ icmp.code = 0;
+ icmp.checksum = 0;
+ icmp.un.echo.sequence = 2012;
+ icmp.un.echo.id = 2014;
+ icmp.checksum = Checksum(&icmp);
+ ASSERT_NO_FATAL_FAILURE(SendEmptyICMP(icmp));
+
ASSERT_NO_FATAL_FAILURE(ExpectICMPSuccess(icmp));
}
@@ -121,29 +158,30 @@ TEST_F(RawSocketTest, MultipleSocketReceive) {
FileDescriptor s2 =
ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP));
- // Prepare and send an ICMP packet. Use arbitrary junk for checksum, sequence,
- // and ID. None of that should matter for raw sockets - the kernel should
- // still give us the packet.
+ // Prepare and send an ICMP packet. Use arbitrary junk for sequence and ID.
+ // None of that should matter for raw sockets - the kernel should still give
+ // us the packet.
struct icmphdr icmp;
icmp.type = ICMP_ECHO;
icmp.code = 0;
- icmp.checksum = 2014;
+ icmp.checksum = 0;
icmp.un.echo.sequence = 2016;
icmp.un.echo.id = 2018;
+ icmp.checksum = Checksum(&icmp);
ASSERT_NO_FATAL_FAILURE(SendEmptyICMP(icmp));
// Both sockets will receive the echo request and reply in indeterminate
// order, so we'll need to read 2 packets from each.
// Receive on socket 1.
- constexpr int kBufSize = 256;
+ constexpr int kBufSize = sizeof(icmp) + sizeof(struct iphdr);
std::vector<char[kBufSize]> recv_buf1(2);
struct sockaddr_in src;
for (int i = 0; i < 2; i++) {
ASSERT_NO_FATAL_FAILURE(ReceiveICMP(recv_buf1[i],
ABSL_ARRAYSIZE(recv_buf1[i]),
sizeof(struct icmphdr), &src));
- EXPECT_EQ(memcmp(&src, &addr_, sizeof(sockaddr_in)), 0);
+ EXPECT_EQ(memcmp(&src, &addr_, sizeof(src)), 0);
}
// Receive on socket 2.
@@ -152,7 +190,7 @@ TEST_F(RawSocketTest, MultipleSocketReceive) {
ASSERT_NO_FATAL_FAILURE(
ReceiveICMPFrom(recv_buf2[i], ABSL_ARRAYSIZE(recv_buf2[i]),
sizeof(struct icmphdr), &src, s2.get()));
- EXPECT_EQ(memcmp(&src, &addr_, sizeof(sockaddr_in)), 0);
+ EXPECT_EQ(memcmp(&src, &addr_, sizeof(src)), 0);
}
// Ensure both sockets receive identical packets.
@@ -193,47 +231,34 @@ TEST_F(RawSocketTest, RawAndPingSockets) {
sizeof(addr_)),
SyscallSucceedsWithValue(sizeof(icmp)));
- // Both sockets will receive the echo request and reply in indeterminate
- // order, so we'll need to read 2 packets from each.
-
- // Receive on socket 1.
- constexpr int kBufSize = 256;
+ // Receive on socket 1, which receives the echo request and reply in
+ // indeterminate order.
+ constexpr int kBufSize = sizeof(icmp) + sizeof(struct iphdr);
std::vector<char[kBufSize]> recv_buf1(2);
struct sockaddr_in src;
for (int i = 0; i < 2; i++) {
ASSERT_NO_FATAL_FAILURE(
ReceiveICMP(recv_buf1[i], kBufSize, sizeof(struct icmphdr), &src));
- EXPECT_EQ(memcmp(&src, &addr_, sizeof(sockaddr_in)), 0);
+ EXPECT_EQ(memcmp(&src, &addr_, sizeof(src)), 0);
}
- // Receive on socket 2.
- std::vector<char[kBufSize]> recv_buf2(2);
- for (int i = 0; i < 2; i++) {
- ASSERT_THAT(RetryEINTR(recv)(ping_sock.get(), recv_buf2[i], kBufSize, 0),
- SyscallSucceedsWithValue(sizeof(struct icmphdr)));
- }
-
- // Ensure both sockets receive identical packets.
- int types[] = {ICMP_ECHO, ICMP_ECHOREPLY};
- for (int type : types) {
- auto match_type_ping = [=](char buf[kBufSize]) {
- struct icmphdr* icmp = reinterpret_cast<struct icmphdr*>(buf);
- return icmp->type == type;
- };
- auto match_type_raw = [=](char buf[kBufSize]) {
- struct icmphdr* icmp =
- reinterpret_cast<struct icmphdr*>(buf + sizeof(struct iphdr));
- return icmp->type == type;
- };
-
- char *icmp1 =
- *std::find_if(recv_buf1.begin(), recv_buf1.end(), match_type_raw);
- char *icmp2 =
- *std::find_if(recv_buf2.begin(), recv_buf2.end(), match_type_ping);
- ASSERT_NE(icmp1, *recv_buf1.end());
- ASSERT_NE(icmp2, *recv_buf2.end());
- EXPECT_EQ(memcmp(icmp1 + sizeof(struct iphdr), icmp2, sizeof(icmp)), 0);
- }
+ // Receive on socket 2. Ping sockets only get the echo reply, not the initial
+ // echo.
+ char ping_recv_buf[kBufSize];
+ ASSERT_THAT(RetryEINTR(recv)(ping_sock.get(), ping_recv_buf, kBufSize, 0),
+ SyscallSucceedsWithValue(sizeof(struct icmphdr)));
+
+ // Ensure both sockets receive identical echo reply packets.
+ auto match_type_raw = [=](char buf[kBufSize]) {
+ struct icmphdr* icmp =
+ reinterpret_cast<struct icmphdr*>(buf + sizeof(struct iphdr));
+ return icmp->type == ICMP_ECHOREPLY;
+ };
+ char* raw_reply =
+ *std::find_if(recv_buf1.begin(), recv_buf1.end(), match_type_raw);
+ ASSERT_NE(raw_reply, *recv_buf1.end());
+ EXPECT_EQ(
+ memcmp(raw_reply + sizeof(struct iphdr), ping_recv_buf, sizeof(icmp)), 0);
}
// Test that shutting down an unconnected socket fails.
@@ -244,8 +269,8 @@ TEST_F(RawSocketTest, FailShutdownWithoutConnect) {
ASSERT_THAT(shutdown(s_, SHUT_RD), SyscallFailsWithErrno(ENOTCONN));
}
-// Test that writing to a shutdown write socket fails.
-TEST_F(RawSocketTest, FailWritingToShutdown) {
+// Shutdown is a no-op for raw sockets (and datagram sockets in general).
+TEST_F(RawSocketTest, ShutdownWriteNoop) {
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
ASSERT_THAT(
@@ -253,13 +278,13 @@ TEST_F(RawSocketTest, FailWritingToShutdown) {
SyscallSucceeds());
ASSERT_THAT(shutdown(s_, SHUT_WR), SyscallSucceeds());
- char c;
- ASSERT_THAT(RetryEINTR(write)(s_, &c, sizeof(c)),
- SyscallFailsWithErrno(EPIPE));
+ constexpr char kBuf[] = "noop";
+ ASSERT_THAT(RetryEINTR(write)(s_, kBuf, sizeof(kBuf)),
+ SyscallSucceedsWithValue(sizeof(kBuf)));
}
-// Test that reading from a shutdown read socket gets nothing.
-TEST_F(RawSocketTest, FailReadingFromShutdown) {
+// Shutdown is a no-op for raw sockets (and datagram sockets in general).
+TEST_F(RawSocketTest, ShutdownReadNoop) {
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
ASSERT_THAT(
@@ -267,8 +292,18 @@ TEST_F(RawSocketTest, FailReadingFromShutdown) {
SyscallSucceeds());
ASSERT_THAT(shutdown(s_, SHUT_RD), SyscallSucceeds());
- char c;
- ASSERT_THAT(read(s_, &c, sizeof(c)), SyscallSucceedsWithValue(0));
+ struct icmphdr icmp;
+ icmp.type = ICMP_ECHO;
+ icmp.code = 0;
+ icmp.checksum = 0;
+ icmp.un.echo.sequence = 2012;
+ icmp.un.echo.id = 2014;
+ icmp.checksum = Checksum(&icmp);
+ ASSERT_NO_FATAL_FAILURE(SendEmptyICMP(icmp));
+
+ char c[sizeof(icmp) + sizeof(struct iphdr)];
+ ASSERT_THAT(read(s_, &c, sizeof(c)),
+ SyscallSucceedsWithValue(sizeof(icmp) + sizeof(struct iphdr)));
}
// Test that listen() fails.
@@ -292,7 +327,7 @@ TEST_F(RawSocketTest, FailGetPeerNameBeforeConnect) {
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
struct sockaddr saddr;
- socklen_t addrlen;
+ socklen_t addrlen = sizeof(saddr);
ASSERT_THAT(getpeername(s_, &saddr, &addrlen),
SyscallFailsWithErrno(ENOTCONN));
}
@@ -305,8 +340,9 @@ TEST_F(RawSocketTest, GetPeerName) {
connect(s_, reinterpret_cast<struct sockaddr*>(&addr_), sizeof(addr_)),
SyscallSucceeds());
struct sockaddr saddr;
- socklen_t addrlen;
- ASSERT_THAT(getpeername(s_, &saddr, &addrlen), SyscallSucceeds());
+ socklen_t addrlen = sizeof(saddr);
+ ASSERT_THAT(getpeername(s_, &saddr, &addrlen),
+ SyscallFailsWithErrno(ENOTCONN));
ASSERT_GT(addrlen, 0);
}
@@ -362,15 +398,16 @@ TEST_F(RawSocketTest, SendAndReceiveViaConnect) {
connect(s_, reinterpret_cast<struct sockaddr*>(&addr_), sizeof(addr_)),
SyscallSucceeds());
- // Prepare and send an ICMP packet. Use arbitrary junk for checksum, sequence,
- // and ID. None of that should matter for raw sockets - the kernel should
- // still give us the packet.
+ // Prepare and send an ICMP packet. Use arbitrary junk for sequence and ID.
+ // None of that should matter for raw sockets - the kernel should still give
+ // us the packet.
struct icmphdr icmp;
icmp.type = ICMP_ECHO;
icmp.code = 0;
- icmp.checksum = 2001;
+ icmp.checksum = 0;
icmp.un.echo.sequence = 2003;
icmp.un.echo.id = 2004;
+ icmp.checksum = Checksum(&icmp);
ASSERT_THAT(send(s_, &icmp, sizeof(icmp), 0),
SyscallSucceedsWithValue(sizeof(icmp)));
@@ -381,17 +418,18 @@ TEST_F(RawSocketTest, SendAndReceiveViaConnect) {
TEST_F(RawSocketTest, SendWithoutConnectFails) {
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
- // Prepare and send an ICMP packet. Use arbitrary junk for checksum, sequence,
- // and ID. None of that should matter for raw sockets - the kernel should
- // still give us the packet.
+ // Prepare and send an ICMP packet. Use arbitrary junk for sequence and ID.
+ // None of that should matter for raw sockets - the kernel should still give
+ // us the packet.
struct icmphdr icmp;
icmp.type = ICMP_ECHO;
icmp.code = 0;
- icmp.checksum = 2015;
+ icmp.checksum = 0;
icmp.un.echo.sequence = 2017;
icmp.un.echo.id = 2019;
+ icmp.checksum = Checksum(&icmp);
ASSERT_THAT(send(s_, &icmp, sizeof(icmp), 0),
- SyscallFailsWithErrno(ENOTCONN));
+ SyscallFailsWithErrno(EDESTADDRREQ));
}
// Bind to localhost.
@@ -423,15 +461,16 @@ TEST_F(RawSocketTest, BindSendAndReceive) {
bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), sizeof(addr_)),
SyscallSucceeds());
- // Prepare and send an ICMP packet. Use arbitrary junk for checksum, sequence,
- // and ID. None of that should matter for raw sockets - the kernel should
- // still give us the packet.
+ // Prepare and send an ICMP packet. Use arbitrary junk for sequence and ID.
+ // None of that should matter for raw sockets - the kernel should still give
+ // us the packet.
struct icmphdr icmp;
icmp.type = ICMP_ECHO;
icmp.code = 0;
- icmp.checksum = 2001;
+ icmp.checksum = 0;
icmp.un.echo.sequence = 2004;
icmp.un.echo.id = 2007;
+ icmp.checksum = Checksum(&icmp);
ASSERT_NO_FATAL_FAILURE(SendEmptyICMP(icmp));
ASSERT_NO_FATAL_FAILURE(ExpectICMPSuccess(icmp));
@@ -448,15 +487,16 @@ TEST_F(RawSocketTest, BindConnectSendAndReceive) {
connect(s_, reinterpret_cast<struct sockaddr*>(&addr_), sizeof(addr_)),
SyscallSucceeds());
- // Prepare and send an ICMP packet. Use arbitrary junk for checksum, sequence,
+ // Prepare and send an ICMP packet. Use arbitrary junk for sequence
// and ID. None of that should matter for raw sockets - the kernel should
// still give us the packet.
struct icmphdr icmp;
icmp.type = ICMP_ECHO;
icmp.code = 0;
- icmp.checksum = 2009;
+ icmp.checksum = 0;
icmp.un.echo.sequence = 2010;
icmp.un.echo.id = 7;
+ icmp.checksum = Checksum(&icmp);
ASSERT_NO_FATAL_FAILURE(SendEmptyICMP(icmp));
ASSERT_NO_FATAL_FAILURE(ExpectICMPSuccess(icmp));
@@ -465,7 +505,7 @@ TEST_F(RawSocketTest, BindConnectSendAndReceive) {
void RawSocketTest::ExpectICMPSuccess(const struct icmphdr& icmp) {
// We're going to receive both the echo request and reply, but the order is
// indeterminate.
- char recv_buf[512];
+ char recv_buf[sizeof(icmp) + sizeof(struct iphdr)];
struct sockaddr_in src;
bool received_request = false;
bool received_reply = false;
@@ -474,7 +514,7 @@ void RawSocketTest::ExpectICMPSuccess(const struct icmphdr& icmp) {
// Receive the packet.
ASSERT_NO_FATAL_FAILURE(ReceiveICMP(recv_buf, ABSL_ARRAYSIZE(recv_buf),
sizeof(struct icmphdr), &src));
- EXPECT_EQ(memcmp(&src, &addr_, sizeof(sockaddr_in)), 0);
+ EXPECT_EQ(memcmp(&src, &addr_, sizeof(src)), 0);
struct icmphdr* recvd_icmp =
reinterpret_cast<struct icmphdr*>(recv_buf + sizeof(struct iphdr));
switch (recvd_icmp->type) {
@@ -527,6 +567,28 @@ void RawSocketTest::SendEmptyICMPTo(int sock, struct sockaddr_in* addr,
ASSERT_THAT(sendmsg(sock, &msg, 0), SyscallSucceedsWithValue(sizeof(icmp)));
}
+unsigned short RawSocketTest::Checksum(struct icmphdr* icmp) {
+ unsigned int total = 0;
+ unsigned short* num = reinterpret_cast<unsigned short*>(icmp);
+
+ // This is just the ICMP header, so there's an even number of bytes.
+ for (unsigned int i = 0; i < sizeof(*icmp); i += sizeof(*num)) {
+ total += *num;
+ num++;
+ }
+
+ // Combine the upper and lower 16 bits. This happens twice in case the first
+ // combination causes a carry.
+ unsigned short upper = total >> 16;
+ unsigned short lower = total & 0xffff;
+ total = upper + lower;
+ upper = total >> 16;
+ lower = total & 0xffff;
+ total = upper + lower;
+
+ return ~total;
+}
+
void RawSocketTest::ReceiveICMP(char* recv_buf, size_t recv_buf_len,
size_t expected_size, struct sockaddr_in* src) {
ASSERT_NO_FATAL_FAILURE(
diff --git a/test/syscalls/syscall_test_runner.go b/test/syscalls/syscall_test_runner.go
index 28f312b8b..9a8e0600b 100644
--- a/test/syscalls/syscall_test_runner.go
+++ b/test/syscalls/syscall_test_runner.go
@@ -187,6 +187,7 @@ func runTestCaseRunsc(testBin string, tc gtest.TestCase, t *testing.T) {
"--network=none",
"-log-format=text",
"-TESTONLY-unsafe-nonroot=true",
+ "--net-raw=true",
}
if *debug {
args = append(args, "-debug", "-log-packets=true")