woolen_common 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. checksums.yaml +15 -0
  2. data/README.md +31 -0
  3. data/ext/woolen_common/extconf.rb +26 -0
  4. data/ext/woolen_common/linux.h +3 -0
  5. data/ext/woolen_common/win.c +18 -0
  6. data/ext/woolen_common/win.h +4 -0
  7. data/ext/woolen_common/win/puts_color.c +139 -0
  8. data/ext/woolen_common/win/puts_color.h +5 -0
  9. data/ext/woolen_common/woolen_common.c +20 -0
  10. data/ext/woolen_common/woolen_common.h +7 -0
  11. data/lib/woolen_common.rb +39 -0
  12. data/lib/woolen_common/abstract_middleware/builder.rb +138 -0
  13. data/lib/woolen_common/abstract_middleware/map_cfg_manager.rb +52 -0
  14. data/lib/woolen_common/abstract_middleware/runner.rb +72 -0
  15. data/lib/woolen_common/action_pool_proxy.rb +28 -0
  16. data/lib/woolen_common/actionpool.rb +10 -0
  17. data/lib/woolen_common/actionpool/pool.rb +295 -0
  18. data/lib/woolen_common/actionpool/queue.rb +41 -0
  19. data/lib/woolen_common/actionpool/thread.rb +181 -0
  20. data/lib/woolen_common/addr_helper.rb +93 -0
  21. data/lib/woolen_common/cache.rb +305 -0
  22. data/lib/woolen_common/common_helper.rb +42 -0
  23. data/lib/woolen_common/config_manager.rb +36 -0
  24. data/lib/woolen_common/drb_helper.rb +125 -0
  25. data/lib/woolen_common/ffi/win32_kernel32.rb +86 -0
  26. data/lib/woolen_common/logger.rb +419 -0
  27. data/lib/woolen_common/pcap/mu/fixnum_ext.rb +8 -0
  28. data/lib/woolen_common/pcap/mu/pcap/ethernet.rb +164 -0
  29. data/lib/woolen_common/pcap/mu/pcap/header.rb +76 -0
  30. data/lib/woolen_common/pcap/mu/pcap/io_pair.rb +68 -0
  31. data/lib/woolen_common/pcap/mu/pcap/io_wrapper.rb +77 -0
  32. data/lib/woolen_common/pcap/mu/pcap/ip.rb +62 -0
  33. data/lib/woolen_common/pcap/mu/pcap/ipv4.rb +274 -0
  34. data/lib/woolen_common/pcap/mu/pcap/ipv6.rb +149 -0
  35. data/lib/woolen_common/pcap/mu/pcap/packet.rb +106 -0
  36. data/lib/woolen_common/pcap/mu/pcap/pkthdr.rb +162 -0
  37. data/lib/woolen_common/pcap/mu/pcap/reader.rb +62 -0
  38. data/lib/woolen_common/pcap/mu/pcap/reader/http_family.rb +175 -0
  39. data/lib/woolen_common/pcap/mu/pcap/sctp.rb +369 -0
  40. data/lib/woolen_common/pcap/mu/pcap/sctp/chunk.rb +124 -0
  41. data/lib/woolen_common/pcap/mu/pcap/sctp/chunk/data.rb +135 -0
  42. data/lib/woolen_common/pcap/mu/pcap/sctp/chunk/init.rb +101 -0
  43. data/lib/woolen_common/pcap/mu/pcap/sctp/chunk/init_ack.rb +69 -0
  44. data/lib/woolen_common/pcap/mu/pcap/sctp/parameter.rb +111 -0
  45. data/lib/woolen_common/pcap/mu/pcap/sctp/parameter/ip_address.rb +49 -0
  46. data/lib/woolen_common/pcap/mu/pcap/stream_packetizer.rb +74 -0
  47. data/lib/woolen_common/pcap/mu/pcap/tcp.rb +522 -0
  48. data/lib/woolen_common/pcap/mu/pcap/udp.rb +81 -0
  49. data/lib/woolen_common/pcap/mu/scenario/pcap.rb +175 -0
  50. data/lib/woolen_common/pcap/mu/scenario/pcap/fields.rb +51 -0
  51. data/lib/woolen_common/pcap/mu/scenario/pcap/rtp.rb +72 -0
  52. data/lib/woolen_common/pcap/pcap.rb +115 -0
  53. data/lib/woolen_common/pcap/readme.md +72 -0
  54. data/lib/woolen_common/ruby_ext/blank.rb +126 -0
  55. data/lib/woolen_common/ruby_ext/drb_ext.rb +7 -0
  56. data/lib/woolen_common/ruby_ext/string.rb +116 -0
  57. data/lib/woolen_common/ruby_ext/win32_ole.rb +4 -0
  58. data/lib/woolen_common/ruby_proxy.rb +5 -0
  59. data/lib/woolen_common/ruby_proxy/client.rb +305 -0
  60. data/lib/woolen_common/ruby_proxy/config.rb +44 -0
  61. data/lib/woolen_common/ruby_proxy/exceptions.rb +17 -0
  62. data/lib/woolen_common/ruby_proxy/proxy.rb +157 -0
  63. data/lib/woolen_common/ruby_proxy/proxy_global_set.rb +44 -0
  64. data/lib/woolen_common/ruby_proxy/proxy_load.rb +34 -0
  65. data/lib/woolen_common/ruby_proxy/server.rb +53 -0
  66. data/lib/woolen_common/splib.rb +36 -0
  67. data/lib/woolen_common/splib/Array.rb +33 -0
  68. data/lib/woolen_common/splib/CodeReloader.rb +59 -0
  69. data/lib/woolen_common/splib/Constants.rb +44 -0
  70. data/lib/woolen_common/splib/Conversions.rb +47 -0
  71. data/lib/woolen_common/splib/Exec.rb +132 -0
  72. data/lib/woolen_common/splib/Float.rb +13 -0
  73. data/lib/woolen_common/splib/HumanIdealRandomIterator.rb +40 -0
  74. data/lib/woolen_common/splib/Monitor.rb +214 -0
  75. data/lib/woolen_common/splib/PriorityQueue.rb +110 -0
  76. data/lib/woolen_common/splib/Sleep.rb +10 -0
  77. data/lib/woolen_common/splib/UrlShorteners.rb +48 -0
  78. data/lib/woolen_common/ssh_proxy.rb +146 -0
  79. data/lib/woolen_common/system_helper.rb +123 -0
  80. data/lib/woolen_common/system_monitor.rb +23 -0
  81. data/lib/woolen_common/system_monitor/linux_monitor.rb +250 -0
  82. data/lib/woolen_common/system_monitor/windows_monitor.rb +145 -0
  83. data/lib/woolen_common/type_helper.rb +42 -0
  84. data/lib/woolen_common/ver_ctrl_middle_ware.rb +92 -0
  85. data/lib/woolen_common/version.rb +3 -0
  86. metadata +210 -0
