blob: 87a72f974d688ab9c8609a5611989ed0c7c8c312 [file] [log] [blame]
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +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 random
18
19from scapy import all as scapy
20from socket import *
21
22import net_test
23
24TCP_FIN = 1
25TCP_SYN = 2
26TCP_RST = 4
27TCP_PSH = 8
28TCP_ACK = 16
29
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090030TCP_WINDOW = 14400
31
Lorenzo Colitti7cd46d32018-01-28 23:06:50 +090032PTB_MTU = 1280
33
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090034PING_IDENT = 0xff19
35PING_PAYLOAD = "foobarbaz"
36PING_SEQ = 3
37PING_TOS = 0x83
38
39# For brevity.
40UDP_PAYLOAD = net_test.UDP_PAYLOAD
41
42
Lorenzo Colitti7e198982016-04-08 13:14:08 +090043def _RandomPort():
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090044 return random.randint(1025, 65535)
45
46def _GetIpLayer(version):
Lorenzo Colitti1d486ca2017-12-01 21:29:51 +090047 return {4: scapy.IP, 5: scapy.IP, 6: scapy.IPv6}[version]
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090048
49def _SetPacketTos(packet, tos):
50 if isinstance(packet, scapy.IPv6):
51 packet.tc = tos
52 elif isinstance(packet, scapy.IP):
53 packet.tos = tos
54 else:
55 raise ValueError("Can't find ToS Field")
56
57def UDP(version, srcaddr, dstaddr, sport=0):
58 ip = _GetIpLayer(version)
59 # Can't just use "if sport" because None has meaning (it means unspecified).
60 if sport == 0:
Lorenzo Colitti7e198982016-04-08 13:14:08 +090061 sport = _RandomPort()
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090062 return ("UDPv%d packet" % version,
63 ip(src=srcaddr, dst=dstaddr) /
64 scapy.UDP(sport=sport, dport=53) / UDP_PAYLOAD)
65
Subash Abhinov Kasiviswanathand6cdfeb2017-07-07 17:05:42 -060066def UDPWithOptions(version, srcaddr, dstaddr, sport=0, lifetime=39):
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090067 if version == 4:
Subash Abhinov Kasiviswanathand6cdfeb2017-07-07 17:05:42 -060068 packet = (scapy.IP(src=srcaddr, dst=dstaddr, ttl=lifetime, tos=0x83) /
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090069 scapy.UDP(sport=sport, dport=53) /
70 UDP_PAYLOAD)
71 else:
72 packet = (scapy.IPv6(src=srcaddr, dst=dstaddr,
Subash Abhinov Kasiviswanathand6cdfeb2017-07-07 17:05:42 -060073 fl=0xbeef, hlim=lifetime, tc=0x83) /
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090074 scapy.UDP(sport=sport, dport=53) /
75 UDP_PAYLOAD)
76 return ("UDPv%d packet with options" % version, packet)
77
Lorenzo Colitti826405a2016-11-09 00:11:48 +090078def SYN(dport, version, srcaddr, dstaddr, sport=0, seq=-1):
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090079 ip = _GetIpLayer(version)
80 if sport == 0:
Lorenzo Colitti7e198982016-04-08 13:14:08 +090081 sport = _RandomPort()
Lorenzo Colitti826405a2016-11-09 00:11:48 +090082 if seq == -1: # Can't use None because it means unspecified.
83 seq = random.getrandbits(32)
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090084 return ("TCP SYN",
85 ip(src=srcaddr, dst=dstaddr) /
86 scapy.TCP(sport=sport, dport=dport,
87 seq=seq, ack=0,
88 flags=TCP_SYN, window=TCP_WINDOW))
89
90def RST(version, srcaddr, dstaddr, packet):
91 ip = _GetIpLayer(version)
92 original = packet.getlayer("TCP")
Lorenzo Colitti424425d2015-12-09 22:23:58 +090093 was_syn_or_fin = (original.flags & (TCP_SYN | TCP_FIN)) != 0
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090094 return ("TCP RST",
95 ip(src=srcaddr, dst=dstaddr) /
96 scapy.TCP(sport=original.dport, dport=original.sport,
Lorenzo Colitti3e8e23f2017-09-20 21:38:44 +090097 ack=original.seq + was_syn_or_fin,
98 seq=original.ack,
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090099 flags=TCP_RST | TCP_ACK, window=TCP_WINDOW))
100
101def SYNACK(version, srcaddr, dstaddr, packet):
102 ip = _GetIpLayer(version)
103 original = packet.getlayer("TCP")
104 return ("TCP SYN+ACK",
105 ip(src=srcaddr, dst=dstaddr) /
106 scapy.TCP(sport=original.dport, dport=original.sport,
107 ack=original.seq + 1, seq=None,
108 flags=TCP_SYN | TCP_ACK, window=None))
109
110def ACK(version, srcaddr, dstaddr, packet, payload=""):
111 ip = _GetIpLayer(version)
112 original = packet.getlayer("TCP")
113 was_syn_or_fin = (original.flags & (TCP_SYN | TCP_FIN)) != 0
114 ack_delta = was_syn_or_fin + len(original.payload)
115 desc = "TCP data" if payload else "TCP ACK"
116 flags = TCP_ACK | TCP_PSH if payload else TCP_ACK
117 return (desc,
118 ip(src=srcaddr, dst=dstaddr) /
119 scapy.TCP(sport=original.dport, dport=original.sport,
120 ack=original.seq + ack_delta, seq=original.ack,
121 flags=flags, window=TCP_WINDOW) /
122 payload)
123
124def FIN(version, srcaddr, dstaddr, packet):
125 ip = _GetIpLayer(version)
126 original = packet.getlayer("TCP")
Lorenzo Colitti03d23662015-11-06 16:42:06 +0900127 was_syn_or_fin = (original.flags & (TCP_SYN | TCP_FIN)) != 0
128 ack_delta = was_syn_or_fin + len(original.payload)
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +0900129 return ("TCP FIN",
130 ip(src=srcaddr, dst=dstaddr) /
131 scapy.TCP(sport=original.dport, dport=original.sport,
Lorenzo Colitti03d23662015-11-06 16:42:06 +0900132 ack=original.seq + ack_delta, seq=original.ack,
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +0900133 flags=TCP_ACK | TCP_FIN, window=TCP_WINDOW))
134
135def GRE(version, srcaddr, dstaddr, proto, packet):
136 if version == 4:
137 ip = scapy.IP(src=srcaddr, dst=dstaddr, proto=net_test.IPPROTO_GRE)
138 else:
139 ip = scapy.IPv6(src=srcaddr, dst=dstaddr, nh=net_test.IPPROTO_GRE)
140 packet = ip / scapy.GRE(proto=proto) / packet
141 return ("GRE packet", packet)
142
143def ICMPPortUnreachable(version, srcaddr, dstaddr, packet):
144 if version == 4:
145 # Linux hardcodes the ToS on ICMP errors to 0xc0 or greater because of
146 # RFC 1812 4.3.2.5 (!).
147 return ("ICMPv4 port unreachable",
148 scapy.IP(src=srcaddr, dst=dstaddr, proto=1, tos=0xc0) /
149 scapy.ICMPerror(type=3, code=3) / packet)
150 else:
151 return ("ICMPv6 port unreachable",
152 scapy.IPv6(src=srcaddr, dst=dstaddr) /
153 scapy.ICMPv6DestUnreach(code=4) / packet)
154
155def ICMPPacketTooBig(version, srcaddr, dstaddr, packet):
156 if version == 4:
Lorenzo Colitti7cd46d32018-01-28 23:06:50 +0900157 desc = "ICMPv4 fragmentation needed"
158 pkt = (scapy.IP(src=srcaddr, dst=dstaddr, proto=1) /
159 scapy.ICMPerror(type=3, code=4) / str(packet)[:64])
160 # Only newer versions of scapy understand that since RFC 1191, the last two
161 # bytes of a fragmentation needed ICMP error contain the MTU.
162 if hasattr(scapy.ICMP, "nexthopmtu"):
163 pkt[scapy.ICMPerror].nexthopmtu = PTB_MTU
164 else:
165 pkt[scapy.ICMPerror].unused = PTB_MTU
166 return desc, pkt
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +0900167 else:
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +0900168 return ("ICMPv6 Packet Too Big",
169 scapy.IPv6(src=srcaddr, dst=dstaddr) /
Lorenzo Colitti7cd46d32018-01-28 23:06:50 +0900170 scapy.ICMPv6PacketTooBig(mtu=PTB_MTU) / str(packet)[:1232])
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +0900171
172def ICMPEcho(version, srcaddr, dstaddr):
173 ip = _GetIpLayer(version)
174 icmp = {4: scapy.ICMP, 6: scapy.ICMPv6EchoRequest}[version]
175 packet = (ip(src=srcaddr, dst=dstaddr) /
176 icmp(id=PING_IDENT, seq=PING_SEQ) / PING_PAYLOAD)
177 _SetPacketTos(packet, PING_TOS)
178 return ("ICMPv%d echo" % version, packet)
179
180def ICMPReply(version, srcaddr, dstaddr, packet):
181 ip = _GetIpLayer(version)
182 # Scapy doesn't provide an ICMP echo reply constructor.
183 icmpv4_reply = lambda **kwargs: scapy.ICMP(type=0, **kwargs)
184 icmp = {4: icmpv4_reply, 6: scapy.ICMPv6EchoReply}[version]
185 packet = (ip(src=srcaddr, dst=dstaddr) /
186 icmp(id=PING_IDENT, seq=PING_SEQ) / PING_PAYLOAD)
187 # IPv6 only started copying the tclass to echo replies in 3.14.
188 if version == 4 or net_test.LINUX_VERSION >= (3, 14):
189 _SetPacketTos(packet, PING_TOS)
190 return ("ICMPv%d echo reply" % version, packet)
191
192def NS(srcaddr, tgtaddr, srcmac):
193 solicited = inet_pton(AF_INET6, tgtaddr)
194 last3bytes = tuple([ord(b) for b in solicited[-3:]])
195 solicited = "ff02::1:ff%02x:%02x%02x" % last3bytes
196 packet = (scapy.IPv6(src=srcaddr, dst=solicited) /
197 scapy.ICMPv6ND_NS(tgt=tgtaddr) /
198 scapy.ICMPv6NDOptSrcLLAddr(lladdr=srcmac))
199 return ("ICMPv6 NS", packet)
200
201def NA(srcaddr, dstaddr, srcmac):
202 packet = (scapy.IPv6(src=srcaddr, dst=dstaddr) /
203 scapy.ICMPv6ND_NA(tgt=srcaddr, R=0, S=1, O=1) /
204 scapy.ICMPv6NDOptDstLLAddr(lladdr=srcmac))
205 return ("ICMPv6 NA", packet)
206