summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2016-01-06 07:21:31 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2016-01-06 07:21:31 +0000
commite732b22a44ce9ee3745b368471b7a41399735c27 (patch)
tree5af65943d543adeff24b477ece599ba56183451a
parent590a20ffdc2a6c57e4b0a5a855926ce9d2042c4d (diff)
parent579791dba57c312b32b3b08412a77f4fbd465b8a (diff)
downloadextras-e732b22a44ce9ee3745b368471b7a41399735c27.tar.gz
Merge changes I62ea60f8,If6613ec1
* changes: Improvements to sock_diag code. Enable various lock debugging options.
-rwxr-xr-xtests/net_test/run_net_test.sh3
-rwxr-xr-xtests/net_test/sock_diag.py39
-rwxr-xr-xtests/net_test/sock_diag_test.py50
3 files changed, 68 insertions, 24 deletions
diff --git a/tests/net_test/run_net_test.sh b/tests/net_test/run_net_test.sh
index 85dc1222..d745ec31 100755
--- a/tests/net_test/run_net_test.sh
+++ b/tests/net_test/run_net_test.sh
@@ -1,7 +1,8 @@
#!/bin/bash
# Kernel configuration options.
-OPTIONS=" IPV6 IPV6_ROUTER_PREF IPV6_MULTIPLE_TABLES IPV6_ROUTE_INFO"
+OPTIONS=" DEBUG_SPINLOCK DEBUG_ATOMIC_SLEEP DEBUG_MUTEXES DEBUG_RT_MUTEXES"
+OPTIONS="$OPTIONS IPV6 IPV6_ROUTER_PREF IPV6_MULTIPLE_TABLES IPV6_ROUTE_INFO"
OPTIONS="$OPTIONS TUN SYN_COOKIES IP_ADVANCED_ROUTER IP_MULTIPLE_TABLES"
OPTIONS="$OPTIONS NETFILTER NETFILTER_ADVANCED NETFILTER_XTABLES"
OPTIONS="$OPTIONS NETFILTER_XT_MARK NETFILTER_XT_TARGET_MARK"
diff --git a/tests/net_test/sock_diag.py b/tests/net_test/sock_diag.py
index 8c70eb33..80899472 100755
--- a/tests/net_test/sock_diag.py
+++ b/tests/net_test/sock_diag.py
@@ -131,13 +131,17 @@ class SockDiag(netlink.NetlinkSocket):
def _EmptyInetDiagSockId():
return InetDiagSockId(("\x00" * len(InetDiagSockId)))
+ def Dump(self, diag_req):
+ out = self._Dump(SOCK_DIAG_BY_FAMILY, diag_req, InetDiagMsg)
+ return out
+
def DumpSockets(self, family, protocol, ext, states, sock_id):
"""Dumps sockets matching the specified parameters."""
if sock_id is None:
sock_id = self._EmptyInetDiagSockId()
diag_req = InetDiagReqV2((family, protocol, ext, states, sock_id))
- return self._Dump(SOCK_DIAG_BY_FAMILY, diag_req, InetDiagMsg)
+ return self.Dump(diag_req)
def DumpAllInetSockets(self, protocol, sock_id=None, ext=0, states=0xffffffff):
# DumpSockets(AF_UNSPEC) does not result in dumping all inet sockets, it
@@ -177,6 +181,15 @@ class SockDiag(netlink.NetlinkSocket):
padded += "\x00" * (16 - len(padded))
return padded
+ # For IPv4 addresses, the kernel seems only to fill in the first 4 bytes of
+ # src and dst, leaving the others unspecified. This seems like a bug because
+ # it might leak kernel memory contents, but regardless, work around it.
+ @staticmethod
+ def FixupDiagMsg(d):
+ if d.family == AF_INET:
+ d.id.src = d.id.src[:4] + "\x00" * 12
+ d.id.dst = d.id.dst[:4] + "\x00" * 12
+
@staticmethod
def DiagReqFromSocket(s):
"""Creates an InetDiagReqV2 that matches the specified socket."""
@@ -197,19 +210,25 @@ class SockDiag(netlink.NetlinkSocket):
sock_id = InetDiagSockId((sport, dport, src, dst, iface, "\x00" * 8))
return InetDiagReqV2((family, protocol, 0, 0xffffffff, sock_id))
- def GetSockDiagForFd(self, s):
- """Gets an InetDiagMsg from the kernel for the specified socket."""
- req = self.DiagReqFromSocket(s)
- for diag_msg, attrs in self._Dump(SOCK_DIAG_BY_FAMILY, req, InetDiagMsg):
+ def FindSockDiagFromReq(self, req):
+ for diag_msg, attrs in self.Dump(req):
return diag_msg
raise ValueError("Dump of %s returned no sockets" % req)
- def GetSockDiag(self, family, protocol, sock_id, ext=0, states=0xffffffff):
- """Gets an InetDiagMsg from the kernel for the specified parameters."""
- req = InetDiagReqV2((family, protocol, ext, states, sock_id))
+ def FindSockDiagFromFd(self, s):
+ """Gets an InetDiagMsg from the kernel for the specified socket."""
+ req = self.DiagReqFromSocket(s)
+ return self.FindSockDiagFromReq(req)
+
+ def GetSockDiag(self, req):
+ """Gets an InetDiagMsg from the kernel for the specified request."""
self._SendNlRequest(SOCK_DIAG_BY_FAMILY, req.Pack(), netlink.NLM_F_REQUEST)
- data = self._Recv()
- return self._ParseNLMsg(data, InetDiagMsg)[0]
+ return self._GetMsg(InetDiagMsg)
+
+ @staticmethod
+ def DiagReqFromDiagMsg(d, protocol):
+ """Constructs a diag_req from a diag_msg the kernel has given us."""
+ return InetDiagReqV2((d.family, protocol, 0, 1 << d.state, d.id))
if __name__ == "__main__":
diff --git a/tests/net_test/sock_diag_test.py b/tests/net_test/sock_diag_test.py
index 2803bd20..c9ee0c87 100755
--- a/tests/net_test/sock_diag_test.py
+++ b/tests/net_test/sock_diag_test.py
@@ -54,28 +54,43 @@ class SockDiagTest(multinetwork_base.MultiNetworkBaseTest):
def tearDown(self):
[s.close() for socketpair in self.socketpairs.values() for s in socketpair]
+ def testFixupDiagMsg(self):
+ src = "0a00fa02303030312030312038302031"
+ dst = "0808080841414141414141416f0a3230"
+ cookie = "4078678100000000"
+ sockid = sock_diag.InetDiagSockId((47436, 32069,
+ src.decode("hex"), dst.decode("hex"), 0,
+ cookie.decode("hex")))
+ msg4 = sock_diag.InetDiagMsg((AF_INET, IPPROTO_TCP, 0,
+ sock_diag.TCP_SYN_RECV, sockid,
+ 980, 123, 456, 789, 5555))
+ # Make a copy, cstructs are mutable.
+ msg6 = sock_diag.InetDiagMsg(msg4.Pack())
+ msg6.family = AF_INET6
+
+ fixed6 = sock_diag.InetDiagMsg(msg6.Pack())
+ self.sock_diag.FixupDiagMsg(fixed6)
+ self.assertEquals(msg6.Pack(), fixed6.Pack())
+
+ fixed4 = sock_diag.InetDiagMsg(msg4.Pack())
+ self.sock_diag.FixupDiagMsg(fixed4)
+ msg4.id.src = src.decode("hex")[:4] + 12 * "\x00"
+ msg4.id.dst = dst.decode("hex")[:4] + 12 * "\x00"
+ self.assertEquals(msg4.Pack(), fixed4.Pack())
+
def assertSockDiagMatchesSocket(self, s, diag_msg):
family = s.getsockopt(net_test.SOL_SOCKET, net_test.SO_DOMAIN)
self.assertEqual(diag_msg.family, family)
- # TODO: The kernel (at least 3.10) seems only to fill in the first 4 bytes
- # of src and dst in the case of IPv4 addresses. This means we can't just do
- # something like:
- # self.assertEqual(diag_msg.id.src, self.sock_diag.PaddedAddress(src))
- # because the trailing bytes might not match.
- # This seems like a bug because it might leaks kernel memory contents, but
- # regardless, work around that here.
- addrlen = {AF_INET: 4, AF_INET6: 16}[family]
+ self.sock_diag.FixupDiagMsg(diag_msg)
src, sport = s.getsockname()[0:2]
+ self.assertEqual(diag_msg.id.src, self.sock_diag.PaddedAddress(src))
self.assertEqual(diag_msg.id.sport, sport)
- self.assertEqual(diag_msg.id.src[:addrlen],
- self.sock_diag.RawAddress(src))
if self.sock_diag.GetDestinationAddress(diag_msg) not in ["0.0.0.0", "::"]:
dst, dport = s.getpeername()[0:2]
- self.assertEqual(diag_msg.id.dst[:addrlen],
- self.sock_diag.RawAddress(dst))
+ self.assertEqual(diag_msg.id.dst, self.sock_diag.PaddedAddress(dst))
self.assertEqual(diag_msg.id.dport, dport)
else:
assertRaisesErrno(errno.ENOTCONN, s.getpeername)
@@ -103,9 +118,18 @@ class SockDiagTest(multinetwork_base.MultiNetworkBaseTest):
random.shuffle(socketpairs)
for socketpair in socketpairs:
for sock in socketpair:
+ # Check that we can find a diag_msg by scanning a dump.
self.assertSockDiagMatchesSocket(
sock,
- self.sock_diag.GetSockDiagForFd(sock))
+ self.sock_diag.FindSockDiagFromFd(sock))
+ cookie = self.sock_diag.FindSockDiagFromFd(sock).id.cookie
+
+ # Check that we can find a diag_msg once we know the cookie.
+ req = self.sock_diag.DiagReqFromSocket(sock)
+ req.id.cookie = cookie
+ req.states = 1 << diag_msg.state
+ diag_msg, attrs = self.sock_diag.GetSockDiag(req)
+ self.assertSockDiagMatchesSocket(sock, diag_msg)
if __name__ == "__main__":