packetman 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Gem Version](https://badge.fury.io/rb/packetman.svg)](http://badge.fury.io/rb/packetman)
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/packetman.svg)](http://badge.fury.io/rb/packetman)
|
6
|
+
[![Test Coverage](https://codeclimate.com/github/jescholl/packetman/badges/coverage.svg)](https://codeclimate.com/github/jescholl/packetman/coverage)
|
7
|
+
[![Inline docs](http://inch-ci.org/github/jescholl/packetman.svg?branch=master)](http://inch-ci.org/github/jescholl/packetman)
|
8
|
+
[![Circle CI](https://circleci.com/gh/jescholl/packetman.svg?style=svg)](https://circleci.com/gh/jescholl/packetman)
|
9
|
+
[![Code Climate](https://codeclimate.com/github/jescholl/packetman/badges/gpa.svg)](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
|