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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d3819b6864ab2d131bcd29e65c79a02123a1d4b4
4
- data.tar.gz: 7de18ca9f2f368755393dbc6c0d3b4edfb34a019
3
+ metadata.gz: a30c3ba57b035cf5927580b722a5651aefc55317
4
+ data.tar.gz: 68c4aa0507610985b538da8e6b8b432ffbd6aa49
5
5
  SHA512:
6
- metadata.gz: f70eb13025b20f23690c6d0b169bb165a7ea035597bd863a5bb1279711eb1f40f54fe393e0611715b980f460e5d899f2ddf92a8ce2806544d70f26d3cf0599e8
7
- data.tar.gz: 3f2df4b4ee6be9f721195aa661b8ae91bf7aeccd77c8935fa6b51464c872e345206c103af7898342f102ddc55859ddb300642a5420b1e7831b24585f3b378dcb
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) [![Code Climate](https://codeclimate.com/github/jescholl/packetman/badges/gpa.svg)](https://codeclimate.com/github/jescholl/packetman) [![Test Coverage](https://codeclimate.com/github/jescholl/packetman/badges/coverage.svg)](https://codeclimate.com/github/jescholl/packetman/coverage) [![Circle CI](https://circleci.com/gh/jescholl/packetman.svg?style=svg)](https://circleci.com/gh/jescholl/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
 
@@ -3,4 +3,4 @@ require 'packetman'
3
3
 
4
4
  search_str = Packetman.config.parse_opts
5
5
 
6
- puts Packetman::Compose.new(search_str)
6
+ puts Packetman::Filter.new(search_str)
@@ -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/compose"
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
@@ -2,8 +2,7 @@ require 'optparse'
2
2
 
3
3
  module Packetman
4
4
  class Config
5
- attr_accessor :transport, :application, :use_bytes, :allow_wildcards, :radix, :start_with_transport
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 offset
20
+ def offset_bits
22
21
  if use_bytes
23
- @offset*8
22
+ offset*8
24
23
  else
25
- @offset
24
+ offset
26
25
  end
27
26
  end
28
27
 
29
- def parse_opts
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 [PROTO]", protocols.keys, "Transport Protocol (#{protocols.keys.join(',')})") {|v| self.transport = v }
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 [RADIX]", Integer, "Treat FILTER_STRING as RADIX instead of String") {|v| self.radix = v; }
35
- opt.on("-o", "--offset [OFFSET]", Integer, "Offset in bits") {|v| self.offset = v; }
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", "--wildcards", "Allow '?' wildcards") { |v| self.allow_wildcards = v }
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
- ARGV.pop
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
@@ -1,3 +1,3 @@
1
1
  module Packetman
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
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.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-04 00:00:00.000000000 Z
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/compose.rb
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
@@ -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