packetfu 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/.gitignore +3 -0
  2. data/INSTALL.rdoc +40 -0
  3. data/LICENSE.txt +25 -0
  4. data/examples/100kpackets.rb +41 -0
  5. data/examples/ackscan.rb +38 -0
  6. data/examples/arp.rb +60 -0
  7. data/examples/arphood.rb +59 -0
  8. data/examples/dissect_thinger.rb +22 -0
  9. data/examples/ethernet.rb +10 -0
  10. data/examples/examples.rb +3 -0
  11. data/examples/ids.rb +4 -0
  12. data/examples/idsv2.rb +6 -0
  13. data/examples/new-simple-stats.rb +52 -0
  14. data/examples/oui.txt +84177 -0
  15. data/examples/packetfu-shell.rb +113 -0
  16. data/examples/simple-sniffer.rb +40 -0
  17. data/examples/simple-stats.rb +50 -0
  18. data/examples/slammer.rb +33 -0
  19. data/examples/uniqpcap.rb +15 -0
  20. data/lib/packetfu.rb +147 -0
  21. data/lib/packetfu/capture.rb +169 -0
  22. data/lib/packetfu/config.rb +58 -0
  23. data/lib/packetfu/inject.rb +65 -0
  24. data/lib/packetfu/packet.rb +533 -0
  25. data/lib/packetfu/pcap.rb +594 -0
  26. data/lib/packetfu/protos/arp.rb +268 -0
  27. data/lib/packetfu/protos/eth.rb +296 -0
  28. data/lib/packetfu/protos/hsrp.rb +206 -0
  29. data/lib/packetfu/protos/icmp.rb +179 -0
  30. data/lib/packetfu/protos/invalid.rb +55 -0
  31. data/lib/packetfu/protos/ip.rb +378 -0
  32. data/lib/packetfu/protos/ipv6.rb +250 -0
  33. data/lib/packetfu/protos/tcp.rb +1127 -0
  34. data/lib/packetfu/protos/udp.rb +240 -0
  35. data/lib/packetfu/structfu.rb +294 -0
  36. data/lib/packetfu/utils.rb +194 -0
  37. data/lib/packetfu/version.rb +50 -0
  38. data/packetfu.gemspec +21 -0
  39. data/setup.rb +1586 -0
  40. data/test/all_tests.rb +41 -0
  41. data/test/ethpacket_spec.rb +74 -0
  42. data/test/packet_spec.rb +73 -0
  43. data/test/packet_subclasses_spec.rb +13 -0
  44. data/test/packetfu_spec.rb +90 -0
  45. data/test/ptest.rb +16 -0
  46. data/test/sample-ipv6.pcap +0 -0
  47. data/test/sample.pcap +0 -0
  48. data/test/sample2.pcap +0 -0
  49. data/test/sample_hsrp_pcapr.cap +0 -0
  50. data/test/structfu_spec.rb +335 -0
  51. data/test/tcp_spec.rb +101 -0
  52. data/test/test_arp.rb +135 -0
  53. data/test/test_eth.rb +91 -0
  54. data/test/test_hsrp.rb +20 -0
  55. data/test/test_icmp.rb +54 -0
  56. data/test/test_inject.rb +31 -0
  57. data/test/test_invalid.rb +28 -0
  58. data/test/test_ip.rb +69 -0
  59. data/test/test_ip6.rb +68 -0
  60. data/test/test_octets.rb +37 -0
  61. data/test/test_packet.rb +174 -0
  62. data/test/test_pcap.rb +209 -0
  63. data/test/test_structfu.rb +112 -0
  64. data/test/test_tcp.rb +327 -0
  65. data/test/test_udp.rb +73 -0
  66. data/test/vlan-pcapr.cap +0 -0
  67. metadata +85 -6
