simple_capture 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d8ab97c1d77026f80dc16f0e798a730078d52f9323b9038769c5d60c2385a1a3
4
+ data.tar.gz: 6fc14246c88e07be902c1dae27ec8ac268f6db4d6d144b414f5902f0ff0d1170
5
+ SHA512:
6
+ metadata.gz: c600259cbe23284c1ba1e27eac9430da64c841c4c0879b850ca8f7c092df0e711aec3335dc3fd827ed206c5df1b16b94c8bb9994a571ee9f32b0c669bec69ebf
7
+ data.tar.gz: 94b33abf943b6a48c13e23e1cc4423171427f15e001e384c8d279903429c3bb70ae03cb48b5ba2ecac63ac84fd0ffdf0058a4f55dedd3af06faf1d4e6a259bbf
data/.gitignore ADDED
@@ -0,0 +1,57 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ # Ignore Byebug command history file.
17
+ .byebug_history
18
+
19
+ ## Specific to RubyMotion:
20
+ .dat*
21
+ .repl_history
22
+ build/
23
+ *.bridgesupport
24
+ build-iPhoneOS/
25
+ build-iPhoneSimulator/
26
+
27
+ ## Specific to RubyMotion (use of CocoaPods):
28
+ #
29
+ # We recommend against adding the Pods directory to your .gitignore. However
30
+ # you should judge for yourself, the pros and cons are mentioned at:
31
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
32
+ #
33
+ # vendor/Pods/
34
+
35
+ ## Documentation cache and generated files:
36
+ /.yardoc/
37
+ /_yardoc/
38
+ /doc/
39
+ /rdoc/
40
+
41
+ ## Environment normalization:
42
+ /.bundle/
43
+ /vendor/bundle
44
+ /lib/bundler/man/
45
+
46
+ # for a library or gem, you might want to ignore these files since the code is
47
+ # intended to run in multiple environments; otherwise, check them in:
48
+ # Gemfile.lock
49
+ # .ruby-version
50
+ # .ruby-gemset
51
+
52
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53
+ .rvmrc
54
+
55
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
56
+ # .rubocop-https?--*
57
+ simple_capture.code-workspace
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.0.0
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Akira kure
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # SimpleCapture
2
+
3
+ Packet capture tool made only with Ruby
4
+
5
+ ## Installation
6
+
7
+ ## Usage
8
+
9
+
10
+ ## Development
11
+
12
+
13
+ ## Contributing
14
+
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "simple_capture"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,11 @@
1
+ require_relative "simple_capture/version"
2
+ require_relative "simple_capture/capture"
3
+ require_relative "simple_capture/packet"
4
+ require_relative "simple_capture/string"
5
+ require_relative "simple_capture/recv_message"
6
+ require_relative "simple_capture/header/ehter_header"
7
+ require_relative "simple_capture/header/ipv4_header"
8
+ require_relative "simple_capture/header/icmp_header"
9
+
10
+ module SimpleCapture
11
+ end
@@ -0,0 +1,92 @@
1
+ require "socket"
2
+
3
+ module SimpleCapture
4
+ class Capture
5
+ SOL_PACKET = 0x0107 # bits/socket.h
6
+ IFINDEX_SIZE = 0x0004 # sizeof(ifreq.ifr_ifindex) on 64bit
7
+ IFREQ_SIZE = 0x0028 # sizeof(ifreq) on 64bit
8
+ SIOCGIFINDEX = 0x8933 # bits/ioctls.h
9
+ PACKET_MR_PROMISC = 0x0001 # netpacket/packet.h
10
+ PACKET_MREQ_SIZE = 0x0010 # sizeof(packet_mreq) on 64bit
11
+ PACKET_ADD_MEMBERSHIP = 0x0001 # netpacket/packet.h
12
+ ETH_P_ALL = 768 # htons(ETH_P_ALL), linux/if_ether.h
13
+
14
+ # @param [String] interface_name
15
+ def initialize(interface_name)
16
+ @interface_name = interface_name
17
+ end
18
+
19
+ # Run Capture
20
+ def run
21
+ socket = generate_socket(@interface_name)
22
+ cap_loop(socket)
23
+ end
24
+
25
+ private
26
+
27
+ def cap_loop(socket)
28
+ while true
29
+ mesg, _ = socket.recvfrom(1500)
30
+ packet = RecvMessageHandler.new(mesg).to_packet
31
+ packet.dump
32
+ end
33
+ end
34
+
35
+ def bind_if(socket, interface_name)
36
+ index_str = mr_ifindex(interface_name)
37
+
38
+ eth_p_all_hbo = [ ETH_P_ALL ].pack('S').unpack('S>').first
39
+ sll = [ Socket::AF_PACKET, eth_p_all_hbo, index_str ].pack('SS>a16')
40
+ socket.bind(sll)
41
+ end
42
+
43
+ # @return [Integer]
44
+ def if_name_to_index(if_name)
45
+ Socket.getifaddrs.find do |ifaddr|
46
+ ifaddr.name == if_name
47
+ end&.ifindex
48
+ end
49
+
50
+ def generate_socket(interface_name)
51
+ socket = Socket.new(Socket::AF_PACKET, Socket::SOCK_RAW, ETH_P_ALL)
52
+ bind_if(socket, interface_name)
53
+ socket_promiscuous(socket, interface_name)
54
+ socket
55
+ end
56
+
57
+ def mr_ifindex(if_name)
58
+ [[if_name_to_index(if_name)].pack("c")].pack("a4")
59
+ end
60
+
61
+ def mr_type
62
+ [PACKET_MR_PROMISC].pack("S")
63
+ end
64
+
65
+ def mr_alen
66
+ [0].pack("S")
67
+ end
68
+
69
+ def mr_address
70
+ [0].pack("C")*8
71
+ end
72
+
73
+ #
74
+ # https://linuxjm.osdn.jp/html/LDP_man-pages/man7/packet.7.html
75
+ # struct packet_mreq {
76
+ # int mr_ifindex; 4Byte
77
+ # unsigned short mr_type; 2Byte
78
+ # unsigned short mr_alen; 2Byte
79
+ # unsigned char mr_address[8]; 1Byte * 8
80
+ #};
81
+ #
82
+ # @param [String]
83
+ # @return [String]
84
+ def mreq(interface)
85
+ mr_ifindex(interface) + mr_type + mr_alen + mr_address
86
+ end
87
+
88
+ def socket_promiscuous(socket, interface_name)
89
+ socket.setsockopt(SOL_PACKET, PACKET_ADD_MEMBERSHIP, mreq(interface_name))
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,70 @@
1
+ module SimpleCapture
2
+ class EtherHeader
3
+ IPv4 = 0x0800
4
+
5
+ attr_reader :dst_mac_address, :src_mac_address, :type
6
+
7
+ # @param [Array<Integer>] [10, 46, ...]
8
+ def initialize(bytes: nil)
9
+ # support 14Byte EhterHeader only now.
10
+ raise ArgumentError, "bytes's size must be 10Byte" unless bytes.size == 14
11
+
12
+ convert_bytes_to_headers(bytes) unless bytes.nil?
13
+ end
14
+
15
+ # @return [Boolean]
16
+ def upper_layer_protocol_ipv4?
17
+ type_hex = type.map { |byte| byte.to_s(16).rjust(2, "0") }
18
+ type_hex.join.to_i(16) == IPv4
19
+ end
20
+
21
+ # Print Header Info
22
+ def dump
23
+ puts "■ether header------------------------------".red
24
+ print_dst_mac_address
25
+ print_src_mac_address
26
+ print_type
27
+ end
28
+
29
+ private
30
+
31
+ def convert_bytes_to_headers(bytes)
32
+ @dst_mac_address = bytes[0..5]
33
+ @src_mac_address = bytes[6..11]
34
+ @type = bytes[12..13]
35
+ end
36
+
37
+ def print_dst_mac_address
38
+ hex_dst_mac_address = dst_mac_address.map { |byte| byte.to_s(16) }
39
+
40
+ puts "dst_mac_address = #{hex_dst_mac_address[0]}:\
41
+ #{hex_dst_mac_address[1]}:\
42
+ #{hex_dst_mac_address[2]}:\
43
+ #{hex_dst_mac_address[3]}:\
44
+ #{hex_dst_mac_address[4]}:\
45
+ #{hex_dst_mac_address[5]}"
46
+ end
47
+
48
+ def print_src_mac_address
49
+ hex_src_mac_address = src_mac_address.map { |byte| byte.to_s(16) }
50
+
51
+ puts "src_mac_address = #{hex_src_mac_address[0]}:\
52
+ #{hex_src_mac_address[1]}:\
53
+ #{hex_src_mac_address[2]}:\
54
+ #{hex_src_mac_address[3]}:\
55
+ #{hex_src_mac_address[4]}:\
56
+ #{hex_src_mac_address[5]}"
57
+ end
58
+
59
+ def print_type
60
+ type_hex = type.map { |byte| byte.to_s(16).rjust(2, "0") }
61
+ type_hex_int = type_hex.join.to_i(16) # ["08", "00"]
62
+ protocol_display = if type_hex_int == IPv4
63
+ "IPv4"
64
+ else
65
+ "[UnKnown Protocol]"
66
+ end
67
+ puts "protocol = #{protocol_display}"
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,76 @@
1
+ module SimpleCapture
2
+ class ICMPHeader
3
+ attr_reader :type, :code, :checksum, :id, :seq_number, :data
4
+
5
+ # @param [Array<Integer>] [10, 46, ...]
6
+ def initialize(bytes: nil)
7
+ convert_bytes_to_header(bytes) unless bytes.nil?
8
+ end
9
+
10
+ def dump
11
+ puts "■icmp--------------------------------------".blue
12
+ print_checksum
13
+ print_code
14
+ print_type
15
+ print_id
16
+ print_seqnumber
17
+ print_data
18
+ end
19
+
20
+ private
21
+
22
+ def print_checksum
23
+ puts "checksum = 0x#{combine_2bits_in_hex(checksum).to_s(16)}"
24
+ end
25
+
26
+ def print_code
27
+ puts "code = #{code}"
28
+ end
29
+
30
+ def print_data
31
+ puts "data = "
32
+ data.each_slice(10) do |data10|
33
+ data10.each { |data_| print "0x#{data_.to_s(16)} " }
34
+ puts "\n"
35
+ end
36
+ end
37
+
38
+ def print_id
39
+ if id
40
+ puts "id = 0x#{combine_2bits_in_hex(id).to_s(16)}"
41
+ end
42
+ end
43
+
44
+ def print_seqnumber
45
+ if seq_number
46
+ puts "seq_number = 0x#{combine_2bits_in_hex(seq_number).to_s(16)}"
47
+ end
48
+ end
49
+
50
+ def print_type
51
+ puts "type = #{type}"
52
+ end
53
+
54
+ # Combine 2 bits of numbers in hexadecimal
55
+ #
56
+ # @param [Array<Integer>] [0d80, 0d30]
57
+ # @return [Integer] 0x501e... 0d80 -> 0x50, 0d30 -> 0x1e
58
+ def combine_2bits_in_hex(bytes)
59
+ (bytes[0].to_s(16) + bytes[1].to_s(16)).to_i(16)
60
+ end
61
+
62
+ def convert_bytes_to_header(bytes)
63
+ @type = bytes[0]
64
+ @code = bytes[1]
65
+ @checksum = bytes[2..3]
66
+
67
+ if @type == 0 || 8
68
+ @id = bytes[4..5]
69
+ @seq_number = bytes[6..7]
70
+ @data = bytes[8..(bytes.size-1)]
71
+ else
72
+ @data = bytes[4..(bytes.size-1)]
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,117 @@
1
+ module SimpleCapture
2
+ class IPv4Header
3
+ ICMP = 1
4
+
5
+ attr_reader :version, :ihl, :type_of_service, :length, :id, :flags, :offset, :ttl,
6
+ :checksum, :src_addr, :dst_addr, :protocol
7
+
8
+ # @param [Array<Integer>] 各バイトの数値の配列、[10, 46, ...]
9
+ def initialize(bytes: nil)
10
+ # support 20Byte IPHeader only now.
11
+ raise ArgumentError, "bytes's size must be 20Byte" unless bytes.size == 20
12
+
13
+ convert_bytes_to_header(bytes) unless bytes.nil?
14
+ end
15
+
16
+ def dump
17
+ puts "■ipv4--------------------------------------".yellow
18
+ print_version
19
+ print_ihl
20
+ print_type_of_service
21
+ print_length
22
+ print_id
23
+ print_flags
24
+ print_offset
25
+ print_ttl
26
+ print_protocol
27
+ print_checksum
28
+ print_src_addr
29
+ print_dst_addr
30
+ end
31
+
32
+ def upper_layer_protocol_icmp?
33
+ protocol == ICMP
34
+ end
35
+
36
+ private
37
+
38
+ # Combine 2 bits of numbers in hexadecimal
39
+ #
40
+ # @param [Array<Integer>] [0d80, 0d30]
41
+ # @return [Integer] 0x501e... 0d80 -> 0x50, 0d30 -> 0x1e
42
+ def combine_2bits_in_hex(bytes)
43
+ bytes_hex = bytes.map { |byte| byte.to_s(16).rjust(2, "0") }
44
+ bytes_hex.join.to_i(16)
45
+
46
+ # (bytes[0].to_s(16) + bytes[1].to_s(16)).to_i(16)
47
+ end
48
+
49
+ def convert_bytes_to_header(bytes)
50
+ @version = bytes[0][4, 4]
51
+ @ihl = bytes[0][0, 4]
52
+ @type_of_service = bytes[1]
53
+ @length = bytes[2..3]
54
+ @id = bytes[4..5]
55
+ bytes67 = combine_2bits_in_hex(bytes[6..7])
56
+ @flags = bytes67[0, 3]
57
+ @offset = bytes67[3, 13]
58
+ @ttl = bytes[8]
59
+ @protocol = bytes[9]
60
+ @checksum = bytes[10..11]
61
+ @src_addr = bytes[12..15]
62
+ @dst_addr = bytes[16..19]
63
+ end
64
+
65
+ def print_checksum
66
+ puts "checksum = 0x#{combine_2bits_in_hex(checksum).to_s(16)}"
67
+ end
68
+
69
+ def print_dst_addr
70
+ puts "dst_addr = #{dst_addr}"
71
+ end
72
+
73
+ def print_flags
74
+ puts "flags = #{flags}"
75
+ end
76
+
77
+ def print_id
78
+ puts "id = 0x#{combine_2bits_in_hex(id).to_s(16)}\n"
79
+ end
80
+
81
+ def print_ihl
82
+ puts "ihl = #{ihl}"
83
+ end
84
+
85
+ def print_length
86
+ puts "length = 0x#{combine_2bits_in_hex(length).to_s(16)}"
87
+ end
88
+
89
+ def print_offset
90
+ puts "offset = #{offset}"
91
+ end
92
+
93
+ def print_protocol
94
+ if protocol == ICMP
95
+ puts "protocol = ICMP"
96
+ else
97
+ puts "protocol = [UnKnown Protocol]"
98
+ end
99
+ end
100
+
101
+ def print_src_addr
102
+ puts "src_addr = #{src_addr}"
103
+ end
104
+
105
+ def print_type_of_service
106
+ puts "type_of_service = #{type_of_service}"
107
+ end
108
+
109
+ def print_ttl
110
+ puts "ttl = #{ttl}"
111
+ end
112
+
113
+ def print_version
114
+ puts "version = #{version}"
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,18 @@
1
+ module SimpleCapture
2
+ class Packet
3
+
4
+ # @param [Array] headers
5
+ def initialize(headers)
6
+ @headers = headers
7
+ end
8
+
9
+ def dump
10
+ puts "\n■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■".green
11
+ puts "Display Packet".green
12
+ puts "■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■".green
13
+ @headers.each do |header|
14
+ header.dump
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module SimpleCapture
2
+ class RecvMessageHandler
3
+ def initialize(mesg)
4
+ @mesg = mesg
5
+ end
6
+
7
+ # @return [Packet]
8
+ def to_packet
9
+ headers = []
10
+ ether = SimpleCapture::EtherHeader.new(bytes: @mesg.bytes[0..13])
11
+ headers.push(ether)
12
+
13
+ if ether.upper_layer_protocol_ipv4?
14
+ ip = SimpleCapture::IPv4Header.new(bytes: @mesg.bytes[14..33])
15
+ headers.push(ip)
16
+ if ip.upper_layer_protocol_icmp?
17
+ icmp = SimpleCapture::ICMPHeader.new(bytes: @mesg.bytes[34..(@mesg.bytes.size-1)])
18
+ headers.push(icmp)
19
+ end
20
+ end
21
+ SimpleCapture::Packet.new(headers)
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,25 @@
1
+ class String
2
+ def colorize(color_code)
3
+ "\e[#{color_code}m#{self}\e[0m"
4
+ end
5
+
6
+ def red
7
+ colorize(31)
8
+ end
9
+
10
+ def green
11
+ colorize(32)
12
+ end
13
+
14
+ def yellow
15
+ colorize(33)
16
+ end
17
+
18
+ def blue
19
+ colorize(34)
20
+ end
21
+
22
+ def pink
23
+ colorize(35)
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module SimpleCapture
2
+ VERSION = "0.1.0"
3
+ end
data/sample_run.rb ADDED
@@ -0,0 +1,4 @@
1
+ require_relative "lib/simple_capture"
2
+
3
+ cap = SimpleCapture::Capture.new("eth1")
4
+ cap.run
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/simple_capture/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "simple_capture"
7
+ spec.version = SimpleCapture::VERSION
8
+ spec.authors = ["Akira Kure"]
9
+ spec.email = ["kuredev@gmail.com"]
10
+
11
+ spec.summary = "Packet capture tool made only with Ruby."
12
+ spec.description = "Packet capture tool made only with Ruby."
13
+ spec.homepage = "https://github.com/kuredev/simple_capture"
14
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
15
+
16
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
17
+
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = "https://github.com/kuredev/simple_capture"
20
+ spec.metadata["changelog_uri"] = "https://github.com/kuredev/simple_capture"
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
26
+ end
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+
31
+ # Uncomment to register a new dependency of your gem
32
+ # spec.add_dependency "example-gem", "~> 1.0"
33
+
34
+ # For more information and examples about making a new gem, checkout our
35
+ # guide at: https://bundler.io/guides/creating_gem.html
36
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_capture
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Akira Kure
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-02-22 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Packet capture tool made only with Ruby.
14
+ email:
15
+ - kuredev@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - ".ruby-version"
22
+ - LICENSE
23
+ - README.md
24
+ - Rakefile
25
+ - bin/console
26
+ - bin/setup
27
+ - lib/simple_capture.rb
28
+ - lib/simple_capture/capture.rb
29
+ - lib/simple_capture/header/ehter_header.rb
30
+ - lib/simple_capture/header/icmp_header.rb
31
+ - lib/simple_capture/header/ipv4_header.rb
32
+ - lib/simple_capture/packet.rb
33
+ - lib/simple_capture/recv_message.rb
34
+ - lib/simple_capture/string.rb
35
+ - lib/simple_capture/version.rb
36
+ - sample_run.rb
37
+ - simple_capture.gemspec
38
+ homepage: https://github.com/kuredev/simple_capture
39
+ licenses: []
40
+ metadata:
41
+ allowed_push_host: https://rubygems.org
42
+ homepage_uri: https://github.com/kuredev/simple_capture
43
+ source_code_uri: https://github.com/kuredev/simple_capture
44
+ changelog_uri: https://github.com/kuredev/simple_capture
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 2.3.0
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubygems_version: 3.2.3
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: Packet capture tool made only with Ruby.
64
+ test_files: []