packetfu 1.1.8 → 1.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/README.rdoc +11 -12
  2. data/bench/octets.rb +9 -9
  3. data/examples/100kpackets.rb +13 -12
  4. data/examples/ackscan.rb +17 -16
  5. data/examples/arp.rb +36 -35
  6. data/examples/arphood.rb +37 -36
  7. data/examples/dissect_thinger.rb +7 -6
  8. data/examples/ethernet.rb +1 -0
  9. data/examples/examples.rb +1 -0
  10. data/examples/ifconfig.rb +1 -0
  11. data/examples/new-simple-stats.rb +24 -23
  12. data/examples/packetfu-shell.rb +26 -25
  13. data/examples/simple-sniffer.rb +10 -9
  14. data/examples/simple-stats.rb +24 -23
  15. data/examples/slammer.rb +4 -3
  16. data/lib/packetfu.rb +128 -127
  17. data/lib/packetfu/capture.rb +170 -169
  18. data/lib/packetfu/config.rb +53 -52
  19. data/lib/packetfu/inject.rb +57 -56
  20. data/lib/packetfu/packet.rb +529 -528
  21. data/lib/packetfu/pcap.rb +580 -579
  22. data/lib/packetfu/protos/arp.rb +91 -90
  23. data/lib/packetfu/protos/arp/header.rb +159 -158
  24. data/lib/packetfu/protos/arp/mixin.rb +37 -36
  25. data/lib/packetfu/protos/eth.rb +45 -44
  26. data/lib/packetfu/protos/eth/header.rb +244 -243
  27. data/lib/packetfu/protos/eth/mixin.rb +4 -3
  28. data/lib/packetfu/protos/hsrp.rb +70 -69
  29. data/lib/packetfu/protos/hsrp/header.rb +108 -107
  30. data/lib/packetfu/protos/hsrp/mixin.rb +30 -29
  31. data/lib/packetfu/protos/icmp.rb +72 -71
  32. data/lib/packetfu/protos/icmp/header.rb +83 -82
  33. data/lib/packetfu/protos/icmp/mixin.rb +15 -14
  34. data/lib/packetfu/protos/invalid.rb +50 -49
  35. data/lib/packetfu/protos/ip.rb +70 -69
  36. data/lib/packetfu/protos/ip/header.rb +292 -291
  37. data/lib/packetfu/protos/ip/mixin.rb +41 -40
  38. data/lib/packetfu/protos/ipv6.rb +51 -50
  39. data/lib/packetfu/protos/ipv6/header.rb +189 -188
  40. data/lib/packetfu/protos/ipv6/mixin.rb +30 -29
  41. data/lib/packetfu/protos/lldp.rb +3 -1
  42. data/lib/packetfu/protos/lldp/header.rb +1 -0
  43. data/lib/packetfu/protos/lldp/mixin.rb +1 -0
  44. data/lib/packetfu/protos/tcp.rb +177 -176
  45. data/lib/packetfu/protos/tcp/ecn.rb +36 -35
  46. data/lib/packetfu/protos/tcp/flags.rb +75 -74
  47. data/lib/packetfu/protos/tcp/header.rb +269 -268
  48. data/lib/packetfu/protos/tcp/hlen.rb +33 -32
  49. data/lib/packetfu/protos/tcp/mixin.rb +47 -46
  50. data/lib/packetfu/protos/tcp/option.rb +322 -321
  51. data/lib/packetfu/protos/tcp/options.rb +96 -95
  52. data/lib/packetfu/protos/tcp/reserved.rb +36 -35
  53. data/lib/packetfu/protos/udp.rb +117 -116
  54. data/lib/packetfu/protos/udp/header.rb +92 -91
  55. data/lib/packetfu/protos/udp/mixin.rb +4 -3
  56. data/lib/packetfu/structfu.rb +281 -280
  57. data/lib/packetfu/utils.rb +211 -208
  58. data/lib/packetfu/version.rb +42 -41
  59. data/packetfu.gemspec +1 -1
  60. data/spec/ethpacket_spec.rb +48 -48
  61. data/spec/packet_spec.rb +57 -57
  62. data/spec/packet_subclasses_spec.rb +8 -8
  63. data/spec/packetfu_spec.rb +59 -59
  64. data/spec/structfu_spec.rb +268 -268
  65. data/spec/tcp_spec.rb +75 -75
  66. data/test/all_tests.rb +13 -13
  67. data/test/func_lldp.rb +3 -3
  68. data/test/ptest.rb +2 -2
  69. data/test/test_arp.rb +116 -116
  70. data/test/test_capture.rb +45 -45
  71. data/test/test_eth.rb +68 -68
  72. data/test/test_hsrp.rb +9 -9
  73. data/test/test_icmp.rb +52 -52
  74. data/test/test_inject.rb +18 -18
  75. data/test/test_invalid.rb +16 -16
  76. data/test/test_ip.rb +36 -36
  77. data/test/test_ip6.rb +48 -48
  78. data/test/test_octets.rb +21 -21
  79. data/test/test_packet.rb +154 -154
  80. data/test/test_pcap.rb +170 -170
  81. data/test/test_structfu.rb +97 -97
  82. data/test/test_tcp.rb +320 -320
  83. data/test/test_udp.rb +76 -76
  84. metadata +2 -2
