DIY-pcap 0.4.1 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/.gitignore +4 -4
  2. data/DIY-pcap.gemspec +17 -17
  3. data/Gemfile +3 -3
  4. data/Rakefile +1 -1
  5. data/lib/DIY-pcap.rb +2 -2
  6. data/lib/diy/command.rb +7 -1
  7. data/lib/diy/controller.rb +10 -15
  8. data/lib/diy/live.rb +9 -2
  9. data/lib/diy/parser/mu/pcap/ethernet.rb +148 -148
  10. data/lib/diy/parser/mu/pcap/header.rb +75 -75
  11. data/lib/diy/parser/mu/pcap/io_pair.rb +67 -67
  12. data/lib/diy/parser/mu/pcap/io_wrapper.rb +76 -76
  13. data/lib/diy/parser/mu/pcap/ip.rb +61 -61
  14. data/lib/diy/parser/mu/pcap/ipv4.rb +257 -257
  15. data/lib/diy/parser/mu/pcap/ipv6.rb +148 -148
  16. data/lib/diy/parser/mu/pcap/packet.rb +104 -104
  17. data/lib/diy/parser/mu/pcap/pkthdr.rb +155 -155
  18. data/lib/diy/parser/mu/pcap/reader.rb +61 -61
  19. data/lib/diy/parser/mu/pcap/reader/http_family.rb +170 -170
  20. data/lib/diy/parser/mu/pcap/sctp.rb +367 -367
  21. data/lib/diy/parser/mu/pcap/sctp/chunk.rb +123 -123
  22. data/lib/diy/parser/mu/pcap/sctp/chunk/data.rb +134 -134
  23. data/lib/diy/parser/mu/pcap/sctp/chunk/init.rb +100 -100
  24. data/lib/diy/parser/mu/pcap/sctp/chunk/init_ack.rb +68 -68
  25. data/lib/diy/parser/mu/pcap/sctp/parameter.rb +110 -110
  26. data/lib/diy/parser/mu/pcap/sctp/parameter/ip_address.rb +48 -48
  27. data/lib/diy/parser/mu/pcap/stream_packetizer.rb +72 -72
  28. data/lib/diy/parser/mu/pcap/tcp.rb +505 -505
  29. data/lib/diy/parser/mu/pcap/udp.rb +69 -69
  30. data/lib/diy/parser/mu/scenario/pcap.rb +172 -172
  31. data/lib/diy/parser/mu/scenario/pcap/fields.rb +50 -50
  32. data/lib/diy/parser/mu/scenario/pcap/rtp.rb +71 -71
  33. data/lib/diy/parser/pcap.rb +109 -109
  34. data/lib/diy/version.rb +1 -1
  35. metadata +7 -9