@@ -0,0 +1,268 @@
1
+ module PacketFu
2
+
3
+ # ARPHeader is a complete ARP struct, used in ARPPacket.
4
+ #
5
+ # ARP is used to discover the machine address of nearby devices.
6
+ #
7
+ # See http://www.networksorcery.com/enp/protocol/arp.htm for details.
8
+ #
9
+ # ==== Header Definition
10
+ #
11
+ # Int16 :arp_hw Default: 1 # Ethernet
12
+ # Int16 :arp_proto, Default: 0x8000 # IP
13
+ # Int8 :arp_hw_len, Default: 6
14
+ # Int8 :arp_proto_len, Default: 4
15
+ # Int16 :arp_opcode, Default: 1 # 1: Request, 2: Reply, 3: Request-Reverse, 4: Reply-Reverse
16
+ # EthMac :arp_src_mac # From eth.rb
17
+ # Octets :arp_src_ip # From ip.rb
18
+ # EthMac :arp_dst_mac # From eth.rb
19
+ # Octets :arp_dst_ip # From ip.rb
20
+ # String :body
21
+ class ARPHeader < Struct.new(:arp_hw, :arp_proto, :arp_hw_len,
22
+ :arp_proto_len, :arp_opcode,
23
+ :arp_src_mac, :arp_src_ip,
24
+ :arp_dst_mac, :arp_dst_ip,
25
+ :body)
26
+ include StructFu
27
+
28
+ def initialize(args={})
29
+ src_mac = args[:arp_src_mac] || (args[:config][:eth_src] if args[:config])
30
+ src_ip_bin = args[:arp_src_ip] || (args[:config][:ip_src_bin] if args[:config])
31
+
32
+ super(
33
+ Int16.new(args[:arp_hw] || 1),
34
+ Int16.new(args[:arp_proto] ||0x0800),
35
+ Int8.new(args[:arp_hw_len] || 6),
36
+ Int8.new(args[:arp_proto_len] || 4),
37
+ Int16.new(args[:arp_opcode] || 1),
38
+ EthMac.new.read(src_mac),
39
+ Octets.new.read(src_ip_bin),
40
+ EthMac.new.read(args[:arp_dst_mac]),
41
+ Octets.new.read(args[:arp_dst_ip]),
42
+ StructFu::String.new.read(args[:body])
43
+ )
44
+ end
45
+
46
+ # Returns the object in string form.
47
+ def to_s
48
+ self.to_a.map {|x| x.to_s}.join
49
+ end
50
+
51
+ # Reads a string to populate the object.
52
+ def read(str)
53
+ force_binary(str)
54
+ return self if str.nil?
55
+ self[:arp_hw].read(str[0,2])
56
+ self[:arp_proto].read(str[2,2])
57
+ self[:arp_hw_len].read(str[4,1])
58
+ self[:arp_proto_len].read(str[5,1])
59
+ self[:arp_opcode].read(str[6,2])
60
+ self[:arp_src_mac].read(str[8,6])
61
+ self[:arp_src_ip].read(str[14,4])
62
+ self[:arp_dst_mac].read(str[18,6])
63
+ self[:arp_dst_ip].read(str[24,4])
64
+ self[:body].read(str[28,str.size])
65
+ self
66
+ end
67
+
68
+ # Setter for the ARP hardware type.
69
+ def arp_hw=(i); typecast i; end
70
+ # Getter for the ARP hardware type.
71
+ def arp_hw; self[:arp_hw].to_i; end
72
+ # Setter for the ARP protocol.
73
+ def arp_proto=(i); typecast i; end
74
+ # Getter for the ARP protocol.
75
+ def arp_proto; self[:arp_proto].to_i; end
76
+ # Setter for the ARP hardware type length.
77
+ def arp_hw_len=(i); typecast i; end
78
+ # Getter for the ARP hardware type length.
79
+ def arp_hw_len; self[:arp_hw_len].to_i; end
80
+ # Setter for the ARP protocol length.
81
+ def arp_proto_len=(i); typecast i; end
82
+ # Getter for the ARP protocol length.
83
+ def arp_proto_len; self[:arp_proto_len].to_i; end
84
+ # Setter for the ARP opcode.
85
+ def arp_opcode=(i); typecast i; end
86
+ # Getter for the ARP opcode.
87
+ def arp_opcode; self[:arp_opcode].to_i; end
88
+ # Setter for the ARP source MAC address.
89
+ def arp_src_mac=(i); typecast i; end
90
+ # Getter for the ARP source MAC address.
91
+ def arp_src_mac; self[:arp_src_mac].to_s; end
92
+ # Getter for the ARP source IP address.
93
+ def arp_src_ip=(i); typecast i; end
94
+ # Setter for the ARP source IP address.
95
+ def arp_src_ip; self[:arp_src_ip].to_s; end
96
+ # Setter for the ARP destination MAC address.
97
+ def arp_dst_mac=(i); typecast i; end
98
+ # Setter for the ARP destination MAC address.
99
+ def arp_dst_mac; self[:arp_dst_mac].to_s; end
100
+ # Setter for the ARP destination IP address.
101
+ def arp_dst_ip=(i); typecast i; end
102
+ # Getter for the ARP destination IP address.
103
+ def arp_dst_ip; self[:arp_dst_ip].to_s; end
104
+
105
+ # Set the source MAC address in a more readable way.
106
+ def arp_saddr_mac=(mac)
107
+ mac = EthHeader.mac2str(mac)
108
+ self[:arp_src_mac].read(mac)
109
+ self.arp_src_mac
110
+ end
111
+
112
+ # Get a more readable source MAC address.
113
+ def arp_saddr_mac
114
+ EthHeader.str2mac(self[:arp_src_mac].to_s)
115
+ end
116
+
117
+ # Set the destination MAC address in a more readable way.
118
+ def arp_daddr_mac=(mac)
119
+ mac = EthHeader.mac2str(mac)
120
+ self[:arp_dst_mac].read(mac)
121
+ self.arp_dst_mac
122
+ end
123
+
124
+ # Get a more readable source MAC address.
125
+ def arp_daddr_mac
126
+ EthHeader.str2mac(self[:arp_dst_mac].to_s)
127
+ end
128
+
129
+ # Set a more readable source IP address.
130
+ def arp_saddr_ip=(addr)
131
+ self[:arp_src_ip].read_quad(addr)
132
+ end
133
+
134
+ # Get a more readable source IP address.
135
+ def arp_saddr_ip
136
+ self[:arp_src_ip].to_x
137
+ end
138
+
139
+ # Set a more readable destination IP address.
140
+ def arp_daddr_ip=(addr)
141
+ self[:arp_dst_ip].read_quad(addr)
142
+ end
143
+
144
+ # Get a more readable destination IP address.
145
+ def arp_daddr_ip
146
+ self[:arp_dst_ip].to_x
147
+ end
148
+
149
+ # Readability aliases
150
+
151
+ alias :arp_src_mac_readable :arp_saddr_mac
152
+ alias :arp_dst_mac_readable :arp_daddr_mac
153
+ alias :arp_src_ip_readable :arp_saddr_ip
154
+ alias :arp_dst_ip_readable :arp_daddr_ip
155
+
156
+ def arp_proto_readable
157
+ "0x%04x" % arp_proto
158
+ end
159
+
160
+ end # class ARPHeader
161
+
162
+ # ARPPacket is used to construct ARP packets. They contain an EthHeader and an ARPHeader.
163
+ # == Example
164
+ #
165
+ # require 'packetfu'
166
+ # arp_pkt = PacketFu::ARPPacket.new(:flavor => "Windows")
167
+ # arp_pkt.arp_saddr_mac="00:1c:23:44:55:66" # Your hardware address
168
+ # arp_pkt.arp_saddr_ip="10.10.10.17" # Your IP address
169
+ # arp_pkt.arp_daddr_ip="10.10.10.1" # Target IP address
170
+ # arp_pkt.arp_opcode=1 # Request
171
+ #
172
+ # arp_pkt.to_w('eth0') # Inject on the wire. (requires root)
173
+ # arp_pkt.to_f('/tmp/arp.pcap') # Write to a file.
174
+ #
175
+ # == Parameters
176
+ #
177
+ # :flavor
178
+ # Sets the "flavor" of the ARP packet. Choices are currently:
179
+ # :windows, :linux, :hp_deskjet
180
+ # :eth
181
+ # A pre-generated EthHeader object. If not specified, a new one will be created.
182
+ # :arp
183
+ # A pre-generated ARPHeader object. If not specificed, a new one will be created.
184
+ # :config
185
+ # A hash of return address details, often the output of Utils.whoami?
186
+ class ARPPacket < Packet
187
+
188
+ attr_accessor :eth_header, :arp_header
189
+
190
+ def self.can_parse?(str)
191
+ return false unless EthPacket.can_parse? str
192
+ return false unless str.size >= 28
193
+ return false unless str[12,2] == "\x08\x06"
194
+ true
195
+ end
196
+
197
+ def read(str=nil,args={})
198
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
199
+ @eth_header.read(str)
200
+ @arp_header.read(str[14,str.size])
201
+ @eth_header.body = @arp_header
202
+ super(args)
203
+ self
204
+ end
205
+
206
+ def initialize(args={})
207
+ @eth_header = EthHeader.new(args).read(args[:eth])
208
+ @arp_header = ARPHeader.new(args).read(args[:arp])
209
+ @eth_header.eth_proto = "\x08\x06"
210
+ @eth_header.body=@arp_header
211
+
212
+ # Please send more flavors to todb+packetfu@planb-security.net.
213
+ # Most of these initial fingerprints come from one (1) sample.
214
+ case (args[:flavor].nil?) ? :nil : args[:flavor].to_s.downcase.intern
215
+ when :windows; @arp_header.body = "\x00" * 64 # 64 bytes of padding
216
+ when :linux; @arp_header.body = "\x00" * 4 + # 32 bytes of padding
217
+ "\x00\x07\x5c\x14" + "\x00" * 4 +
218
+ "\x00\x0f\x83\x34" + "\x00\x0f\x83\x74" +
219
+ "\x01\x11\x83\x78" + "\x00\x00\x00\x0c" +
220
+ "\x00\x00\x00\x00"
221
+ when :hp_deskjet; # Pads up to 60 bytes.
222
+ @arp_header.body = "\xe0\x90\x0d\x6c" +
223
+ "\xff\xff\xee\xee" + "\x00" * 4 +
224
+ "\xe0\x8f\xfa\x18\x00\x20"
225
+ else; @arp_header.body = "\x00" * 18 # Pads up to 60 bytes.
226
+ end
227
+
228
+ @headers = [@eth_header, @arp_header]
229
+ super
230
+ end
231
+
232
+ # Generates summary data for ARP packets.
233
+ def peek_format
234
+ peek_data = ["A "]
235
+ peek_data << "%-5d" % self.to_s.size
236
+ peek_data << arp_saddr_mac
237
+ peek_data << "(#{arp_saddr_ip})"
238
+ peek_data << "->"
239
+ peek_data << case arp_daddr_mac
240
+ when "00:00:00:00:00:00"; "Bcast00"
241
+ when "ff:ff:ff:ff:ff:ff"; "BcastFF"
242
+ else; arp_daddr_mac
243
+ end
244
+ peek_data << "(#{arp_daddr_ip})"
245
+ peek_data << ":"
246
+ peek_data << case arp_opcode
247
+ when 1; "Requ"
248
+ when 2; "Repl"
249
+ when 3; "RReq"
250
+ when 4; "RRpl"
251
+ when 5; "IReq"
252
+ when 6; "IRpl"
253
+ else; "0x%02x" % arp_opcode
254
+ end
255
+ peek_data.join
256
+ end
257
+
258
+ # While there are lengths in ARPPackets, there's not
259
+ # much to do with them.
260
+ def recalc(args={})
261
+ @headers[0].inspect
262
+ end
263
+
264
+ end
265
+
266
+ end
267
+
268
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
@@ -0,0 +1,296 @@
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
+ # TODO: Need to come up with a good way of dealing with vlan
136
+ # tagging. Having a usually empty struct member seems weird,
137
+ # but there may not be another way to do it if I want to preserve
138
+ # the Eth-ness of vlan-tagged 802.1Q packets. Also, may as well
139
+ # deal with 0x88a8 as well (http://en.wikipedia.org/wiki/802.1ad)
140
+ #
141
+ # ==== Header Definition
142
+ #
143
+ # EthMac :eth_dst # See EthMac
144
+ # EthMac :eth_src # See EthMac
145
+ # Int16 :eth_proto, Default: 0x8000 # IP 0x0800, Arp 0x0806
146
+ # String :body
147
+ class EthHeader < Struct.new(:eth_dst, :eth_src, :eth_proto, :body)
148
+ include StructFu
149
+
150
+ def initialize(args={})
151
+ super(
152
+ EthMac.new.read(args[:eth_dst]),
153
+ EthMac.new.read(args[:eth_src]),
154
+ Int16.new(args[:eth_proto] || 0x0800),
155
+ StructFu::String.new.read(args[:body])
156
+ )
157
+ end
158
+
159
+ # Setter for the Ethernet destination address.
160
+ def eth_dst=(i); typecast(i); end
161
+ # Getter for the Ethernet destination address.
162
+ def eth_dst; self[:eth_dst].to_s; end
163
+ # Setter for the Ethernet source address.
164
+ def eth_src=(i); typecast(i); end
165
+ # Getter for the Ethernet source address.
166
+ def eth_src; self[:eth_src].to_s; end
167
+ # Setter for the Ethernet protocol number.
168
+ def eth_proto=(i); typecast(i); end
169
+ # Getter for the Ethernet protocol number.
170
+ def eth_proto; self[:eth_proto].to_i; end
171
+
172
+ # Returns the object in string form.
173
+ def to_s
174
+ self.to_a.map {|x| x.to_s}.join
175
+ end
176
+
177
+ # Reads a string to populate the object.
178
+ def read(str)
179
+ force_binary(str)
180
+ return self if str.nil?
181
+ self[:eth_dst].read str[0,6]
182
+ self[:eth_src].read str[6,6]
183
+ self[:eth_proto].read str[12,2]
184
+ self[:body].read str[14,str.size]
185
+ self
186
+ end
187
+
188
+ # Converts a readable MAC (11:22:33:44:55:66) to a binary string.
189
+ # Readable MAC's may be split on colons, dots, spaces, or underscores.
190
+ #
191
+ # irb> PacketFu::EthHeader.mac2str("11:22:33:44:55:66")
192
+ #
193
+ # #=> "\021\"3DUf"
194
+ def self.mac2str(mac)
195
+ if mac.split(/[:\x2d\x2e\x5f]+/).size == 6
196
+ ret = mac.split(/[:\x2d\x2e\x20\x5f]+/).collect {|x| x.to_i(16)}.pack("C6")
197
+ else
198
+ raise ArgumentError, "Unkown format for mac address."
199
+ end
200
+ return ret
201
+ end
202
+
203
+ # Converts a binary string to a readable MAC (11:22:33:44:55:66).
204
+ #
205
+ # irb> PacketFu::EthHeader.str2mac("\x11\x22\x33\x44\x55\x66")
206
+ #
207
+ # #=> "11:22:33:44:55:66"
208
+ def self.str2mac(mac='')
209
+ if mac.to_s.size == 6 && mac.kind_of?(::String)
210
+ ret = mac.unpack("C6").map {|x| sprintf("%02x",x)}.join(":")
211
+ end
212
+ end
213
+
214
+ # Sets the source MAC address in a more readable way.
215
+ def eth_saddr=(mac)
216
+ mac = EthHeader.mac2str(mac)
217
+ self[:eth_src].read mac
218
+ self[:eth_src]
219
+ end
220
+
221
+ # Gets the source MAC address in a more readable way.
222
+ def eth_saddr
223
+ EthHeader.str2mac(self[:eth_src].to_s)
224
+ end
225
+
226
+ # Set the destination MAC address in a more readable way.
227
+ def eth_daddr=(mac)
228
+ mac = EthHeader.mac2str(mac)
229
+ self[:eth_dst].read mac
230
+ self[:eth_dst]
231
+ end
232
+
233
+ # Gets the destination MAC address in a more readable way.
234
+ def eth_daddr
235
+ EthHeader.str2mac(self[:eth_dst].to_s)
236
+ end
237
+
238
+ # Readability aliases
239
+
240
+ alias :eth_dst_readable :eth_daddr
241
+ alias :eth_src_readable :eth_saddr
242
+
243
+ def eth_proto_readable
244
+ "0x%04x" % eth_proto
245
+ end
246
+
247
+ end
248
+
249
+ # EthPacket is used to construct Ethernet packets. They contain an
250
+ # Ethernet header, and that's about it.
251
+ #
252
+ # == Example
253
+ #
254
+ # require 'packetfu'
255
+ # eth_pkt = PacketFu::EthPacket.new
256
+ # eth_pkt.eth_saddr="00:1c:23:44:55:66"
257
+ # eth_pkt.eth_daddr="00:1c:24:aa:bb:cc"
258
+ #
259
+ # eth_pkt.to_w('eth0') # Inject on the wire. (require root)
260
+ #
261
+ class EthPacket < Packet
262
+ attr_accessor :eth_header
263
+
264
+ def self.can_parse?(str)
265
+ # XXX Temporary fix. Need to extend the EthHeader class to handle more.
266
+ valid_eth_types = [0x0800, 0x0806, 0x86dd]
267
+ return false unless str.size >= 14
268
+ type = str[12,2].unpack("n").first rescue nil
269
+ return false unless valid_eth_types.include? type
270
+ true
271
+ end
272
+
273
+ def read(str=nil,args={})
274
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
275
+ @eth_header.read(str)
276
+ super(args)
277
+ return self
278
+ end
279
+
280
+ # Does nothing, really, since there's no length or
281
+ # checksum to calculate for a straight Ethernet packet.
282
+ def recalc(args={})
283
+ @headers[0].inspect
284
+ end
285
+
286
+ def initialize(args={})
287
+ @eth_header = EthHeader.new(args).read(args[:eth])
288
+ @headers = [@eth_header]
289
+ super
290
+ end
291
+
292
+ end
293
+
294
+ end
295
+
296
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby