diff --git a/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java b/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java index be0550e7971f498415ea3b2e4bf71dd32d7e8c88..5e5bad91c5bfb75361cebee713116f0ee096ba53 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java +++ b/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java @@ -442,13 +442,15 @@ private void createHostTables(Statement stmt) throws SQLException { + "FOREIGN KEY(ip_address_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE," + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL )"); - // maps an address to an artifact using it + // maps an address to an content/item using it stmt.execute("CREATE TABLE tsk_host_address_usage (id " + dbQueryHelper.getPrimaryKey() + " PRIMARY KEY, " + "addr_obj_id " + dbQueryHelper.getBigIntType() + " NOT NULL, " - + "artifact_obj_id " + dbQueryHelper.getBigIntType() + " NOT NULL, " - + "UNIQUE(addr_obj_id, artifact_obj_id), " + + "obj_id " + dbQueryHelper.getBigIntType() + " NOT NULL, " // obj id of the content/item using the address + + "data_source_obj_id " + dbQueryHelper.getBigIntType() + " NOT NULL, " // data source where the usage was found + + "UNIQUE(addr_obj_id, obj_id), " + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, " - + "FOREIGN KEY(artifact_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )"); + + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, " + + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )"); } // Must be called after tsk_persons, tsk_hosts and tsk_objects have been created. diff --git a/bindings/java/src/org/sleuthkit/datamodel/HostAddressManager.java b/bindings/java/src/org/sleuthkit/datamodel/HostAddressManager.java index b38f5be5e415f277969da84f959921355098f22f..6cc054ed25a8ab9ff897ee09087466fdad073a36 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/HostAddressManager.java +++ b/bindings/java/src/org/sleuthkit/datamodel/HostAddressManager.java @@ -212,7 +212,7 @@ private HostAddress createHostAddress(HostAddress.HostAddressType type, String a * * @throws TskCoreException */ - public void mapHostToAddress(Host host, HostAddress hostAddress, Long time, Content source) throws TskCoreException { + public void assignHostToAddress(Host host, HostAddress hostAddress, Long time, Content source) throws TskCoreException { String insertSQL = db.getInsertOrIgnoreSQL(" INTO tsk_host_address_map(host_id, addr_obj_id, source_obj_id, time) " + " VALUES(?, ?, ?, ?) "); @@ -242,13 +242,13 @@ public void mapHostToAddress(Host host, HostAddress hostAddress, Long time, Cont } /** - * Get all the addresses that have been mapped to the given host + * Get all the addresses that have been assigned to the given host. * * @param host Host to get addresses for. * * @return List of addresses, may be empty. */ - List<HostAddress> getHostAddresses(Host host) throws TskCoreException { + List<HostAddress> getHostAddressesAssignedTo(Host host) throws TskCoreException { String queryString = "SELECT addr_obj_id FROM tsk_host_address_map " + " WHERE host_id = " + host.getId(); @@ -588,24 +588,90 @@ List<HostAddress> getHostNameByIp(String ipAddress) throws TskCoreException { /** * Associate the given artifact with a HostAddress. * - * @param artifact The artifact to associate the host address with. + * @param content The content/item using the address. * @param hostAddress The host address. */ - public void addUsage(BlackboardArtifact artifact, HostAddress hostAddress) throws TskCoreException { - final String insertSQL = db.getInsertOrIgnoreSQL(" INTO tsk_host_address_usage(addr_obj_id, artifact_obj_id) " - + " VALUES(" + hostAddress.getId() + ", " + artifact.getId() + ") "); + public void addUsage(Content content, HostAddress hostAddress) throws TskCoreException { + final String insertSQL = db.getInsertOrIgnoreSQL(" INTO tsk_host_address_usage(addr_obj_id, obj_id, data_source_obj_id) " + + " VALUES(" + hostAddress.getId() + ", " + content.getId() + ", " + content.getDataSource().getId() + ") "); db.acquireSingleUserCaseWriteLock(); try (CaseDbConnection connection = this.db.getConnection(); Statement s = connection.createStatement()) { connection.executeUpdate(s, insertSQL); } catch (SQLException ex) { - throw new TskCoreException(String.format("Error associating host address %s with artifact with id %d", hostAddress.getAddress(), artifact.getId()), ex); + throw new TskCoreException(String.format("Error associating host address %s with artifact with id %d", hostAddress.getAddress(), content.getId()), ex); } finally { db.releaseSingleUserCaseWriteLock(); } } + private final String ADDRESS_USAGE_QUERY = "SELECT addresses.id as id, addresses.address_type as address_type, addresses.address as address " + + " FROM tsk_host_address_usage as usage " + + " JOIN tsk_host_addresses as addresses " + + " ON usage.addr_obj_id = addresses.id "; + + /** + * Get all the addresses that have been used by the given content. + * + * @param content Content to get addresses used for. + * + * @return List of addresses, may be empty. + * + * @throws TskCoreException + */ + public List<HostAddress> getHostAddressesUsedByContent(Content content) throws TskCoreException { + String queryString = ADDRESS_USAGE_QUERY + + " WHERE usage.obj_id = " + content.getId(); + + return getHostAddressesUsed(queryString); + } + + /** + * Get all the addresses that have been used by the given data source. + * + * @param dataSource Data source to get addresses used for. + * + * @return List of addresses, may be empty. + * + * @throws TskCoreException + */ + public List<HostAddress> getHostAddressesUsedOnDataSource(Content dataSource) throws TskCoreException { + String queryString = ADDRESS_USAGE_QUERY + + " WHERE usage.data_source_obj_id = " + dataSource.getId(); + + return getHostAddressesUsed(queryString); + } + + /** + * Gets the host addresses used by running the given query. + * + * @param addressesUsedSQL SQL query to run. + * + * @return List of addresses, may be empty. + * + * @throws TskCoreException + */ + private List<HostAddress> getHostAddressesUsed(String addressesUsedSQL) throws TskCoreException { + + List<HostAddress> addressesUsed = new ArrayList<>(); + + db.acquireSingleUserCaseReadLock(); + try (CaseDbConnection connection = this.db.getConnection(); + Statement s = connection.createStatement(); + ResultSet rs = connection.executeQuery(s, addressesUsedSQL)) { + + while (rs.next()) { + addressesUsed.add(new HostAddress(db, rs.getLong("id"), HostAddress.HostAddressType.fromID(rs.getInt("address_type")), rs.getString("address"))); + } + return addressesUsed; + } catch (SQLException ex) { + throw new TskCoreException(String.format("Error getting host addresses used with query string = %s", addressesUsedSQL), ex); + } finally { + db.releaseSingleUserCaseReadLock(); + } + } + /** * Detects format of address. * diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java index 6e9e863c7f0e1a760bcd7d208761d3f89b6a6d10..def7786840433d344fcd14b6c40812c890ccff80 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java @@ -2536,10 +2536,12 @@ private CaseDbSchemaVersionNumber updateFromSchema8dot6toSchema8dot7(CaseDbSchem // maps an address to an artifact using it statement.execute("CREATE TABLE tsk_host_address_usage (id " + primaryKeyType + " PRIMARY KEY, " + "addr_obj_id " + bigIntDataType + " NOT NULL, " - + "artifact_obj_id " + bigIntDataType + " NOT NULL, " - + "UNIQUE(addr_obj_id, artifact_obj_id), " + + "obj_id " + bigIntDataType + " NOT NULL, " + + "data_source_obj_id " + bigIntDataType + " NOT NULL, " // data source where the usage was found + + "UNIQUE(addr_obj_id, obj_id), " + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, " - + "FOREIGN KEY(artifact_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )"); + + + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )"); return new CaseDbSchemaVersionNumber(8, 7); diff --git a/bindings/java/test/org/sleuthkit/datamodel/OsAccountTest.java b/bindings/java/test/org/sleuthkit/datamodel/OsAccountTest.java index 86a626efff38178b784b8b27219c1e1d91a517e3..29efc1cf49819b9e495a953f297fee7d11af01b0 100644 --- a/bindings/java/test/org/sleuthkit/datamodel/OsAccountTest.java +++ b/bindings/java/test/org/sleuthkit/datamodel/OsAccountTest.java @@ -240,6 +240,32 @@ public void mergeTests() throws TskCoreException { @Test public void hostAddressTests() throws TskCoreException { + + + // lets add a file + long dataSourceObjectId = fs.getDataSource().getId(); + + SleuthkitCase.CaseDbTransaction trans = caseDB.beginTransaction(); + + // Add a root folder + FsContent _root = caseDB.addFileSystemFile(dataSourceObjectId, fs.getId(), "", 0, 0, + TskData.TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, TskData.TSK_FS_NAME_FLAG_ENUM.ALLOC, + (short) 0, 200, 0, 0, 0, 0, null, null, null, false, fs, null, null, Collections.emptyList(), trans); + + // Add a dir - no attributes + FsContent _windows = caseDB.addFileSystemFile(dataSourceObjectId, fs.getId(), "Windows", 0, 0, + TskData.TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, TskData.TSK_FS_NAME_FLAG_ENUM.ALLOC, + (short) 0, 200, 0, 0, 0, 0, null, null, null, false, _root, "S-1-5-80-956008885-3418522649-1831038044-1853292631-227147846", null, Collections.emptyList(), trans); + + // add another no attribute file to same folder + FsContent _abcTextFile = caseDB.addFileSystemFile(dataSourceObjectId, fs.getId(), "abc.txt", 0, 0, + TskData.TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, TskData.TSK_FS_NAME_FLAG_ENUM.ALLOC, + (short) 0, 200, 0, 0, 0, 0, null, null, "Text/Plain", true, _windows, null, null, Collections.emptyList(), trans); + + trans.commit(); + + + String ipv4Str = "11.22.33.44"; String ipv6Str = "2001:0db8:85a3:0000:0000:8a2e:0370:6666"; String hostnameStr = "basis.com"; @@ -262,11 +288,13 @@ public void hostAddressTests() throws TskCoreException { // Test host map Host host = caseDB.getHostManager().createHost("TestHostAddress"); - SleuthkitCase.CaseDbTransaction trans = caseDB.beginTransaction(); + + trans = caseDB.beginTransaction(); DataSource ds = caseDB.addLocalFilesDataSource("devId", "pathToFiles", "EST", null, trans); trans.commit(); - caseDB.getHostAddressManager().mapHostToAddress(host, ipv4addr, (long) 0, ds); - List<HostAddress> hostAddrs = caseDB.getHostAddressManager().getHostAddresses(host); + + caseDB.getHostAddressManager().assignHostToAddress(host, ipv4addr, (long) 0, ds); + List<HostAddress> hostAddrs = caseDB.getHostAddressManager().getHostAddressesAssignedTo(host); assertEquals(hostAddrs.size() == 1, true); // Test IP mapping @@ -275,6 +303,23 @@ public void hostAddressTests() throws TskCoreException { assertEquals(ipForHostSet.size() == 1, true); List<HostAddress> hostForIpSet = caseDB.getHostAddressManager().getHostNameByIp(ipv4addr.getAddress()); assertEquals(hostForIpSet.size() == 1, true); + + + // add address usage + caseDB.getHostAddressManager().addUsage(_abcTextFile, ipv4addr); + caseDB.getHostAddressManager().addUsage(_abcTextFile, addr2); + caseDB.getHostAddressManager().addUsage(_abcTextFile, hostAddr); + + //test get addressUsed methods + List<HostAddress> addrUsedByAbc = caseDB.getHostAddressManager().getHostAddressesUsedByContent(_abcTextFile); + assertEquals(addrUsedByAbc.size() == 3, true); + + List<HostAddress> addrUsedByRoot = caseDB.getHostAddressManager().getHostAddressesUsedByContent(_root); + assertEquals(addrUsedByRoot.isEmpty(), true); + + List<HostAddress> addrUsedOnDataSource = caseDB.getHostAddressManager().getHostAddressesUsedOnDataSource(_root.getDataSource()); + assertEquals(addrUsedOnDataSource.size() == 3, true); + } @Test