packetfu 1.1.9 → 1.1.10

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