blob: 1994742cf4c99064abe51efb06d057701efd5818 [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
30TCP_SEQ = 1692871236
31TCP_WINDOW = 14400
32
33PING_IDENT = 0xff19
34PING_PAYLOAD = "foobarbaz"
35PING_SEQ = 3
36PING_TOS = 0x83
37
38# For brevity.
39UDP_PAYLOAD = net_test.UDP_PAYLOAD
40
41
Lorenzo Colitti7e198982016-04-08 13:14:08 +090042def _RandomPort():
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090043 return random.randint(1025, 65535)
44
45def _GetIpLayer(version):
46 return {4: scapy.IP, 6: scapy.IPv6}[version]
47
48def _SetPacketTos(packet, tos):
49 if isinstance(packet, scapy.IPv6):
50 packet.tc = tos
51 elif isinstance(packet, scapy.IP):
52 packet.tos = tos
53 else:
54 raise ValueError("Can't find ToS Field")
55
56def UDP(version, srcaddr, dstaddr, sport=0):
57 ip = _GetIpLayer(version)
58 # Can't just use "if sport" because None has meaning (it means unspecified).
59 if sport == 0:
Lorenzo Colitti7e198982016-04-08 13:14:08 +090060 sport = _RandomPort()
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090061 return ("UDPv%d packet" % version,
62 ip(src=srcaddr, dst=dstaddr) /
63 scapy.UDP(sport=sport, dport=53) / UDP_PAYLOAD)
64
65def UDPWithOptions(version, srcaddr, dstaddr, sport=0):
66 if version == 4:
67 packet = (scapy.IP(src=srcaddr, dst=dstaddr, ttl=39, tos=0x83) /
68 scapy.UDP(sport=sport, dport=53) /
69 UDP_PAYLOAD)
70 else:
71 packet = (scapy.IPv6(src=srcaddr, dst=dstaddr,
72 fl=0xbeef, hlim=39, tc=0x83) /
73 scapy.UDP(sport=sport, dport=53) /
74 UDP_PAYLOAD)
75 return ("UDPv%d packet with options" % version, packet)
76
77def SYN(dport, version, srcaddr, dstaddr, sport=0, seq=TCP_SEQ):
78 ip = _GetIpLayer(version)
79 if sport == 0:
Lorenzo Colitti7e198982016-04-08 13:14:08 +090080 sport = _RandomPort()
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090081 return ("TCP SYN",
82 ip(src=srcaddr, dst=dstaddr) /
83 scapy.TCP(sport=sport, dport=dport,
84 seq=seq, ack=0,
85 flags=TCP_SYN, window=TCP_WINDOW))
86
87def RST(version, srcaddr, dstaddr, packet):
88 ip = _GetIpLayer(version)
89 original = packet.getlayer("TCP")
Lorenzo Colitti424425d2015-12-09 22:23:58 +090090 was_syn_or_fin = (original.flags & (TCP_SYN | TCP_FIN)) != 0
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090091 return ("TCP RST",
92 ip(src=srcaddr, dst=dstaddr) /
93 scapy.TCP(sport=original.dport, dport=original.sport,
Lorenzo Colitti424425d2015-12-09 22:23:58 +090094 ack=original.seq + was_syn_or_fin, seq=None,
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +090095 flags=TCP_RST | TCP_ACK, window=TCP_WINDOW))
96
97def SYNACK(version, srcaddr, dstaddr, packet):
98 ip = _GetIpLayer(version)
99 original = packet.getlayer("TCP")
100 return ("TCP SYN+ACK",
101 ip(src=srcaddr, dst=dstaddr) /
102 scapy.TCP(sport=original.dport, dport=original.sport,
103 ack=original.seq + 1, seq=None,
104 flags=TCP_SYN | TCP_ACK, window=None))
105
106def ACK(version, srcaddr, dstaddr, packet, payload=""):
107 ip = _GetIpLayer(version)
108 original = packet.getlayer("TCP")
109 was_syn_or_fin = (original.flags & (TCP_SYN | TCP_FIN)) != 0
110 ack_delta = was_syn_or_fin + len(original.payload)
111 desc = "TCP data" if payload else "TCP ACK"
112 flags = TCP_ACK | TCP_PSH if payload else TCP_ACK
113 return (desc,
114 ip(src=srcaddr, dst=dstaddr) /
115 scapy.TCP(sport=original.dport, dport=original.sport,
116 ack=original.seq + ack_delta, seq=original.ack,
117 flags=flags, window=TCP_WINDOW) /
118 payload)
119
120def FIN(version, srcaddr, dstaddr, packet):
121 ip = _GetIpLayer(version)
122 original = packet.getlayer("TCP")
Lorenzo Colitti03d23662015-11-06 16:42:06 +0900123 was_syn_or_fin = (original.flags & (TCP_SYN | TCP_FIN)) != 0
124 ack_delta = was_syn_or_fin + len(original.payload)
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +0900125 return ("TCP FIN",
126 ip(src=srcaddr, dst=dstaddr) /
127 scapy.TCP(sport=original.dport, dport=original.sport,
Lorenzo Colitti03d23662015-11-06 16:42:06 +0900128 ack=original.seq + ack_delta, seq=original.ack,
Lorenzo Colitti3e6c2d92015-10-28 16:56:12 +0900129 flags=TCP_ACK | TCP_FIN, window=TCP_WINDOW))
130
131def GRE(version, srcaddr, dstaddr, proto, packet):
132 if version == 4:
133 ip = scapy.IP(src=srcaddr, dst=dstaddr, proto=net_test.IPPROTO_GRE)
134 else:
135 ip = scapy.IPv6(src=srcaddr, dst=dstaddr, nh=net_test.IPPROTO_GRE)
136 packet = ip / scapy.GRE(proto=proto) / packet
137 return ("GRE packet", packet)
138
139def ICMPPortUnreachable(version, srcaddr, dstaddr, packet):
140 if version == 4:
141 # Linux hardcodes the ToS on ICMP errors to 0xc0 or greater because of
142 # RFC 1812 4.3.2.5 (!).
143 return ("ICMPv4 port unreachable",
144 scapy.IP(src=srcaddr, dst=dstaddr, proto=1, tos=0xc0) /
145 scapy.ICMPerror(type=3, code=3) / packet)
146 else:
147 return ("ICMPv6 port unreachable",
148 scapy.IPv6(src=srcaddr, dst=dstaddr) /
149 scapy.ICMPv6DestUnreach(code=4) / packet)
150
151def ICMPPacketTooBig(version, srcaddr, dstaddr, packet):
152 if version == 4:
153 return ("ICMPv4 fragmentation needed",
154 scapy.IP(src=srcaddr, dst=dstaddr, proto=1) /
155 scapy.ICMPerror(type=3, code=4, unused=1280) / str(packet)[:64])
156 else:
157 udp = packet.getlayer("UDP")
158 udp.payload = str(udp.payload)[:1280-40-8]
159 return ("ICMPv6 Packet Too Big",
160 scapy.IPv6(src=srcaddr, dst=dstaddr) /
161 scapy.ICMPv6PacketTooBig() / str(packet)[:1232])
162
163def ICMPEcho(version, srcaddr, dstaddr):
164 ip = _GetIpLayer(version)
165 icmp = {4: scapy.ICMP, 6: scapy.ICMPv6EchoRequest}[version]
166 packet = (ip(src=srcaddr, dst=dstaddr) /
167 icmp(id=PING_IDENT, seq=PING_SEQ) / PING_PAYLOAD)
168 _SetPacketTos(packet, PING_TOS)
169 return ("ICMPv%d echo" % version, packet)
170
171def ICMPReply(version, srcaddr, dstaddr, packet):
172 ip = _GetIpLayer(version)
173 # Scapy doesn't provide an ICMP echo reply constructor.
174 icmpv4_reply = lambda **kwargs: scapy.ICMP(type=0, **kwargs)
175 icmp = {4: icmpv4_reply, 6: scapy.ICMPv6EchoReply}[version]
176 packet = (ip(src=srcaddr, dst=dstaddr) /
177 icmp(id=PING_IDENT, seq=PING_SEQ) / PING_PAYLOAD)
178 # IPv6 only started copying the tclass to echo replies in 3.14.
179 if version == 4 or net_test.LINUX_VERSION >= (3, 14):
180 _SetPacketTos(packet, PING_TOS)
181 return ("ICMPv%d echo reply" % version, packet)
182
183def NS(srcaddr, tgtaddr, srcmac):
184 solicited = inet_pton(AF_INET6, tgtaddr)
185 last3bytes = tuple([ord(b) for b in solicited[-3:]])
186 solicited = "ff02::1:ff%02x:%02x%02x" % last3bytes
187 packet = (scapy.IPv6(src=srcaddr, dst=solicited) /
188 scapy.ICMPv6ND_NS(tgt=tgtaddr) /
189 scapy.ICMPv6NDOptSrcLLAddr(lladdr=srcmac))
190 return ("ICMPv6 NS", packet)
191
192def NA(srcaddr, dstaddr, srcmac):
193 packet = (scapy.IPv6(src=srcaddr, dst=dstaddr) /
194 scapy.ICMPv6ND_NA(tgt=srcaddr, R=0, S=1, O=1) /
195 scapy.ICMPv6NDOptDstLLAddr(lladdr=srcmac))
196 return ("ICMPv6 NA", packet)
197