packetfu 1.1.8 → 1.1.9

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.
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,221 +1,224 @@
1
+ # -*- coding: binary -*-
1
2
  require 'singleton'
2
3
  module PacketFu
3
4
 
4
- # Utils is a collection of various and sundry network utilities that are useful for packet
5
- # manipulation.
6
- class Utils
5
+ # Utils is a collection of various and sundry network utilities that are useful for packet
6
+ # manipulation.
7
+ class Utils
7
8
 
8
- # Returns the MAC address of an IP address, or nil if it's not responsive to arp. Takes
9
- # a dotted-octect notation of the target IP address, as well as a number of parameters:
10
- #
11
- # === Parameters
12
- # :eth_saddr
13
- # Source MAC address. Defaults to "00:00:00:00:00:00".
14
- # :ip_saddr
15
- # Source IP address. Defaults to "0.0.0.0"
16
- # :flavor
17
- # The flavor of the ARP request. Defaults to :none.
18
- # :timeout
19
- # Timeout in seconds. Defaults to 3.
20
- #
21
- # === Example
22
- # PacketFu::Utils::arp("192.168.1.1") #=> "00:18:39:01:33:70"
23
- # PacketFu::Utils::arp("192.168.1.1", :timeout => 5, :flavor => :hp_deskjet)
24
- #
25
- # === Warning
26
- #
27
- # It goes without saying, spewing forged ARP packets on your network is a great way to really
28
- # irritate your co-workers.
29
- def self.arp(target_ip,args={})
30
- iface = args[:iface] || :eth0
31
- args[:config] ||= whoami?(:iface => iface)
32
- arp_pkt = PacketFu::ARPPacket.new(:flavor => (args[:flavor] || :none), :config => args[:config])
33
- arp_pkt.eth_daddr = "ff:ff:ff:ff:ff:ff"
34
- arp_pkt.arp_daddr_mac = "00:00:00:00:00:00"
35
- arp_pkt.arp_daddr_ip = target_ip
36
- # Stick the Capture object in its own thread.
37
- cap_thread = Thread.new do
38
- target_mac = nil
39
- cap = PacketFu::Capture.new(:iface => iface, :start => true,
40
- :filter => "arp src #{target_ip} and ether dst #{arp_pkt.eth_saddr}")
41
- arp_pkt.to_w(iface) # Shorthand for sending single packets to the default interface.
42
- timeout = 0
43
- while target_mac.nil? && timeout <= (args[:timeout] || 3)
44
- if cap.save > 0
45
- arp_response = PacketFu::Packet.parse(cap.array[0])
46
- target_mac = arp_response.arp_saddr_mac if arp_response.arp_saddr_ip = target_ip
47
- end
48
- timeout += 0.1
49
- sleep 0.1 # Check for a response ten times per second.
50
- end
51
- target_mac
52
- end # cap_thread
53
- cap_thread.value
54
- end
9
+ # Returns the MAC address of an IP address, or nil if it's not responsive to arp. Takes
10
+ # a dotted-octect notation of the target IP address, as well as a number of parameters:
11
+ #
12
+ # === Parameters
13
+ # :iface
14
+ # Interface. Defaults to "eth0"
15
+ # :eth_saddr
16
+ # Source MAC address. Defaults to "00:00:00:00:00:00".
17
+ # :ip_saddr
18
+ # Source IP address. Defaults to "0.0.0.0"
19
+ # :flavor
20
+ # The flavor of the ARP request. Defaults to :none.
21
+ # :timeout
22
+ # Timeout in seconds. Defaults to 3.
23
+ #
24
+ # === Example
25
+ # PacketFu::Utils::arp("192.168.1.1") #=> "00:18:39:01:33:70"
26
+ # PacketFu::Utils::arp("192.168.1.1", :iface => "wlan2", :timeout => 5, :flavor => :hp_deskjet)
27
+ #
28
+ # === Warning
29
+ #
30
+ # It goes without saying, spewing forged ARP packets on your network is a great way to really
31
+ # irritate your co-workers.
32
+ def self.arp(target_ip,args={})
33
+ iface = args[:iface] || :eth0
34
+ args[:config] ||= whoami?(:iface => iface)
35
+ arp_pkt = PacketFu::ARPPacket.new(:flavor => (args[:flavor] || :none), :config => args[:config])
36
+ arp_pkt.eth_daddr = "ff:ff:ff:ff:ff:ff"
37
+ arp_pkt.arp_daddr_mac = "00:00:00:00:00:00"
38
+ arp_pkt.arp_daddr_ip = target_ip
39
+ # Stick the Capture object in its own thread.
40
+ cap_thread = Thread.new do
41
+ target_mac = nil
42
+ cap = PacketFu::Capture.new(:iface => iface, :start => true,
43
+ :filter => "arp src #{target_ip} and ether dst #{arp_pkt.eth_saddr}")
44
+ arp_pkt.to_w(iface) # Shorthand for sending single packets to the default interface.
45
+ timeout = 0
46
+ while target_mac.nil? && timeout <= (args[:timeout] || 3)
47
+ if cap.save > 0
48
+ arp_response = PacketFu::Packet.parse(cap.array[0])
49
+ target_mac = arp_response.arp_saddr_mac if arp_response.arp_saddr_ip = target_ip
50
+ end
51
+ timeout += 0.1
52
+ sleep 0.1 # Check for a response ten times per second.
53
+ end
54
+ target_mac
55
+ end # cap_thread
56
+ cap_thread.value
57
+ end
55
58
 
