packetman 0.1.0 → 0.1.5

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
- SHA1:
3
- metadata.gz: d179b4712440f17879c705887caeec69fd857517
4
- data.tar.gz: 7879478eab7e6ecca5d75bff051a5dcad4006465
2
+ SHA256:
3
+ metadata.gz: 2820eacc8a12d33ab3ce8799c4c37d350457775f741173b86766fe5e8236951e
4
+ data.tar.gz: e977ac8d6076e95671ac2ccf0539c14d38653b01395e9fe838bcfdf2c55d76b7
5
5
  SHA512:
6
- metadata.gz: 59f189ec8d961cc829938163d21daffea43b4ce14f5b0487d49339ad59abf6cbefabfbb5254e2b949132987ee06df4b584664d9e0d1f7973c33835c1328cd59a
7
- data.tar.gz: 4e6b9134085f93800d07dd8a5e218c48d1c25260832b837c4f2e4fc365545234589232e0af344b8e1687eb90f6aa93d91875a341cfcf1165c1bec3d2341fd3a5
6
+ metadata.gz: '06068e575d4aa980070dadb455f1032910e43d03c39fcc28416eb66517d0b4ba120c595110ece205b478ddd9d18d5ada0a26980276f1d02f1ad7327778323128'
7
+ data.tar.gz: f64e896df598544f0f3174cda71dc430189de8a735f6d0c2639dcbef9877cfa2f4b596fe00fa4bfbd7f0102e4b9a87e529f66a5078598b85fd4118e5e5d84e79
@@ -0,0 +1,55 @@
1
+ version: 2.1
2
+ jobs:
3
+ build:
4
+ parameters:
5
+ ruby_version:
6
+ description: Version of ruby to test
7
+ type: string
8
+ environment:
9
+ GEM_HOME: vendor/bundle
10
+ docker:
11
+ - image: circleci/ruby:<< parameters.ruby_version >>
12
+ working_directory: /tmp/project
13
+ steps:
14
+ - checkout
15
+ - restore_cache:
16
+ keys:
17
+ - v1-bundle-{{ .Environment.CIRCLE_JOB }}-{{ .Environment.CIRCLE_SHA1 }}
18
+ - v1-bundle-{{ .Environment.CIRCLE_JOB }}-
19
+ - run:
20
+ name: Bundle install
21
+ command: >
22
+ gem install bundler -i vendor/bundle
23
+ && bundle install --path vendor/bundle
24
+ - run:
25
+ name: Prepare CodeClimate
26
+ command: >
27
+ curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
28
+ && chmod +x ./cc-test-reporter
29
+ - save_cache:
30
+ key: v1-bundle-{{ .Environment.CIRCLE_JOB }}-{{ .Environment.CIRCLE_SHA1 }}
31
+ paths:
32
+ - /tmp/project/vendor
33
+ - run:
34
+ name: Run Tests
35
+ command: >
36
+ ./cc-test-reporter before-build
37
+ bundle exec rake spec
38
+ ./cc-test-reporter after-build
39
+
40
+ workflows:
41
+ version: 2
42
+ build:
43
+ jobs:
44
+ - build:
45
+ name: ruby_2_3_8
46
+ ruby_version: 2.3.8
47
+ - build:
48
+ name: ruby_2_4_10
49
+ ruby_version: 2.4.10
50
+ - build:
51
+ name: ruby_2_5_8
52
+ ruby_version: 2.5.8
53
+ - build:
54
+ name: ruby_2_6_6
55
+ ruby_version: 2.6.6
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ /vendor/
data/README.md CHANGED
@@ -1,8 +1,12 @@
1
1
  # Packetman
2
2
 
3
- Advanced tcpdump and Wireshark capture generator.
3
+ Advanced tcpdump and Wireshark filter string generator.
4
4
 
