summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2017-06-11 07:33:58 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2017-06-11 07:33:58 +0000
commit09579d4fa96a183d3bc0386b9e105fe9ec173b69 (patch)
tree53f2e7d323ec56d73b863def7d8b4040830d0953
parentfe921ae1091457ad9dfa78b2ec8986e1616295f5 (diff)
parentb5a21f86ba75257864dd14239db561167839cc95 (diff)
downloadtests-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.py53
-rwxr-xr-xnet/test/cstruct_test.py27
-rwxr-xr-xnet/test/net_test.py1
-rwxr-xr-xnet/test/sock_diag_test.py15
-rwxr-xr-xnet/test/xfrm.py31
-rwxr-xr-xnet/test/xfrm_test.py36
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()