metasploit_data_models 0.24.5 → 1.0.0.pre.rails.pre.4.0a
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -1
- data/.simplecov +1 -1
- data/Gemfile +8 -5
- data/app/models/mdm/api_key.rb +1 -0
- data/app/models/mdm/client.rb +2 -2
- data/app/models/mdm/cred.rb +13 -13
- data/app/models/mdm/event.rb +5 -4
- data/app/models/mdm/exploit_attempt.rb +1 -0
- data/app/models/mdm/exploited_host.rb +1 -1
- data/app/models/mdm/host.rb +37 -20
- data/app/models/mdm/host_detail.rb +2 -2
- data/app/models/mdm/host_tag.rb +1 -1
- data/app/models/mdm/listener.rb +2 -1
- data/app/models/mdm/loot.rb +1 -0
- data/app/models/mdm/macro.rb +1 -1
- data/app/models/mdm/mod_ref.rb +1 -0
- data/app/models/mdm/module/action.rb +1 -7
- data/app/models/mdm/module/arch.rb +0 -6
- data/app/models/mdm/module/author.rb +1 -8
- data/app/models/mdm/module/detail.rb +1 -1
- data/app/models/mdm/module/mixin.rb +0 -6
- data/app/models/mdm/module/platform.rb +0 -6
- data/app/models/mdm/module/ref.rb +0 -6
- data/app/models/mdm/module/target.rb +0 -7
- data/app/models/mdm/nexpose_console.rb +1 -0
- data/app/models/mdm/note.rb +3 -3
- data/app/models/mdm/ref.rb +0 -6
- data/app/models/mdm/route.rb +2 -1
- data/app/models/mdm/service.rb +1 -1
- data/app/models/mdm/session.rb +8 -7
- data/app/models/mdm/session_event.rb +2 -1
- data/app/models/mdm/tag.rb +2 -2
- data/app/models/mdm/task.rb +1 -3
- data/app/models/mdm/user.rb +4 -5
- data/app/models/mdm/vuln.rb +8 -7
- data/app/models/mdm/vuln_attempt.rb +1 -0
- data/app/models/mdm/vuln_detail.rb +3 -2
- data/app/models/mdm/vuln_ref.rb +1 -1
- data/app/models/mdm/web_form.rb +2 -1
- data/app/models/mdm/web_page.rb +3 -2
- data/app/models/mdm/web_site.rb +3 -2
- data/app/models/mdm/web_vuln.rb +1 -0
- data/app/models/mdm/wmap_request.rb +12 -0
- data/app/models/mdm/wmap_target.rb +12 -0
- data/app/models/mdm/workspace.rb +4 -3
- data/app/models/metasploit_data_models/automatic_exploitation/match.rb +0 -3
- data/app/models/metasploit_data_models/automatic_exploitation/match_result.rb +0 -12
- data/app/models/metasploit_data_models/automatic_exploitation/match_set.rb +0 -1
- data/app/models/metasploit_data_models/automatic_exploitation/run.rb +0 -2
- data/app/validators/ip_format_validator.rb +6 -1
- data/config/initializers/ipaddr.rb +35 -0
- data/db/migrate/002_add_workspaces.rb +2 -2
- data/db/migrate/007_add_loots.rb +1 -1
- data/db/migrate/008_create_users.rb +1 -1
- data/db/migrate/011_add_reports.rb +1 -1
- data/db/migrate/012_add_tasks.rb +1 -1
- data/db/migrate/026_add_creds_table.rb +2 -2
- data/db/migrate/20100824151500_add_exploited_table.rb +1 -1
- data/db/migrate/20100911122000_add_report_templates.rb +1 -1
- data/db/migrate/20100916175000_add_campaigns_and_templates.rb +1 -1
- data/db/migrate/20101001000000_add_web_tables.rb +13 -13
- data/db/migrate/20110204112800_add_host_tags.rb +1 -1
- data/db/migrate/20110527000001_add_api_keys_table.rb +1 -1
- data/db/migrate/20110606000001_add_macros_table.rb +2 -2
- data/db/migrate/20110624000001_add_listeners_table.rb +1 -1
- data/db/migrate/20110630000001_add_nexpose_consoles_table.rb +1 -1
- data/db/migrate/20110717000001_add_profiles_table.rb +1 -1
- data/db/migrate/20130522001343_create_task_creds.rb +1 -1
- data/db/migrate/20130522032517_create_task_hosts.rb +1 -1
- data/db/migrate/20130522041110_create_task_services.rb +1 -1
- data/db/migrate/20130604145732_create_task_sessions.rb +1 -1
- data/db/migrate/20131002004641_create_automatic_exploitation_matches.rb +1 -1
- data/db/migrate/20131002164449_create_automatic_exploitation_match_sets.rb +1 -1
- data/db/migrate/20131008213344_create_automatic_exploitation_runs.rb +1 -1
- data/db/migrate/20131017150735_create_automatic_exploitation_match_results.rb +1 -1
- data/db/migrate/20150219173821_create_module_runs.rb +1 -1
- data/db/migrate/20150317145455_rename_module_indices.rb +29 -0
- data/db/migrate/20150421211719_rename_automatic_exploitation_index.rb +16 -0
- data/lib/mdm/host/operating_system_normalization.rb +1 -1
- data/lib/metasploit_data_models.rb +1 -0
- data/lib/metasploit_data_models/engine.rb +1 -1
- data/lib/metasploit_data_models/version.rb +5 -3
- data/metasploit_data_models.gemspec +11 -8
- data/spec/app/models/mdm/event_spec.rb +17 -11
- data/spec/app/models/mdm/host_spec.rb +2 -2
- data/spec/app/models/mdm/module/action_spec.rb +0 -5
- data/spec/app/models/mdm/module/arch_spec.rb +0 -5
- data/spec/app/models/mdm/module/author_spec.rb +0 -6
- data/spec/app/models/mdm/module/detail_spec.rb +3 -3
- data/spec/app/models/mdm/module/mixin_spec.rb +0 -5
- data/spec/app/models/mdm/module/platform_spec.rb +0 -5
- data/spec/app/models/mdm/module/ref_spec.rb +0 -5
- data/spec/app/models/mdm/module/target_spec.rb +0 -6
- data/spec/app/models/mdm/ref_spec.rb +0 -3
- data/spec/app/models/mdm/service_spec.rb +1 -1
- data/spec/app/models/mdm/web_vuln_spec.rb +3 -3
- data/spec/app/models/mdm/wmap_request_spec.rb +2 -0
- data/spec/app/models/mdm/wmap_target_spec.rb +2 -0
- data/spec/app/models/mdm/workspace_spec.rb +2 -2
- data/spec/app/models/metasploit_data_models/search/operation/port/number_spec.rb +1 -1
- data/spec/dummy/config/application.rb +1 -7
- data/spec/dummy/config/environments/development.rb +2 -13
- data/spec/dummy/config/environments/production.rb +2 -0
- data/spec/dummy/config/environments/test.rb +2 -6
- data/spec/dummy/db/structure.sql +24 -19
- data/spec/dummy/db/structure.sql.from_rails_3 +3403 -0
- data/spec/factories/mdm/module/details.rb +1 -1
- data/spec/lib/ipaddr_spec.rb +31 -0
- data/spec/lib/metasploit_data_models/version_spec.rb +1 -3
- data/spec/support/shared/examples/coerces_inet_column_type_to_string.rb +15 -0
- metadata +63 -28
data/app/models/mdm/note.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# Data gathered or derived from the {#host} or {#service} such as its {#ntype fingerprint}.
|
2
2
|
class Mdm::Note < ActiveRecord::Base
|
3
|
+
|
3
4
|
#
|
4
5
|
# Associations
|
5
6
|
#
|
@@ -84,10 +85,9 @@ class Mdm::Note < ActiveRecord::Base
|
|
84
85
|
# Scopes
|
85
86
|
#
|
86
87
|
|
87
|
-
scope :flagged, where('critical = true AND seen = false')
|
88
|
+
scope :flagged, -> { where('critical = true AND seen = false') }
|
88
89
|
|
89
|
-
|
90
|
-
scope :visible, where(notes[:ntype].not_in(['web.form', 'web.url', 'web.vuln']))
|
90
|
+
scope :visible, -> { where(Mdm::Note[:ntype].not_in(['web.form', 'web.url', 'web.vuln'])) }
|
91
91
|
|
92
92
|
scope :search, lambda { |*args|
|
93
93
|
where(["(data NOT ILIKE 'BAh7%' AND data LIKE ?)" +
|
data/app/models/mdm/ref.rb
CHANGED
data/app/models/mdm/route.rb
CHANGED
data/app/models/mdm/service.rb
CHANGED
@@ -167,7 +167,7 @@ class Mdm::Service < ActiveRecord::Base
|
|
167
167
|
# Scopes
|
168
168
|
#
|
169
169
|
|
170
|
-
scope :inactive, where("services.state != 'open'")
|
170
|
+
scope :inactive, -> { where("services.state != 'open'") }
|
171
171
|
scope :with_state, lambda { |a_state| where("services.state = ?", a_state)}
|
172
172
|
scope :search, lambda { |*args|
|
173
173
|
where([
|
data/app/models/mdm/session.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# A session opened on a {#host} using an {#via_exploit exploit} and controlled through a {#via_payload payload} to
|
2
2
|
# connect back to the local host using meterpreter or a cmd shell.
|
3
3
|
class Mdm::Session < ActiveRecord::Base
|
4
|
+
|
4
5
|
#
|
5
6
|
# Associations
|
6
7
|
#
|
@@ -10,10 +11,10 @@ class Mdm::Session < ActiveRecord::Base
|
|
10
11
|
#
|
11
12
|
# @return [Array<Mdm::Event>]
|
12
13
|
has_many :events,
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
-> { order('created_at') },
|
15
|
+
class_name: 'Mdm::SessionEvent',
|
16
|
+
dependent: :delete_all,
|
17
|
+
inverse_of: :session
|
17
18
|
|
18
19
|
# @!attribute exploit_attempt
|
19
20
|
# Exploit attempt that created this session.
|
@@ -162,9 +163,9 @@ class Mdm::Session < ActiveRecord::Base
|
|
162
163
|
# Scopes
|
163
164
|
#
|
164
165
|
|
165
|
-
scope :alive, where('closed_at IS NULL')
|
166
|
-
scope :dead, where('closed_at IS NOT NULL')
|
167
|
-
scope :upgradeable, where("closed_at IS NULL AND stype = 'shell' and platform ILIKE '%win%'")
|
166
|
+
scope :alive, -> { where('closed_at IS NULL') }
|
167
|
+
scope :dead, -> { where('closed_at IS NOT NULL') }
|
168
|
+
scope :upgradeable, -> { where("closed_at IS NULL AND stype = 'shell' and platform ILIKE '%win%'") }
|
168
169
|
|
169
170
|
#
|
170
171
|
# Serializations
|
data/app/models/mdm/tag.rb
CHANGED
@@ -2,7 +2,7 @@ class Mdm::Tag < ActiveRecord::Base
|
|
2
2
|
include Metasploit::Model::Search
|
3
3
|
|
4
4
|
#
|
5
|
-
#
|
5
|
+
# Associations
|
6
6
|
#
|
7
7
|
|
8
8
|
# @!attribute hosts_tags
|
@@ -48,7 +48,7 @@ class Mdm::Tag < ActiveRecord::Base
|
|
48
48
|
}
|
49
49
|
validates :name,
|
50
50
|
:format => {
|
51
|
-
:with =>
|
51
|
+
:with => /\A[A-Za-z0-9\x2e\x2d_]+\z/, :message => "must be alphanumeric, dots, dashes, or underscores"
|
52
52
|
},
|
53
53
|
:presence => true
|
54
54
|
|
data/app/models/mdm/task.rb
CHANGED
data/app/models/mdm/user.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
class Mdm::User < ActiveRecord::Base
|
2
2
|
extend MetasploitDataModels::SerializedPrefs
|
3
|
-
|
3
|
+
|
4
4
|
#
|
5
|
-
#
|
5
|
+
# Associations
|
6
6
|
#
|
7
7
|
|
8
8
|
has_many :automatic_exploitation_runs,
|
@@ -26,8 +26,7 @@ class Mdm::User < ActiveRecord::Base
|
|
26
26
|
class_name: 'Mdm::Tag',
|
27
27
|
inverse_of: :user
|
28
28
|
|
29
|
-
|
30
|
-
has_and_belongs_to_many :workspaces, :join_table => 'workspace_members', :uniq => true, :class_name => 'Mdm::Workspace'
|
29
|
+
has_and_belongs_to_many :workspaces, -> { uniq }, :join_table => 'workspace_members', :class_name => 'Mdm::Workspace'
|
31
30
|
|
32
31
|
#
|
33
32
|
# Serialziations
|
@@ -39,7 +38,7 @@ class Mdm::User < ActiveRecord::Base
|
|
39
38
|
serialized_prefs_attr_accessor :http_proxy_host, :http_proxy_port, :http_proxy_user, :http_proxy_pass
|
40
39
|
serialized_prefs_attr_accessor :time_zone, :session_key
|
41
40
|
serialized_prefs_attr_accessor :last_login_address # specifically NOT last_login_ip to prevent confusion with AuthLogic magic columns (which dont work for serialized fields)
|
42
|
-
|
41
|
+
|
43
42
|
Metasploit::Concern.run(self)
|
44
43
|
end
|
45
44
|
|
data/app/models/mdm/vuln.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# A vulnerability found on a {#host} or {#service}.
|
2
2
|
class Mdm::Vuln < ActiveRecord::Base
|
3
|
+
|
3
4
|
#
|
4
5
|
# Associations
|
5
6
|
#
|
@@ -61,10 +62,11 @@ class Mdm::Vuln < ActiveRecord::Base
|
|
61
62
|
#
|
62
63
|
# @return [<ActiveRecord::RelationMdm::Note>]
|
63
64
|
has_many :notes,
|
65
|
+
-> { order('notes.created_at') },
|
64
66
|
class_name: 'Mdm::Note',
|
65
67
|
inverse_of: :vuln,
|
66
|
-
dependent: :delete_all
|
67
|
-
|
68
|
+
dependent: :delete_all
|
69
|
+
|
68
70
|
|
69
71
|
#
|
70
72
|
# Through :vuln_refs
|
@@ -104,11 +106,10 @@ class Mdm::Vuln < ActiveRecord::Base
|
|
104
106
|
#
|
105
107
|
# @return [ActiveRecord::Relation<Mdm::Module::Detail>]
|
106
108
|
has_many :module_details,
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
109
|
+
-> { uniq },
|
110
|
+
:class_name => 'Mdm::Module::Detail',
|
111
|
+
:source => :detail,
|
112
|
+
:through => :module_refs
|
112
113
|
#
|
113
114
|
# Attributes
|
114
115
|
#
|
@@ -1,6 +1,7 @@
|
|
1
1
|
class Mdm::VulnDetail < ActiveRecord::Base
|
2
|
+
|
2
3
|
#
|
3
|
-
#
|
4
|
+
# Associations
|
4
5
|
#
|
5
6
|
|
6
7
|
belongs_to :nexpose_console,
|
@@ -11,7 +12,7 @@ class Mdm::VulnDetail < ActiveRecord::Base
|
|
11
12
|
class_name: 'Mdm::Vuln',
|
12
13
|
counter_cache: :vuln_detail_count,
|
13
14
|
inverse_of: :vuln_details
|
14
|
-
|
15
|
+
|
15
16
|
#
|
16
17
|
# Validations
|
17
18
|
#
|
data/app/models/mdm/vuln_ref.rb
CHANGED
data/app/models/mdm/web_form.rb
CHANGED
data/app/models/mdm/web_page.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
class Mdm::WebPage < ActiveRecord::Base
|
2
|
+
|
2
3
|
#
|
3
|
-
#
|
4
|
+
# Associations
|
4
5
|
#
|
5
6
|
|
6
7
|
belongs_to :web_site,
|
@@ -12,7 +13,7 @@ class Mdm::WebPage < ActiveRecord::Base
|
|
12
13
|
#
|
13
14
|
|
14
15
|
serialize :headers, MetasploitDataModels::Base64Serializer.new
|
15
|
-
|
16
|
+
|
16
17
|
Metasploit::Concern.run(self)
|
17
18
|
end
|
18
19
|
|
data/app/models/mdm/web_site.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
class Mdm::WebSite < ActiveRecord::Base
|
2
|
+
|
2
3
|
#
|
3
|
-
#
|
4
|
+
# Associations
|
4
5
|
#
|
5
6
|
|
6
7
|
belongs_to :service,
|
@@ -39,7 +40,7 @@ class Mdm::WebSite < ActiveRecord::Base
|
|
39
40
|
|
40
41
|
def to_url(ignore_vhost=false)
|
41
42
|
proto = self.service.name == "https" ? "https" : "http"
|
42
|
-
host = ignore_vhost ? self.service.host.address : self.vhost
|
43
|
+
host = ignore_vhost ? self.service.host.address.to_s : self.vhost
|
43
44
|
port = self.service.port
|
44
45
|
|
45
46
|
if Rex::Socket.is_ipv6?(host)
|
data/app/models/mdm/web_vuln.rb
CHANGED
@@ -1,3 +1,15 @@
|
|
1
1
|
class Mdm::WmapRequest < ActiveRecord::Base
|
2
2
|
Metasploit::Concern.run(self)
|
3
|
+
|
4
|
+
#
|
5
|
+
# Attributes
|
6
|
+
#
|
7
|
+
|
8
|
+
# @!attribute [rw] address
|
9
|
+
# The IP address for this request. Necessary to avoid coercion to an `IPAddr` object.
|
10
|
+
#
|
11
|
+
# @return [String]
|
12
|
+
def address
|
13
|
+
self[:address].to_s
|
14
|
+
end
|
3
15
|
end
|
@@ -1,3 +1,15 @@
|
|
1
1
|
class Mdm::WmapTarget < ActiveRecord::Base
|
2
2
|
Metasploit::Concern.run(self)
|
3
|
+
|
4
|
+
#
|
5
|
+
# Attributes
|
6
|
+
#
|
7
|
+
|
8
|
+
# @!attribute [rw] address
|
9
|
+
# The IP address for this target. Necessary to avoid coercion to an `IPAddr` object.
|
10
|
+
#
|
11
|
+
# @return [String]
|
12
|
+
def address
|
13
|
+
self[:address].to_s
|
14
|
+
end
|
3
15
|
end
|
data/app/models/mdm/workspace.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
class Mdm::Workspace < ActiveRecord::Base
|
2
|
+
|
2
3
|
#
|
3
4
|
# Callbacks
|
4
5
|
#
|
@@ -29,8 +30,8 @@ class Mdm::Workspace < ActiveRecord::Base
|
|
29
30
|
has_many :listeners, :dependent => :destroy, :class_name => 'Mdm::Listener'
|
30
31
|
has_many :notes, :class_name => 'Mdm::Note'
|
31
32
|
belongs_to :owner, :class_name => 'Mdm::User', :foreign_key => 'owner_id'
|
32
|
-
has_many :tasks, :dependent => :destroy, :class_name => 'Mdm::Task'
|
33
|
-
has_and_belongs_to_many :users, :join_table => 'workspace_members', :
|
33
|
+
has_many :tasks, -> { order('created_at DESC') }, :dependent => :destroy, :class_name => 'Mdm::Task'
|
34
|
+
has_and_belongs_to_many :users, -> { uniq }, :join_table => 'workspace_members', :class_name => 'Mdm::User'
|
34
35
|
|
35
36
|
#
|
36
37
|
# Through :hosts
|
@@ -177,7 +178,7 @@ class Mdm::Workspace < ActiveRecord::Base
|
|
177
178
|
def web_unique_forms(addrs=nil)
|
178
179
|
forms = unique_web_forms
|
179
180
|
if addrs
|
180
|
-
forms.reject!
|
181
|
+
forms.reject!{|f| not addrs.include?( f.web_site.service.host.address.to_s ) }
|
181
182
|
end
|
182
183
|
forms
|
183
184
|
end
|
@@ -1,6 +1,4 @@
|
|
1
1
|
class MetasploitDataModels::AutomaticExploitation::Match < ActiveRecord::Base
|
2
|
-
attr_accessible :match_set_id, :module_fullname
|
3
|
-
|
4
2
|
|
5
3
|
#
|
6
4
|
# Associations
|
@@ -11,7 +9,6 @@ class MetasploitDataModels::AutomaticExploitation::Match < ActiveRecord::Base
|
|
11
9
|
#
|
12
10
|
# @return [Mdm::Vuln, Mdm::Service]
|
13
11
|
belongs_to :matchable, polymorphic: true
|
14
|
-
attr_accessible :matchable
|
15
12
|
|
16
13
|
# @!attribute module_detail
|
17
14
|
# The MSF module that this match connects to
|
@@ -1,5 +1,4 @@
|
|
1
1
|
class MetasploitDataModels::AutomaticExploitation::MatchResult < ActiveRecord::Base
|
2
|
-
attr_accessible :match_id, :run_id, :state
|
3
2
|
|
4
3
|
# Running associated exploit did NOT create a session
|
5
4
|
FAILED = "failed"
|
@@ -36,16 +35,5 @@ class MetasploitDataModels::AutomaticExploitation::MatchResult < ActiveRecord::B
|
|
36
35
|
scope :succeeded, lambda { where(state:"succeeded") }
|
37
36
|
scope :failed, lambda { where(state:"failed") }
|
38
37
|
|
39
|
-
# Runs of {#match} by workspace ID
|
40
|
-
scope :by_workspace, lambda { |workspace_id|
|
41
|
-
joins(
|
42
|
-
MetasploitDataModels::AutomaticExploitation::MatchResult.join_association(:match),
|
43
|
-
MetasploitDataModels::AutomaticExploitation::Match.join_association(:match_set)
|
44
|
-
).where(
|
45
|
-
MetasploitDataModels::AutomaticExploitation::MatchSet[:workspace_id].eq(workspace_id),
|
46
|
-
)
|
47
|
-
}
|
48
|
-
|
49
38
|
Metasploit::Concern.run(self)
|
50
39
|
end
|
51
|
-
|
@@ -4,7 +4,12 @@ class IpFormatValidator < ActiveModel::EachValidator
|
|
4
4
|
def validate_each(object, attribute, value)
|
5
5
|
error_message_block = lambda{ object.errors[attribute] << " must be a valid IPv4 or IPv6 address" }
|
6
6
|
begin
|
7
|
-
|
7
|
+
if value.is_a? IPAddr
|
8
|
+
potential_ip = value.dup
|
9
|
+
else
|
10
|
+
potential_ip = IPAddr.new(value)
|
11
|
+
end
|
12
|
+
|
8
13
|
error_message_block.call unless potential_ip.ipv4? || potential_ip.ipv6?
|
9
14
|
rescue ArgumentError
|
10
15
|
error_message_block.call
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module IPAddrExtensions
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
included do
|
4
|
+
begin
|
5
|
+
remove_method :==
|
6
|
+
rescue NameError => e
|
7
|
+
puts e.message
|
8
|
+
end
|
9
|
+
|
10
|
+
alias_method :spaceship_without_rescue, :<=>
|
11
|
+
alias_method :<=>, :spaceship_with_rescue
|
12
|
+
|
13
|
+
alias_method_chain :include?, :rescue
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def spaceship_with_rescue(other)
|
18
|
+
begin
|
19
|
+
spaceship_without_rescue(other)
|
20
|
+
rescue ArgumentError
|
21
|
+
false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def include_with_rescue?(other)
|
26
|
+
begin
|
27
|
+
include_without_rescue?(other)
|
28
|
+
rescue ArgumentError
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
IPAddr.send(:include, IPAddrExtensions)
|