56
- # Since 177/8 is IANA reserved (for now), this network should
57
- # be handled by your default gateway and default interface.
58
- def self.rand_routable_daddr
59
- IPAddr.new((rand(16777216) + 2969567232), Socket::AF_INET)
60
- end
59
+ # Since 177/8 is IANA reserved (for now), this network should
60
+ # be handled by your default gateway and default interface.
61
+ def self.rand_routable_daddr
62
+ IPAddr.new((rand(16777216) + 2969567232), Socket::AF_INET)
63
+ end
61
64
 
62
- # Discovers the local IP and Ethernet address, which is useful for writing
63
- # packets you expect to get a response to. Note, this is a noisy
64
- # operation; a UDP packet is generated and dropped on to the default (or named)
65
- # interface, and then captured (which means you need to be root to do this).
66
- #
67
- # whoami? returns a hash of :eth_saddr, :eth_src, :ip_saddr, :ip_src,
68
- # :ip_src_bin, :eth_dst, and :eth_daddr (the last two are usually suitable
69
- # for a gateway mac address). It's most useful as an argument to
70
- # PacketFu::Config.new, or as an argument to the many Packet constructors.
71
- #
72
- # Note that if you have multiple interfaces with the same route (such as when
73
- # wlan0 and eth0 are associated to the same network), the "first" one
74
- # according to Pcap.lookupdev will be used, regardless of which :iface you
75
- # pick.
76
- #
77
- # === Parameters
78
- # :iface => "eth0"
79
- # An interface to listen for packets on. Note that since we rely on the OS to send the probe packet,
80
- # you will need to specify a target which will use this interface.
81
- # :target => "1.2.3.4"
82
- # A target IP address. By default, a packet will be sent to a random address in the 177/8 network.
83
- def self.whoami?(args={})
84
- unless args.kind_of? Hash
85
- raise ArgumentError, "Argument to `whoami?' must be a Hash"
86
- end
87
- if args[:iface].to_s =~ /^lo/ # Linux loopback more or less. Need a switch for windows loopback, too.
88
- dst_host = "127.0.0.1"
89
- else
90
- dst_host = (args[:target] || rand_routable_daddr.to_s)
91
- end
65
+ # Discovers the local IP and Ethernet address, which is useful for writing
66
+ # packets you expect to get a response to. Note, this is a noisy
67
+ # operation; a UDP packet is generated and dropped on to the default (or named)
68
+ # interface, and then captured (which means you need to be root to do this).
69
+ #
70
+ # whoami? returns a hash of :eth_saddr, :eth_src, :ip_saddr, :ip_src,
71
+ # :ip_src_bin, :eth_dst, and :eth_daddr (the last two are usually suitable
72
+ # for a gateway mac address). It's most useful as an argument to
73
+ # PacketFu::Config.new, or as an argument to the many Packet constructors.
74
+ #
75
+ # Note that if you have multiple interfaces with the same route (such as when
76
+ # wlan0 and eth0 are associated to the same network), the "first" one
77
+ # according to Pcap.lookupdev will be used, regardless of which :iface you
78
+ # pick.
79
+ #
80
+ # === Parameters
81
+ # :iface => "eth0"
82
+ # An interface to listen for packets on. Note that since we rely on the OS to send the probe packet,
83
+ # you will need to specify a target which will use this interface.
84
+ # :target => "1.2.3.4"
85
+ # A target IP address. By default, a packet will be sent to a random address in the 177/8 network.
86
+ def self.whoami?(args={})
87
+ unless args.kind_of? Hash
88
+ raise ArgumentError, "Argument to `whoami?' must be a Hash"
89
+ end
90
+ if args[:iface].to_s =~ /^lo/ # Linux loopback more or less. Need a switch for windows loopback, too.
91
+ dst_host = "127.0.0.1"
92
+ else
93
+ dst_host = (args[:target] || rand_routable_daddr.to_s)
94
+ end
92
95
 
