diff --git a/.gitignore b/.gitignore index ca9cc09a12faeb763bd4ab605e24151dbbb3d625..6183fdd47afb6216b0c14f8dc508912d12261c81 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ __pycache__/ *$py.class .pytest_cache/ .env - +.python-version # docker-compose override file docker-compose.override.yml diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md new file mode 100644 index 0000000000000000000000000000000000000000..9dfc798c38813857e97c28df68506dba668b624d --- /dev/null +++ b/CONTRIBUTION.md @@ -0,0 +1,313 @@ +# Contributing to Mock'it + +Thank you for your interest in contributing to Mock'it! This project is a powerful network device emulator that supports SSH, SNMP, Telnet, and Netconf protocols, currently supporting 115+ different network vendors. Your contributions help make this tool more comprehensive and useful for the networking community. + +## Getting Started + +Before contributing, please: + +1. Fork the repository on GitLab +2. Clone your fork locally +3. Set up the development environment (see [Development Setup](#development-setup)) +4. Read this guide thoroughly +5. Check existing issues to see if your contribution is already being worked on + +## Types of Contributions + +We welcome various types of contributions: + +### Adding New Device Support +- Add support for network devices not currently supported +- Contribute SNMP walk data for devices missing SNMP support +- Add Netconf configuration templates for controller-based devices + +### Improving Existing Devices +- Add missing command responses for existing devices +- Create Python logic for complex command handling +- Add support for different versions of existing devices +- Fix issues with existing device emulations + +### Testing and Quality +- Write tests for new or existing functionality +- Report issues you encounter +- Optimize existing code + +### Documentation +- Document device-specific configurations +- Create guides for common use cases +- Provide real-world usage examples + +## Development Setup + +### Prerequisites +- Docker and Docker Compose +- Python 3.8+ (for local development) +- Git + +### Local Development Environment + +1. Clone the repository: + ```bash + git clone https://gitlab.com/slurpit.io/mockit.git + cd mockit + ``` + +2. Install Python dependencies: + ```bash + pip install -r requirements.txt + ``` + +3. Set up development environment: + ```bash + # Configure git hooks for version management + git config core.hooksPath .githooks + ``` + +4. Test the setup: + ```bash + # Run basic tests + cd tests + docker compose -f compose-dev_ssh_telnet.yml up -d --build + docker exec devices-test_container sh -c "pytest test_ssh_telnet.py -v" + docker compose -f compose-dev_ssh_telnet.yml down + ``` + +## Adding New Device Support + +### 1. SSH/Telnet Device Support + +#### Step 1: Create Device Directory Structure +```bash +mkdir -p configs/your_device_type/{templates,scripts,netconf} +``` + +#### Step 2: Add Command Templates +Create static command responses in `configs/your_device_type/templates/`: +- Each file should be named exactly as the command (e.g., `show version`) +- File content should be the pure output (no command prompt) +- Example: `configs/your_device_type/templates/show version` + +#### Step 3: Add Dynamic Scripts (Optional) +Create `configs/your_device_type/scripts/__init__.py` for complex logic: +```python +def handle_command(command: str): + if command.startswith('show interface'): + # Your dynamic logic here + return "Interface output here" + return "" +``` + +#### Step 4: Add Device to Supported Lists +- Add device name to `supported_devices_ssh.md` +- Add device name to `supported_devices_telnet.md` (if telnet supported) + +#### Step 5: Test Your Device +```bash +# Test SSH +docker compose up -d --build +ssh test@localhost -p 22 + +# Test Telnet (if supported) +telnet localhost 23 +``` + +### 2. SNMP Device Support + +#### Step 1: Gather SNMP Data +Use `snmpwalk` to collect SNMP data from a real device: +```bash +# Linux +snmpwalk -v2c -c public > snmp_output.txt + +# Windows +snmpwalk -v:"2" -c:"public" -r:"" > snmp_output.txt +``` + +#### Step 2: Create SNMP Configuration +Create `configs/your_device_type/snmp.json` with the collected data. + +#### Step 3: Add to Supported List +Add device name to `supported_devices_snmp.md`. + +### 3. Netconf Device Support + +#### Step 1: Create Netconf Template +Create `configs/your_device_type/netconf/get-config.xml`: +```xml + + + + + + +``` + +## Improving Existing Devices + +### Adding New Commands +1. Static Commands: Add new files to `templates/` directory +2. Dynamic Commands: Modify `scripts/__init__.py` to handle new commands + +### Adding Version Support +1. Create version-specific directory: `configs/device_type/version_name/` +2. Copy existing templates and modify as needed +3. Use `DEVICE_VERSION` environment variable to switch versions + +### Using Database Operations +For complex state management, use the built-in database operations: +```python +from src.ssh_server.db_operations import create_table, create_record, read_record, update_record, delete_record + +# Create a table for your device +create_table('your_device_type') + +def handle_command(command: str): + if command.startswith('vlan'): + # Your VLAN management logic + create_record('your_device_type', 'vlan', 'vlan_data') + return "VLAN created" +``` + +## Testing Your Changes + +### Running Tests +```bash +cd tests + +# Test SSH and Telnet +docker compose -f compose-dev_ssh_telnet.yml up -d --build +docker exec devices-test_container sh -c "pytest test_ssh_telnet.py -v" + +# Test SNMP +docker compose -f docker-compose.yml up -d --build +docker exec devices-test_container sh -c "pytest test_snmp.py -v" + +# Test Netconf +docker exec devices-test_container sh -c "pytest test_netconf.py -v" + +# Clean up +docker compose -f compose-dev_ssh_telnet.yml down +``` + +### Manual Testing +1. SSH Testing: Use Netmiko or direct SSH connection +2. SNMP Testing: Use `snmpwalk` or SNMP tools +3. Telnet Testing: Use telnet client +4. Netconf Testing: Use `netconf-console` or `ncclient` + +### Test with Real Network Automation Tools +Test your device with popular automation tools: +- Netmiko: Python library for network device automation +- Ansible: Network automation platform +- NAPALM: Network automation library + +## Submitting Changes + +### 1. Create a Branch +```bash +git checkout -b feature/your-device-support +# or +git checkout -b fix/issue-description +``` + +### 2. Commit Your Changes +```bash +git add . +git commit -m "Add support for [device type]" +``` + +### 3. Push and Create Merge Request +```bash +git push origin feature/your-device-support +``` + +Then create a merge request on GitLab with: +- Clear description of changes +- Screenshots or test results +- Reference to any related issues + +### 4. Merge Request Template +```markdown +## Description +Brief description of your changes + +## Type of Change +- [ ] New device support +- [ ] Bug fix +- [ ] Documentation update +- [ ] Test improvement + +## Testing +- [ ] Manual testing completed +- [ ] Automated tests pass +- [ ] Tested with [specific tools/libraries] + +## Checklist +- [ ] Code follows project style guidelines +- [ ] Self-review completed +- [ ] Documentation updated (if needed) +- [ ] No breaking changes (or documented) +``` + +## Code Style and Guidelines + +### Python Code +- Follow PEP 8 style guidelines +- Use meaningful variable and function names +- Add comments for complex logic +- Keep functions focused and small + +### File Organization +- Device configs go in `configs/device_type/` +- Static templates in `templates/` subdirectory +- Dynamic scripts in `scripts/` subdirectory +- Tests in `tests/` directory + +### Naming Conventions +- Device types: `vendor_os` (e.g., `cisco_ios`, `juniper_junos`) +- Command files: exact command name (e.g., `show version`) +- Version directories: `v6`, `v7`, etc. + +## Documentation + +### Device Documentation +When adding new devices, consider documenting: +- Device capabilities and limitations +- Supported commands +- Configuration examples +- Known issues or workarounds + +### README Updates +Update relevant sections in `README.md` if you: +- Add new environment variables +- Change configuration options +- Add new features + +## Community Guidelines + +### Code of Conduct +- Be respectful and inclusive +- Provide constructive feedback +- Help others learn and grow +- Follow the project's mission + +### Getting Help +- Check existing issues and discussions +- Ask questions in merge request comments +- Provide detailed information when reporting issues + +### Recognition +Contributors will be recognized in: +- Project documentation +- Release notes +- Community acknowledgments + +## Questions? + +If you have questions about contributing: +1. Check existing issues and discussions +2. Create a new issue with the "question" label +3. Reach out to maintainers through merge request comments + +Thank you for contributing to Mock'it! Your efforts help make network testing and development more accessible to everyone. diff --git a/configs/arista_eos/templates/show lacp internal.txt b/configs/arista_eos/templates/show lacp internal.txt new file mode 100644 index 0000000000000000000000000000000000000000..d929f3e5715c5118f3417fb4ec642a7137dd9996 --- /dev/null +++ b/configs/arista_eos/templates/show lacp internal.txt @@ -0,0 +1,36 @@ +LACP System-identifier: 8000,aa-bb-cc-dd-ee-01 +State: A = Active, P = Passive; S=ShortTimeout, L=LongTimeout; + G = Aggregable, I = Individual; s+=InSync, s-=OutOfSync; + C = Collecting, X = state machine expired, + D = Distributing, d = default neighbor state + | Partner Actor + Port Status | Sys-id Port# State OperKey PortPriority +------------ --------------|----------------------------- ----------- ------------- ------------- ------------ +Port Channel Port-Channel4: + Et29/1 Bundled | 007F,aa-bb-cc-dd-ee-02 117 ALGs+CD 0x0004 32768 + Et30/1 Bundled | 007F,aa-bb-cc-dd-ee-02 121 ALGs+CD 0x0004 32768 +Port Channel Port-Channel10: + Et28/1 Bundled | 8000,aa-bb-cc-dd-ee-03 114 ALGs+CD 0x000a 32768 +Port Channel Port-Channel14: + Et21/1 Bundled | 8000,aa-bb-cc-dd-ee-04 85 ALGs+CD 0x000e 32768 +Port Channel Port-Channel100: + Et13/1 Bundled | 007F,aa-bb-cc-dd-ee-05 53 ALGs+CD 0x0064 32768 + Et14/1 Bundled | 007F,aa-bb-cc-dd-ee-05 57 ALGs+CD 0x0064 32768 +Port Channel Port-Channel110: + Et25/1 Bundled | 8000,aa-bb-cc-dd-ee-06 101 ALGs+CD 0x006e 32768 + Et26/1 Bundled | 8000,aa-bb-cc-dd-ee-06 133 ALGs+CD 0x006e 32768 + Et27/1 Bundled | 8000,aa-bb-cc-dd-ee-06 127 ALGs+CD 0x006e 32768 +Port Channel Port-Channel119: + No ports in aggregate +Port Channel Port-Channel125: + Et4/1 Bundled | 007F,aa-bb-cc-dd-ee-07 17 ALGs+CD 0x007d 32768 + Et5/1 Bundled | 007F,aa-bb-cc-dd-ee-07 21 ALGs+CD 0x007d 32768 +Port Channel Port-Channel130: + Et6/1 Bundled | 8000,aa-bb-cc-dd-ee-08 25 ALGs+CD 0x0082 32768 + Et7/1 Bundled | 8000,aa-bb-cc-dd-ee-08 29 ALGs+CD 0x0082 32768 +Port Channel Port-Channel140: + Et19/1 Bundled | 007F,aa-bb-cc-dd-ee-09 77 ALGs+CD 0x008c 32768 +Port Channel Port-Channel310: + No ports in aggregate +Port Channel Port-Channel400: + Et23/1 Bundled | 8000,aa-bb-cc-dd-ee-0a 93 ALGs+CD 0x0190 32768 \ No newline at end of file diff --git a/configs/asterfusion_asternos/asterfusion_asternos_server.py b/configs/asterfusion_asternos/asterfusion_asternos_server.py new file mode 100644 index 0000000000000000000000000000000000000000..69c86453c656fc86128a1a2a0e148bb89f798dab --- /dev/null +++ b/configs/asterfusion_asternos/asterfusion_asternos_server.py @@ -0,0 +1,27 @@ +from src.ssh_server.ssh_server import SSH_Server +from src.ssh_server.ssh_handler import SSH_Handler +from asyncssh.process import SSHServerProcess + +class asterfusion_asternos_server(SSH_Server): + pass + +class asterfusion_asternos_handler(SSH_Handler): + def __init__(self, process: SSHServerProcess, options): + options['device_type'] = 'asterfusion_asternos' + super().__init__(process, options=options) + self.set_prompt_terminator(pri_terminator = "#", alt_terminator = ">") + + + def handle_custom_command(self, command): + if command == "config system": + self.config_mode = command == "config system" + self.set_prompt_terminator(pri_terminator = self.pri_terminator, alt_terminator = self.alt_terminator) + return "Configuration successed" + + if command == "exit" and self.config_mode: + self.config_mode = False + self.set_prompt_terminator(pri_terminator = self.pri_terminator, alt_terminator = self.alt_terminator) + return "Configuration exited" + return "" + + \ No newline at end of file diff --git a/configs/asterfusion_asternos/netconf/get-config.xml b/configs/asterfusion_asternos/netconf/get-config.xml new file mode 100644 index 0000000000000000000000000000000000000000..6b805e7302740027a64a76dfaa548cc448875efe --- /dev/null +++ b/configs/asterfusion_asternos/netconf/get-config.xml @@ -0,0 +1,7 @@ + + + + Hello from asterfusion_asternos! + + diff --git a/configs/asterfusion_asternos/scripts/__init__.py b/configs/asterfusion_asternos/scripts/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..20ab2f609be071b11183234a754a553ac8b6eaf8 --- /dev/null +++ b/configs/asterfusion_asternos/scripts/__init__.py @@ -0,0 +1,3 @@ +# from src.ssh_server.db_operations import create_table, create_record, read_record, update_record, delete_record +def handle_command(command: str): + return "" \ No newline at end of file diff --git a/configs/bintec_boss/bintec_boss_server.py b/configs/bintec_boss/bintec_boss_server.py new file mode 100644 index 0000000000000000000000000000000000000000..7d2d853076de85f4139d2b3ea6c01419f008cdaa --- /dev/null +++ b/configs/bintec_boss/bintec_boss_server.py @@ -0,0 +1,12 @@ +from src.ssh_server.ssh_server import SSH_Server +from src.ssh_server.ssh_handler import SSH_Handler +from asyncssh.process import SSHServerProcess + +class bintec_boss_server(SSH_Server): + pass + +class bintec_boss_handler(SSH_Handler): + def __init__(self, process: SSHServerProcess, options): + options['device_type'] = 'bintec_boss' + super().__init__(process, options=options) + self.set_prompt_terminator(pri_terminator = ">", alt_terminator = ">") diff --git a/configs/bintec_boss/netconf/get-config.xml b/configs/bintec_boss/netconf/get-config.xml new file mode 100644 index 0000000000000000000000000000000000000000..a7894d19786c5c83efb749a6342b717b36bb8cab --- /dev/null +++ b/configs/bintec_boss/netconf/get-config.xml @@ -0,0 +1,7 @@ + + + + Hello from bintec_boss! + + diff --git a/configs/bintec_boss/scripts/__init__.py b/configs/bintec_boss/scripts/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..20ab2f609be071b11183234a754a553ac8b6eaf8 --- /dev/null +++ b/configs/bintec_boss/scripts/__init__.py @@ -0,0 +1,3 @@ +# from src.ssh_server.db_operations import create_table, create_record, read_record, update_record, delete_record +def handle_command(command: str): + return "" \ No newline at end of file diff --git a/configs/ciena_saos/templates/aggregation show member.txt b/configs/ciena_saos/templates/aggregation show member.txt new file mode 100644 index 0000000000000000000000000000000000000000..d0cd63e7c976b1ba76b840c19260f222a833efb4 --- /dev/null +++ b/configs/ciena_saos/templates/aggregation show member.txt @@ -0,0 +1,12 @@ ++--------------------------------- Agg Member Info ---------------------------------+ +|Aggregator | Id |Mode| Type|Tot| Member Port(s) | ++---------------+----+----+-----+---+-----+-----+-----+-----+-----+-----+-----+-----+ +|LAG-AGG-DUMMY1 |1001|LACP|Added| 1 | 10 | | | | | | | | +| | | |Selec| 1 | 10 | | | | | | | | +| | | |Agged| 1 | 10 | | | | | | | | +|_______________|____|____|Distr| 1 | 10 | | | | | | | | +|LAG-AGG-DUMMY2 |1002|LACP|Added| 2 | 6 | 7 | | | | | | | +| | | |Selec| 2 | 6 | 7 | | | | | | | +| | | |Agged| 2 | 6 | 7 | | | | | | | +|_______________|____|____|Distr| 2 | 6 | 7 | | | | | | | ++---------------+----+----+-----+---+-----+-----+-----+-----+-----+-----+-----+-----+ \ No newline at end of file diff --git a/configs/ciena_saos10/ciena_saos10_server.py b/configs/ciena_saos10/ciena_saos10_server.py new file mode 100644 index 0000000000000000000000000000000000000000..515b2455a193b02cd2e6fc8a118566c0f43d40e2 --- /dev/null +++ b/configs/ciena_saos10/ciena_saos10_server.py @@ -0,0 +1,14 @@ +from src.ssh_server.ssh_server import SSH_Server +from src.ssh_server.ssh_handler import SSH_Handler +from asyncssh.process import SSHServerProcess + +class ciena_saos10_server(SSH_Server): + pass + +class ciena_saos10_handler(SSH_Handler): + def __init__(self, process: SSHServerProcess, options): + options['device_type'] = 'ciena_saos10' + super().__init__(process, options=options) + self.set_prompt_terminator(pri_terminator = "#", alt_terminator = ">") + + \ No newline at end of file diff --git a/configs/ciena_saos10/netconf/get-config.xml b/configs/ciena_saos10/netconf/get-config.xml new file mode 100644 index 0000000000000000000000000000000000000000..a9d73ae1349d4b21b74eced72159f5bd75e9c24a --- /dev/null +++ b/configs/ciena_saos10/netconf/get-config.xml @@ -0,0 +1,7 @@ + + + + Hello from ciena_saos10! + + diff --git a/configs/ciena_saos10/scripts/__init__.py b/configs/ciena_saos10/scripts/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..20ab2f609be071b11183234a754a553ac8b6eaf8 --- /dev/null +++ b/configs/ciena_saos10/scripts/__init__.py @@ -0,0 +1,3 @@ +# from src.ssh_server.db_operations import create_table, create_record, read_record, update_record, delete_record +def handle_command(command: str): + return "" \ No newline at end of file diff --git a/configs/ciena_saos10/templates/.gitkeep b/configs/ciena_saos10/templates/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/configs/cisco_ios/templates/show lacp internal.txt b/configs/cisco_ios/templates/show lacp internal.txt new file mode 100644 index 0000000000000000000000000000000000000000..a1730d420e981f24ec3f51e6e437a21d5dd063e8 --- /dev/null +++ b/configs/cisco_ios/templates/show lacp internal.txt @@ -0,0 +1,8 @@ +Flags: S - Device is requesting Slow LACPDUs + F - Device is requesting Fast LACPDUs + A - Device is in Active mode P - Device is in Passive mode + +Channel group 10 + LACP port Admin Oper Port Port +Port Flags State Priority Key Key Number State +Te0/0/1 SA down 32768 0xA 0x0 0x1 0x4D \ No newline at end of file diff --git a/configs/fiberstore_fsosv2/fiberstore_fsosv2_server.py b/configs/fiberstore_fsosv2/fiberstore_fsosv2_server.py new file mode 100644 index 0000000000000000000000000000000000000000..17d3ac228d31362181ad571c3efae1b88677e613 --- /dev/null +++ b/configs/fiberstore_fsosv2/fiberstore_fsosv2_server.py @@ -0,0 +1,14 @@ +from src.ssh_server.ssh_server import SSH_Server +from src.ssh_server.ssh_handler import SSH_Handler +from asyncssh.process import SSHServerProcess + +class fiberstore_fsosv2_server(SSH_Server): + pass + +class fiberstore_fsosv2_handler(SSH_Handler): + def __init__(self, process: SSHServerProcess, options): + options['device_type'] = 'fiberstore_fsosv2' + super().__init__(process, options=options) + self.set_prompt_terminator(pri_terminator = "#", alt_terminator = ">") + + \ No newline at end of file diff --git a/configs/fiberstore_fsosv2/netconf/get-config.xml b/configs/fiberstore_fsosv2/netconf/get-config.xml new file mode 100644 index 0000000000000000000000000000000000000000..04cba23ce27ec48021795e1b5a9cbeb35920b4c6 --- /dev/null +++ b/configs/fiberstore_fsosv2/netconf/get-config.xml @@ -0,0 +1,7 @@ + + + + Hello from fiberstore_fsosv2! + + diff --git a/configs/fiberstore_fsosv2/scripts/__init__.py b/configs/fiberstore_fsosv2/scripts/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..20ab2f609be071b11183234a754a553ac8b6eaf8 --- /dev/null +++ b/configs/fiberstore_fsosv2/scripts/__init__.py @@ -0,0 +1,3 @@ +# from src.ssh_server.db_operations import create_table, create_record, read_record, update_record, delete_record +def handle_command(command: str): + return "" \ No newline at end of file diff --git a/configs/fiberstore_fsosv2/templates/.gitkeep b/configs/fiberstore_fsosv2/templates/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/configs/fiberstore_networkos/fiberstore_networkos_server.py b/configs/fiberstore_networkos/fiberstore_networkos_server.py new file mode 100644 index 0000000000000000000000000000000000000000..d19cd58cdfe492f8ff49b892e8facde7866035eb --- /dev/null +++ b/configs/fiberstore_networkos/fiberstore_networkos_server.py @@ -0,0 +1,14 @@ +from src.ssh_server.ssh_server import SSH_Server +from src.ssh_server.ssh_handler import SSH_Handler +from asyncssh.process import SSHServerProcess + +class fiberstore_networkos_server(SSH_Server): + pass + +class fiberstore_networkos_handler(SSH_Handler): + def __init__(self, process: SSHServerProcess, options): + options['device_type'] = 'fiberstore_networkos' + super().__init__(process, options=options) + self.set_prompt_terminator(pri_terminator = "#", alt_terminator = ">") + + \ No newline at end of file diff --git a/configs/fiberstore_networkos/netconf/get-config.xml b/configs/fiberstore_networkos/netconf/get-config.xml new file mode 100644 index 0000000000000000000000000000000000000000..d3b26b4a9e9002abbcf12f44e680fec13c9681e0 --- /dev/null +++ b/configs/fiberstore_networkos/netconf/get-config.xml @@ -0,0 +1,7 @@ + + + + Hello from fiberstore_networkos! + + diff --git a/configs/fiberstore_networkos/scripts/__init__.py b/configs/fiberstore_networkos/scripts/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..20ab2f609be071b11183234a754a553ac8b6eaf8 --- /dev/null +++ b/configs/fiberstore_networkos/scripts/__init__.py @@ -0,0 +1,3 @@ +# from src.ssh_server.db_operations import create_table, create_record, read_record, update_record, delete_record +def handle_command(command: str): + return "" \ No newline at end of file diff --git a/configs/fiberstore_networkos/templates/.gitkeep b/configs/fiberstore_networkos/templates/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/configs/huawei_olt/huawei_olt_server.py b/configs/huawei_olt/huawei_olt_server.py index b6a03f84f7a98bbc88e9b67d117a1ec53ca57b78..ba20affef9bbed5267218225cb2fe2a36992ed0b 100644 --- a/configs/huawei_olt/huawei_olt_server.py +++ b/configs/huawei_olt/huawei_olt_server.py @@ -11,12 +11,23 @@ class huawei_olt_handler(SSH_Handler): def __init__(self, process: SSHServerProcess, options): options['device_type'] = 'huawei_olt' super().__init__(process, options=options) - self.enable = False self.set_prompt_terminator(pri_terminator = "#", alt_terminator = ">") + + def handle_custom_command(self, command): + if command == "huawei_olt": + return "huawei_olt" class huawei_olt_telnet_handler(Telnet_Handler): def __init__(self, reader, writer, options=None): super().__init__(reader, writer, options=options or {}) - self.enable = False - self.set_prompt_terminator(pri_terminator = "#", alt_terminator = ">") + self.set_prompt_terminator(pri_terminator = ">", alt_terminator = "$") + + def handle_custom_command(self, command): + if command == "huawei_olt": + return "huawei_olt" + + async def open(self): + self.respond("YES/NO" + self.terminator) + await self.process.stdin.readline() + return await super().open() \ No newline at end of file diff --git a/configs/huawei_smartax/huawei_smartax_server.py b/configs/huawei_smartax/huawei_smartax_server.py index 725c1686244ad482cdaad56e4407884c326b03d3..93076bb8b1f5cd1326de51b95ce1b4b97f1e6e53 100644 --- a/configs/huawei_smartax/huawei_smartax_server.py +++ b/configs/huawei_smartax/huawei_smartax_server.py @@ -10,7 +10,7 @@ class huawei_smartax_handler(SSH_Handler): def __init__(self, process: SSHServerProcess, options): options['device_type'] = 'huawei_smartax' super().__init__(process, options=options) - self.enable = False + self.config_pattern = "(config)" self.set_prompt_terminator(pri_terminator = "#", alt_terminator = ">") async def open(self): diff --git a/configs/huawei_smartaxmmi/huawei_smartaxmmi_server.py b/configs/huawei_smartaxmmi/huawei_smartaxmmi_server.py new file mode 100644 index 0000000000000000000000000000000000000000..cb74fd2957d6f9980a9da80ca96b8e9197a0b552 --- /dev/null +++ b/configs/huawei_smartaxmmi/huawei_smartaxmmi_server.py @@ -0,0 +1,32 @@ +from src.ssh_server.ssh_server import SSH_Server +from src.ssh_server.ssh_handler import SSH_Handler +from asyncssh.process import SSHServerProcess + +class huawei_smartaxmmi_server(SSH_Server): + pass + + +class huawei_smartaxmmi_handler(SSH_Handler): + def __init__(self, process: SSHServerProcess, options): + options['device_type'] = 'huawei_smartaxmmi' + super().__init__(process, options=options) + self.config_pattern = "(config)" + self.set_prompt_terminator(pri_terminator = "#", alt_terminator = ">") + + async def open(self): + self.respond("YES/NO" + self.terminator) + await self.process.stdin.readline() + return await super().open() + + + def handle_custom_command(self, command): + if "config" in command: + self.config_mode = True + self.set_prompt_terminator(pri_terminator = self.pri_terminator, alt_terminator = self.alt_terminator) + return "Configuration successed" + if command == "return" and self.config_mode: + self.config_mode = False + self.set_prompt_terminator(pri_terminator = self.pri_terminator, alt_terminator = self.alt_terminator) + return "Configuration exited" + return "" + \ No newline at end of file diff --git a/configs/huawei_smartaxmmi/netconf/get-config.xml b/configs/huawei_smartaxmmi/netconf/get-config.xml new file mode 100644 index 0000000000000000000000000000000000000000..e062ec660fb521094c9faf8c9e21d551fa1ecae8 --- /dev/null +++ b/configs/huawei_smartaxmmi/netconf/get-config.xml @@ -0,0 +1,7 @@ + + + + Hello from huawei_smartaxmmi! + + diff --git a/configs/huawei_smartaxmmi/scripts/__init__.py b/configs/huawei_smartaxmmi/scripts/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..20ab2f609be071b11183234a754a553ac8b6eaf8 --- /dev/null +++ b/configs/huawei_smartaxmmi/scripts/__init__.py @@ -0,0 +1,3 @@ +# from src.ssh_server.db_operations import create_table, create_record, read_record, update_record, delete_record +def handle_command(command: str): + return "" \ No newline at end of file diff --git a/configs/huawei_vrp/templates/display lacp statistics eth-trunk.txt b/configs/huawei_vrp/templates/display lacp statistics eth-trunk.txt new file mode 100644 index 0000000000000000000000000000000000000000..4b09b6c080a8bd9ace4e3ba9ac16fd683f8f297f --- /dev/null +++ b/configs/huawei_vrp/templates/display lacp statistics eth-trunk.txt @@ -0,0 +1,55 @@ + Eth-Trunk5's PDU statistics is: + ------------------------------------------------------------------------------- + Port LacpRevPdu LacpSentPdu MarkerRevPdu MarkerSentPdu + DUMMY-GE1/0/1 1892 1888 0 0 + + Eth-Trunk10's PDU statistics is: + ------------------------------------------------------------------------------- + Port LacpRevPdu LacpSentPdu MarkerRevPdu MarkerSentPdu + DUMMY-GE1/0/2 1887 1885 0 0 + + Eth-Trunk13's PDU statistics is: + ------------------------------------------------------------------------------- + Port LacpRevPdu LacpSentPdu MarkerRevPdu MarkerSentPdu + DUMMY-GE1/0/3 0 0 0 0 + DUMMY-GE1/0/4 0 0 0 0 + DUMMY-GE1/0/5 0 0 0 0 + + Eth-Trunk14's PDU statistics is: + ------------------------------------------------------------------------------- + Port LacpRevPdu LacpSentPdu MarkerRevPdu MarkerSentPdu + + Eth-Trunk15's PDU statistics is: + ------------------------------------------------------------------------------- + Port LacpRevPdu LacpSentPdu MarkerRevPdu MarkerSentPdu + DUMMY-GE1/0/6 0 0 0 0 + + Eth-Trunk20's PDU statistics is: + ------------------------------------------------------------------------------- + Port LacpRevPdu LacpSentPdu MarkerRevPdu MarkerSentPdu + DUMMY-GE1/0/7 1878 1883 0 0 + DUMMY-GE1/0/8 1878 1883 0 0 + + Eth-Trunk30's PDU statistics is: + ------------------------------------------------------------------------------- + Port LacpRevPdu LacpSentPdu MarkerRevPdu MarkerSentPdu + DUMMY-GE1/0/9 1787 1796 0 0 + + Eth-Trunk40's PDU statistics is: + ------------------------------------------------------------------------------- + Port LacpRevPdu LacpSentPdu MarkerRevPdu MarkerSentPdu + + Eth-Trunk50's PDU statistics is: + ------------------------------------------------------------------------------- + Port LacpRevPdu LacpSentPdu MarkerRevPdu MarkerSentPdu + DUMMY-GE1/0/10 1878 56176 0 0 + + Eth-Trunk60's PDU statistics is: + ------------------------------------------------------------------------------- + Port LacpRevPdu LacpSentPdu MarkerRevPdu MarkerSentPdu + DUMMY-GE1/0/11 0 0 0 0 + + Eth-Trunk90's PDU statistics is: + ------------------------------------------------------------------------------- + Port LacpRevPdu LacpSentPdu MarkerRevPdu MarkerSentPdu + DUMMY-GE1/0/12 1879 56184 0 0 \ No newline at end of file diff --git a/configs/infinera_packet/infinera_packet_server.py b/configs/infinera_packet/infinera_packet_server.py new file mode 100644 index 0000000000000000000000000000000000000000..c8f72d1b6aec875c9a200ca4de4397a3d2caaf04 --- /dev/null +++ b/configs/infinera_packet/infinera_packet_server.py @@ -0,0 +1,14 @@ +from src.ssh_server.ssh_server import SSH_Server +from src.ssh_server.ssh_handler import SSH_Handler +from asyncssh.process import SSHServerProcess + +class infinera_packet_server(SSH_Server): + pass + +class infinera_packet_handler(SSH_Handler): + def __init__(self, process: SSHServerProcess, options): + options['device_type'] = 'infinera_packet' + super().__init__(process, options=options) + self.set_prompt_terminator(pri_terminator = "#", alt_terminator = ">") + + \ No newline at end of file diff --git a/configs/infinera_packet/netconf/get-config.xml b/configs/infinera_packet/netconf/get-config.xml new file mode 100644 index 0000000000000000000000000000000000000000..ebc288242d820316a6e6430bfd7e9523281fce36 --- /dev/null +++ b/configs/infinera_packet/netconf/get-config.xml @@ -0,0 +1,7 @@ + + + + Hello from infinera_packet! + + diff --git a/configs/infinera_packet/scripts/__init__.py b/configs/infinera_packet/scripts/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..20ab2f609be071b11183234a754a553ac8b6eaf8 --- /dev/null +++ b/configs/infinera_packet/scripts/__init__.py @@ -0,0 +1,3 @@ +# from src.ssh_server.db_operations import create_table, create_record, read_record, update_record, delete_record +def handle_command(command: str): + return "" \ No newline at end of file diff --git a/configs/infinera_packet/templates/.gitkeep b/configs/infinera_packet/templates/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/configs/lancom_lcossx4/lancom_lcossx4_server.py b/configs/lancom_lcossx4/lancom_lcossx4_server.py new file mode 100644 index 0000000000000000000000000000000000000000..770eaab9009d5bfdf652203511f06c3162fa63c3 --- /dev/null +++ b/configs/lancom_lcossx4/lancom_lcossx4_server.py @@ -0,0 +1,12 @@ +from src.ssh_server.ssh_server import SSH_Server +from src.ssh_server.ssh_handler import SSH_Handler +from asyncssh.process import SSHServerProcess + +class lancom_lcossx4_server(SSH_Server): + pass + +class lancom_lcossx4_handler(SSH_Handler): + def __init__(self, process: SSHServerProcess, options): + options['device_type'] = 'lancom_lcossx4' + super().__init__(process, options=options) + self.set_prompt_terminator(pri_terminator = ">", alt_terminator = ">") diff --git a/configs/lancom_lcossx4/netconf/get-config.xml b/configs/lancom_lcossx4/netconf/get-config.xml new file mode 100644 index 0000000000000000000000000000000000000000..90286462af466ea0782f745621172bea6f9e58aa --- /dev/null +++ b/configs/lancom_lcossx4/netconf/get-config.xml @@ -0,0 +1,7 @@ + + + + Hello from lancom_lcossx4! + + diff --git a/configs/lancom_lcossx4/scripts/__init__.py b/configs/lancom_lcossx4/scripts/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..20ab2f609be071b11183234a754a553ac8b6eaf8 --- /dev/null +++ b/configs/lancom_lcossx4/scripts/__init__.py @@ -0,0 +1,3 @@ +# from src.ssh_server.db_operations import create_table, create_record, read_record, update_record, delete_record +def handle_command(command: str): + return "" \ No newline at end of file diff --git a/configs/nec_ix/nec_ix_server.py b/configs/nec_ix/nec_ix_server.py new file mode 100644 index 0000000000000000000000000000000000000000..55fb67ca0674c7616b55d60176421708ba43eca4 --- /dev/null +++ b/configs/nec_ix/nec_ix_server.py @@ -0,0 +1,24 @@ +from src.ssh_server.ssh_server import SSH_Server +from src.ssh_server.ssh_handler import SSH_Handler +from asyncssh.process import SSHServerProcess + +class nec_ix_server(SSH_Server): + pass + +class nec_ix_handler(SSH_Handler): + def __init__(self, process: SSHServerProcess, options): + options['device_type'] = 'nec_ix' + super().__init__(process, options=options) + self.config_pattern = "(config)" + self.set_prompt_terminator(pri_terminator = "#", alt_terminator = ">") + + def handle_custom_command(self, command): + if "svintr-config" in command: + self.config_mode = True + self.set_prompt_terminator(pri_terminator = self.pri_terminator, alt_terminator = self.alt_terminator) + return "Enable mode" + if "exit" in command: + self.config_mode = False + self.set_prompt_terminator(pri_terminator = self.pri_terminator, alt_terminator = self.alt_terminator) + return "Exit mode" + return "" \ No newline at end of file diff --git a/configs/nec_ix/netconf/get-config.xml b/configs/nec_ix/netconf/get-config.xml new file mode 100644 index 0000000000000000000000000000000000000000..ca5f1c8d7692bae9d7dd79d66e4783282c5895af --- /dev/null +++ b/configs/nec_ix/netconf/get-config.xml @@ -0,0 +1,7 @@ + + + + Hello from nec_ix! + + diff --git a/configs/nec_ix/scripts/__init__.py b/configs/nec_ix/scripts/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..20ab2f609be071b11183234a754a553ac8b6eaf8 --- /dev/null +++ b/configs/nec_ix/scripts/__init__.py @@ -0,0 +1,3 @@ +# from src.ssh_server.db_operations import create_table, create_record, read_record, update_record, delete_record +def handle_command(command: str): + return "" \ No newline at end of file diff --git a/configs/nokia_isam/templates/.gitkeep b/configs/nokia_isam/templates/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/configs/nokia_isam/templates/show router arp.txt b/configs/nokia_isam/templates/show router arp.txt new file mode 100644 index 0000000000000000000000000000000000000000..5e2f19d704042424d54afc0a140622f61927b51c --- /dev/null +++ b/configs/nokia_isam/templates/show router arp.txt @@ -0,0 +1,13 @@ +=============================================================================== +ARP Table (Router: Base) +=============================================================================== +IP Address MAC Address Expiry Type Interface +------------------------------------------------------------------------------- +192.168.1.10 00:11:22:33:44:55 00h00m00s Oth system +192.168.1.11 00:11:22:33:44:55 00h00m00s Oth[I] to-DEVICE-A01 +192.168.1.12 aa:bb:cc:dd:ee:01 00h07m18s Dyn[I] to-DEVICE-A01 +192.168.1.13 00:11:22:33:44:55 00h00m00s Oth[I] to-DEVICE-A02 +192.168.1.14 aa:bb:cc:dd:ee:02 00h07m13s Dyn[I] to-DEVICE-A02 +------------------------------------------------------------------------------- +No. of ARP Entries: 5 +=============================================================================== \ No newline at end of file diff --git a/configs/nokia_isam/templates/show router interface.txt b/configs/nokia_isam/templates/show router interface.txt new file mode 100644 index 0000000000000000000000000000000000000000..a5cab8707848bdbc86b399e7dd37e5f3175d16f0 --- /dev/null +++ b/configs/nokia_isam/templates/show router interface.txt @@ -0,0 +1,15 @@ +=============================================================================== +Interface Table (Router: Base) +=============================================================================== +Interface-Name Adm Opr(v4/v6) Mode Port/SapId + IP-Address PfxState +------------------------------------------------------------------------------- +system Up Up/Down Network system + 192.168.1.10/32 n/a +to-DEVICE-A01 Up Up/Down Network lag-10:10 + 192.168.1.11/31 n/a +to-DEVICE-A02 Up Up/Down Network lag-20:20 + 192.168.1.13/31 n/a +------------------------------------------------------------------------------- +Interfaces : 3 +=============================================================================== \ No newline at end of file diff --git a/configs/nokia_isam/templates/show router route table.txt b/configs/nokia_isam/templates/show router route table.txt new file mode 100644 index 0000000000000000000000000000000000000000..77bfa02dff604c37c69709499f157422e81b7527 --- /dev/null +++ b/configs/nokia_isam/templates/show router route table.txt @@ -0,0 +1,95 @@ +=============================================================================== +Route Table (Router: Base) +=============================================================================== +Dest Prefix[Flags] Type Proto Age Pref + Next Hop[Interface Name] Metric +------------------------------------------------------------------------------- +10.20.1.0/31 Remote OSPF 29d05h31m 10 + 192.168.1.12 41 +10.20.1.2/31 Remote OSPF 30d09h02m 10 + 192.168.1.14 41 +10.20.1.4/31 Remote OSPF 30d09h06m 10 + 192.168.1.12 41 +10.20.1.6/31 Remote OSPF 30d08h51m 10 + 192.168.1.14 42 +10.20.1.8/31 Remote OSPF 30d09h06m 10 + 192.168.1.12 45 +10.30.2.0/24 Remote OSPF 11d19h56m 150 + 192.168.1.14 0 +192.168.10.23/32 Remote OSPF 30d09h06m 10 + 192.168.1.12 45 +192.168.10.41/32 Remote OSPF 09d08h39m 10 + 192.168.1.12 41 +192.168.1.10/32 Local Local 99d00h42m 0 + system 0 +192.168.1.20/32 Remote OSPF 30d09h06m 10 + 192.168.1.12 41 +192.168.1.21/32 Remote OSPF 30d09h02m 10 + 192.168.1.14 41 +192.168.1.22/32 Remote OSPF 01d09h39m 10 + 192.168.1.12 41 +192.168.1.23/32 Remote OSPF 03d07h36m 10 + 192.168.1.12 41 +192.168.1.30/32 Remote OSPF 30d09h06m 10 + 192.168.1.12 40 +192.168.1.31/32 Remote OSPF 30d09h02m 10 + 192.168.1.14 40 +192.168.1.32/31 Remote OSPF 30d09h02m 10 + 192.168.1.14 41 +192.168.1.40/31 Local Local 60d02h46m 0 + to-DEVICE-A01 0 +192.168.1.42/31 Local Local 43d09h23m 0 + to-DEVICE-A02 0 +192.168.1.44/31 Remote OSPF 03d07h43m 10 + 192.168.1.12 81 +192.168.1.46/31 Remote OSPF 30d09h06m 10 + 192.168.1.12 41 +192.168.1.50/31 Remote OSPF 01d09h39m 10 + 192.168.1.12 41 +192.168.1.60/31 Remote OSPF 11h32m08s 10 + 192.168.1.14 41 +192.168.1.62/31 Remote OSPF 03d07h36m 10 + 192.168.1.12 81 +192.168.1.64/31 Remote OSPF 03d07h36m 10 + 192.168.1.12 41 +172.20.0.0/24 Remote OSPF 16d04h33m 10 + 192.168.1.14 1041 +172.20.2.0/24 Remote OSPF 03d07h36m 10 + 192.168.1.14 1041 +172.20.3.0/24 Remote OSPF 16d04h25m 10 + 192.168.1.14 1041 +172.20.4.0/24 Remote OSPF 01d09h38m 10 + 192.168.1.14 1041 +172.20.255.0/24 Remote OSPF 11d19h56m 150 + 192.168.1.14 0 +198.51.100.0/28 Remote OSPF 30d09h02m 10 + 192.168.1.14 1041 +198.51.100.16/28 Remote OSPF 02d18h22m 150 + 192.168.1.12 1 +198.51.100.32/28 Remote OSPF 02d18h22m 150 + 192.168.1.12 1 +198.51.100.48/29 Remote OSPF 30d09h02m 10 + 192.168.1.14 1041 +198.51.100.64/29 Remote OSPF 03d07h35m 10 + 192.168.1.14 1041 +198.51.100.80/29 Remote OSPF 30d09h02m 10 + 192.168.1.14 1041 +198.51.100.96/29 Remote OSPF 01d09h38m 10 + 192.168.1.14 1041 +203.0.113.0/24 Remote OSPF 30d09h02m 10 + 192.168.1.14 1041 +203.0.113.16/24 Remote OSPF 30d09h02m 10 + 192.168.1.14 1041 +203.0.113.32/24 Remote OSPF 01d09h38m 10 + 192.168.1.14 1041 +203.0.113.48/25 Remote OSPF 03d07h35m 10 + 192.168.1.14 1041 +10.0.0.0/12 Remote OSPF 11d19h56m 150 + 192.168.1.14 0 +------------------------------------------------------------------------------- +No. of Routes: 41 +Flags: n = Number of times nexthop is repeated + B = BGP backup route available + L = LFA nexthop available + S = Sticky ECMP requested +=============================================================================== \ No newline at end of file diff --git a/configs/nokia_isam/templates/show service fdb-mac.txt b/configs/nokia_isam/templates/show service fdb-mac.txt new file mode 100644 index 0000000000000000000000000000000000000000..aab6a92475bb01dcc903112bd2da5eea5ba9b2d2 --- /dev/null +++ b/configs/nokia_isam/templates/show service fdb-mac.txt @@ -0,0 +1,17 @@ +=============================================================================== +Service Forwarding Database +=============================================================================== +ServId MAC Source-Identifier Type Last Change + Age +------------------------------------------------------------------------------- +886 00:11:22:33:44:55 sdp:100:200 L/0 06/12/25 14:44:23 +8050 00:11:22:33:44:55 sdp:100:8050 L/0 06/12/25 14:44:23 +8050 aa:bb:cc:dd:ee:01 sap:lt:1/1/1:101 L/0 06/24/25 17:25:43 +8050 aa:bb:cc:dd:ee:02 sap:lt:1/1/1:101 L/0 06/17/25 03:13:06 +8050 aa:bb:cc:dd:ee:03 sap:lt:1/1/2:101 L/0 06/26/25 15:33:01 +8050 aa:bb:cc:dd:ee:04 sdp:100:8050 L/0 06/12/25 14:44:22 +------------------------------------------------------------------------------- +No. of Entries: 6 +------------------------------------------------------------------------------- +Legend: L=Learned; P=MAC is protected +=============================================================================== \ No newline at end of file diff --git a/configs/nokia_isam/templates/show software-mngt version ansi.txt b/configs/nokia_isam/templates/show software-mngt version ansi.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b838cbafdcef5ed69ec8ec74f8c8b52ba107285 --- /dev/null +++ b/configs/nokia_isam/templates/show software-mngt version ansi.txt @@ -0,0 +1,5 @@ +============================================================================================================================================================================================================================== +ansi table +============================================================================================================================================================================================================================== + isam-feature-group : R6.5.02rh +============================================================================================================================================================================================================================== \ No newline at end of file diff --git a/configs/raisecom_roap/templates/show link-aggregation.txt b/configs/raisecom_roap/templates/show link-aggregation.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6aa8b7d3a5fa78033230576fcd19aa5fba085b8 --- /dev/null +++ b/configs/raisecom_roap/templates/show link-aggregation.txt @@ -0,0 +1,27 @@ +Link aggregation status: Enable +Load sharing mode: SXORDMAC +Load sharing ticket generation algorithm: N/A +Link aggregation destination-address: 0000.1111.2222 + +Group information: + +GroupID : 1 Mode : Manual +MinLinks : 1 MaxLinks : 4 +UpLinks : 0 Master Port : +Restore Mode : non-revertive Restore delay(s): 1800 +Member Port : +Efficient Port : + +GroupID : 2 Mode : Manual +MinLinks : 1 MaxLinks : 4 +UpLinks : 0 Master Port : +Restore Mode : non-revertive Restore delay(s): 1800 +Member Port : +Efficient Port : + +GroupID : 3 Mode : Manual +MinLinks : 1 MaxLinks : 4 +UpLinks : 0 Master Port : +Restore Mode : non-revertive Restore delay(s): 1800 +Member Port : +Efficient Port : \ No newline at end of file diff --git a/configs/silverpeak_vxoa/netconf/get-config.xml b/configs/silverpeak_vxoa/netconf/get-config.xml new file mode 100644 index 0000000000000000000000000000000000000000..4a8b361304ee3c15fcd1f03bf3ffbd706cbd0b19 --- /dev/null +++ b/configs/silverpeak_vxoa/netconf/get-config.xml @@ -0,0 +1,7 @@ + + + + Hello from silverpeak_vxoa! + + diff --git a/configs/silverpeak_vxoa/scripts/__init__.py b/configs/silverpeak_vxoa/scripts/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..20ab2f609be071b11183234a754a553ac8b6eaf8 --- /dev/null +++ b/configs/silverpeak_vxoa/scripts/__init__.py @@ -0,0 +1,3 @@ +# from src.ssh_server.db_operations import create_table, create_record, read_record, update_record, delete_record +def handle_command(command: str): + return "" \ No newline at end of file diff --git a/configs/silverpeak_vxoa/silverpeak_vxoa_server.py b/configs/silverpeak_vxoa/silverpeak_vxoa_server.py new file mode 100644 index 0000000000000000000000000000000000000000..681a4eb17c337ea62c359a1f02ee54d8c41a5530 --- /dev/null +++ b/configs/silverpeak_vxoa/silverpeak_vxoa_server.py @@ -0,0 +1,14 @@ +from src.ssh_server.ssh_server import SSH_Server +from src.ssh_server.ssh_handler import SSH_Handler +from asyncssh.process import SSHServerProcess + +class silverpeak_vxoa_server(SSH_Server): + pass + +class silverpeak_vxoa_handler(SSH_Handler): + def __init__(self, process: SSHServerProcess, options): + options['device_type'] = 'silverpeak_vxoa' + super().__init__(process, options=options) + self.set_prompt_terminator(pri_terminator = "#", alt_terminator = ">") + + \ No newline at end of file diff --git a/configs/silverpeak_vxoa/templates/.gitkeep b/configs/silverpeak_vxoa/templates/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/dev/ssh_tester.py b/dev/ssh_tester.py index 667c222b95c1da680f76a93f88f6103dfe6dfbb6..b6a0593ad79c4541af997fe9171f48854828760e 100644 --- a/dev/ssh_tester.py +++ b/dev/ssh_tester.py @@ -1,11 +1,12 @@ from netmiko import ConnectHandler -def run_command(host, device_type, command, username="test", password="test"): +def run_command(host, device_type, command, username="test", password="test", secret="secret"): parameters = { "device_type": device_type, "host": host, # "username": username, # "password": password, + # "secret": secret, "use_keys": True, "key_file": "./auth_keys/auth", } diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 170ab182bec0e2ca86c94203d6413d1627ae2574..72ab92d189c31979df4a1e74005a226fc60d34d7 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -10,6 +10,8 @@ services: - NETCONF_PASSWORD=test - AUTHKEY_ENABLED=true - DEBUG_ENABLED=true + - ENABLE_MODE=true + - ENABLE_SECRET=secret # - OPENAI_SUPPORT=true # - DEVICE_VERSION=v6 # - DEVICE_DELAY=1 diff --git a/src/options.py b/src/options.py index d88282f162ce05f42565c12afa6be31940c2457d..7fc99ec15ab552937ef8a41431bc35696f065e6a 100644 --- a/src/options.py +++ b/src/options.py @@ -77,6 +77,8 @@ def get_options(): "device_version": device_version, "authkey_enabled": get_opt("AUTHKEY_ENABLED", "false", as_bool=True), "authkey_path": os.environ.get("AUTHKEY_PATH", ""), + "enable_mode": get_opt("ENABLE_MODE", "false", as_bool=True), + "enable_secret": get_opt("ENABLE_SECRET", ""), "port": int(get_opt("SSH_PORT", '22')), }, 'snmp': { diff --git a/src/ssh_server/ssh_handler.py b/src/ssh_server/ssh_handler.py index 988ed9066396a5cd891a93e9f873ce15ab5e666b..b2494422c1fe0156a35161d804169062845b72d2 100644 --- a/src/ssh_server/ssh_handler.py +++ b/src/ssh_server/ssh_handler.py @@ -25,12 +25,20 @@ class SSH_Handler: self.new_line = options['new_line'] self.pri_terminator = "#" self.alt_terminator = ">" - self.enable = True self.config_mode = False self.config_pattern = "..#" self.delay = options['delay'] self.break_commands = ['exit', 'quit', 'logout', r'\q'] self.handle_script_function = None + + # Password protection for enable command + self.enable_mode = options.get('enable_mode', False) + self.enable_secret = options.get('enable_secret', '') + self.enable = False + + self.password_required = False + self.password_attempts = 0 + self.max_password_attempts = 3 config_dir = f"configs/{self.device_type}" if self.device_version: config_dir +=f"/{self.device_version}" @@ -236,12 +244,28 @@ class SSH_Handler: return True if command in self.break_commands: - return False + if self.enable: + self.enable = False + self.set_prompt_terminator(pri_terminator = self.pri_terminator, alt_terminator = self.alt_terminator) + return True + else: + return False # Handle enable and disable command - if command == "enable" or command == "disable": - self.enable = command == "enable" - self.set_prompt_terminator(pri_terminator = self.pri_terminator, alt_terminator = self.alt_terminator) + if self.enable_mode: + if command == "enable" or command == "system-view" or command == "sudo": + # Require password for enable command + if await self.prompt_password(): + self.enable = True + self.set_prompt_terminator(pri_terminator = self.pri_terminator, alt_terminator = self.alt_terminator) + else: + # Password failed, stay in user mode + self.enable = False + self.set_prompt_terminator(pri_terminator = self.pri_terminator, alt_terminator = self.alt_terminator) + elif command == "disable": # disable command + self.enable = False + self.set_prompt_terminator(pri_terminator = self.pri_terminator, alt_terminator = self.alt_terminator) + return True if self.openai_support: self.respond(self.get_ai_output(command)) @@ -329,7 +353,7 @@ class SSH_Handler: @property def terminator(self): - return self.pri_terminator if self.enable else self.alt_terminator + return self.pri_terminator if self.enable or not self.enable_mode else self.alt_terminator @staticmethod def _read_file(filename): @@ -354,6 +378,35 @@ class SSH_Handler: # Join the lines back into a single string return "\n".join(lines) + async def prompt_password(self): + """ + Prompts the user for enable password and validates it. + Returns True if password is correct, False otherwise. + """ + if self.enable_secret == "": + return True + + self.password_required = True + self.respond("Password: ") + + # Read password input (it won't be echoed) + password = await self.process.stdin.readline() + password = password.strip() + + self.password_required = False + + if password == self.enable_secret: + self.password_attempts = 0 + return True + else: + self.password_attempts += 1 + if self.password_attempts >= self.max_password_attempts: + self.respond("Access denied. Too many incorrect attempts.") + return False + else: + self.respond("Access denied.") + return False + def respond(self, response = ""): """ Sends a response back to the SSH client. diff --git a/tests/README.md b/tests/README.md index 64f2a2ac4b6abb3c6ad01d08ce25ecded502596a..21983f9fdcfc28120f95e5b6ea3c2d630b318329 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,18 +1,11 @@ +# Navigate to the tests directory +cd /home/osboxes/Documents/Slurpit/mockit/tests -# Test all devices +# Start the test environment +docker compose -f compose-dev_ssh_telnet.yml up -d --build -```sh -docker compose -f docker-compose_set1.yml up -d --build -``` +# Run the tests +docker exec devices-test_container sh -c "pytest test_ssh_telnet.py -v" -```sh -docker exec devices_test_container sh -c "pytest test_ssh_set1.py | tee /output.txt" -``` - -```sh -docker cp devices_test_container:/output.txt . -``` - -```sh -docker compose -f docker-compose_set1.yml down -``` +# Clean up when done +docker compose -f compose-dev_ssh_telnet.yml down \ No newline at end of file diff --git a/tests/test_ssh_telnet.py b/tests/test_ssh_telnet.py index 66bf45d94cae8391b55e0344b715127f728f71f8..c6740b9ebcfa94a5e3d731c77b4486b18320d5f1 100644 --- a/tests/test_ssh_telnet.py +++ b/tests/test_ssh_telnet.py @@ -206,6 +206,19 @@ DEVICE_VERSIONS = { "mikrotik_routeros": ["v6", "v7"] } +# Devices that should have enable mode enabled during testing +DEVICES_WITH_ENABLE_MODE = { + "apresia_aeos": True, + "huawei_olt": True, + "huawei_smartax": True + # Add more devices as needed +} + +# Enable secrets for devices (optional) +DEVICE_ENABLE_SECRETS = { + # Add more devices as needed +} + # modify here the set of platforms for reduced set when testing # SSH_PLATFORMS_SUPPORTED = [] # TELNET_PLATFORMS_SUPPORTED = [] @@ -262,10 +275,12 @@ def get_ids_from_params(params): -def reconfigure_device(device_type: str, version: str | None, enable_telnet: bool): +def reconfigure_device(device_type: str, version: str | None, enable_telnet: bool, enable_mode: bool = False, enable_secret: str = ""): message = (f"DEVICE_TYPE={device_type}\n" f"DEVICE_VERSION={version or ''}\n" - f"TELNET_SERVER_ENABLED={bool(enable_telnet)}\n") + f"TELNET_SERVER_ENABLED={bool(enable_telnet)}\n" + f"ENABLE_MODE={str(enable_mode).lower()}\n" + f"ENABLE_SECRET={enable_secret}\n") sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: sock.bind(('', 0)) @@ -300,5 +315,48 @@ def run_command(device_type, telnet: bool): ) def test_mock_device(device_type: str, version: str, telnet: bool, reconfigure: bool, start_telnet: bool): if reconfigure: - reconfigure_device(device_type, version, start_telnet) + # Check if this device should have enable mode enabled + enable_mode = DEVICES_WITH_ENABLE_MODE.get(device_type, False) + enable_secret = DEVICE_ENABLE_SECRETS.get(device_type, "") + reconfigure_device(device_type, version, start_telnet, enable_mode, enable_secret) assert run_command(device_type, telnet) == "test", 'telnet test failed' + + +def test_enable_mode_functionality(): + """Test enable mode functionality for devices that support it""" + test_devices = ["cisco_ios", "arista_eos", "juniper_junos"] + + for device_type in test_devices: + # Configure device with enable mode + enable_secret = DEVICE_ENABLE_SECRETS.get(device_type, "test123") + reconfigure_device(device_type, None, False, True, enable_secret) + + # Test SSH connection and enable command + platform = device_type + parameters = { + "device_type": platform, + "host": mocked_device, + "port": ssh_port, + "username": "root", + "password": "test", + "verbose": True, + "fast_cli": False, + "conn_timeout": 10, + } + + with ConnectHandler(**parameters) as net_connect: + # Test basic command first + result = net_connect.send_command('echo test') + assert result == "test", f'Basic command failed for {device_type}' + + # Test enable command (this should prompt for password) + # Note: This test might need adjustment based on how netmiko handles enable mode + try: + net_connect.enable() + # If enable succeeds, test privileged command + result = net_connect.send_command('show version') + assert result is not None, f'Enable mode failed for {device_type}' + except Exception as e: + # Enable might fail if password is required, which is expected + print(f"Enable mode test for {device_type}: {e}") + pass