lanet 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/index.html +256 -129
- data/lib/lanet/traceroute.rb +66 -92
- data/lib/lanet/version.rb +1 -1
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 0fa5904938004f84fe7b8d599da632140a532925cd0a0c48d5986d44443c0987
         | 
| 4 | 
            +
              data.tar.gz: f039a015dcd75704b7fe80f2a84afbd758505048e78bc86001b9821c1be7a353
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: ac7892c9bd9179483ea9ebb796fb567a11f79aab6197b1c49a11d2797167e91c59be5da17e861a3e08069bc4ff745eae8534e8cdcda516739906a8011ab9ffc8
         | 
| 7 | 
            +
              data.tar.gz: ef408dedc43f2461c69d0a00ae207f4bd139e06f171cb5cfd0fd6f40e58d2e0aa1bc59403428587f6982a378418ff241fecb1805254b37ea63d1a39ccc8116e3
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file. | |
| 5 5 | 
             
            The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
         | 
| 6 6 | 
             
            and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
         | 
| 7 7 |  | 
| 8 | 
            +
            ## [0.5.1] - 2025-03-20
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            ### Changed
         | 
| 11 | 
            +
            - Optimized traceroute implementation for better performance and code readability
         | 
| 12 | 
            +
            - Simplified protocol selection logic with dedicated methods
         | 
| 13 | 
            +
            - Improved error handling for socket operations
         | 
| 14 | 
            +
            - Enhanced hostname extraction in traceroute results
         | 
| 15 | 
            +
            - Reorganized code structure for better maintainability
         | 
| 16 | 
            +
            - Added Windows-specific socket handling optimizations
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            ### Fixed
         | 
| 19 | 
            +
            - Fixed redundant code in socket handling for different operating systems
         | 
| 20 | 
            +
            - Improved error messages for unprivileged traceroute attempts
         | 
| 21 | 
            +
            - Fixed potential memory leaks in socket resource management
         | 
| 22 | 
            +
            - Added proper handling for non-standard traceroute output formats
         | 
| 23 | 
            +
             | 
| 8 24 | 
             
            ## [0.5.0] - 2025-03-12
         | 
| 9 25 |  | 
| 10 26 | 
             
            ### Added
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -20,7 +20,7 @@ A lightweight, powerful LAN communication tool that enables secure message excha | |
| 20 20 | 
             
            - **Digital Signatures**: Ensure message authenticity and integrity
         | 
| 21 21 | 
             
            - **File Transfers**: Securely send encrypted files over the LAN with progress tracking and integrity verification
         | 
| 22 22 | 
             
            - **Mesh Networking**: Create resilient mesh networks for decentralized communication, enabling messages to be routed through multiple hops without central infrastructure
         | 
| 23 | 
            -
            - **Advanced Traceroute**: Analyze network paths using multiple protocols (ICMP, UDP, and TCP)
         | 
| 23 | 
            +
            - **Advanced Traceroute**: Analyze network paths using multiple protocols (ICMP, UDP, and TCP) with intelligent fallback mechanisms
         | 
| 24 24 |  | 
| 25 25 | 
             
            ## Security Features
         | 
| 26 26 |  | 
    
        data/index.html
    CHANGED
    
    | @@ -1,5 +1,6 @@ | |
| 1 1 | 
             
            <!DOCTYPE html>
         | 
| 2 2 | 
             
            <html lang="en">
         | 
| 3 | 
            +
             | 
| 3 4 | 
             
            <head>
         | 
| 4 5 | 
             
                <meta charset="UTF-8">
         | 
| 5 6 | 
             
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
         | 
| @@ -7,188 +8,297 @@ | |
| 7 8 | 
             
                <style>
         | 
| 8 9 | 
             
                    body {
         | 
| 9 10 | 
             
                        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
         | 
| 10 | 
            -
                        line-height: 1.7; | 
| 11 | 
            -
                         | 
| 12 | 
            -
                         | 
| 13 | 
            -
                         | 
| 11 | 
            +
                        line-height: 1.7;
         | 
| 12 | 
            +
                        /* Increased line height for better readability */
         | 
| 13 | 
            +
                        color: #34495e;
         | 
| 14 | 
            +
                        /* Darker, more professional text color */
         | 
| 15 | 
            +
                        max-width: 980px;
         | 
| 16 | 
            +
                        /* Slightly wider max width for content */
         | 
| 17 | 
            +
                        margin: 20px auto;
         | 
| 18 | 
            +
                        /* Added top and bottom margin for better spacing */
         | 
| 14 19 | 
             
                        padding: 20px;
         | 
| 15 | 
            -
                        background-color: #f4f6f9; | 
| 20 | 
            +
                        background-color: #f4f6f9;
         | 
| 21 | 
            +
                        /* Lighter background color */
         | 
| 16 22 | 
             
                    }
         | 
| 23 | 
            +
             | 
| 17 24 | 
             
                    h1 {
         | 
| 18 | 
            -
                        color: #34495e; | 
| 19 | 
            -
                         | 
| 20 | 
            -
                         | 
| 21 | 
            -
                         | 
| 25 | 
            +
                        color: #34495e;
         | 
| 26 | 
            +
                        /* Darker heading color */
         | 
| 27 | 
            +
                        border-bottom: 3px solid #3498db;
         | 
| 28 | 
            +
                        /* Thicker border */
         | 
| 29 | 
            +
                        padding-bottom: 12px;
         | 
| 30 | 
            +
                        /* Increased padding */
         | 
| 31 | 
            +
                        letter-spacing: -0.5px;
         | 
| 32 | 
            +
                        /* Slightly tighter letter spacing for headings */
         | 
| 22 33 | 
             
                    }
         | 
| 34 | 
            +
             | 
| 23 35 | 
             
                    h2 {
         | 
| 24 | 
            -
                        color: #3498db; | 
| 25 | 
            -
                         | 
| 26 | 
            -
                        margin- | 
| 36 | 
            +
                        color: #3498db;
         | 
| 37 | 
            +
                        /* Primary blue color for subheadings */
         | 
| 38 | 
            +
                        margin-top: 35px;
         | 
| 39 | 
            +
                        /* Increased top margin */
         | 
| 40 | 
            +
                        margin-bottom: 10px;
         | 
| 41 | 
            +
                        /* Added bottom margin */
         | 
| 27 42 | 
             
                    }
         | 
| 43 | 
            +
             | 
| 28 44 | 
             
                    h3 {
         | 
| 29 | 
            -
                        color: #2ecc71; | 
| 45 | 
            +
                        color: #2ecc71;
         | 
| 46 | 
            +
                        /* Vibrant green for section titles */
         | 
| 30 47 | 
             
                        margin-top: 30px;
         | 
| 31 48 | 
             
                        margin-bottom: 8px;
         | 
| 32 49 | 
             
                    }
         | 
| 50 | 
            +
             | 
| 33 51 | 
             
                    h4 {
         | 
| 34 | 
            -
                        color: #34495e; | 
| 52 | 
            +
                        color: #34495e;
         | 
| 53 | 
            +
                        /* Darker color for sub-subheadings */
         | 
| 35 54 | 
             
                        margin-top: 25px;
         | 
| 36 55 | 
             
                        margin-bottom: 5px;
         | 
| 37 56 | 
             
                    }
         | 
| 57 | 
            +
             | 
| 38 58 | 
             
                    p {
         | 
| 39 | 
            -
                        margin-bottom: 15px; | 
| 40 | 
            -
                         | 
| 59 | 
            +
                        margin-bottom: 15px;
         | 
| 60 | 
            +
                        /* Increased paragraph spacing */
         | 
| 61 | 
            +
                        color: #555;
         | 
| 62 | 
            +
                        /* Slightly softer paragraph text color */
         | 
| 41 63 | 
             
                    }
         | 
