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