@@ -1,38 +1,39 @@
1
+ # -*- coding: binary -*-
1
2
  module PacketFu
2
- # This Mixin simplifies access to the ARPHeaders. Mix this in with your
3
- # packet interface, and it will add methods that essentially delegate to
4
- # the 'arp_header' method (assuming that it is a ARPHeader object)
5
- module ARPHeaderMixin
6
- def arp_hw=(v); self.arp_header.arp_hw= v; end
7
- def arp_hw; self.arp_header.arp_hw; end
8
- def arp_proto=(v); self.arp_header.arp_proto= v; end
9
- def arp_proto; self.arp_header.arp_proto; end
10
- def arp_hw_len=(v); self.arp_header.arp_hw_len= v; end
11
- def arp_hw_len; self.arp_header.arp_hw_len; end
12
- def arp_proto_len=(v); self.arp_header.arp_proto_len= v; end
13
- def arp_proto_len; self.arp_header.arp_proto_len; end
14
- def arp_opcode=(v); self.arp_header.arp_opcode= v; end
15
- def arp_opcode; self.arp_header.arp_opcode; end
16
- def arp_src_mac=(v); self.arp_header.arp_src_mac= v; end
17
- def arp_src_mac; self.arp_header.arp_src_mac; end
18
- def arp_src_ip=(v); self.arp_header.arp_src_ip= v; end
19
- def arp_src_ip; self.arp_header.arp_src_ip; end
20
- def arp_dst_mac=(v); self.arp_header.arp_dst_mac= v; end
21
- def arp_dst_mac; self.arp_header.arp_dst_mac; end
22
- def arp_dst_ip=(v); self.arp_header.arp_dst_ip= v; end
23
- def arp_dst_ip; self.arp_header.arp_dst_ip; end
24
- def arp_saddr_mac=(v); self.arp_header.arp_saddr_mac= v; end
25
- def arp_saddr_mac; self.arp_header.arp_saddr_mac; end
26
- def arp_daddr_mac=(v); self.arp_header.arp_daddr_mac= v; end
27
- def arp_daddr_mac; self.arp_header.arp_daddr_mac; end
28
- def arp_saddr_ip=(v); self.arp_header.arp_saddr_ip= v; end
29
- def arp_saddr_ip; self.arp_header.arp_saddr_ip; end
30
- def arp_daddr_ip=(v); self.arp_header.arp_daddr_ip= v; end
31
- def arp_daddr_ip; self.arp_header.arp_daddr_ip; end
32
- def arp_src_mac_readable; self.arp_header.arp_src_mac_readable; end
33
- def arp_dst_mac_readable; self.arp_header.arp_dst_mac_readable; end
34
- def arp_src_ip_readable; self.arp_header.arp_src_ip_readable; end
35
- def arp_dst_ip_readable; self.arp_header.arp_dst_ip_readable; end
36
- def arp_proto_readable; self.arp_header.arp_proto_readable; end
37
- end
3
+ # This Mixin simplifies access to the ARPHeaders. Mix this in with your
4
+ # packet interface, and it will add methods that essentially delegate to
5
+ # the 'arp_header' method (assuming that it is a ARPHeader object)
6
+ module ARPHeaderMixin
7
+ def arp_hw=(v); self.arp_header.arp_hw= v; end
8
+ def arp_hw; self.arp_header.arp_hw; end
9
+ def arp_proto=(v); self.arp_header.arp_proto= v; end
10
+ def arp_proto; self.arp_header.arp_proto; end
11
+ def arp_hw_len=(v); self.arp_header.arp_hw_len= v; end
12
+ def arp_hw_len; self.arp_header.arp_hw_len; end
13
+ def arp_proto_len=(v); self.arp_header.arp_proto_len= v; end
14
+ def arp_proto_len; self.arp_header.arp_proto_len; end
15
+ def arp_opcode=(v); self.arp_header.arp_opcode= v; end
16
+ def arp_opcode; self.arp_header.arp_opcode; end
17
+ def arp_src_mac=(v); self.arp_header.arp_src_mac= v; end
18
+ def arp_src_mac; self.arp_header.arp_src_mac; end
19
+ def arp_src_ip=(v); self.arp_header.arp_src_ip= v; end
20
+ def arp_src_ip; self.arp_header.arp_src_ip; end
21
+ def arp_dst_mac=(v); self.arp_header.arp_dst_mac= v; end
22
+ def arp_dst_mac; self.arp_header.arp_dst_mac; end
23
+ def arp_dst_ip=(v); self.arp_header.arp_dst_ip= v; end
24
+ def arp_dst_ip; self.arp_header.arp_dst_ip; end
25
+ def arp_saddr_mac=(v); self.arp_header.arp_saddr_mac= v; end
26
+ def arp_saddr_mac; self.arp_header.arp_saddr_mac; end
27
+ def arp_daddr_mac=(v); self.arp_header.arp_daddr_mac= v; end
28
+ def arp_daddr_mac; self.arp_header.arp_daddr_mac; end
29
+ def arp_saddr_ip=(v); self.arp_header.arp_saddr_ip= v; end
30
+ def arp_saddr_ip; self.arp_header.arp_saddr_ip; end
31
+ def arp_daddr_ip=(v); self.arp_header.arp_daddr_ip= v; end
32
+ def arp_daddr_ip; self.arp_header.arp_daddr_ip; end
33
+ def arp_src_mac_readable; self.arp_header.arp_src_mac_readable; end
34
+ def arp_dst_mac_readable; self.arp_header.arp_dst_mac_readable; end
35
+ def arp_src_ip_readable; self.arp_header.arp_src_ip_readable; end
36
+ def arp_dst_ip_readable; self.arp_header.arp_dst_ip_readable; end
37
+ def arp_proto_readable; self.arp_header.arp_proto_readable; end
38
+ end
38
39
  end
