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 normalizedAddress = getNormalizedAddress(address);
121 String queryString =
"SELECT * FROM tsk_host_addresses"
122 +
" WHERE address = ? AND address_type = ?";
124 PreparedStatement query = connection.getPreparedStatement(queryString, Statement.NO_GENERATED_KEYS);
125 query.clearParameters();
126 query.setString(1, normalizedAddress.toLowerCase());
127 query.setInt(2, addressType.getId());
128 try (ResultSet rs = query.executeQuery()) {
130 return Optional.empty();
132 HostAddress
newHostAddress =
new HostAddress(db, rs.getLong(
"id"), HostAddressType.fromID(rs.getInt(
"address_type")), rs.getString(
"address"));
133 recentHostAddressCache.put(createRecentHostAddressKey(newHostAddress.getAddressType(), normalizedAddress), newHostAddress);
134 return Optional.of(newHostAddress);
137 }
catch (SQLException ex) {
138 throw new TskCoreException(String.format(
"Error getting host address with type = %s and address = %s", type.getName(), address), ex);
150 private String createRecentHostAddressKey(HostAddressType type, String address) {
151 return createRecentHostAddressKey(type.getId(), address);
162 private String createRecentHostAddressKey(
int typeId, String address) {
163 return typeId +
"#" + address.toLowerCase();
179 CaseDbConnection connection = this.db.getConnection();
186 if (hostAddress.isPresent()) {
187 return hostAddress.get();
210 addressType = getDNSType(address);
213 String normalizedAddress = getNormalizedAddress(address);
217 long parentObjId = 0;
218 int objTypeId = TskData.ObjectType.HOST_ADDRESS.getObjectType();
220 long objId = db.addObject(parentObjId, objTypeId, connection);
222 String hostAddressInsertSQL =
"INSERT INTO tsk_host_addresses(id, address_type, address) VALUES (?, ?, ?)";
223 PreparedStatement preparedStatement = connection.getPreparedStatement(hostAddressInsertSQL, Statement.RETURN_GENERATED_KEYS);
225 preparedStatement.clearParameters();
226 preparedStatement.setLong(1, objId);
227 preparedStatement.setInt(2, addressType.getId());
228 preparedStatement.setString(3, normalizedAddress.toLowerCase());
230 connection.executeUpdate(preparedStatement);
231 HostAddress hostAddress =
new HostAddress(db, objId, addressType, normalizedAddress);
232 recentHostAddressCache.put(createRecentHostAddressKey(addressType, normalizedAddress), hostAddress);
234 }
catch (SQLException ex) {
235 throw new TskCoreException(String.format(
"Error adding host address of type = %s, with address = %s", type.getName(), address), ex);
251 String insertSQL = db.getInsertOrIgnoreSQL(
" INTO tsk_host_address_map(host_id, addr_obj_id, source_obj_id, time) "
252 +
" VALUES(?, ?, ?, ?) ");
255 try (CaseDbConnection connection = this.db.getConnection()) {
257 PreparedStatement preparedStatement = connection.getPreparedStatement(insertSQL, Statement.NO_GENERATED_KEYS);
259 preparedStatement.clearParameters();
260 preparedStatement.setLong(1, host.getHostId());
261 preparedStatement.setLong(2, hostAddress.getId());
262 preparedStatement.setLong(3, source.getId());
264 preparedStatement.setLong(4, time);
266 preparedStatement.setNull(4, java.sql.Types.BIGINT);
269 connection.executeUpdate(preparedStatement);
270 }
catch (SQLException ex) {
271 LOGGER.log(Level.SEVERE, null, ex);
272 throw new TskCoreException(String.format(
"Error adding host address mapping for host name = %s, with address = %s", host.getName(), hostAddress.getAddress()), ex);
287 String queryString =
"SELECT addr_obj_id FROM tsk_host_address_map "
288 +
" WHERE host_id = " + host.getHostId();
290 List<HostAddress> addresses =
new ArrayList<>();
293 try (CaseDbConnection connection = this.db.getConnection();
294 Statement s = connection.createStatement();
295 ResultSet rs = connection.executeQuery(s, queryString)) {
302 }
catch (SQLException ex) {
303 throw new TskCoreException(String.format(
"Error getting host addresses for host " + host.getName()), ex);
320 try (CaseDbConnection connection = this.db.getConnection()) {
338 String queryString =
"SELECT * FROM tsk_host_addresses"
339 +
" WHERE id = " + id;
341 try (Statement s = connection.createStatement();
342 ResultSet rs = connection.executeQuery(s, queryString)) {
345 throw new TskCoreException(String.format(
"No address found with id = %d",
id));
347 long objId = rs.getLong(
"id");
348 int type = rs.getInt(
"address_type");
349 String address = rs.getString(
"address");
350 HostAddress hostAddress =
new HostAddress(db, objId, HostAddress.HostAddressType.fromID(type), address);
351 recentHostAddressCache.put(createRecentHostAddressKey(type, address), hostAddress);
354 }
catch (SQLException ex) {
355 throw new TskCoreException(String.format(
"Error getting host address with id = %d",
id), ex);
372 try (CaseDbConnection connection = this.db.getConnection()) {
374 }
catch (SQLException ex) {
375 throw new TskCoreException(String.format(
"Error adding host DNS address mapping for DNS name = %s, and IP address = %s", dnsNameAddress.getAddress(), ipAddress.getAddress()), ex);
396 if (Objects.isNull(caseDbTransaction)) {
397 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()));
401 }
catch (SQLException ex) {
402 throw new TskCoreException(String.format(
"Error adding host DNS address mapping for DNS name = %s, and IP address = %s", dnsNameAddress.
getAddress(), ipAddress.
getAddress()), ex);
420 throw new TskCoreException(
"IllegalArguments passed to addHostNameAndIpMapping: A host name address is expected.");
422 if ((ipAddress.getAddressType() != HostAddress.HostAddressType.IPV4) && (ipAddress.getAddressType() != HostAddress.HostAddressType.IPV6)) {
423 throw new TskCoreException(
"IllegalArguments passed to addHostNameAndIpMapping:An IPv4/IPv6 address is expected.");
425 if (Objects.isNull(connection)) {
426 throw new TskCoreException(
"IllegalArguments passed to addHostNameAndIpMapping: null connection passed to addHostNameAndIpMapping");
429 String insertSQL = db.getInsertOrIgnoreSQL(
" INTO tsk_host_address_dns_ip_map(dns_address_id, ip_address_id, source_obj_id, time) "
430 +
" VALUES(?, ?, ?, ?) ");
432 PreparedStatement preparedStatement = connection.getPreparedStatement(insertSQL, Statement.NO_GENERATED_KEYS);
434 preparedStatement.clearParameters();
435 preparedStatement.setLong(1, dnsNameAddress.getId());
436 preparedStatement.setLong(2, ipAddress.getId());
437 preparedStatement.setLong(3, source.getId());
439 preparedStatement.setLong(4, time);
441 preparedStatement.setNull(4, java.sql.Types.BIGINT);
443 connection.executeUpdate(preparedStatement);
444 recentHostNameAndIpMappingCache.put(ipAddress.getId(),
new Byte((byte) 1));
445 recentHostNameAndIpMappingCache.put(dnsNameAddress.getId(),
new Byte((byte) 1));
462 Byte isPresent = recentHostNameAndIpMappingCache.getIfPresent(addressObjectId);
464 if (Objects.nonNull(isPresent)) {
468 String queryString =
"SELECT count(*) as mappingCount FROM tsk_host_address_dns_ip_map WHERE ip_address_id = ? OR dns_address_id = ? ";
471 try (CaseDbConnection connection = this.db.getConnection();
472 PreparedStatement ps = connection.getPreparedStatement(queryString, Statement.NO_GENERATED_KEYS);) {
473 ps.clearParameters();
474 ps.setLong(1, addressObjectId);
475 ps.setLong(2, addressObjectId);
476 try (ResultSet rs = ps.executeQuery()) {
480 boolean status = rs.getLong(
"mappingCount") > 0;
482 recentHostNameAndIpMappingCache.put(addressObjectId,
new Byte((byte) 1));
487 }
catch (SQLException ex) {
488 throw new TskCoreException(
"Error looking up host address / Ip mapping for address = " + addressObjectId, ex);
509 HostAddress hostAddress = recentHostAddressCache.getIfPresent(createRecentHostAddressKey(type, address));
510 if (Objects.nonNull(hostAddress)) {
511 return Optional.of(hostAddress.
getId());
516 addressType = getDNSType(address);
518 String normalizedAddress = getNormalizedAddress(address);
520 String queryString =
"SELECT id, address_type, address FROM tsk_host_addresses"
521 +
" WHERE address = ? AND address_type = ?";
524 try (CaseDbConnection connection = this.db.getConnection();
525 PreparedStatement query = connection.getPreparedStatement(queryString, Statement.NO_GENERATED_KEYS);) {
526 query.clearParameters();
527 query.setString(1, normalizedAddress.toLowerCase());
528 query.setInt(2, addressType.getId());
529 try (ResultSet rs = query.executeQuery()) {
531 return Optional.empty();
533 long objId = rs.getLong(
"id");
534 int addrType = rs.getInt(
"address_type");
535 String addr = rs.getString(
"address");
537 recentHostAddressCache.put(createRecentHostAddressKey(addrType, normalizedAddress), hostAddr);
538 return Optional.of(objId);
541 }
catch (SQLException ex) {
542 throw new TskCoreException(String.format(
"Error getting host address with type = %s and address = %s", type.getName(), address), ex);
558 String queryString =
"SELECT ip_address_id FROM tsk_host_address_dns_ip_map as map "
559 +
" JOIN tsk_host_addresses as addresses "
560 +
" ON map.dns_address_id = addresses.id "
562 +
" AND addresses.address = ?";
565 try (CaseDbConnection connection = this.db.getConnection()) {
566 List<HostAddress> IpAddresses =
new ArrayList<>();
567 PreparedStatement query = connection.getPreparedStatement(queryString, Statement.NO_GENERATED_KEYS);
568 query.clearParameters();
569 query.setString(1, hostname.toLowerCase());
570 try (ResultSet rs = query.executeQuery()) {
572 long ipAddressObjId = rs.getLong(
"ip_address_id");
574 recentHostNameAndIpMappingCache.put(ipAddressObjId,
new Byte((byte) 1));
578 }
catch (SQLException ex) {
579 throw new TskCoreException(String.format(
"Error getting host addresses for host name: " + hostname), ex);
594 List<HostAddress> getHostNameByIp(String ipAddress)
throws TskCoreException {
595 String queryString =
"SELECT dns_address_id FROM tsk_host_address_dns_ip_map as map "
596 +
" JOIN tsk_host_addresses as addresses "
597 +
" ON map.ip_address_id = addresses.id "
600 +
" AND addresses.address = ?";
603 try (CaseDbConnection connection = this.db.getConnection()) {
604 List<HostAddress> dnsNames =
new ArrayList<>();
605 PreparedStatement query = connection.getPreparedStatement(queryString, Statement.NO_GENERATED_KEYS);
606 query.clearParameters();
607 query.setString(1, ipAddress.toLowerCase());
608 try (ResultSet rs = query.executeQuery()) {
610 long dnsAddressId = rs.getLong(
"dns_address_id");
612 recentHostNameAndIpMappingCache.put(dnsAddressId,
new Byte((byte) 1));
616 }
catch (SQLException ex) {
617 throw new TskCoreException(String.format(
"Error getting host addresses for IP address: " + ipAddress), ex);
631 String key = content.getDataSource().getId() +
"#" + hostAddress.getId() +
"#" + content.getId();
632 Boolean cachedValue = hostAddressUsageCache.getIfPresent(key);
633 if (null != cachedValue) {
637 final String insertSQL = db.getInsertOrIgnoreSQL(
" INTO tsk_host_address_usage(addr_obj_id, obj_id, data_source_obj_id) "
638 +
" VALUES(" + hostAddress.getId() +
", " + content.getId() +
", " + content.getDataSource().getId() +
") ");
641 try (CaseDbConnection connection = this.db.getConnection();
642 Statement s = connection.createStatement()) {
643 connection.executeUpdate(s, insertSQL);
644 hostAddressUsageCache.put(key,
true);
645 }
catch (SQLException ex) {
646 throw new TskCoreException(String.format(
"Error associating host address %s with artifact with id %d", hostAddress.getAddress(), content.getId()), ex);
652 private final String ADDRESS_USAGE_QUERY =
"SELECT addresses.id as id, addresses.address_type as address_type, addresses.address as address "
653 +
" FROM tsk_host_address_usage as usage "
654 +
" JOIN tsk_host_addresses as addresses "
655 +
" ON usage.addr_obj_id = addresses.id ";
667 String queryString = ADDRESS_USAGE_QUERY
668 +
" WHERE usage.obj_id = " + content.getId();
670 return getHostAddressesUsed(queryString);
683 String queryString = ADDRESS_USAGE_QUERY
684 +
" WHERE usage.data_source_obj_id = " + dataSource.getId();
686 return getHostAddressesUsed(queryString);
698 private List<HostAddress> getHostAddressesUsed(String addressesUsedSQL)
throws TskCoreException {
700 List<HostAddress> addressesUsed =
new ArrayList<>();
703 try (CaseDbConnection connection = this.db.getConnection();
704 Statement s = connection.createStatement();
705 ResultSet rs = connection.executeQuery(s, addressesUsedSQL)) {
710 return addressesUsed;
711 }
catch (SQLException ex) {
712 throw new TskCoreException(String.format(
"Error getting host addresses used with query string = %s", addressesUsedSQL), ex);
725 private HostAddress.HostAddressType getDNSType(String address) {
726 if (isIPv4(address)) {
727 return HostAddress.HostAddressType.IPV4;
728 }
else if (isIPv6(address)) {
729 return HostAddress.HostAddressType.IPV6;
731 return HostAddress.HostAddressType.HOSTNAME;
735 private static final Pattern IPV4_PATTERN =
736 Pattern.compile(
"^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\\.(?!$)|$)){4}$");
744 private static boolean isIPv4(String ipAddress) {
745 if (ipAddress != null) {
746 return IPV4_PATTERN.matcher(ipAddress).matches();
757 private static final Pattern IPV6_STD_PATTERN =
758 Pattern.compile(
"^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}(%.+)?$");
759 private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
760 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})*)?)(%.+)?$");
763 private static boolean isIPv6StdAddress(
final String input) {
764 return IPV6_STD_PATTERN.matcher(input).matches();
766 private static boolean isIPv6HexCompressedAddress(
final String input) {
767 return IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
777 private static boolean isIPv6(String ipAddress) {
779 if (ipAddress != null) {
780 return isIPv6StdAddress(ipAddress) || isIPv6HexCompressedAddress(ipAddress);
796 private static String getNormalizedAddress(String address) {
798 String normalizedAddress = address;
800 if (isIPv6(address)) {
801 normalizedAddress = getNormalizedIPV6Address(address);
804 return normalizedAddress;
818 private static String getNormalizedIPV6Address(String address) {
820 String normalizedAddress = address;
821 if ( normalizedAddress.contains(
"%") ) {
822 normalizedAddress = normalizedAddress.substring(0, normalizedAddress.indexOf(
"%"));
825 return normalizedAddress;
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)