diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2016-01-06 07:21:31 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2016-01-06 07:21:31 +0000 |
commit | e732b22a44ce9ee3745b368471b7a41399735c27 (patch) | |
tree | 5af65943d543adeff24b477ece599ba56183451a | |
parent | 590a20ffdc2a6c57e4b0a5a855926ce9d2042c4d (diff) | |
parent | 579791dba57c312b32b3b08412a77f4fbd465b8a (diff) | |
download | extras-e732b22a44ce9ee3745b368471b7a41399735c27.tar.gz |
Merge changes I62ea60f8,If6613ec1
* changes:
Improvements to sock_diag code.
Enable various lock debugging options.
-rwxr-xr-x | tests/net_test/run_net_test.sh | 3 | ||||
-rwxr-xr-x | tests/net_test/sock_diag.py | 39 | ||||
-rwxr-xr-x | tests/net_test/sock_diag_test.py | 50 |
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__": |