3 # Copyright 2014 The Android Open Source Project
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
20 from socket import * # pylint: disable=wildcard-import
22 import time # pylint: disable=unused-import
25 from scapy import all as scapy
28 import multinetwork_base
33 UDP_PAYLOAD = net_test.UDP_PAYLOAD
37 IPV4_MARK_REFLECT_SYSCTL = "/proc/sys/net/ipv4/fwmark_reflect"
38 IPV6_MARK_REFLECT_SYSCTL = "/proc/sys/net/ipv6/fwmark_reflect"
39 SYNCOOKIES_SYSCTL = "/proc/sys/net/ipv4/tcp_syncookies"
40 TCP_MARK_ACCEPT_SYSCTL = "/proc/sys/net/ipv4/tcp_fwmark_accept"
42 # The IP[V6]UNICAST_IF socket option was added between 3.1 and 3.4.
43 HAVE_UNICAST_IF = net_test.LINUX_VERSION >= (3, 4, 0)
46 class ConfigurationError(AssertionError):
50 class InboundMarkingTest(multinetwork_base.MultiNetworkBaseTest):
53 def _SetInboundMarking(cls, netid, is_add):
54 for version in [4, 6]:
55 # Run iptables to set up incoming packet marking.
56 iface = cls.GetInterfaceName(netid)
57 add_del = "-A" if is_add else "-D"
58 iptables = {4: "iptables", 6: "ip6tables"}[version]
59 args = "%s %s INPUT -t mangle -i %s -j MARK --set-mark %d" % (
60 iptables, add_del, iface, netid)
61 iptables = "/sbin/" + iptables
62 ret = os.spawnvp(os.P_WAIT, iptables, args.split(" "))
64 raise ConfigurationError("Setup command failed: %s" % args)
68 super(InboundMarkingTest, cls).setUpClass()
69 for netid in cls.tuns:
70 cls._SetInboundMarking(netid, True)
73 def tearDownClass(cls):
74 for netid in cls.tuns:
75 cls._SetInboundMarking(netid, False)
76 super(InboundMarkingTest, cls).tearDownClass()
79 def SetMarkReflectSysctls(cls, value):
80 cls.SetSysctl(IPV4_MARK_REFLECT_SYSCTL, value)
82 cls.SetSysctl(IPV6_MARK_REFLECT_SYSCTL, value)
84 # This does not exist if we use the version of the patch that uses a
85 # common sysctl for IPv4 and IPv6.
89 class OutgoingTest(multinetwork_base.MultiNetworkBaseTest):
91 # How many times to run outgoing packet tests.
94 def CheckPingPacket(self, version, netid, routing_mode, dstaddr, packet):
95 s = self.BuildSocket(version, net_test.PingSocket, netid, routing_mode)
97 myaddr = self.MyAddress(version, netid)
98 s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
99 s.bind((myaddr, packets.PING_IDENT))
100 net_test.SetSocketTos(s, packets.PING_TOS)
102 desc, expected = packets.ICMPEcho(version, myaddr, dstaddr)
103 msg = "IPv%d ping: expected %s on %s" % (
104 version, desc, self.GetInterfaceName(netid))
106 s.sendto(packet + packets.PING_PAYLOAD, (dstaddr, 19321))
108 self.ExpectPacketOn(netid, msg, expected)
110 def CheckTCPSYNPacket(self, version, netid, routing_mode, dstaddr):
111 s = self.BuildSocket(version, net_test.TCPSocket, netid, routing_mode)
113 if version == 6 and dstaddr.startswith("::ffff"):
115 myaddr = self.MyAddress(version, netid)
116 desc, expected = packets.SYN(53, version, myaddr, dstaddr,
117 sport=None, seq=None)
119 # Non-blocking TCP connects always return EINPROGRESS.
120 self.assertRaisesErrno(errno.EINPROGRESS, s.connect, (dstaddr, 53))
121 msg = "IPv%s TCP connect: expected %s on %s" % (
122 version, desc, self.GetInterfaceName(netid))
123 self.ExpectPacketOn(netid, msg, expected)
126 def CheckUDPPacket(self, version, netid, routing_mode, dstaddr):
127 s = self.BuildSocket(version, net_test.UDPSocket, netid, routing_mode)
129 if version == 6 and dstaddr.startswith("::ffff"):
131 myaddr = self.MyAddress(version, netid)
132 desc, expected = packets.UDP(version, myaddr, dstaddr, sport=None)
133 msg = "IPv%s UDP %%s: expected %s on %s" % (
134 version, desc, self.GetInterfaceName(netid))
136 s.sendto(UDP_PAYLOAD, (dstaddr, 53))
137 self.ExpectPacketOn(netid, msg % "sendto", expected)
139 # IP_UNICAST_IF doesn't seem to work on connected sockets, so no TCP.
140 if routing_mode != "ucast_oif":
141 s.connect((dstaddr, 53))
143 self.ExpectPacketOn(netid, msg % "connect/send", expected)
146 def CheckRawGrePacket(self, version, netid, routing_mode, dstaddr):
147 s = self.BuildSocket(version, net_test.RawGRESocket, netid, routing_mode)
149 inner_version = {4: 6, 6: 4}[version]
150 inner_src = self.MyAddress(inner_version, netid)
151 inner_dst = self.GetRemoteAddress(inner_version)
152 inner = str(packets.UDP(inner_version, inner_src, inner_dst, sport=None)[1])
154 ethertype = {4: net_test.ETH_P_IP, 6: net_test.ETH_P_IPV6}[inner_version]
155 # A GRE header can be as simple as two zero bytes and the ethertype.
156 packet = struct.pack("!i", ethertype) + inner
157 myaddr = self.MyAddress(version, netid)
159 s.sendto(packet, (dstaddr, IPPROTO_GRE))
160 desc, expected = packets.GRE(version, myaddr, dstaddr, ethertype, inner)
161 msg = "Raw IPv%d GRE with inner IPv%d UDP: expected %s on %s" % (
162 version, inner_version, desc, self.GetInterfaceName(netid))
163 self.ExpectPacketOn(netid, msg, expected)
165 def CheckOutgoingPackets(self, routing_mode):
166 v4addr = self.IPV4_ADDR
167 v6addr = self.IPV6_ADDR
168 v4mapped = "::ffff:" + v4addr
170 for _ in xrange(self.ITERATIONS):
171 for netid in self.tuns:
173 self.CheckPingPacket(4, netid, routing_mode, v4addr, self.IPV4_PING)
175 if routing_mode != "oif":
176 self.CheckPingPacket(6, netid, routing_mode, v6addr, self.IPV6_PING)
178 # IP_UNICAST_IF doesn't seem to work on connected sockets, so no TCP.
179 if routing_mode != "ucast_oif":
180 self.CheckTCPSYNPacket(4, netid, routing_mode, v4addr)
181 self.CheckTCPSYNPacket(6, netid, routing_mode, v6addr)
182 self.CheckTCPSYNPacket(6, netid, routing_mode, v4mapped)
184 self.CheckUDPPacket(4, netid, routing_mode, v4addr)
185 self.CheckUDPPacket(6, netid, routing_mode, v6addr)
186 self.CheckUDPPacket(6, netid, routing_mode, v4mapped)
188 # Creating raw sockets on non-root UIDs requires properly setting
189 # capabilities, which is hard to do from Python.
190 # IP_UNICAST_IF is not supported on raw sockets.
191 if routing_mode not in ["uid", "ucast_oif"]:
192 self.CheckRawGrePacket(4, netid, routing_mode, v4addr)
193 self.CheckRawGrePacket(6, netid, routing_mode, v6addr)
195 def testMarkRouting(self):
196 """Checks that socket marking selects the right outgoing interface."""
197 self.CheckOutgoingPackets("mark")
199 @unittest.skipUnless(multinetwork_base.HAVE_UID_ROUTING, "no UID routes")
200 def testUidRouting(self):
201 """Checks that UID routing selects the right outgoing interface."""
202 self.CheckOutgoingPackets("uid")
204 def testOifRouting(self):
205 """Checks that oif routing selects the right outgoing interface."""
206 self.CheckOutgoingPackets("oif")
208 @unittest.skipUnless(HAVE_UNICAST_IF, "no support for UNICAST_IF")
209 def testUcastOifRouting(self):
210 """Checks that ucast oif routing selects the right outgoing interface."""
211 self.CheckOutgoingPackets("ucast_oif")
213 def CheckRemarking(self, version, use_connect):
214 # Remarking or resetting UNICAST_IF on connected sockets does not work.
218 modes = ["mark", "oif"]
220 modes += ["ucast_oif"]
223 s = net_test.UDPSocket(self.GetProtocolFamily(version))
225 # Figure out what packets to expect.
226 unspec = {4: "0.0.0.0", 6: "::"}[version]
227 sport = packets.RandomPort()
228 s.bind((unspec, sport))
229 dstaddr = {4: self.IPV4_ADDR, 6: self.IPV6_ADDR}[version]
230 desc, expected = packets.UDP(version, unspec, dstaddr, sport)
232 # If we're testing connected sockets, connect the socket on the first
235 netid = self.tuns.keys()[0]
236 self.SelectInterface(s, netid, mode)
237 s.connect((dstaddr, 53))
238 expected.src = self.MyAddress(version, netid)
240 # For each netid, select that network without closing the socket, and
241 # check that the packets sent on that socket go out on the right network.
242 for netid in self.tuns:
243 self.SelectInterface(s, netid, mode)
245 expected.src = self.MyAddress(version, netid)
246 s.sendto(UDP_PAYLOAD, (dstaddr, 53))
247 connected_str = "Connected" if use_connect else "Unconnected"
248 msg = "%s UDPv%d socket remarked using %s: expecting %s on %s" % (
249 connected_str, version, mode, desc, self.GetInterfaceName(netid))
250 self.ExpectPacketOn(netid, msg, expected)
251 self.SelectInterface(s, None, mode)
253 def testIPv4Remarking(self):
254 """Checks that updating the mark on an IPv4 socket changes routing."""
255 self.CheckRemarking(4, False)
256 self.CheckRemarking(4, True)
258 def testIPv6Remarking(self):
259 """Checks that updating the mark on an IPv6 socket changes routing."""
260 self.CheckRemarking(6, False)
261 self.CheckRemarking(6, True)
263 def testIPv6StickyPktinfo(self):
264 for _ in xrange(self.ITERATIONS):
265 for netid in self.tuns:
266 s = net_test.UDPSocket(AF_INET6)
269 net_test.SetFlowLabel(s, net_test.IPV6_ADDR, 0xdead)
270 s.setsockopt(net_test.SOL_IPV6, net_test.IPV6_FLOWINFO_SEND, 1)
272 # Set some destination options.
273 nonce = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c"
275 "\x11\x02", # Next header=UDP, 24 bytes of options.
276 "\x01\x06", "\x00" * 6, # PadN, 6 bytes of padding.
277 "\x8b\x0c", # ILNP nonce, 12 bytes.
280 s.setsockopt(net_test.SOL_IPV6, IPV6_DSTOPTS, dstopts)
281 s.setsockopt(net_test.SOL_IPV6, IPV6_UNICAST_HOPS, 255)
283 pktinfo = multinetwork_base.MakePktInfo(6, None, self.ifindices[netid])
285 # Set the sticky pktinfo option.
286 s.setsockopt(net_test.SOL_IPV6, IPV6_PKTINFO, pktinfo)
288 # Specify the flowlabel in the destination address.
289 s.sendto(UDP_PAYLOAD, (net_test.IPV6_ADDR, 53, 0xdead, 0))
291 sport = s.getsockname()[1]
292 srcaddr = self.MyAddress(6, netid)
293 expected = (scapy.IPv6(src=srcaddr, dst=net_test.IPV6_ADDR,
294 fl=0xdead, hlim=255) /
295 scapy.IPv6ExtHdrDestOpt(
296 options=[scapy.PadN(optdata="\x00\x00\x00\x00\x00\x00"),
297 scapy.HBHOptUnknown(otype=0x8b,
299 scapy.UDP(sport=sport, dport=53) /
301 msg = "IPv6 UDP using sticky pktinfo: expected UDP packet on %s" % (
302 self.GetInterfaceName(netid))
303 self.ExpectPacketOn(netid, msg, expected)
305 def CheckPktinfoRouting(self, version):
306 for _ in xrange(self.ITERATIONS):
307 for netid in self.tuns:
308 family = self.GetProtocolFamily(version)
309 s = net_test.UDPSocket(family)
312 # Create a flowlabel so we can use it.
313 net_test.SetFlowLabel(s, net_test.IPV6_ADDR, 0xbeef)
315 # Specify some arbitrary options.
317 (net_test.SOL_IPV6, IPV6_HOPLIMIT, 39),
318 (net_test.SOL_IPV6, IPV6_TCLASS, 0x83),
319 (net_test.SOL_IPV6, IPV6_FLOWINFO, int(htonl(0xbeef))),
322 # Support for setting IPv4 TOS and TTL via cmsg only appeared in 3.13.
324 s.setsockopt(net_test.SOL_IP, IP_TTL, 39)
325 s.setsockopt(net_test.SOL_IP, IP_TOS, 0x83)
327 dstaddr = self.GetRemoteAddress(version)
328 self.SendOnNetid(version, s, dstaddr, 53, netid, UDP_PAYLOAD, cmsgs)
330 sport = s.getsockname()[1]
331 srcaddr = self.MyAddress(version, netid)
333 desc, expected = packets.UDPWithOptions(version, srcaddr, dstaddr,
336 msg = "IPv%d UDP using pktinfo routing: expected %s on %s" % (
337 version, desc, self.GetInterfaceName(netid))
338 self.ExpectPacketOn(netid, msg, expected)
340 def testIPv4PktinfoRouting(self):
341 self.CheckPktinfoRouting(4)
343 def testIPv6PktinfoRouting(self):
344 self.CheckPktinfoRouting(6)
347 class MarkTest(InboundMarkingTest):
349 def CheckReflection(self, version, gen_packet, gen_reply):
350 """Checks that replies go out on the same interface as the original.
352 For each combination:
353 - Calls gen_packet to generate a packet to that IP address.
354 - Writes the packet generated by gen_packet on the given tun
355 interface, causing the kernel to receive it.
356 - Checks that the kernel's reply matches the packet generated by
360 version: An integer, 4 or 6.
361 gen_packet: A function taking an IP version (an integer), a source
362 address and a destination address (strings), and returning a scapy
364 gen_reply: A function taking the same arguments as gen_packet,
365 plus a scapy packet, and returning a scapy packet.
367 for netid, iif, ip_if, myaddr, remoteaddr in self.Combinations(version):
368 # Generate a test packet.
369 desc, packet = gen_packet(version, remoteaddr, myaddr)
371 # Test with mark reflection enabled and disabled.
372 for reflect in [0, 1]:
373 self.SetMarkReflectSysctls(reflect)
374 # HACK: IPv6 ping replies always do a routing lookup with the
375 # interface the ping came in on. So even if mark reflection is not
376 # working, IPv6 ping replies will be properly reflected. Don't
377 # fail when that happens.
378 if reflect or desc == "ICMPv6 echo":
379 reply_desc, reply = gen_reply(version, myaddr, remoteaddr, packet)
381 reply_desc, reply = None, None
383 msg = self._FormatMessage(iif, ip_if, "reflect=%d" % reflect,
385 self._ReceiveAndExpectResponse(netid, packet, reply, msg)
387 def SYNToClosedPort(self, *args):
388 return packets.SYN(999, *args)
390 def testIPv4ICMPErrorsReflectMark(self):
391 self.CheckReflection(4, packets.UDP, packets.ICMPPortUnreachable)
393 def testIPv6ICMPErrorsReflectMark(self):
394 self.CheckReflection(6, packets.UDP, packets.ICMPPortUnreachable)
396 def testIPv4PingRepliesReflectMarkAndTos(self):
397 self.CheckReflection(4, packets.ICMPEcho, packets.ICMPReply)
399 def testIPv6PingRepliesReflectMarkAndTos(self):
400 self.CheckReflection(6, packets.ICMPEcho, packets.ICMPReply)
402 def testIPv4RSTsReflectMark(self):
403 self.CheckReflection(4, self.SYNToClosedPort, packets.RST)
405 def testIPv6RSTsReflectMark(self):
406 self.CheckReflection(6, self.SYNToClosedPort, packets.RST)
409 class TCPAcceptTest(InboundMarkingTest):
411 MODE_BINDTODEVICE = "SO_BINDTODEVICE"
412 MODE_INCOMING_MARK = "incoming mark"
413 MODE_EXPLICIT_MARK = "explicit mark"
418 super(TCPAcceptTest, cls).setUpClass()
420 # Open a port so we can observe SYN+ACKs. Since it's a dual-stack socket it
421 # will accept both IPv4 and IPv6 connections. We do this here instead of in
422 # each test so we can use the same socket every time. That way, if a kernel
423 # bug causes incoming packets to mark the listening socket instead of the
424 # accepted socket, the test will fail as soon as the next address/interface
425 # combination is tried.
426 cls.listenport = 1234
427 cls.listensocket = net_test.IPv6TCPSocket()
428 cls.listensocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
429 cls.listensocket.bind(("::", cls.listenport))
430 cls.listensocket.listen(100)
432 def BounceSocket(self, s):
433 """Attempts to invalidate a socket's destination cache entry."""
434 if s.family == AF_INET:
435 tos = s.getsockopt(SOL_IP, IP_TOS)
436 s.setsockopt(net_test.SOL_IP, IP_TOS, 53)
437 s.setsockopt(net_test.SOL_IP, IP_TOS, tos)
439 # UDP, 8 bytes dstopts; PAD1, 4 bytes padding; 4 bytes zeros.
440 pad8 = "".join(["\x11\x00", "\x01\x04", "\x00" * 4])
441 s.setsockopt(net_test.SOL_IPV6, IPV6_DSTOPTS, pad8)
442 s.setsockopt(net_test.SOL_IPV6, IPV6_DSTOPTS, "")
444 def _SetTCPMarkAcceptSysctl(self, value):
445 self.SetSysctl(TCP_MARK_ACCEPT_SYSCTL, value)
447 def CheckTCPConnection(self, mode, listensocket, netid, version,
448 myaddr, remoteaddr, packet, reply, msg):
449 establishing_ack = packets.ACK(version, remoteaddr, myaddr, reply)[1]
451 # Attempt to confuse the kernel.
452 self.BounceSocket(listensocket)
454 self.ReceivePacketOn(netid, establishing_ack)
456 # If we're using UID routing, the accept() call has to be run as a UID that
457 # is routed to the specified netid, because the UID of the socket returned
458 # by accept() is the effective UID of the process that calls it. It doesn't
459 # need to be the same UID; any UID that selects the same interface will do.
460 with net_test.RunAsUid(self.UidForNetid(netid)):
461 s, _ = listensocket.accept()
464 # Check that data sent on the connection goes out on the right interface.
465 desc, data = packets.ACK(version, myaddr, remoteaddr, establishing_ack,
468 self.ExpectPacketOn(netid, msg + ": expecting %s" % desc, data)
471 # Keep up our end of the conversation.
472 ack = packets.ACK(version, remoteaddr, myaddr, data)[1]
473 self.BounceSocket(listensocket)
474 self.ReceivePacketOn(netid, ack)
476 mark = self.GetSocketMark(s)
481 if mode == self.MODE_INCOMING_MARK:
482 self.assertEquals(netid, mark,
483 msg + ": Accepted socket: Expected mark %d, got %d" % (
485 elif mode != self.MODE_EXPLICIT_MARK:
486 self.assertEquals(0, self.GetSocketMark(listensocket))
488 # Check the FIN was sent on the right interface, and ack it. We don't expect
489 # this to fail because by the time the connection is established things are
490 # likely working, but a) extra tests are always good and b) extra packets
491 # like the FIN (and retransmitted FINs) could cause later tests that expect
492 # no packets to fail.
493 desc, fin = packets.FIN(version, myaddr, remoteaddr, ack)
494 self.ExpectPacketOn(netid, msg + ": expecting %s after close" % desc, fin)
496 desc, finack = packets.FIN(version, remoteaddr, myaddr, fin)
497 self.ReceivePacketOn(netid, finack)
499 # Since we called close() earlier, the userspace socket object is gone, so
500 # the socket has no UID. If we're doing UID routing, the ack might be routed
501 # incorrectly. Not much we can do here.
502 desc, finackack = packets.ACK(version, myaddr, remoteaddr, finack)
503 if mode != self.MODE_UID:
504 self.ExpectPacketOn(netid, msg + ": expecting final ack", finackack)
506 self.ClearTunQueues()
508 def CheckTCP(self, version, modes):
509 """Checks that incoming TCP connections work.
512 version: An integer, 4 or 6.
513 modes: A list of modes to excercise.
515 for syncookies in [0, 2]:
517 for netid, iif, ip_if, myaddr, remoteaddr in self.Combinations(version):
518 if mode == self.MODE_UID:
519 listensocket = self.BuildSocket(6, net_test.TCPSocket, netid, mode)
520 listensocket.listen(100)
522 listensocket = self.listensocket
524 listenport = listensocket.getsockname()[1]
526 accept_sysctl = 1 if mode == self.MODE_INCOMING_MARK else 0
527 self._SetTCPMarkAcceptSysctl(accept_sysctl)
529 bound_dev = iif if mode == self.MODE_BINDTODEVICE else None
530 self.BindToDevice(listensocket, bound_dev)
532 mark = netid if mode == self.MODE_EXPLICIT_MARK else 0
533 self.SetSocketMark(listensocket, mark)
535 # Generate the packet here instead of in the outer loop, so
536 # subsequent TCP connections use different source ports and
537 # retransmissions from old connections don't confuse subsequent
539 desc, packet = packets.SYN(listenport, version, remoteaddr, myaddr)
542 reply_desc, reply = packets.SYNACK(version, myaddr, remoteaddr,
545 reply_desc, reply = None, None
547 extra = "mode=%s, syncookies=%d" % (mode, syncookies)
548 msg = self._FormatMessage(iif, ip_if, extra, desc, reply_desc)
549 reply = self._ReceiveAndExpectResponse(netid, packet, reply, msg)
551 self.CheckTCPConnection(mode, listensocket, netid, version, myaddr,
552 remoteaddr, packet, reply, msg)
554 def testBasicTCP(self):
555 self.CheckTCP(4, [None, self.MODE_BINDTODEVICE, self.MODE_EXPLICIT_MARK])
556 self.CheckTCP(6, [None, self.MODE_BINDTODEVICE, self.MODE_EXPLICIT_MARK])
558 def testIPv4MarkAccept(self):
559 self.CheckTCP(4, [self.MODE_INCOMING_MARK])
561 def testIPv6MarkAccept(self):
562 self.CheckTCP(6, [self.MODE_INCOMING_MARK])
564 @unittest.skipUnless(multinetwork_base.HAVE_UID_ROUTING, "no UID routes")
565 def testIPv4UidAccept(self):
566 self.CheckTCP(4, [self.MODE_UID])
568 @unittest.skipUnless(multinetwork_base.HAVE_UID_ROUTING, "no UID routes")
569 def testIPv6UidAccept(self):
570 self.CheckTCP(6, [self.MODE_UID])
572 def testIPv6ExplicitMark(self):
573 self.CheckTCP(6, [self.MODE_EXPLICIT_MARK])
576 class RATest(multinetwork_base.MultiNetworkBaseTest):
578 def testDoesNotHaveObsoleteSysctl(self):
579 self.assertFalse(os.path.isfile(
580 "/proc/sys/net/ipv6/route/autoconf_table_offset"))
582 @unittest.skipUnless(multinetwork_base.HAVE_AUTOCONF_TABLE,
583 "no support for per-table autoconf")
584 def testPurgeDefaultRouters(self):
586 def CheckIPv6Connectivity(expect_connectivity):
587 for netid in self.NETIDS:
588 s = net_test.UDPSocket(AF_INET6)
589 self.SetSocketMark(s, netid)
590 if expect_connectivity:
591 self.assertTrue(s.sendto(UDP_PAYLOAD, (net_test.IPV6_ADDR, 1234)))
593 self.assertRaisesErrno(errno.ENETUNREACH, s.sendto, UDP_PAYLOAD,
594 (net_test.IPV6_ADDR, 1234))
597 CheckIPv6Connectivity(True)
598 self.SetIPv6SysctlOnAllIfaces("accept_ra", 1)
599 self.SetSysctl("/proc/sys/net/ipv6/conf/all/forwarding", 1)
600 CheckIPv6Connectivity(False)
602 self.SetSysctl("/proc/sys/net/ipv6/conf/all/forwarding", 0)
603 for netid in self.NETIDS:
605 CheckIPv6Connectivity(True)
607 def testOnlinkCommunication(self):
608 """Checks that on-link communication goes direct and not through routers."""
609 for netid in self.tuns:
610 # Send a UDP packet to a random on-link destination.
611 s = net_test.UDPSocket(AF_INET6)
612 iface = self.GetInterfaceName(netid)
613 self.BindToDevice(s, iface)
614 # dstaddr can never be our address because GetRandomDestination only fills
615 # in the lower 32 bits, but our address has 0xff in the byte before that
616 # (since it's constructed from the EUI-64 and so has ff:fe in the middle).
617 dstaddr = self.GetRandomDestination(self.IPv6Prefix(netid))
618 s.sendto(UDP_PAYLOAD, (dstaddr, 53))
620 # Expect an NS for that destination on the interface.
621 myaddr = self.MyAddress(6, netid)
622 mymac = self.MyMacAddress(netid)
623 desc, expected = packets.NS(myaddr, dstaddr, mymac)
624 msg = "Sending UDP packet to on-link destination: expecting %s" % desc
625 time.sleep(0.0001) # Required to make the test work on kernel 3.1(!)
626 self.ExpectPacketOn(netid, msg, expected)
629 tgtmac = "02:00:00:00:%02x:99" % netid
630 _, reply = packets.NA(dstaddr, myaddr, tgtmac)
631 # Don't use ReceivePacketOn, since that uses the router's MAC address as
632 # the source. Instead, construct our own Ethernet header with source
634 reply = scapy.Ether(src=tgtmac, dst=mymac) / reply
635 self.ReceiveEtherPacketOn(netid, reply)
637 # Expect the kernel to send the original UDP packet now that the ND cache
638 # entry has been populated.
639 sport = s.getsockname()[1]
640 desc, expected = packets.UDP(6, myaddr, dstaddr, sport=sport)
641 msg = "After NA response, expecting %s" % desc
642 self.ExpectPacketOn(netid, msg, expected)
644 # This test documents a known issue: routing tables are never deleted.
645 @unittest.skipUnless(multinetwork_base.HAVE_AUTOCONF_TABLE,
646 "no support for per-table autoconf")
647 def testLeftoverRoutes(self):
649 return len(open("/proc/net/ipv6_route").readlines())
651 num_routes = GetNumRoutes()
652 for i in xrange(10, 20):
654 self.tuns[i] = self.CreateTunInterface(i)
659 self.assertLess(num_routes, GetNumRoutes())
662 class PMTUTest(InboundMarkingTest):
666 # Socket options to change PMTU behaviour.
671 # Socket options to get the MTU.
675 def GetSocketMTU(self, version, s):
677 ip6_mtuinfo = s.getsockopt(net_test.SOL_IPV6, self.IPV6_PATHMTU, 32)
678 unused_sockaddr, mtu = struct.unpack("=28sI", ip6_mtuinfo)
681 return s.getsockopt(net_test.SOL_IP, self.IP_MTU)
683 def DisableFragmentationAndReportErrors(self, version, s):
685 s.setsockopt(net_test.SOL_IP, self.IP_MTU_DISCOVER, self.IP_PMTUDISC_DO)
686 s.setsockopt(net_test.SOL_IP, net_test.IP_RECVERR, 1)
688 s.setsockopt(net_test.SOL_IPV6, self.IPV6_DONTFRAG, 1)
689 s.setsockopt(net_test.SOL_IPV6, net_test.IPV6_RECVERR, 1)
691 def CheckPMTU(self, version, use_connect, modes):
693 def SendBigPacket(version, s, dstaddr, netid, payload):
697 self.SendOnNetid(version, s, dstaddr, 1234, netid, payload, [])
699 for netid in self.tuns:
701 s = self.BuildSocket(version, net_test.UDPSocket, netid, mode)
702 self.DisableFragmentationAndReportErrors(version, s)
704 srcaddr = self.MyAddress(version, netid)
705 dst_prefix, intermediate = {
706 4: ("172.19.", "172.16.9.12"),
707 6: ("2001:db8::", "2001:db8::1")
709 dstaddr = self.GetRandomDestination(dst_prefix)
712 s.connect((dstaddr, 1234))
714 payload = self.PAYLOAD_SIZE * "a"
716 # Send a packet and receive a packet too big.
717 SendBigPacket(version, s, dstaddr, netid, payload)
718 received = self.ReadAllPacketsOn(netid)
719 self.assertEquals(1, len(received))
720 _, toobig = packets.ICMPPacketTooBig(version, intermediate, srcaddr,
722 self.ReceivePacketOn(netid, toobig)
724 # Check that another send on the same socket returns EMSGSIZE.
725 self.assertRaisesErrno(
727 SendBigPacket, version, s, dstaddr, netid, payload)
729 # If this is a connected socket, make sure the socket MTU was set.
730 # Note that in IPv4 this only started working in Linux 3.6!
731 if use_connect and (version == 6 or net_test.LINUX_VERSION >= (3, 6)):
732 self.assertEquals(1280, self.GetSocketMTU(version, s))
736 # Check that other sockets pick up the PMTU we have been told about by
737 # connecting another socket to the same destination and getting its MTU.
738 # This new socket can use any method to select its outgoing interface;
739 # here we use a mark for simplicity.
740 s2 = self.BuildSocket(version, net_test.UDPSocket, netid, "mark")
741 s2.connect((dstaddr, 1234))
742 self.assertEquals(1280, self.GetSocketMTU(version, s2))
744 # Also check the MTU reported by ip route get, this time using the oif.
745 routes = self.iproute.GetRoutes(dstaddr, self.ifindices[netid], 0, None)
746 self.assertTrue(routes)
748 rtmsg, attributes = route
749 self.assertEquals(iproute.RTN_UNICAST, rtmsg.type)
750 metrics = attributes["RTA_METRICS"]
751 self.assertEquals(metrics["RTAX_MTU"], 1280)
753 def testIPv4BasicPMTU(self):
754 """Tests IPv4 path MTU discovery.
756 Relevant kernel commits:
758 6a66271 ipv4, fib: pass LOOPBACK_IFINDEX instead of 0 to flowi4_iif
761 4bc64dd ipv4, fib: pass LOOPBACK_IFINDEX instead of 0 to flowi4_iif
764 self.CheckPMTU(4, True, ["mark", "oif"])
765 self.CheckPMTU(4, False, ["mark", "oif"])
767 def testIPv6BasicPMTU(self):
768 self.CheckPMTU(6, True, ["mark", "oif"])
769 self.CheckPMTU(6, False, ["mark", "oif"])
771 @unittest.skipUnless(multinetwork_base.HAVE_UID_ROUTING, "no UID routes")
772 def testIPv4UIDPMTU(self):
773 self.CheckPMTU(4, True, ["uid"])
774 self.CheckPMTU(4, False, ["uid"])
776 @unittest.skipUnless(multinetwork_base.HAVE_UID_ROUTING, "no UID routes")
777 def testIPv6UIDPMTU(self):
778 self.CheckPMTU(6, True, ["uid"])
779 self.CheckPMTU(6, False, ["uid"])
781 # Making Path MTU Discovery work on unmarked sockets requires that mark
782 # reflection be enabled. Otherwise the kernel has no way to know what routing
783 # table the original packet used, and thus it won't be able to clone the
786 def testIPv4UnmarkedSocketPMTU(self):
787 self.SetMarkReflectSysctls(1)
789 self.CheckPMTU(4, False, [None])
791 self.SetMarkReflectSysctls(0)
793 def testIPv6UnmarkedSocketPMTU(self):
794 self.SetMarkReflectSysctls(1)
796 self.CheckPMTU(6, False, [None])
798 self.SetMarkReflectSysctls(0)
801 @unittest.skipUnless(multinetwork_base.HAVE_UID_ROUTING, "no UID routes")
802 class UidRoutingTest(multinetwork_base.MultiNetworkBaseTest):
803 """Tests that per-UID routing works properly.
805 Relevant kernel commits:
807 0b42874 net: core: Support UID-based routing.
808 0836a0c Handle 'sk' being NULL in UID-based routing.
811 99a6ea4 net: core: Support UID-based routing.
812 455b09d Handle 'sk' being NULL in UID-based routing.
815 def GetRulesAtPriority(self, version, priority):
816 rules = self.iproute.DumpRules(version)
817 out = [(rule, attributes) for rule, attributes in rules
818 if attributes.get("FRA_PRIORITY", 0) == priority]
821 def CheckInitialTablesHaveNoUIDs(self, version):
823 for priority in [0, 32766, 32767]:
824 rules.extend(self.GetRulesAtPriority(version, priority))
825 for _, attributes in rules:
826 self.assertNotIn("FRA_UID_START", attributes)
827 self.assertNotIn("FRA_UID_END", attributes)
829 def testIPv4InitialTablesHaveNoUIDs(self):
830 self.CheckInitialTablesHaveNoUIDs(4)
832 def testIPv6InitialTablesHaveNoUIDs(self):
833 self.CheckInitialTablesHaveNoUIDs(6)
835 def CheckGetAndSetRules(self, version):
837 return random.randint(1000000, 2000000)
839 start, end = tuple(sorted([Random(), Random()]))
844 self.iproute.UidRangeRule(version, True, start, end, table,
847 rules = self.GetRulesAtPriority(version, priority)
848 self.assertTrue(rules)
849 _, attributes = rules[-1]
850 self.assertEquals(priority, attributes["FRA_PRIORITY"])
851 self.assertEquals(start, attributes["FRA_UID_START"])
852 self.assertEquals(end, attributes["FRA_UID_END"])
853 self.assertEquals(table, attributes["FRA_TABLE"])
855 self.iproute.UidRangeRule(version, False, start, end, table,
858 def testIPv4GetAndSetRules(self):
859 self.CheckGetAndSetRules(4)
861 def testIPv6GetAndSetRules(self):
862 self.CheckGetAndSetRules(6)
864 def ExpectNoRoute(self, addr, oif, mark, uid):
865 # The lack of a route may be either an error, or an unreachable route.
867 routes = self.iproute.GetRoutes(addr, oif, mark, uid)
869 self.assertEquals(iproute.RTN_UNREACHABLE, rtmsg.type)
871 if int(e.errno) != -int(errno.ENETUNREACH):
874 def ExpectRoute(self, addr, oif, mark, uid):
875 routes = self.iproute.GetRoutes(addr, oif, mark, uid)
877 self.assertEquals(iproute.RTN_UNICAST, rtmsg.type)
879 def CheckGetRoute(self, version, addr):
880 self.ExpectNoRoute(addr, 0, 0, 0)
881 for netid in self.NETIDS:
882 uid = self.UidForNetid(netid)
883 self.ExpectRoute(addr, 0, 0, uid)
884 self.ExpectNoRoute(addr, 0, 0, 0)
886 def testIPv4RouteGet(self):
887 self.CheckGetRoute(4, net_test.IPV4_ADDR)
889 def testIPv6RouteGet(self):
890 self.CheckGetRoute(6, net_test.IPV6_ADDR)
893 class RulesTest(net_test.NetworkTest):
895 RULE_PRIORITY = 99999
898 self.iproute = iproute.IPRoute()
899 for version in [4, 6]:
900 self.iproute.DeleteRulesAtPriority(version, self.RULE_PRIORITY)
903 for version in [4, 6]:
904 self.iproute.DeleteRulesAtPriority(version, self.RULE_PRIORITY)
906 def testRuleDeletionMatchesTable(self):
907 for version in [4, 6]:
908 # Add rules with mark 300 pointing at tables 301 and 302.
909 # This checks for a kernel bug where deletion request for tables > 256
911 self.iproute.FwmarkRule(version, True, 300, 301,
912 priority=self.RULE_PRIORITY)
913 self.iproute.FwmarkRule(version, True, 300, 302,
914 priority=self.RULE_PRIORITY)
915 # Delete rule with mark 300 pointing at table 302.
916 self.iproute.FwmarkRule(version, False, 300, 302,
917 priority=self.RULE_PRIORITY)
918 # Check that the rule pointing at table 301 is still around.
919 attributes = [a for _, a in self.iproute.DumpRules(version)
920 if a.get("FRA_PRIORITY", 0) == self.RULE_PRIORITY]
921 self.assertEquals(1, len(attributes))
922 self.assertEquals(301, attributes[0]["FRA_TABLE"])
925 class TcpTest(multinetwork_base.MultiNetworkBaseTest):
930 # Pick an interface to send traffic on and two to forward traffic between.
931 self.netid, self.iface1, self.iface2 = random.sample(self.tuns.keys(), 3)
932 for netid in self.tuns:
933 iface = self.GetInterfaceName(netid)
934 self.SetSysctl("/proc/sys/net/ipv6/conf/%s/accept_ra" % iface, 2)
935 self.SetSysctl("/proc/sys/net/ipv6/conf/all/forwarding", 1)
936 self.iproute.IifRule(6, True,
937 self.GetInterfaceName(self.iface1),
938 self._TableForNetid(self.iface2), self.PRIORITY_IIF)
941 for netid in self.tuns:
942 iface = self.GetInterfaceName(netid)
943 self.SetSysctl("/proc/sys/net/ipv6/conf/%s/accept_ra" % iface, 0)
944 self.SetSysctl("/proc/sys/net/ipv6/conf/all/forwarding", 0)
945 self.iproute.IifRule(6, False,
946 self.GetInterfaceName(self.iface1),
947 self._TableForNetid(self.iface2), self.PRIORITY_IIF)
950 listenport = packets.RandomPort()
951 self.listensocket = net_test.IPv6TCPSocket()
952 self.listensocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
953 self.listensocket.bind(("::", listenport))
954 self.listensocket.listen(100)
955 self.SetSocketMark(self.listensocket, self.netid)
958 remoteaddr = self.GetRemoteAddress(version)
959 myaddr = self.MyAddress(version, self.netid)
961 desc, syn = packets.SYN(listenport, version, remoteaddr, myaddr)
962 synack_desc, synack = packets.SYNACK(version, myaddr, remoteaddr, syn)
963 msg = "Sent %s, expected %s" % (desc, synack_desc)
964 reply = self._ReceiveAndExpectResponse(self.netid, syn, synack, msg)
966 establishing_ack = packets.ACK(version, remoteaddr, myaddr, reply)[1]
967 self.ReceivePacketOn(self.netid, establishing_ack)
968 accepted, peer = self.listensocket.accept()
969 remoteport = accepted.getpeername()[1]
972 desc, fin = packets.FIN(version, myaddr, remoteaddr, establishing_ack)
973 self.ExpectPacketOn(self.netid, msg + ": expecting %s after close" % desc, fin)
975 desc, finack = packets.FIN(version, remoteaddr, myaddr, fin)
976 self.ReceivePacketOn(self.netid, finack)
978 # Check our socket is now in TIME_WAIT.
979 sockets = self.ReadProcNetSocket("tcp6")
980 mysrc = "%s:%04X" % (net_test.FormatSockStatAddress(myaddr), listenport)
981 mydst = "%s:%04X" % (net_test.FormatSockStatAddress(remoteaddr), remoteport)
983 sockets = [s for s in sockets if s[0] == mysrc and s[1] == mydst]
984 self.assertEquals(1, len(sockets))
985 self.assertEquals("%02X" % self.TCP_TIME_WAIT, sockets[0][2])
987 # Remove our IP address.
988 self.iproute.DelAddress(myaddr, 64, self.ifindices[self.netid])
990 self.ReceivePacketOn(self.iface1, finack)
991 self.ReceivePacketOn(self.iface1, establishing_ack)
992 self.ReceivePacketOn(self.iface1, establishing_ack)
996 if __name__ == "__main__":