@@ -1,148 +1,148 @@
1
- # http://www.mudynamics.com
2
- # http://labs.mudynamics.com
3
- # http://www.pcapr.net
4
-
5
- require 'ipaddr'
6
-
7
- module Mu
8
- class Pcap
9
-
10
- class IPv6 < IP
11
- FORMAT = 'NnCCa16a16'
12
-
13
- attr_accessor :next_header, :hop_limit
14
-
15
- def initialize
16
- super
17
- @next_header = 0
18
- @hop_limit = 64
19
- end
20
-
21
- def v6?
22
- return true
23
- end
24
-
25
- alias :proto :next_header
26
- alias :ttl :hop_limit
27
-
28
- def flow_id
29
- if not @payload or @payload.is_a? String
30
- return [:ipv6, @next_header, @src, @dst]
31
- else
32
- return [:ipv6, @src, @dst, @payload.flow_id]
33
- end
34
- end
35
-
36
- def self.from_bytes bytes
37
- Pcap.assert bytes.length >= 40, 'Truncated IPv6 header: ' +
38
- "expected at least 40 bytes, got #{bytes.length} bytes"
39
-
40
- vcl, length, next_header, hop_limit, src, dst =
41
- bytes[0, 40].unpack FORMAT
42
- version = vcl >> 28 & 0x0f
43
- traffic_class = vcl >> 20 & 0xff
44
- flow_label = vcl & 0xfffff
45
-
46
- Pcap.assert version == 6, "Wrong IPv6 version: got (#{version})"
47
- Pcap.assert bytes.length >= (40 + length), 'Truncated IPv6 header: ' +
48
- "expected #{length + 40} bytes, got #{bytes.length} bytes"
49
-
50
- ipv6 = IPv6.new
51
- ipv6.next_header = next_header
52
- ipv6.hop_limit = hop_limit
53
- ipv6.src = IPAddr.new_ntoh(src).to_s
54
- ipv6.dst = IPAddr.new_ntoh(dst).to_s
55
-
56
- ipv6.payload_raw = bytes[40..-1]
57
- ipv6.next_header, ipv6.payload =
58
- payload_from_bytes ipv6, ipv6.next_header, bytes[40...40+length]
59
-
60
- return ipv6
61
- end
62
-
63
- # Parse bytes and returns next_header and payload. Skips extension
64
- # headers.
65
- def self.payload_from_bytes ipv6, next_header, bytes
66
- begin
67
- case next_header
68
- when IPPROTO_TCP
69
- payload = TCP.from_bytes bytes
70
- when IPPROTO_UDP
71
- payload = UDP.from_bytes bytes
72
- when IPPROTO_SCTP
73
- payload = SCTP.from_bytes bytes
74
- when IPPROTO_HOPOPTS
75
- next_header, payload = eight_byte_header_from_bytes(ipv6,
76
- bytes, 'hop-by-hop options')
77
- when IPPROTO_ROUTING
78
- next_header, payload = eight_byte_header_from_bytes(ipv6,
79
- bytes, 'routing')
80
- when IPPROTO_DSTOPTS
81
- next_header, payload = eight_byte_header_from_bytes(ipv6,
82
- bytes, 'destination options')
83
- when IPPROTO_FRAGMENT
84
- Pcap.assert bytes.length >= 8,
85
- "Truncated IPv6 fragment header"
86
- Pcap.assert false, 'IPv6 fragments are not supported'
87
- when IPPROTO_AH
88
- next_header, payload = ah_header_from_bytes(ipv6,
89
- bytes, 'authentication header')
90
- when IPPROTO_NONE
91
- payload = ''
92
- else
93
- payload = bytes
94
- end
95
- rescue ParseError => e
96
- Pcap.warning e
97
- payload = bytes
98
- end
99
- return [next_header, payload]
100
- end
101
-
102
- # Parse extension header that's a multiple of 8 bytes
103
- def self.eight_byte_header_from_bytes ipv6, bytes, name
104
- Pcap.assert bytes.length >= 8, "Truncated IPv6 #{name} header"
105
- length = (bytes[1].ord + 1) * 8
106
- Pcap.assert bytes.length >= length, "Truncated IPv6 #{name} header"
107
- return payload_from_bytes(ipv6, bytes[0].ord, bytes[length..-1])
108
- end
109
-
110
- # Parse authentication header (whose length field is interpeted differently)
111
- def self.ah_header_from_bytes ipv6, bytes, name
112
- Pcap.assert bytes.length >= 8, "Truncated IPv6 #{name} header"
113
- length = (bytes[1].ord + 2) * 4
114
- Pcap.assert bytes.length >= length, "Truncated IPv6 #{name} header"
115
- return payload_from_bytes(ipv6, bytes[0].ord, bytes[length..-1])
116
- end
117
-
118
- def write io
119
- if @payload.is_a? String
120
- payload = @payload
121
- else
122
- string_io = StringIO.new
123
- @payload.write string_io, self
124
- payload = string_io.string
125
- end
126
- src = IPAddr.new(@src, Socket::AF_INET6).hton
127
- dst = IPAddr.new(@dst, Socket::AF_INET6).hton
128
- header = [0x60000000, payload.length, @next_header, @hop_limit,
129
- src, dst].pack FORMAT
130
- io.write header
131
- io.write payload
132
- end
133
-
134
- def pseudo_header payload_length
135
- return IPAddr.new(@src, Socket::AF_INET6).hton +
136
- IPAddr.new(@dst, Socket::AF_INET6).hton +
137
- [payload_length, '', @next_header].pack('Na3C')
138
- end
139
-
140
- def == other
141
- return super &&
142
- self.next_header == other.next_header &&
143
- self.hop_limit == other.hop_limit
144
- end
145
- end
146
-
147
- end
148
- end
1
+ # http://www.mudynamics.com
2
+ # http://labs.mudynamics.com
3
+ # http://www.pcapr.net
4
+
5
+ require 'ipaddr'
6
+
7
+ module Mu
8
+ class Pcap
9
+
10
+ class IPv6 < IP
11
+ FORMAT = 'NnCCa16a16'
12
+
13
+ attr_accessor :next_header, :hop_limit
14
+
15
+ def initialize
16
+ super
17
+ @next_header = 0
18
+ @hop_limit = 64
19
+ end
20
+
21
+ def v6?
22
+ return true
23
+ end
24
+
25
+ alias :proto :next_header
26
+ alias :ttl :hop_limit
27
+
28
+ def flow_id
29
+ if not @payload or @payload.is_a? String
30
+ return [:ipv6, @next_header, @src, @dst]
31
+ else
32
+ return [:ipv6, @src, @dst, @payload.flow_id]
33
+ end
34
+ end
35
+
36
+ def self.from_bytes bytes
37
+ Pcap.assert bytes.length >= 40, 'Truncated IPv6 header: ' +
38
+ "expected at least 40 bytes, got #{bytes.length} bytes"
39
+
40
+ vcl, length, next_header, hop_limit, src, dst =
41
+ bytes[0, 40].unpack FORMAT
42
+ version = vcl >> 28 & 0x0f
43
+ traffic_class = vcl >> 20 & 0xff
44
+ flow_label = vcl & 0xfffff
45
+
46
+ Pcap.assert version == 6, "Wrong IPv6 version: got (#{version})"
47
+ Pcap.assert bytes.length >= (40 + length), 'Truncated IPv6 header: ' +
48
+ "expected #{length + 40} bytes, got #{bytes.length} bytes"
49
+
50
+ ipv6 = IPv6.new
51
+ ipv6.next_header = next_header
52
+ ipv6.hop_limit = hop_limit
53
+ ipv6.src = IPAddr.new_ntoh(src).to_s
54
+ ipv6.dst = IPAddr.new_ntoh(dst).to_s
55
+
56
+ ipv6.payload_raw = bytes[40..-1]
57
+ ipv6.next_header, ipv6.payload =
58
+ payload_from_bytes ipv6, ipv6.next_header, bytes[40...40+length]
59
+
60
+ return ipv6
61
+ end
62
+
63
+ # Parse bytes and returns next_header and payload. Skips extension
64
+ # headers.
65
+ def self.payload_from_bytes ipv6, next_header, bytes
66
+ begin
67
+ case next_header
68
+ when IPPROTO_TCP
69
+ payload = TCP.from_bytes bytes
70
+ when IPPROTO_UDP
71
+ payload = UDP.from_bytes bytes
72
+ when IPPROTO_SCTP
73
+ payload = SCTP.from_bytes bytes
74
+ when IPPROTO_HOPOPTS
75
+ next_header, payload = eight_byte_header_from_bytes(ipv6,
76
+ bytes, 'hop-by-hop options')
77
+ when IPPROTO_ROUTING
78
+ next_header, payload = eight_byte_header_from_bytes(ipv6,
79
+ bytes, 'routing')
80
+ when IPPROTO_DSTOPTS
81
+ next_header, payload = eight_byte_header_from_bytes(ipv6,
82
+ bytes, 'destination options')
83
+ when IPPROTO_FRAGMENT
84
+ Pcap.assert bytes.length >= 8,
85
+ "Truncated IPv6 fragment header"
86
+ Pcap.assert false, 'IPv6 fragments are not supported'
87
+ when IPPROTO_AH
88
+ next_header, payload = ah_header_from_bytes(ipv6,
89
+ bytes, 'authentication header')
90
+ when IPPROTO_NONE
91
+ payload = ''
92
+ else
93
+ payload = bytes
94
+ end
95
+ rescue ParseError => e
96
+ Pcap.warning e
97
+ payload = bytes
98
+ end
99
+ return [next_header, payload]
100
+ end
101
+
102
+ # Parse extension header that's a multiple of 8 bytes
103
+ def self.eight_byte_header_from_bytes ipv6, bytes, name
104
+ Pcap.assert bytes.length >= 8, "Truncated IPv6 #{name} header"
105
+ length = (bytes[1].ord + 1) * 8
106
+ Pcap.assert bytes.length >= length, "Truncated IPv6 #{name} header"
107
+ return payload_from_bytes(ipv6, bytes[0].ord, bytes[length..-1])
108
+ end
109
+
110
+ # Parse authentication header (whose length field is interpeted differently)
111
+ def self.ah_header_from_bytes ipv6, bytes, name
112
+ Pcap.assert bytes.length >= 8, "Truncated IPv6 #{name} header"
113
+ length = (bytes[1].ord + 2) * 4
114
+ Pcap.assert bytes.length >= length, "Truncated IPv6 #{name} header"
115
+ return payload_from_bytes(ipv6, bytes[0].ord, bytes[length..-1])
116
+ end
117
+
118
+ def write io
119
+ if @payload.is_a? String
120
+ payload = @payload
121
+ else
122
+ string_io = StringIO.new
123
+ @payload.write string_io, self
124
+ payload = string_io.string
125
+ end
126
+ src = IPAddr.new(@src, Socket::AF_INET6).hton
127
+ dst = IPAddr.new(@dst, Socket::AF_INET6).hton
128
+ header = [0x60000000, payload.length, @next_header, @hop_limit,
129
+ src, dst].pack FORMAT
130
+ io.write header
131
+ io.write payload
132
+ end
133
+
134
+ def pseudo_header payload_length
135
+ return IPAddr.new(@src, Socket::AF_INET6).hton +
136
+ IPAddr.new(@dst, Socket::AF_INET6).hton +
137
+ [payload_length, '', @next_header].pack('Na3C')
138
+ end
139
+
140
+ def == other
141
+ return super &&
142
+ self.next_header == other.next_header &&
143
+ self.hop_limit == other.hop_limit
144
+ end
145
+ end
146
+
147
+ end
148
+ end
@@ -1,104 +1,104 @@
1
- # http://www.mudynamics.com
2
- # http://labs.mudynamics.com
3
- # http://www.pcapr.net
4
-
5
- module Mu
6
- class Pcap
7
-
8
- class Packet
9
- attr_accessor :payload, :payload_raw
10
-
11
- def initialize
12
- @payload = ''
13
- @payload_raw = ''
14
- end
15
-
16
- # Get payload as bytes. If the payload is a parsed object, returns
17
- # raw payload. Otherwise return unparsed bytes.
18
- def payload_bytes
19
- if @payload.is_a? String
20
- return @payload
21
- end
22
- return @payload_raw
23
- end
24
-
25
- def deepdup
26
- dup = self.dup
27
- if @payload.respond_to? :deepdup
28
- dup.payload = @payload.deepdup
29
- else
30
- dup.payload = @payload.dup
31
- end
32
- return dup
33
- end
34
-
35
- def flow_id
36
- raise NotImplementedError
37
- end
38
-
39
- # Reassemble, reorder, and merge packets.
40
- def self.normalize packets
41
- begin
42
- packets = TCP.reorder packets
43
- rescue TCP::ReorderError => e
44
- Pcap.warning e
45
- end
46
-
47
- begin
48
- packets = SCTP.reorder packets
49
- rescue SCTP::ReorderError => e
50
- Pcap.warning e
51
- end
52
-
53
- begin
54
- packets = TCP.merge packets
55
- rescue TCP::MergeError => e
56
- Pcap.warning e
57
- end
58
- return packets
59
- end
60
-
61
- # Remove non-L7/DNS/DHCP traffic if there is L7 traffic. Returns
62
- # original packets if there is no L7 traffic.
63
- IGNORE_UDP_PORTS = [
64
- 53, # DNS
65
- 67, 68, # DHCP
66
- 546, 547 # DHCPv6
67
- ]
68
- def self.isolate_l7 packets
69
- cleaned_packets = []
70
- packets.each do |packet|
71
- if TCP.tcp? packet
72
- cleaned_packets << packet
73
- elsif UDP.udp? packet
74
- src_port = packet.payload.payload.src_port
75
- dst_port = packet.payload.payload.dst_port
76
- if not IGNORE_UDP_PORTS.member? src_port and
77
- not IGNORE_UDP_PORTS.member? dst_port
78
- cleaned_packets << packet
79
- end
80
- elsif SCTP.sctp? packet
81
- cleaned_packets << packet
82
- end
83
- end
84
- if cleaned_packets.empty?
85
- return packets
86
- end
87
- return cleaned_packets
88
- end
89
-
90
- def to_bytes
91
- io = StringIO.new
92
- write io
93
- io.close
94
- return io.string
95
- end
96
-
97
- def == other
98
- return self.class == other.class && self.payload == other.payload &&
99
- self.payload_raw == other.payload_raw
100
- end
101
- end
102
-
103
- end
104
- end
1
+ # http://www.mudynamics.com
2
+ # http://labs.mudynamics.com
3
+ # http://www.pcapr.net
4
+
5
+ module Mu
6
+ class Pcap
7
+
8
+ class Packet
9
+ attr_accessor :payload, :payload_raw
10
+
11
+ def initialize
12
+ @payload = ''
13
+ @payload_raw = ''
14
+ end
15
+
16
+ # Get payload as bytes. If the payload is a parsed object, returns
17
+ # raw payload. Otherwise return unparsed bytes.
18
+ def payload_bytes
19
+ if @payload.is_a? String
20
+ return @payload
21
+ end
22
+ return @payload_raw
23
+ end
24
+
25
+ def deepdup
26
+ dup = self.dup
27
+ if @payload.respond_to? :deepdup
28
+ dup.payload = @payload.deepdup
29
+ else
30
+ dup.payload = @payload.dup
31
+ end
32
+ return dup
33
+ end
34
+
35
+ def flow_id
36
+ raise NotImplementedError
37
+ end
38
+
39
+ # Reassemble, reorder, and merge packets.
40
+ def self.normalize packets
41
+ begin
42
+ packets = TCP.reorder packets
43
+ rescue TCP::ReorderError => e
44
+ Pcap.warning e
45
+ end
46
+
47
+ begin
48
+ packets = SCTP.reorder packets
49
+ rescue SCTP::ReorderError => e
50
+ Pcap.warning e
51
+ end
52
+
53
+ begin
54
+ packets = TCP.merge packets
55
+ rescue TCP::MergeError => e
56
+ Pcap.warning e
57
+ end
58
+ return packets
59
+ end
60
+
61
+ # Remove non-L7/DNS/DHCP traffic if there is L7 traffic. Returns
62
+ # original packets if there is no L7 traffic.
63
+ IGNORE_UDP_PORTS = [
64
+ 53, # DNS
65
+ 67, 68, # DHCP
66
+ 546, 547 # DHCPv6
67
+ ]
68
+ def self.isolate_l7 packets
69
+ cleaned_packets = []
70
+ packets.each do |packet|
71
+ if TCP.tcp? packet
72
+ cleaned_packets << packet
73
+ elsif UDP.udp? packet
74
+ src_port = packet.payload.payload.src_port
75
+ dst_port = packet.payload.payload.dst_port
76
+ if not IGNORE_UDP_PORTS.member? src_port and
77
+ not IGNORE_UDP_PORTS.member? dst_port
78
+ cleaned_packets << packet
79
+ end
80
+ elsif SCTP.sctp? packet
81
+ cleaned_packets << packet
82
+ end
83
+ end
84
+ if cleaned_packets.empty?
85
+ return packets
86
+ end
87
+ return cleaned_packets
88
+ end
89
+
90
+ def to_bytes
91
+ io = StringIO.new
92
+ write io
93
+ io.close
94
+ return io.string
95
+ end
96
+
97
+ def == other
98
+ return self.class == other.class && self.payload == other.payload &&
99
+ self.payload_raw == other.payload_raw
100
+ end
101
+ end
102
+
103
+ end
104
+ end