5
- [![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
 
@@ -34,7 +38,40 @@ Or install it yourself as:
34
38
 
35
39
  ## Usage
36
40
 
37
- TODO: Write usage instructions here
41
+ $ packetman -h
42
+
43
+ Usage: packetman [OPTIONS] FILTER_STRING
44
+ -p, --protocol PROTO Transport Protocol (tcp,udp,icmp)
45
+ -t, --transport OFFSET starts at transport header instead of data payload
46
+ -r, --radix RADIX Treat FILTER_STRING as RADIX instead of String
47
+ -o, --offset OFFSET Offset in bits
48
+ -b, --byte-offset Use 8-bit bytes instead of bits for offset
49
+ -w, --wildcard [CHARACTER=?] Treat CHARACTER as single-character wildcard
50
+ -v, --version Show version
51
+
52
+ Create and use a filter string to capture all HTTP GET requests to `/foo/bar`
53
+
54
+ $ sudo tcpdump -nA `packetman GET /foo/bar`
55
+ tcpdump: data link type PKTAP
56
+ tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
57
+ listening on pktap, link-type PKTAP (Packet Tap), capture size 262144 bytes
58
+ 16:49:04.516409 IP 127.0.0.1.54662 > 127.0.0.1.80: Flags [P.], seq 1488105913:1488105994, ack 1397163988, win 4121, options [nop,nop,TS val 875380202 ecr 2751916352], length 81: HTTP: GET /foo/bar HTTP/1.1
59
+ .....b....j...E.....@.@..S..
60
+ ..:.....PX...SG......75.....
61
+ 4-=....@GET /foo/bar HTTP/1.1
62
+ Host: localhost
63
+ User-Agent: curl/7.43.0
64
+ Accept: */*
65
+
66
+ Hexadecimal string with wildcards
67
+
68
+ $ packetman -r 16 -w '?' "A8C401???C200A"
69
+ tcp[((tcp[12:1] & 0xf0) >> 2) + 0:4] & 0xffffff00 = 0xa8c40100 && tcp[((tcp[12:1] & 0xf0) >> 2) + 4:2] & 0x0fff = 0x0c20 && tcp[((tcp[12:1] & 0xf0) >> 2) + 6:1] & 0xff = 0x0a
70
+
71
+ Base 4 string with wildcards and offset beginning at start of the TCP header
72
+
73
+ $ packetman -t -o 3 -r 4 -w i 1223iiii2212
74
+ tcp[0:4] & 0x1fe01fe0 = 0x0d6014c0
38
75
 
39
76
  ## Development
40
77
 
@@ -0,0 +1,7 @@
1
+ ---
2
+ dns: # packetman -tbo 21 -p udp -w '.' 'google.com'
3
+ :offset: 21
4
+ :start_with_transport: true
5
+ :offset_type: :bytes
6
+ :wildcard: .
7
+ :transport: udp
@@ -1,35 +1,56 @@
1
1
  ---
2
- transport:
3
- tcp:
4
- table:
5
- Source Port: 16
6
- Destination Port: 16
7
- Sequence Number: 32
8
- Acknowledgement Number: 32
9
- Data Offset: 4
10
- RESERVED: 3
11
- ECN: 3
12
- Control Bits: 6
13
- Window: 16
14
- Checksum: 16
15
- Urgent Pointer: 16
16
- Options and Padding: 32
17
- payload_query: '((tcp[12:1] & 0xf0) >> 2)'
18
- udp:
19
- table:
20
- Source Port: 16
21
- Destination Port: 16
22
- Length: 16
23
- Checksum: 16
24
- payload_query: 8
25
- icmp:
26
- table:
27
- Type: 8
28
- Code: 8
29
- Checksum: 16
30
- Type Specific Options: 32
31
- application:
32
- http:
33
- transport_protocol: tcp
34
- dns:
35
- transport_protocol: tcp
2
+ tcp:
3
+ table:
4
+ - - :value: Source Port
5
+ :colspan: 16
6
+ - :value: Destination Port
7
+ :colspan: 16
8
+ - :separator
9
+ - - :value: Sequence Number
10
+ :colspan: 32
11
+ - :separator
12
+ - - :value: Acknowledgement Number
13
+ :colspan: 32
14
+ - :separator
15
+ - - :value: Data Offset
16
+ :colspan: 4
17
+ - :value: RESERVED
18
+ :colspan: 3
19
+ - :value: ECN
20
+ :colspan: 3
21
+ - :value: Control Bits
22
+ :colspan: 6
23
+ - :value: Window
24
+ :colspan: 16
25
+ - :separator
26
+ - - :value: Checksum
27
+ :colspan: 16
28
+ - :value: Urgent Pointer
29
+ :colspan: 16
30
+ - :separator
31
+ - - :value: Options and Padding
32
+ :colspan: 32
33
+ payload_query: '((tcp[12:1] & 0xf0) >> 2)'
34
+ udp:
35
+ table:
36
+ - - :value: Source Port
37
+ :colspan: 16
38
+ - :value: Destination Port
39
+ :colspan: 16
40
+ - :separator
41
+ - - :value: Length
42
+ :colspan: 16
43
+ - :value: Checksum
44
+ :colspan: 16
45
+ payload_query: 8
46
+ icmp:
47
+ table:
48
+ - - :value: Type
49
+ :colspan: 8
50
+ - :value: Code
51
+ :colspan: 8
52
+ - :value: Checksum
53
+ :colspan: 16
54
+ - :separator
55
+ - - :value: Type Specific Options
56
+ :colspan: 32
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'packetman'
3
3
 
4
- search_str = Packetman.config.parse_opts
4
+ catch :exit do
5
+ search_str = Packetman.config.parse_opts
5
6
 
6
- puts Packetman::Compose.new(search_str)
7
+ puts Packetman::Filter.new(search_str)
8
+ end
@@ -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
@@ -16,9 +17,5 @@ module Packetman
16
17
  @config = Config.new
17
18
  end
18
19
 
19
- def user_input(prompt)
20
- puts prompt
21
- gets
22
- end
23
20
  end
24
21
  end
@@ -0,0 +1,33 @@
1
+ module Packetman
2
+ class Clause
3
+ include ConfigMethods
4
+
5
+ attr_accessor :search, :mask, :start_bit
6
+
7
+ def initialize(search, mask, start_bit)
8
+ self.search = search
9
+ self.mask = mask
10
+ self.start_bit = start_bit
11
+ end
12
+
13
+ # Address of first byte
14
+ def start_byte
15
+ [config.payload_query, (config.offset_bits + start_bit)/8].compact.join(' + ')
16
+ end
17
+
18
+ def num_bytes
19
+ Filter.bit_length(search)/8
20
+ end
21
+
22
+ # Full address of the query data (eg. `tcp[0:4]`)
23
+ def data_address
24
+ "#{config.transport}[#{start_byte}:#{num_bytes}]"
25
+ end
26
+
27
+ # The whole filter clause fully assembled
28
+ def to_s
29
+ "#{data_address} & #{mask} = #{search}"
30
+ end
31
+
32
+ end
33
+ end
@@ -2,69 +2,63 @@ require 'optparse'
2
2
 
3
3
  module Packetman
4
4
  class Config
5
- attr_accessor :transport, :application, :offset_units, :offset_type, :allow_wildcards, :radix
6
- attr_writer :offset
5
+ attr_accessor :transport, :application, :offset_type, :radix, :start_with_transport, :offset, :wildcard
7
6
 
8
7
  def initialize
9
- @transport = "tcp"
10
- @application = "http"
11
- @offset = 0
12
- @offset_units = "bits"
13
- @offset_type = "application"
14
- @allow_wildcards = true
8
+ self.transport = "tcp"
9
+ self.offset = 0
10
+ self.offset_type = :bits
15
11
  end
16
12
 
17
13
  def protocols
18
14
  @protocols ||= YAML.load(File.read(File.expand_path('../../../config/protocols.yml', __FILE__)))
19
15
  end
20
16
 
17
+ def applications
18
+ @applications ||= YAML.load(File.read(File.expand_path('../../../config/applications.yml', __FILE__)))
19
+ end
20
+
21
21
  def payload_query
22
- case offset_type
23
- when "application"
24
- protocols['transport'][transport.to_s]['payload_query']
22
+ protocols[transport]['payload_query'] unless start_with_transport
23
+ end
24
+
25
+ def offset_bits
26
+ if offset_type == :bytes
27
+ offset*8
25
28
  else
26
- "0"
29
+ offset
27
30
  end
28
31
  end
29
32
 
30
- def offset
31
- case offset_units
32
- when "bytes"
33
- @offset*8
34
- else
35
- @offset
33
+ # FIXME figure out a way to do defaults so this can just set defaults
34
+ def application_override(app_name)
35
+ applications[app_name].each do |key, value|
36
+ __send__("#{key}=", value)
36
37
  end
37
38
  end
38
39
 
39
- def parse_opts
40
+ def opts
40
41
  @opts ||= OptionParser.new do |opt|
41
42
  opt.banner = "Usage: #{File.basename($PROGRAM_NAME)} [OPTIONS] FILTER_STRING"
42
- opt.on("-t", "--transport [PROTO]", protocols['transport'].keys, "Transport Protocol (#{protocols['transport'].keys.join(',')})") {|v| self.transport = v }
43
- opt.on("-a", "--application [PROTO]", protocols['application'].keys, "Application protocol (#{protocols['application'].keys.join(',')})") { |v| self.application = v }
44
- #opt.on("-a", "--application [PROTO]", String, "Application Protocol (http|dns|icmp)") {|v| self.application = v }
45
- opt.on("-r", "--radix [RADIX]", Integer, "Treat FILTER_STRING as RADIX instead of String") {|v| self.radix = v; }
46
- opt.on("-o", "--offset [OFFSET]", Integer, "Offset in bits") {|v| self.offset = v; }
47
- opt.on("-b", "--byte-offset", "Use 8-bit bytes instead of bits for offset") { |v| self.offset_units = "bytes" }
48
- opt.on("-O", "--offset-type [TYPE]", ["application", "transport"], "Begin offset at the application/transport header.") { |v| self.offset_type = v }
49
- opt.on("--[no-]wildcards", "Allow '?' wildcards") { |v| self.allow_wildcards = v }
43
+ opt.on("-p", "--protocol PROTO", protocols.keys, "Transport Protocol (#{protocols.keys.join(',')})") { |v| self.transport = v }
44
+ opt.on("-a", "--application APPLICATION", applications.keys, "Application Protocol (#{applications.keys.join(',')}) OVERRIDES ALL OTHER SETTINGS") { |v| application_override(v) }
45
+ opt.on("-t", "--transport", "OFFSET starts at transport header instead of data payload") { |v| self.start_with_transport = v }
46
+ opt.on("-r", "--radix RADIX", Integer, "Treat FILTER_STRING as RADIX instead of String") { |v| self.radix = v }
47
+ opt.on("-o", "--offset OFFSET", Integer, "Offset in bits") { |v| self.offset = v }
48
+ opt.on("-b", "--byte-offset", "Use 8-bit bytes instead of bits for offset") { |v| self.offset_type = :bytes if v }
49
+ opt.on("-w", "--wildcard CHARACTER", "Treat CHARACTER as single-character wildcard") { |v| raise "invalid wildcard" if v.to_s.length > 1; self.wildcard = v }
50
+ opt.on("--table", "Show transport header table") { puts Packetman::Table.new; throw :exit }
51
+ opt.on("-v", "--version", "Show version") { puts Packetman::VERSION; throw :exit }
50
52
  end
53
+ end
51
54
 
52
- @opts.parse!
53
-
54
- raise "Invalid command line arguments" if ARGV.size != 1
55
-
56
- ARGV.pop
57
-
58
-
59
- # if transport !~ /tcp|udp/i ||
60
- # application !~ /http|dns|icmp/i
61
- # raise "invalid options"
62
- # end
63
- #
64
- # if offset_units == :bits
65
- # offset /= 8.to_f
66
- # offset_units = :octets
67
- # end
55
+ def parse_opts
56
+ unparsed_opts = opts.parse!
57
+ if unparsed_opts.length < 1
58
+ puts opts
59
+ throw :exit
60
+ end
61
+ unparsed_opts.join(" ")
68
62
  end
69
63
 
70
64
  end
@@ -7,5 +7,9 @@ module Packetman
7
7
  def config
8
8
  Packetman.config
9
9
  end
10
+
11
+ def protocols
12
+ config.protocols
13
+ end
10
14
  end
11
15
  end
@@ -0,0 +1,101 @@
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
+ else
17
+ nil
18
+ end
19
+ end
20
+
21
+ def self.bit_density(radix=config.radix)
22
+ (radix.nil?) ? 8 : Math.log2(radix).ceil
23
+ end
24
+
25
+ def map_chr
26
+ shift_and_pad(input.scan(/./).map{ |chr| yield chr }.join)
27
+ end
28
+
29
+ def shift_and_pad(bin_str)
30
+ #shift
31
+ bin_str.ljust(target_bit_length, '0').
32
+ #pad
33
+ rjust(target_bit_length + config.offset_bits % 8, '0')
34
+ end
35
+
36
+ def target_bit_length
37
+ ((input.length*self.class.bit_density + config.offset_bits)/8.to_f).ceil*8 - config.offset_bits
38
+ end
39
+
40
+ # Mask for 1 character of current radix
41
+ def radix_mask
42
+ ("1"*self.class.bit_density).to_i(2)
43
+ end
44
+
45
+ # Mask string for _chr_ substituting wildcards as necessary
46
+ def mask_chr(chr)
47
+ if chr == config.wildcard
48
+ 0
49
+ else
50
+ radix_mask
51
+ end.to_s(2).rjust(self.class.bit_density, '0')
52
+ end
53
+
54
+ # Converts the `chr` from `config.radix` to binary, substituting wildcards as necessary
55
+ #
56
+ # @param chr [String] character to convert to binary
57
+ # @return [String] binary string
58
+ def bin_chr(chr)
59
+ chr = '0' if chr == config.wildcard
60
+
61
+ if config.radix
62
+ raise "invalid character '#{chr}' for radix=#{config.radix}" if chr.downcase != chr.to_i(config.radix).to_s(config.radix).downcase
63
+ chr.to_i(config.radix)
64
+ else
65
+ chr.ord
66
+ end.to_s(2).rjust(self.class.bit_density, '0')
67
+ end
68
+
69
+ def mask_hex
70
+ hex_encode(map_chr{ |c| mask_chr(c) })
71
+ end
72
+
73
+ def search_hex
74
+ hex_encode(map_chr{ |c| bin_chr(c) })
75
+ end
76
+
77
+ # Transform _bin_str_ to array of 32, 16, and 8 bit hex encoded strings
78
+ def hex_encode(bin_str)
79
+ bin_str.reverse.scan(/.{1,4}/).map{ |chunk|
80
+ chunk.reverse.to_i(2).to_s(16)
81
+ }.reverse.join.scan(/.{8}|.{4}|.{2}/).map{ |hex|
82
+ hex.prepend('0x')
83
+ }
84
+ end
85
+
86
+ def clauses
87
+ start_bit = 0
88
+ [].tap do |filter|
89
+ search_hex.zip(mask_hex).each do |search, mask|
90
+ filter << Packetman::Clause.new(search, mask, start_bit)
91
+ start_bit += self.class.bit_length(search)
92
+ end
93
+ end
94
+ end
95
+
96
+ def to_s
97
+ clauses.map{ |clause| clause.to_s }.join(' && ')
98
+ end
99
+
100
+ end
101
+ end
@@ -1,57 +1,28 @@
1
+ require 'terminal-table'
2
+
1
3
  module Packetman
2
4
  class Table
3
5
  include ConfigMethods
4
6
 
5
- attr_reader :line_h, :line_v
6
- attr_accessor :columns
7
-
8
- def initialize(cols = 32)
9
- @line_v = '|'
10
- @line_h = '-'
11
- @columns = cols
12
- end
13
-
14
- def line_h=(value)
15
- raise "Invalid character" if value.length != 1
16
- @line_h = value
17
- end
18
-
19
- def line_v=(value)
20
- raise "Invalid character" if value.length != 1
21
- @line_v = value
22
- end
23
-
24
- def column_width
25
- (columns-1).to_s.length
26
- end
7
+ def initialize
27
8
 
28
- def horizontal_bar
29
- line_v + line_h*(table_width - 2) + line_v + "\n"
9
+ @term_table = Terminal::Table.new(headings: headings, rows: rows, style: style)
30
10
  end
31
11
 
32
- def table_width
33
- columns*(column_width + 1) + 1
12
+ def headings
13
+ [*0..31].map{ |c| "%02d" % c }
34
14
  end
35
15
 
36
- def cell_size(field_size)
37
- field_size*(column_width + 1) - 1
16
+ def rows
17
+ protocols[config.transport]['table']
38
18
  end
39
19
 
40
- def header_row
41
- line_v + columns.times.map{ |n| sprintf "%0#{column_width}d", n }.join(line_v) + line_v + "\n"
20
+ def style
21
+ { alignment: :center, padding_left: 0, padding_right: 0}
42
22
  end
43
23
 
44
24
  def to_s
45
- output = horizontal_bar + header_row + horizontal_bar
46
-
47
- config.protocols['transport'][config.transport]['table'].each do |label, size|
48
- output += sprintf "%s%.#{cell_size(size)}s", line_v, label.center(cell_size(size))
49
- if output.split("\n").last.length == (table_width - 1)
50
- output += line_v + "\n"
51
- output += horizontal_bar
52
- end
53
- end
54
- output
25
+ @term_table.to_s
55
26
  end
56
27
 
57
28
  end
@@ -1,3 +1,3 @@
1
1
  module Packetman
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.5"
3
3
  end
@@ -19,9 +19,10 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_development_dependency "bundler", "~> 1"
23
- spec.add_development_dependency "rake", "~> 10.0"
24
- spec.add_development_dependency "rspec", "~> 3.3"
25
- spec.add_development_dependency "pry", "~> 0.10"
26
- spec.add_development_dependency "codeclimate-test-reporter"
22
+ spec.add_dependency "terminal-table", "~> 1.8"
23
+ spec.add_development_dependency "bundler", "~> 2.0"
24
+ spec.add_development_dependency "rake", "~> 13.0"
25
+ spec.add_development_dependency "rspec", "~> 3.9"
26
+ spec.add_development_dependency "simplecov", "~> 0.17"
27
+ spec.add_development_dependency "pry", "~> 0.12"
27
28
  end
metadata CHANGED
@@ -1,85 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: packetman
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.5
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-09-20 00:00:00.000000000 Z
11
+ date: 2020-08-03 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: terminal-table
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.8'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: '1'
33
+ version: '2.0'
20
34
  type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: '1'
40
+ version: '2.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '10.0'
47
+ version: '13.0'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: '10.0'
54
+ version: '13.0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rspec
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '3.3'
61
+ version: '3.9'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '3.3'
68
+ version: '3.9'
55
69
  - !ruby/object:Gem::Dependency
56
- name: pry
70
+ name: simplecov
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: '0.10'
75
+ version: '0.17'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '0.10'
82
+ version: '0.17'
69
83
  - !ruby/object:Gem::Dependency
70
- name: codeclimate-test-reporter
84
+ name: pry
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - ">="
87
+ - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: '0'
89
+ version: '0.12'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - ">="
94
+ - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: '0'
96
+ version: '0.12'
83
97
  description: Simple tool for creating advanced tcpdump queries, because manually writing
84
98
  `tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420` is no fun.
85
99
  email:
@@ -89,9 +103,10 @@ executables:
89
103
  extensions: []
90
104
  extra_rdoc_files: []
91
105
  files:
106
+ - ".bundle/config"
107
+ - ".circleci/config.yml"
92
108
  - ".gitignore"
93
109
  - ".rspec"
94
- - ".travis.yml"
95
110
  - Gemfile
96
111
  - LICENSE.txt
97
112
  - NOTES.md
@@ -100,17 +115,17 @@ files:
100
115
  - TODO.md
101
116
  - bin/console
102
117
  - bin/setup
103
- - circle.yml
118
+ - config/applications.yml
104
119
  - config/protocols.yml
105
120
  - exe/packetman
106
121
  - lib/packetman.rb
107
- - lib/packetman/compose.rb
122
+ - lib/packetman/clause.rb
108
123
  - lib/packetman/config.rb
109
124
  - lib/packetman/config_methods.rb
125
+ - lib/packetman/filter.rb
110
126
  - lib/packetman/table.rb
111
127
  - lib/packetman/version.rb
112
128
  - packetman.gemspec
113
- - packetman_notes
114
129
  homepage: https://github.com/jescholl/packetman
115
130
  licenses:
116
131
  - MIT
@@ -131,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
131
146
  version: '0'
132
147
  requirements: []
133
148
  rubyforge_project:
134
- rubygems_version: 2.4.5
149
+ rubygems_version: 2.7.6.2
135
150
  signing_key:
136
151
  specification_version: 4
137
152
  summary: Advanced tcpdump and Wiresharp filter generator.
@@ -1,4 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.2.2
4
- before_install: gem install bundler -v 1.10.5
data/circle.yml DELETED
@@ -1,3 +0,0 @@
1
- machine:
2
- ruby:
3
- version: 2.1.6
@@ -1,97 +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
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
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)
58
- end
59
-
60
- def search_hex
61
- hex_encode(search)
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(/.{1,8}/).map{ |hex| hex.prepend('0x') }
66
- end
67
-
68
- def full_bit_length(num, radix=nil)
69
- return num.to_i(radix).to_s(radix).length * bit_density(radix) if radix
70
-
71
- case num
72
- when /^0x/
73
- $'.length * bit_density(16)
74
- when /^0b/
75
- $'.length * bit_density(2)
76
- else
77
- nil
78
- end
79
- end
80
-
81
- def start_byte(position)
82
- "#{config.payload_query} + #{(config.offset + position)/8}"
83
- end
84
-
85
- def to_s
86
- clauses = []
87
- position = 0
88
- search_hex.zip(mask_hex).each_with_index do |(hex_search, hex_mask),i|
89
- search_bit_length = full_bit_length(hex_search)
90
- clauses << "#{config.transport}[#{start_byte(position)}:#{search_bit_length/8}] & #{hex_mask} = #{hex_search}"
91
- position += search_bit_length
92
- end
93
-
94
- clauses.join(' && ')
95
- end
96
- end
97
- end
@@ -1,156 +0,0 @@
1
- 7a
2
- 1111010
3
-
4
- #NOTE: I think this is wrong
5
- # also, maybe I don't need to worry about the bits bing aligned on the byte, just on the bit, as long as it's what the user asked for
6
-
7
- hex and string need to be 0 padded on the left
8
- binary needs to fill to the right to hex encode, starting at the offset bit
9
-
10
- Packetman.compose3("0b1111", 3)
11
- 1111
12
- (fill right to ((4+3)/8.to_f).ceil*8 = 8 )
13
- 11110000
14
- (shift mask and search >> 3)
15
- 00011110
16
- 00011110
17
- (sample byte sequence)
18
- 00011111
19
-
20
- Packetman.compose3("0b1111010", 3)
21
- 1111010
22
- (fill right to ((7+3)/8.to_f).ceil*8 = 16)
23
- 11110100 00000000
24
- (shift mask and search >> 3)
25
- 00011111 11000000
26
- 00011110 10000000
27
- (sample byte sequence)
28
- 00011110 10101010
29
-
30
-
31
- Packetman.compose3("0b1111010????????", 3)
32
- 1111010? ???????
33
- (fill right to ((15+3)/8.to_f).ceil*8 = 24)
34
- 1111010? ???????0 00000000
35
- (shift mask and search >> 3)
36
- 00011111 11000000 00000000
37
- 00011110 10000000 00000000
38
- (sample byte sequence)
39
- 00011110 10101010 10101010
40
-
41
- Packetman.compose3("0x123",3)
42
- 100100011
43
- (left fill to 12 first, or manual right fill with 16-12)
44
- (fill right to ((3*4)+3)/8.to_f).ceil*8 = 16)
45
- 00010010 00110000
46
- (shift mask and search >> 3)
47
- 00000011 11111110
48
- 00000010 01000110
49
- (sample byte sequence)
50
- 00000010 01000111
51
-
52
-
53
-
54
-
55
- Packetman.compose3("0xa",3)
56
- "((tcp[0:1] & 0xa) >> 1) = 0xa"
57
- 1010
58
- (generate shifted mask)
59
- 00011110
60
- (generate shifted search)
61
- 00010100
62
- (sample byte sequence)
63
- 10010101
64
-
65
- 0b00011110 & 0b10010101 == 0x14
66
-
67
-
68
-
69
-
70
-
71
-
72
- Packetman.compose3("0b001010010", 3)
73
- "((tcp[0:2] & 0x1ff0) >> 4 = 0x52"
74
- 001010010
75
- (generate shifted mask)
76
- (turn preceding 0s to 1s)
77
- (left shift (((binlen)+3)/8.to_f).ceil*8 - binlen - 3)
78
- 1111111110000
79
- (generate shifted search - same as above)
80
- 0010100100000
81
- (sample byte sequence)
82
- 0010100101010
83
-
84
- 0b0010100101010 & 1111111110000 == 0b0010100100000
85
-
86
-
87
- Packetman.compose3("0b00??1010?111?00010101??10101010?????1010111110???111110101001111010101??????????10100101010100011???????", 5)
88
- 00??1010?111?00010101??10101010?????1010111110???111110101001111010101??????????10100101010100011???????
89
- (generate search str - replace ?s with 0s)
90
- 00001010011100001010100101010100000010101111100001111101010011110101010000000000101001010101000110000000
91
- (generate shifted mask)
92
- (turn preceding 0s to 1s)
93
- (left shift (((binlen)+5)/8.to_f).ceil*8 - binlen - 5)
94
- 11001111011101111111100111111110000011111111110001111111111111111111110000000000111111111111111110000000000
95
- 11001111011101111111100111111110000011111111110001111111111111111111110000000000111111111111111110000000
96
- (generate shifted search - same as above)
97
- 00001010011100001010100101010100000010101111100001111101010011110101010000000000101001010101000110000000000
98
- (sample byte sequence)
99
- 00011010011100001010111101010101100110101111100101111101010011110101010010101001101001010101000110110100101
100
-
101
- 00011010011100001010111101010101100110101111100101111101010011110101010010101001101001010101000110110100101 &
102
- 11001111011101111111100111111110000011111111110001111111111111111111110000000000111111111111111110000000000 ==
103
- 00001010011100001010100101010100000010101111100001111101010011110101010000000000101001010101000110000000000
104
-
105
-
106
- # NOTE
107
-
108
- instead of shifting the product of (mask & input), shift search
109
- this makes the form
110
- "tcp[0:1] & mask = shifted_search"
111
-
112
-
113
- Packetman.compose3("0xa",1)
114
- "((tcp[0:1] & 0x78) >> 3) = 0xa"
115
- 1010
116
- (generate shifted mask)
117
- (left shift (((hexlen*4)+1)/8.to_f).ceil*8 - hexlen*4 - 1)
118
- (use length of mask to determine how much data to take)
119
- 01111000
120
- (sample byte sequence)
121
- 11010101
122
-
123
- (0b01111000 & 0b11010101) >> 3 == 0xa
124
-
125
-
126
- Packetman.compose3("0x123", 3)
127
- "((tcp[0:2] & 0x1ffe) >> 1) = 0x123"
128
- 100100011
129
- (hex: left fill with 1s to hexlen*4)
130
- 111100100011
131
- (generate shifted mask)
132
- (left shift (((hexlen*4)+3)/8.to_f).ceil*8 - hexlen*4 - 3)
133
- (use length of mask to determine how much data to take)
134
- 0001111111111110
135
- (sample byte sequence)
136
- 1000001001000111
137
-
138
- (0b1000001001000111 & 0b0001111111111110) >> 1 == 0x123
139
-
140
- Packetman.compose3("abc", 3)
141
- "((tcp[0:4] & 0x1fffffe0 >> 5) = 0x616263"
142
- 11000010110001001100011
143
- (str: left fill with 1s to len*8)
144
- 111000010110001001100011
145
- (generate shifted mask)
146
- (left shift (((strlen*8)+3)/8.to_f).ceil*8 - strlen*8 - 3)
147
- (use length of mask to determine how much data to take)
148
- 00011111 11111111 11111111 11100000
149
- (sample byte sequence)
150
- 10101100 00101100 01001100 01110101
151
-
152
- (0b10101100001011000100110001110101 & 0b00011111111111111111111111100000) >> 5 == 0b11000010110001001100011
153
-
154
-
155
-
156
-