packetfu 1.1.10 → 1.1.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -0
  4. data/.gitignore +3 -0
  5. data/.travis.yml +8 -0
  6. data/CONTRIBUTING.md +47 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +1 -1
  9. data/README.rdoc +35 -30
  10. data/Rakefile +4 -4
  11. data/bench/octets.rb +9 -9
  12. data/examples/100kpackets.rb +12 -12
  13. data/examples/ackscan.rb +16 -16
  14. data/examples/arp.rb +35 -35
  15. data/examples/arphood.rb +36 -36
  16. data/examples/dissect_thinger.rb +6 -6
  17. data/examples/new-simple-stats.rb +23 -23
  18. data/examples/packetfu-shell.rb +25 -25
  19. data/examples/simple-sniffer.rb +9 -9
  20. data/examples/simple-stats.rb +23 -23
  21. data/examples/slammer.rb +3 -3
  22. data/gem-public_cert.pem +21 -0
  23. data/lib/packetfu.rb +149 -127
  24. data/lib/packetfu/capture.rb +169 -169
  25. data/lib/packetfu/config.rb +52 -52
  26. data/lib/packetfu/inject.rb +56 -56
  27. data/lib/packetfu/packet.rb +531 -528
  28. data/lib/packetfu/pcap.rb +579 -579
  29. data/lib/packetfu/protos/arp.rb +90 -90
  30. data/lib/packetfu/protos/arp/header.rb +158 -158
  31. data/lib/packetfu/protos/arp/mixin.rb +36 -36
  32. data/lib/packetfu/protos/eth.rb +44 -44
  33. data/lib/packetfu/protos/eth/header.rb +243 -243
  34. data/lib/packetfu/protos/eth/mixin.rb +3 -3
  35. data/lib/packetfu/protos/hsrp.rb +69 -69
  36. data/lib/packetfu/protos/hsrp/header.rb +107 -107
  37. data/lib/packetfu/protos/hsrp/mixin.rb +29 -29
  38. data/lib/packetfu/protos/icmp.rb +71 -71
  39. data/lib/packetfu/protos/icmp/header.rb +82 -82
  40. data/lib/packetfu/protos/icmp/mixin.rb +14 -14
  41. data/lib/packetfu/protos/invalid.rb +49 -49
  42. data/lib/packetfu/protos/ip.rb +69 -69
  43. data/lib/packetfu/protos/ip/header.rb +291 -291
  44. data/lib/packetfu/protos/ip/mixin.rb +40 -40
  45. data/lib/packetfu/protos/ipv6.rb +50 -50
  46. data/lib/packetfu/protos/ipv6/header.rb +188 -188
  47. data/lib/packetfu/protos/ipv6/mixin.rb +29 -29
  48. data/lib/packetfu/protos/tcp.rb +176 -176
  49. data/lib/packetfu/protos/tcp/ecn.rb +35 -35
  50. data/lib/packetfu/protos/tcp/flags.rb +74 -74
  51. data/lib/packetfu/protos/tcp/header.rb +268 -268
  52. data/lib/packetfu/protos/tcp/hlen.rb +32 -32
  53. data/lib/packetfu/protos/tcp/mixin.rb +46 -46
  54. data/lib/packetfu/protos/tcp/option.rb +321 -321
  55. data/lib/packetfu/protos/tcp/options.rb +95 -95
  56. data/lib/packetfu/protos/tcp/reserved.rb +35 -35
  57. data/lib/packetfu/protos/udp.rb +159 -123
  58. data/lib/packetfu/protos/udp/header.rb +91 -91
  59. data/lib/packetfu/protos/udp/mixin.rb +3 -3
  60. data/lib/packetfu/structfu.rb +280 -280
  61. data/lib/packetfu/utils.rb +292 -225
  62. data/lib/packetfu/version.rb +41 -41
  63. data/packetfu.gemspec +14 -3
  64. data/spec/arp_spec.rb +191 -0
  65. data/spec/eth_spec.rb +148 -0
  66. data/spec/icmp_spec.rb +97 -0
  67. data/spec/ip_spec.rb +78 -0
  68. data/spec/ipv6_spec.rb +81 -0
  69. data/spec/packet_spec.rb +61 -59
  70. data/spec/packet_subclasses_spec.rb +9 -10
  71. data/spec/packetfu_spec.rb +55 -62
  72. data/spec/sample3.pcap +0 -0
  73. data/spec/spec_helper.rb +44 -0
  74. data/spec/structfu_spec.rb +270 -271
  75. data/spec/tcp_spec.rb +76 -77
  76. data/spec/udp_spec.rb +32 -0
  77. data/spec/utils_spec.rb +95 -0
  78. data/test/all_tests.rb +14 -17
  79. data/test/func_lldp.rb +3 -3
  80. data/test/ptest.rb +2 -2
  81. data/test/test_capture.rb +45 -45
  82. data/test/test_eth.rb +70 -68
  83. data/test/test_hsrp.rb +9 -9
  84. data/test/test_inject.rb +18 -18
  85. data/test/test_invalid.rb +16 -16
  86. data/test/test_octets.rb +23 -21
  87. data/test/test_packet.rb +156 -154
  88. data/test/test_pcap.rb +172 -170
  89. data/test/test_structfu.rb +99 -97
  90. data/test/test_tcp.rb +322 -320
  91. data/test/test_udp.rb +78 -76
  92. metadata +108 -44
  93. metadata.gz.sig +2 -0
  94. data/spec/ethpacket_spec.rb +0 -74
  95. data/test/test_arp.rb +0 -135
  96. data/test/test_icmp.rb +0 -62
  97. data/test/test_ip.rb +0 -50
  98. data/test/test_ip6.rb +0 -68
