packetfu 1.0.0
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.
- data/.document +4 -0
- data/CHANGES +36 -0
- data/INSTALL +40 -0
- data/LICENSE +28 -0
- data/README +25 -0
- data/TODO +25 -0
- data/examples/ackscan.rb +38 -0
- data/examples/arp.rb +60 -0
- data/examples/arphood.rb +56 -0
- data/examples/ethernet.rb +10 -0
- data/examples/examples.rb +3 -0
- data/examples/ids.rb +4 -0
- data/examples/idsv2.rb +6 -0
- data/examples/oui.txt +84177 -0
- data/examples/packetfu-shell.rb +111 -0
- data/examples/simple-stats.rb +42 -0
- data/examples/slammer.rb +33 -0
- data/examples/uniqpcap.rb +15 -0
- data/lib/packetfu.rb +108 -0
- data/lib/packetfu/arp.rb +239 -0
- data/lib/packetfu/capture.rb +169 -0
- data/lib/packetfu/config.rb +55 -0
- data/lib/packetfu/eth.rb +264 -0
- data/lib/packetfu/icmp.rb +153 -0
- data/lib/packetfu/inject.rb +65 -0
- data/lib/packetfu/invalid.rb +41 -0
- data/lib/packetfu/ip.rb +318 -0
- data/lib/packetfu/ipv6.rb +230 -0
- data/lib/packetfu/packet.rb +492 -0
- data/lib/packetfu/pcap.rb +502 -0
- data/lib/packetfu/structfu.rb +274 -0
- data/lib/packetfu/tcp.rb +1061 -0
- data/lib/packetfu/udp.rb +210 -0
- data/lib/packetfu/utils.rb +182 -0
- data/test/all_tests.rb +37 -0
- data/test/ptest.rb +10 -0
- data/test/sample.pcap +0 -0
- data/test/sample2.pcap +0 -0
- data/test/test_arp.rb +135 -0
- data/test/test_eth.rb +90 -0
- data/test/test_icmp.rb +54 -0
- data/test/test_inject.rb +33 -0
- data/test/test_invalid.rb +28 -0
- data/test/test_ip.rb +69 -0
- data/test/test_ip6.rb +68 -0
- data/test/test_octets.rb +37 -0
- data/test/test_packet.rb +41 -0
- data/test/test_pcap.rb +210 -0
- data/test/test_structfu.rb +112 -0
- data/test/test_tcp.rb +327 -0
- data/test/test_udp.rb +73 -0
- metadata +144 -0
@@ -0,0 +1,169 @@
|
|
1
|
+
module PacketFu
|
2
|
+
|
3
|
+
# The Capture class is used to construct PcapRub objects in order to collect
|
4
|
+
# packets from an interface.
|
5
|
+
#
|
6
|
+
# This class requires PcapRub. In addition, you will need root (or root-like) privileges
|
7
|
+
# in order to capture from the interface.
|
8
|
+
#
|
9
|
+
# Note, on some wireless cards, setting :promisc => true will disable capturing.
|
10
|
+
#
|
11
|
+
# == Example
|
12
|
+
#
|
13
|
+
# # Typical use
|
14
|
+
# cap = PacketFu::Capture.new(:iface => 'eth0', :promisc => true)
|
15
|
+
# cap.start
|
16
|
+
# sleep 10
|
17
|
+
# cap.save
|
18
|
+
# first_packet = cap.array[0]
|
19
|
+
#
|
20
|
+
# # Tcpdump-like use
|
21
|
+
# cap = PacketFu::Capture.new(:start => true)
|
22
|
+
# cap.show_live(:save => true, :filter => 'tcp and not port 22')
|
23
|
+
#
|
24
|
+
# == See Also
|
25
|
+
#
|
26
|
+
# Read, Write
|
27
|
+
class Capture
|
28
|
+
attr_accessor :array, :stream # Leave these public and open.
|
29
|
+
attr_reader :iface, :snaplen, :promisc, :timeout # Cant change after the init.
|
30
|
+
|
31
|
+
def initialize(args={})
|
32
|
+
@array = [] # Where the packet array goes.
|
33
|
+
@stream = [] # Where the stream goes.
|
34
|
+
@iface = args[:iface] || ENV['IFACE'] || Pcap.lookupdev || "lo"
|
35
|
+
@snaplen = args[:snaplen] || 0xffff
|
36
|
+
@promisc = args[:promisc] || false # Sensible for some Intel wifi cards
|
37
|
+
@timeout = args[:timeout] || 1
|
38
|
+
|
39
|
+
setup_params(args)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Used by new().
|
43
|
+
def setup_params(args={})
|
44
|
+
filter = args[:filter] # Not global; filter criteria can change.
|
45
|
+
start = args[:start] || false
|
46
|
+
capture if start
|
47
|
+
bpf(:filter=>filter) if filter
|
48
|
+
end
|
49
|
+
|
50
|
+
# capture() initializes the @stream varaible. Valid arguments are:
|
51
|
+
#
|
52
|
+
# :filter
|
53
|
+
# Provide a bpf filter to enable for the capture. For example, 'ip and not tcp'
|
54
|
+
# :start
|
55
|
+
# When true, start capturing packets to the @stream variable. Defaults to true
|
56
|
+
def capture(args={})
|
57
|
+
if Process.euid.zero?
|
58
|
+
filter = args[:filter]
|
59
|
+
start = args[:start] || true
|
60
|
+
if start
|
61
|
+
begin
|
62
|
+
@stream = Pcap.open_live(@iface,@snaplen,@promisc,@timeout)
|
63
|
+
rescue RuntimeError
|
64
|
+
$stderr.print "Are you sure you're root? Error: "
|
65
|
+
raise
|
66
|
+
end
|
67
|
+
bpf(:filter=>filter) if filter
|
68
|
+
else
|
69
|
+
@stream = []
|
70
|
+
end
|
71
|
+
@stream
|
72
|
+
else
|
73
|
+
raise RuntimeError,"Not root, so can't capture packets. Error: "
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# start() is equivalent to capture().
|
78
|
+
def start(args={})
|
79
|
+
capture(args)
|
80
|
+
end
|
81
|
+
|
82
|
+
# clear() clears the @stream and @array variables, essentially starting the
|
83
|
+
# capture session over. Valid arguments are:
|
84
|
+
#
|
85
|
+
# :array
|
86
|
+
# If true, the @array is cleared.
|
87
|
+
# :stream
|
88
|
+
# If true, the @stream is cleared.
|
89
|
+
def clear(args={})
|
90
|
+
array = args[:array] || true
|
91
|
+
stream = args[:stream] || true
|
92
|
+
@array = [] if array
|
93
|
+
@stream = [] if stream
|
94
|
+
end
|
95
|
+
|
96
|
+
# bpf() sets a bpf filter on a capture session. Valid arugments are:
|
97
|
+
#
|
98
|
+
# :filter
|
99
|
+
# Provide a bpf filter to enable for the capture. For example, 'ip and not tcp'
|
100
|
+
def bpf(args={})
|
101
|
+
filter = args[:filter]
|
102
|
+
capture if @stream.class == Array
|
103
|
+
@stream.setfilter(filter)
|
104
|
+
end
|
105
|
+
|
106
|
+
# wire_to_array() saves a packet stream as an array of binary strings. From here,
|
107
|
+
# packets may accessed by other functions. Note that the wire_to_array empties
|
108
|
+
# the stream, so multiple calls will append new packets to @array.
|
109
|
+
# Valid arguments are:
|
110
|
+
#
|
111
|
+
# :filter
|
112
|
+
# Provide a bpf filter to apply to packets moving from @stream to @array.
|
113
|
+
def wire_to_array(args={})
|
114
|
+
filter = args[:filter]
|
115
|
+
bpf(:filter=>filter) if filter
|
116
|
+
|
117
|
+
while this_pkt = @stream.next
|
118
|
+
@array << this_pkt
|
119
|
+
end
|
120
|
+
@array.size
|
121
|
+
end
|
122
|
+
|
123
|
+
# next() exposes the Stream object's next method to the outside world.
|
124
|
+
def next
|
125
|
+
return @stream.next
|
126
|
+
end
|
127
|
+
|
128
|
+
# w2a() is a equivalent to wire_to_array()
|
129
|
+
def w2a(args={})
|
130
|
+
wire_to_array(args)
|
131
|
+
end
|
132
|
+
|
133
|
+
# save() is a equivalent to wire_to_array()
|
134
|
+
def save(args={})
|
135
|
+
wire_to_array(args)
|
136
|
+
end
|
137
|
+
|
138
|
+
# show_live() is a method to capture packets and display peek() data to stdout. Valid arguments are:
|
139
|
+
#
|
140
|
+
# :filter
|
141
|
+
# Provide a bpf filter to captured packets.
|
142
|
+
# :save
|
143
|
+
# Save the capture in @array
|
144
|
+
# :verbose
|
145
|
+
# TODO: Not implemented yet; do more than just peek() at the packets.
|
146
|
+
# :quiet
|
147
|
+
# TODO: Not implemented yet; do less than peek() at the packets.
|
148
|
+
def show_live(args={})
|
149
|
+
filter = args[:filter]
|
150
|
+
save = args[:save]
|
151
|
+
verbose = args[:verbose] || args[:v] || false
|
152
|
+
quiet = args[:quiet] || args[:q] || false # Setting q and v doesn't make a lot of sense but hey.
|
153
|
+
|
154
|
+
# Ensure the capture's started.
|
155
|
+
if @stream.class == Array
|
156
|
+
capture
|
157
|
+
end
|
158
|
+
|
159
|
+
@stream.setfilter(filter) if filter
|
160
|
+
while true
|
161
|
+
@stream.each do |pkt|
|
162
|
+
puts Packet.parse(pkt).peek
|
163
|
+
@array << pkt if args[:save]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module PacketFu
|
2
|
+
|
3
|
+
# The Config class holds various bits of useful default information
|
4
|
+
# for packet creation. If initialized without arguments, @iface will be
|
5
|
+
# set to ENV['IFACE'] or Pcap.lookupdev (or lo), and the @pcapfile will
|
6
|
+
# be set to "/tmp/out.pcap" # (yes, it's Linux-biased, sorry, fixing
|
7
|
+
# this is a TODO.)
|
8
|
+
#
|
9
|
+
# Any number of instance variables can be passed in to the intialize function (as a
|
10
|
+
# hash), though only the expected network-related variables will be readable and
|
11
|
+
# writeable directly.
|
12
|
+
#
|
13
|
+
# == Examples
|
14
|
+
#
|
15
|
+
# PacketFu::Config.new(:ip_saddr => "1.2.3.4").ip_saddr #=> "1.2.3.4"
|
16
|
+
# PacketFu::Config.new(:foo=>"bar").foo #=> NomethodError: undefined method `foo'...
|
17
|
+
#
|
18
|
+
# The config() function, however, does provide access to custom variables:
|
19
|
+
#
|
20
|
+
# PacketFu::Config.new(:foo=>"bar").config[:foo] #=> "bar"
|
21
|
+
# obj = PacketFu::Config.new(:foo=>"bar")
|
22
|
+
# obj.config(:baz => "bat")
|
23
|
+
# obj.config #=> {:iface=>"eth0", :baz=>"bat", :pcapfile=>"/tmp/out.pcap", :foo=>"bar"}
|
24
|
+
class Config
|
25
|
+
attr_accessor :eth_saddr, # The discovered eth_saddr
|
26
|
+
:eth_daddr, # The discovered eth_daddr (ie, the gateway)
|
27
|
+
:eth_src, # The discovered eth_src in binary form.
|
28
|
+
:eth_dst, # The discovered eth_dst (gateway) in binary form.
|
29
|
+
:ip_saddr, # The discovered ip_saddr
|
30
|
+
:ip_src, # The discovered ip_src in binary form.
|
31
|
+
:iface, # The declared interface.
|
32
|
+
:pcapfile # A declared default file to write to.
|
33
|
+
|
34
|
+
def initialize(args={})
|
35
|
+
if Process.euid.zero?
|
36
|
+
@iface = args[:iface] || ENV['IFACE'] || Pcap.lookupdev || "lo"
|
37
|
+
end
|
38
|
+
@pcapfile = "/tmp/out.pcap"
|
39
|
+
args.each_pair { |k,v| self.instance_variable_set(("@" + k.to_s).intern,v) }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns all instance variables as a hash (including custom variables set at initialization).
|
43
|
+
def config(arg=nil)
|
44
|
+
if arg.nil?
|
45
|
+
config_hash = {}
|
46
|
+
self.instance_variables.each { |v| config_hash[v.delete("@").intern] = self.instance_variable_get(v) }
|
47
|
+
config_hash
|
48
|
+
else
|
49
|
+
arg.each_pair {|k,v| self.instance_variable_set(("@" + k.to_s).intern, v)}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
data/lib/packetfu/eth.rb
ADDED
@@ -0,0 +1,264 @@
|
|
1
|
+
module PacketFu
|
2
|
+
|
3
|
+
# EthOui is the Organizationally Unique Identifier portion of a MAC address, used in EthHeader.
|
4
|
+
#
|
5
|
+
# See the OUI list at http://standards.ieee.org/regauth/oui/oui.txt
|
6
|
+
#
|
7
|
+
# ==== Header Definition
|
8
|
+
#
|
9
|
+
# Fixnum :b0
|
10
|
+
# Fixnum :b1
|
11
|
+
# Fixnum :b2
|
12
|
+
# Fixnum :b3
|
13
|
+
# Fixnum :b4
|
14
|
+
# Fixnum :b5
|
15
|
+
# Fixnum :local
|
16
|
+
# Fixnum :multicast
|
17
|
+
# Int16 :oui, Default: 0x1ac5 :)
|
18
|
+
class EthOui < Struct.new(:b5, :b4, :b3, :b2, :b1, :b0, :local, :multicast, :oui)
|
19
|
+
|
20
|
+
# EthOui is unusual in that the bit values do not enjoy StructFu typing.
|
21
|
+
def initialize(args={})
|
22
|
+
args[:local] ||= 0
|
23
|
+
args[:oui] ||= 0x1ac # :)
|
24
|
+
args.each_pair {|k,v| args[k] = 0 unless v}
|
25
|
+
super(args[:b5], args[:b4], args[:b3], args[:b2],
|
26
|
+
args[:b1], args[:b0], args[:local], args[:multicast],
|
27
|
+
args[:oui])
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the object in string form.
|
31
|
+
def to_s
|
32
|
+
byte = 0
|
33
|
+
byte += 0b10000000 if b5.to_i == 1
|
34
|
+
byte += 0b01000000 if b4.to_i == 1
|
35
|
+
byte += 0b00100000 if b3.to_i == 1
|
36
|
+
byte += 0b00010000 if b2.to_i == 1
|
37
|
+
byte += 0b00001000 if b1.to_i == 1
|
38
|
+
byte += 0b00000100 if b0.to_i == 1
|
39
|
+
byte += 0b00000010 if local.to_i == 1
|
40
|
+
byte += 0b00000001 if multicast.to_i == 1
|
41
|
+
[byte,oui].pack("Cn")
|
42
|
+
end
|
43
|
+
|
44
|
+
# Reads a string to populate the object.
|
45
|
+
def read(str)
|
46
|
+
force_binary(str)
|
47
|
+
return self if str.nil?
|
48
|
+
if 1.respond_to? :ord
|
49
|
+
byte = str[0].ord
|
50
|
+
else
|
51
|
+
byte = str[0]
|
52
|
+
end
|
53
|
+
self[:b5] = byte & 0b10000000 == 0b10000000 ? 1 : 0
|
54
|
+
self[:b4] = byte & 0b01000000 == 0b01000000 ? 1 : 0
|
55
|
+
self[:b3] = byte & 0b00100000 == 0b00100000 ? 1 : 0
|
56
|
+
self[:b2] = byte & 0b00010000 == 0b00010000 ? 1 : 0
|
57
|
+
self[:b1] = byte & 0b00001000 == 0b00001000 ? 1 : 0
|
58
|
+
self[:b0] = byte & 0b00000100 == 0b00000100 ? 1 : 0
|
59
|
+
self[:local] = byte & 0b00000010 == 0b00000010 ? 1 : 0
|
60
|
+
self[:multicast] = byte & 0b00000001 == 0b00000001 ? 1 : 0
|
61
|
+
self[:oui] = str[1,2].unpack("n").first
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
# EthNic is the Network Interface Controler portion of a MAC address, used in EthHeader.
|
68
|
+
#
|
69
|
+
# ==== Header Definition
|
70
|
+
#
|
71
|
+
# Fixnum :n1
|
72
|
+
# Fixnum :n2
|
73
|
+
# Fixnum :n3
|
74
|
+
#
|
75
|
+
class EthNic < Struct.new(:n0, :n1, :n2)
|
76
|
+
|
77
|
+
# EthNic does not enjoy StructFu typing.
|
78
|
+
def initialize(args={})
|
79
|
+
args.each_pair {|k,v| args[k] = 0 unless v}
|
80
|
+
super(args[:n0], args[:n1], args[:n2])
|
81
|
+
end
|
82
|
+
|
83
|
+
# Returns the object in string form.
|
84
|
+
def to_s
|
85
|
+
[n0,n1,n2].map {|x| x.to_i}.pack("C3")
|
86
|
+
end
|
87
|
+
|
88
|
+
# Reads a string to populate the object.
|
89
|
+
def read(str)
|
90
|
+
force_binary(str)
|
91
|
+
return self if str.nil?
|
92
|
+
self[:n0], self[:n1], self[:n2] = str[0,3].unpack("C3")
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
# EthMac is the combination of an EthOui and EthNic, used in EthHeader.
|
99
|
+
#
|
100
|
+
# ==== Header Definition
|
101
|
+
#
|
102
|
+
# EthOui :oui # See EthOui
|
103
|
+
# EthNic :nic # See EthNic
|
104
|
+
class EthMac < Struct.new(:oui, :nic)
|
105
|
+
|
106
|
+
def initialize(args={})
|
107
|
+
super(
|
108
|
+
EthOui.new.read(args[:oui]),
|
109
|
+
EthNic.new.read(args[:nic]))
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns the object in string form.
|
113
|
+
def to_s
|
114
|
+
"#{self[:oui]}#{self[:nic]}"
|
115
|
+
end
|
116
|
+
|
117
|
+
# Reads a string to populate the object.
|
118
|
+
def read(str)
|
119
|
+
force_binary(str)
|
120
|
+
return self if str.nil?
|
121
|
+
self.oui.read str[0,3]
|
122
|
+
self.nic.read str[3,3]
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
# EthHeader is a complete Ethernet struct, used in EthPacket.
|
129
|
+
# It's the base header for all other protocols, such as IPHeader,
|
130
|
+
# TCPHeader, etc.
|
131
|
+
#
|
132
|
+
# For more on the construction on MAC addresses, see
|
133
|
+
# http://en.wikipedia.org/wiki/MAC_address
|
134
|
+
#
|
135
|
+
# ==== Header Definition
|
136
|
+
#
|
137
|
+
# EthMac :eth_dst # See EthMac
|
138
|
+
# EthMac :eth_src # See EthMac
|
139
|
+
# Int16 :eth_proto, Default: 0x8000 # IP 0x0800, Arp 0x0806
|
140
|
+
# String :body
|
141
|
+
class EthHeader < Struct.new(:eth_dst, :eth_src, :eth_proto, :body)
|
142
|
+
include StructFu
|
143
|
+
|
144
|
+
def initialize(args={})
|
145
|
+
super(
|
146
|
+
EthMac.new.read(args[:eth_dst]),
|
147
|
+
EthMac.new.read(args[:eth_src]),
|
148
|
+
Int16.new(args[:eth_proto] || 0x0800),
|
149
|
+
StructFu::String.new.read(args[:body])
|
150
|
+
)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Setter for the Ethernet destination address.
|
154
|
+
def eth_dst=(i); typecast(i); end
|
155
|
+
# Getter for the Ethernet destination address.
|
156
|
+
def eth_dst; self[:eth_dst].to_s; end
|
157
|
+
# Setter for the Ethernet source address.
|
158
|
+
def eth_src=(i); typecast(i); end
|
159
|
+
# Getter for the Ethernet source address.
|
160
|
+
def eth_src; self[:eth_src].to_s; end
|
161
|
+
# Setter for the Ethernet protocol number.
|
162
|
+
def eth_proto=(i); typecast(i); end
|
163
|
+
# Getter for the Ethernet protocol number.
|
164
|
+
def eth_proto; self[:eth_proto].to_i; end
|
165
|
+
|
166
|
+
# Returns the object in string form.
|
167
|
+
def to_s
|
168
|
+
self.to_a.map {|x| x.to_s}.join
|
169
|
+
end
|
170
|
+
|
171
|
+
# Reads a string to populate the object.
|
172
|
+
def read(str)
|
173
|
+
force_binary(str)
|
174
|
+
return self if str.nil?
|
175
|
+
self[:eth_dst].read str[0,6]
|
176
|
+
self[:eth_src].read str[6,6]
|
177
|
+
self[:eth_proto].read str[12,2]
|
178
|
+
self[:body].read str[14,str.size]
|
179
|
+
self
|
180
|
+
end
|
181
|
+
|
182
|
+
# Converts a readable MAC (11:22:33:44:55:66) to a binary string.
|
183
|
+
# Readable MAC's may be split on colons, dots, spaces, or underscores.
|
184
|
+
#
|
185
|
+
# irb> PacketFu::EthHeader.mac2str("11:22:33:44:55:66")
|
186
|
+
#
|
187
|
+
# #=> "\021\"3DUf"
|
188
|
+
def self.mac2str(mac)
|
189
|
+
if mac.split(/[:\x2d\x2e\x5f]+/).size == 6
|
190
|
+
ret = mac.split(/[:\x2d\x2e\x20\x5f]+/).collect {|x| x.to_i(16)}.pack("C6")
|
191
|
+
else
|
192
|
+
raise ArgumentError, "Unkown format for mac address."
|
193
|
+
end
|
194
|
+
return ret
|
195
|
+
end
|
196
|
+
|
197
|
+
# Converts a binary string to a readable MAC (11:22:33:44:55:66).
|
198
|
+
#
|
199
|
+
# irb> PacketFu::EthHeader.str2mac("\x11\x22\x33\x44\x55\x66")
|
200
|
+
#
|
201
|
+
# #=> "11:22:33:44:55:66"
|
202
|
+
def self.str2mac(mac='')
|
203
|
+
if mac.to_s.size == 6 && mac.kind_of?(::String)
|
204
|
+
ret = mac.unpack("C6").map {|x| sprintf("%02x",x)}.join(":")
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Sets the source MAC address in a more readable way.
|
209
|
+
def eth_saddr=(mac)
|
210
|
+
mac = EthHeader.mac2str(mac)
|
211
|
+
self[:eth_src].read mac
|
212
|
+
self[:eth_src]
|
213
|
+
end
|
214
|
+
|
215
|
+
# Gets the source MAC address in a more readable way.
|
216
|
+
def eth_saddr
|
217
|
+
EthHeader.str2mac(self[:eth_src].to_s)
|
218
|
+
end
|
219
|
+
|
220
|
+
# Set the destination MAC address in a more readable way.
|
221
|
+
def eth_daddr=(mac)
|
222
|
+
mac = EthHeader.mac2str(mac)
|
223
|
+
self[:eth_dst].read mac
|
224
|
+
self[:eth_dst]
|
225
|
+
end
|
226
|
+
|
227
|
+
# Gets the destination MAC address in a more readable way.
|
228
|
+
def eth_daddr
|
229
|
+
EthHeader.str2mac(self[:eth_dst].to_s)
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
# EthPacket is used to construct Ethernet packets. They contain an
|
235
|
+
# Ethernet header, and that's about it.
|
236
|
+
#
|
237
|
+
# == Example
|
238
|
+
#
|
239
|
+
# require 'packetfu'
|
240
|
+
# eth_pkt = PacketFu::EthPacket.new
|
241
|
+
# eth_pkt.eth_saddr="00:1c:23:44:55:66"
|
242
|
+
# eth_pkt.eth_daddr="00:1c:24:aa:bb:cc"
|
243
|
+
#
|
244
|
+
# eth_pkt.to_w('eth0') # Inject on the wire. (require root)
|
245
|
+
class EthPacket < Packet
|
246
|
+
attr_accessor :eth_header
|
247
|
+
|
248
|
+
def initialize(args={})
|
249
|
+
@eth_header = EthHeader.new(args).read(args[:eth])
|
250
|
+
@headers = [@eth_header]
|
251
|
+
super
|
252
|
+
end
|
253
|
+
|
254
|
+
# Does nothing, really, since there's no length or
|
255
|
+
# checksum to calculate for a straight Ethernet packet.
|
256
|
+
def recalc(args={})
|
257
|
+
@headers[0].inspect
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|
261
|
+
|
262
|
+
end
|
263
|
+
|
264
|
+
# vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
|