blob: 34394cd46a062bcdc6a01b7d8c47eb6180560ce1 [file] [log] [blame]
Lorenzo Colitti03e8e542015-10-28 17:50:04 +09001#!/usr/bin/python
2#
3# Copyright 2015 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 itertools
18import random
19import unittest
20
21from socket import *
22
Lorenzo Colitti03e8e542015-10-28 17:50:04 +090023import multinetwork_base
24import net_test
25import packets
26
Lorenzo Colitti03e8e542015-10-28 17:50:04 +090027class ForwardingTest(multinetwork_base.MultiNetworkBaseTest):
Lorenzo Colitti03e8e542015-10-28 17:50:04 +090028 TCP_TIME_WAIT = 6
29
30 def ForwardBetweenInterfaces(self, enabled, iface1, iface2):
31 for iif, oif in itertools.permutations([iface1, iface2]):
32 self.iproute.IifRule(6, enabled, self.GetInterfaceName(iif),
33 self._TableForNetid(oif), self.PRIORITY_IIF)
34
35 def setUp(self):
36 self.SetSysctl("/proc/sys/net/ipv6/conf/all/forwarding", 1)
37
38 def tearDown(self):
39 self.SetSysctl("/proc/sys/net/ipv6/conf/all/forwarding", 0)
40
Subash Abhinov Kasiviswanathand6cdfeb2017-07-07 17:05:42 -060041 """Checks that IPv6 forwarding works for UDP packets and is not broken by early demux.
42
43 Relevant kernel commits:
44 upstream:
45 5425077d73e0c8e net: ipv6: Add early demux handler for UDP unicast
46 0bd84065b19bca1 net: ipv6: Fix UDP early demux lookup with udp_l3mdev_accept=0
47 Ifa9c2ddfaa5b51 net: ipv6: reset daddr and dport in sk if connect() fails
48 """
49 def CheckForwardingUdp(self, netid, iface1, iface2):
50 # TODO: Make a test for IPv4
51 # 1. Make version as an argument. Pick address to bind from array based
52 # on version.
53 # 2. The prefix length of the address is hardcoded to /64. Use the subnet
54 # mask there instead.
55 # 3. We recreate the address with SendRA, which obviously only works for
56 # IPv6. Use AddAddress for IPv4.
57
58 # Create a UDP socket and bind to it
59 version = 6
60 s = net_test.UDPSocket(AF_INET6)
61 self.SetSocketMark(s, netid)
62 s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
63 s.bind(("::", 53))
64
65 remoteaddr = self.GetRemoteAddress(version)
66 myaddr = self.MyAddress(version, netid)
67
68 try:
69 # Delete address and check if packet is forwarded
70 # (and not dropped because an incorrect socket match happened)
71 self.iproute.DelAddress(myaddr, 64, self.ifindices[netid])
72 hoplimit = 39
73 desc, udp_pkt = packets.UDPWithOptions(version, myaddr, remoteaddr, 53)
74 # Decrements the hoplimit of a packet to simulate forwarding.
75 desc_fwded, udp_fwd = packets.UDPWithOptions(version, myaddr, remoteaddr,
76 53, hoplimit - 1)
77 msg = "Sent %s, expected %s" % (desc, desc_fwded)
78 self.ReceivePacketOn(iface1, udp_pkt)
79 self.ExpectPacketOn(iface2, msg, udp_fwd)
80 finally:
81 # Recreate the address.
82 self.SendRA(netid)
83 s.close()
84
85 """Checks that IPv6 forwarding doesn't crash the system.
86
87 Relevant kernel commits:
88 upstream net-next:
89 e7eadb4 ipv6: inet6_sk() should use sk_fullsock()
90 android-3.10:
91 feee3c1 ipv6: inet6_sk() should use sk_fullsock()
92 cdab04e net: add sk_fullsock() helper
93 android-3.18:
94 8246f18 ipv6: inet6_sk() should use sk_fullsock()
95 bea19db net: add sk_fullsock() helper
96 """
97 def CheckForwardingCrashTcp(self, netid, iface1, iface2):
Lorenzo Colitti03e8e542015-10-28 17:50:04 +090098 version = 6
Lorenzo Colitti7e198982016-04-08 13:14:08 +090099 listensocket = net_test.IPv6TCPSocket()
100 self.SetSocketMark(listensocket, netid)
101 listenport = net_test.BindRandomPort(version, listensocket)
102
Lorenzo Colitti03e8e542015-10-28 17:50:04 +0900103 remoteaddr = self.GetRemoteAddress(version)
104 myaddr = self.MyAddress(version, netid)
105
106 desc, syn = packets.SYN(listenport, version, remoteaddr, myaddr)
107 synack_desc, synack = packets.SYNACK(version, myaddr, remoteaddr, syn)
108 msg = "Sent %s, expected %s" % (desc, synack_desc)
109 reply = self._ReceiveAndExpectResponse(netid, syn, synack, msg)
110
111 establishing_ack = packets.ACK(version, remoteaddr, myaddr, reply)[1]
112 self.ReceivePacketOn(netid, establishing_ack)
113 accepted, peer = listensocket.accept()
114 remoteport = accepted.getpeername()[1]
115
116 accepted.close()
117 desc, fin = packets.FIN(version, myaddr, remoteaddr, establishing_ack)
118 self.ExpectPacketOn(netid, msg + ": expecting %s after close" % desc, fin)
119
120 desc, finack = packets.FIN(version, remoteaddr, myaddr, fin)
121 self.ReceivePacketOn(netid, finack)
122
123 # Check our socket is now in TIME_WAIT.
124 sockets = self.ReadProcNetSocket("tcp6")
125 mysrc = "%s:%04X" % (net_test.FormatSockStatAddress(myaddr), listenport)
126 mydst = "%s:%04X" % (net_test.FormatSockStatAddress(remoteaddr), remoteport)
127 state = None
128 sockets = [s for s in sockets if s[0] == mysrc and s[1] == mydst]
129 self.assertEquals(1, len(sockets))
130 self.assertEquals("%02X" % self.TCP_TIME_WAIT, sockets[0][2])
131
132 # Remove our IP address.
133 try:
134 self.iproute.DelAddress(myaddr, 64, self.ifindices[netid])
135
136 self.ReceivePacketOn(iface1, finack)
137 self.ReceivePacketOn(iface1, establishing_ack)
138 self.ReceivePacketOn(iface1, establishing_ack)
139 # No crashes? Good.
140
141 finally:
142 # Put back our IP address.
143 self.SendRA(netid)
144 listensocket.close()
145
Subash Abhinov Kasiviswanathand6cdfeb2017-07-07 17:05:42 -0600146 def CheckForwardingHandlerByProto(self, protocol, netid, iif, oif):
147 if protocol == IPPROTO_UDP:
148 self.CheckForwardingUdp(netid, iif, oif)
149 elif protocol == IPPROTO_TCP:
150 self.CheckForwardingCrashTcp(netid, iif, oif)
151 else:
152 raise NotImplementedError
153
154 def CheckForwardingByProto(self, proto):
Lorenzo Colitti03e8e542015-10-28 17:50:04 +0900155 # Run the test a few times as it doesn't crash/hang the first time.
156 for netids in itertools.permutations(self.tuns):
157 # Pick an interface to send traffic on and two to forward traffic between.
158 netid, iface1, iface2 = random.sample(netids, 3)
159 self.ForwardBetweenInterfaces(True, iface1, iface2)
160 try:
Subash Abhinov Kasiviswanathand6cdfeb2017-07-07 17:05:42 -0600161 self.CheckForwardingHandlerByProto(proto, netid, iface1, iface2)
Lorenzo Colitti03e8e542015-10-28 17:50:04 +0900162 finally:
163 self.ForwardBetweenInterfaces(False, iface1, iface2)
164
Subash Abhinov Kasiviswanathand6cdfeb2017-07-07 17:05:42 -0600165 def testForwardingUdp(self):
166 self.CheckForwardingByProto(IPPROTO_UDP)
167
168 def testForwardingCrashTcp(self):
169 self.CheckForwardingByProto(IPPROTO_TCP)
Lorenzo Colitti03e8e542015-10-28 17:50:04 +0900170
171if __name__ == "__main__":
172 unittest.main()