@@ -1,53 +1,54 @@
1
+ # -*- coding: binary -*-
1
2
  require 'packetfu/protos/eth/header'
2
3
  require 'packetfu/protos/eth/mixin'
3
4
 
4
5
  module PacketFu
5
- # EthPacket is used to construct Ethernet packets. They contain an
6
- # Ethernet header, and that's about it.
7
- #
8
- # == Example
9
- #
10
- # require 'packetfu'
11
- # eth_pkt = PacketFu::EthPacket.new
12
- # eth_pkt.eth_saddr="00:1c:23:44:55:66"
13
- # eth_pkt.eth_daddr="00:1c:24:aa:bb:cc"
14
- #
15
- # eth_pkt.to_w('eth0') # Inject on the wire. (require root)
16
- #
17
- class EthPacket < Packet
6
+ # EthPacket is used to construct Ethernet packets. They contain an
7
+ # Ethernet header, and that's about it.
8
+ #
9
+ # == Example
10
+ #
11
+ # require 'packetfu'
12
+ # eth_pkt = PacketFu::EthPacket.new
13
+ # eth_pkt.eth_saddr="00:1c:23:44:55:66"
14
+ # eth_pkt.eth_daddr="00:1c:24:aa:bb:cc"
15
+ #
16
+ # eth_pkt.to_w('eth0') # Inject on the wire. (require root)
17
+ #
18
+ class EthPacket < Packet
18
19
  include ::PacketFu::EthHeaderMixin