93
- dst_port = rand(0xffff-1024)+1024
94
- msg = "PacketFu whoami? packet #{(Time.now.to_i + rand(0xffffff)+1)}"
95
- iface = (args[:iface] || ENV['IFACE'] || Pcap.lookupdev || :lo ).to_s
96
- cap = PacketFu::Capture.new(:iface => iface, :promisc => false, :start => true, :filter => "udp and dst host #{dst_host} and dst port #{dst_port}")
97
- udp_sock = UDPSocket.new
98
- udp_sock.send(msg,0,dst_host,dst_port)
99
- udp_sock = nil
100
- cap.save
101
- pkt = Packet.parse(cap.array[0]) unless cap.save.zero?
102
- timeout = 0
103
- while timeout < 1 # Sometimes packet generation can be a little pokey.
104
- if pkt
105
- timeout = 1.1 # Cancel the timeout
106
- if pkt.payload == msg
107
- my_data = {
108
- :iface => (args[:iface] || ENV['IFACE'] || Pcap.lookupdev || "lo").to_s,
109
- :pcapfile => args[:pcapfile] || "/tmp/out.pcap",
110
- :eth_saddr => pkt.eth_saddr,
111
- :eth_src => pkt.eth_src.to_s,
112
- :ip_saddr => pkt.ip_saddr,
113
- :ip_src => pkt.ip_src,
114
- :ip_src_bin => [pkt.ip_src].pack("N"),
115
- :eth_dst => pkt.eth_dst.to_s,
116
- :eth_daddr => pkt.eth_daddr
117
- }
118
- else raise SecurityError,
119
- "whoami() packet doesn't match sent data. Something fishy's going on."
120
- end
121
- else
122
- sleep 0.1; timeout += 0.1
123
- cap.save
124
- pkt = Packet.parse(cap.array[0]) unless cap.save.zero?
125
- end
126
- raise SocketError, "Didn't receive the whomi() packet, can't automatically configure." if !pkt
127
- cap = nil
128
- end
129
- my_data
130
- end
96
+ dst_port = rand(0xffff-1024)+1024
97
+ msg = "PacketFu whoami? packet #{(Time.now.to_i + rand(0xffffff)+1)}"
98
+ iface = (args[:iface] || ENV['IFACE'] || Pcap.lookupdev || :lo ).to_s
99
+ cap = PacketFu::Capture.new(:iface => iface, :promisc => false, :start => true, :filter => "udp and dst host #{dst_host} and dst port #{dst_port}")
100
+ udp_sock = UDPSocket.new
101
+ udp_sock.send(msg,0,dst_host,dst_port)
102
+ udp_sock = nil
103
+ cap.save
104
+ pkt = Packet.parse(cap.array[0]) unless cap.save.zero?
105
+ timeout = 0
106
+ while timeout < 1 # Sometimes packet generation can be a little pokey.
107
+ if pkt
108
+ timeout = 1.1 # Cancel the timeout
109
+ if pkt.payload == msg
110
+ my_data = {
111
+ :iface => (args[:iface] || ENV['IFACE'] || Pcap.lookupdev || "lo").to_s,
112
+ :pcapfile => args[:pcapfile] || "/tmp/out.pcap",
113
+ :eth_saddr => pkt.eth_saddr,
114
+ :eth_src => pkt.eth_src.to_s,
115
+ :ip_saddr => pkt.ip_saddr,
116
+ :ip_src => pkt.ip_src,
117
+ :ip_src_bin => [pkt.ip_src].pack("N"),
118
+ :eth_dst => pkt.eth_dst.to_s,
119
+ :eth_daddr => pkt.eth_daddr
120
+ }
121
+ else raise SecurityError,
122
+ "whoami() packet doesn't match sent data. Something fishy's going on."
123
+ end
124
+ else
125
+ sleep 0.1; timeout += 0.1
126
+ cap.save
127
+ pkt = Packet.parse(cap.array[0]) unless cap.save.zero?
128
+ end
129
+ raise SocketError, "Didn't receive the whoami() packet, can't automatically configure." if !pkt
130
+ cap = nil
131
+ end
132
+ my_data
133
+ end
131
134
 
132
- # This is a brute-force approach at trying to find a suitable interface with an IP address.
133
- def self.lookupdev
134
- # XXX cycle through eth0-9 and wlan0-9, and if a cap start throws a RuntimeErorr (and we're
135
- # root), it's not a good interface. Boy, really ought to fix lookupdev directly with another
136
- # method that returns an array rather than just the first candidate.
137
- end
135
+ # This is a brute-force approach at trying to find a suitable interface with an IP address.
136
+ def self.lookupdev
137
+ # XXX cycle through eth0-9 and wlan0-9, and if a cap start throws a RuntimeErorr (and we're
138
+ # root), it's not a good interface. Boy, really ought to fix lookupdev directly with another
139
+ # method that returns an array rather than just the first candidate.
140
+ end
138
141
 
139
- # Handles ifconfig for various (okay, two) platforms.
140
- # Will have Windows done shortly.
141
- #
142
- # Takes an argument (either string or symbol) of the interface to look up, and
143
- # returns a hash which contains at least the :iface element, and if configured,
144
- # these additional elements:
145
- #
146
- # :eth_saddr # A human readable MAC address
147
- # :eth_src # A packed MAC address
148
- # :ip_saddr # A dotted-quad string IPv4 address
149
- # :ip_src # A packed IPv4 address
150
- # :ip4_obj # An IPAddr object with bitmask
151
- # :ip6_saddr # A colon-delimited hex IPv6 address, with bitmask
152
- # :ip6_obj # An IPAddr object with bitmask
153
- #
154
- # === Example
155
- # PacketFu::Utils.ifconfig :wlan0 # Not associated yet
156
- # #=> {:eth_saddr=>"00:1d:e0:73:9d:ff", :eth_src=>"\000\035\340s\235\377", :iface=>"wlan0"}
157
- # PacketFu::Utils.ifconfig("eth0") # Takes 'eth0' as default
158
- # #=> {:eth_saddr=>"00:1c:23:35:70:3b", :eth_src=>"\000\034#5p;", :ip_saddr=>"10.10.10.9", :ip4_obj=>#<IPAddr: IPv4:10.10.10.0/255.255.254.0>, :ip_src=>"\n\n\n\t", :iface=>"eth0", :ip6_saddr=>"fe80::21c:23ff:fe35:703b/64", :ip6_obj=>#<IPAddr: IPv6:fe80:0000:0000:0000:0000:0000:0000:0000/ffff:ffff:ffff:ffff:0000:0000:0000:0000>}
159
- # PacketFu::Utils.ifconfig :lo
160
- # #=> {:ip_saddr=>"127.0.0.1", :ip4_obj=>#<IPAddr: IPv4:127.0.0.0/255.0.0.0>, :ip_src=>"\177\000\000\001", :iface=>"lo", :ip6_saddr=>"::1/128", :ip6_obj=>#<IPAddr: IPv6:0000:0000:0000:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>}
161
- def self.ifconfig(iface='eth0')
162
- ret = {}
163
- iface = iface.to_s.scan(/[0-9A-Za-z]/).join # Sanitizing input, no spaces, semicolons, etc.
164
- case RUBY_PLATFORM
165
- when /linux/i
166
- ifconfig_data = %x[ifconfig #{iface}]
167
- if ifconfig_data =~ /#{iface}/i
168
- ifconfig_data = ifconfig_data.split(/[\s]*\n[\s]*/)
169
- else
170
- raise ArgumentError, "Cannot ifconfig #{iface}"
171
- end
172
- real_iface = ifconfig_data.first
173
- ret[:iface] = real_iface.split.first.downcase
174
- if real_iface =~ /[\s]HWaddr[\s]+([0-9a-fA-F:]{17})/i
175
- ret[:eth_saddr] = $1.downcase
176
- ret[:eth_src] = EthHeader.mac2str(ret[:eth_saddr])
177
- end
178
- ifconfig_data.each do |s|
179
- case s
180
- when /inet addr:[\s]*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(.*Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+))?/i
181
- ret[:ip_saddr] = $1
182
- ret[:ip_src] = [IPAddr.new($1).to_i].pack("N")
183
- ret[:ip4_obj] = IPAddr.new($1)
184
- ret[:ip4_obj] = ret[:ip4_obj].mask($3) if $3
185
- when /inet6 addr:[\s]*([0-9a-fA-F:\x2f]+)/
186
- ret[:ip6_saddr] = $1
187
- ret[:ip6_obj] = IPAddr.new($1)
188
- end
189
- end # linux
190
- when /darwin/i
191
- ifconfig_data = %x[ifconfig #{iface}]
192
- if ifconfig_data =~ /#{iface}/i
193
- ifconfig_data = ifconfig_data.split(/[\s]*\n[\s]*/)
194
- else
195
- raise ArgumentError, "Cannot ifconfig #{iface}"
196
- end
197
- real_iface = ifconfig_data.first
198
- ret[:iface] = real_iface.split(':')[0]
199
- ifconfig_data.each do |s|
200
- case s
201
- when /ether[\s]([0-9a-fA-F:]{17})/i
202
- ret[:eth_saddr] = $1
203
- ret[:eth_src] = EthHeader.mac2str(ret[:eth_saddr])
204
- when /inet[\s]*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(.*Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+))?/i
205
- ret[:ip_saddr] = $1
206
- ret[:ip_src] = [IPAddr.new($1).to_i].pack("N")
207
- ret[:ip4_obj] = IPAddr.new($1)
208
- ret[:ip4_obj] = ret[:ip4_obj].mask($3) if $3
209
- when /inet6[\s]*([0-9a-fA-F:\x2f]+)/
210
- ret[:ip6_saddr] = $1
211
- ret[:ip6_obj] = IPAddr.new($1)
212
- end
213
- end # darwin
214
- end # RUBY_PLATFORM
215
- ret
216
- end
142
+ # Handles ifconfig for various (okay, two) platforms.
143
+ # Will have Windows done shortly.
144
+ #
145
+ # Takes an argument (either string or symbol) of the interface to look up, and
146
+ # returns a hash which contains at least the :iface element, and if configured,
147
+ # these additional elements:
148
+ #
149
+ # :eth_saddr # A human readable MAC address
150
+ # :eth_src # A packed MAC address
151
+ # :ip_saddr # A dotted-quad string IPv4 address
152
+ # :ip_src # A packed IPv4 address
153
+ # :ip4_obj # An IPAddr object with bitmask
154
+ # :ip6_saddr # A colon-delimited hex IPv6 address, with bitmask
155
+ # :ip6_obj # An IPAddr object with bitmask
156
+ #
157
+ # === Example
158
+ # PacketFu::Utils.ifconfig :wlan0 # Not associated yet
159
+ # #=> {:eth_saddr=>"00:1d:e0:73:9d:ff", :eth_src=>"\000\035\340s\235\377", :iface=>"wlan0"}
160
+ # PacketFu::Utils.ifconfig("eth0") # Takes 'eth0' as default
161
+ # #=> {:eth_saddr=>"00:1c:23:35:70:3b", :eth_src=>"\000\034#5p;", :ip_saddr=>"10.10.10.9", :ip4_obj=>#<IPAddr: IPv4:10.10.10.0/255.255.254.0>, :ip_src=>"\n\n\n\t", :iface=>"eth0", :ip6_saddr=>"fe80::21c:23ff:fe35:703b/64", :ip6_obj=>#<IPAddr: IPv6:fe80:0000:0000:0000:0000:0000:0000:0000/ffff:ffff:ffff:ffff:0000:0000:0000:0000>}
162
+ # PacketFu::Utils.ifconfig :lo
163
+ # #=> {:ip_saddr=>"127.0.0.1", :ip4_obj=>#<IPAddr: IPv4:127.0.0.0/255.0.0.0>, :ip_src=>"\177\000\000\001", :iface=>"lo", :ip6_saddr=>"::1/128", :ip6_obj=>#<IPAddr: IPv6:0000:0000:0000:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>}
164
+ def self.ifconfig(iface='eth0')
165
+ ret = {}
166
+ iface = iface.to_s.scan(/[0-9A-Za-z]/).join # Sanitizing input, no spaces, semicolons, etc.
167
+ case RUBY_PLATFORM
168
+ when /linux/i
169
+ ifconfig_data = %x[ifconfig #{iface}]
170
+ if ifconfig_data =~ /#{iface}/i
171
+ ifconfig_data = ifconfig_data.split(/[\s]*\n[\s]*/)
172
+ else
173
+ raise ArgumentError, "Cannot ifconfig #{iface}"
174
+ end
175
+ real_iface = ifconfig_data.first
176
+ ret[:iface] = real_iface.split.first.downcase
177
+ if real_iface =~ /[\s]HWaddr[\s]+([0-9a-fA-F:]{17})/i
178
+ ret[:eth_saddr] = $1.downcase
179
+ ret[:eth_src] = EthHeader.mac2str(ret[:eth_saddr])
180
+ end
181
+ ifconfig_data.each do |s|
182
+ case s
183
+ when /inet addr:[\s]*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(.*Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+))?/i
184
+ ret[:ip_saddr] = $1
185
+ ret[:ip_src] = [IPAddr.new($1).to_i].pack("N")
186
+ ret[:ip4_obj] = IPAddr.new($1)
187
+ ret[:ip4_obj] = ret[:ip4_obj].mask($3) if $3
188
+ when /inet6 addr:[\s]*([0-9a-fA-F:\x2f]+)/
189
+ ret[:ip6_saddr] = $1
190
+ ret[:ip6_obj] = IPAddr.new($1)
191
+ end
192
+ end # linux
193
+ when /darwin/i
194
+ ifconfig_data = %x[ifconfig #{iface}]
195
+ if ifconfig_data =~ /#{iface}/i
196
+ ifconfig_data = ifconfig_data.split(/[\s]*\n[\s]*/)
197
+ else
198
+ raise ArgumentError, "Cannot ifconfig #{iface}"
199
+ end
200
+ real_iface = ifconfig_data.first
201
+ ret[:iface] = real_iface.split(':')[0]
202
+ ifconfig_data.each do |s|
203
+ case s
204
+ when /ether[\s]([0-9a-fA-F:]{17})/i
205
+ ret[:eth_saddr] = $1
206
+ ret[:eth_src] = EthHeader.mac2str(ret[:eth_saddr])
207
+ when /inet[\s]*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(.*Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+))?/i
208
+ ret[:ip_saddr] = $1
209
+ ret[:ip_src] = [IPAddr.new($1).to_i].pack("N")
210
+ ret[:ip4_obj] = IPAddr.new($1)
211
+ ret[:ip4_obj] = ret[:ip4_obj].mask($3) if $3
212
+ when /inet6[\s]*([0-9a-fA-F:\x2f]+)/
213
+ ret[:ip6_saddr] = $1
214
+ ret[:ip6_obj] = IPAddr.new($1)
215
+ end
216
+ end # darwin
217
+ end # RUBY_PLATFORM
218
+ ret
219
+ end
217
220
 