| 42 | 
            -
             | 
| 64 | 
            +
             | 
| 65 | 
            +
                    ul,
         | 
| 66 | 
            +
                    ol {
         | 
| 43 67 | 
             
                        margin-bottom: 15px;
         | 
| 44 68 | 
             
                        color: #555;
         | 
| 45 69 | 
             
                    }
         | 
| 70 | 
            +
             | 
| 46 71 | 
             
                    pre {
         | 
| 47 | 
            -
                        background-color: #f0f0f0; | 
| 48 | 
            -
                         | 
| 49 | 
            -
                        border | 
| 50 | 
            -
                         | 
| 72 | 
            +
                        background-color: #f0f0f0;
         | 
| 73 | 
            +
                        /* Slightly darker pre background */
         | 
| 74 | 
            +
                        border: 1px solid #ccc;
         | 
| 75 | 
            +
                        /* Lighter border */
         | 
| 76 | 
            +
                        border-left: 5px solid #3498db;
         | 
| 77 | 
            +
                        /* Thicker, more prominent left border */
         | 
| 78 | 
            +
                        padding: 16px;
         | 
| 79 | 
            +
                        /* Increased padding */
         | 
| 51 80 | 
             
                        overflow-x: auto;
         | 
| 52 | 
            -
                        border-radius: 6px; | 
| 53 | 
            -
                         | 
| 81 | 
            +
                        border-radius: 6px;
         | 
| 82 | 
            +
                        /* More rounded corners */
         | 
| 83 | 
            +
                        font-size: 0.95em;
         | 
| 84 | 
            +
                        /* Slightly smaller font size in code blocks */
         | 
| 54 85 | 
             
                    }
         | 
| 86 | 
            +
             | 
| 55 87 | 
             
                    code {
         | 
| 56 88 | 
             
                        font-family: 'Courier New', Courier, monospace;
         | 
| 57 | 
            -
                        color: #2c3e50; | 
| 89 | 
            +
                        color: #2c3e50;
         | 
| 90 | 
            +
                        /* Darker code text color */
         | 
| 58 91 | 
             
                    }
         | 
| 92 | 
            +
             | 
| 59 93 | 
             
                    .container {
         | 
| 60 94 | 
             
                        background-color: #fff;
         | 
| 61 | 
            -
                        border-radius: 10px; | 
| 62 | 
            -
                         | 
| 63 | 
            -
                         | 
| 95 | 
            +
                        border-radius: 10px;
         | 
| 96 | 
            +
                        /* More rounded container corners */
         | 
| 97 | 
            +
                        box-shadow: 0 3px 20px rgba(0, 0, 0, 0.08);
         | 
| 98 | 
            +
                        /* Softer, more subtle shadow */
         | 
| 99 | 
            +
                        padding: 40px;
         | 
| 100 | 
            +
                        /* Increased container padding */
         | 
| 64 101 | 
             
                    }
         | 
| 102 | 
            +
             | 
| 65 103 | 
             
                    .feature {
         | 
| 66 | 
            -
                        margin: 25px 0; | 
| 67 | 
            -
                         | 
| 68 | 
            -
                         | 
| 104 | 
            +
                        margin: 25px 0;
         | 
| 105 | 
            +
                        /* Increased feature margin */
         | 
| 106 | 
            +
                        padding-left: 25px;
         | 
| 107 | 
            +
                        /* Increased padding */
         | 
| 108 | 
            +
                        border-left: 5px solid #2ecc71;
         | 
| 109 | 
            +
                        /* Thicker feature border */
         | 
| 69 110 | 
             
                    }
         | 
| 111 | 
            +
             | 
| 70 112 | 
             
                    .security-feature {
         | 
| 71 113 | 
             
                        background-color: #e8f4fc;
         | 
| 72 | 
            -
                        padding: 20px; | 
| 73 | 
            -
                         | 
| 74 | 
            -
                         | 
| 114 | 
            +
                        padding: 20px;
         | 
| 115 | 
            +
                        /* Increased padding */
         | 
| 116 | 
            +
                        margin: 15px 0;
         | 
| 117 | 
            +
                        /* Increased margin */
         | 
| 118 | 
            +
                        border-radius: 8px;
         | 
| 119 | 
            +
                        /* More rounded corners */
         | 
| 75 120 | 
             
                    }
         | 
| 121 | 
            +
             | 
| 76 122 | 
             
                    .security-feature ul li {
         | 
| 77 | 
            -
                        margin-bottom: 8px; | 
| 123 | 
            +
                        margin-bottom: 8px;
         | 
| 124 | 
            +
                        /* Spacing in security feature lists */
         | 
| 78 125 | 
             
                    }
         | 
| 126 | 
            +
             | 
| 79 127 | 
             
                    .cli-example {
         | 
| 80 128 | 
             
                        background-color: #2c3e50;
         | 
| 81 129 | 
             
                        color: #ecf0f1;
         | 
| 82 | 
            -
                        padding: 15px 20px; | 
| 83 | 
            -
                         | 
| 84 | 
            -
                         | 
| 130 | 
            +
                        padding: 15px 20px;
         | 
| 131 | 
            +
                        /* Increased padding */
         | 
| 132 | 
            +
                        margin: 15px 0;
         | 
| 133 | 
            +
                        /* Increased margin */
         | 
| 134 | 
            +
                        border-radius: 8px;
         | 
| 135 | 
            +
                        /* More rounded corners */
         | 
| 85 136 | 
             
                        font-family: 'Courier New', Courier, monospace;
         | 
| 86 137 | 
             
                        position: relative;
         | 
| 87 | 
            -
                        font-size: 0.95em; | 
| 138 | 
            +
                        font-size: 0.95em;
         | 
| 139 | 
            +
                        /* Slightly smaller font size in CLI examples */
         | 
| 88 140 | 
             
                    }
         | 
| 141 | 
            +
             | 
| 89 142 | 
             
                    .cli-example::before {
         | 
| 90 143 | 
             
                        content: "$";
         | 
| 91 144 | 
             
                        color: #3498db;
         | 
| 92 | 
            -
                        margin-right: 12px; | 
| 145 | 
            +
                        margin-right: 12px;
         | 
| 146 | 
            +
                        /* Increased margin */
         | 
| 93 147 | 
             
                        font-weight: bold;
         | 
| 94 | 
            -
                        display: inline-block; | 
| 95 | 
            -
                         | 
| 96 | 
            -
                         | 
| 148 | 
            +
                        display: inline-block;
         | 
| 149 | 
            +
                        /* Ensure proper spacing */
         | 
| 150 | 
            +
                        width: 15px;
         | 
| 151 | 
            +
                        /* Fixed width for the dollar sign to align commands */
         | 
| 152 | 
            +
                        text-align: right;
         | 
| 153 | 
            +
                        /* Align dollar sign to the right */
         | 
| 97 154 | 
             
                    }
         | 
| 155 | 
            +
             | 
| 98 156 | 
             
                    .cli-section {
         | 
| 99 | 
            -
                        margin-bottom: 40px; | 
| 157 | 
            +
                        margin-bottom: 40px;
         | 
| 158 | 
            +
                        /* Increased bottom margin */
         | 
| 100 159 | 
             
                        background-color: #f8f9fa;
         | 
| 101 | 
            -
                        padding: 25px; | 
| 102 | 
            -
                         | 
| 160 | 
            +
                        padding: 25px;
         | 
| 161 | 
            +
                        /* Increased padding */
         | 
| 162 | 
            +
                        border-radius: 8px;
         | 
| 163 | 
            +
                        /* More rounded corners */
         | 
| 103 164 | 
             
                    }
         | 
| 165 | 
            +
             | 
| 104 166 | 
             
                    .output-example {
         | 
| 105 167 | 
             
                        background-color: #f0f0f0;
         | 
| 106 | 
            -
                        padding: 15px; | 
| 107 | 
            -
                         | 
| 108 | 
            -
                         | 
| 168 | 
            +
                        padding: 15px;
         | 
| 169 | 
            +
                        /* Increased padding */
         | 
| 170 | 
            +
                        margin: 15px 0;
         | 
| 171 | 
            +
                        /* Increased margin */
         | 
| 172 | 
            +
                        border-radius: 8px;
         | 
| 173 | 
            +
                        /* More rounded corners */
         | 
| 109 174 | 
             
                        font-family: 'Courier New', Courier, monospace;
         | 
| 110 175 | 
             
                        font-size: 0.9em;
         | 
| 111 | 
            -
                        border-left: 5px solid #9b59b6; | 
| 176 | 
            +
                        border-left: 5px solid #9b59b6;
         | 
| 177 | 
            +
                        /* Thicker border */
         | 
| 112 178 | 
             
                    }
         | 
| 179 | 
            +
             | 
| 113 180 | 
             
                    .tab-container {
         | 
| 114 181 | 
             
                        border: 1px solid #ddd;
         | 
| 115 | 
            -
                        border-radius: 8px; | 
| 182 | 
            +
                        border-radius: 8px;
         | 
| 183 | 
            +
                        /* More rounded corners */
         | 
| 116 184 | 
             
                        overflow: hidden;
         | 
| 117 | 
            -
                        margin: 25px 0; | 
| 185 | 
            +
                        margin: 25px 0;
         | 
| 186 | 
            +
                        /* Increased margin */
         | 
| 118 187 | 
             
                    }
         | 
| 188 | 
            +
             | 
| 119 189 | 
             
                    .tab-buttons {
         | 
| 120 190 | 
             
                        display: flex;
         | 
| 121 191 | 
             
                        background-color: #f5f5f5;
         | 
| 122 | 
            -
                        border-bottom: 1px solid #ddd; | 
| 192 | 
            +
                        border-bottom: 1px solid #ddd;
         | 
| 193 | 
            +
                        /* Added bottom border to tab buttons container */
         | 
| 123 194 | 
             
                    }
         | 
| 195 | 
            +
             | 
| 124 196 | 
             
                    .tab-button {
         | 
| 125 | 
            -
                        padding: 12px 25px; | 
| 197 | 
            +
                        padding: 12px 25px;
         | 
| 198 | 
            +
                        /* Increased padding */
         | 
| 126 199 | 
             
                        background-color: transparent;
         | 
| 127 200 | 
             
                        border: none;
         | 
| 128 201 | 
             
                        cursor: pointer;
         | 
| 129 | 
            -
                        border-right: none; | 
| 202 | 
            +
                        border-right: none;
         | 
| 203 | 
            +
                        /* Removed right border */
         | 
| 130 204 | 
             
                        transition: background-color 0.3s;
         | 
| 131 | 
            -
                        font-weight: 500; | 
| 132 | 
            -
                         | 
| 205 | 
            +
                        font-weight: 500;
         | 
| 206 | 
            +
                        /* Slightly bolder tab button text */
         | 
| 207 | 
            +
                        color: #777;
         | 
| 208 | 
            +
                        /* Slightly muted tab button text color */
         | 
| 133 209 | 
             
                    }
         | 
| 210 | 
            +
             | 
| 134 211 | 
             
                    .tab-button:hover {
         | 
| 135 | 
            -
                        background-color: #f0f0f0; | 
| 136 | 
            -
                         | 
| 212 | 
            +
                        background-color: #f0f0f0;
         | 
| 213 | 
            +
                        /* Lighter hover background */
         | 
| 214 | 
            +
                        color: #555;
         | 
| 215 | 
            +
                        /* Darker hover text color */
         | 
| 137 216 | 
             
                    }
         | 
| 217 | 
            +
             | 
| 138 218 | 
             
                    .tab-button.active {
         | 
| 139 | 
            -
                        background-color: #fff; | 
| 140 | 
            -
                         | 
| 141 | 
            -
                         | 
| 142 | 
            -
                         | 
| 219 | 
            +
                        background-color: #fff;
         | 
| 220 | 
            +
                        /* White background for active tab */
         | 
| 221 | 
            +
                        border-bottom: 3px solid #3498db;
         | 
| 222 | 
            +
                        /* Underline for active tab */
         | 
| 223 | 
            +
                        color: #34495e;
         | 
| 224 | 
            +
                        /* Darker text for active tab */
         | 
| 225 | 
            +
                        font-weight: bold;
         | 
| 226 | 
            +
                        /* Bold text for active tab */
         | 
| 143 227 | 
             
                    }
         | 
| 228 | 
            +
             | 
| 144 229 | 
             
                    .tab-content {
         | 
| 145 230 | 
             
                        display: none;
         | 
| 146 | 
            -
                        padding: 20px; | 
| 147 | 
            -
                         | 
| 231 | 
            +
                        padding: 20px;
         | 
| 232 | 
            +
                        /* Increased padding */
         | 
| 233 | 
            +
                        background-color: #fff;
         | 
| 234 | 
            +
                        /* White background for tab content */
         | 
| 148 235 | 
             
                    }
         | 
| 236 | 
            +
             | 
| 149 237 | 
             
                    .tab-content.active {
         | 
| 150 238 | 
             
                        display: block;
         | 
| 151 239 | 
             
                    }
         | 
| 240 | 
            +
             | 
| 152 241 | 
             
                    .badge {
         | 
| 153 242 | 
             
                        display: inline-block;
         | 
| 154 | 
            -
                        padding: 4px 10px; | 
| 155 | 
            -
                         | 
| 156 | 
            -
                         | 
| 157 | 
            -
                         | 
| 158 | 
            -
                         | 
| 243 | 
            +
                        padding: 4px 10px;
         | 
| 244 | 
            +
                        /* Increased badge padding */
         | 
| 245 | 
            +
                        border-radius: 6px;
         | 
| 246 | 
            +
                        /* More rounded corners */
         | 
| 247 | 
            +
                        font-size: 13px;
         | 
| 248 | 
            +
                        /* Slightly larger font size */
         | 
| 249 | 
            +
                        font-weight: 600;
         | 
| 250 | 
            +
                        /* Bolder badge text */
         | 
| 251 | 
            +
                        letter-spacing: 0.5px;
         | 
| 252 | 
            +
                        /* Added letter spacing */
         | 
| 159 253 | 
             
                    }
         | 
| 254 | 
            +
             | 
| 160 255 | 
             
                    .badge-new {
         | 
| 161 256 | 
             
                        background-color: #2ecc71;
         | 
| 162 257 | 
             
                        color: white;
         | 
| 163 258 | 
             
                    }
         | 
| 259 | 
            +
             | 
| 164 260 | 
             
                    .note {
         | 
| 165 261 | 
             
                        background-color: #fff8e1;
         | 
| 166 | 
            -
                        padding: 15px; | 
| 167 | 
            -
                         | 
| 168 | 
            -
                         | 
| 169 | 
            -
                         | 
| 262 | 
            +
                        padding: 15px;
         | 
| 263 | 
            +
                        /* Increased padding */
         | 
| 264 | 
            +
                        border-left: 5px solid #ffc107;
         | 
| 265 | 
            +
                        /* Thicker border */
         | 
| 266 | 
            +
                        margin: 15px 0;
         | 
| 267 | 
            +
                        /* Increased margin */
         | 
| 268 | 
            +
                        border-radius: 6px;
         | 
| 269 | 
            +
                        /* More rounded corners */
         | 
| 170 270 | 
             
                    }
         | 
| 271 | 
            +
             | 
| 171 272 | 
             
                    .note strong {
         | 
| 172 273 | 
             
                        font-weight: bold;
         | 
| 173 | 
            -
                        color: #333; | 
| 274 | 
            +
                        color: #333;
         | 
| 275 | 
            +
                        /* Make "Note:" bold and slightly darker */
         | 
| 174 276 | 
             
                    }
         | 
| 277 | 
            +
             | 
| 175 278 | 
             
                    footer {
         | 
| 176 | 
            -
                        margin-top: 50px; | 
| 279 | 
            +
                        margin-top: 50px;
         | 
| 280 | 
            +
                        /* Increased footer margin */
         | 
| 177 281 | 
             
                        text-align: center;
         | 
| 178 282 | 
             
                        color: #7f8c8d;
         | 
| 179 283 | 
             
                        padding-top: 20px;
         | 
| 180 | 
            -
                        border-top: 1px solid #ddd; | 
| 284 | 
            +
                        border-top: 1px solid #ddd;
         | 
| 285 | 
            +
                        /* Added top border to footer */
         | 
| 181 286 | 
             
                    }
         | 
| 287 | 
            +
             | 
| 182 288 | 
             
                    footer p {
         | 
| 183 | 
            -
                        color: #95a5a6; | 
| 184 | 
            -
                         | 
| 289 | 
            +
                        color: #95a5a6;
         | 
| 290 | 
            +
                        /* Softer footer text color */
         | 
| 291 | 
            +
                        font-size: 0.9em;
         | 
| 292 | 
            +
                        /* Smaller footer font size */
         | 
| 185 293 | 
             
                    }
         | 
| 186 294 | 
             
                </style>
         | 
| 187 295 | 
             
            </head>
         | 
| 296 | 
            +
             | 
| 188 297 | 
             
            <body>
         | 
| 189 298 | 
             
                <div class="container">
         | 
| 190 299 | 
             
                    <h1>Lanet</h1>
         | 
| 191 | 
            -
                    <p>A secure network communication library that enables reliable and protected message exchange between devices | 
| 300 | 
            +
                    <p>A secure network communication library that enables reliable and protected message exchange between devices
         | 
| 301 | 
            +
                        on the same network.</p>
         | 
| 192 302 |  | 
| 193 303 | 
             
                    <h2>Key Features</h2>
         | 
| 194 304 |  | 
| @@ -205,9 +315,11 @@ | |
| 205 315 | 
             
                            <h4>Benefits of Digital Signatures:</h4>
         | 
| 206 316 | 
             
                            <ul>
         | 
| 207 317 | 
             
                                <li><strong>Authentication</strong>: Verify that the message came from the claimed sender</li>
         | 
| 208 | 
            -
                                <li><strong>Data Integrity</strong>: Ensure the message hasn't been tampered with during transit | 
| 318 | 
            +
                                <li><strong>Data Integrity</strong>: Ensure the message hasn't been tampered with during transit
         | 
| 319 | 
            +
                                </li>
         | 
| 209 320 | 
             
                                <li><strong>Non-repudiation</strong>: Senders cannot deny sending a message they signed</li>
         | 
| 210 | 
            -
                                <li><strong>Protection against MITM attacks</strong>: Detect man-in-the-middle tampering attempts | 
| 321 | 
            +
                                <li><strong>Protection against MITM attacks</strong>: Detect man-in-the-middle tampering attempts
         | 
| 322 | 
            +
                                </li>
         | 
| 211 323 | 
             
                            </ul>
         | 
| 212 324 | 
             
                        </div>
         | 
| 213 325 | 
             
                    </div>
         | 
| @@ -224,13 +336,15 @@ | |
| 224 336 |  | 
| 225 337 | 
             
                    <div class="feature">
         | 
| 226 338 | 
             
                        <h3>File Transfer <span class="badge badge-new">New in v0.3.0</span></h3>
         | 
| 227 | 
            -
                        <p>Securely transfer files between devices with encryption, digital signatures, and integrity verification | 
| 339 | 
            +
                        <p>Securely transfer files between devices with encryption, digital signatures, and integrity verification.
         | 
| 340 | 
            +
                        </p>
         | 
| 228 341 | 
             
                    </div>
         | 
| 229 342 |  | 
| 230 343 | 
             
                    <div class="feature">
         | 
| 231 344 | 
             
                        <h3>Mesh Networking <span class="badge badge-new">New in v0.4.0</span></h3>
         | 
| 232 | 
            -
                        <p>Create resilient, decentralized mesh networks that enable communication between devices even without | 
| 233 | 
            -
             | 
| 345 | 
            +
                        <p>Create resilient, decentralized mesh networks that enable communication between devices even without
         | 
| 346 | 
            +
                            direct connectivity.</p>
         | 
| 347 | 
            +
             | 
| 234 348 | 
             
                        <div class="security-feature">
         | 
| 235 349 | 
             
                            <h4>Benefits of Mesh Networking:</h4>
         | 
| 236 350 | 
             
                            <ul>
         | 
| @@ -244,17 +358,24 @@ | |
| 244 358 | 
             
                    </div>
         | 
| 245 359 |  | 
| 246 360 | 
             
                    <div class="feature">
         | 
| 247 | 
            -
                        <h3>Advanced Traceroute <span class="badge badge-new">New in v0.5. | 
| 248 | 
            -
                        <p>Analyze network paths with multi-protocol traceroute capabilities to understand connectivity and | 
| 249 | 
            -
             | 
| 361 | 
            +
                        <h3>Advanced Traceroute <span class="badge badge-new">New in v0.5.1</span></h3>
         | 
| 362 | 
            +
                        <p>Analyze network paths with multi-protocol traceroute capabilities to understand connectivity and
         | 
| 363 | 
            +
                            troubleshoot network issues.</p>
         | 
| 364 | 
            +
             | 
| 250 365 | 
             
                        <div class="security-feature">
         | 
| 251 366 | 
             
                            <h4>Features of Advanced Traceroute:</h4>
         | 
| 252 367 | 
             
                            <ul>
         | 
| 253 | 
            -
                                <li><strong>Multi-protocol support</strong>: Use ICMP, UDP, or TCP protocols for different network | 
| 254 | 
            -
             | 
| 368 | 
            +
                                <li><strong>Multi-protocol support</strong>: Use ICMP, UDP, or TCP protocols for different network
         | 
| 369 | 
            +
                                    environments</li>
         | 
| 370 | 
            +
                                <li><strong>Load balancing detection</strong>: Identify multi-path routing and load balancers in the
         | 
| 371 | 
            +
                                    network</li>
         | 
| 255 372 | 
             
                                <li><strong>Response time analysis</strong>: Measure latency at each hop in the network path</li>
         | 
| 256 | 
            -
                                <li><strong>Customizable parameters</strong>: Adjust max hops, timeouts, and query count for | 
| 257 | 
            -
             | 
| 373 | 
            +
                                <li><strong>Customizable parameters</strong>: Adjust max hops, timeouts, and query count for
         | 
| 374 | 
            +
                                    different scenarios</li>
         | 
| 375 | 
            +
                                <li><strong>Hostname resolution</strong>: Automatically resolve IP addresses to hostnames for easier
         | 
| 376 | 
            +
                                    identification</li>
         | 
| 377 | 
            +
                                <li><strong>Fallback mechanism</strong>: Automatically uses system traceroute when elevated
         | 
| 378 | 
            +
                                    permissions aren't available</li>
         | 
| 258 379 | 
             
                            </ul>
         | 
| 259 380 | 
             
                        </div>
         | 
| 260 381 | 
             
                    </div>
         | 
| @@ -262,7 +383,8 @@ | |
| 262 383 | 
             
                    <h2>Command Line Interface</h2>
         | 
| 263 384 |  | 
| 264 385 | 
             
                    <div class="note">
         | 
| 265 | 
            -
                        <strong>Note:</strong> All Lanet commands have detailed help available. Try | 
| 386 | 
            +
                        <strong>Note:</strong> All Lanet commands have detailed help available. Try
         | 
| 387 | 
            +
                        <code>lanet [command] --help</code> for more options.
         | 
| 266 388 | 
             
                    </div>
         | 
| 267 389 |  | 
| 268 390 | 
             
                    <div class="cli-section">
         | 
| @@ -280,12 +402,12 @@ | |
| 280 402 | 
             
                        </div>
         | 
| 281 403 |  | 
| 282 404 | 
             
                        <div class="output-example">
         | 
| 283 | 
            -
            Key pair generated!
         | 
| 284 | 
            -
            Private key saved to: /home/user/.lanet_keys/lanet_private.key
         | 
| 285 | 
            -
            Public key saved to: /home/user/.lanet_keys/lanet_public.key
         | 
| 405 | 
            +
                            Key pair generated!
         | 
| 406 | 
            +
                            Private key saved to: /home/user/.lanet_keys/lanet_private.key
         | 
| 407 | 
            +
                            Public key saved to: /home/user/.lanet_keys/lanet_public.key
         | 
| 286 408 |  | 
| 287 | 
            -
            IMPORTANT: Keep your private key secure and never share it.
         | 
| 288 | 
            -
            Share your public key with others who need to verify your messages.
         | 
| 409 | 
            +
                            IMPORTANT: Keep your private key secure and never share it.
         | 
| 410 | 
            +
                            Share your public key with others who need to verify your messages.
         | 
| 289 411 | 
             
                        </div>
         | 
| 290 412 |  | 
| 291 413 | 
             
                        <h4>Send a Signed Message</h4>
         | 
| @@ -295,7 +417,8 @@ Share your public key with others who need to verify your messages. | |
| 295 417 |  | 
| 296 418 | 
             
                        <h4>Send a Signed & Encrypted Message</h4>
         | 
| 297 419 | 
             
                        <div class="cli-example">
         | 
| 298 | 
            -
                            lanet send --target 192.168.1.5 --message "Secure signed message" --key "my_secret_key" | 
| 420 | 
            +
                            lanet send --target 192.168.1.5 --message "Secure signed message" --key "my_secret_key"
         | 
| 421 | 
            +
                            --private-key-file lanet_private.key
         | 
| 299 422 | 
             
                        </div>
         | 
| 300 423 |  | 
| 301 424 | 
             
                        <h4>Broadcast a Signed Message</h4>
         | 
| @@ -315,10 +438,10 @@ Share your public key with others who need to verify your messages. | |
| 315 438 |  | 
| 316 439 | 
             
                        <p>Example output when receiving a signed message:</p>
         | 
| 317 440 | 
             
                        <div class="output-example">
         | 
| 318 | 
            -
            Message from 192.168.1.5:
         | 
| 319 | 
            -
            Content: Hello, this is a signed message
         | 
| 320 | 
            -
            Signature: ✓ VERIFIED
         | 
| 321 | 
            -
            ----------------------------------------
         | 
| 441 | 
            +
                            Message from 192.168.1.5:
         | 
| 442 | 
            +
                            Content: Hello, this is a signed message
         | 
| 443 | 
            +
                            Signature: ✓ VERIFIED
         | 
| 444 | 
            +
                            ----------------------------------------
         | 
| 322 445 | 
             
                        </div>
         | 
| 323 446 | 
             
                    </div>
         | 
| 324 447 |  | 
| @@ -391,7 +514,8 @@ Signature: ✓ VERIFIED | |
| 391 514 |  | 
| 392 515 | 
             
                        <p>Send a file with encryption and digital signature:</p>
         | 
| 393 516 | 
             
                        <div class="cli-example">
         | 
| 394 | 
            -
                            lanet send-file --target 192.168.1.5 --file document.pdf --key "my_secret_key" --private-key-file | 
| 517 | 
            +
                            lanet send-file --target 192.168.1.5 --file document.pdf --key "my_secret_key" --private-key-file
         | 
| 518 | 
            +
                            lanet_private.key
         | 
| 395 519 | 
             
                        </div>
         | 
| 396 520 |  | 
| 397 521 | 
             
                        <h4>Receive Files</h4>
         | 
| @@ -401,15 +525,16 @@ Signature: ✓ VERIFIED | |
| 401 525 |  | 
| 402 526 | 
             
                        <p>With signature verification:</p>
         | 
| 403 527 | 
             
                        <div class="cli-example">
         | 
| 404 | 
            -
                            lanet receive-file --output ./downloads --encryption-key "my_secret_key" --public-key-file | 
| 528 | 
            +
                            lanet receive-file --output ./downloads --encryption-key "my_secret_key" --public-key-file
         | 
| 529 | 
            +
                            lanet_public.key
         | 
| 405 530 | 
             
                        </div>
         | 
| 406 531 |  | 
| 407 532 | 
             
                        <p>Example output during file transfer:</p>
         | 
| 408 533 | 
             
                        <div class="output-example">
         | 
| 409 | 
            -
            Receiving file: document.pdf from 192.168.1.5
         | 
| 410 | 
            -
            Size: 1048576 bytes
         | 
| 411 | 
            -
            Transfer ID: 8a7b6c5d-4e3f-2g1h-0i9j-8k7l6m5n4o3p
         | 
| 412 | 
            -
            Progress: 75% (786432/1048576 bytes)
         | 
| 534 | 
            +
                            Receiving file: document.pdf from 192.168.1.5
         | 
| 535 | 
            +
                            Size: 1048576 bytes
         | 
| 536 | 
            +
                            Transfer ID: 8a7b6c5d-4e3f-2g1h-0i9j-8k7l6m5n4o3p
         | 
| 537 | 
            +
                            Progress: 75% (786432/1048576 bytes)
         | 
| 413 538 | 
             
                        </div>
         | 
| 414 539 | 
             
                    </div>
         | 
| 415 540 |  | 
| @@ -443,13 +568,13 @@ Progress: 75% (786432/1048576 bytes) | |
| 443 568 |  | 
| 444 569 | 
             
                        <p>Example output when viewing mesh info:</p>
         | 
| 445 570 | 
             
                        <div class="output-example">
         | 
| 446 | 
            -
            Mesh Node ID: 4f9a8b7c-6d5e-4f3e-2d1c-0b9a8b7c6d5e
         | 
| 571 | 
            +
                            Mesh Node ID: 4f9a8b7c-6d5e-4f3e-2d1c-0b9a8b7c6d5e
         | 
| 447 572 |  | 
| 448 | 
            -
            Connected nodes:
         | 
| 449 | 
            -
             | 
| 450 | 
            -
             | 
| 573 | 
            +
                            Connected nodes:
         | 
| 574 | 
            +
                            b1c2d3e4-f5g6-7h8i-9j0k-l1m2n3o4p5q6 (192.168.1.5, last seen 12s ago)
         | 
| 575 | 
            +
                            c5d4e3f2-g1h0-i9j8-k7l6-m5n4o3p2q1r0 (192.168.1.10, last seen 5s ago)
         | 
| 451 576 |  | 
| 452 | 
            -
            Message cache: 24 messages
         | 
| 577 | 
            +
                            Message cache: 24 messages
         | 
| 453 578 | 
             
                        </div>
         | 
| 454 579 | 
             
                    </div>
         | 
| 455 580 |  | 
| @@ -478,20 +603,20 @@ Message cache: 24 messages | |
| 478 603 |  | 
| 479 604 | 
             
                        <p>Example output of a traceroute:</p>
         | 
| 480 605 | 
             
                        <div class="output-example">
         | 
| 481 | 
            -
            Tracing route to github.com using UDP protocol
         | 
| 482 | 
            -
            Maximum hops: 30, Timeout: 1s, Queries: 3
         | 
| 483 | 
            -
            ======================================================================
         | 
| 484 | 
            -
            TTL | 
| 485 | 
            -
            ----------------------------------------------------------------------
         | 
| 486 | 
            -
             | 
| 487 | 
            -
             | 
| 488 | 
            -
             | 
| 489 | 
            -
             | 
| 490 | 
            -
             | 
| 491 | 
            -
             | 
| 492 | 
            -
             | 
| 493 | 
            -
            ======================================================================
         | 
| 494 | 
            -
            Trace complete.
         | 
| 606 | 
            +
                            Tracing route to github.com using UDP protocol
         | 
| 607 | 
            +
                            Maximum hops: 30, Timeout: 1s, Queries: 3
         | 
| 608 | 
            +
                            ======================================================================
         | 
| 609 | 
            +
                            TTL IP Address Hostname Response Time
         | 
| 610 | 
            +
                            ----------------------------------------------------------------------
         | 
| 611 | 
            +
                            1 192.168.1.1 router.home 2.34ms
         | 
| 612 | 
            +
                            2 172.16.42.1 isp-gateway.net 8.72ms
         | 
| 613 | 
            +
                            3 216.58.223.14 15.35ms
         | 
| 614 | 
            +
                            4 172.217.170.78 edge-router.google.com 22.89ms
         | 
| 615 | 
            +
                            5 * * Request timed out
         | 
| 616 | 
            +
                            6 140.82.121.4 github.com 45.23ms
         | 
| 617 | 
            +
                            Destination unreachable
         | 
| 618 | 
            +
                            ======================================================================
         | 
| 619 | 
            +
                            Trace complete.
         | 
| 495 620 | 
             
                        </div>
         | 
| 496 621 | 
             
                    </div>
         | 
| 497 622 |  | 
| @@ -741,10 +866,11 @@ end</code></pre> | |
| 741 866 | 
             
                    <pre><code>gem install lanet</code></pre>
         | 
| 742 867 |  | 
| 743 868 | 
             
                    <h2>Documentation</h2>
         | 
| 744 | 
            -
                    <p>For complete documentation, please visit the <a href="https://github.com/davidesantangelo/lanet">GitHub | 
| 869 | 
            +
                    <p>For complete documentation, please visit the <a href="https://github.com/davidesantangelo/lanet">GitHub
         | 
| 870 | 
            +
                            repository</a>.</p>
         | 
| 745 871 |  | 
| 746 872 | 
             
                    <footer style="margin-top: 40px; text-align: center; color: #7f8c8d;">
         | 
| 747 | 
            -
                        <p>Lanet v0.5. | 
| 873 | 
            +
                        <p>Lanet v0.5.1 - Secure Network Communications Library</p>
         | 
| 748 874 | 
             
                    </footer>
         | 
| 749 875 | 
             
                </div>
         | 
| 750 876 |  | 
| @@ -767,4 +893,5 @@ end</code></pre> | |
| 767 893 | 
             
                    }
         | 
| 768 894 | 
             
                </script>
         | 
| 769 895 | 
             
            </body>
         | 
| 896 | 
            +
             | 
| 770 897 | 
             
            </html>
         | 
    
        data/lib/lanet/traceroute.rb
    CHANGED
    
    | @@ -34,14 +34,7 @@ module Lanet | |
| 34 34 | 
             
                  destination_ip = resolve_destination(destination)
         | 
| 35 35 |  | 
| 36 36 | 
             
                  begin
         | 
| 37 | 
            -
                     | 
| 38 | 
            -
                    when :icmp
         | 
| 39 | 
            -
                      trace_icmp(destination_ip)
         | 
| 40 | 
            -
                    when :udp
         | 
| 41 | 
            -
                      trace_udp(destination_ip)
         | 
| 42 | 
            -
                    when :tcp
         | 
| 43 | 
            -
                      trace_tcp(destination_ip)
         | 
| 44 | 
            -
                    end
         | 
| 37 | 
            +
                    trace_protocol(destination_ip)
         | 
| 45 38 | 
             
                  rescue StandardError => e
         | 
| 46 39 | 
             
                    raise e unless e.message.include?("Must run as root/administrator")
         | 
| 47 40 |  | 
| @@ -54,15 +47,20 @@ module Lanet | |
| 54 47 |  | 
| 55 48 | 
             
                private
         | 
| 56 49 |  | 
| 50 | 
            +
                def trace_protocol(destination_ip)
         | 
| 51 | 
            +
                  case @protocol
         | 
| 52 | 
            +
                  when :icmp then trace_icmp(destination_ip)
         | 
| 53 | 
            +
                  when :udp then trace_udp(destination_ip)
         | 
| 54 | 
            +
                  when :tcp then trace_tcp(destination_ip)
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 57 58 | 
             
                def trace_using_system_command(destination)
         | 
| 58 59 | 
             
                  # Build the appropriate system traceroute command
         | 
| 59 60 | 
             
                  system_cmd = case @protocol
         | 
| 60 | 
            -
                               when :icmp
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                                | 
| 63 | 
            -
                                 "traceroute -T"
         | 
| 64 | 
            -
                               else
         | 
| 65 | 
            -
                                 "traceroute" # UDP is the default for most traceroute commands
         | 
| 61 | 
            +
                               when :icmp then "traceroute -I"
         | 
| 62 | 
            +
                               when :tcp then "traceroute -T"
         | 
| 63 | 
            +
                               else "traceroute" # UDP is the default
         | 
| 66 64 | 
             
                               end
         | 
| 67 65 |  | 
| 68 66 | 
             
                  # Add options for max hops, timeout, and queries/retries
         | 
| @@ -90,32 +88,18 @@ module Lanet | |
| 90 88 | 
             
                    hop_details = Regexp.last_match(2)
         | 
| 91 89 |  | 
| 92 90 | 
             
                    # Parse the hop details
         | 
| 93 | 
            -
                    hostname = nil
         | 
| 94 | 
            -
                    avg_time = nil
         | 
| 95 | 
            -
             | 
| 96 | 
            -
                    # Check for timeout indicated by asterisks
         | 
| 97 91 | 
             
                    if ["* * *", "*"].include?(hop_details.strip)
         | 
| 98 92 | 
             
                      # All timeouts at this hop
         | 
| 99 93 | 
             
                      @results << { ttl: hop_num, ip: nil, hostname: nil, avg_time: nil, timeouts: @queries }
         | 
| 100 94 | 
             
                      next
         | 
| 101 95 | 
             
                    end
         | 
| 102 96 |  | 
| 103 | 
            -
                    # Extract  | 
| 97 | 
            +
                    # Extract IP, hostname, and timing info
         | 
| 104 98 | 
             
                    all_ips = extract_multiple_ips(hop_details)
         | 
| 105 | 
            -
             | 
| 106 | 
            -
                    # Extract the first IP (primary IP for this hop)
         | 
| 107 99 | 
             
                    ip = all_ips&.first
         | 
| 108 | 
            -
             | 
| 109 | 
            -
                    # Try to extract hostname if present
         | 
| 110 | 
            -
                    # Format: "hostname (ip)"
         | 
| 111 | 
            -
                    if hop_details =~ /([^\s(]+)\s+\(([0-9.]+)\)/
         | 
| 112 | 
            -
                      hostname = Regexp.last_match(1)
         | 
| 113 | 
            -
                      # We already have the IP from all_ips, so no need to set it again
         | 
| 114 | 
            -
                    end
         | 
| 115 | 
            -
             | 
| 116 | 
            -
                    # Extract response times - typically format is "X.XXX ms Y.YYY ms Z.ZZZ ms"
         | 
| 100 | 
            +
                    hostname = extract_hostname(hop_details)
         | 
| 117 101 | 
             
                    times = hop_details.scan(/(\d+\.\d+)\s*ms/).flatten.map(&:to_f)
         | 
| 118 | 
            -
                    avg_time = (times.sum / times.size).round(2)  | 
| 102 | 
            +
                    avg_time = times.any? ? (times.sum / times.size).round(2) : nil
         | 
| 119 103 |  | 
| 120 104 | 
             
                    # Add to results
         | 
| 121 105 | 
             
                    @results << {
         | 
| @@ -124,22 +108,22 @@ module Lanet | |
| 124 108 | 
             
                      hostname: hostname,
         | 
| 125 109 | 
             
                      avg_time: avg_time,
         | 
| 126 110 | 
             
                      timeouts: @queries - times.size,
         | 
| 127 | 
            -
                      # Include all IPs if there are multiple
         | 
| 128 111 | 
             
                      all_ips: all_ips&.size && all_ips.size > 1 ? all_ips : nil
         | 
| 129 112 | 
             
                    }
         | 
| 130 113 | 
             
                  end
         | 
| 131 114 | 
             
                end
         | 
| 132 115 |  | 
| 116 | 
            +
                def extract_hostname(hop_details)
         | 
| 117 | 
            +
                  hop_details =~ /([^\s(]+)\s+\(([0-9.]+)\)/ ? Regexp.last_match(1) : nil
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
             | 
| 133 120 | 
             
                def extract_multiple_ips(hop_details)
         | 
| 134 121 | 
             
                  # Match all IP addresses in the hop details
         | 
| 135 122 | 
             
                  ips = hop_details.scan(/\b(?:\d{1,3}\.){3}\d{1,3}\b/).uniq
         | 
| 136 123 |  | 
| 137 | 
            -
                  # If no IPs were found in a non-timeout line,  | 
| 124 | 
            +
                  # If no IPs were found in a non-timeout line, try alternate format
         | 
| 138 125 | 
             
                  if ips.empty? && !hop_details.include?("*")
         | 
| 139 | 
            -
                     | 
| 140 | 
            -
                    potential_ips = hop_details.split(/\s+/).select do |part|
         | 
| 141 | 
            -
                      part =~ /\b(?:\d{1,3}\.){3}\d{1,3}\b/
         | 
| 142 | 
            -
                    end
         | 
| 126 | 
            +
                    potential_ips = hop_details.split(/\s+/).select { |part| part =~ /\b(?:\d{1,3}\.){3}\d{1,3}\b/ }
         | 
| 143 127 | 
             
                    ips = potential_ips unless potential_ips.empty?
         | 
| 144 128 | 
             
                  end
         | 
| 145 129 |  | 
| @@ -153,14 +137,10 @@ module Lanet | |
| 153 137 | 
             
                  # Otherwise, resolve the hostname to an IPv4 address
         | 
| 154 138 | 
             
                  begin
         | 
| 155 139 | 
             
                    addresses = Resolv.getaddresses(destination)
         | 
| 156 | 
            -
             | 
| 157 | 
            -
                    # If no addresses are returned, the hostname is unresolvable
         | 
| 158 140 | 
             
                    raise Resolv::ResolvError, "no address for #{destination}" if addresses.empty?
         | 
| 159 141 |  | 
| 160 142 | 
             
                    # Find the first IPv4 address
         | 
| 161 143 | 
             
                    ipv4_address = addresses.find { |addr| addr =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ }
         | 
| 162 | 
            -
             | 
| 163 | 
            -
                    # If no IPv4 address is found, raise an error
         | 
| 164 144 | 
             
                    raise "No IPv4 address found for hostname: #{destination}" if ipv4_address.nil?
         | 
| 165 145 |  | 
| 166 146 | 
             
                    ipv4_address
         | 
| @@ -181,10 +161,8 @@ module Lanet | |
| 181 161 | 
             
                    hop_info = trace_hop_icmp(destination_ip, ttl)
         | 
| 182 162 | 
             
                    @results << hop_info
         | 
| 183 163 |  | 
| 184 | 
            -
                    # Stop if we've reached the destination
         | 
| 185 | 
            -
                    break if hop_info[:ip] == destination_ip
         | 
| 186 | 
            -
                    # Stop if we've hit an unreachable marker
         | 
| 187 | 
            -
                    break if hop_info[:unreachable]
         | 
| 164 | 
            +
                    # Stop if we've reached the destination or hit unreachable
         | 
| 165 | 
            +
                    break if hop_info[:ip] == destination_ip || hop_info[:unreachable]
         | 
| 188 166 | 
             
                  end
         | 
| 189 167 | 
             
                end
         | 
| 190 168 |  | 
| @@ -193,9 +171,7 @@ module Lanet | |
| 193 171 |  | 
| 194 172 | 
             
                  # Use ping with increasing TTL values
         | 
| 195 173 | 
             
                  @queries.times do
         | 
| 196 | 
            -
                    Time.now
         | 
| 197 174 | 
             
                    cmd = ping_command_with_ttl(destination_ip, ttl)
         | 
| 198 | 
            -
             | 
| 199 175 | 
             
                    ip = nil
         | 
| 200 176 | 
             
                    response_time = nil
         | 
| 201 177 |  | 
| @@ -246,8 +222,6 @@ module Lanet | |
| 246 222 |  | 
| 247 223 | 
             
                def trace_hop_udp(destination_ip, ttl)
         | 
| 248 224 | 
             
                  hop_info = { ttl: ttl, responses: [] }
         | 
| 249 | 
            -
             | 
| 250 | 
            -
                  # Create a listener socket for ICMP responses
         | 
| 251 225 | 
             
                  icmp_socket = create_icmp_socket
         | 
| 252 226 |  | 
| 253 227 | 
             
                  @queries.times do |i|
         | 
| @@ -295,25 +269,23 @@ module Lanet | |
| 295 269 |  | 
| 296 270 | 
             
                def create_icmp_socket
         | 
| 297 271 | 
             
                  socket = Socket.new(Socket::AF_INET, Socket::SOCK_RAW, Socket::IPPROTO_ICMP)
         | 
| 298 | 
            -
                   | 
| 299 | 
            -
                  # Windows requires different socket setup
         | 
| 300 | 
            -
                  else
         | 
| 301 | 
            -
                    socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
         | 
| 302 | 
            -
                  end
         | 
| 272 | 
            +
                  socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true) unless windows?
         | 
| 303 273 | 
             
                  socket
         | 
| 304 274 | 
             
                rescue Errno::EPERM, Errno::EACCES
         | 
| 305 275 | 
             
                  raise "Must run as root/administrator to create raw sockets for traceroute"
         | 
| 306 276 | 
             
                end
         | 
| 307 277 |  | 
| 278 | 
            +
                def windows?
         | 
| 279 | 
            +
                  RbConfig::CONFIG["host_os"] =~ /mswin|mingw|cygwin/
         | 
| 280 | 
            +
                end
         | 
| 281 | 
            +
             | 
| 308 282 | 
             
                def trace_tcp(destination_ip)
         | 
| 309 283 | 
             
                  1.upto(@max_hops) do |ttl|
         | 
| 310 284 | 
             
                    hop_info = trace_hop_tcp(destination_ip, ttl)
         | 
| 311 285 | 
             
                    @results << hop_info
         | 
| 312 286 |  | 
| 313 | 
            -
                    # Stop if we've reached the destination
         | 
| 314 | 
            -
                    break if hop_info[:ip] == destination_ip
         | 
| 315 | 
            -
                    # Stop if we've hit an unreachable marker
         | 
| 316 | 
            -
                    break if hop_info[:unreachable]
         | 
| 287 | 
            +
                    # Stop if we've reached the destination or hit unreachable
         | 
| 288 | 
            +
                    break if hop_info[:ip] == destination_ip || hop_info[:unreachable]
         | 
| 317 289 | 
             
                  end
         | 
| 318 290 | 
             
                end
         | 
| 319 291 |  | 
| @@ -324,15 +296,16 @@ module Lanet | |
| 324 296 | 
             
                    # Use different ports for each query
         | 
| 325 297 | 
             
                    port = 80 + i
         | 
| 326 298 | 
             
                    start_time = Time.now
         | 
| 299 | 
            +
                    socket = nil
         | 
| 327 300 |  | 
| 328 301 | 
             
                    begin
         | 
| 329 302 | 
             
                      # Create TCP socket with specific TTL
         | 
| 330 303 | 
             
                      socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
         | 
| 331 304 | 
             
                      socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, ttl)
         | 
| 305 | 
            +
                      sockaddr = Socket.sockaddr_in(port, destination_ip)
         | 
| 332 306 |  | 
| 333 307 | 
             
                      # Attempt to connect with timeout
         | 
| 334 308 | 
             
                      Timeout.timeout(@timeout) do
         | 
| 335 | 
            -
                        sockaddr = Socket.sockaddr_in(port, destination_ip)
         | 
| 336 309 | 
             
                        socket.connect_nonblock(sockaddr)
         | 
| 337 310 | 
             
                      end
         | 
| 338 311 |  | 
| @@ -345,39 +318,7 @@ module Lanet | |
| 345 318 | 
             
                      }
         | 
| 346 319 | 
             
                    rescue IO::WaitWritable
         | 
| 347 320 | 
             
                      # Connection in progress - need to use select for non-blocking socket
         | 
| 348 | 
            -
                       | 
| 349 | 
            -
                      ip = nil
         | 
| 350 | 
            -
             | 
| 351 | 
            -
                      begin
         | 
| 352 | 
            -
                        Timeout.timeout(@timeout) do
         | 
| 353 | 
            -
                          _, writable, = IO.select(nil, [socket], nil, @timeout)
         | 
| 354 | 
            -
                          if writable&.any?
         | 
| 355 | 
            -
                            # Socket is writable, check for errors
         | 
| 356 | 
            -
                            begin
         | 
| 357 | 
            -
                              socket.connect_nonblock(sockaddr) # Will raise Errno::EISCONN if connected
         | 
| 358 | 
            -
                            rescue Errno::EISCONN
         | 
| 359 | 
            -
                              # Successfully connected
         | 
| 360 | 
            -
                              response_time = ((Time.now - start_time) * 1000).round(2)
         | 
| 361 | 
            -
                              ip = destination_ip
         | 
| 362 | 
            -
                            rescue SystemCallError
         | 
| 363 | 
            -
                              # Get the intermediary IP from the error
         | 
| 364 | 
            -
                              # This is a simplification - in reality, we'd need to use raw sockets
         | 
| 365 | 
            -
                              # and analyze TCP packets with specific TTL values
         | 
| 366 | 
            -
                              ip = nil
         | 
| 367 | 
            -
                            end
         | 
| 368 | 
            -
                          end
         | 
| 369 | 
            -
                        end
         | 
| 370 | 
            -
                      rescue Timeout::Error
         | 
| 371 | 
            -
                        hop_info[:responses] << { ip: nil, response_time: nil, timeout: true }
         | 
| 372 | 
            -
                      end
         | 
| 373 | 
            -
             | 
| 374 | 
            -
                      if ip
         | 
| 375 | 
            -
                        hop_info[:responses] << {
         | 
| 376 | 
            -
                          ip: ip,
         | 
| 377 | 
            -
                          response_time: response_time,
         | 
| 378 | 
            -
                          timeout: false
         | 
| 379 | 
            -
                        }
         | 
| 380 | 
            -
                      end
         | 
| 321 | 
            +
                      handle_wait_writable(socket, sockaddr, start_time, destination_ip, hop_info)
         | 
| 381 322 | 
             
                    rescue SystemCallError, Timeout::Error
         | 
| 382 323 | 
             
                      hop_info[:responses] << { ip: nil, response_time: nil, timeout: true }
         | 
| 383 324 | 
             
                    ensure
         | 
| @@ -388,6 +329,39 @@ module Lanet | |
| 388 329 | 
             
                  process_hop_responses(hop_info)
         | 
| 389 330 | 
             
                end
         | 
| 390 331 |  | 
| 332 | 
            +
                def handle_wait_writable(socket, sockaddr, start_time, destination_ip, hop_info)
         | 
| 333 | 
            +
                  response_time = nil
         | 
| 334 | 
            +
                  ip = nil
         | 
| 335 | 
            +
             | 
| 336 | 
            +
                  begin
         | 
| 337 | 
            +
                    Timeout.timeout(@timeout) do
         | 
| 338 | 
            +
                      _, writable, = IO.select(nil, [socket], nil, @timeout)
         | 
| 339 | 
            +
                      if writable&.any?
         | 
| 340 | 
            +
                        begin
         | 
| 341 | 
            +
                          socket.connect_nonblock(sockaddr) # Will raise Errno::EISCONN if connected
         | 
| 342 | 
            +
                        rescue Errno::EISCONN
         | 
| 343 | 
            +
                          # Successfully connected
         | 
| 344 | 
            +
                          response_time = ((Time.now - start_time) * 1000).round(2)
         | 
| 345 | 
            +
                          ip = destination_ip
         | 
| 346 | 
            +
                        rescue SystemCallError
         | 
| 347 | 
            +
                          # Get the intermediary IP from the error - would need raw sockets to do properly
         | 
| 348 | 
            +
                          ip = nil
         | 
| 349 | 
            +
                        end
         | 
| 350 | 
            +
                      end
         | 
| 351 | 
            +
                    end
         | 
| 352 | 
            +
                  rescue Timeout::Error
         | 
| 353 | 
            +
                    hop_info[:responses] << { ip: nil, response_time: nil, timeout: true }
         | 
| 354 | 
            +
                  end
         | 
| 355 | 
            +
             | 
| 356 | 
            +
                  return unless ip
         | 
| 357 | 
            +
             | 
| 358 | 
            +
                  hop_info[:responses] << {
         | 
| 359 | 
            +
                    ip: ip,
         | 
| 360 | 
            +
                    response_time: response_time,
         | 
| 361 | 
            +
                    timeout: false
         | 
| 362 | 
            +
                  }
         | 
| 363 | 
            +
                end
         | 
| 364 | 
            +
             | 
| 391 365 | 
             
                def process_hop_responses(hop_info)
         | 
| 392 366 | 
             
                  # Count timeouts
         | 
| 393 367 | 
             
                  timeouts = hop_info[:responses].count { |r| r[:timeout] }
         | 
    
        data/lib/lanet/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: lanet
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.5. | 
| 4 | 
            +
              version: 0.5.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Davide Santangelo
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2025-03- | 
| 11 | 
            +
            date: 2025-03-20 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: thor
         |