19
20
 
20
- attr_accessor :eth_header
21
-
22
- def self.can_parse?(str)
23
- # XXX Temporary fix. Need to extend the EthHeader class to handle more.
24
- valid_eth_types = [0x0800, 0x0806, 0x86dd, 0x88cc]
25
- return false unless str.size >= 14
26
- type = str[12,2].unpack("n").first rescue nil
27
- return false unless valid_eth_types.include? type
28
- true
29
- end
30
-
31
- def read(str=nil,args={})
32
- raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
33
- @eth_header.read(str)
34
- super(args)
35
- return self
36
- end
37
-
38
- # Does nothing, really, since there's no length or
39
- # checksum to calculate for a straight Ethernet packet.
40
- def recalc(args={})
41
- @headers[0].inspect
42
- end
43
-
44
- def initialize(args={})
45
- @eth_header = EthHeader.new(args).read(args[:eth])
46
- @headers = [@eth_header]
47
- super
48
- end
49
-
50
- end
21
+ attr_accessor :eth_header
22
+
23
+ def self.can_parse?(str)
24
+ # XXX Temporary fix. Need to extend the EthHeader class to handle more.
25
+ valid_eth_types = [0x0800, 0x0806, 0x86dd, 0x88cc]
26
+ return false unless str.size >= 14
27
+ type = str[12,2].unpack("n").first rescue nil
28
+ return false unless valid_eth_types.include? type
29
+ true
30
+ end
31
+
32
+ def read(str=nil,args={})
33
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
34
+ @eth_header.read(str)
35
+ super(args)
36
+ return self
37
+ end
38
+
39
+ # Does nothing, really, since there's no length or
40
+ # checksum to calculate for a straight Ethernet packet.
41
+ def recalc(args={})
42
+ @headers[0].inspect
43
+ end
44
+
45
+ def initialize(args={})
46
+ @eth_header = EthHeader.new(args).read(args[:eth])
47
+ @headers = [@eth_header]
48
+ super
49
+ end
50
+
51
+ end
51
52
 
52
53
  end
53
54
 
@@ -1,247 +1,248 @@
1
+ # -*- coding: binary -*-
1
2
  module PacketFu
2
- # EthOui is the Organizationally Unique Identifier portion of a MAC address, used in EthHeader.
3
- #
4
- # See the OUI list at http://standards.ieee.org/regauth/oui/oui.txt
5
- #
6
- # ==== Header Definition
7
- #
8
- # Fixnum :b0
9
- # Fixnum :b1
10
- # Fixnum :b2
11
- # Fixnum :b3
12
- # Fixnum :b4
13
- # Fixnum :b5
14
- # Fixnum :local
15
- # Fixnum :multicast
16
- # Int16 :oui, Default: 0x1ac5 :)
17
- class EthOui < Struct.new(:b5, :b4, :b3, :b2, :b1, :b0, :local, :multicast, :oui)
18
-
19
- # EthOui is unusual in that the bit values do not enjoy StructFu typing.
20
- def initialize(args={})
21
- args[:local] ||= 0
22
- args[:oui] ||= 0x1ac # :)
23
- args.each_pair {|k,v| args[k] = 0 unless v}
24
- super(args[:b5], args[:b4], args[:b3], args[:b2],
25
- args[:b1], args[:b0], args[:local], args[:multicast],
26
- args[:oui])
27
- end
28
-
29
- # Returns the object in string form.
30
- def to_s
31
- byte = 0
32
- byte += 0b10000000 if b5.to_i == 1
33
- byte += 0b01000000 if b4.to_i == 1
34
- byte += 0b00100000 if b3.to_i == 1
35
- byte += 0b00010000 if b2.to_i == 1
36
- byte += 0b00001000 if b1.to_i == 1
37
- byte += 0b00000100 if b0.to_i == 1
38
- byte += 0b00000010 if local.to_i == 1
39
- byte += 0b00000001 if multicast.to_i == 1
40
- [byte,oui].pack("Cn")
41
- end
42
-
43
- # Reads a string to populate the object.
44
- def read(str)
45
- force_binary(str)
46
- return self if str.nil?
47
- if 1.respond_to? :ord
48
- byte = str[0].ord
49
- else
50
- byte = str[0]
51
- end
52
- self[:b5] = byte & 0b10000000 == 0b10000000 ? 1 : 0
53
- self[:b4] = byte & 0b01000000 == 0b01000000 ? 1 : 0
54
- self[:b3] = byte & 0b00100000 == 0b00100000 ? 1 : 0
55
- self[:b2] = byte & 0b00010000 == 0b00010000 ? 1 : 0
56
- self[:b1] = byte & 0b00001000 == 0b00001000 ? 1 : 0
57
- self[:b0] = byte & 0b00000100 == 0b00000100 ? 1 : 0
58
- self[:local] = byte & 0b00000010 == 0b00000010 ? 1 : 0
59
- self[:multicast] = byte & 0b00000001 == 0b00000001 ? 1 : 0
60
- self[:oui] = str[1,2].unpack("n").first
61
- self
62
- end
63
-
64
- end
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
65
66
 