218
- end
221
+ end
219
222
 
220
223
  end
221
224
 
@@ -1,50 +1,51 @@
1
+ # -*- coding: binary -*-
1
2
  module PacketFu
2
3
 
3
- # Check the repo's for version release histories
4
- VERSION = "1.1.8"
4
+ # Check the repo's for version release histories
5
+ VERSION = "1.1.9"
5
6
 
6
- # Returns PacketFu::VERSION
7
- def self.version
8
- VERSION
9
- end
7
+ # Returns PacketFu::VERSION
8
+ def self.version
9
+ VERSION
10
+ end
10
11
 
11
- # Returns a version string in a binary format for easy comparisons.
12
- def self.binarize_version(str)
13
- if(str.respond_to?(:split) && str =~ /^[0-9]+(\.([0-9]+)(\.[0-9]+)?)?\..+$/)
14
- bin_major,bin_minor,bin_teeny = str.split(/\x2e/).map {|x| x.to_i}
15
- bin_version = (bin_major.to_i << 16) + (bin_minor.to_i << 8) + bin_teeny.to_i
16
- else
17
- raise ArgumentError, "Compare version malformed. Should be \x22x.y.z\x22"
18
- end
19
- end
12
+ # Returns a version string in a binary format for easy comparisons.
13
+ def self.binarize_version(str)
14
+ if(str.respond_to?(:split) && str =~ /^[0-9]+(\.([0-9]+)(\.[0-9]+)?)?\..+$/)
15
+ bin_major,bin_minor,bin_teeny = str.split(/\x2e/).map {|x| x.to_i}
16
+ bin_version = (bin_major.to_i << 16) + (bin_minor.to_i << 8) + bin_teeny.to_i
17
+ else
18
+ raise ArgumentError, "Compare version malformed. Should be \x22x.y.z\x22"
19
+ end
20
+ end
20
21
 
