6 open(FLOWS, ">&=3");# or die "failed to open fd 3 for writing: $!\n";
7 open(PACKETS, ">&=4");# or die "failed to open fd 4 for writing: $!\n";
9 # Print pcap file header.
10 print PACKETS pack('NnnNNNN',
11 0xa1b2c3d4, # magic number
15 0, # time stamp accuracy
19 output(DL_HEADER => '802.2');
21 for my $dl_header qw(802.2+SNAP Ethernet) {
22 my %a = (DL_HEADER => $dl_header);
23 for my $dl_vlan qw(none zero nonzero) {
24 my %b = (%a, DL_VLAN => $dl_vlan);
27 output(%b, DL_TYPE => 'non-ip');
29 for my $ip_options qw(no yes) {
30 my %c = (%b, DL_TYPE => 'ip', IP_OPTIONS => $ip_options);
31 for my $ip_fragment qw(no first middle last) {
32 my %d = (%c, IP_FRAGMENT => $ip_fragment);
33 for my $tp_proto qw(TCP TCP+options UDP ICMP other) {
34 output(%d, TP_PROTO => $tp_proto);
46 $flow{DL_SRC} = "00:02:e3:0f:80:a4";
47 $flow{DL_DST} = "00:1a:92:40:ac:05";
49 $flow{NW_SRC} = '0.0.0.0';
50 $flow{NW_DST} = '0.0.0.0';
53 if (defined($attrs{DL_VLAN})) {
54 my (%vlan_map) = ('none' => 0xffff,
57 $flow{DL_VLAN} = $vlan_map{$attrs{DL_VLAN}};
59 $flow{DL_VLAN} = 0xffff; # OFP_VLAN_NONE
61 if ($attrs{DL_HEADER} eq '802.2') {
62 $flow{DL_TYPE} = 0x5ff; # OFP_DL_TYPE_NOT_ETH_TYPE
63 } elsif ($attrs{DL_TYPE} eq 'ip') {
64 $flow{DL_TYPE} = 0x0800; # ETH_TYPE_IP
65 $flow{NW_SRC} = '10.0.2.15';
66 $flow{NW_DST} = '192.168.1.20';
67 if ($attrs{TP_PROTO} eq 'other') {
69 } elsif ($attrs{TP_PROTO} eq 'TCP' ||
70 $attrs{TP_PROTO} eq 'TCP+options') {
71 $flow{NW_PROTO} = 6; # IP_TYPE_TCP
74 } elsif ($attrs{TP_PROTO} eq 'UDP') {
75 $flow{NW_PROTO} = 17; # IP_TYPE_UDP
78 } elsif ($attrs{TP_PROTO} eq 'ICMP') {
79 $flow{NW_PROTO} = 1; # IP_TYPE_ICMP
80 $flow{TP_SRC} = 8; # echo request
81 $flow{TP_DST} = 0; # code
85 if ($attrs{IP_FRAGMENT} ne 'no') {
86 $flow{TP_SRC} = $flow{TP_DST} = 0;
88 } elsif ($attrs{DL_TYPE} eq 'non-ip') {
89 $flow{DL_TYPE} = 0x5678;
96 $packet .= pack_ethaddr($flow{DL_DST});
97 $packet .= pack_ethaddr($flow{DL_SRC});
98 $packet .= pack('n', 0) if $attrs{DL_HEADER} =~ /^802.2/;
99 if ($attrs{DL_HEADER} eq '802.2') {
100 $packet .= pack('CCC', 0x42, 0x42, 0x03); # LLC for 802.1D STP.
102 if ($attrs{DL_HEADER} eq '802.2+SNAP') {
103 $packet .= pack('CCC', 0xaa, 0xaa, 0x03); # LLC for SNAP.
104 $packet .= pack('CCC', 0, 0, 0); # SNAP OUI.
106 if ($attrs{DL_VLAN} ne 'none') {
107 $packet .= pack('nn', 0x8100, $flow{DL_VLAN});
109 $packet .= pack('n', $flow{DL_TYPE});
110 if ($attrs{DL_TYPE} eq 'ip') {
111 my $ip = pack('CCnnnCCnNN',
112 (4 << 4) | 5, # version, hdrlen
114 0, # total length (filled in later)
118 $flow{NW_PROTO}, # protocol
122 if ($attrs{IP_OPTIONS} eq 'yes') {
123 substr($ip, 0, 1) = pack('C', (4 << 4) | 8);
124 $ip .= pack('CCnnnCCCx',
134 if ($attrs{IP_FRAGMENT} ne 'no') {
135 my (%frag_map) = ('first' => 0x2000, # more frags, ofs 0
136 'middle' => 0x2111, # more frags, ofs 0x888
137 'last' => 0x0222); # last frag, ofs 0x1110
139 = pack('n', $frag_map{$attrs{IP_FRAGMENT}});
142 if ($attrs{TP_PROTO} =~ '^TCP') {
143 my $tcp = pack('nnNNnnnn',
144 $flow{TP_SRC}, # source port
145 $flow{TP_DST}, # dest port
148 (5 << 12) | 0x02 | 0x10, # hdrlen, SYN, ACK
151 12893); # urgent pointer
152 if ($attrs{TP_PROTO} eq 'TCP+options') {
153 substr($tcp, 12, 2) = pack('n', (6 << 12) | 0x02 | 0x10);
154 $tcp .= pack('CCn', 2, 4, 1975); # MSS option
158 } elsif ($attrs{TP_PROTO} eq 'UDP') {
160 my $udp = pack('nnnn', $flow{TP_SRC}, $flow{TP_DST}, $len, 0);
161 $udp .= chr($len) while length($udp) < $len;
163 } elsif ($attrs{TP_PROTO} eq 'ICMP') {
169 931); # sequence number
170 } elsif ($attrs{TP_PROTO} eq 'other') {
171 $ip .= 'other header';
176 substr($ip, 2, 2) = pack('n', length($ip));
180 substr($packet, 12, 2) = pack('n', length($packet))
181 if $attrs{DL_HEADER} =~ /^802.2/;
183 print join(' ', map("$_=$attrs{$_}", keys(%attrs))), "\n";
184 print join(' ', map("$_=$flow{$_}", keys(%flow))), "\n";
187 print FLOWS pack('Nn',
190 print FLOWS pack_ethaddr($flow{DL_SRC});
191 print FLOWS pack_ethaddr($flow{DL_DST});
192 print FLOWS pack('nnCxNNnn',
196 inet_aton($flow{NW_SRC}),
197 inet_aton($flow{NW_DST}),
201 print PACKETS pack('NNNN',
202 0, # timestamp seconds
203 0, # timestamp microseconds
204 length($packet), # bytes saved
205 length($packet)), # total length
211 my $xx = '([0-9a-fA-F][0-9a-fA-F])';
212 my (@octets) = /$xx:$xx:$xx:$xx:$xx:$xx/;
213 @octets == 6 or die $_;
215 $out .= pack('C', hex($_)) foreach @octets;
221 my ($a, $b, $c, $d) = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
222 defined $d or die $_;
223 return ($a << 24) | ($b << 16) | ($c << 8) | $d;