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