diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2017-06-11 07:33:58 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2017-06-11 07:33:58 +0000 |
commit | 09579d4fa96a183d3bc0386b9e105fe9ec173b69 (patch) | |
tree | 53f2e7d323ec56d73b863def7d8b4040830d0953 | |
parent | fe921ae1091457ad9dfa78b2ec8986e1616295f5 (diff) | |
parent | b5a21f86ba75257864dd14239db561167839cc95 (diff) | |
download | tests-09579d4fa96a183d3bc0386b9e105fe9ec173b69.tar.gz |
release-request-46bf7ca6-57e7-44b8-8edc-ea8830c1cb3b-for-git_oc-mr1-release-4090244 snap-temp-L07700000073092334
Change-Id: I0357512a00668b0a1450ba061c36b10a7bbbca04
-rw-r--r-- | net/test/cstruct.py | 53 | ||||
-rwxr-xr-x | net/test/cstruct_test.py | 27 | ||||
-rwxr-xr-x | net/test/net_test.py | 1 | ||||
-rwxr-xr-x | net/test/sock_diag_test.py | 15 | ||||
-rwxr-xr-x | net/test/xfrm.py | 31 | ||||
-rwxr-xr-x | net/test/xfrm_test.py | 36 |
6 files changed, 152 insertions, 11 deletions
diff --git a/net/test/cstruct.py b/net/test/cstruct.py index 43c47a2..d31979e 100644 --- a/net/test/cstruct.py +++ b/net/test/cstruct.py @@ -25,7 +25,8 @@ Example usage: >>> NLMsgHdr = cstruct.Struct("NLMsgHdr", "=LHHLL", "length type flags seq pid") >>> >>> ->>> # Create instances from tuples or raw bytes. Data past the end is ignored. +>>> # Create instances from a tuple of values, raw bytes, zero-initialized, or +>>> # using keywords. ... n1 = NLMsgHdr((44, 32, 0x2, 0, 491)) >>> print n1 NLMsgHdr(length=44, type=32, flags=2, seq=0, pid=491) @@ -35,6 +36,14 @@ NLMsgHdr(length=44, type=32, flags=2, seq=0, pid=491) >>> print n2 NLMsgHdr(length=44, type=33, flags=2, seq=0, pid=510) >>> +>>> n3 = netlink.NLMsgHdr() # Zero-initialized +>>> print n3 +NLMsgHdr(length=0, type=0, flags=0, seq=0, pid=0) +>>> +>>> n4 = netlink.NLMsgHdr(length=44, type=33) # Other fields zero-initialized +>>> print n4 +NLMsgHdr(length=44, type=33, flags=0, seq=0, pid=0) +>>> >>> # Serialize to raw bytes. ... print n1.Pack().encode("hex") 2c0000002000020000000000eb010000 @@ -123,12 +132,14 @@ def Struct(name, fmt, fieldnames, substructs={}): _asciiz.add(index) _format += "s" else: - # Standard struct format character. + # Standard struct format character. _format += fmt[i] _length = CalcSize(_format) def _SetValues(self, values): + # Replace self._values with the given list. We can't do direct assignment + # because of the __setattr__ overload on this class. super(CStruct, self).__setattr__("_values", list(values)) def _Parse(self, data): @@ -139,19 +150,37 @@ def Struct(name, fmt, fieldnames, substructs={}): values[index] = self._nested[index](value) self._SetValues(values) - def __init__(self, values): - # Initializing from a string. - if isinstance(values, str): - if len(values) < self._length: + def __init__(self, tuple_or_bytes=None, **kwargs): + """Construct an instance of this Struct. + + 1. With no args, the whole struct is zero-initialized. + 2. With keyword args, the matching fields are populated; rest are zeroed. + 3. With one tuple as the arg, the fields are assigned based on position. + 4. With one string arg, the Struct is parsed from bytes. + """ + if tuple_or_bytes and kwargs: + raise TypeError( + "%s: cannot specify both a tuple and keyword args" % self._name) + + if tuple_or_bytes is None: + # Default construct from null bytes. + self._Parse("\x00" * len(self)) + # If any keywords were supplied, set those fields. + for k, v in kwargs.iteritems(): + setattr(self, k, v) + elif isinstance(tuple_or_bytes, str): + # Initializing from a string. + if len(tuple_or_bytes) < self._length: raise TypeError("%s requires string of length %d, got %d" % - (self._name, self._length, len(values))) - self._Parse(values) + (self._name, self._length, len(tuple_or_bytes))) + self._Parse(tuple_or_bytes) else: # Initializing from a tuple. - if len(values) != len(self._fieldnames): + if len(tuple_or_bytes) != len(self._fieldnames): raise TypeError("%s has exactly %d fieldnames (%d given)" % - (self._name, len(self._fieldnames), len(values))) - self._SetValues(values) + (self._name, len(self._fieldnames), + len(tuple_or_bytes))) + self._SetValues(tuple_or_bytes) def _FieldIndex(self, attr): try: @@ -164,6 +193,8 @@ def Struct(name, fmt, fieldnames, substructs={}): return self._values[self._FieldIndex(name)] def __setattr__(self, name, value): + # TODO: check value type against self._format and throw here, or else + # callers get an unhelpful exception when they call Pack(). self._values[self._FieldIndex(name)] = value @classmethod diff --git a/net/test/cstruct_test.py b/net/test/cstruct_test.py index fdcbd55..b69aeb7 100755 --- a/net/test/cstruct_test.py +++ b/net/test/cstruct_test.py @@ -110,6 +110,33 @@ class CstructTest(unittest.TestCase): " int3=12345, ascii4=hello\x00visible123, word5=33210)") self.assertEquals(expected, str(t)) + def testZeroInitialization(self): + TestStruct = cstruct.Struct("TestStruct", "B16si16AH", + "byte1 string2 int3 ascii4 word5") + t = TestStruct() + self.assertEquals(0, t.byte1) + self.assertEquals("\x00" * 16, t.string2) + self.assertEquals(0, t.int3) + self.assertEquals("\x00" * 16, t.ascii4) + self.assertEquals(0, t.word5) + self.assertEquals("\x00" * len(TestStruct), t.Pack()) + + def testKeywordInitialization(self): + TestStruct = cstruct.Struct("TestStruct", "=B16sIH", + "byte1 string2 int3 word4") + text = "hello world! ^_^" + text_bytes = text.encode("hex") + + # Populate all fields + t1 = TestStruct(byte1=1, string2=text, int3=0xFEDCBA98, word4=0x1234) + expected = ("01" + text_bytes + "98BADCFE" "3412").decode("hex") + self.assertEquals(expected, t1.Pack()) + + # Partially populated + t1 = TestStruct(string2=text, word4=0x1234) + expected = ("00" + text_bytes + "00000000" "3412").decode("hex") + self.assertEquals(expected, t1.Pack()) + if __name__ == "__main__": unittest.main() diff --git a/net/test/net_test.py b/net/test/net_test.py index 423228b..290a24a 100755 --- a/net/test/net_test.py +++ b/net/test/net_test.py @@ -40,6 +40,7 @@ SO_BINDTODEVICE = 25 SO_MARK = 36 SO_PROTOCOL = 38 SO_DOMAIN = 39 +SO_COOKIE = 57 ETH_P_IP = 0x0800 ETH_P_IPV6 = 0x86dd diff --git a/net/test/sock_diag_test.py b/net/test/sock_diag_test.py index 72b9a11..be7d09d 100755 --- a/net/test/sock_diag_test.py +++ b/net/test/sock_diag_test.py @@ -19,6 +19,7 @@ from errno import * # pylint: disable=wildcard-import import os import random from socket import * # pylint: disable=wildcard-import +import struct import threading import time import unittest @@ -32,6 +33,7 @@ import tcp_test NUM_SOCKETS = 30 NO_BYTECODE = "" +HAVE_KERNEL_SUPPORT = net_test.LINUX_VERSION >= (4, 9, 0) class SockDiagBaseTest(multinetwork_base.MultiNetworkBaseTest): @@ -303,6 +305,19 @@ class SockDiagTest(SockDiagBaseTest): DiagDump(op) # No errors? Good. self.assertRaisesErrno(EINVAL, DiagDump, op + 17) + def CheckSocketCookie(self, inet, addr): + """Tests that getsockopt SO_COOKIE can get cookie for all sockets.""" + socketpair = net_test.CreateSocketPair(inet, SOCK_STREAM, addr) + for sock in socketpair: + diag_msg = self.sock_diag.FindSockDiagFromFd(sock) + cookie = sock.getsockopt(net_test.SOL_SOCKET, net_test.SO_COOKIE, 8) + self.assertEqual(diag_msg.id.cookie, cookie) + + @unittest.skipUnless(HAVE_KERNEL_SUPPORT, "SO_COOKIE not supported") + def testGetsockoptcookie(self): + self.CheckSocketCookie(AF_INET, "127.0.0.1") + self.CheckSocketCookie(AF_INET6, "::1") + class SockDestroyTest(SockDiagBaseTest): """Tests that SOCK_DESTROY works correctly. diff --git a/net/test/xfrm.py b/net/test/xfrm.py index 84b488f..96bfd25 100755 --- a/net/test/xfrm.py +++ b/net/test/xfrm.py @@ -18,6 +18,7 @@ # pylint: disable=g-bad-todo +import os from socket import * # pylint: disable=wildcard-import import cstruct @@ -152,6 +153,9 @@ XfrmUsersaInfo = cstruct.Struct( "sel id saddr lft curlft stats seq reqid family mode replay_window flags", [XfrmSelector, XfrmId, XfrmLifetimeCfg, XfrmLifetimeCur, XfrmStats]) +XfrmUserSpiInfo = cstruct.Struct( + "XfrmUserSpiInfo", "=SII", "info min max", [XfrmUsersaInfo]) + XfrmUsersaId = cstruct.Struct( "XfrmUsersaInfo", "=16sIHBx", "daddr spi family proto") @@ -218,6 +222,8 @@ class Xfrm(netlink.NetlinkSocket): struct_type = XfrmUsersaId elif command == XFRM_MSG_DELSA: struct_type = XfrmUsersaId + elif command == XFRM_MSG_ALLOCSPI: + struct_type = XfrmUserSpiInfo else: struct_type = None @@ -276,6 +282,31 @@ class Xfrm(netlink.NetlinkSocket): flags = netlink.NLM_F_REQUEST | netlink.NLM_F_ACK self._SendNlRequest(XFRM_MSG_DELSA, usersa_id.Pack(), flags) + def AllocSpi(self, dst, proto, min_spi, max_spi): + """Allocate (reserve) an SPI. + + This sends an XFRM_MSG_ALLOCSPI message and returns the resulting + XfrmUsersaInfo struct. + """ + spi = XfrmUserSpiInfo("\x00" * len(XfrmUserSpiInfo)) + spi.min = min_spi + spi.max = max_spi + spi.info.id.daddr = PaddedAddress(dst) + spi.info.id.proto = proto + + msg = spi.Pack() + flags = netlink.NLM_F_REQUEST + self._SendNlRequest(XFRM_MSG_ALLOCSPI, msg, flags) + # Read the response message. + data = self._Recv() + nl_hdr, data = cstruct.Read(data, netlink.NLMsgHdr) + if nl_hdr.type == XFRM_MSG_NEWSA: + return XfrmUsersaInfo(data) + if nl_hdr.type == netlink.NLMSG_ERROR: + error = netlink.NLMsgErr(data).error + raise IOError(error, os.strerror(-error)) + raise ValueError("Unexpected netlink message type: %d" % nl_hdr.type) + def DumpSaInfo(self): return self._Dump(XFRM_MSG_GETSA, None, XfrmUsersaInfo, "") diff --git a/net/test/xfrm_test.py b/net/test/xfrm_test.py index 518d84f..530a88c 100755 --- a/net/test/xfrm_test.py +++ b/net/test/xfrm_test.py @@ -329,6 +329,42 @@ class XfrmTest(multinetwork_base.MultiNetworkBaseTest): scapy.UDP(sport=srcport, dport=53) / "foo") self.assertRaisesErrno(EAGAIN, twisted_socket.recv, 4096) + def testAllocSpecificSpi(self): + spi = 0xABCD + new_sa = self.xfrm.AllocSpi("::", IPPROTO_ESP, spi, spi) + self.assertEquals(spi, ntohl(new_sa.id.spi)) + + def testAllocSpecificSpiUnavailable(self): + """Attempt to allocate the same SPI twice.""" + spi = 0xABCD + new_sa = self.xfrm.AllocSpi("::", IPPROTO_ESP, spi, spi) + self.assertEquals(spi, ntohl(new_sa.id.spi)) + with self.assertRaisesErrno(ENOENT): + new_sa = self.xfrm.AllocSpi("::", IPPROTO_ESP, spi, spi) + + def testAllocRangeSpi(self): + start, end = 0xABCD0, 0xABCDF + new_sa = self.xfrm.AllocSpi("::", IPPROTO_ESP, start, end) + spi = ntohl(new_sa.id.spi) + self.assertGreaterEqual(spi, start) + self.assertLessEqual(spi, end) + + def testAllocRangeSpiUnavailable(self): + """Attempt to allocate N+1 SPIs from a range of size N.""" + start, end = 0xABCD0, 0xABCDF + range_size = end - start + 1 + spis = set() + # Assert that allocating SPI fails when none are available. + with self.assertRaisesErrno(ENOENT): + # Allocating range_size + 1 SPIs is guaranteed to fail. Due to the way + # kernel picks random SPIs, this has a high probability of failing before + # reaching that limit. + for i in xrange(range_size + 1): + new_sa = self.xfrm.AllocSpi("::", IPPROTO_ESP, start, end) + spi = ntohl(new_sa.id.spi) + self.assertNotIn(spi, spis) + spis.add(spi) + if __name__ == "__main__": unittest.main() |