ronin-db-activerecord 0.1.0.beta1
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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.github/workflows/ruby.yml +31 -0
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/COPYING.txt +165 -0
- data/ChangeLog.md +39 -0
- data/Gemfile +27 -0
- data/README.md +143 -0
- data/Rakefile +72 -0
- data/db/migrate/0001_create_ronin_ip_address_mac_addresses_table.rb +43 -0
- data/db/migrate/0002_create_ronin_vulnerabilities_table.rb +61 -0
- data/db/migrate/0003_create_ronin_url_schemes_table.rb +32 -0
- data/db/migrate/0004_create_ronin_url_query_param_names_table.rb +32 -0
- data/db/migrate/0005_create_ronin_user_names_table.rb +33 -0
- data/db/migrate/0006_create_ronin_software_vendors_table.rb +32 -0
- data/db/migrate/0007_create_ronin_advisories_table.rb +42 -0
- data/db/migrate/0008_create_ronin_host_name_ip_addresses_table.rb +43 -0
- data/db/migrate/0009_create_ronin_host_names_table.rb +34 -0
- data/db/migrate/0010_create_ronin_arches_table.rb +37 -0
- data/db/migrate/0011_create_ronin_email_addresses_table.rb +44 -0
- data/db/migrate/0012_create_ronin_oses_table.rb +36 -0
- data/db/migrate/0013_create_ronin_organizations_table.rb +31 -0
- data/db/migrate/0014_create_ronin_ip_addresses_table.rb +35 -0
- data/db/migrate/0015_create_ronin_os_guesses_table.rb +40 -0
- data/db/migrate/0016_create_ronin_url_query_params_table.rb +42 -0
- data/db/migrate/0017_create_ronin_passwords_table.rb +32 -0
- data/db/migrate/0018_create_ronin_open_ports_table.rb +46 -0
- data/db/migrate/0019_create_ronin_urls_table.rb +50 -0
- data/db/migrate/0020_create_ronin_softwares_table.rb +39 -0
- data/db/migrate/0021_create_ronin_mac_addresses_table.rb +33 -0
- data/db/migrate/0022_create_ronin_countries_table.rb +34 -0
- data/db/migrate/0023_create_ronin_services_table.rb +32 -0
- data/db/migrate/0024_create_ronin_credentials_table.rb +44 -0
- data/db/migrate/0025_create_ronin_ports_table.rb +33 -0
- data/db/migrate/0026_create_ronin_asns_table.rb +44 -0
- data/db/migrate/0027_create_ronin_http_query_param_names_table.rb +32 -0
- data/db/migrate/0028_create_ronin_http_query_params_table.rb +42 -0
- data/db/migrate/0029_create_ronin_http_header_names_table.rb +31 -0
- data/db/migrate/0030_create_ronin_http_request_headers_table.rb +41 -0
- data/db/migrate/0031_create_ronin_http_response_headers_table.rb +41 -0
- data/db/migrate/0032_create_ronin_http_requests_table.rb +41 -0
- data/db/migrate/0033_create_ronin_http_responses_table.rb +36 -0
- data/db/migrate/0034_create_ronin_service_credentials_table.rb +41 -0
- data/db/migrate/0035_create_ronin_web_credentials_table.rb +41 -0
- data/gemspec.yml +28 -0
- data/lib/ronin/db/address.rb +105 -0
- data/lib/ronin/db/advisory.rb +169 -0
- data/lib/ronin/db/arch.rb +160 -0
- data/lib/ronin/db/asn.rb +212 -0
- data/lib/ronin/db/credential.rb +248 -0
- data/lib/ronin/db/email_address.rb +225 -0
- data/lib/ronin/db/host_name.rb +224 -0
- data/lib/ronin/db/host_name_ip_address.rb +65 -0
- data/lib/ronin/db/http_header_name.rb +75 -0
- data/lib/ronin/db/http_query_param.rb +79 -0
- data/lib/ronin/db/http_query_param_name.rb +76 -0
- data/lib/ronin/db/http_request.rb +120 -0
- data/lib/ronin/db/http_request_header.rb +78 -0
- data/lib/ronin/db/http_response.rb +91 -0
- data/lib/ronin/db/http_response_header.rb +78 -0
- data/lib/ronin/db/ip_address.rb +351 -0
- data/lib/ronin/db/ip_address_mac_address.rb +62 -0
- data/lib/ronin/db/mac_address.rb +91 -0
- data/lib/ronin/db/migrations.rb +137 -0
- data/lib/ronin/db/model/has_name.rb +102 -0
- data/lib/ronin/db/model/has_unique_name.rb +82 -0
- data/lib/ronin/db/model/importable.rb +85 -0
- data/lib/ronin/db/model/last_scanned_at.rb +48 -0
- data/lib/ronin/db/model.rb +37 -0
- data/lib/ronin/db/models.rb +108 -0
- data/lib/ronin/db/open_port.rb +148 -0
- data/lib/ronin/db/organization.rb +50 -0
- data/lib/ronin/db/os.rb +183 -0
- data/lib/ronin/db/os_guess.rb +67 -0
- data/lib/ronin/db/password.rb +167 -0
- data/lib/ronin/db/port.rb +123 -0
- data/lib/ronin/db/root.rb +28 -0
- data/lib/ronin/db/schema_migration.rb +34 -0
- data/lib/ronin/db/service.rb +48 -0
- data/lib/ronin/db/service_credential.rb +66 -0
- data/lib/ronin/db/software.rb +85 -0
- data/lib/ronin/db/software_vendor.rb +42 -0
- data/lib/ronin/db/url.rb +497 -0
- data/lib/ronin/db/url_query_param.rb +79 -0
- data/lib/ronin/db/url_query_param_name.rb +76 -0
- data/lib/ronin/db/url_scheme.rb +80 -0
- data/lib/ronin/db/user_name.rb +96 -0
- data/lib/ronin/db/vulnerability.rb +81 -0
- data/lib/ronin/db/web_credential.rb +69 -0
- data/ronin-db-activerecord.gemspec +61 -0
- data/spec/advisory_spec.rb +277 -0
- data/spec/arch_spec.rb +228 -0
- data/spec/asn_spec.rb +504 -0
- data/spec/credential_spec.rb +362 -0
- data/spec/email_address_spec.rb +372 -0
- data/spec/host_name_ip_address_spec.rb +8 -0
- data/spec/host_name_spec.rb +207 -0
- data/spec/http_header_name_spec.rb +25 -0
- data/spec/http_query_param_name_spec.rb +25 -0
- data/spec/http_query_param_spec.rb +104 -0
- data/spec/http_request_header_spec.rb +72 -0
- data/spec/http_request_spec.rb +168 -0
- data/spec/http_response_header_spec.rb +74 -0
- data/spec/http_response_spec.rb +103 -0
- data/spec/ip_address_mac_addresses_spec.rb +8 -0
- data/spec/ip_address_spec.rb +386 -0
- data/spec/mac_address_spec.rb +67 -0
- data/spec/migrations_spec.rb +122 -0
- data/spec/model/has_name_spec.rb +65 -0
- data/spec/model/has_unique_name_spec.rb +61 -0
- data/spec/model/importable_spec.rb +105 -0
- data/spec/models_spec.rb +60 -0
- data/spec/open_port_spec.rb +87 -0
- data/spec/organization_spec.rb +10 -0
- data/spec/os_guess_spec.rb +43 -0
- data/spec/os_spec.rb +114 -0
- data/spec/password_spec.rb +81 -0
- data/spec/port_spec.rb +102 -0
- data/spec/schema_migration_spec.rb +8 -0
- data/spec/service_credential_spec.rb +43 -0
- data/spec/service_spec.rb +39 -0
- data/spec/software_spec.rb +76 -0
- data/spec/software_vendor_spec.rb +33 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/url_query_param_name_spec.rb +25 -0
- data/spec/url_query_param_spec.rb +110 -0
- data/spec/url_scheme_spec.rb +39 -0
- data/spec/url_spec.rb +951 -0
- data/spec/user_name_spec.rb +54 -0
- data/spec/vulnerability_spec.rb +8 -0
- data/spec/web_credential_spec.rb +72 -0
- metadata +266 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
6
|
+
#
|
|
7
|
+
# ronin-db-activerecord is free software: you can redistribute it and/or modify
|
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
# (at your option) any later version.
|
|
11
|
+
#
|
|
12
|
+
# ronin-db-activerecord is distributed in the hope that it will be useful,
|
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
# GNU Lesser General Public License for more details.
|
|
16
|
+
#
|
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
18
|
+
# along with ronin-db-activerecord. If not, see <https://www.gnu.org/licenses/>.
|
|
19
|
+
#
|
|
20
|
+
|
|
21
|
+
require 'ronin/db/address'
|
|
22
|
+
|
|
23
|
+
require 'active_record'
|
|
24
|
+
require 'ipaddr'
|
|
25
|
+
require 'resolv'
|
|
26
|
+
|
|
27
|
+
module Ronin
|
|
28
|
+
module DB
|
|
29
|
+
#
|
|
30
|
+
# Represents IP addresses and their associated {HostName host names}
|
|
31
|
+
# and {MACAddress MAC addresses}.
|
|
32
|
+
#
|
|
33
|
+
class IPAddress < Address
|
|
34
|
+
|
|
35
|
+
# @!attribute [rw] address
|
|
36
|
+
# The IP Address.
|
|
37
|
+
#
|
|
38
|
+
# @return [String]
|
|
39
|
+
attribute :address, :string
|
|
40
|
+
validates :address, presence: true,
|
|
41
|
+
uniqueness: true,
|
|
42
|
+
length: {maximum: 39},
|
|
43
|
+
format: {
|
|
44
|
+
with: /#{Resolv::IPv4::Regex}|#{Resolv::IPv6::Regex}/,
|
|
45
|
+
message: 'Must be a valid IP address'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# @!attribute [rw] hton
|
|
49
|
+
# The IP address, but in network byte-order.
|
|
50
|
+
#
|
|
51
|
+
# @return [String]
|
|
52
|
+
attribute :hton, :binary
|
|
53
|
+
before_save :set_hton
|
|
54
|
+
|
|
55
|
+
# @!attribute [rw] version
|
|
56
|
+
# Type of the address.
|
|
57
|
+
#
|
|
58
|
+
# @return [Integer]
|
|
59
|
+
attribute :version, :integer
|
|
60
|
+
validates :version, inclusion: {in: [4, 6]}
|
|
61
|
+
|
|
62
|
+
# @!attribute [rw] ip_address_mac_addresses
|
|
63
|
+
# The MAC Addresses associations.
|
|
64
|
+
#
|
|
65
|
+
# @return [Array<IPAddressMACAddress>]
|
|
66
|
+
has_many :ip_address_mac_addresses, dependent: :destroy,
|
|
67
|
+
class_name: 'IPAddressMACAddress'
|
|
68
|
+
|
|
69
|
+
# @!attribute [rw] mac_addresses
|
|
70
|
+
# The MAC Addresses associated with the IP Address.
|
|
71
|
+
#
|
|
72
|
+
# @return [Array<MACAddress>]
|
|
73
|
+
has_many :mac_addresses, through: :ip_address_mac_addresses,
|
|
74
|
+
class_name: 'MACAddress'
|
|
75
|
+
|
|
76
|
+
# @!attribute [rw] host_name_ip_addresses
|
|
77
|
+
# The host-names that the IP Address serves.
|
|
78
|
+
#
|
|
79
|
+
# @return [Array<HostNameIPAddress>]
|
|
80
|
+
has_many :host_name_ip_addresses, dependent: :destroy,
|
|
81
|
+
class_name: 'HostNameIPAddress'
|
|
82
|
+
|
|
83
|
+
# @!attribute [rw] host_names
|
|
84
|
+
# The host-names associated with the IP Address.
|
|
85
|
+
#
|
|
86
|
+
# @return [Array<HostName>]
|
|
87
|
+
has_many :host_names, through: :host_name_ip_addresses
|
|
88
|
+
|
|
89
|
+
# @!attribute [rw] open_ports
|
|
90
|
+
# The open ports of the host.
|
|
91
|
+
#
|
|
92
|
+
# @return [Array<OpenPort>]
|
|
93
|
+
has_many :open_ports, dependent: :destroy
|
|
94
|
+
|
|
95
|
+
# @!attribute [rw] ports
|
|
96
|
+
# The ports of the host.
|
|
97
|
+
#
|
|
98
|
+
# @return [Array<Port>]
|
|
99
|
+
has_many :ports, through: :open_ports
|
|
100
|
+
|
|
101
|
+
# @!attribute [rw] os_guesses
|
|
102
|
+
# Any OS guesses against the IP Address.
|
|
103
|
+
#
|
|
104
|
+
# @return [Array<OSGuess>]
|
|
105
|
+
has_many :os_guesses, dependent: :destroy,
|
|
106
|
+
class_name: 'OSGuess'
|
|
107
|
+
|
|
108
|
+
# @!attribute [rw] oses
|
|
109
|
+
# Any OSes that the IP Address might be running
|
|
110
|
+
#
|
|
111
|
+
# @return [Array<OS>]
|
|
112
|
+
has_many :oses, through: :os_guesses,
|
|
113
|
+
class_name: 'OS'
|
|
114
|
+
|
|
115
|
+
#
|
|
116
|
+
# Searches for all IPv4 addresses.
|
|
117
|
+
#
|
|
118
|
+
# @return [Array<IPAddress>]
|
|
119
|
+
# The IPv4 addresses.
|
|
120
|
+
#
|
|
121
|
+
# @api public
|
|
122
|
+
#
|
|
123
|
+
def self.v4
|
|
124
|
+
where(version: 4)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
#
|
|
128
|
+
# Searches for all IPv6 addresses.
|
|
129
|
+
#
|
|
130
|
+
# @return [Array<IPAddress>]
|
|
131
|
+
# The IPv6 addresses.
|
|
132
|
+
#
|
|
133
|
+
# @api public
|
|
134
|
+
#
|
|
135
|
+
def self.v6
|
|
136
|
+
where(version: 6)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
#
|
|
140
|
+
# Queries all IP address that are between the first IP address and last IP
|
|
141
|
+
# address.
|
|
142
|
+
#
|
|
143
|
+
# @param [String] first_ip
|
|
144
|
+
# The first IP of the IP range.
|
|
145
|
+
#
|
|
146
|
+
# @param [String] last_ip
|
|
147
|
+
# The last IP of the IP range.
|
|
148
|
+
#
|
|
149
|
+
# @return [Array<IPAddress>]
|
|
150
|
+
#
|
|
151
|
+
def self.between(first_ip,last_ip)
|
|
152
|
+
first_ip_hton = IPAddr.new(first_ip).hton
|
|
153
|
+
last_ip_hton = IPAddr.new(last_ip).hton
|
|
154
|
+
|
|
155
|
+
hton = arel_table[:hton]
|
|
156
|
+
|
|
157
|
+
where(hton.gteq(first_ip_hton).and(hton.lteq(last_ip_hton)))
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
#
|
|
161
|
+
# Queries all IP addresses that exist in the range of IP addresses.
|
|
162
|
+
#
|
|
163
|
+
# @param [Range, #begin, #end] range
|
|
164
|
+
# The IP range to query.
|
|
165
|
+
#
|
|
166
|
+
# @return [Array<IPAddress>]
|
|
167
|
+
#
|
|
168
|
+
def self.in_range(range)
|
|
169
|
+
between(range.begin,range.end)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
#
|
|
173
|
+
# Searches for all IP addresses associated with specific MAC address(es).
|
|
174
|
+
#
|
|
175
|
+
# @param [Array<String>, String] mac
|
|
176
|
+
# The MAC address(es) to search for.
|
|
177
|
+
#
|
|
178
|
+
# @return [Array<IPAddress>]
|
|
179
|
+
# The matching IP addresses.
|
|
180
|
+
#
|
|
181
|
+
# @api public
|
|
182
|
+
#
|
|
183
|
+
def self.with_mac_address(mac)
|
|
184
|
+
joins(:mac_addresses).where(mac_addresses: {address: mac})
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
#
|
|
188
|
+
# Searches for IP addresses associated with the given host name(s).
|
|
189
|
+
#
|
|
190
|
+
# @param [Array<String>, String] name
|
|
191
|
+
# The host name(s) to search for.
|
|
192
|
+
#
|
|
193
|
+
# @return [Array<IPAddress>]
|
|
194
|
+
# The matching IP addresses.
|
|
195
|
+
#
|
|
196
|
+
# @api public
|
|
197
|
+
#
|
|
198
|
+
def self.with_host_name(name)
|
|
199
|
+
joins(:host_names).where(host_names: {name: name})
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
#
|
|
203
|
+
# Searches for IP addresses with the given open port(s).
|
|
204
|
+
#
|
|
205
|
+
# @param [Array<Integer>, Integer] number
|
|
206
|
+
# The port number(s) to search for.
|
|
207
|
+
#
|
|
208
|
+
# @return [Array<IPAddress>]
|
|
209
|
+
# The matching IP addresses.
|
|
210
|
+
#
|
|
211
|
+
# @api public
|
|
212
|
+
#
|
|
213
|
+
def self.with_port_number(number)
|
|
214
|
+
joins(:ports).where(ports: {number: number})
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
#
|
|
218
|
+
# Initializes the IP address record.
|
|
219
|
+
#
|
|
220
|
+
# @param [Array] arguments
|
|
221
|
+
# Additional attribute arguments.
|
|
222
|
+
#
|
|
223
|
+
# @param [Hash{Symbol => Object}] kwargs
|
|
224
|
+
# Additional attribute values.
|
|
225
|
+
#
|
|
226
|
+
# @note Also assigns a default value to `version` based on the `address`.
|
|
227
|
+
#
|
|
228
|
+
def initialize(*arguments,**kwargs)
|
|
229
|
+
super(*arguments,**kwargs)
|
|
230
|
+
|
|
231
|
+
self.version ||= if ipaddr
|
|
232
|
+
if ipaddr.ipv6? then 6
|
|
233
|
+
else 4
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
#
|
|
239
|
+
# Sets the IP address'es address.
|
|
240
|
+
#
|
|
241
|
+
# @param [String, IPAddr, nil] new_address
|
|
242
|
+
# The new address to use.
|
|
243
|
+
#
|
|
244
|
+
# @return [String, IPAddr, nil]
|
|
245
|
+
# The IP address'es new address.
|
|
246
|
+
#
|
|
247
|
+
def address=(new_address)
|
|
248
|
+
@ipaddr = nil
|
|
249
|
+
super(new_address)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
#
|
|
253
|
+
# Returns an `IPAddr` object for the IP address.
|
|
254
|
+
#
|
|
255
|
+
# @return [IPAddr]
|
|
256
|
+
# The IPAddr object representing either the IPv4 or IPv6 address.
|
|
257
|
+
#
|
|
258
|
+
# @api public
|
|
259
|
+
#
|
|
260
|
+
def ipaddr
|
|
261
|
+
@ipaddr ||= if self.address
|
|
262
|
+
begin
|
|
263
|
+
IPAddr.new(self.address)
|
|
264
|
+
rescue IPAddr::InvalidAddressError
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
#
|
|
270
|
+
# Queries the {ASN} record for the IP address.
|
|
271
|
+
#
|
|
272
|
+
# @return [ASN, nil]
|
|
273
|
+
#
|
|
274
|
+
def asn
|
|
275
|
+
ASN.containing_ip(ipaddr)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
#
|
|
279
|
+
# The MAC Address that was most recently used by the IP Address.
|
|
280
|
+
#
|
|
281
|
+
# @return [MACAddress]
|
|
282
|
+
# The MAC Address that most recently used the IP Address.
|
|
283
|
+
#
|
|
284
|
+
# @api public
|
|
285
|
+
#
|
|
286
|
+
def recent_mac_address
|
|
287
|
+
self.ip_address_mac_addresses.order('created_at DESC').mac_addresses.first
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
#
|
|
291
|
+
# The host-name that was most recently used by the IP Address.
|
|
292
|
+
#
|
|
293
|
+
# @return [HostName]
|
|
294
|
+
# The host-name that most recently used by the IP Address.
|
|
295
|
+
#
|
|
296
|
+
# @api public
|
|
297
|
+
#
|
|
298
|
+
def recent_host_name
|
|
299
|
+
self.host_name_ip_addresses.order('created_at DESC').host_names.first
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
#
|
|
303
|
+
# The Operating System that was most recently guessed for the IP
|
|
304
|
+
# Address.
|
|
305
|
+
#
|
|
306
|
+
# @return [OS]
|
|
307
|
+
# The Operating System that most recently was guessed.
|
|
308
|
+
#
|
|
309
|
+
# @api public
|
|
310
|
+
#
|
|
311
|
+
def recent_os_guess
|
|
312
|
+
self.os_guesses.order('created_at DESC').oses.first
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
alias to_ip ipaddr
|
|
316
|
+
|
|
317
|
+
#
|
|
318
|
+
# Converts the address to an Integer.
|
|
319
|
+
#
|
|
320
|
+
# @return [Integer]
|
|
321
|
+
# The network representation of the IP address.
|
|
322
|
+
#
|
|
323
|
+
# @api public
|
|
324
|
+
#
|
|
325
|
+
def to_i
|
|
326
|
+
ipaddr.to_i
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
private
|
|
330
|
+
|
|
331
|
+
#
|
|
332
|
+
# Sets the `hton` attribute.
|
|
333
|
+
#
|
|
334
|
+
def set_hton
|
|
335
|
+
self.hton = self.ipaddr.hton
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
require 'ronin/db/ip_address_mac_address'
|
|
343
|
+
require 'ronin/db/mac_address'
|
|
344
|
+
require 'ronin/db/host_name_ip_address'
|
|
345
|
+
require 'ronin/db/host_name'
|
|
346
|
+
require 'ronin/db/open_port'
|
|
347
|
+
require 'ronin/db/port'
|
|
348
|
+
require 'ronin/db/host_name'
|
|
349
|
+
require 'ronin/db/os_guess'
|
|
350
|
+
require 'ronin/db/os'
|
|
351
|
+
require 'ronin/db/asn'
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
6
|
+
#
|
|
7
|
+
# ronin-db-activerecord is free software: you can redistribute it and/or modify
|
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
# (at your option) any later version.
|
|
11
|
+
#
|
|
12
|
+
# ronin-db-activerecord is distributed in the hope that it will be useful,
|
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
# GNU Lesser General Public License for more details.
|
|
16
|
+
#
|
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
18
|
+
# along with ronin-db-activerecord. If not, see <https://www.gnu.org/licenses/>.
|
|
19
|
+
#
|
|
20
|
+
|
|
21
|
+
require 'ronin/db/model'
|
|
22
|
+
|
|
23
|
+
require 'active_record'
|
|
24
|
+
|
|
25
|
+
module Ronin
|
|
26
|
+
module DB
|
|
27
|
+
#
|
|
28
|
+
# Associates an {IPAddress} with a {MACAddress}.
|
|
29
|
+
#
|
|
30
|
+
class IPAddressMACAddress < ActiveRecord::Base
|
|
31
|
+
|
|
32
|
+
include Model
|
|
33
|
+
|
|
34
|
+
# @!attribute [rw] id
|
|
35
|
+
# The primary-key of the join model.
|
|
36
|
+
#
|
|
37
|
+
# @return [Integer]
|
|
38
|
+
attribute :id, :integer
|
|
39
|
+
|
|
40
|
+
# @!attribute [rw] ip_address
|
|
41
|
+
# The IP Address.
|
|
42
|
+
#
|
|
43
|
+
# @return [IPAddress]
|
|
44
|
+
belongs_to :ip_address, required: true,
|
|
45
|
+
class_name: 'IPAddress'
|
|
46
|
+
|
|
47
|
+
# @!attribute [rw] mac_address
|
|
48
|
+
# The Mac Address.
|
|
49
|
+
#
|
|
50
|
+
# @return [MACAddress]
|
|
51
|
+
belongs_to :mac_address, required: true,
|
|
52
|
+
class_name: 'MACAddress'
|
|
53
|
+
|
|
54
|
+
# @!attribute [r] created_at
|
|
55
|
+
# Tracks when an IP Address becomes associated with a MAC Address.
|
|
56
|
+
#
|
|
57
|
+
# @return [Time]
|
|
58
|
+
attribute :created_at, :time
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
6
|
+
#
|
|
7
|
+
# ronin-db-activerecord is free software: you can redistribute it and/or modify
|
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
# (at your option) any later version.
|
|
11
|
+
#
|
|
12
|
+
# ronin-db-activerecord is distributed in the hope that it will be useful,
|
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
# GNU Lesser General Public License for more details.
|
|
16
|
+
#
|
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
18
|
+
# along with ronin-db-activerecord. If not, see <https://www.gnu.org/licenses/>.
|
|
19
|
+
#
|
|
20
|
+
|
|
21
|
+
require 'ronin/db/address'
|
|
22
|
+
|
|
23
|
+
require 'active_record'
|
|
24
|
+
require 'strscan'
|
|
25
|
+
|
|
26
|
+
module Ronin
|
|
27
|
+
module DB
|
|
28
|
+
#
|
|
29
|
+
# Represents MAC addresses and their associated {IPAddress IP addresses}.
|
|
30
|
+
#
|
|
31
|
+
class MACAddress < Address
|
|
32
|
+
|
|
33
|
+
# @!attribute [rw] address
|
|
34
|
+
# The MAC address.
|
|
35
|
+
#
|
|
36
|
+
# @return [String]
|
|
37
|
+
attribute :address, :string # length: 17..17,
|
|
38
|
+
validates :address, presence: true,
|
|
39
|
+
uniqueness: true,
|
|
40
|
+
length: {maximum: 17},
|
|
41
|
+
format: {
|
|
42
|
+
with: /[0-9a-fA-F]{2}(?::[0-9a-fA-F]{2}){5}/,
|
|
43
|
+
message: 'Must be a valid MAC address'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# @!attribute [rw] ip_address_mac_addresses
|
|
47
|
+
# The IP Addresses the MAC Address hosts
|
|
48
|
+
#
|
|
49
|
+
# @return [Array<IPAddressMACAddress>]
|
|
50
|
+
has_many :ip_address_mac_addresses, dependent: :destroy,
|
|
51
|
+
class_name: 'IPAddressMACAddress'
|
|
52
|
+
|
|
53
|
+
# @!attribute [rw] ip_addresses
|
|
54
|
+
# The IP Addresses associated with the MAC Address
|
|
55
|
+
#
|
|
56
|
+
# @return [Array<IPAddress>]
|
|
57
|
+
has_many :ip_addresses, through: :ip_address_mac_addresses,
|
|
58
|
+
class_name: 'IPAddress'
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# The IP Address that most recently used the MAC Address.
|
|
62
|
+
#
|
|
63
|
+
# @return [IPAddress]
|
|
64
|
+
# The IP Address that most recently used the MAC Address.
|
|
65
|
+
#
|
|
66
|
+
# @api public
|
|
67
|
+
#
|
|
68
|
+
def recent_ip_address
|
|
69
|
+
self.ip_address_mac_addresses.order('created_at DESC').ip_addresses.first
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
#
|
|
73
|
+
# Converts the MAC address to an Integer.
|
|
74
|
+
#
|
|
75
|
+
# @return [Integer]
|
|
76
|
+
# The network representation of the MAC address.
|
|
77
|
+
#
|
|
78
|
+
# @api public
|
|
79
|
+
#
|
|
80
|
+
def to_i
|
|
81
|
+
self.address.split(':').inject(0) do |bits,char|
|
|
82
|
+
bits = ((bits << 8) | char.hex)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
require 'ronin/db/ip_address_mac_address'
|
|
91
|
+
require 'ronin/db/ip_address'
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
6
|
+
#
|
|
7
|
+
# ronin-db-activerecord is free software: you can redistribute it and/or modify
|
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
# (at your option) any later version.
|
|
11
|
+
#
|
|
12
|
+
# ronin-db-activerecord is distributed in the hope that it will be useful,
|
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
# GNU Lesser General Public License for more details.
|
|
16
|
+
#
|
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
18
|
+
# along with ronin-db-activerecord. If not, see <https://www.gnu.org/licenses/>.
|
|
19
|
+
#
|
|
20
|
+
|
|
21
|
+
require 'ronin/db/schema_migration'
|
|
22
|
+
|
|
23
|
+
require 'active_record'
|
|
24
|
+
require 'active_record/migration'
|
|
25
|
+
|
|
26
|
+
module Ronin
|
|
27
|
+
module DB
|
|
28
|
+
module Migrations
|
|
29
|
+
#
|
|
30
|
+
# The current migration version of the database.
|
|
31
|
+
#
|
|
32
|
+
# @return [Integer]
|
|
33
|
+
#
|
|
34
|
+
def self.current_version
|
|
35
|
+
context.current_version
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
#
|
|
39
|
+
# Determines if the database needs migrating up.
|
|
40
|
+
#
|
|
41
|
+
# @return [Boolean]
|
|
42
|
+
#
|
|
43
|
+
def self.needs_migration?
|
|
44
|
+
context.needs_migration?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
#
|
|
48
|
+
# Migrates the database to the target version.
|
|
49
|
+
#
|
|
50
|
+
# @param [Integer, nil] target_version
|
|
51
|
+
# The desired target version.
|
|
52
|
+
#
|
|
53
|
+
# @api semipublic
|
|
54
|
+
#
|
|
55
|
+
def self.migrate(target_version=nil)
|
|
56
|
+
context.migrate(target_version)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
#
|
|
60
|
+
# Explicitly migrates up the database to the target version.
|
|
61
|
+
#
|
|
62
|
+
# @param [Integer, nil] target_version
|
|
63
|
+
# The desired target version.
|
|
64
|
+
#
|
|
65
|
+
# @api semipublic
|
|
66
|
+
#
|
|
67
|
+
def self.up(target_version=nil,&block)
|
|
68
|
+
context.up(target_version,&block)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#
|
|
72
|
+
# Explicitly migrates down the database to the target version.
|
|
73
|
+
#
|
|
74
|
+
# @param [Integer, nil] target_version
|
|
75
|
+
# The desired target version.
|
|
76
|
+
#
|
|
77
|
+
# @api semipublic
|
|
78
|
+
#
|
|
79
|
+
def self.down(target_version=nil,&block)
|
|
80
|
+
context.down(target_version,&block)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
#
|
|
84
|
+
# Rollbacks the last number of migrations.
|
|
85
|
+
#
|
|
86
|
+
# @param [Integer] steps
|
|
87
|
+
# The number of migrations to rollback.
|
|
88
|
+
#
|
|
89
|
+
# @api semipublic
|
|
90
|
+
#
|
|
91
|
+
def self.rollback(steps=1)
|
|
92
|
+
context.rollback(steps)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
#
|
|
96
|
+
# Applies the next number of migrations.
|
|
97
|
+
#
|
|
98
|
+
# @param [Integer] steps
|
|
99
|
+
# The number of migrations to rollback.
|
|
100
|
+
#
|
|
101
|
+
# @api semipublic
|
|
102
|
+
#
|
|
103
|
+
def self.foreward(steps=1)
|
|
104
|
+
context.foreward(steps)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
# Path to the `db/migrate/` directory in `ronin-db-activerecord`.
|
|
110
|
+
DIR = File.expand_path('../../../db/migrate',__dir__)
|
|
111
|
+
|
|
112
|
+
#
|
|
113
|
+
# Extensions `ActiveRecord::MigrationContext` to load our migrations from
|
|
114
|
+
# the `db/migrate/` directory and update our
|
|
115
|
+
# `ronin_schema_migration` table.
|
|
116
|
+
#
|
|
117
|
+
# @api private
|
|
118
|
+
#
|
|
119
|
+
class MigrationContext < ActiveRecord::MigrationContext
|
|
120
|
+
|
|
121
|
+
def initialize
|
|
122
|
+
super([Ronin::DB::Migrations::DIR],Ronin::DB::SchemaMigration)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
#
|
|
128
|
+
# The migration context.
|
|
129
|
+
#
|
|
130
|
+
# @return [MigrationContext]
|
|
131
|
+
#
|
|
132
|
+
def self.context
|
|
133
|
+
@migrations ||= MigrationContext.new
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|