21
- # Returns true if the version is equal to or greater than the compare version.
22
- # If the current version of PacketFu is "0.3.1" for example:
23
- #
24
- # PacketFu.at_least? "0" # => true
25
- # PacketFu.at_least? "0.2.9" # => true
26
- # PacketFu.at_least? "0.3" # => true
27
- # PacketFu.at_least? "1" # => true after 1.0's release
28
- # PacketFu.at_least? "1.12" # => false
29
- # PacketFu.at_least? "2" # => false
30
- def self.at_least?(str)
31
- this_version = binarize_version(self.version)
32
- ask_version = binarize_version(str)
33
- this_version >= ask_version
34
- end
22
+ # Returns true if the version is equal to or greater than the compare version.
23
+ # If the current version of PacketFu is "0.3.1" for example:
24
+ #
25
+ # PacketFu.at_least? "0" # => true
26
+ # PacketFu.at_least? "0.2.9" # => true
27
+ # PacketFu.at_least? "0.3" # => true
28
+ # PacketFu.at_least? "1" # => true after 1.0's release
29
+ # PacketFu.at_least? "1.12" # => false
30
+ # PacketFu.at_least? "2" # => false
31
+ def self.at_least?(str)
32
+ this_version = binarize_version(self.version)
33
+ ask_version = binarize_version(str)
34
+ this_version >= ask_version
35
+ end
35
36
 
36
- # Returns true if the current version is older than the compare version.
37
- def self.older_than?(str)
38
- return false if str == self.version
39
- this_version = binarize_version(self.version)
40
- ask_version = binarize_version(str)
41
- this_version < ask_version
42
- end
37
+ # Returns true if the current version is older than the compare version.
38
+ def self.older_than?(str)
39
+ return false if str == self.version
40
+ this_version = binarize_version(self.version)
41
+ ask_version = binarize_version(str)
42
+ this_version < ask_version
43
+ end
43
44
 
44
- # Returns true if the current version is newer than the compare version.
45
- def self.newer_than?(str)
46
- return false if str == self.version
47
- !self.older_than?(str)
48
- end
45
+ # Returns true if the current version is newer than the compare version.
46
+ def self.newer_than?(str)
47
+ return false if str == self.version
48
+ !self.older_than?(str)
49
+ end
49
50
 
50
51
  end