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,39 +1,39 @@
1
1
  # -*- coding: binary -*-
2
2
  module PacketFu
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
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
39
39
  end
@@ -3,52 +3,52 @@ require 'packetfu/protos/eth/header'
3
3
  require 'packetfu/protos/eth/mixin'
4
4
 
5
5
  module PacketFu
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
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
19
19
  include ::PacketFu::EthHeaderMixin
20
20
 
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
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
52
52
 
53
53
  end
54
54
 
@@ -1,248 +1,248 @@
1
1
  # -*- coding: binary -*-
2
2
  module PacketFu
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
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
66
 
67
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
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
248
  end