diff --git a/assets/scripts/bin/nmap.lua b/assets/scripts/bin/nmap.lua new file mode 100644 index 0000000..55220ef --- /dev/null +++ b/assets/scripts/bin/nmap.lua @@ -0,0 +1,9 @@ +-- /bin/nmap - Network exploration tool and security/port scanner. +local target_ip = arg[1] + +if not target_ip then + return "nmap: requires a target host to be specified" +end + +-- TODO: Add args such as -sV for version detection etc. +return { action = "scan", target = target_ip } diff --git a/client/src/terminal.cpp b/client/src/terminal.cpp index 7f436e0..bd9d5ce 100644 --- a/client/src/terminal.cpp +++ b/client/src/terminal.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "terminal.h" #include "client_network.h" @@ -43,7 +45,21 @@ void Terminal::update(void) { _prompt = server_msg.substr(last_newline+1); std::string output = server_msg.substr(0, last_newline); if(!output.empty()) { - _history.push_back(output); + /* Split multiline output and push each line to history. */ + std::stringstream ss(output); + std::string line; + while(std::getline(ss, line, '\n')) { + /* Replace tabs. */ + std::string line_with_spaces; + for(char ch : line) { + if(ch == '\t') { + line_with_spaces += " "; + } else { + line_with_spaces += ch; + } + } + _history.push_back(line_with_spaces); + } } } else { /* diff --git a/common/src/command_processor.cpp b/common/src/command_processor.cpp index 4ac7446..81ed008 100644 --- a/common/src/command_processor.cpp +++ b/common/src/command_processor.cpp @@ -192,6 +192,24 @@ std::string CommandProcessor::_handle_vfs_action(sol::table action) { return "Connection closed."; } else if(action_name == "close_terminal") { return "__CLOSE_CONNECTION__"; + } else if(action_name == "scan") { + std::string target_ip = action["target"].get_or(""); + if(!_world_vfs.count(target_ip)) { + return std::string("nmap: Could not resolve host: ") + target_ip; + } + + vfs_node* target_root = _world_vfs[target_ip]; + if(target_root->services.empty()) { + return std::string("No open ports for ") + target_ip; + } + + std::stringstream ss; + ss<<"Host: "<services) { + ss< services; }; std::string get_full_path(vfs_node* node); diff --git a/common/src/vfs_manager.cpp b/common/src/vfs_manager.cpp index c5e620c..948829b 100644 --- a/common/src/vfs_manager.cpp +++ b/common/src/vfs_manager.cpp @@ -77,6 +77,9 @@ vfs_node* VFSManager::create_vfs(const std::string& system_type) { /* Link to the shared directories from the template. */ root->children["bin"] = copy_vfs_node(_vfs_root->children["bin"], root); + /* Default services. All machines have SSH currently. */ + root->services[22] = "SSH v1.2"; + if(system_type == "npc") { vfs_node* npc_file = new_node("npc_system.txt", FILE_NODE, root); npc_file->content = "This guy sucks nuts!"; diff --git a/server/src/network_manager.cpp b/server/src/network_manager.cpp index 806e735..e9ff3fc 100644 --- a/server/src/network_manager.cpp +++ b/server/src/network_manager.cpp @@ -16,6 +16,11 @@ NetworkManager::NetworkManager(void) : _acceptor(_io_context) { /* VFS setup. */ _world_vfs["8.8.8.8"] = _vfs_manager.create_vfs("npc"); _world_vfs["10.0.2.15"] = _vfs_manager.create_vfs("npc"); + + /* Specific npc services. */ + _world_vfs["8.8.8.8"]->services[80] = "HTTPD v2.4"; + _world_vfs["10.0.2.15"]->services[21] = "FTPd v3.0"; + fprintf(stderr, "Created world with %zu networks\n", _world_vfs.size()); }