OSDN Git Service

Make CloseSocketFromFd work on mapped sockets too.
authorLorenzo Colitti <lorenzo@google.com>
Fri, 15 Jan 2016 17:21:58 +0000 (02:21 +0900)
committerLorenzo Colitti <lorenzo@google.com>
Mon, 18 Jan 2016 20:55:16 +0000 (05:55 +0900)
Change-Id: I8ca9f205fcca49391f2e20339c8a6ddc66f75c3c

tests/net_test/sock_diag.py

index 5cb83cf..58a1781 100755 (executable)
@@ -338,7 +338,27 @@ class SockDiag(netlink.NetlinkSocket):
   @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))
+    # For a dual-stack socket connected to a mapped address, the diag_msg
+    # returned by the kernel has family AF_INET6 and mapped addresses. But if
+    # we ask the kernel to find a socket based on that data, we'll get ENOENT.
+    # This is because inet_diag_find_one_icsk sees diag_req.family == AF_INET6
+    # and looks in the IPv6 TCP hash table, but mapped sockets are in the IPv4
+    # hash tables. So fix up the diag_req to specify AF_INET.
+    #
+    # TODO: Should the kernel do this for us in inet_diag_find_one_icsk?
+    mapped_prefix = inet_pton(AF_INET6, "::ffff:0.0.0.0")[:12]
+    if (d.family == AF_INET6 and
+        (d.id.src.startswith(mapped_prefix) or
+         d.id.dst.startswith(mapped_prefix))):
+      family = AF_INET
+      sock_id = InetDiagSockId((d.id.sport, d.id.dport,
+                                d.id.src[12:16] + "\x00" * 12,
+                                d.id.dst[12:16] + "\x00" * 12,
+                                d.id.iface, d.id.cookie))
+    else:
+      family = d.family
+      sock_id = d.id
+    return InetDiagReqV2((family, protocol, 0, 1 << d.state, sock_id))
 
   def CloseSocket(self, req):
     self._SendNlRequest(SOCK_DESTROY, req.Pack(),