19 package org.sleuthkit.datamodel;
21 import com.google.common.cache.Cache;
22 import com.google.common.cache.CacheBuilder;
23 import java.sql.PreparedStatement;
24 import java.sql.ResultSet;
25 import java.sql.SQLException;
26 import java.sql.Statement;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Objects;
30 import java.util.Optional;
31 import java.util.logging.Level;
32 import java.util.logging.Logger;
33 import java.util.regex.Pattern;
42 private static final Logger LOGGER = Logger.getLogger(
HostAddressManager.class.getName());
51 private final Cache<Long, Byte> recentHostNameAndIpMappingCache = CacheBuilder.newBuilder().maximumSize(200000).build();
59 private final Cache<String, HostAddress> recentHostAddressCache = CacheBuilder.newBuilder().maximumSize(200000).build();
67 private final Cache<String, Boolean> hostAddressUsageCache = CacheBuilder.newBuilder().maximumSize(200000).build();
92 try (CaseDbConnection connection = this.db.getConnection()) {
112 HostAddress hostAddress = recentHostAddressCache.getIfPresent(createRecentHostAddressKey(type, address));
113 if (Objects.nonNull(hostAddress)) {
114 return Optional.of(hostAddress);
117 if (type.equals(HostAddress.HostAddressType.DNS_AUTO)) {
118 addressType = getDNSType(address);
120 String queryString =
"SELECT * FROM tsk_host_addresses"
121 +
" WHERE address = ? AND address_type = ?";
123 PreparedStatement query = connection.getPreparedStatement(queryString, Statement.NO_GENERATED_KEYS);
124 query.clearParameters();
125 query.setString(1, address.toLowerCase());
126 query.setInt(2, addressType.getId());
127 try (ResultSet rs = query.executeQuery()) {
129 return Optional.empty();
131 HostAddress
newHostAddress =
new HostAddress(db, rs.getLong(
"id"), HostAddressType.fromID(rs.getInt(
"address_type")), address);
132 recentHostAddressCache.put(createRecentHostAddressKey(newHostAddress.getAddressType(), address), newHostAddress);
133 return Optional.of(newHostAddress);
136 }
catch (SQLException ex) {
137 throw new TskCoreException(String.format(
"Error getting host address with type = %s and address = %s", type.getName(), address), ex);
149 private String createRecentHostAddressKey(HostAddressType type, String address) {
150 return createRecentHostAddressKey(type.getId(), address);
161 private String createRecentHostAddressKey(
int typeId, String address) {
162 return typeId +
"#" + address.toLowerCase();
178 CaseDbConnection connection = this.db.getConnection();
185 if (hostAddress.isPresent()) {
186 return hostAddress.get();
209 addressType = getDNSType(address);
215 long parentObjId = 0;
216 int objTypeId = TskData.ObjectType.HOST_ADDRESS.getObjectType();
218 long objId = db.addObject(parentObjId, objTypeId, connection);
220 String hostAddressInsertSQL =
"INSERT INTO tsk_host_addresses(id, address_type, address) VALUES (?, ?, ?)";
221 PreparedStatement preparedStatement = connection.getPreparedStatement(hostAddressInsertSQL, Statement.RETURN_GENERATED_KEYS);
223 preparedStatement.clearParameters();
224 preparedStatement.setLong(1, objId);
225 preparedStatement.setInt(2, addressType.getId());
226 preparedStatement.setString(3, address.toLowerCase());
228 connection.executeUpdate(preparedStatement);
229 HostAddress hostAddress =
new HostAddress(db, objId, addressType, address);
230 recentHostAddressCache.put(createRecentHostAddressKey(addressType, address), hostAddress);
232 }
catch (SQLException ex) {
233 throw new TskCoreException(String.format(
"Error adding host address of type = %s, with address = %s", type.getName(), address), ex);
249 String insertSQL = db.getInsertOrIgnoreSQL(
" INTO tsk_host_address_map(host_id, addr_obj_id, source_obj_id, time) "
250 +
" VALUES(?, ?, ?, ?) ");
253 try (CaseDbConnection connection = this.db.getConnection()) {
255 PreparedStatement preparedStatement = connection.getPreparedStatement(insertSQL, Statement.NO_GENERATED_KEYS);
257 preparedStatement.clearParameters();
258 preparedStatement.setLong(1, host.getHostId());
259 preparedStatement.setLong(2, hostAddress.getId());
260 preparedStatement.setLong(3, source.getId());
262 preparedStatement.setLong(4, time);
264 preparedStatement.setNull(4, java.sql.Types.BIGINT);
267 connection.executeUpdate(preparedStatement);
268 }
catch (SQLException ex) {
269 LOGGER.log(Level.SEVERE, null, ex);
270 throw new TskCoreException(String.format(
"Error adding host address mapping for host name = %s, with address = %s", host.getName(), hostAddress.getAddress()), ex);
285 String queryString =
"SELECT addr_obj_id FROM tsk_host_address_map "
286 +
" WHERE host_id = " + host.getHostId();
288 List<HostAddress> addresses =
new ArrayList<>();
291 try (CaseDbConnection connection = this.db.getConnection();
292 Statement s = connection.createStatement();
293 ResultSet rs = connection.executeQuery(s, queryString)) {
300 }
catch (SQLException ex) {
301 throw new TskCoreException(String.format(
"Error getting host addresses for host " + host.getName()), ex);
318 try (CaseDbConnection connection = this.db.getConnection()) {
336 String queryString =
"SELECT * FROM tsk_host_addresses"
337 +
" WHERE id = " + id;
339 try (Statement s = connection.createStatement();
340 ResultSet rs = connection.executeQuery(s, queryString)) {
343 throw new TskCoreException(String.format(
"No address found with id = %d",
id));
345 long objId = rs.getLong(
"id");
346 int type = rs.getInt(
"address_type");
347 String address = rs.getString(
"address");
348 HostAddress hostAddress =
new HostAddress(db, objId, HostAddress.HostAddressType.fromID(type), address);
349 recentHostAddressCache.put(createRecentHostAddressKey(type, address), hostAddress);
352 }
catch (SQLException ex) {
353 throw new TskCoreException(String.format(
"Error getting host address with id = %d",
id), ex);
370 try (CaseDbConnection connection = this.db.getConnection()) {
372 }
catch (SQLException ex) {
373 throw new TskCoreException(String.format(
"Error adding host DNS address mapping for DNS name = %s, and IP address = %s", dnsNameAddress.getAddress(), ipAddress.getAddress()), ex);
394 if (Objects.isNull(caseDbTransaction)) {
395 throw new TskCoreException(String.format(
"Error adding host DNS address mapping for DNS name = %s, and IP address = %s, null caseDbTransaction passed to addHostNameAndIpMapping", dnsNameAddress.
getAddress(), ipAddress.
getAddress()));
399 }
catch (SQLException ex) {
400 throw new TskCoreException(String.format(
"Error adding host DNS address mapping for DNS name = %s, and IP address = %s", dnsNameAddress.
getAddress(), ipAddress.
getAddress()), ex);
418 throw new TskCoreException(
"IllegalArguments passed to addHostNameAndIpMapping: A host name address is expected.");
420 if ((ipAddress.getAddressType() != HostAddress.HostAddressType.IPV4) && (ipAddress.getAddressType() != HostAddress.HostAddressType.IPV6)) {
421 throw new TskCoreException(
"IllegalArguments passed to addHostNameAndIpMapping:An IPv4/IPv6 address is expected.");
423 if (Objects.isNull(connection)) {
424 throw new TskCoreException(
"IllegalArguments passed to addHostNameAndIpMapping: null connection passed to addHostNameAndIpMapping");
427 String insertSQL = db.getInsertOrIgnoreSQL(
" INTO tsk_host_address_dns_ip_map(dns_address_id, ip_address_id, source_obj_id, time) "
428 +
" VALUES(?, ?, ?, ?) ");
430 PreparedStatement preparedStatement = connection.getPreparedStatement(insertSQL, Statement.NO_GENERATED_KEYS);
432 preparedStatement.clearParameters();
433 preparedStatement.setLong(1, dnsNameAddress.getId());
434 preparedStatement.setLong(2, ipAddress.getId());
435 preparedStatement.setLong(3, source.getId());
437 preparedStatement.setLong(4, time);
439 preparedStatement.setNull(4, java.sql.Types.BIGINT);
441 connection.executeUpdate(preparedStatement);
442 recentHostNameAndIpMappingCache.put(ipAddress.getId(),
new Byte((byte) 1));
443 recentHostNameAndIpMappingCache.put(dnsNameAddress.getId(),
new Byte((byte) 1));
460 Byte isPresent = recentHostNameAndIpMappingCache.getIfPresent(addressObjectId);
462 if (Objects.nonNull(isPresent)) {
466 String queryString =
"SELECT count(*) as mappingCount FROM tsk_host_address_dns_ip_map WHERE ip_address_id = ? OR dns_address_id = ? ";
469 try (CaseDbConnection connection = this.db.getConnection();
470 PreparedStatement ps = connection.getPreparedStatement(queryString, Statement.NO_GENERATED_KEYS);) {
471 ps.clearParameters();
472 ps.setLong(1, addressObjectId);
473 ps.setLong(2, addressObjectId);
474 try (ResultSet rs = ps.executeQuery()) {
478 boolean status = rs.getLong(
"mappingCount") > 0;
480 recentHostNameAndIpMappingCache.put(addressObjectId,
new Byte((byte) 1));
485 }
catch (SQLException ex) {
486 throw new TskCoreException(
"Error looking up host address / Ip mapping for address = " + addressObjectId, ex);
507 HostAddress hostAddress = recentHostAddressCache.getIfPresent(createRecentHostAddressKey(type, address));
508 if (Objects.nonNull(hostAddress)) {
509 return Optional.of(hostAddress.
getId());
514 addressType = getDNSType(address);
517 String queryString =
"SELECT id, address_type, address FROM tsk_host_addresses"
518 +
" WHERE address = ? AND address_type = ?";
521 try (CaseDbConnection connection = this.db.getConnection();
522 PreparedStatement query = connection.getPreparedStatement(queryString, Statement.NO_GENERATED_KEYS);) {
523 query.clearParameters();
524 query.setString(1, address.toLowerCase());
525 query.setInt(2, addressType.getId());
526 try (ResultSet rs = query.executeQuery()) {
528 return Optional.empty();
530 long objId = rs.getLong(
"id");
531 int addrType = rs.getInt(
"address_type");
532 String addr = rs.getString(
"address");
534 recentHostAddressCache.put(createRecentHostAddressKey(addrType, address), hostAddr);
535 return Optional.of(objId);
538 }
catch (SQLException ex) {
539 throw new TskCoreException(String.format(
"Error getting host address with type = %s and address = %s", type.getName(), address), ex);
555 String queryString =
"SELECT ip_address_id FROM tsk_host_address_dns_ip_map as map "
556 +
" JOIN tsk_host_addresses as addresses "
557 +
" ON map.dns_address_id = addresses.id "
559 +
" AND addresses.address = ?";
562 try (CaseDbConnection connection = this.db.getConnection()) {
563 List<HostAddress> IpAddresses =
new ArrayList<>();
564 PreparedStatement query = connection.getPreparedStatement(queryString, Statement.NO_GENERATED_KEYS);
565 query.clearParameters();
566 query.setString(1, hostname.toLowerCase());
567 try (ResultSet rs = query.executeQuery()) {
569 long ipAddressObjId = rs.getLong(
"ip_address_id");
571 recentHostNameAndIpMappingCache.put(ipAddressObjId,
new Byte((byte) 1));
575 }
catch (SQLException ex) {
576 throw new TskCoreException(String.format(
"Error getting host addresses for host name: " + hostname), ex);
591 List<HostAddress> getHostNameByIp(String ipAddress)
throws TskCoreException {
592 String queryString =
"SELECT dns_address_id FROM tsk_host_address_dns_ip_map as map "
593 +
" JOIN tsk_host_addresses as addresses "
594 +
" ON map.ip_address_id = addresses.id "
597 +
" AND addresses.address = ?";
600 try (CaseDbConnection connection = this.db.getConnection()) {
601 List<HostAddress> dnsNames =
new ArrayList<>();
602 PreparedStatement query = connection.getPreparedStatement(queryString, Statement.NO_GENERATED_KEYS);
603 query.clearParameters();
604 query.setString(1, ipAddress.toLowerCase());
605 try (ResultSet rs = query.executeQuery()) {
607 long dnsAddressId = rs.getLong(
"dns_address_id");
609 recentHostNameAndIpMappingCache.put(dnsAddressId,
new Byte((byte) 1));
613 }
catch (SQLException ex) {
614 throw new TskCoreException(String.format(
"Error getting host addresses for IP address: " + ipAddress), ex);
628 String key = content.getDataSource().getId() +
"#" + hostAddress.getId() +
"#" + content.getId();
629 Boolean cachedValue = hostAddressUsageCache.getIfPresent(key);
630 if (null != cachedValue) {
634 final String insertSQL = db.getInsertOrIgnoreSQL(
" INTO tsk_host_address_usage(addr_obj_id, obj_id, data_source_obj_id) "
635 +
" VALUES(" + hostAddress.getId() +
", " + content.getId() +
", " + content.getDataSource().getId() +
") ");
638 try (CaseDbConnection connection = this.db.getConnection();
639 Statement s = connection.createStatement()) {
640 connection.executeUpdate(s, insertSQL);
641 hostAddressUsageCache.put(key,
true);
642 }
catch (SQLException ex) {
643 throw new TskCoreException(String.format(
"Error associating host address %s with artifact with id %d", hostAddress.getAddress(), content.getId()), ex);
649 private final String ADDRESS_USAGE_QUERY =
"SELECT addresses.id as id, addresses.address_type as address_type, addresses.address as address "
650 +
" FROM tsk_host_address_usage as usage "
651 +
" JOIN tsk_host_addresses as addresses "
652 +
" ON usage.addr_obj_id = addresses.id ";
664 String queryString = ADDRESS_USAGE_QUERY
665 +
" WHERE usage.obj_id = " + content.getId();
667 return getHostAddressesUsed(queryString);
680 String queryString = ADDRESS_USAGE_QUERY
681 +
" WHERE usage.data_source_obj_id = " + dataSource.getId();
683 return getHostAddressesUsed(queryString);
695 private List<HostAddress> getHostAddressesUsed(String addressesUsedSQL)
throws TskCoreException {
697 List<HostAddress> addressesUsed =
new ArrayList<>();
700 try (CaseDbConnection connection = this.db.getConnection();
701 Statement s = connection.createStatement();
702 ResultSet rs = connection.executeQuery(s, addressesUsedSQL)) {
707 return addressesUsed;
708 }
catch (SQLException ex) {
709 throw new TskCoreException(String.format(
"Error getting host addresses used with query string = %s", addressesUsedSQL), ex);
722 private HostAddress.HostAddressType getDNSType(String address) {
723 if (isIPv4(address)) {
724 return HostAddress.HostAddressType.IPV4;
725 }
else if (isIPv6(address)) {
726 return HostAddress.HostAddressType.IPV6;
728 return HostAddress.HostAddressType.HOSTNAME;
732 private static final Pattern IPV4_PATTERN =
733 Pattern.compile(
"^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\\.(?!$)|$)){4}$");
741 private static boolean isIPv4(String ipAddress) {
742 if (ipAddress != null) {
743 return IPV4_PATTERN.matcher(ipAddress).matches();
749 private static final Pattern IPV6_STD_PATTERN =
750 Pattern.compile(
"^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");
751 private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
752 Pattern.compile(
"^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");
755 private static boolean isIPv6StdAddress(
final String input) {
756 return IPV6_STD_PATTERN.matcher(input).matches();
758 private static boolean isIPv6HexCompressedAddress(
final String input) {
759 return IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
769 private static boolean isIPv6(String ipAddress) {
771 if (ipAddress != null) {
772 return isIPv6StdAddress(ipAddress) || isIPv6HexCompressedAddress(ipAddress);
List< HostAddress > getHostAddressesUsedOnDataSource(Content dataSource)
Optional< HostAddress > getHostAddress(HostAddress.HostAddressType type, String address)
List< HostAddress > getHostAddressesUsedByContent(Content content)
void addHostNameAndIpMapping(HostAddress dnsNameAddress, HostAddress ipAddress, Long time, Content source, final SleuthkitCase.CaseDbTransaction caseDbTransaction)
void addUsage(Content content, HostAddress hostAddress)
static HostAddressType fromID(int typeId)
Optional< Long > hostAddressExists(HostAddress.HostAddressType type, String address)
void releaseSingleUserCaseReadLock()
HostAddress newHostAddress(HostAddress.HostAddressType type, String address)
void acquireSingleUserCaseWriteLock()
void releaseSingleUserCaseWriteLock()
List< HostAddress > getIpAddress(String hostname)
void assignHostToAddress(Host host, HostAddress hostAddress, Long time, Content source)
HostAddress getHostAddress(long id)
boolean hostNameAndIpMappingExists(long addressObjectId)
void acquireSingleUserCaseReadLock()
void addHostNameAndIpMapping(HostAddress dnsNameAddress, HostAddress ipAddress, Long time, Content source)