Home | History | Annotate | Download | only in test
      1 #!/usr/bin/python
      2 #
      3 # Copyright 2014 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 # http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 
     17 import errno
     18 import os
     19 import random
     20 from socket import *  # pylint: disable=wildcard-import
     21 import struct
     22 import time           # pylint: disable=unused-import
     23 import unittest
     24 
     25 from scapy import all as scapy
     26 
     27 import csocket
     28 import iproute
     29 import multinetwork_base
     30 import net_test
     31 import packets
     32 
     33 # For brevity.
     34 UDP_PAYLOAD = net_test.UDP_PAYLOAD
     35 
     36 IPV6_FLOWINFO = 11
     37 
     38 IPV4_MARK_REFLECT_SYSCTL = "/proc/sys/net/ipv4/fwmark_reflect"
     39 IPV6_MARK_REFLECT_SYSCTL = "/proc/sys/net/ipv6/fwmark_reflect"
     40 SYNCOOKIES_SYSCTL = "/proc/sys/net/ipv4/tcp_syncookies"
     41 TCP_MARK_ACCEPT_SYSCTL = "/proc/sys/net/ipv4/tcp_fwmark_accept"
     42 
     43 # The IP[V6]UNICAST_IF socket option was added between 3.1 and 3.4.
     44 HAVE_UNICAST_IF = net_test.LINUX_VERSION >= (3, 4, 0)
     45 
     46 
     47 class ConfigurationError(AssertionError):
     48   pass
     49 
     50 
     51 class InboundMarkingTest(multinetwork_base.MultiNetworkBaseTest):
     52 
     53   @classmethod
     54   def _SetInboundMarking(cls, netid, is_add):
     55     for version in [4, 6]:
     56       # Run iptables to set up incoming packet marking.
     57       iface = cls.GetInterfaceName(netid)
     58       add_del = "-A" if is_add else "-D"
     59       iptables = {4: "iptables", 6: "ip6tables"}[version]
     60       args = "%s INPUT -t mangle -i %s -j MARK --set-mark %d" % (
     61           add_del, iface, netid)
     62       if net_test.RunIptablesCommand(version, args):
     63         raise ConfigurationError("Setup command failed: %s" % args)
     64 
     65   @classmethod
     66   def setUpClass(cls):
     67     super(InboundMarkingTest, cls).setUpClass()
     68     for netid in cls.tuns:
     69       cls._SetInboundMarking(netid, True)
     70 
     71   @classmethod
     72   def tearDownClass(cls):
     73     for netid in cls.tuns:
     74       cls._SetInboundMarking(netid, False)
     75     super(InboundMarkingTest, cls).tearDownClass()
     76 
     77   @classmethod
     78   def SetMarkReflectSysctls(cls, value):
     79     cls.SetSysctl(IPV4_MARK_REFLECT_SYSCTL, value)
     80     try:
     81       cls.SetSysctl(IPV6_MARK_REFLECT_SYSCTL, value)
     82     except IOError:
     83       # This does not exist if we use the version of the patch that uses a
     84       # common sysctl for IPv4 and IPv6.
     85       pass
     86 
     87 
     88 class OutgoingTest(multinetwork_base.MultiNetworkBaseTest):
     89 
     90   # How many times to run outgoing packet tests.
     91   ITERATIONS = 5
     92 
     93   def CheckPingPacket(self, version, netid, routing_mode, dstaddr, packet):
     94     s = self.BuildSocket(version, net_test.PingSocket, netid, routing_mode)
     95 
     96     myaddr = self.MyAddress(version, netid)
     97     s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
     98     s.bind((myaddr, packets.PING_IDENT))
     99     net_test.SetSocketTos(s, packets.PING_TOS)
    100 
    101     desc, expected = packets.ICMPEcho(version, myaddr, dstaddr)
    102     msg = "IPv%d ping: expected %s on %s" % (
    103         version, desc, self.GetInterfaceName(netid))
    104 
    105     s.sendto(packet + packets.PING_PAYLOAD, (dstaddr, 19321))
    106 
    107     self.ExpectPacketOn(netid, msg, expected)
    108 
    109   def CheckTCPSYNPacket(self, version, netid, routing_mode, dstaddr):
    110     s = self.BuildSocket(version, net_test.TCPSocket, netid, routing_mode)
    111 
    112     if version == 6 and dstaddr.startswith("::ffff"):
    113       version = 4
    114     myaddr = self.MyAddress(version, netid)
    115     desc, expected = packets.SYN(53, version, myaddr, dstaddr,
    116                                  sport=None, seq=None)
    117 
    118     # Non-blocking TCP connects always return EINPROGRESS.
    119     self.assertRaisesErrno(errno.EINPROGRESS, s.connect, (dstaddr, 53))
    120     msg = "IPv%s TCP connect: expected %s on %s" % (
    121         version, desc, self.GetInterfaceName(netid))
    122     self.ExpectPacketOn(netid, msg, expected)
    123     s.close()
    124 
    125   def CheckUDPPacket(self, version, netid, routing_mode, dstaddr):
    126     s = self.BuildSocket(version, net_test.UDPSocket, netid, routing_mode)
    127 
    128     if version == 6 and dstaddr.startswith("::ffff"):
    129       version = 4
    130     myaddr = self.MyAddress(version, netid)
    131     desc, expected = packets.UDP(version, myaddr, dstaddr, sport=None)
    132     msg = "IPv%s UDP %%s: expected %s on %s" % (
    133         version, desc, self.GetInterfaceName(netid))
    134 
    135     s.sendto(UDP_PAYLOAD, (dstaddr, 53))
    136     self.ExpectPacketOn(netid, msg % "sendto", expected)
    137 
    138     # IP_UNICAST_IF doesn't seem to work on connected sockets, so no TCP.
    139     if routing_mode != "ucast_oif":
    140       s.connect((dstaddr, 53))
    141       s.send(UDP_PAYLOAD)
    142       self.ExpectPacketOn(netid, msg % "connect/send", expected)
    143       s.close()
    144 
    145   def CheckRawGrePacket(self, version, netid, routing_mode, dstaddr):
    146     s = self.BuildSocket(version, net_test.RawGRESocket, netid, routing_mode)
    147 
    148     inner_version = {4: 6, 6: 4}[version]
    149     inner_src = self.MyAddress(inner_version, netid)
    150     inner_dst = self.GetRemoteAddress(inner_version)
    151     inner = str(packets.UDP(inner_version, inner_src, inner_dst, sport=None)[1])
    152 
    153     ethertype = {4: net_test.ETH_P_IP, 6: net_test.ETH_P_IPV6}[inner_version]
    154     # A GRE header can be as simple as two zero bytes and the ethertype.
    155     packet = struct.pack("!i", ethertype) + inner
    156     myaddr = self.MyAddress(version, netid)
    157 
    158     s.sendto(packet, (dstaddr, IPPROTO_GRE))
    159     desc, expected = packets.GRE(version, myaddr, dstaddr, ethertype, inner)
    160     msg = "Raw IPv%d GRE with inner IPv%d UDP: expected %s on %s" % (
    161         version, inner_version, desc, self.GetInterfaceName(netid))
    162     self.ExpectPacketOn(netid, msg, expected)
    163 
    164   def CheckOutgoingPackets(self, routing_mode):
    165     v4addr = self.IPV4_ADDR
    166     v6addr = self.IPV6_ADDR
    167     v4mapped = "::ffff:" + v4addr
    168 
    169     for _ in xrange(self.ITERATIONS):
    170       for netid in self.tuns:
    171 
    172         self.CheckPingPacket(4, netid, routing_mode, v4addr, self.IPV4_PING)
    173         # Kernel bug.
    174         if routing_mode != "oif":
    175           self.CheckPingPacket(6, netid, routing_mode, v6addr, self.IPV6_PING)
    176 
    177         # IP_UNICAST_IF doesn't seem to work on connected sockets, so no TCP.
    178         if routing_mode != "ucast_oif":
    179           self.CheckTCPSYNPacket(4, netid, routing_mode, v4addr)
    180           self.CheckTCPSYNPacket(6, netid, routing_mode, v6addr)
    181           self.CheckTCPSYNPacket(6, netid, routing_mode, v4mapped)
    182 
    183         self.CheckUDPPacket(4, netid, routing_mode, v4addr)
    184         self.CheckUDPPacket(6, netid, routing_mode, v6addr)
    185         self.CheckUDPPacket(6, netid, routing_mode, v4mapped)
    186 
    187         # Creating raw sockets on non-root UIDs requires properly setting
    188         # capabilities, which is hard to do from Python.
    189         # IP_UNICAST_IF is not supported on raw sockets.
    190         if routing_mode not in ["uid", "ucast_oif"]:
    191           self.CheckRawGrePacket(4, netid, routing_mode, v4addr)
    192           self.CheckRawGrePacket(6, netid, routing_mode, v6addr)
    193 
    194   def testMarkRouting(self):
    195     """Checks that socket marking selects the right outgoing interface."""
    196     self.CheckOutgoingPackets("mark")
    197 
    198   def testUidRouting(self):
    199     """Checks that UID routing selects the right outgoing interface."""
    200     self.CheckOutgoingPackets("uid")
    201 
    202   def testOifRouting(self):
    203     """Checks that oif routing selects the right outgoing interface."""
    204     self.CheckOutgoingPackets("oif")
    205 
    206   @unittest.skipUnless(HAVE_UNICAST_IF, "no support for UNICAST_IF")
    207   def testUcastOifRouting(self):
    208     """Checks that ucast oif routing selects the right outgoing interface."""
    209     self.CheckOutgoingPackets("ucast_oif")
    210 
    211   def CheckRemarking(self, version, use_connect):
    212     modes = ["mark", "oif", "uid"]
    213     # Setting UNICAST_IF on connected sockets does not work.
    214     if not use_connect and HAVE_UNICAST_IF:
    215       modes += ["ucast_oif"]
    216 
    217     for mode in modes:
    218       s = net_test.UDPSocket(self.GetProtocolFamily(version))
    219 
    220       # Figure out what packets to expect.
    221       sport = net_test.BindRandomPort(version, s)
    222       dstaddr = {4: self.IPV4_ADDR, 6: self.IPV6_ADDR}[version]
    223       unspec = {4: "0.0.0.0", 6: "::"}[version]  # Placeholder.
    224       desc, expected = packets.UDP(version, unspec, dstaddr, sport)
    225 
    226       # If we're testing connected sockets, connect the socket on the first
    227       # netid now.
    228       if use_connect:
    229         netid = self.tuns.keys()[0]
    230         self.SelectInterface(s, netid, mode)
    231         s.connect((dstaddr, 53))
    232         expected.src = self.MyAddress(version, netid)
    233 
    234       # For each netid, select that network without closing the socket, and
    235       # check that the packets sent on that socket go out on the right network.
    236       #
    237       # For connected sockets, routing is cached in the socket's destination
    238       # cache entry. In this case, we check that just re-selecting the netid
    239       # (except via SO_BINDTODEVICE) does not change routing, but that
    240       # subsequently invalidating the destination cache entry does. Arguably
    241       # this is a bug in the kernel because re-selecting the netid should cause
    242       # routing to change. But it is a convenient way to check that
    243       # InvalidateDstCache actually works.
    244       prevnetid = None
    245       for netid in self.tuns:
    246         self.SelectInterface(s, netid, mode)
    247         if not use_connect:
    248           expected.src = self.MyAddress(version, netid)
    249 
    250         def ExpectSendUsesNetid(netid):
    251           connected_str = "Connected" if use_connect else "Unconnected"
    252           msg = "%s UDPv%d socket remarked using %s: expecting %s on %s" % (
    253               connected_str, version, mode, desc, self.GetInterfaceName(netid))
    254           if use_connect:
    255             s.send(UDP_PAYLOAD)
    256           else:
    257             s.sendto(UDP_PAYLOAD, (dstaddr, 53))
    258           self.ExpectPacketOn(netid, msg, expected)
    259 
    260         if use_connect and mode in ["mark", "uid", "ucast_oif"]:
    261           # If we have a destination cache entry, packets are not rerouted...
    262           if prevnetid:
    263             ExpectSendUsesNetid(prevnetid)
    264             # ... until we invalidate it.
    265             self.InvalidateDstCache(version, dstaddr, prevnetid)
    266           ExpectSendUsesNetid(netid)
    267         else:
    268           ExpectSendUsesNetid(netid)
    269 
    270         self.SelectInterface(s, None, mode)
    271         prevnetid = netid
    272 
    273   def testIPv4Remarking(self):
    274     """Checks that updating the mark on an IPv4 socket changes routing."""
    275     self.CheckRemarking(4, False)
    276     self.CheckRemarking(4, True)
    277 
    278   def testIPv6Remarking(self):
    279     """Checks that updating the mark on an IPv6 socket changes routing."""
    280     self.CheckRemarking(6, False)
    281     self.CheckRemarking(6, True)
    282 
    283   def testIPv6StickyPktinfo(self):
    284     for _ in xrange(self.ITERATIONS):
    285       for netid in self.tuns:
    286         s = net_test.UDPSocket(AF_INET6)
    287 
    288         # Set a flowlabel.
    289         net_test.SetFlowLabel(s, net_test.IPV6_ADDR, 0xdead)
    290         s.setsockopt(net_test.SOL_IPV6, net_test.IPV6_FLOWINFO_SEND, 1)
    291 
    292         # Set some destination options.
    293         nonce = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c"
    294         dstopts = "".join([
    295             "\x11\x02",              # Next header=UDP, 24 bytes of options.
    296             "\x01\x06", "\x00" * 6,  # PadN, 6 bytes of padding.
    297             "\x8b\x0c",              # ILNP nonce, 12 bytes.
    298             nonce
    299         ])
    300         s.setsockopt(net_test.SOL_IPV6, IPV6_DSTOPTS, dstopts)
    301         s.setsockopt(net_test.SOL_IPV6, IPV6_UNICAST_HOPS, 255)
    302 
    303         pktinfo = multinetwork_base.MakePktInfo(6, None, self.ifindices[netid])
    304 
    305         # Set the sticky pktinfo option.
    306         s.setsockopt(net_test.SOL_IPV6, IPV6_PKTINFO, pktinfo)
    307 
    308         # Specify the flowlabel in the destination address.
    309         s.sendto(UDP_PAYLOAD, (net_test.IPV6_ADDR, 53, 0xdead, 0))
    310 
    311         sport = s.getsockname()[1]
    312         srcaddr = self.MyAddress(6, netid)
    313         expected = (scapy.IPv6(src=srcaddr, dst=net_test.IPV6_ADDR,
    314                                fl=0xdead, hlim=255) /
    315                     scapy.IPv6ExtHdrDestOpt(
    316                         options=[scapy.PadN(optdata="\x00\x00\x00\x00\x00\x00"),
    317                                  scapy.HBHOptUnknown(otype=0x8b,
    318                                                      optdata=nonce)]) /
    319                     scapy.UDP(sport=sport, dport=53) /
    320                     UDP_PAYLOAD)
    321         msg = "IPv6 UDP using sticky pktinfo: expected UDP packet on %s" % (
    322             self.GetInterfaceName(netid))
    323         self.ExpectPacketOn(netid, msg, expected)
    324 
    325   def CheckPktinfoRouting(self, version):
    326     for _ in xrange(self.ITERATIONS):
    327       for netid in self.tuns:
    328         family = self.GetProtocolFamily(version)
    329         s = net_test.UDPSocket(family)
    330 
    331         if version == 6:
    332           # Create a flowlabel so we can use it.
    333           net_test.SetFlowLabel(s, net_test.IPV6_ADDR, 0xbeef)
    334 
    335           # Specify some arbitrary options.
    336           cmsgs = [
    337               (net_test.SOL_IPV6, IPV6_HOPLIMIT, 39),
    338               (net_test.SOL_IPV6, IPV6_TCLASS, 0x83),
    339               (net_test.SOL_IPV6, IPV6_FLOWINFO, int(htonl(0xbeef))),
    340           ]
    341         else:
    342           # Support for setting IPv4 TOS and TTL via cmsg only appeared in 3.13.
    343           cmsgs = []
    344           s.setsockopt(net_test.SOL_IP, IP_TTL, 39)
    345           s.setsockopt(net_test.SOL_IP, IP_TOS, 0x83)
    346 
    347         dstaddr = self.GetRemoteAddress(version)
    348         self.SendOnNetid(version, s, dstaddr, 53, netid, UDP_PAYLOAD, cmsgs)
    349 
    350         sport = s.getsockname()[1]
    351         srcaddr = self.MyAddress(version, netid)
    352 
    353         desc, expected = packets.UDPWithOptions(version, srcaddr, dstaddr,
    354                                                 sport=sport)
    355 
    356         msg = "IPv%d UDP using pktinfo routing: expected %s on %s" % (
    357             version, desc, self.GetInterfaceName(netid))
    358         self.ExpectPacketOn(netid, msg, expected)
    359 
    360   def testIPv4PktinfoRouting(self):
    361     self.CheckPktinfoRouting(4)
    362 
    363   def testIPv6PktinfoRouting(self):
    364     self.CheckPktinfoRouting(6)
    365 
    366 
    367 class MarkTest(InboundMarkingTest):
    368 
    369   def CheckReflection(self, version, gen_packet, gen_reply):
    370     """Checks that replies go out on the same interface as the original.
    371 
    372     For each combination:
    373      - Calls gen_packet to generate a packet to that IP address.
    374      - Writes the packet generated by gen_packet on the given tun
    375        interface, causing the kernel to receive it.
    376      - Checks that the kernel's reply matches the packet generated by
    377        gen_reply.
    378 
    379     Args:
    380       version: An integer, 4 or 6.
    381       gen_packet: A function taking an IP version (an integer), a source
    382         address and a destination address (strings), and returning a scapy
    383         packet.
    384       gen_reply: A function taking the same arguments as gen_packet,
    385         plus a scapy packet, and returning a scapy packet.
    386     """
    387     for netid, iif, ip_if, myaddr, remoteaddr in self.Combinations(version):
    388       # Generate a test packet.
    389       desc, packet = gen_packet(version, remoteaddr, myaddr)
    390 
    391       # Test with mark reflection enabled and disabled.
    392       for reflect in [0, 1]:
    393         self.SetMarkReflectSysctls(reflect)
    394         # HACK: IPv6 ping replies always do a routing lookup with the
    395         # interface the ping came in on. So even if mark reflection is not
    396         # working, IPv6 ping replies will be properly reflected. Don't
    397         # fail when that happens.
    398         if reflect or desc == "ICMPv6 echo":
    399           reply_desc, reply = gen_reply(version, myaddr, remoteaddr, packet)
    400         else:
    401           reply_desc, reply = None, None
    402 
    403         msg = self._FormatMessage(iif, ip_if, "reflect=%d" % reflect,
    404                                   desc, reply_desc)
    405         self._ReceiveAndExpectResponse(netid, packet, reply, msg)
    406 
    407   def SYNToClosedPort(self, *args):
    408     return packets.SYN(999, *args)
    409 
    410   def testIPv4ICMPErrorsReflectMark(self):
    411     self.CheckReflection(4, packets.UDP, packets.ICMPPortUnreachable)
    412 
    413   def testIPv6ICMPErrorsReflectMark(self):
    414     self.CheckReflection(6, packets.UDP, packets.ICMPPortUnreachable)
    415 
    416   def testIPv4PingRepliesReflectMarkAndTos(self):
    417     self.CheckReflection(4, packets.ICMPEcho, packets.ICMPReply)
    418 
    419   def testIPv6PingRepliesReflectMarkAndTos(self):
    420     self.CheckReflection(6, packets.ICMPEcho, packets.ICMPReply)
    421 
    422   def testIPv4RSTsReflectMark(self):
    423     self.CheckReflection(4, self.SYNToClosedPort, packets.RST)
    424 
    425   def testIPv6RSTsReflectMark(self):
    426     self.CheckReflection(6, self.SYNToClosedPort, packets.RST)
    427 
    428 
    429 class TCPAcceptTest(InboundMarkingTest):
    430 
    431   MODE_BINDTODEVICE = "SO_BINDTODEVICE"
    432   MODE_INCOMING_MARK = "incoming mark"
    433   MODE_EXPLICIT_MARK = "explicit mark"
    434   MODE_UID = "uid"
    435 
    436   @classmethod
    437   def setUpClass(cls):
    438     super(TCPAcceptTest, cls).setUpClass()
    439 
    440     # Open a port so we can observe SYN+ACKs. Since it's a dual-stack socket it
    441     # will accept both IPv4 and IPv6 connections. We do this here instead of in
    442     # each test so we can use the same socket every time. That way, if a kernel
    443     # bug causes incoming packets to mark the listening socket instead of the
    444     # accepted socket, the test will fail as soon as the next address/interface
    445     # combination is tried.
    446     cls.listensocket = net_test.IPv6TCPSocket()
    447     cls.listenport = net_test.BindRandomPort(6, cls.listensocket)
    448 
    449   def _SetTCPMarkAcceptSysctl(self, value):
    450     self.SetSysctl(TCP_MARK_ACCEPT_SYSCTL, value)
    451 
    452   def CheckTCPConnection(self, mode, listensocket, netid, version,
    453                          myaddr, remoteaddr, packet, reply, msg):
    454     establishing_ack = packets.ACK(version, remoteaddr, myaddr, reply)[1]
    455 
    456     # Attempt to confuse the kernel.
    457     self.InvalidateDstCache(version, remoteaddr, netid)
    458 
    459     self.ReceivePacketOn(netid, establishing_ack)
    460 
    461     # If we're using UID routing, the accept() call has to be run as a UID that
    462     # is routed to the specified netid, because the UID of the socket returned
    463     # by accept() is the effective UID of the process that calls it. It doesn't
    464     # need to be the same UID; any UID that selects the same interface will do.
    465     with net_test.RunAsUid(self.UidForNetid(netid)):
    466       s, _ = listensocket.accept()
    467 
    468     try:
    469       # Check that data sent on the connection goes out on the right interface.
    470       desc, data = packets.ACK(version, myaddr, remoteaddr, establishing_ack,
    471                                payload=UDP_PAYLOAD)
    472       s.send(UDP_PAYLOAD)
    473       self.ExpectPacketOn(netid, msg + ": expecting %s" % desc, data)
    474       self.InvalidateDstCache(version, remoteaddr, netid)
    475 
    476       # Keep up our end of the conversation.
    477       ack = packets.ACK(version, remoteaddr, myaddr, data)[1]
    478       self.InvalidateDstCache(version, remoteaddr, netid)
    479       self.ReceivePacketOn(netid, ack)
    480 
    481       mark = self.GetSocketMark(s)
    482     finally:
    483       self.InvalidateDstCache(version, remoteaddr, netid)
    484       s.close()
    485       self.InvalidateDstCache(version, remoteaddr, netid)
    486 
    487     if mode == self.MODE_INCOMING_MARK:
    488       self.assertEquals(netid, mark,
    489                         msg + ": Accepted socket: Expected mark %d, got %d" % (
    490                             netid, mark))
    491     elif mode != self.MODE_EXPLICIT_MARK:
    492       self.assertEquals(0, self.GetSocketMark(listensocket))
    493 
    494     # Check the FIN was sent on the right interface, and ack it. We don't expect
    495     # this to fail because by the time the connection is established things are
    496     # likely working, but a) extra tests are always good and b) extra packets
    497     # like the FIN (and retransmitted FINs) could cause later tests that expect
    498     # no packets to fail.
    499     desc, fin = packets.FIN(version, myaddr, remoteaddr, ack)
    500     self.ExpectPacketOn(netid, msg + ": expecting %s after close" % desc, fin)
    501 
    502     desc, finack = packets.FIN(version, remoteaddr, myaddr, fin)
    503     self.ReceivePacketOn(netid, finack)
    504 
    505     # Since we called close() earlier, the userspace socket object is gone, so
    506     # the socket has no UID. If we're doing UID routing, the ack might be routed
    507     # incorrectly. Not much we can do here.
    508     desc, finackack = packets.ACK(version, myaddr, remoteaddr, finack)
    509     self.ExpectPacketOn(netid, msg + ": expecting final ack", finackack)
    510 
    511   def CheckTCP(self, version, modes):
    512     """Checks that incoming TCP connections work.
    513 
    514     Args:
    515       version: An integer, 4 or 6.
    516       modes: A list of modes to excercise.
    517     """
    518     for syncookies in [0, 2]:
    519       for mode in modes:
    520         for netid, iif, ip_if, myaddr, remoteaddr in self.Combinations(version):
    521           listensocket = self.listensocket
    522           listenport = listensocket.getsockname()[1]
    523 
    524           accept_sysctl = 1 if mode == self.MODE_INCOMING_MARK else 0
    525           self._SetTCPMarkAcceptSysctl(accept_sysctl)
    526           self.SetMarkReflectSysctls(accept_sysctl)
    527 
    528           bound_dev = iif if mode == self.MODE_BINDTODEVICE else None
    529           self.BindToDevice(listensocket, bound_dev)
    530 
    531           mark = netid if mode == self.MODE_EXPLICIT_MARK else 0
    532           self.SetSocketMark(listensocket, mark)
    533 
    534           uid = self.UidForNetid(netid) if mode == self.MODE_UID else 0
    535           os.fchown(listensocket.fileno(), uid, -1)
    536 
    537           # Generate the packet here instead of in the outer loop, so
    538           # subsequent TCP connections use different source ports and
    539           # retransmissions from old connections don't confuse subsequent
    540           # tests.
    541           desc, packet = packets.SYN(listenport, version, remoteaddr, myaddr)
    542 
    543           if mode:
    544             reply_desc, reply = packets.SYNACK(version, myaddr, remoteaddr,
    545                                                packet)
    546           else:
    547             reply_desc, reply = None, None
    548 
    549           extra = "mode=%s, syncookies=%d" % (mode, syncookies)
    550           msg = self._FormatMessage(iif, ip_if, extra, desc, reply_desc)
    551           reply = self._ReceiveAndExpectResponse(netid, packet, reply, msg)
    552           if reply:
    553             self.CheckTCPConnection(mode, listensocket, netid, version, myaddr,
    554                                     remoteaddr, packet, reply, msg)
    555 
    556   def testBasicTCP(self):
    557     self.CheckTCP(4, [None, self.MODE_BINDTODEVICE, self.MODE_EXPLICIT_MARK])
    558     self.CheckTCP(6, [None, self.MODE_BINDTODEVICE, self.MODE_EXPLICIT_MARK])
    559 
    560   def testIPv4MarkAccept(self):
    561     self.CheckTCP(4, [self.MODE_INCOMING_MARK])
    562 
    563   def testIPv6MarkAccept(self):
    564     self.CheckTCP(6, [self.MODE_INCOMING_MARK])
    565 
    566   def testIPv4UidAccept(self):
    567     self.CheckTCP(4, [self.MODE_UID])
    568 
    569   def testIPv6UidAccept(self):
    570     self.CheckTCP(6, [self.MODE_UID])
    571 
    572   def testIPv6ExplicitMark(self):
    573     self.CheckTCP(6, [self.MODE_EXPLICIT_MARK])
    574 
    575 @unittest.skipUnless(multinetwork_base.HAVE_AUTOCONF_TABLE,
    576                      "need support for per-table autoconf")
    577 class RIOTest(multinetwork_base.MultiNetworkBaseTest):
    578   """Test for IPv6 RFC 4191 route information option
    579 
    580   Relevant kernel commits:
    581     upstream:
    582       f104a567e673 ipv6: use rt6_get_dflt_router to get default router in rt6_route_rcv
    583       bbea124bc99d net: ipv6: Add sysctl for minimum prefix len acceptable in RIOs.
    584 
    585     android-4.9:
    586       d860b2e8a7f1 FROMLIST: net: ipv6: Add sysctl for minimum prefix len acceptable in RIOs
    587 
    588     android-4.4:
    589       e953f89b8563 net: ipv6: Add sysctl for minimum prefix len acceptable in RIOs.
    590 
    591     android-4.1:
    592       84f2f47716cd net: ipv6: Add sysctl for minimum prefix len acceptable in RIOs.
    593 
    594     android-3.18:
    595       65f8936934fa net: ipv6: Add sysctl for minimum prefix len acceptable in RIOs.
    596 
    597     android-3.10:
    598       161e88ebebc7 net: ipv6: Add sysctl for minimum prefix len acceptable in RIOs.
    599 
    600   """
    601 
    602   def setUp(self):
    603     super(RIOTest, self).setUp()
    604     self.NETID = random.choice(self.NETIDS)
    605     self.IFACE = self.GetInterfaceName(self.NETID)
    606     # return min/max plen to default values before each test case
    607     self.SetAcceptRaRtInfoMinPlen(0)
    608     self.SetAcceptRaRtInfoMaxPlen(0)
    609 
    610   def GetRoutingTable(self):
    611     return self._TableForNetid(self.NETID)
    612 
    613   def SetAcceptRaRtInfoMinPlen(self, plen):
    614     self.SetSysctl(
    615         "/proc/sys/net/ipv6/conf/%s/accept_ra_rt_info_min_plen"
    616         % self.IFACE, plen)
    617 
    618   def GetAcceptRaRtInfoMinPlen(self):
    619     return int(self.GetSysctl(
    620         "/proc/sys/net/ipv6/conf/%s/accept_ra_rt_info_min_plen" % self.IFACE))
    621 
    622   def SetAcceptRaRtInfoMaxPlen(self, plen):
    623     self.SetSysctl(
    624         "/proc/sys/net/ipv6/conf/%s/accept_ra_rt_info_max_plen"
    625         % self.IFACE, plen)
    626 
    627   def GetAcceptRaRtInfoMaxPlen(self):
    628     return int(self.GetSysctl(
    629         "/proc/sys/net/ipv6/conf/%s/accept_ra_rt_info_max_plen" % self.IFACE))
    630 
    631   def SendRIO(self, rtlifetime, plen, prefix, prf):
    632     options = scapy.ICMPv6NDOptRouteInfo(rtlifetime=rtlifetime, plen=plen,
    633                                          prefix=prefix, prf=prf)
    634     self.SendRA(self.NETID, options=(options,))
    635 
    636   def FindRoutesWithDestination(self, destination):
    637     canonical = net_test.CanonicalizeIPv6Address(destination)
    638     return [r for _, r in self.iproute.DumpRoutes(6, self.GetRoutingTable())
    639             if ('RTA_DST' in r and r['RTA_DST'] == canonical)]
    640 
    641   def FindRoutesWithGateway(self):
    642     return [r for _, r in self.iproute.DumpRoutes(6, self.GetRoutingTable())
    643             if 'RTA_GATEWAY' in r]
    644 
    645   def CountRoutes(self):
    646     return len(self.iproute.DumpRoutes(6, self.GetRoutingTable()))
    647 
    648   def GetRouteExpiration(self, route):
    649     return float(route['RTA_CACHEINFO'].expires) / 100.0
    650 
    651   def AssertExpirationInRange(self, routes, lifetime, epsilon):
    652     self.assertTrue(routes)
    653     found = False
    654     # Assert that at least one route in routes has the expected lifetime
    655     for route in routes:
    656       expiration = self.GetRouteExpiration(route)
    657       if expiration < lifetime - epsilon:
    658         continue
    659       if expiration > lifetime + epsilon:
    660         continue
    661       found = True
    662     self.assertTrue(found)
    663 
    664   def DelRA6(self, prefix, plen):
    665     version = 6
    666     netid = self.NETID
    667     table = self._TableForNetid(netid)
    668     router = self._RouterAddress(netid, version)
    669     ifindex = self.ifindices[netid]
    670     # We actually want to specify RTPROT_RA, however an upstream
    671     # kernel bug causes RAs to be installed with RTPROT_BOOT.
    672     self.iproute._Route(version, iproute.RTPROT_BOOT, iproute.RTM_DELROUTE,
    673                         table, prefix, plen, router, ifindex, None, None)
    674 
    675   def testSetAcceptRaRtInfoMinPlen(self):
    676     for plen in xrange(-1, 130):
    677       self.SetAcceptRaRtInfoMinPlen(plen)
    678       self.assertEquals(plen, self.GetAcceptRaRtInfoMinPlen())
    679 
    680   def testSetAcceptRaRtInfoMaxPlen(self):
    681     for plen in xrange(-1, 130):
    682       self.SetAcceptRaRtInfoMaxPlen(plen)
    683       self.assertEquals(plen, self.GetAcceptRaRtInfoMaxPlen())
    684 
    685   def testZeroRtLifetime(self):
    686     PREFIX = "2001:db8:8901:2300::"
    687     RTLIFETIME = 73500
    688     PLEN = 56
    689     PRF = 0
    690     self.SetAcceptRaRtInfoMaxPlen(PLEN)
    691     self.SendRIO(RTLIFETIME, PLEN, PREFIX, PRF)
    692     # Give the kernel time to notice our RA
    693     time.sleep(0.01)
    694     self.assertTrue(self.FindRoutesWithDestination(PREFIX))
    695     # RIO with rtlifetime = 0 should remove from routing table
    696     self.SendRIO(0, PLEN, PREFIX, PRF)
    697     # Give the kernel time to notice our RA
    698     time.sleep(0.01)
    699     self.assertFalse(self.FindRoutesWithDestination(PREFIX))
    700 
    701   def testMinPrefixLenRejection(self):
    702     PREFIX = "2001:db8:8902:2345::"
    703     RTLIFETIME = 70372
    704     PRF = 0
    705     # sweep from high to low to avoid spurious failures from late arrivals.
    706     for plen in xrange(130, 1, -1):
    707       self.SetAcceptRaRtInfoMinPlen(plen)
    708       # RIO with plen < min_plen should be ignored
    709       self.SendRIO(RTLIFETIME, plen - 1, PREFIX, PRF)
    710     # Give the kernel time to notice our RAs
    711     time.sleep(0.1)
    712     # Expect no routes
    713     routes = self.FindRoutesWithDestination(PREFIX)
    714     self.assertFalse(routes)
    715 
    716   def testMaxPrefixLenRejection(self):
    717     PREFIX = "2001:db8:8903:2345::"
    718     RTLIFETIME = 73078
    719     PRF = 0
    720     # sweep from low to high to avoid spurious failures from late arrivals.
    721     for plen in xrange(-1, 128, 1):
    722       self.SetAcceptRaRtInfoMaxPlen(plen)
    723       # RIO with plen > max_plen should be ignored
    724       self.SendRIO(RTLIFETIME, plen + 1, PREFIX, PRF)
    725     # Give the kernel time to notice our RAs
    726     time.sleep(0.1)
    727     # Expect no routes
    728     routes = self.FindRoutesWithDestination(PREFIX)
    729     self.assertFalse(routes)
    730 
    731   def testSimpleAccept(self):
    732     PREFIX = "2001:db8:8904:2345::"
    733     RTLIFETIME = 9993
    734     PRF = 0
    735     PLEN = 56
    736     self.SetAcceptRaRtInfoMinPlen(48)
    737     self.SetAcceptRaRtInfoMaxPlen(64)
    738     self.SendRIO(RTLIFETIME, PLEN, PREFIX, PRF)
    739     # Give the kernel time to notice our RA
    740     time.sleep(0.01)
    741     routes = self.FindRoutesWithGateway()
    742     self.AssertExpirationInRange(routes, RTLIFETIME, 1)
    743     self.DelRA6(PREFIX, PLEN)
    744 
    745   def testEqualMinMaxAccept(self):
    746     PREFIX = "2001:db8:8905:2345::"
    747     RTLIFETIME = 6326
    748     PLEN = 21
    749     PRF = 0
    750     self.SetAcceptRaRtInfoMinPlen(PLEN)
    751     self.SetAcceptRaRtInfoMaxPlen(PLEN)
    752     self.SendRIO(RTLIFETIME, PLEN, PREFIX, PRF)
    753     # Give the kernel time to notice our RA
    754     time.sleep(0.01)
    755     routes = self.FindRoutesWithGateway()
    756     self.AssertExpirationInRange(routes, RTLIFETIME, 1)
    757     self.DelRA6(PREFIX, PLEN)
    758 
    759   def testZeroLengthPrefix(self):
    760     PREFIX = "2001:db8:8906:2345::"
    761     RTLIFETIME = self.RA_VALIDITY * 2
    762     PLEN = 0
    763     PRF = 0
    764     # Max plen = 0 still allows default RIOs!
    765     self.SetAcceptRaRtInfoMaxPlen(PLEN)
    766     self.SendRA(self.NETID)
    767     # Give the kernel time to notice our RA
    768     time.sleep(0.01)
    769     default = self.FindRoutesWithGateway()
    770     self.AssertExpirationInRange(default, self.RA_VALIDITY, 1)
    771     # RIO with prefix length = 0, should overwrite default route lifetime
    772     # note that the RIO lifetime overwrites the RA lifetime.
    773     self.SendRIO(RTLIFETIME, PLEN, PREFIX, PRF)
    774     # Give the kernel time to notice our RA
    775     time.sleep(0.01)
    776     default = self.FindRoutesWithGateway()
    777     self.AssertExpirationInRange(default, RTLIFETIME, 1)
    778     self.DelRA6(PREFIX, PLEN)
    779 
    780   def testManyRIOs(self):
    781     RTLIFETIME = 68012
    782     PLEN = 56
    783     PRF = 0
    784     COUNT = 1000
    785     baseline = self.CountRoutes()
    786     self.SetAcceptRaRtInfoMaxPlen(56)
    787     # Send many RIOs compared to the expected number on a healthy system.
    788     for i in xrange(0, COUNT):
    789       prefix = "2001:db8:%x:1100::" % i
    790       self.SendRIO(RTLIFETIME, PLEN, prefix, PRF)
    791     time.sleep(0.1)
    792     self.assertEquals(COUNT + baseline, self.CountRoutes())
    793     for i in xrange(0, COUNT):
    794       prefix = "2001:db8:%x:1100::" % i
    795       self.DelRA6(prefix, PLEN)
    796     # Expect that we can return to baseline config without lingering routes.
    797     self.assertEquals(baseline, self.CountRoutes())
    798 
    799 class RATest(multinetwork_base.MultiNetworkBaseTest):
    800 
    801   def testDoesNotHaveObsoleteSysctl(self):
    802     self.assertFalse(os.path.isfile(
    803         "/proc/sys/net/ipv6/route/autoconf_table_offset"))
    804 
    805   @unittest.skipUnless(multinetwork_base.HAVE_AUTOCONF_TABLE,
    806                        "no support for per-table autoconf")
    807   def testPurgeDefaultRouters(self):
    808 
    809     def CheckIPv6Connectivity(expect_connectivity):
    810       for netid in self.NETIDS:
    811         s = net_test.UDPSocket(AF_INET6)
    812         self.SetSocketMark(s, netid)
    813         if expect_connectivity:
    814           self.assertTrue(s.sendto(UDP_PAYLOAD, (net_test.IPV6_ADDR, 1234)))
    815         else:
    816           self.assertRaisesErrno(errno.ENETUNREACH, s.sendto, UDP_PAYLOAD,
    817                                  (net_test.IPV6_ADDR, 1234))
    818 
    819     try:
    820       CheckIPv6Connectivity(True)
    821       self.SetIPv6SysctlOnAllIfaces("accept_ra", 1)
    822       self.SetSysctl("/proc/sys/net/ipv6/conf/all/forwarding", 1)
    823       CheckIPv6Connectivity(False)
    824     finally:
    825       self.SetSysctl("/proc/sys/net/ipv6/conf/all/forwarding", 0)
    826       for netid in self.NETIDS:
    827         self.SendRA(netid)
    828       CheckIPv6Connectivity(True)
    829 
    830   def testOnlinkCommunication(self):
    831     """Checks that on-link communication goes direct and not through routers."""
    832     for netid in self.tuns:
    833       # Send a UDP packet to a random on-link destination.
    834       s = net_test.UDPSocket(AF_INET6)
    835       iface = self.GetInterfaceName(netid)
    836       self.BindToDevice(s, iface)
    837       # dstaddr can never be our address because GetRandomDestination only fills
    838       # in the lower 32 bits, but our address has 0xff in the byte before that
    839       # (since it's constructed from the EUI-64 and so has ff:fe in the middle).
    840       dstaddr = self.GetRandomDestination(self.OnlinkPrefix(6, netid))
    841       s.sendto(UDP_PAYLOAD, (dstaddr, 53))
    842 
    843       # Expect an NS for that destination on the interface.
    844       myaddr = self.MyAddress(6, netid)
    845       mymac = self.MyMacAddress(netid)
    846       desc, expected = packets.NS(myaddr, dstaddr, mymac)
    847       msg = "Sending UDP packet to on-link destination: expecting %s" % desc
    848       time.sleep(0.0001)  # Required to make the test work on kernel 3.1(!)
    849       self.ExpectPacketOn(netid, msg, expected)
    850 
    851       # Send an NA.
    852       tgtmac = "02:00:00:00:%02x:99" % netid
    853       _, reply = packets.NA(dstaddr, myaddr, tgtmac)
    854       # Don't use ReceivePacketOn, since that uses the router's MAC address as
    855       # the source. Instead, construct our own Ethernet header with source
    856       # MAC of tgtmac.
    857       reply = scapy.Ether(src=tgtmac, dst=mymac) / reply
    858       self.ReceiveEtherPacketOn(netid, reply)
    859 
    860       # Expect the kernel to send the original UDP packet now that the ND cache
    861       # entry has been populated.
    862       sport = s.getsockname()[1]
    863       desc, expected = packets.UDP(6, myaddr, dstaddr, sport=sport)
    864       msg = "After NA response, expecting %s" % desc
    865       self.ExpectPacketOn(netid, msg, expected)
    866 
    867   # This test documents a known issue: routing tables are never deleted.
    868   @unittest.skipUnless(multinetwork_base.HAVE_AUTOCONF_TABLE,
    869                        "no support for per-table autoconf")
    870   def testLeftoverRoutes(self):
    871     def GetNumRoutes():
    872       return len(open("/proc/net/ipv6_route").readlines())
    873 
    874     num_routes = GetNumRoutes()
    875     for i in xrange(10, 20):
    876       try:
    877         self.tuns[i] = self.CreateTunInterface(i)
    878         self.SendRA(i)
    879         self.tuns[i].close()
    880       finally:
    881         del self.tuns[i]
    882     self.assertLess(num_routes, GetNumRoutes())
    883 
    884 
    885 class PMTUTest(InboundMarkingTest):
    886 
    887   PAYLOAD_SIZE = 1400
    888   dstaddrs = set()
    889 
    890   def GetSocketMTU(self, version, s):
    891     if version == 6:
    892       ip6_mtuinfo = s.getsockopt(net_test.SOL_IPV6, csocket.IPV6_PATHMTU, 32)
    893       unused_sockaddr, mtu = struct.unpack("=28sI", ip6_mtuinfo)
    894       return mtu
    895     else:
    896       return s.getsockopt(net_test.SOL_IP, csocket.IP_MTU)
    897 
    898   def DisableFragmentationAndReportErrors(self, version, s):
    899     if version == 4:
    900       s.setsockopt(net_test.SOL_IP, csocket.IP_MTU_DISCOVER,
    901                    csocket.IP_PMTUDISC_DO)
    902       s.setsockopt(net_test.SOL_IP, net_test.IP_RECVERR, 1)
    903     else:
    904       s.setsockopt(net_test.SOL_IPV6, csocket.IPV6_DONTFRAG, 1)
    905       s.setsockopt(net_test.SOL_IPV6, net_test.IPV6_RECVERR, 1)
    906 
    907   def CheckPMTU(self, version, use_connect, modes):
    908 
    909     def SendBigPacket(version, s, dstaddr, netid, payload):
    910       if use_connect:
    911         s.send(payload)
    912       else:
    913         self.SendOnNetid(version, s, dstaddr, 1234, netid, payload, [])
    914 
    915     for netid in self.tuns:
    916       for mode in modes:
    917         s = self.BuildSocket(version, net_test.UDPSocket, netid, mode)
    918         self.DisableFragmentationAndReportErrors(version, s)
    919 
    920         srcaddr = self.MyAddress(version, netid)
    921         dst_prefix, intermediate = {
    922             4: ("172.19.", "172.16.9.12"),
    923             6: ("2001:db8::", "2001:db8::1")
    924         }[version]
    925 
    926         # Run this test often enough (e.g., in presubmits), and eventually
    927         # we'll be unlucky enough to pick the same address twice, in which
    928         # case the test will fail because the kernel will already have seen
    929         # the lower MTU. Don't do this.
    930         dstaddr = self.GetRandomDestination(dst_prefix)
    931         while dstaddr in self.dstaddrs:
    932           dstaddr = self.GetRandomDestination(dst_prefix)
    933         self.dstaddrs.add(dstaddr)
    934 
    935         if use_connect:
    936           s.connect((dstaddr, 1234))
    937 
    938         payload = self.PAYLOAD_SIZE * "a"
    939 
    940         # Send a packet and receive a packet too big.
    941         SendBigPacket(version, s, dstaddr, netid, payload)
    942         received = self.ReadAllPacketsOn(netid)
    943         self.assertEquals(1, len(received),
    944                           "unexpected packets: %s" % received[1:])
    945         _, toobig = packets.ICMPPacketTooBig(version, intermediate, srcaddr,
    946                                              received[0])
    947         self.ReceivePacketOn(netid, toobig)
    948 
    949         # Check that another send on the same socket returns EMSGSIZE.
    950         self.assertRaisesErrno(
    951             errno.EMSGSIZE,
    952             SendBigPacket, version, s, dstaddr, netid, payload)
    953 
    954         # If this is a connected socket, make sure the socket MTU was set.
    955         # Note that in IPv4 this only started working in Linux 3.6!
    956         if use_connect and (version == 6 or net_test.LINUX_VERSION >= (3, 6)):
    957           self.assertEquals(1280, self.GetSocketMTU(version, s))
    958 
    959         s.close()
    960 
    961         # Check that other sockets pick up the PMTU we have been told about by
    962         # connecting another socket to the same destination and getting its MTU.
    963         # This new socket can use any method to select its outgoing interface;
    964         # here we use a mark for simplicity.
    965         s2 = self.BuildSocket(version, net_test.UDPSocket, netid, "mark")
    966         s2.connect((dstaddr, 1234))
    967         self.assertEquals(1280, self.GetSocketMTU(version, s2))
    968 
    969         # Also check the MTU reported by ip route get, this time using the oif.
    970         routes = self.iproute.GetRoutes(dstaddr, self.ifindices[netid], 0, None)
    971         self.assertTrue(routes)
    972         route = routes[0]
    973         rtmsg, attributes = route
    974         self.assertEquals(iproute.RTN_UNICAST, rtmsg.type)
    975         metrics = attributes["RTA_METRICS"]
    976         self.assertEquals(metrics["RTAX_MTU"], 1280)
    977 
    978   def testIPv4BasicPMTU(self):
    979     """Tests IPv4 path MTU discovery.
    980 
    981     Relevant kernel commits:
    982       upstream net-next:
    983         6a66271 ipv4, fib: pass LOOPBACK_IFINDEX instead of 0 to flowi4_iif
    984 
    985       android-3.10:
    986         4bc64dd ipv4, fib: pass LOOPBACK_IFINDEX instead of 0 to flowi4_iif
    987     """
    988 
    989     self.CheckPMTU(4, True, ["mark", "oif"])
    990     self.CheckPMTU(4, False, ["mark", "oif"])
    991 
    992   def testIPv6BasicPMTU(self):
    993     self.CheckPMTU(6, True, ["mark", "oif"])
    994     self.CheckPMTU(6, False, ["mark", "oif"])
    995 
    996   def testIPv4UIDPMTU(self):
    997     self.CheckPMTU(4, True, ["uid"])
    998     self.CheckPMTU(4, False, ["uid"])
    999 
   1000   def testIPv6UIDPMTU(self):
   1001     self.CheckPMTU(6, True, ["uid"])
   1002     self.CheckPMTU(6, False, ["uid"])
   1003 
   1004   # Making Path MTU Discovery work on unmarked  sockets requires that mark
   1005   # reflection be enabled. Otherwise the kernel has no way to know what routing
   1006   # table the original packet used, and thus it won't be able to clone the
   1007   # correct route.
   1008 
   1009   def testIPv4UnmarkedSocketPMTU(self):
   1010     self.SetMarkReflectSysctls(1)
   1011     try:
   1012       self.CheckPMTU(4, False, [None])
   1013     finally:
   1014       self.SetMarkReflectSysctls(0)
   1015 
   1016   def testIPv6UnmarkedSocketPMTU(self):
   1017     self.SetMarkReflectSysctls(1)
   1018     try:
   1019       self.CheckPMTU(6, False, [None])
   1020     finally:
   1021       self.SetMarkReflectSysctls(0)
   1022 
   1023 
   1024 class UidRoutingTest(multinetwork_base.MultiNetworkBaseTest):
   1025   """Tests that per-UID routing works properly.
   1026 
   1027   Relevant kernel commits:
   1028     upstream net-next:
   1029       7d99569460 net: ipv4: Don't crash if passing a null sk to ip_do_redirect.
   1030       d109e61bfe net: ipv4: Don't crash if passing a null sk to ip_rt_update_pmtu.
   1031       35b80733b3 net: core: add missing check for uid_range in rule_exists.
   1032       e2d118a1cb net: inet: Support UID-based routing in IP protocols.
   1033       622ec2c9d5 net: core: add UID to flows, rules, and routes
   1034       86741ec254 net: core: Add a UID field to struct sock.
   1035 
   1036     android-3.18:
   1037       b004e79504 net: ipv4: Don't crash if passing a null sk to ip_rt_update_pmtu.
   1038       04c0eace81 net: inet: Support UID-based routing in IP protocols.
   1039       18c36d7b71 net: core: add UID to flows, rules, and routes
   1040       80e3440721 net: core: Add a UID field to struct sock.
   1041       fa8cc2c30c Revert "net: core: Support UID-based routing."
   1042       b585141890 Revert "Handle 'sk' being NULL in UID-based routing."
   1043       5115ab7514 Revert "net: core: fix UID-based routing build"
   1044       f9f4281f79 Revert "ANDROID: net: fib: remove duplicate assignment"
   1045 
   1046     android-4.4:
   1047       341965cf10 net: ipv4: Don't crash if passing a null sk to ip_rt_update_pmtu.
   1048       344afd627c net: inet: Support UID-based routing in IP protocols.
   1049       03441d56d8 net: core: add UID to flows, rules, and routes
   1050       eb964bdba7 net: core: Add a UID field to struct sock.
   1051       9789b697c6 Revert "net: core: Support UID-based routing."
   1052   """
   1053 
   1054   def GetRulesAtPriority(self, version, priority):
   1055     rules = self.iproute.DumpRules(version)
   1056     out = [(rule, attributes) for rule, attributes in rules
   1057            if attributes.get("FRA_PRIORITY", 0) == priority]
   1058     return out
   1059 
   1060   def CheckInitialTablesHaveNoUIDs(self, version):
   1061     rules = []
   1062     for priority in [0, 32766, 32767]:
   1063       rules.extend(self.GetRulesAtPriority(version, priority))
   1064     for _, attributes in rules:
   1065       self.assertNotIn("FRA_UID_RANGE", attributes)
   1066 
   1067   def testIPv4InitialTablesHaveNoUIDs(self):
   1068     self.CheckInitialTablesHaveNoUIDs(4)
   1069 
   1070   def testIPv6InitialTablesHaveNoUIDs(self):
   1071     self.CheckInitialTablesHaveNoUIDs(6)
   1072 
   1073   @staticmethod
   1074   def _Random():
   1075     return random.randint(1000000, 2000000)
   1076 
   1077   def CheckGetAndSetRules(self, version):
   1078     start, end = tuple(sorted([self._Random(), self._Random()]))
   1079     table = self._Random()
   1080     priority = self._Random()
   1081 
   1082     # Can't create a UID range to UID -1 because -1 is INVALID_UID...
   1083     self.assertRaisesErrno(
   1084         errno.EINVAL,
   1085         self.iproute.UidRangeRule, version, True, 100, 0xffffffff, table,
   1086         priority)
   1087 
   1088     # ... but -2 is valid.
   1089     self.iproute.UidRangeRule(version, True, 100, 0xfffffffe, table, priority)
   1090     self.iproute.UidRangeRule(version, False, 100, 0xfffffffe, table, priority)
   1091 
   1092     try:
   1093       # Create a UID range rule.
   1094       self.iproute.UidRangeRule(version, True, start, end, table, priority)
   1095 
   1096       # Check that deleting the wrong UID range doesn't work.
   1097       self.assertRaisesErrno(
   1098           errno.ENOENT,
   1099           self.iproute.UidRangeRule, version, False, start, end + 1, table,
   1100           priority)
   1101       self.assertRaisesErrno(errno.ENOENT,
   1102         self.iproute.UidRangeRule, version, False, start + 1, end, table,
   1103         priority)
   1104 
   1105       # Check that the UID range appears in dumps.
   1106       rules = self.GetRulesAtPriority(version, priority)
   1107       self.assertTrue(rules)
   1108       _, attributes = rules[-1]
   1109       self.assertEquals(priority, attributes["FRA_PRIORITY"])
   1110       uidrange = attributes["FRA_UID_RANGE"]
   1111       self.assertEquals(start, uidrange.start)
   1112       self.assertEquals(end, uidrange.end)
   1113       self.assertEquals(table, attributes["FRA_TABLE"])
   1114     finally:
   1115       self.iproute.UidRangeRule(version, False, start, end, table, priority)
   1116       self.assertRaisesErrno(
   1117           errno.ENOENT,
   1118           self.iproute.UidRangeRule, version, False, start, end, table,
   1119           priority)
   1120 
   1121     try:
   1122       # Create a rule without a UID range.
   1123       self.iproute.FwmarkRule(version, True, 300, 301, priority + 1)
   1124 
   1125       # Check it doesn't have a UID range.
   1126       rules = self.GetRulesAtPriority(version, priority + 1)
   1127       self.assertTrue(rules)
   1128       for _, attributes in rules:
   1129         self.assertIn("FRA_TABLE", attributes)
   1130         self.assertNotIn("FRA_UID_RANGE", attributes)
   1131     finally:
   1132       self.iproute.FwmarkRule(version, False, 300, 301, priority + 1)
   1133 
   1134     # Test that EEXIST worksfor UID range rules too. This behaviour was only
   1135     # added in 4.8.
   1136     if net_test.LINUX_VERSION >= (4, 8, 0):
   1137       ranges = [(100, 101), (100, 102), (99, 101), (1234, 5678)]
   1138       dup = ranges[0]
   1139       try:
   1140         # Check that otherwise identical rules with different UID ranges can be
   1141         # created without EEXIST.
   1142         for start, end in ranges:
   1143           self.iproute.UidRangeRule(version, True, start, end, table, priority)
   1144         # ... but EEXIST is returned if the UID range is identical.
   1145         self.assertRaisesErrno(
   1146           errno.EEXIST,
   1147           self.iproute.UidRangeRule, version, True, dup[0], dup[1], table,
   1148           priority)
   1149       finally:
   1150         # Clean up.
   1151         for start, end in ranges + [dup]:
   1152           try:
   1153             self.iproute.UidRangeRule(version, False, start, end, table,
   1154                                       priority)
   1155           except IOError:
   1156             pass
   1157 
   1158   def testIPv4GetAndSetRules(self):
   1159     self.CheckGetAndSetRules(4)
   1160 
   1161   def testIPv6GetAndSetRules(self):
   1162     self.CheckGetAndSetRules(6)
   1163 
   1164   def ExpectNoRoute(self, addr, oif, mark, uid):
   1165     # The lack of a route may be either an error, or an unreachable route.
   1166     try:
   1167       routes = self.iproute.GetRoutes(addr, oif, mark, uid)
   1168       rtmsg, _ = routes[0]
   1169       self.assertEquals(iproute.RTN_UNREACHABLE, rtmsg.type)
   1170     except IOError, e:
   1171       if int(e.errno) != -int(errno.ENETUNREACH):
   1172         raise e
   1173 
   1174   def ExpectRoute(self, addr, oif, mark, uid):
   1175     routes = self.iproute.GetRoutes(addr, oif, mark, uid)
   1176     rtmsg, _ = routes[0]
   1177     self.assertEquals(iproute.RTN_UNICAST, rtmsg.type)
   1178 
   1179   def CheckGetRoute(self, version, addr):
   1180     self.ExpectNoRoute(addr, 0, 0, 0)
   1181     for netid in self.NETIDS:
   1182       uid = self.UidForNetid(netid)
   1183       self.ExpectRoute(addr, 0, 0, uid)
   1184     self.ExpectNoRoute(addr, 0, 0, 0)
   1185 
   1186   def testIPv4RouteGet(self):
   1187     self.CheckGetRoute(4, net_test.IPV4_ADDR)
   1188 
   1189   def testIPv6RouteGet(self):
   1190     self.CheckGetRoute(6, net_test.IPV6_ADDR)
   1191 
   1192   def testChangeFdAttributes(self):
   1193     netid = random.choice(self.NETIDS)
   1194     uid = self._Random()
   1195     table = self._TableForNetid(netid)
   1196     remoteaddr = self.GetRemoteAddress(6)
   1197     s = socket(AF_INET6, SOCK_DGRAM, 0)
   1198 
   1199     def CheckSendFails():
   1200       self.assertRaisesErrno(errno.ENETUNREACH,
   1201                              s.sendto, "foo", (remoteaddr, 53))
   1202     def CheckSendSucceeds():
   1203       self.assertEquals(len("foo"), s.sendto("foo", (remoteaddr, 53)))
   1204 
   1205     CheckSendFails()
   1206     self.iproute.UidRangeRule(6, True, uid, uid, table, self.PRIORITY_UID)
   1207     try:
   1208       CheckSendFails()
   1209       os.fchown(s.fileno(), uid, -1)
   1210       CheckSendSucceeds()
   1211       os.fchown(s.fileno(), -1, -1)
   1212       CheckSendSucceeds()
   1213       os.fchown(s.fileno(), -1, 12345)
   1214       CheckSendSucceeds()
   1215       os.fchmod(s.fileno(), 0777)
   1216       CheckSendSucceeds()
   1217       os.fchown(s.fileno(), 0, -1)
   1218       CheckSendFails()
   1219     finally:
   1220       self.iproute.UidRangeRule(6, False, uid, uid, table, self.PRIORITY_UID)
   1221 
   1222 
   1223 class RulesTest(net_test.NetworkTest):
   1224 
   1225   RULE_PRIORITY = 99999
   1226 
   1227   def setUp(self):
   1228     self.iproute = iproute.IPRoute()
   1229     for version in [4, 6]:
   1230       self.iproute.DeleteRulesAtPriority(version, self.RULE_PRIORITY)
   1231 
   1232   def tearDown(self):
   1233     for version in [4, 6]:
   1234       self.iproute.DeleteRulesAtPriority(version, self.RULE_PRIORITY)
   1235 
   1236   def testRuleDeletionMatchesTable(self):
   1237     for version in [4, 6]:
   1238       # Add rules with mark 300 pointing at tables 301 and 302.
   1239       # This checks for a kernel bug where deletion request for tables > 256
   1240       # ignored the table.
   1241       self.iproute.FwmarkRule(version, True, 300, 301,
   1242                               priority=self.RULE_PRIORITY)
   1243       self.iproute.FwmarkRule(version, True, 300, 302,
   1244                               priority=self.RULE_PRIORITY)
   1245       # Delete rule with mark 300 pointing at table 302.
   1246       self.iproute.FwmarkRule(version, False, 300, 302,
   1247                               priority=self.RULE_PRIORITY)
   1248       # Check that the rule pointing at table 301 is still around.
   1249       attributes = [a for _, a in self.iproute.DumpRules(version)
   1250                     if a.get("FRA_PRIORITY", 0) == self.RULE_PRIORITY]
   1251       self.assertEquals(1, len(attributes))
   1252       self.assertEquals(301, attributes[0]["FRA_TABLE"])
   1253 
   1254 
   1255 if __name__ == "__main__":
   1256   unittest.main()
   1257