packetman 0.1.1 → 0.1.2
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.
- checksums.yaml +4 -4
- data/README.md +5 -1
- data/exe/packetman +1 -1
- data/lib/packetman.rb +3 -1
- data/lib/packetman/clause.rb +26 -0
- data/lib/packetman/config.rb +15 -14
- data/lib/packetman/filter.rb +89 -0
- data/lib/packetman/version.rb +1 -1
- metadata +4 -3
- data/lib/packetman/compose.rb +0 -93
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a30c3ba57b035cf5927580b722a5651aefc55317
|
4
|
+
data.tar.gz: 68c4aa0507610985b538da8e6b8b432ffbd6aa49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 976a934d36e13ceb1593728d7067198bbbe78d036da0a600ffa58703483709ca35c813feb3198aa3575ed9f6c9ca680a96572c31a05358ee542438c5d248fec3
|
7
|
+
data.tar.gz: 727bf261f5a87940af9abd8e636272dce8d1e2de7746976b2079b2b6dff2717da849fbd780b0da17df47ee2fed1a981f48ae0e7ce7cdb52ad7e61cd532f8354f
|
data/README.md
CHANGED
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
Advanced tcpdump and Wireshark capture generator.
|
4
4
|
|
5
|
-
[](http://badge.fury.io/rb/packetman)
|
5
|
+
[](http://badge.fury.io/rb/packetman)
|
6
|
+
[](https://codeclimate.com/github/jescholl/packetman/coverage)
|
7
|
+
[](http://inch-ci.org/github/jescholl/packetman)
|
8
|
+
[](https://circleci.com/gh/jescholl/packetman)
|
9
|
+
[](https://codeclimate.com/github/jescholl/packetman)
|
6
10
|
|
7
11
|
Packetman is a packet capture filter generator modeled after [Wireshark's String-Matching Capture Filter Generator](https://www.wireshark.org/tools/string-cf.html) but with a lot more features allowing much finer control over the packets you see.
|
8
12
|
|
data/exe/packetman
CHANGED
data/lib/packetman.rb
CHANGED
@@ -3,7 +3,8 @@ require "packetman/version"
|
|
3
3
|
require "packetman/config"
|
4
4
|
require "packetman/config_methods"
|
5
5
|
require "packetman/table"
|
6
|
-
require "packetman/
|
6
|
+
require "packetman/filter"
|
7
|
+
require "packetman/clause"
|
7
8
|
|
8
9
|
module Packetman
|
9
10
|
class << self
|
@@ -15,5 +16,6 @@ module Packetman
|
|
15
16
|
def config!
|
16
17
|
@config = Config.new
|
17
18
|
end
|
19
|
+
|
18
20
|
end
|
19
21
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Packetman
|
2
|
+
class Clause
|
3
|
+
include ConfigMethods
|
4
|
+
|
5
|
+
attr_accessor :search, :mask, :offset
|
6
|
+
|
7
|
+
def initialize(search, mask, offset)
|
8
|
+
self.search = search
|
9
|
+
self.mask = mask
|
10
|
+
self.offset = offset
|
11
|
+
end
|
12
|
+
|
13
|
+
def start_byte(start_bit)
|
14
|
+
"#{config.payload_query} + #{(config.offset_bits + start_bit)/8}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def data_address(start_bit, data_bits)
|
18
|
+
"#{config.transport}[#{start_byte(start_bit)}:#{data_bits/8}]"
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
"#{data_address(offset, Filter.bit_length(search))} & #{mask} = #{search}"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
data/lib/packetman/config.rb
CHANGED
@@ -2,8 +2,7 @@ require 'optparse'
|
|
2
2
|
|
3
3
|
module Packetman
|
4
4
|
class Config
|
5
|
-
attr_accessor :transport, :application, :use_bytes, :
|
6
|
-
attr_writer :offset
|
5
|
+
attr_accessor :transport, :application, :use_bytes, :radix, :start_with_transport, :offset, :wildcard
|
7
6
|
|
8
7
|
def initialize
|
9
8
|
@transport = "tcp"
|
@@ -18,31 +17,33 @@ module Packetman
|
|
18
17
|
protocols[transport]['payload_query'] unless start_with_transport
|
19
18
|
end
|
20
19
|
|
21
|
-
def
|
20
|
+
def offset_bits
|
22
21
|
if use_bytes
|
23
|
-
|
22
|
+
offset*8
|
24
23
|
else
|
25
|
-
|
24
|
+
offset
|
26
25
|
end
|
27
26
|
end
|
28
27
|
|
29
|
-
def
|
28
|
+
def opts
|
30
29
|
@opts ||= OptionParser.new do |opt|
|
31
30
|
opt.banner = "Usage: #{File.basename($PROGRAM_NAME)} [OPTIONS] FILTER_STRING"
|
32
|
-
opt.on("-p", "--protocol
|
31
|
+
opt.on("-p", "--protocol PROTO", protocols.keys, "Transport Protocol ( #{protocols.keys.join(',')})") { |v| self.transport = v }
|
33
32
|
opt.on("-t", "--transport", "OFFSET starts at transport header instead of data payload") { |v| self.start_with_transport = v }
|
34
|
-
opt.on("-r", "--radix
|
35
|
-
opt.on("-o", "--offset
|
33
|
+
opt.on("-r", "--radix RADIX", Integer, "Treat FILTER_STRING as RADIX instead of String") { |v| self.radix = v }
|
34
|
+
opt.on("-o", "--offset OFFSET", Integer, "Offset in bits") { |v| self.offset = v }
|
36
35
|
opt.on("-b", "--byte-offset", "Use 8-bit bytes instead of bits for offset") { |v| self.use_bytes = v }
|
37
|
-
opt.on("-w", "--
|
36
|
+
opt.on("-w", "--wildcard [CHARACTER=?]", "Treat CHARACTER as single-character wildcard") { |v| raise "invalid wildcard" if v.to_s.length > 1; self.wildcard = v || '?' }
|
38
37
|
opt.on("-v", "--version", "Show version") { puts Packetman::VERSION; exit }
|
39
38
|
end
|
39
|
+
end
|
40
40
|
|
41
|
-
@opts.parse!
|
42
|
-
|
43
|
-
raise "Invalid command line arguments" if ARGV.size != 1
|
44
41
|
|
45
|
-
|
42
|
+
def parse_opts
|
43
|
+
filter_str = ARGV.pop
|
44
|
+
raise "Invalid command line arguments" unless filter_str
|
45
|
+
opts.parse!
|
46
|
+
filter_str
|
46
47
|
end
|
47
48
|
|
48
49
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Packetman
|
2
|
+
class Filter
|
3
|
+
include ConfigMethods
|
4
|
+
|
5
|
+
attr_accessor :input
|
6
|
+
|
7
|
+
def initialize(input)
|
8
|
+
self.input = input
|
9
|
+
yield config if block_given?
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.bit_length(num)
|
13
|
+
case num
|
14
|
+
when /^0x/
|
15
|
+
$'.length * bit_density(16)
|
16
|
+
when /^0b/
|
17
|
+
$'.length * bit_density(2)
|
18
|
+
else
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.bit_density(radix=config.radix)
|
24
|
+
(radix.nil?) ? 8 : Math.log2(radix).to_i
|
25
|
+
end
|
26
|
+
|
27
|
+
def map_chr
|
28
|
+
pad_right(input.scan(/./).map{ |chr| yield chr }.join)
|
29
|
+
end
|
30
|
+
|
31
|
+
def pad_right(bin_str)
|
32
|
+
bin_str.ljust(desired_length, '0')
|
33
|
+
end
|
34
|
+
|
35
|
+
def desired_length
|
36
|
+
((input.length + config.offset_bits)/8.to_f).ceil*8 - config.offset_bits
|
37
|
+
end
|
38
|
+
|
39
|
+
def radix_mask
|
40
|
+
("1"*self.class.bit_density).to_i(2)
|
41
|
+
end
|
42
|
+
|
43
|
+
def mask_chr(chr)
|
44
|
+
if chr == config.wildcard
|
45
|
+
0
|
46
|
+
else
|
47
|
+
radix_mask
|
48
|
+
end.to_s(2).rjust(self.class.bit_density, '0')
|
49
|
+
end
|
50
|
+
|
51
|
+
def bin_chr(chr)
|
52
|
+
chr = '0' if chr == config.wildcard
|
53
|
+
|
54
|
+
if config.radix
|
55
|
+
raise "invalid character '#{chr}' for radix=#{config.radix}" if chr.downcase != chr.to_i(config.radix).to_s(config.radix).downcase
|
56
|
+
chr.to_i(config.radix)
|
57
|
+
else
|
58
|
+
chr.ord
|
59
|
+
end.to_s(2).rjust(self.class.bit_density, '0')
|
60
|
+
end
|
61
|
+
|
62
|
+
def mask_hex
|
63
|
+
hex_encode(map_chr{ |c| mask_chr(c) })
|
64
|
+
end
|
65
|
+
|
66
|
+
def search_hex
|
67
|
+
hex_encode(map_chr{ |c| bin_chr(c) })
|
68
|
+
end
|
69
|
+
|
70
|
+
def hex_encode(bin_str)
|
71
|
+
bin_str.reverse.scan(/.{1,4}/).map{ |chunk|
|
72
|
+
chunk.reverse.to_i(2).to_s(16)
|
73
|
+
}.reverse.join.scan(/.{8}|.{4}|.{2}/).map{ |hex|
|
74
|
+
hex.prepend('0x')
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_s
|
79
|
+
offset = 0
|
80
|
+
[].tap do |filter|
|
81
|
+
search_hex.zip(mask_hex).each do |search, mask|
|
82
|
+
filter << Packetman::Clause.new(search, mask, offset)
|
83
|
+
offset += self.class.bit_length(search)
|
84
|
+
end
|
85
|
+
end.map{ |b| b.to_s }.join(' && ')
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
data/lib/packetman/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: packetman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Scholl
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -104,9 +104,10 @@ files:
|
|
104
104
|
- config/protocols.yml
|
105
105
|
- exe/packetman
|
106
106
|
- lib/packetman.rb
|
107
|
-
- lib/packetman/
|
107
|
+
- lib/packetman/clause.rb
|
108
108
|
- lib/packetman/config.rb
|
109
109
|
- lib/packetman/config_methods.rb
|
110
|
+
- lib/packetman/filter.rb
|
110
111
|
- lib/packetman/table.rb
|
111
112
|
- lib/packetman/version.rb
|
112
113
|
- packetman.gemspec
|
data/lib/packetman/compose.rb
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
module Packetman
|
2
|
-
class Compose
|
3
|
-
include ConfigMethods
|
4
|
-
|
5
|
-
def initialize(input, radix=config.radix)
|
6
|
-
@input = input
|
7
|
-
@radix = radix
|
8
|
-
end
|
9
|
-
|
10
|
-
def desired_length
|
11
|
-
((@input.length + config.offset)/8.to_f).ceil*8 - config.offset
|
12
|
-
end
|
13
|
-
|
14
|
-
def bit_density(radix=@radix)
|
15
|
-
(radix.nil?) ? 8 : Math.log2(radix).to_i
|
16
|
-
end
|
17
|
-
|
18
|
-
def mask_bits
|
19
|
-
shift(@input.scan(/./).map{ |c| mask_chr(c) }.join)
|
20
|
-
end
|
21
|
-
|
22
|
-
def radix_mask
|
23
|
-
("1"*bit_density).to_i(2)
|
24
|
-
end
|
25
|
-
|
26
|
-
def shift(input)
|
27
|
-
input.ljust(desired_length, '0')
|
28
|
-
end
|
29
|
-
|
30
|
-
def search_bits
|
31
|
-
shift(@input.scan(/./).map{ |c| bin_chr(c) }.join)
|
32
|
-
end
|
33
|
-
|
34
|
-
def mask_chr(chr)
|
35
|
-
if chr == '?'
|
36
|
-
raise "wildcards not allowed" unless config.allow_wildcards
|
37
|
-
0
|
38
|
-
else
|
39
|
-
radix_mask
|
40
|
-
end.to_s(2).rjust(bit_density, '0')
|
41
|
-
end
|
42
|
-
|
43
|
-
def bin_chr(chr)
|
44
|
-
if chr == '?'
|
45
|
-
raise "wildcards not allowed" unless config.allow_wildcards
|
46
|
-
chr = '0'
|
47
|
-
end
|
48
|
-
|
49
|
-
if @radix
|
50
|
-
chr.to_i(@radix)
|
51
|
-
else
|
52
|
-
chr.ord
|
53
|
-
end.to_s(2).rjust(bit_density, '0')
|
54
|
-
end
|
55
|
-
|
56
|
-
def mask_hex
|
57
|
-
hex_encode(mask_bits)
|
58
|
-
end
|
59
|
-
|
60
|
-
def search_hex
|
61
|
-
hex_encode(search_bits)
|
62
|
-
end
|
63
|
-
|
64
|
-
def hex_encode(bin_str)
|
65
|
-
bin_str.reverse.scan(/.{1,4}/).map{ |chunk| chunk.reverse.to_i(2).to_s(16) }.reverse.join.scan(/.{8}|.{4}|.{2}/).map{ |hex| hex.prepend('0x') }
|
66
|
-
end
|
67
|
-
|
68
|
-
def bit_length(num)
|
69
|
-
case num
|
70
|
-
when /^0x/
|
71
|
-
$'.length * bit_density(16)
|
72
|
-
when /^0b/
|
73
|
-
$'.length * bit_density(2)
|
74
|
-
else
|
75
|
-
nil
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def start_byte(bit_position)
|
80
|
-
[config.payload_query, (config.offset + bit_position)/8].compact.join(' + ')
|
81
|
-
end
|
82
|
-
|
83
|
-
def data_address(start_bit, bit_length)
|
84
|
-
"#{config.transport}[#{start_byte(start_bit)}:#{bit_length/8}]"
|
85
|
-
end
|
86
|
-
|
87
|
-
def to_s
|
88
|
-
search_hex.zip(mask_hex).map.with_index do |(search, mask),i|
|
89
|
-
"#{data_address(i*32, bit_length(search))} & #{mask} = #{search}"
|
90
|
-
end.join(' && ')
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|