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 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