diff options
author | Kevin Krakauer <krakauer@google.com> | 2019-05-05 16:06:11 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2019-05-05 16:07:25 -0700 |
commit | ff8ed5e6a5a391c5465230121af09afa5d1906e9 (patch) | |
tree | 7ce5c0fc2db7745ac102e23c7fa2b657f556949e | |
parent | ebe2f78d9bc8639f0967c08777a3c9431ac44700 (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.go | 17 | ||||
-rw-r--r-- | pkg/tcpip/transport/icmp/endpoint.go | 16 | ||||
-rw-r--r-- | pkg/tcpip/transport/raw/endpoint.go | 45 | ||||
-rw-r--r-- | test/syscalls/linux/raw_socket_ipv4.cc | 208 | ||||
-rw-r--r-- | test/syscalls/syscall_test_runner.go | 1 |
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") |