@@ -1,173 +1,173 @@
1
1
  # -*- coding: binary -*-
2
2
  module PacketFu
3
3
 
4
- # The Capture class is used to construct PcapRub objects in order to collect
5
- # packets from an interface.
6
- #
7
- # This class requires PcapRub. In addition, you will need root (or root-like) privileges
8
- # in order to capture from the interface.
9
- #
10
- # Note, on some wireless cards, setting :promisc => true will disable capturing.
11
- #
12
- # == Example
13
- #
14
- # # Typical use
15
- # cap = PacketFu::Capture.new(:iface => 'eth0', :promisc => true)
16
- # cap.start
17
- # sleep 10
18
- # cap.save
19
- # first_packet = cap.array[0]
20
- #
21
- # # Tcpdump-like use
22
- # cap = PacketFu::Capture.new(:start => true)
23
- # cap.show_live(:save => true, :filter => 'tcp and not port 22')
24
- #
25
- # == See Also
26
- #
27
- # Read, Write
28
- class Capture
29
- attr_accessor :array, :stream # Leave these public and open.
30
- attr_reader :iface, :snaplen, :promisc, :timeout, :filter
31
-
32
- def initialize(args={})
33
- @array = [] # Where the packet array goes.
34
- @stream = [] # Where the stream goes.
35
- @iface = (args[:iface] || ENV['IFACE'] || Pcap.lookupdev || "lo").to_s
36
- @snaplen = args[:snaplen] || 0xffff
37
- @promisc = args[:promisc] || false # Sensible for some Intel wifi cards
38
- @timeout = args[:timeout] || 1
39
- @filter = args[:filter] || args[:bpf]
40
- setup_params(args)
41
- end
42
-
43
- # Used by new().
44
- def setup_params(args={})
45
- filter = args[:filter] || args[:bpf] || @filter
46
- start = args[:start] || false
47
- capture if start
48
- bpf(:filter=>filter) if filter
49
- end
50
-
51
- # capture() initializes the @stream varaible. Valid arguments are:
52
- #
53
- # :filter
54
- # Provide a bpf filter to enable for the capture. For example, 'ip and not tcp'
55
- # :start
56
- # When true, start capturing packets to the @stream variable. Defaults to true
57
- def capture(args={})
58
- if Process.euid.zero?
59
- filter = args[:filter] || args[:bpf] || @filter
60
- start = args[:start] || true
61
- if start
62
- begin
63
- @stream = Pcap.open_live(@iface,@snaplen,@promisc,@timeout)
64
- rescue RuntimeError
65
- $stderr.print "Are you sure you're root? Error: "
66
- raise
67
- end
68
- bpf(:filter=>filter) if filter
69
- else
70
- @stream = []
71
- end
72
- @stream
73
- else
74
- raise RuntimeError,"Not root, so can't capture packets. Error: "
75
- end
76
- end
77
-
78
- # start() is equivalent to capture().
79
- def start(args={})
80
- capture(args)
81
- end
82
-
83
- # clear() clears the @stream and @array variables, essentially starting the
84
- # capture session over. Valid arguments are:
85
- #
86
- # :array
87
- # If true, the @array is cleared.
88
- # :stream
89
- # If true, the @stream is cleared.
90
- def clear(args={})
91
- array = args[:array] || true
92
- stream = args[:stream] || true
93
- @array = [] if array
94
- @stream = [] if stream
95
- end
96
-
97
- # bpf() sets a bpf filter on a capture session. Valid arugments are:
98
- #
99
- # :filter
100
- # Provide a bpf filter to enable for the capture. For example, 'ip and not tcp'
101
- def bpf(args={})
102
- filter = args[:filter] || args[:bpf] || @filter
103
- capture if @stream.class == Array
104
- @stream.setfilter(filter) if filter
105
- @filter = filter
106
- end
107
-
108
- alias :filter :bpf
109
-
110
- # wire_to_array() saves a packet stream as an array of binary strings. From here,
111
- # packets may accessed by other functions. Note that the wire_to_array empties
112
- # the stream, so multiple calls will append new packets to @array.
113
- # Valid arguments are:
114
- #
115
- # :filter
116
- # Provide a bpf filter to apply to packets moving from @stream to @array.
117
- def wire_to_array(args={})
118
- filter = args[:filter] || args[:bpf] || @filter
119
- bpf(:filter=>filter) if filter
120
-
121
- while this_pkt = @stream.next
122
- @array << this_pkt
123
- end
124
- @array.size
125
- end
126
-
127
- # next() exposes the Stream object's next method to the outside world.
128
- def next
129
- return @stream.next
130
- end
131
-
132
- # w2a() is a equivalent to wire_to_array()
133
- def w2a(args={})
134
- wire_to_array(args)
135
- end
136
-
137
- # save() is a equivalent to wire_to_array()
138
- def save(args={})
139
- wire_to_array(args)
140
- end
141
-
142
- # show_live() is a method to capture packets and display peek() data to stdout. Valid arguments are:
143
- #
144
- # :filter
145
- # Provide a bpf filter to captured packets.
146
- # :save
147
- # Save the capture in @array
148
- # :verbose
149
- # TODO: Not implemented yet; do more than just peek() at the packets.
150
- # :quiet
151
- # TODO: Not implemented yet; do less than peek() at the packets.
152
- def show_live(args={})
153
- filter = args[:filter] || args[:bpf] || @filter
154
- save = args[:save]
155
- verbose = args[:verbose] || args[:v] || false
156
- quiet = args[:quiet] || args[:q] || false # Setting q and v doesn't make a lot of sense but hey.
157
-
158
- # Ensure the capture's started.
159
- if @stream.class == Array
160
- capture
161
- end
162
-
163
- @stream.setfilter(filter) if filter
164
- while true
165
- @stream.each do |pkt|
166
- puts Packet.parse(pkt).peek
167
- @array << pkt if args[:save]
168
- end
169
- end
170
- end
171
-
172
- end
4
+ # The Capture class is used to construct PcapRub objects in order to collect
5
+ # packets from an interface.
6
+ #
7
+ # This class requires PcapRub. In addition, you will need root (or root-like) privileges
8
+ # in order to capture from the interface.
9
+ #
10
+ # Note, on some wireless cards, setting :promisc => true will disable capturing.
11
+ #
12
+ # == Example
13
+ #
14
+ # # Typical use
15
+ # cap = PacketFu::Capture.new(:iface => 'eth0', :promisc => true)
16
+ # cap.start
17
+ # sleep 10
18
+ # cap.save
19
+ # first_packet = cap.array[0]
20
+ #
21
+ # # Tcpdump-like use
22
+ # cap = PacketFu::Capture.new(:start => true)
23
+ # cap.show_live(:save => true, :filter => 'tcp and not port 22')
24
+ #
25
+ # == See Also
26
+ #
27
+ # Read, Write
28
+ class Capture
29
+ attr_accessor :array, :stream # Leave these public and open.
30
+ attr_reader :iface, :snaplen, :promisc, :timeout, :filter
31
+
32
+ def initialize(args={})
33
+ @array = [] # Where the packet array goes.
34
+ @stream = [] # Where the stream goes.
35
+ @iface = (args[:iface] || ENV['IFACE'] || Pcap.lookupdev || "lo").to_s
36
+ @snaplen = args[:snaplen] || 0xffff
37
+ @promisc = args[:promisc] || false # Sensible for some Intel wifi cards
38
+ @timeout = args[:timeout] || 1
39
+ @filter = args[:filter] || args[:bpf]
40
+ setup_params(args)
41
+ end
42
+
43
+ # Used by new().
44
+ def setup_params(args={})
45
+ filter = args[:filter] || args[:bpf] || @filter
46
+ start = args[:start] || false
47
+ capture if start
48
+ bpf(:filter=>filter) if filter
49
+ end
50
+
51
+ # capture() initializes the @stream varaible. Valid arguments are:
52
+ #
53
+ # :filter
54
+ # Provide a bpf filter to enable for the capture. For example, 'ip and not tcp'
55
+ # :start
56
+ # When true, start capturing packets to the @stream variable. Defaults to true
57
+ def capture(args={})
58
+ if Process.euid.zero?
59
+ filter = args[:filter] || args[:bpf] || @filter
60
+ start = args[:start] || true
61
+ if start
62
+ begin
63
+ @stream = Pcap.open_live(@iface,@snaplen,@promisc,@timeout)
64
+ rescue RuntimeError
65
+ $stderr.print "Are you sure you're root? Error: "
66
+ raise
67
+ end
68
+ bpf(:filter=>filter) if filter
69
+ else
70
+ @stream = []
71
+ end
72
+ @stream
73
+ else
74
+ raise RuntimeError,"Not root, so can't capture packets. Error: "
75
+ end
76
+ end
77
+
78
+ # start() is equivalent to capture().
79
+ def start(args={})
80
+ capture(args)
81
+ end
82
+
83
+ # clear() clears the @stream and @array variables, essentially starting the
84
+ # capture session over. Valid arguments are:
85
+ #
86
+ # :array
87
+ # If true, the @array is cleared.
88
+ # :stream
89
+ # If true, the @stream is cleared.
90
+ def clear(args={})
91
+ array = args[:array] || true
92
+ stream = args[:stream] || true
93
+ @array = [] if array
94
+ @stream = [] if stream
95
+ end
96
+
97
+ # bpf() sets a bpf filter on a capture session. Valid arugments are:
98
+ #
99
+ # :filter
100
+ # Provide a bpf filter to enable for the capture. For example, 'ip and not tcp'
101
+ def bpf(args={})
102
+ filter = args[:filter] || args[:bpf] || @filter
103
+ capture if @stream.class == Array
104
+ @stream.setfilter(filter) if filter
105
+ @filter = filter
106
+ end
107
+
108
+ alias :filter :bpf
109
+
110
+ # wire_to_array() saves a packet stream as an array of binary strings. From here,
111
+ # packets may accessed by other functions. Note that the wire_to_array empties
112
+ # the stream, so multiple calls will append new packets to @array.
113
+ # Valid arguments are:
114
+ #
115
+ # :filter
116
+ # Provide a bpf filter to apply to packets moving from @stream to @array.
117
+ def wire_to_array(args={})
118
+ filter = args[:filter] || args[:bpf] || @filter
119
+ bpf(:filter=>filter) if filter
120
+
121
+ while this_pkt = @stream.next
122
+ @array << this_pkt
123
+ end
124
+ @array.size
125
+ end
126
+
127
+ # next() exposes the Stream object's next method to the outside world.
128
+ def next
129
+ return @stream.next
130
+ end
131
+
132
+ # w2a() is a equivalent to wire_to_array()
133
+ def w2a(args={})
134
+ wire_to_array(args)
135
+ end
136
+
137
+ # save() is a equivalent to wire_to_array()
138
+ def save(args={})
139
+ wire_to_array(args)
140
+ end
141
+
142
+ # show_live() is a method to capture packets and display peek() data to stdout. Valid arguments are:
143
+ #
144
+ # :filter
145
+ # Provide a bpf filter to captured packets.
146
+ # :save
147
+ # Save the capture in @array
148
+ # :verbose
149
+ # TODO: Not implemented yet; do more than just peek() at the packets.
150
+ # :quiet
151
+ # TODO: Not implemented yet; do less than peek() at the packets.
152
+ def show_live(args={})
153
+ filter = args[:filter] || args[:bpf] || @filter
154
+ save = args[:save]
155
+ verbose = args[:verbose] || args[:v] || false
156
+ quiet = args[:quiet] || args[:q] || false # Setting q and v doesn't make a lot of sense but hey.
157
+
158
+ # Ensure the capture's started.
159
+ if @stream.class == Array
160
+ capture
161
+ end
162
+
163
+ @stream.setfilter(filter) if filter
164
+ while true
165
+ @stream.each do |pkt|
166
+ puts Packet.parse(pkt).peek
167
+ @array << pkt if args[:save]
168
+ end
169
+ end
170
+ end
171
+
172
+ end
173
173
  end
