]>
Commit | Line | Data |
---|---|---|
1ca0323e | 1 | #! /usr/bin/env python3 |
3b1101d2 BP |
2 | |
3 | # Copyright (c) 2009, 2010, 2011, 2012, 2015, 2017 Nicira, Inc. | |
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 | ||
3b1101d2 BP |
17 | import socket |
18 | import struct | |
19 | ||
20 | ||
21 | def pack_ethaddr(ea): | |
22 | octets = ea.split(':') | |
23 | assert len(octets) == 6 | |
24 | return b''.join([struct.pack('B', int(octet, 16)) for octet in octets]) | |
25 | ||
26 | ||
27 | def output(attrs): | |
28 | # Compose flow. | |
29 | ||
30 | flow = {} | |
31 | flow['DL_SRC'] = "00:02:e3:0f:80:a4" | |
32 | flow['DL_DST'] = "00:1a:92:40:ac:05" | |
33 | flow['NW_PROTO'] = 0 | |
34 | flow['NW_TOS'] = 0 | |
35 | flow['NW_SRC'] = '0.0.0.0' | |
36 | flow['NW_DST'] = '0.0.0.0' | |
37 | flow['TP_SRC'] = 0 | |
38 | flow['TP_DST'] = 0 | |
39 | if 'DL_VLAN' in attrs: | |
40 | flow['DL_VLAN'] = {'none': 0xffff, | |
41 | 'zero': 0, | |
42 | 'nonzero': 0x0123}[attrs['DL_VLAN']] | |
43 | else: | |
44 | flow['DL_VLAN'] = 0xffff # OFP_VLAN_NONE | |
45 | if attrs['DL_HEADER'] == '802.2': | |
46 | flow['DL_TYPE'] = 0x5ff # OFP_DL_TYPE_NOT_ETH_TYPE | |
47 | elif attrs['DL_TYPE'] == 'ip': | |
48 | flow['DL_TYPE'] = 0x0800 # ETH_TYPE_IP | |
49 | flow['NW_SRC'] = '10.0.2.15' | |
50 | flow['NW_DST'] = '192.168.1.20' | |
51 | flow['NW_TOS'] = 44 | |
52 | if attrs['TP_PROTO'] == 'other': | |
53 | flow['NW_PROTO'] = 42 | |
54 | elif attrs['TP_PROTO'] in ('TCP', 'TCP+options'): | |
55 | flow['NW_PROTO'] = 6 # IPPROTO_TCP | |
56 | flow['TP_SRC'] = 6667 | |
57 | flow['TP_DST'] = 9998 | |
58 | elif attrs['TP_PROTO'] == 'UDP': | |
59 | flow['NW_PROTO'] = 17 # IPPROTO_UDP | |
60 | flow['TP_SRC'] = 1112 | |
61 | flow['TP_DST'] = 2223 | |
62 | elif attrs['TP_PROTO'] == 'ICMP': | |
63 | flow['NW_PROTO'] = 1 # IPPROTO_ICMP | |
64 | flow['TP_SRC'] = 8 # echo request | |
65 | flow['TP_DST'] = 0 # code | |
66 | else: | |
67 | assert False | |
68 | if attrs['IP_FRAGMENT'] not in ('no', 'first'): | |
69 | flow['TP_SRC'] = flow['TP_DST'] = 0 | |
70 | elif attrs['DL_TYPE'] == 'non-ip': | |
71 | flow['DL_TYPE'] = 0x5678 | |
72 | else: | |
73 | assert False | |
74 | ||
75 | # Compose packet | |
76 | packet = b'' | |
77 | wildcards = 1 << 5 | 1 << 6 | 1 << 7 | 32 << 8 | 32 << 14 | 1 << 21 | |
78 | ||
79 | packet += pack_ethaddr(flow['DL_DST']) | |
80 | packet += pack_ethaddr(flow['DL_SRC']) | |
81 | if flow['DL_VLAN'] != 0xffff: | |
82 | packet += struct.pack('>HH', 0x8100, flow['DL_VLAN']) | |
83 | len_ofs = len(packet) | |
84 | if attrs['DL_HEADER'].startswith('802.2'): | |
85 | packet += struct.pack('>H', 0) | |
86 | if attrs['DL_HEADER'] == '802.2': | |
87 | packet += struct.pack('BBB', 0x42, 0x42, 0x03) # LLC for 802.1D STP | |
88 | else: | |
89 | if attrs['DL_HEADER'] == '802.2+SNAP': | |
90 | packet += struct.pack('BBB', 0xaa, 0xaa, 0x03) # LLC for SNAP | |
91 | packet += struct.pack('BBB', 0, 0, 0) # SNAP OUI | |
92 | packet += struct.pack('>H', flow['DL_TYPE']) | |
93 | if attrs['DL_TYPE'] == 'ip': | |
94 | ip = struct.pack('>BBHHHBBHLL', | |
95 | (4 << 4) | 5, # version, hdrlen | |
96 | flow['NW_TOS'], # type of service | |
97 | 0, # total length, filled in later | |
98 | 65432, # id | |
99 | 0, # frag offset | |
100 | 64, # ttl | |
101 | flow['NW_PROTO'], # protocol | |
102 | 0, # checksum | |
103 | 0x0a00020f, # source | |
104 | 0xc0a80114) # dest | |
105 | wildcards &= ~(1 << 5 | 63 << 8 | 63 << 14 | 1 << 21) | |
106 | if attrs['IP_OPTIONS'] == 'yes': | |
107 | ip = struct.pack('B', (4 << 4) | 8) + ip[1:] | |
108 | ip += struct.pack('>BBHHHBBBx', | |
109 | 130, # type | |
110 | 11, # length | |
111 | 0x6bc5, # top secret | |
112 | 0xabcd, | |
113 | 0x1234, | |
114 | 1, | |
115 | 2, | |
116 | 3) | |
117 | if attrs['IP_FRAGMENT'] != 'no': | |
118 | frag_map = {'first': 0x2000, # more frags, ofs 0 | |
119 | 'middle': 0x2111, # more frags, ofs 0x888 | |
120 | 'last': 0x0222} # last frag, ofs 0x1110 | |
121 | ip = (ip[:6] | |
122 | + struct.pack('>H', frag_map[attrs['IP_FRAGMENT']]) | |
123 | + ip[8:]) | |
124 | if attrs['IP_FRAGMENT'] in ('no', 'first'): | |
125 | if attrs['TP_PROTO'].startswith('TCP'): | |
126 | tcp = struct.pack('>HHLLHHHH', | |
127 | flow['TP_SRC'], # source port | |
128 | flow['TP_DST'], # dest port | |
129 | 87123455, # seqno | |
130 | 712378912, # ackno | |
131 | (5 << 12) | 0x02 | 0x10, | |
132 | # hdrlen, SYN, ACK | |
133 | 5823, # window size | |
134 | 18923, # checksum | |
135 | 12893) # urgent pointer | |
136 | if attrs['TP_PROTO'] == 'TCP+options': | |
137 | tcp = (tcp[:12] | |
138 | + struct.pack('H', (6 << 12) | 0x02 | 0x10) | |
139 | + tcp[14:]) | |
140 | tcp += struct.pack('>BBH', 2, 4, 1975) # MSS option | |
141 | tcp += b'payload' | |
142 | ip += tcp | |
143 | wildcards &= ~(1 << 6 | 1 << 7) | |
144 | elif attrs['TP_PROTO'] == 'UDP': | |
145 | udp_len = 15 | |
146 | udp = struct.pack('>HHHH', | |
147 | flow['TP_SRC'], | |
148 | flow['TP_DST'], | |
149 | udp_len, 0) | |
150 | while len(udp) < udp_len: | |
151 | udp += struct.pack('B', udp_len) | |
152 | ip += udp | |
153 | wildcards &= ~(1 << 6 | 1 << 7) | |
154 | elif attrs['TP_PROTO'] == 'ICMP': | |
155 | ip += struct.pack('>BBHHH', | |
156 | 8, # echo request | |
157 | 0, # code | |
158 | 0, # checksum | |
159 | 736, # identifier | |
160 | 931) # sequence number | |
161 | wildcards &= ~(1 << 6 | 1 << 7) | |
162 | elif attrs['TP_PROTO'] == 'other': | |
163 | ip += b'other header' | |
164 | else: | |
165 | assert False | |
166 | ip = ip[:2] + struct.pack('>H', len(ip)) + ip[4:] | |
167 | packet += ip | |
168 | if attrs['DL_HEADER'].startswith('802.2'): | |
169 | packet_len = len(packet) | |
170 | if flow['DL_VLAN'] != 0xffff: | |
171 | packet_len -= 4 | |
172 | packet = (packet[:len_ofs] | |
173 | + struct.pack('>H', packet_len) | |
174 | + packet[len_ofs + 2:]) | |
175 | ||
176 | print(' '.join(['%s=%s' for k, v in attrs.items()])) | |
177 | print(' '.join(['%s=%s' for k, v in flow.items()])) | |
178 | print() | |
179 | ||
180 | flows.write(struct.pack('>LH', | |
181 | wildcards, # wildcards | |
182 | 1)) # in_port | |
183 | flows.write(pack_ethaddr(flow['DL_SRC'])) | |
184 | flows.write(pack_ethaddr(flow['DL_DST'])) | |
185 | flows.write(struct.pack('>HBxHBBxx', | |
186 | flow['DL_VLAN'], | |
187 | 0, # DL_VLAN_PCP | |
188 | flow['DL_TYPE'], | |
189 | flow['NW_TOS'], | |
190 | flow['NW_PROTO'])) | |
191 | flows.write(socket.inet_aton(flow['NW_SRC'])) | |
192 | flows.write(socket.inet_aton(flow['NW_DST'])) | |
193 | flows.write(struct.pack('>HH', flow['TP_SRC'], flow['TP_DST'])) | |
194 | ||
195 | packets.write(struct.pack('>LLLL', | |
196 | 0, # timestamp seconds | |
197 | 0, # timestamp microseconds | |
198 | len(packet), # bytes saved | |
199 | len(packet))) # total length | |
200 | packets.write(packet) | |
201 | ||
202 | ||
c2104b9b AGS |
203 | flows = open('flows', 'wb') |
204 | packets = open('pcap', 'wb') | |
3b1101d2 BP |
205 | |
206 | # Print pcap file header. | |
207 | packets.write(struct.pack('>LHHLLLL', | |
208 | 0xa1b2c3d4, # magic number | |
209 | 2, # major version | |
210 | 4, # minor version | |
211 | 0, # time zone offset | |
212 | 0, # time stamp accuracy | |
213 | 1518, # snaplen | |
214 | 1)) # Ethernet | |
215 | ||
216 | output({'DL_HEADER': '802.2'}) | |
217 | ||
218 | for dl_header in ('802.2+SNAP', 'Ethernet'): | |
219 | a = {'DL_HEADER': dl_header} | |
220 | for dl_vlan in ('none', 'zero', 'nonzero'): | |
221 | b = a.copy() | |
222 | b['DL_VLAN'] = dl_vlan | |
223 | ||
224 | # Non-IP case. | |
225 | c = b.copy() | |
226 | c['DL_TYPE'] = 'non-ip' | |
227 | output(c) | |
228 | ||
229 | for ip_options in ('no', 'yes'): | |
230 | c = b.copy() | |
231 | c['DL_TYPE'] = 'ip' | |
232 | c['IP_OPTIONS'] = ip_options | |
233 | for ip_fragment in ('no', 'first', 'middle', 'last'): | |
234 | d = c.copy() | |
235 | d['IP_FRAGMENT'] = ip_fragment | |
236 | for tp_proto in ('TCP', 'TCP+options', 'UDP', 'ICMP', 'other'): | |
237 | e = d.copy() | |
238 | e['TP_PROTO'] = tp_proto | |
239 | output(e) |