]>
Commit | Line | Data |
---|---|---|
1 | #! /usr/bin/perl | |
2 | ||
3 | # Copyright (c) 2009 Nicira Networks. | |
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 | ||
17 | use strict; | |
18 | use warnings; | |
19 | ||
20 | open(FLOWS, ">&=3");# or die "failed to open fd 3 for writing: $!\n"; | |
21 | open(PACKETS, ">&=4");# or die "failed to open fd 4 for writing: $!\n"; | |
22 | ||
23 | # Print pcap file header. | |
24 | print PACKETS pack('NnnNNNN', | |
25 | 0xa1b2c3d4, # magic number | |
26 | 2, # major version | |
27 | 4, # minor version | |
28 | 0, # time zone offset | |
29 | 0, # time stamp accuracy | |
30 | 1518, # snaplen | |
31 | 1); # Ethernet | |
32 | ||
33 | output(DL_HEADER => '802.2'); | |
34 | ||
35 | for my $dl_header qw(802.2+SNAP Ethernet) { | |
36 | my %a = (DL_HEADER => $dl_header); | |
37 | for my $dl_vlan qw(none zero nonzero) { | |
38 | my %b = (%a, DL_VLAN => $dl_vlan); | |
39 | ||
40 | # Non-IP case. | |
41 | output(%b, DL_TYPE => 'non-ip'); | |
42 | ||
43 | for my $ip_options qw(no yes) { | |
44 | my %c = (%b, DL_TYPE => 'ip', IP_OPTIONS => $ip_options); | |
45 | for my $ip_fragment qw(no first middle last) { | |
46 | my %d = (%c, IP_FRAGMENT => $ip_fragment); | |
47 | for my $tp_proto qw(TCP TCP+options UDP ICMP other) { | |
48 | output(%d, TP_PROTO => $tp_proto); | |
49 | } | |
50 | } | |
51 | } | |
52 | } | |
53 | } | |
54 | ||
55 | sub output { | |
56 | my (%attrs) = @_; | |
57 | ||
58 | # Compose flow. | |
59 | my (%flow); | |
60 | $flow{DL_SRC} = "00:02:e3:0f:80:a4"; | |
61 | $flow{DL_DST} = "00:1a:92:40:ac:05"; | |
62 | $flow{NW_PROTO} = 0; | |
63 | $flow{NW_SRC} = '0.0.0.0'; | |
64 | $flow{NW_DST} = '0.0.0.0'; | |
65 | $flow{TP_SRC} = 0; | |
66 | $flow{TP_DST} = 0; | |
67 | if (defined($attrs{DL_VLAN})) { | |
68 | my (%vlan_map) = ('none' => 0xffff, | |
69 | 'zero' => 0, | |
70 | 'nonzero' => 0x0123); | |
71 | $flow{DL_VLAN} = $vlan_map{$attrs{DL_VLAN}}; | |
72 | } else { | |
73 | $flow{DL_VLAN} = 0xffff; # OFP_VLAN_NONE | |
74 | } | |
75 | if ($attrs{DL_HEADER} eq '802.2') { | |
76 | $flow{DL_TYPE} = 0x5ff; # OFP_DL_TYPE_NOT_ETH_TYPE | |
77 | } elsif ($attrs{DL_TYPE} eq 'ip') { | |
78 | $flow{DL_TYPE} = 0x0800; # ETH_TYPE_IP | |
79 | $flow{NW_SRC} = '10.0.2.15'; | |
80 | $flow{NW_DST} = '192.168.1.20'; | |
81 | if ($attrs{TP_PROTO} eq 'other') { | |
82 | $flow{NW_PROTO} = 42; | |
83 | } elsif ($attrs{TP_PROTO} eq 'TCP' || | |
84 | $attrs{TP_PROTO} eq 'TCP+options') { | |
85 | $flow{NW_PROTO} = 6; # IP_TYPE_TCP | |
86 | $flow{TP_SRC} = 6667; | |
87 | $flow{TP_DST} = 9998; | |
88 | } elsif ($attrs{TP_PROTO} eq 'UDP') { | |
89 | $flow{NW_PROTO} = 17; # IP_TYPE_UDP | |
90 | $flow{TP_SRC} = 1112; | |
91 | $flow{TP_DST} = 2223; | |
92 | } elsif ($attrs{TP_PROTO} eq 'ICMP') { | |
93 | $flow{NW_PROTO} = 1; # IP_TYPE_ICMP | |
94 | $flow{TP_SRC} = 8; # echo request | |
95 | $flow{TP_DST} = 0; # code | |
96 | } else { | |
97 | die; | |
98 | } | |
99 | if ($attrs{IP_FRAGMENT} ne 'no') { | |
100 | $flow{TP_SRC} = $flow{TP_DST} = 0; | |
101 | } | |
102 | } elsif ($attrs{DL_TYPE} eq 'non-ip') { | |
103 | $flow{DL_TYPE} = 0x5678; | |
104 | } else { | |
105 | die; | |
106 | } | |
107 | ||
108 | # Compose packet. | |
109 | my $packet = ''; | |
110 | $packet .= pack_ethaddr($flow{DL_DST}); | |
111 | $packet .= pack_ethaddr($flow{DL_SRC}); | |
112 | $packet .= pack('n', 0) if $attrs{DL_HEADER} =~ /^802.2/; | |
113 | if ($attrs{DL_HEADER} eq '802.2') { | |
114 | $packet .= pack('CCC', 0x42, 0x42, 0x03); # LLC for 802.1D STP. | |
115 | } else { | |
116 | if ($attrs{DL_HEADER} eq '802.2+SNAP') { | |
117 | $packet .= pack('CCC', 0xaa, 0xaa, 0x03); # LLC for SNAP. | |
118 | $packet .= pack('CCC', 0, 0, 0); # SNAP OUI. | |
119 | } | |
120 | if ($attrs{DL_VLAN} ne 'none') { | |
121 | $packet .= pack('nn', 0x8100, $flow{DL_VLAN}); | |
122 | } | |
123 | $packet .= pack('n', $flow{DL_TYPE}); | |
124 | if ($attrs{DL_TYPE} eq 'ip') { | |
125 | my $ip = pack('CCnnnCCnNN', | |
126 | (4 << 4) | 5, # version, hdrlen | |
127 | 0, # type of service | |
128 | 0, # total length (filled in later) | |
129 | 65432, # id | |
130 | 0, # frag offset | |
131 | 64, # ttl | |
132 | $flow{NW_PROTO}, # protocol | |
133 | 0, # checksum | |
134 | 0x0a00020f, # source | |
135 | 0xc0a80114); # dest | |
136 | if ($attrs{IP_OPTIONS} eq 'yes') { | |
137 | substr($ip, 0, 1) = pack('C', (4 << 4) | 8); | |
138 | $ip .= pack('CCnnnCCCx', | |
139 | 130, # type | |
140 | 11, # length | |
141 | 0x6bc5, # top secret | |
142 | 0xabcd, | |
143 | 0x1234, | |
144 | 1, | |
145 | 2, | |
146 | 3); | |
147 | } | |
148 | if ($attrs{IP_FRAGMENT} ne 'no') { | |
149 | my (%frag_map) = ('first' => 0x2000, # more frags, ofs 0 | |
150 | 'middle' => 0x2111, # more frags, ofs 0x888 | |
151 | 'last' => 0x0222); # last frag, ofs 0x1110 | |
152 | substr($ip, 6, 2) | |
153 | = pack('n', $frag_map{$attrs{IP_FRAGMENT}}); | |
154 | } | |
155 | ||
156 | if ($attrs{TP_PROTO} =~ '^TCP') { | |
157 | my $tcp = pack('nnNNnnnn', | |
158 | $flow{TP_SRC}, # source port | |
159 | $flow{TP_DST}, # dest port | |
160 | 87123455, # seqno | |
161 | 712378912, # ackno | |
162 | (5 << 12) | 0x02 | 0x10, # hdrlen, SYN, ACK | |
163 | 5823, # window size | |
164 | 18923, # checksum | |
165 | 12893); # urgent pointer | |
166 | if ($attrs{TP_PROTO} eq 'TCP+options') { | |
167 | substr($tcp, 12, 2) = pack('n', (6 << 12) | 0x02 | 0x10); | |
168 | $tcp .= pack('CCn', 2, 4, 1975); # MSS option | |
169 | } | |
170 | $tcp .= 'payload'; | |
171 | $ip .= $tcp; | |
172 | } elsif ($attrs{TP_PROTO} eq 'UDP') { | |
173 | my $len = 15; | |
174 | my $udp = pack('nnnn', $flow{TP_SRC}, $flow{TP_DST}, $len, 0); | |
175 | $udp .= chr($len) while length($udp) < $len; | |
176 | $ip .= $udp; | |
177 | } elsif ($attrs{TP_PROTO} eq 'ICMP') { | |
178 | $ip .= pack('CCnnn', | |
179 | 8, # echo request | |
180 | 0, # code | |
181 | 0, # checksum | |
182 | 736, # identifier | |
183 | 931); # sequence number | |
184 | } elsif ($attrs{TP_PROTO} eq 'other') { | |
185 | $ip .= 'other header'; | |
186 | } else { | |
187 | die; | |
188 | } | |
189 | ||
190 | substr($ip, 2, 2) = pack('n', length($ip)); | |
191 | $packet .= $ip; | |
192 | } | |
193 | } | |
194 | substr($packet, 12, 2) = pack('n', length($packet)) | |
195 | if $attrs{DL_HEADER} =~ /^802.2/; | |
196 | ||
197 | print join(' ', map("$_=$attrs{$_}", keys(%attrs))), "\n"; | |
198 | print join(' ', map("$_=$flow{$_}", keys(%flow))), "\n"; | |
199 | print "\n"; | |
200 | ||
201 | print FLOWS pack('Nn', | |
202 | 0, # wildcards | |
203 | 1); # in_port | |
204 | print FLOWS pack_ethaddr($flow{DL_SRC}); | |
205 | print FLOWS pack_ethaddr($flow{DL_DST}); | |
206 | print FLOWS pack('nnCxNNnn', | |
207 | $flow{DL_VLAN}, | |
208 | $flow{DL_TYPE}, | |
209 | $flow{NW_PROTO}, | |
210 | inet_aton($flow{NW_SRC}), | |
211 | inet_aton($flow{NW_DST}), | |
212 | $flow{TP_SRC}, | |
213 | $flow{TP_DST}); | |
214 | ||
215 | print PACKETS pack('NNNN', | |
216 | 0, # timestamp seconds | |
217 | 0, # timestamp microseconds | |
218 | length($packet), # bytes saved | |
219 | length($packet)), # total length | |
220 | $packet; | |
221 | } | |
222 | ||
223 | sub pack_ethaddr { | |
224 | local ($_) = @_; | |
225 | my $xx = '([0-9a-fA-F][0-9a-fA-F])'; | |
226 | my (@octets) = /$xx:$xx:$xx:$xx:$xx:$xx/; | |
227 | @octets == 6 or die $_; | |
228 | my ($out) = ''; | |
229 | $out .= pack('C', hex($_)) foreach @octets; | |
230 | return $out; | |
231 | } | |
232 | ||
233 | sub inet_aton { | |
234 | local ($_) = @_; | |
235 | my ($a, $b, $c, $d) = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/; | |
236 | defined $d or die $_; | |
237 | return ($a << 24) | ($b << 16) | ($c << 8) | $d; | |
238 | } |