@@ -0,0 +1,274 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # http://www.mudynamics.com
3
+ # http://labs.mudynamics.com
4
+ # http://www.pcapr.net
5
+
6
+ require 'ipaddr'
7
+
8
+ module Mu
9
+ class Pcap
10
+
11
+ class IPv4 < IP
12
+ IP_RF = 0x8000 # Reserved
13
+ IP_DF = 0x4000 # Don't fragment
14
+ IP_MF = 0x2000 # More fragments
15
+ IP_OFFMASK = 0x1fff
16
+
17
+ FMT_HEADER = 'CCnnnCCna4a4'
18
+
19
+
20
+ class << self
21
+ def build_pkt(lv2_pkt,src=nil, dst=nil, ip_id=0, offset=0, ttl=64, proto=0, dscp=0)
22
+ if lv2_pkt && lv2_pkt.is_a?(Packet)
23
+ the_ip_pkt = self.new(src, dst, ip_id, offset, ttl, proto, dscp)
24
+ lv2_pkt.payload = the_ip_pkt
25
+ the_ip_pkt
26
+ else
27
+ raise 'can not build udp pkt with not Packet'
28
+ end
29
+ end
30
+ end
31
+
32
+ attr_accessor :ip_id, :offset, :ttl, :proto, :src, :dst, :dscp
33
+
34
+ def initialize src=nil, dst=nil, ip_id=0, offset=0, ttl=64, proto=0, dscp=0
35
+ super()
36
+ @ip_id = ip_id
37
+ @offset = offset
38
+ @ttl = ttl
39
+ @proto = proto
40
+ @src = src
41
+ @dst = dst
42
+ @dscp = dscp
43
+ end
44
+
45
+ def v4?
46
+ true
47
+ end
48
+
49
+ def flow_id
50
+ if not @payload or @payload.is_a? String
51
+ [:ipv4, @proto, @src, @dst]
52
+ else
53
+ [:ipv4, @src, @dst, @payload.flow_id]
54
+ end
55
+ end
56
+
57
+ NTOP = {} # Network to human cache
58
+ HTON = {} # Human to network cache
59
+
60
+ def self.from_bytes bytes
61
+ bytes.length >= 20 or
62
+ raise ParseError, "Truncated IPv4 header: expected at least 20 bytes, got #{bytes.length} bytes"
63
+
64
+ vhl, tos, length, id, offset, ttl, proto, checksum, src, dst = bytes[0, 20].unpack FMT_HEADER
65
+ version = vhl >> 4
66
+ hl = (vhl & 0b1111) * 4
67
+
68
+ version == 4 or
69
+ raise ParseError, "Wrong IPv4 version: got (#{version})"
70
+ hl >= 20 or
71
+ raise ParseError, "Bad IPv4 header length: expected at least 20 bytes raise ParseError, got #{hl} bytes"
72
+ bytes.length >= hl or
73
+ raise ParseError, "Truncated IPv4 header: expected #{hl} bytes raise ParseError, got #{bytes.length} bytes"
74
+ length >= 20 or
75
+ raise ParseError, "Bad IPv4 packet length: expected at least 20 bytes raise ParseError, got #{length} bytes"
76
+ bytes.length >= length or
77
+ raise ParseError, "Truncated IPv4 packet: expected #{length} bytes raise ParseError, got #{bytes.length} bytes"
78
+
79
+ if hl != 20
80
+ IPv4.check_options bytes[20, hl-20]
81
+ end
82
+
83
+ src = NTOP[src] ||= IPAddr.ntop(src)
84
+ dst = NTOP[dst] ||= IPAddr.ntop(dst)
85
+ dscp = tos >> 2
86
+ ipv4 = IPv4.new(src, dst, id, offset, ttl, proto, dscp)
87
+ ipv4.payload_raw = bytes[hl..-1]
88
+
89
+ payload = bytes[hl...length]
90
+ if offset & (IP_OFFMASK | IP_MF) == 0
91
+ begin
92
+ case proto
93
+ when IPPROTO_TCP
94
+ ipv4.payload = TCP.from_bytes payload
95
+ when IPPROTO_UDP
96
+ ipv4.payload = UDP.from_bytes payload
97
+ when IPPROTO_SCTP
98
+ #ipv4.payload = SCTP.from_bytes payload
99
+ ipv4.payload = payload
100
+ else
101
+ ipv4.payload = payload
102
+ end
103
+ rescue ParseError => e
104
+ Pcap.warning e
105
+ end
106
+ else
107
+ ipv4.payload = payload
108
+ end
109
+ return ipv4
110
+ end
111
+
112
+ def write io
113
+ if @payload.is_a? String
114
+ payload = @payload
115
+ else
116
+ string_io = StringIO.new
117
+ @payload.write string_io, self
118
+ string_io.close
119
+ payload = string_io.string
120
+ end
121
+ length = 20 + payload.bytesize
122
+ if length > 65535
123
+ Pcap.warning "IPv4 payload is too large"
124
+ end
125
+
126
+ src = HTON[@src] ||= IPAddr.new(@src).hton
127
+ dst = HTON[@dst] ||= IPAddr.new(@dst).hton
128
+ fields = [0x45, @dscp << 2, length, @ip_id, @offset, @ttl, @proto, 0, src, dst]
129
+ header = fields.pack(FMT_HEADER)
130
+ fields[7] = IP.checksum(header)
131
+ header = fields.pack(FMT_HEADER)
132
+ io.write header
133
+ io.write payload
134
+ end
135
+
136
+ FMT_PSEUDO_HEADER = 'a4a4CCn'
137
+
138
+ def pseudo_header payload_length
139
+ src = HTON[@src] ||= IPAddr.new(@src).hton
140
+ dst = HTON[@dst] ||= IPAddr.new(@dst).hton
141
+ return [src, dst, 0, @proto, payload_length].pack(FMT_PSEUDO_HEADER)
142
+ end
143
+
144
+ def fragment?
145
+ return (@offset & (IP_OFFMASK | IP_MF) != 0)
146
+ end
147
+
148
+ # Check that IP or TCP options are valid. Do nothing if they are valid.
149
+ # Both IP and TCP options are 8-bit TLVs with an inclusive length. Both
150
+ # have one byte options 0 and 1.
151
+ def self.check_options options, label='IPv4'
152
+ while not options.empty?
153
+ type = options.slice!(0, 1)[0].ord
154
+ if type == 0 or type == 1
155
+ next
156
+ end
157
+ Pcap.assert !options.empty?,
158
+ "#{label} option #{type} is missing the length field"
159
+ length = options.slice!(0, 1)[0].ord
160
+ Pcap.assert length >= 2,
161
+ "#{label} option #{type} has invalid length: #{length}"
162
+ Pcap.assert length - 2 <= options.length,
163
+ "#{label} option #{type} has truncated data"
164
+ options.slice! 0, length - 2
165
+ end
166
+ end
167
+
168
+ ReassembleState = ::Struct.new :packets, :bytes, :mf, :overlap
169
+
170
+ # Reassemble fragmented IPv4 packets
171
+ def self.reassemble packets
172
+ reassembled_packets = []
173
+ flow_id_to_state = {}
174
+ packets.each do |packet|
175
+ if not packet.is_a?(Ethernet) or not packet.payload.is_a?(IPv4)
176
+ # Ignore non-IPv4 packet
177
+ elsif not packet.payload.fragment?
178
+ # Ignore non-fragments
179
+ else
180
+ # Get reassembly state
181
+ ip = packet.payload
182
+ flow_id = [ip.ip_id, ip.proto, ip.src, ip.dst]
183
+ state = flow_id_to_state[flow_id]
184
+ if not state
185
+ state = ReassembleState.new [], [], true, false
186
+ flow_id_to_state[flow_id] = state
187
+ end
188
+ state.packets << packet
189
+
190
+ # Clear the more-fragments flag if no more fragments
191
+ if ip.offset & IP_MF == 0
192
+ state.mf = false
193
+ end
194
+
195
+ # Add the bytes
196
+ start = (ip.offset & IP_OFFMASK) * 8
197
+ finish = start + ip.payload.length
198
+ state.bytes.fill nil, start, finish - start
199
+ start.upto(finish-1) do |i|
200
+ if not state.bytes[i]
201
+ byte = ip.payload[i - start].chr
202
+ state.bytes[i] = byte
203
+ elsif not state.overlap
204
+ name = "%s:%s:%d" % [ip.src, ip.dst, ip.proto]
205
+ Pcap.warning \
206
+ "IPv4 flow #{name} contains overlapping fragements"
207
+ state.overlap = true
208
+ end
209
+ end
210
+
211
+ # We're done if we've received a fragment without the
212
+ # more-fragments flag and all the bytes in the buffer have been
213
+ # set.
214
+ if not state.mf and state.bytes.all?
215
+ # Remove fragments from reassembled_packets
216
+ state.packets.each do |packet|
217
+ reassembled_packets.delete_if do |reassembled_packet|
218
+ packet.object_id == reassembled_packet.object_id
219
+ end
220
+ end
221
+ # Remove state
222
+ flow_id_to_state.delete flow_id
223
+ # Create new packet
224
+ packet = state.packets[0].deepdup
225
+ ipv4 = packet.payload
226
+ ipv4.offset = 0
227
+ ipv4.payload = state.bytes.join
228
+ # Decode
229
+ begin
230
+ case ipv4.proto
231
+ when IPPROTO_TCP
232
+ ipv4.payload = TCP.from_bytes ipv4.payload
233
+ when IPPROTO_UDP
234
+ ipv4.payload = UDP.from_bytes ipv4.payload
235
+ when IPPROTO_SCTP
236
+ ipv4.payload = SCTP.from_bytes ipv4.payload
237
+ end
238
+ rescue ParseError => e
239
+ Pcap.warning e
240
+ end
241
+ end
242
+ end
243
+ reassembled_packets << packet
244
+ end
245
+ if !flow_id_to_state.empty?
246
+ Pcap.warning \
247
+ "#{flow_id_to_state.length} flow(s) have IPv4 fragments " \
248
+ "that can't be reassembled"
249
+ end
250
+
251
+ return reassembled_packets
252
+ end
253
+
254
+ def to_s
255
+ if @payload.is_a? String
256
+ payload = @payload.inspect
257
+ else
258
+ payload = @payload.to_s
259
+ end
260
+ return "ipv4(%d, %s, %s, %s)" % [@proto, @src, @dst, payload]
261
+ end
262
+
263
+ def == other
264
+ return super &&
265
+ self.proto == other.proto &&
266
+ self.ip_id == other.ip_id &&
267
+ self.offset == other.offset &&
268
+ self.ttl == other.ttl &&
269
+ self.dscp == other.dscp
270
+ end
271
+ end
272
+
273
+ end
274
+ end
@@ -0,0 +1,149 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # http://www.mudynamics.com
3
+ # http://labs.mudynamics.com
4
+ # http://www.pcapr.net
5
+
6
+ require 'ipaddr'
7
+
8
+ module Mu
9
+ class Pcap
10
+
11
+ class IPv6 < IP
12
+ FORMAT = 'NnCCa16a16'
13
+
14
+ attr_accessor :next_header, :hop_limit
15
+
16
+ def initialize
17
+ super
18
+ @next_header = 0
19
+ @hop_limit = 64
20
+ end
21
+
22
+ def v6?
23
+ return true
24
+ end
25
+
26
+ alias :proto :next_header
27
+ alias :ttl :hop_limit
28
+
29
+ def flow_id
30
+ if not @payload or @payload.is_a? String
31
+ return [:ipv6, @next_header, @src, @dst]
32
+ else
33
+ return [:ipv6, @src, @dst, @payload.flow_id]
34
+ end
35
+ end
36
+
37
+ def self.from_bytes bytes
38
+ Pcap.assert bytes.bytesize >= 40, 'Truncated IPv6 header: ' +
39
+ "expected at least 40 bytes, got #{bytes.bytesize} bytes"
40
+
41
+ vcl, length, next_header, hop_limit, src, dst =
42
+ bytes[0, 40].unpack FORMAT
43
+ version = vcl >> 28 & 0x0f
44
+ traffic_class = vcl >> 20 & 0xff
45
+ flow_label = vcl & 0xfffff
46
+
47
+ Pcap.assert version == 6, "Wrong IPv6 version: got (#{version})"
48
+ Pcap.assert bytes.length >= (40 + length), 'Truncated IPv6 header: ' +
49
+ "expected #{length + 40} bytes, got #{bytes.length} bytes"
50
+
51
+ ipv6 = IPv6.new
52
+ ipv6.next_header = next_header
53
+ ipv6.hop_limit = hop_limit
54
+ ipv6.src = IPAddr.new_ntoh(src).to_s
55
+ ipv6.dst = IPAddr.new_ntoh(dst).to_s
56
+
57
+ ipv6.payload_raw = bytes[40..-1]
58
+ ipv6.next_header, ipv6.payload =
59
+ payload_from_bytes ipv6, ipv6.next_header, bytes[40...40+length]
60
+
61
+ return ipv6
62
+ end
63
+
64
+ # Parse bytes and returns next_header and payload. Skips extension
65
+ # headers.
66
+ def self.payload_from_bytes ipv6, next_header, bytes
67
+ begin
68
+ case next_header
69
+ when IPPROTO_TCP
70
+ payload = TCP.from_bytes bytes
71
+ when IPPROTO_UDP
72
+ payload = UDP.from_bytes bytes
73
+ when IPPROTO_SCTP
74
+ payload = SCTP.from_bytes bytes
75
+ when IPPROTO_HOPOPTS
76
+ next_header, payload = eight_byte_header_from_bytes(ipv6,
77
+ bytes, 'hop-by-hop options')
78
+ when IPPROTO_ROUTING
79
+ next_header, payload = eight_byte_header_from_bytes(ipv6,
80
+ bytes, 'routing')
81
+ when IPPROTO_DSTOPTS
82
+ next_header, payload = eight_byte_header_from_bytes(ipv6,
83
+ bytes, 'destination options')
84
+ when IPPROTO_FRAGMENT
85
+ Pcap.assert bytes.length >= 8,
86
+ "Truncated IPv6 fragment header"
87
+ Pcap.assert false, 'IPv6 fragments are not supported'
88
+ when IPPROTO_AH
89
+ next_header, payload = ah_header_from_bytes(ipv6,
90
+ bytes, 'authentication header')
91
+ when IPPROTO_NONE
92
+ payload = ''
93
+ else
94
+ payload = bytes
95
+ end
96
+ rescue ParseError => e
97
+ Pcap.warning e
98
+ payload = bytes
99
+ end
100
+ return [next_header, payload]
101
+ end
102
+
103
+ # Parse extension header that's a multiple of 8 bytes
104
+ def self.eight_byte_header_from_bytes ipv6, bytes, name
105
+ Pcap.assert bytes.length >= 8, "Truncated IPv6 #{name} header"
106
+ length = (bytes[1].ord + 1) * 8
107
+ Pcap.assert bytes.length >= length, "Truncated IPv6 #{name} header"
108
+ return payload_from_bytes(ipv6, bytes[0].ord, bytes[length..-1])
109
+ end
110
+
111
+ # Parse authentication header (whose length field is interpeted differently)
112
+ def self.ah_header_from_bytes ipv6, bytes, name
113
+ Pcap.assert bytes.length >= 8, "Truncated IPv6 #{name} header"
114
+ length = (bytes[1].ord + 2) * 4
115
+ Pcap.assert bytes.length >= length, "Truncated IPv6 #{name} header"
116
+ return payload_from_bytes(ipv6, bytes[0].ord, bytes[length..-1])
117
+ end
118
+
119
+ def write io
120
+ if @payload.is_a? String
121
+ payload = @payload
122
+ else
123
+ string_io = StringIO.new
124
+ @payload.write string_io, self
125
+ payload = string_io.string
126
+ end
127
+ src = IPAddr.new(@src, Socket::AF_INET6).hton
128
+ dst = IPAddr.new(@dst, Socket::AF_INET6).hton
129
+ header = [0x60000000, payload.bytesize, @next_header, @hop_limit,
130
+ src, dst].pack FORMAT
131
+ io.write header
132
+ io.write payload
133
+ end
134
+
135
+ def pseudo_header payload_length
136
+ return IPAddr.new(@src, Socket::AF_INET6).hton +
137
+ IPAddr.new(@dst, Socket::AF_INET6).hton +
138
+ [payload_length, '', @next_header].pack('Na3C')
139
+ end
140
+
141
+ def == other
142
+ return super &&
143
+ self.next_header == other.next_header &&
144
+ self.hop_limit == other.hop_limit
145
+ end
146
+ end
147
+
148
+ end
149
+ end
@@ -0,0 +1,106 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # http://www.mudynamics.com
3
+ # http://labs.mudynamics.com
4
+ # http://www.pcapr.net
5
+
6
+ module Mu
7
+ class Pcap
8
+
9
+ class Packet
10
+ attr_accessor :payload, :payload_raw
11
+
12
+ def initialize
13
+ @payload = ''
14
+ @payload_raw = ''
15
+ end
16
+
17
+ # Get payload as bytes. If the payload is a parsed object, returns
18
+ # raw payload. Otherwise return unparsed bytes.
19
+ def payload_bytes
20
+ if @payload.is_a? String
21
+ return @payload
22
+ end
23
+ return @payload_raw
24
+ end
25
+
26
+ def deepdup
27
+ dup = self.dup
28
+ if @payload.respond_to? :deepdup
29
+ dup.payload = @payload.deepdup
30
+ else
31
+ dup.payload = @payload.dup
32
+ end
33
+ return dup
34
+ end
35
+
36
+ def flow_id
37
+ raise NotImplementedError
38
+ end
39
+
40
+ # Reassemble, reorder, and merge packets.
41
+ def self.normalize packets
42
+ begin
43
+ packets = TCP.reorder packets
44
+ rescue TCP::ReorderError => e
45
+ Pcap.warning e
46
+ end
47
+
48
+ begin
49
+ packets = SCTP.reorder packets
50
+ rescue SCTP::ReorderError => e
51
+ Pcap.warning e
52
+ end
53
+
54
+ begin
55
+ packets = TCP.merge packets
56
+ rescue TCP::MergeError => e
57
+ Pcap.warning e
58
+ end
59
+ return packets
60
+ end
61
+
62
+ # Remove non-L7/DNS/DHCP traffic if there is L7 traffic. Returns
63
+ # original packets if there is no L7 traffic.
64
+ IGNORE_UDP_PORTS = [
65
+ 53, # DNS
66
+ 67, 68, # DHCP
67
+ 546, 547 # DHCPv6
68
+ ]
69
+
70
+ def self.isolate_l7 packets
71
+ cleaned_packets = []
72
+ packets.each do |packet|
73
+ if TCP.tcp? packet
74
+ cleaned_packets << packet
75
+ elsif UDP.udp? packet
76
+ src_port = packet.payload.payload.src_port
77
+ dst_port = packet.payload.payload.dst_port
78
+ if not IGNORE_UDP_PORTS.member? src_port and
79
+ not IGNORE_UDP_PORTS.member? dst_port
80
+ cleaned_packets << packet
81
+ end
82
+ elsif SCTP.sctp? packet
83
+ cleaned_packets << packet
84
+ end
85
+ end
86
+ if cleaned_packets.empty?
87
+ return packets
88
+ end
89
+ return cleaned_packets
90
+ end
91
+
92
+ def to_bytes
93
+ io = StringIO.new
94
+ write io
95
+ io.close
96
+ return "#{io.string}\0"
97
+ end
98
+
99
+ def == other
100
+ return self.class == other.class && self.payload == other.payload &&
101
+ self.payload_raw == other.payload_raw
102
+ end
103
+ end
104
+
105
+ end
106
+ end