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