66
67
  # EthNic is the Network Interface Controler portion of a MAC address, used in EthHeader.
67
- #
68
- # ==== Header Definition
69
- #
70
- # Fixnum :n1
71
- # Fixnum :n2
72
- # Fixnum :n3
73
- #
74
- class EthNic < Struct.new(:n0, :n1, :n2)
75
-
76
- # EthNic does not enjoy StructFu typing.
77
- def initialize(args={})
78
- args.each_pair {|k,v| args[k] = 0 unless v}
79
- super(args[:n0], args[:n1], args[:n2])
80
- end
81
-
82
- # Returns the object in string form.
83
- def to_s
84
- [n0,n1,n2].map {|x| x.to_i}.pack("C3")
85
- end
86
-
87
- # Reads a string to populate the object.
88
- def read(str)
89
- force_binary(str)
90
- return self if str.nil?
91
- self[:n0], self[:n1], self[:n2] = str[0,3].unpack("C3")
92
- self
93
- end
94
-
95
- end
96
-
97
- # EthMac is the combination of an EthOui and EthNic, used in EthHeader.
98
- #
99
- # ==== Header Definition
100
- #
101
- # EthOui :oui # See EthOui
102
- # EthNic :nic # See EthNic
103
- class EthMac < Struct.new(:oui, :nic)
104
-
105
- def initialize(args={})
106
- super(
107
- EthOui.new.read(args[:oui]),
108
- EthNic.new.read(args[:nic]))
109
- end
110
-
111
- # Returns the object in string form.
112
- def to_s
113
- "#{self[:oui]}#{self[:nic]}"
114
- end
115
-
116
- # Reads a string to populate the object.
117
- def read(str)
118
- force_binary(str)
119
- return self if str.nil?
120
- self.oui.read str[0,3]
121
- self.nic.read str[3,3]
122
- self
123
- end
124
-
125
- end
126
-
127
- # EthHeader is a complete Ethernet struct, used in EthPacket.
128
- # It's the base header for all other protocols, such as IPHeader,
129
- # TCPHeader, etc.
130
- #
131
- # For more on the construction on MAC addresses, see
132
- # http://en.wikipedia.org/wiki/MAC_address
133
- #
134
- # TODO: Need to come up with a good way of dealing with vlan
135
- # tagging. Having a usually empty struct member seems weird,
136
- # but there may not be another way to do it if I want to preserve
137
- # the Eth-ness of vlan-tagged 802.1Q packets. Also, may as well
138
- # deal with 0x88a8 as well (http://en.wikipedia.org/wiki/802.1ad)
139
- #
140
- # ==== Header Definition
141
- #
142
- # EthMac :eth_dst # See EthMac
143
- # EthMac :eth_src # See EthMac
144
- # Int16 :eth_proto, Default: 0x8000 # IP 0x0800, Arp 0x0806
145
- # String :body
146
- class EthHeader < Struct.new(:eth_dst, :eth_src, :eth_proto, :body)
147
- include StructFu
148
-
149
- def initialize(args={})
150
- super(
151
- EthMac.new.read(args[:eth_dst]),
152
- EthMac.new.read(args[:eth_src]),
153
- Int16.new(args[:eth_proto] || 0x0800),
154
- StructFu::String.new.read(args[:body])
155
- )
156
- end
157
-
158
- # Setter for the Ethernet destination address.
159
- def eth_dst=(i); typecast(i); end
160
- # Getter for the Ethernet destination address.
161
- def eth_dst; self[:eth_dst].to_s; end
162
- # Setter for the Ethernet source address.
163
- def eth_src=(i); typecast(i); end
164
- # Getter for the Ethernet source address.
165
- def eth_src; self[:eth_src].to_s; end
166
- # Setter for the Ethernet protocol number.
167
- def eth_proto=(i); typecast(i); end
168
- # Getter for the Ethernet protocol number.
169
- def eth_proto; self[:eth_proto].to_i; end
170
-
171
- # Returns the object in string form.
172
- def to_s
173
- self.to_a.map {|x| x.to_s}.join
174
- end
175
-
176
- # Reads a string to populate the object.
177
- def read(str)
178
- force_binary(str)
179
- return self if str.nil?
180
- self[:eth_dst].read str[0,6]
181
- self[:eth_src].read str[6,6]
182
- self[:eth_proto].read str[12,2]
183
- self[:body].read str[14,str.size]
184
- self
185
- end
186
-
187
- # Converts a readable MAC (11:22:33:44:55:66) to a binary string.
188
- # Readable MAC's may be split on colons, dots, spaces, or underscores.
189
- #
190
- # irb> PacketFu::EthHeader.mac2str("11:22:33:44:55:66")
191
- #
192
- # #=> "\021\"3DUf"
193
- def self.mac2str(mac)
194
- if mac.split(/[:\x2d\x2e\x5f]+/).size == 6
195
- ret = mac.split(/[:\x2d\x2e\x20\x5f]+/).collect {|x| x.to_i(16)}.pack("C6")
196
- else
197
- raise ArgumentError, "Unkown format for mac address."
198
- end
199
- return ret
200
- end
201
-
202
- # Converts a binary string to a readable MAC (11:22:33:44:55:66).
203
- #
204
- # irb> PacketFu::EthHeader.str2mac("\x11\x22\x33\x44\x55\x66")
205
- #
206
- # #=> "11:22:33:44:55:66"
207
- def self.str2mac(mac='')
208
- if mac.to_s.size == 6 && mac.kind_of?(::String)
209
- ret = mac.unpack("C6").map {|x| sprintf("%02x",x)}.join(":")
210
- end
211
- end
212
-
213
- # Sets the source MAC address in a more readable way.
214
- def eth_saddr=(mac)
215
- mac = EthHeader.mac2str(mac)
216
- self[:eth_src].read mac
217
- self[:eth_src]
218
- end
219
-
220
- # Gets the source MAC address in a more readable way.
221
- def eth_saddr
222
- EthHeader.str2mac(self[:eth_src].to_s)
223
- end
224
-
225
- # Set the destination MAC address in a more readable way.
226
- def eth_daddr=(mac)
227
- mac = EthHeader.mac2str(mac)
228
- self[:eth_dst].read mac
229
- self[:eth_dst]
230
- end
231
-
232
- # Gets the destination MAC address in a more readable way.
233
- def eth_daddr
234
- EthHeader.str2mac(self[:eth_dst].to_s)
235
- end
236
-
237
- # Readability aliases
238
-
239
- alias :eth_dst_readable :eth_daddr
240
- alias :eth_src_readable :eth_saddr
241
-
242
- def eth_proto_readable
243
- "0x%04x" % eth_proto
244
- end
245
-
246
- end
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
247
248
  end