rex-socket 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a2cd6273cbf1dc4a60a2af6dc31601368bc7931d
4
+ data.tar.gz: 3c8cbbe8f77806d8c391e79964b30dc0c43a3afd
5
+ SHA512:
6
+ metadata.gz: baba065cc14de4e9b4ecab38bed825e2fd4eca61566ff743c394b0eee694a65b0f81bfcfaa4b2f81802a21ea3f0cb920417fea4f0a9f602a1f8eb9922c81a5e0
7
+ data.tar.gz: 6381df08052531dab6b6382f85883c20962a971584e1f24e416d80d5a1fb2624f0847f7cb133659b81ad04dd2edea3e3dcb74f7172361c5d81907a91a677230b
Binary file
Binary file
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.12.5
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at DMaloney@rapid7.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rex-socket.gemspec
4
+ gemspec
@@ -0,0 +1,32 @@
1
+ # Rex::Socket
2
+
3
+ The Ruby Exploitation (Rex) Socket Abstraction Library. This library includes all of the code needed to turn sockets into
4
+ Rex::Sockets with the functionality for things like L3 pivoting used by Metasploit.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'rex-socket'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install rex-socket
21
+
22
+
23
+ ## Development
24
+
25
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
26
+
27
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
28
+
29
+ ## Contributing
30
+
31
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rex-socket. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
32
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rex/socket"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,798 @@
1
+ # -*- coding: binary -*-
2
+ require 'rex/socket/version'
3
+ require 'socket'
4
+ require 'thread'
5
+ require 'resolv'
6
+ require 'rex/exceptions'
7
+
8
+ module Rex
9
+
10
+ ###
11
+ #
12
+ # Base class for all sockets.
13
+ #
14
+ ###
15
+ module Socket
16
+
17
+ module Comm
18
+ end
19
+
20
+ require 'rex/socket/x509_certificate'
21
+ require 'rex/socket/parameters'
22
+ require 'rex/socket/tcp'
23
+ require 'rex/socket/tcp_server'
24
+
25
+ require 'rex/socket/comm'
26
+ require 'rex/socket/comm/local'
27
+
28
+ require 'rex/socket/switch_board'
29
+ require 'rex/socket/subnet_walker'
30
+ require 'rex/socket/range_walker'
31
+
32
+ ##
33
+ #
34
+ # Factory methods
35
+ #
36
+ ##
37
+
38
+ #
39
+ # Create a socket instance using the supplied parameter hash.
40
+ #
41
+ def self.create(opts = {})
42
+ return create_param(Rex::Socket::Parameters.from_hash(opts))
43
+ end
44
+
45
+ #
46
+ # Create a socket using the supplied Rex::Socket::Parameter instance.
47
+ #
48
+ def self.create_param(param)
49
+ return param.comm.create(param)
50
+ end
51
+
52
+ #
53
+ # Create a TCP socket using the supplied parameter hash.
54
+ #
55
+ def self.create_tcp(opts = {})
56
+ return create_param(Rex::Socket::Parameters.from_hash(opts.merge('Proto' => 'tcp')))
57
+ end
58
+
59
+ #
60
+ # Create a TCP server socket using the supplied parameter hash.
61
+ #
62
+ def self.create_tcp_server(opts = {})
63
+ return create_tcp(opts.merge('Server' => true))
64
+ end
65
+
66
+ #
67
+ # Create a UDP socket using the supplied parameter hash.
68
+ #
69
+ def self.create_udp(opts = {})
70
+ return create_param(Rex::Socket::Parameters.from_hash(opts.merge('Proto' => 'udp')))
71
+ end
72
+
73
+ #
74
+ # Create a IP socket using the supplied parameter hash.
75
+ #
76
+ def self.create_ip(opts = {})
77
+ return create_param(Rex::Socket::Parameters.from_hash(opts.merge('Proto' => 'ip')))
78
+ end
79
+
80
+
81
+ #
82
+ # Common Regular Expressions
83
+ #
84
+
85
+ MATCH_IPV6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/
86
+
87
+ MATCH_IPV4 = /^\s*(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))\s*$/
88
+
89
+ MATCH_IPV4_PRIVATE = /^\s*(?:10\.|192\.168|172.(?:1[6-9]|2[0-9]|3[01])\.|169\.254)/
90
+
91
+ ##
92
+ #
93
+ # Serialization
94
+ #
95
+ ##
96
+
97
+
98
+ # Cache our IPv6 support flag
99
+ @@support_ipv6 = nil
100
+
101
+ #
102
+ # Determine whether we support IPv6
103
+ #
104
+ def self.support_ipv6?
105
+ return @@support_ipv6 if not @@support_ipv6.nil?
106
+
107
+ @@support_ipv6 = false
108
+
109
+ if (::Socket.const_defined?('AF_INET6'))
110
+ begin
111
+ s = ::Socket.new(::Socket::AF_INET6, ::Socket::SOCK_DGRAM, ::Socket::IPPROTO_UDP)
112
+ s.close
113
+ @@support_ipv6 = true
114
+ rescue
115
+ end
116
+ end
117
+
118
+ return @@support_ipv6
119
+ end
120
+
121
+ #
122
+ # Determine whether this is an IPv4 address
123
+ #
124
+ def self.is_ipv4?(addr)
125
+ ( addr =~ MATCH_IPV4 ) ? true : false
126
+ end
127
+
128
+ #
129
+ # Determine whether this is an IPv6 address
130
+ #
131
+ def self.is_ipv6?(addr)
132
+ ( addr =~ MATCH_IPV6 ) ? true : false
133
+ end
134
+
135
+ #
136
+ # Checks to see if the supplied address is in "dotted" form
137
+ #
138
+ def self.dotted_ip?(addr)
139
+ # Match IPv6
140
+ return true if (support_ipv6? and addr =~ MATCH_IPV6)
141
+
142
+ # Match IPv4
143
+ return true if (addr =~ MATCH_IPV4)
144
+
145
+ false
146
+ end
147
+
148
+ #
149
+ # Return true if +addr+ is within the ranges specified in RFC1918, or
150
+ # RFC5735/RFC3927
151
+ #
152
+ def self.is_internal?(addr)
153
+ if self.dotted_ip?(addr)
154
+ addr =~ MATCH_IPV4_PRIVATE
155
+ else
156
+ false
157
+ end
158
+ end
159
+
160
+ # Get the first address returned by a DNS lookup for +hostname+.
161
+ #
162
+ # @see .getaddresses
163
+ #
164
+ # @param (see .getaddresses)
165
+ # @return [String] ASCII IP address
166
+ def self.getaddress(hostname, accept_ipv6 = true)
167
+ getaddresses(hostname, accept_ipv6).first
168
+ end
169
+
170
+ #
171
+ # Wrapper for +::Socket.gethostbyname+ that takes special care to see if the
172
+ # supplied address is already an ASCII IP address. This is necessary to
173
+ # prevent blocking while waiting on a DNS reverse lookup when we already
174
+ # have what we need.
175
+ #
176
+ # @param hostname [String] A hostname or ASCII IP address
177
+ # @return [Array<String>]
178
+ def self.getaddresses(hostname, accept_ipv6 = true)
179
+ if hostname =~ MATCH_IPV4 or (accept_ipv6 and hostname =~ MATCH_IPV6)
180
+ return [hostname]
181
+ end
182
+
183
+ res = ::Socket.gethostbyname(hostname)
184
+ return [] if not res
185
+
186
+ # Shift the first three elements out, leaving just the list of
187
+ # addresses
188
+ res.shift # name
189
+ res.shift # alias hostnames
190
+ res.shift # address_family
191
+
192
+ # Rubinius has a bug where gethostbyname returns dotted quads instead of
193
+ # NBO, but that's what we want anyway, so just short-circuit here.
194
+ if res[0] =~ MATCH_IPV4 || res[0] =~ MATCH_IPV6
195
+ unless accept_ipv6
196
+ res.reject!{ |ascii| ascii =~ MATCH_IPV6 }
197
+ end
198
+ else
199
+ unless accept_ipv6
200
+ res.reject!{ |nbo| nbo.length != 4 }
201
+ end
202
+ res.map!{ |nbo| self.addr_ntoa(nbo) }
203
+ end
204
+
205
+ res
206
+ end
207
+
208
+ #
209
+ # Wrapper for Socket.gethostbyname which takes into account whether or not
210
+ # an IP address is supplied. If it is, then reverse DNS resolution does
211
+ # not occur. This is done in order to prevent delays, such as would occur
212
+ # on Windows.
213
+ #
214
+ def self.gethostbyname(host)
215
+ if (is_ipv4?(host))
216
+ return [ host, [], 2, host.split('.').map{ |c| c.to_i }.pack("C4") ]
217
+ end
218
+
219
+ if is_ipv6?(host)
220
+ # pop off the scopeid since gethostbyname isn't smart enough to
221
+ # deal with it.
222
+ host, _ = host.split('%', 2)
223
+ end
224
+
225
+ ::Socket.gethostbyname(host)
226
+ end
227
+
228
+ #
229
+ # Create a sockaddr structure using the supplied IP address, port, and
230
+ # address family
231
+ #
232
+ def self.to_sockaddr(ip, port)
233
+
234
+ if (ip == '::ffff:0.0.0.0')
235
+ ip = support_ipv6?() ? '::' : '0.0.0.0'
236
+ end
237
+
238
+ return ::Socket.pack_sockaddr_in(port, ip)
239
+ end
240
+
241
+ #
242
+ # Returns the address family, host, and port of the supplied sockaddr as
243
+ # [ af, host, port ]
244
+ #
245
+ def self.from_sockaddr(saddr)
246
+ port, host = ::Socket::unpack_sockaddr_in(saddr)
247
+ af = ::Socket::AF_INET
248
+ if (support_ipv6?() and is_ipv6?(host))
249
+ af = ::Socket::AF_INET6
250
+ end
251
+ return [ af, host, port ]
252
+ end
253
+
254
+ #
255
+ # Resolves a host to raw network-byte order.
256
+ #
257
+ def self.resolv_nbo(host)
258
+ self.gethostbyname( Rex::Socket.getaddress(host, true) )[3]
259
+ end
260
+
261
+ #
262
+ # Resolves a host to raw network-byte order.
263
+ #
264
+ def self.resolv_nbo_list(host)
265
+ Rex::Socket.getaddresses(host).map{|addr| self.gethostbyname(addr)[3] }
266
+ end
267
+
268
+ #
269
+ # Resolves a host to a network-byte order ruby integer.
270
+ #
271
+ def self.resolv_nbo_i(host)
272
+ addr_ntoi(resolv_nbo(host))
273
+ end
274
+
275
+ #
276
+ # Resolves a host to a list of network-byte order ruby integers.
277
+ #
278
+ def self.resolv_nbo_i_list(host)
279
+ resolv_nbo_list(host).map{|addr| addr_ntoi(addr) }
280
+ end
281
+
282
+ #
283
+ # Converts an ASCII IP address to a CIDR mask. Returns
284
+ # nil if it's not convertable.
285
+ #
286
+ def self.addr_atoc(mask)
287
+ mask_i = resolv_nbo_i(mask)
288
+ cidr = nil
289
+ 0.upto(32) do |i|
290
+ if ((1 << i)-1) << (32-i) == mask_i
291
+ cidr = i
292
+ break
293
+ end
294
+ end
295
+ return cidr
296
+ end
297
+
298
+ #
299
+ # Resolves a CIDR bitmask into a dotted-quad. Returns
300
+ # nil if it's not convertable.
301
+ #
302
+ def self.addr_ctoa(cidr)
303
+ return nil unless (0..32) === cidr.to_i
304
+ addr_itoa(((1 << cidr)-1) << 32-cidr)
305
+ end
306
+
307
+ #
308
+ # Resolves a host to a dotted address.
309
+ #
310
+ def self.resolv_to_dotted(host)
311
+ addr_ntoa(addr_aton(host))
312
+ end
313
+
314
+ #
315
+ # Converts a ascii address into an integer
316
+ #
317
+ def self.addr_atoi(addr)
318
+ resolv_nbo_i(addr)
319
+ end
320
+
321
+ #
322
+ # Converts a ascii address into a list of addresses
323
+ #
324
+ def self.addr_atoi_list(addr)
325
+ resolv_nbo_i_list(addr)
326
+ end
327
+
328
+ #
329
+ # Converts an integer address into ascii
330
+ #
331
+ # @param (see #addr_iton)
332
+ # @return (see #addr_ntoa)
333
+ def self.addr_itoa(addr, v6=false)
334
+ nboa = addr_iton(addr, v6)
335
+
336
+ addr_ntoa(nboa)
337
+ end
338
+
339
+ #
340
+ # Converts a ascii address to network byte order
341
+ #
342
+ def self.addr_aton(addr)
343
+ resolv_nbo(addr)
344
+ end
345
+
346
+ #
347
+ # Converts a network byte order address to ascii
348
+ #
349
+ # @param addr [String] Packed network-byte-order address
350
+ # @return [String] Human readable IP address.
351
+ def self.addr_ntoa(addr)
352
+ # IPv4
353
+ if (addr.length == 4)
354
+ return addr.unpack('C4').join('.')
355
+ end
356
+
357
+ # IPv6
358
+ if (addr.length == 16)
359
+ return compress_address(addr.unpack('n8').map{ |c| "%x" % c }.join(":"))
360
+ end
361
+
362
+ raise RuntimeError, "Invalid address format"
363
+ end
364
+
365
+ #
366
+ # Implement zero compression for IPv6 addresses.
367
+ # Uses the compression method from Marco Ceresa's IPAddress GEM
368
+ #
369
+ # @see https://github.com/bluemonk/ipaddress/blob/master/lib/ipaddress/ipv6.rb
370
+ #
371
+ # @param addr [String] Human readable IPv6 address
372
+ # @return [String] Human readable IPv6 address with runs of 0s removed
373
+ def self.compress_address(addr)
374
+ return addr unless is_ipv6?(addr)
375
+ addr = addr.dup
376
+ while true
377
+ break if addr.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::')
378
+ break if addr.sub!(/\b0:0:0:0:0:0:0\b/, ':')
379
+ break if addr.sub!(/\b0:0:0:0:0:0\b/, ':')
380
+ break if addr.sub!(/\b0:0:0:0:0\b/, ':')
381
+ break if addr.sub!(/\b0:0:0:0\b/, ':')
382
+ break if addr.sub!(/\b0:0:0\b/, ':')
383
+ break if addr.sub!(/\b0:0\b/, ':')
384
+ break
385
+ end
386
+ addr.sub(/:{3,}/, '::')
387
+ end
388
+
389
+ #
390
+ # Converts a network byte order address to an integer
391
+ #
392
+ def self.addr_ntoi(addr)
393
+
394
+ bits = addr.unpack("N*")
395
+
396
+ if (bits.length == 1)
397
+ return bits[0]
398
+ end
399
+
400
+ if (bits.length == 4)
401
+ val = 0
402
+ bits.each_index { |i| val += ( bits[i] << (96 - (i * 32)) ) }
403
+ return val
404
+ end
405
+
406
+ raise RuntimeError, "Invalid address format"
407
+ end
408
+
409
+ #
410
+ # Converts an integer into a network byte order address
411
+ #
412
+ # @param addr [Numeric] The address as a number
413
+ # @param v6 [Boolean] Whether +addr+ is IPv6
414
+ def self.addr_iton(addr, v6=false)
415
+ if(addr < 0x100000000 && !v6)
416
+ return [addr].pack('N')
417
+ else
418
+ w = []
419
+ w[0] = (addr >> 96) & 0xffffffff
420
+ w[1] = (addr >> 64) & 0xffffffff
421
+ w[2] = (addr >> 32) & 0xffffffff
422
+ w[3] = addr & 0xffffffff
423
+ return w.pack('N4')
424
+ end
425
+ end
426
+
427
+ #
428
+ # Converts a colon-delimited MAC address into a 6-byte binary string
429
+ #
430
+ def self.eth_aton(mac)
431
+ mac.split(":").map{|c| c.to_i(16) }.pack("C*")
432
+ end
433
+
434
+ #
435
+ # Converts a 6-byte binary string into a colon-delimited MAC address
436
+ #
437
+ def self.eth_ntoa(bin)
438
+ bin.unpack("C6").map{|x| "%.2x" % x }.join(":").upcase
439
+ end
440
+
441
+ #
442
+ # Converts a CIDR subnet into an array (base, bcast)
443
+ #
444
+ def self.cidr_crack(cidr, v6=false)
445
+ tmp = cidr.split('/')
446
+
447
+ tst,scope = tmp[0].split("%",2)
448
+ scope = "%" + scope if scope
449
+ scope ||= ""
450
+
451
+ addr = addr_atoi(tst)
452
+
453
+ bits = 32
454
+ mask = 0
455
+ use6 = false
456
+
457
+ if (addr > 0xffffffff or v6 or cidr =~ /:/)
458
+ use6 = true
459
+ bits = 128
460
+ end
461
+
462
+ mask = (2 ** bits) - (2 ** (bits - tmp[1].to_i))
463
+ base = addr & mask
464
+
465
+ stop = base + (2 ** (bits - tmp[1].to_i)) - 1
466
+ return [self.addr_itoa(base, use6) + scope, self.addr_itoa(stop, use6) + scope]
467
+ end
468
+
469
+ #
470
+ # Converts a netmask (255.255.255.240) into a bitmask (28). This is the
471
+ # lame kid way of doing it.
472
+ #
473
+ def self.net2bitmask(netmask)
474
+
475
+ nmask = resolv_nbo(netmask)
476
+ imask = addr_ntoi(nmask)
477
+ bits = 32
478
+
479
+ if (imask > 0xffffffff)
480
+ bits = 128
481
+ end
482
+
483
+ 0.upto(bits-1) do |bit|
484
+ p = 2 ** bit
485
+ return (bits - bit) if ((imask & p) == p)
486
+ end
487
+
488
+ 0
489
+ end
490
+
491
+ #
492
+ # Converts a bitmask (28) into a netmask (255.255.255.240)
493
+ #
494
+ def self.bit2netmask(bitmask, ipv6=false)
495
+ if bitmask > 32 or ipv6
496
+ i = ((~((2 ** (128 - bitmask)) - 1)) & (2**128-1))
497
+ n = Rex::Socket.addr_iton(i, true)
498
+ return Rex::Socket.addr_ntoa(n)
499
+ else
500
+ [ (~((2 ** (32 - bitmask)) - 1)) & 0xffffffff ].pack('N').unpack('CCCC').join('.')
501
+ end
502
+ end
503
+
504
+
505
+ def self.portspec_crack(pspec)
506
+ portspec_to_portlist(pspec)
507
+ end
508
+
509
+ #
510
+ # Converts a port specification like "80,21-25,!24,443" into a sorted,
511
+ # unique array of valid port numbers like [21,22,23,25,80,443]
512
+ #
513
+ def self.portspec_to_portlist(pspec)
514
+ ports = []
515
+ remove = []
516
+
517
+ # Build ports array from port specification
518
+ pspec.split(/,/).each do |item|
519
+ target = ports
520
+
521
+ item.strip!
522
+
523
+ if item.start_with? '!'
524
+ item.delete! '!'
525
+ target = remove
526
+ end
527
+
528
+ start, stop = item.split(/-/).map { |p| p.to_i }
529
+
530
+ start ||= 0
531
+ stop ||= item.match(/-/) ? 65535 : start
532
+
533
+ start, stop = stop, start if stop < start
534
+
535
+ start.upto(stop) { |p| target << p }
536
+ end
537
+
538
+ if ports.empty? and not remove.empty? then
539
+ ports = 1.upto 65535
540
+ end
541
+
542
+ # Sort, and remove dups and invalid ports
543
+ ports.sort.uniq.delete_if { |p| p < 1 or p > 65535 or remove.include? p }
544
+ end
545
+
546
+ #
547
+ # Converts a port list like [1,2,3,4,5,100] into a
548
+ # range specification like "1-5,100"
549
+ #
550
+ def self.portlist_to_portspec(parr)
551
+ ranges = []
552
+ range = []
553
+ lastp = nil
554
+
555
+ parr.uniq.sort{|a,b| a<=>b}.map{|a| a.to_i}.each do |n|
556
+ next if (n < 1 or n > 65535)
557
+ if not lastp
558
+ range = [n]
559
+ lastp = n
560
+ next
561
+ end
562
+
563
+ if lastp == n - 1
564
+ range << n
565
+ else
566
+ ranges << range
567
+ range = [n]
568
+ end
569
+ lastp = n
570
+ end
571
+
572
+ ranges << range
573
+ ranges.delete(nil)
574
+ ranges.uniq.map{|x| x.length == 1 ? "#{x[0]}" : "#{x[0]}-#{x[-1]}"}.join(",")
575
+ end
576
+
577
+ ##
578
+ #
579
+ # Utility class methods
580
+ #
581
+ ##
582
+
583
+ #
584
+ # This method does NOT send any traffic to the destination, instead, it uses a
585
+ # "bound" UDP socket to determine what source address we would use to
586
+ # communicate with the specified destination. The destination defaults to
587
+ # Google's DNS server to make the standard behavior determine which IP
588
+ # we would use to communicate with the internet.
589
+ #
590
+ def self.source_address(dest='8.8.8.8', comm = ::Rex::Socket::Comm::Local)
591
+ begin
592
+ s = self.create_udp(
593
+ 'PeerHost' => dest,
594
+ 'PeerPort' => 31337,
595
+ 'Comm' => comm
596
+ )
597
+ r = s.getsockname[1]
598
+ s.close
599
+
600
+ # Trim off the trailing interface ID for link-local IPv6
601
+ return r.split('%').first
602
+ rescue ::Exception
603
+ return '127.0.0.1'
604
+ end
605
+ end
606
+
607
+ #
608
+ # Identifies the link-local address of a given interface (if IPv6 is enabled)
609
+ #
610
+ def self.ipv6_link_address(intf)
611
+ r = source_address("FF02::1%#{intf}")
612
+ return nil if r.nil? || r !~ /^fe80/i
613
+ r
614
+ end
615
+
616
+ #
617
+ # Identifies the mac address of a given interface (if IPv6 is enabled)
618
+ #
619
+ def self.ipv6_mac(intf)
620
+ r = ipv6_link_address(intf)
621
+ return if not r
622
+ raw = addr_aton(r)[-8, 8]
623
+ (raw[0,3] + raw[5,3]).unpack("C*").map{|c| "%.2x" % c}.join(":")
624
+ end
625
+
626
+ #
627
+ # Create a TCP socket pair.
628
+ #
629
+ # sf: This create a socket pair using native ruby sockets and will work
630
+ # on Windows where ::Socket.pair is not implemented.
631
+ # Note: OpenSSL requires native ruby sockets for its io.
632
+ #
633
+ # Note: Even though sub-threads are smashing the parent threads local, there
634
+ # is no concurrent use of the same locals and this is safe.
635
+ def self.tcp_socket_pair
636
+ lsock = nil
637
+ rsock = nil
638
+ laddr = '127.0.0.1'
639
+ lport = 0
640
+ threads = []
641
+ mutex = ::Mutex.new
642
+
643
+ threads << Rex::ThreadFactory.spawn('TcpSocketPair', false) {
644
+ server = nil
645
+ mutex.synchronize {
646
+ threads << Rex::ThreadFactory.spawn('TcpSocketPairClient', false) {
647
+ mutex.synchronize {
648
+ rsock = ::TCPSocket.new( laddr, lport )
649
+ }
650
+ }
651
+ server = ::TCPServer.new(laddr, 0)
652
+ if (server.getsockname =~ /127\.0\.0\.1:/)
653
+ # JRuby ridiculousness
654
+ caddr, lport = server.getsockname.split(":")
655
+ caddr = caddr[1,caddr.length]
656
+ lport = lport.to_i
657
+ else
658
+ # Sane implementations where Socket#getsockname returns a
659
+ # sockaddr
660
+ lport, caddr = ::Socket.unpack_sockaddr_in( server.getsockname )
661
+ end
662
+ }
663
+ lsock, _ = server.accept
664
+ server.close
665
+ }
666
+
667
+ threads.each { |t| t.join }
668
+
669
+ return [lsock, rsock]
670
+ end
671
+
672
+ #
673
+ # Create a UDP socket pair using native ruby UDP sockets.
674
+ #
675
+ def self.udp_socket_pair
676
+ laddr = '127.0.0.1'
677
+
678
+ lsock = ::UDPSocket.new
679
+ lsock.bind( laddr, 0 )
680
+
681
+ rsock = ::UDPSocket.new
682
+ rsock.bind( laddr, 0 )
683
+
684
+ rsock.connect( *lsock.addr.values_at(3,1) )
685
+
686
+ lsock.connect( *rsock.addr.values_at(3,1) )
687
+
688
+ return [lsock, rsock]
689
+ end
690
+
691
+
692
+ ##
693
+ #
694
+ # Class initialization
695
+ #
696
+ ##
697
+
698
+ #
699
+ # Initialize general socket parameters.
700
+ #
701
+ def initsock(params = nil)
702
+ if (params)
703
+ self.peerhost = params.peerhost
704
+ self.peerport = params.peerport
705
+ self.localhost = params.localhost
706
+ self.localport = params.localport
707
+ self.context = params.context || {}
708
+ self.ipv = params.v6 ? 6 : 4
709
+ end
710
+ end
711
+
712
+ #
713
+ # By default, all sockets are themselves selectable file descriptors.
714
+ #
715
+ def fd
716
+ self
717
+ end
718
+
719
+ #
720
+ # Returns local connection information.
721
+ #
722
+ def getsockname
723
+ Socket.from_sockaddr(super)
724
+ end
725
+
726
+ #
727
+ # Wrapper around getsockname
728
+ #
729
+ def getlocalname
730
+ getsockname
731
+ end
732
+
733
+ #
734
+ # Return peer connection information.
735
+ #
736
+ def getpeername_as_array
737
+ peer_name = nil
738
+ begin
739
+ peer_name = Socket.from_sockaddr(self.getpeername)
740
+ rescue ::Errno::EINVAL => e
741
+ # Ruby's getpeername method may call rb_sys_fail("getpeername(2)")
742
+ elog("#{e.message} (#{e.class})#{e.backtrace * "\n"}\n", 'core', LEV_3)
743
+ end
744
+
745
+ return peer_name
746
+ end
747
+
748
+ #
749
+ # Returns a string that indicates the type of the socket, such as 'tcp'.
750
+ #
751
+ def type?
752
+ raise NotImplementedError, "Socket type is not supported."
753
+ end
754
+
755
+ #
756
+ # The peer host of the connected socket.
757
+ #
758
+ attr_reader :peerhost
759
+ #
760
+ # The peer port of the connected socket.
761
+ #
762
+ attr_reader :peerport
763
+ #
764
+ # The local host of the connected socket.
765
+ #
766
+ attr_reader :localhost
767
+ #
768
+ # The local port of the connected socket.
769
+ #
770
+ attr_reader :localport
771
+ #
772
+ # The IP version of the socket
773
+ #
774
+ attr_reader :ipv
775
+ #
776
+ # Contextual information that describes the source and other
777
+ # instance-specific attributes. This comes from the param.context
778
+ # attribute.
779
+ #
780
+ attr_reader :context
781
+
782
+ protected
783
+
784
+ attr_writer :peerhost, :peerport, :localhost, :localport # :nodoc:
785
+ attr_writer :context # :nodoc:
786
+ attr_writer :ipv # :nodoc:
787
+
788
+ end
789
+
790
+ end
791
+
792
+ #
793
+ # Globalized socket constants
794
+ #
795
+ SHUT_RDWR = ::Socket::SHUT_RDWR
796
+ SHUT_RD = ::Socket::SHUT_RD
797
+ SHUT_WR = ::Socket::SHUT_WR
798
+