@@ -1,59 +1,59 @@
1
1
  # -*- coding: binary -*-
2
2
  module PacketFu
3
3
 
4
- # The Config class holds various bits of useful default information
5
- # for packet creation. If initialized without arguments, @iface will be
6
- # set to ENV['IFACE'] or Pcap.lookupdev (or lo), and the @pcapfile will
7
- # be set to "/tmp/out.pcap" # (yes, it's Linux-biased, sorry, fixing
8
- # this is a TODO.)
9
- #
10
- # Any number of instance variables can be passed in to the intialize function (as a
11
- # hash), though only the expected network-related variables will be readable and
12
- # writeable directly.
13
- #
14
- # == Examples
15
- #
16
- # PacketFu::Config.new(:ip_saddr => "1.2.3.4").ip_saddr #=> "1.2.3.4"
17
- # PacketFu::Config.new(:foo=>"bar").foo #=> NomethodError: undefined method `foo'...
18
- #
19
- # The config() function, however, does provide access to custom variables:
20
- #
21
- # PacketFu::Config.new(:foo=>"bar").config[:foo] #=> "bar"
22
- # obj = PacketFu::Config.new(:foo=>"bar")
23
- # obj.config(:baz => "bat")
24
- # obj.config #=> {:iface=>"eth0", :baz=>"bat", :pcapfile=>"/tmp/out.pcap", :foo=>"bar"}
25
- class Config
26
- attr_accessor :eth_saddr, # The discovered eth_saddr
27
- :eth_daddr, # The discovered eth_daddr (ie, the gateway)
28
- :eth_src, # The discovered eth_src in binary form.
29
- :eth_dst, # The discovered eth_dst (gateway) in binary form.
30
- :ip_saddr, # The discovered ip_saddr
31
- :ip_src, # The discovered ip_src in binary form.
32
- :iface, # The declared interface.
33
- :pcapfile # A declared default file to write to.
34
-
35
- def initialize(args={})
36
- if Process.euid.zero?
37
- @iface = args[:iface] || ENV['IFACE'] || Pcap.lookupdev || "lo"
38
- end
39
- @pcapfile = "/tmp/out.pcap"
40
- args.each_pair { |k,v| self.instance_variable_set(("@#{k}"),v) }
41
- end
4
+ # The Config class holds various bits of useful default information
5
+ # for packet creation. If initialized without arguments, @iface will be
6
+ # set to ENV['IFACE'] or Pcap.lookupdev (or lo), and the @pcapfile will
7
+ # be set to "/tmp/out.pcap" # (yes, it's Linux-biased, sorry, fixing
8
+ # this is a TODO.)
9
+ #
10
+ # Any number of instance variables can be passed in to the intialize function (as a
11
+ # hash), though only the expected network-related variables will be readable and
12
+ # writeable directly.
13
+ #
14
+ # == Examples
15
+ #
16
+ # PacketFu::Config.new(:ip_saddr => "1.2.3.4").ip_saddr #=> "1.2.3.4"
17
+ # PacketFu::Config.new(:foo=>"bar").foo #=> NomethodError: undefined method `foo'...
18
+ #
19
+ # The config() function, however, does provide access to custom variables:
20
+ #
21
+ # PacketFu::Config.new(:foo=>"bar").config[:foo] #=> "bar"
22
+ # obj = PacketFu::Config.new(:foo=>"bar")
23
+ # obj.config(:baz => "bat")
24
+ # obj.config #=> {:iface=>"eth0", :baz=>"bat", :pcapfile=>"/tmp/out.pcap", :foo=>"bar"}
25
+ class Config
26
+ attr_accessor :eth_saddr, # The discovered eth_saddr
27
+ :eth_daddr, # The discovered eth_daddr (ie, the gateway)
28
+ :eth_src, # The discovered eth_src in binary form.
29
+ :eth_dst, # The discovered eth_dst (gateway) in binary form.
30
+ :ip_saddr, # The discovered ip_saddr
31
+ :ip_src, # The discovered ip_src in binary form.
32
+ :iface, # The declared interface.
33
+ :pcapfile # A declared default file to write to.
34
+
35
+ def initialize(args={})
36
+ if Process.euid.zero?
37
+ @iface = args[:iface] || ENV['IFACE'] || Pcap.lookupdev || "lo"
38
+ end
39
+ @pcapfile = "/tmp/out.pcap"
40
+ args.each_pair { |k,v| self.instance_variable_set(("@#{k}"),v) }
41
+ end
42
42
 
43
- # Returns all instance variables as a hash (including custom variables set at initialization).
44
- def config(arg=nil)
45
- if arg
46
- arg.each_pair {|k,v| self.instance_variable_set(("@" + k.to_s).intern, v)}
47
- else
48
- config_hash = {}
49
- self.instance_variables.each do |v|
50
- key = v.to_s.gsub(/^@/,"").to_sym
51
- config_hash[key] = self.instance_variable_get(v)
52
- end
53
- config_hash
54
- end
55
- end
43
+ # Returns all instance variables as a hash (including custom variables set at initialization).
44
+ def config(arg=nil)
45
+ if arg
46
+ arg.each_pair {|k,v| self.instance_variable_set(("@" + k.to_s).intern, v)}
47
+ else
48
+ config_hash = {}
49
+ self.instance_variables.each do |v|
50
+ key = v.to_s.gsub(/^@/,"").to_sym
51
+ config_hash[key] = self.instance_variable_get(v)
52
+ end
53
+ config_hash
54
+ end
55
+ end
56
56
 
57
- end
57
+ end
58
58
 
59
59
  end