├── .github └── workflows │ ├── codacy.yml │ ├── codeql.yml │ └── codeql2.yml ├── COPYING ├── Makefile ├── README.md ├── SECURITY.md ├── ipscan.c ├── ipscan.h ├── ipscan_db.c ├── ipscan_general.c ├── ipscan_icmpv6.c ├── ipscan_portlist.h ├── ipscan_tcp.c ├── ipscan_udp.c ├── ipscan_web.c └── upgrade.bsh /.github/workflows/codacy.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # This workflow checks out code, performs a Codacy security scan 7 | # and integrates the results with the 8 | # GitHub Advanced Security code scanning feature. For more information on 9 | # the Codacy security scan action usage and parameters, see 10 | # https://github.com/codacy/codacy-analysis-cli-action. 11 | # For more information on Codacy Analysis CLI in general, see 12 | # https://github.com/codacy/codacy-analysis-cli. 13 | 14 | name: Codacy Security Scan 15 | 16 | on: 17 | push: 18 | branches: [ "master" ] 19 | pull_request: 20 | # The branches below must be a subset of the branches above 21 | branches: [ "master" ] 22 | schedule: 23 | - cron: '0 3 * * 1' 24 | workflow_dispatch: 25 | 26 | permissions: 27 | contents: read 28 | 29 | jobs: 30 | codacy-security-scan: 31 | permissions: 32 | contents: read # for actions/checkout to fetch code 33 | security-events: write # for github/codeql-action/upload-sarif to upload SARIF results 34 | actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status 35 | name: Codacy Security Scan 36 | runs-on: ubuntu-latest 37 | steps: 38 | # Checkout the repository to the GitHub Actions runner 39 | - name: Checkout code 40 | uses: actions/checkout@v3 41 | 42 | # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis 43 | - name: Run Codacy Analysis CLI 44 | uses: codacy/codacy-analysis-cli-action@d840f886c4bd4edc059706d09c6a1586111c540b 45 | with: 46 | # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository 47 | # You can also omit the token and run the tools that support default configurations 48 | project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} 49 | verbose: true 50 | output: results.sarif 51 | format: sarif 52 | # Adjust severity of non-security issues 53 | gh-code-scanning-compat: true 54 | # Force 0 exit code to allow SARIF file generation 55 | # This will handover control about PR rejection to the GitHub side 56 | max-allowed-issues: 2147483647 57 | 58 | # Upload the SARIF file generated in the previous step 59 | - name: Upload SARIF results file 60 | uses: github/codeql-action/upload-sarif@v2 61 | with: 62 | sarif_file: results.sarif 63 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | name: "CodeQL" 8 | 9 | on: 10 | push: 11 | branches: [ "master" ] 12 | pull_request: 13 | # The branches below must be a subset of the branches above 14 | branches: [ "master" ] 15 | schedule: 16 | - cron: '0 2 * * 1' 17 | workflow_dispatch: 18 | 19 | jobs: 20 | analyze: 21 | name: Analyze 22 | runs-on: ubuntu-latest 23 | permissions: 24 | actions: read 25 | contents: read 26 | security-events: write 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | language: [ 'cpp' ] 32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 33 | # Use only 'java' to analyze code written in Java, Kotlin or both 34 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 35 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 36 | 37 | steps: 38 | - name: Checkout repository 39 | uses: actions/checkout@v3 40 | 41 | # Initializes the CodeQL tools for scanning. 42 | - name: Initialize CodeQL 43 | uses: github/codeql-action/init@v2 44 | with: 45 | languages: ${{ matrix.language }} 46 | # If you wish to specify custom queries, you can do so here or in a config file. 47 | # By default, queries listed here will override any specified in a config file. 48 | # Prefix the list here with "+" to use these queries and those in the config file. 49 | 50 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 51 | # queries: security-extended,security-and-quality 52 | 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v2 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 61 | 62 | # If the Autobuild fails above, remove it and uncomment the following three lines. 63 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 64 | 65 | # - run: | 66 | # echo "Run, Build Application using script" 67 | # ./location_of_script_within_repo/buildscript.sh 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v2 71 | with: 72 | category: "/language:${{matrix.language}}" 73 | -------------------------------------------------------------------------------- /.github/workflows/codeql2.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL Advanced" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | branches: [ "master" ] 19 | schedule: 20 | - cron: '28 13 * * 0' 21 | 22 | jobs: 23 | analyze: 24 | name: Analyze (${{ matrix.language }}) 25 | # Runner size impacts CodeQL analysis time. To learn more, please see: 26 | # - https://gh.io/recommended-hardware-resources-for-running-codeql 27 | # - https://gh.io/supported-runners-and-hardware-resources 28 | # - https://gh.io/using-larger-runners (GitHub.com only) 29 | # Consider using larger runners or machines with greater resources for possible analysis time improvements. 30 | runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} 31 | permissions: 32 | # required for all workflows 33 | security-events: write 34 | 35 | # required to fetch internal or private CodeQL packs 36 | packages: read 37 | 38 | # only required for workflows in private repositories 39 | actions: read 40 | contents: read 41 | 42 | strategy: 43 | fail-fast: false 44 | matrix: 45 | include: 46 | - language: actions 47 | build-mode: none 48 | - language: c-cpp 49 | build-mode: autobuild 50 | # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' 51 | # Use `c-cpp` to analyze code written in C, C++ or both 52 | # Use 'java-kotlin' to analyze code written in Java, Kotlin or both 53 | # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both 54 | # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, 55 | # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. 56 | # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how 57 | # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages 58 | steps: 59 | - name: Checkout repository 60 | uses: actions/checkout@v4 61 | 62 | # Add any setup steps before running the `github/codeql-action/init` action. 63 | # This includes steps like installing compilers or runtimes (`actions/setup-node` 64 | # or others). This is typically only required for manual builds. 65 | # - name: Setup runtime (example) 66 | # uses: actions/setup-example@v1 67 | 68 | # Initializes the CodeQL tools for scanning. 69 | - name: Initialize CodeQL 70 | uses: github/codeql-action/init@v3 71 | with: 72 | languages: ${{ matrix.language }} 73 | build-mode: ${{ matrix.build-mode }} 74 | # If you wish to specify custom queries, you can do so here or in a config file. 75 | # By default, queries listed here will override any specified in a config file. 76 | # Prefix the list here with "+" to use these queries and those in the config file. 77 | 78 | # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 79 | # queries: security-extended,security-and-quality 80 | 81 | # If the analyze step fails for one of the languages you are analyzing with 82 | # "We were unable to automatically build your code", modify the matrix above 83 | # to set the build mode to "manual" for that language. Then modify this step 84 | # to build your code. 85 | # ℹ️ Command-line programs to run using the OS shell. 86 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 87 | - if: matrix.build-mode == 'manual' 88 | shell: bash 89 | run: | 90 | echo 'If you are using a "manual" build mode for one or more of the' \ 91 | 'languages you are analyzing, replace this with the commands to build' \ 92 | 'your code, for example:' 93 | echo ' make bootstrap' 94 | echo ' make release' 95 | exit 1 96 | 97 | - name: Perform CodeQL Analysis 98 | uses: github/codeql-action/analyze@v3 99 | with: 100 | category: "/language:${{matrix.language}}" 101 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | 624 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # IPscan - an HTTP-initiated IPv6 port scanner. 2 | # 3 | # (C) Copyright 2011-2025 Tim Chappell. 4 | # 5 | # This file is part of IPscan. 6 | # 7 | # IPscan is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with IPscan. If not, see . 19 | 20 | # Makefile version 21 | # 0.01 - initial version 22 | # 0.02 - added MySQL support 23 | # 0.03 - addition of ping functionality (suid bit set) 24 | # 0.04 - default to MySQL 25 | # 0.05 - remove sqlite support 26 | # 0.06 - move $(LIBS) to the end of each link line 27 | # 0.07 - minor corrections to support FreeBSD gmake builds 28 | # 0.08 - add extra compiler checks 29 | # 0.09 - add 'running as root' check for install step 30 | # 0.10 - strip symbols from the final objects 31 | # 0.11 - add additional object security-related options 32 | # 0.12 - tidy up 33 | # 0.13 - add support for servers where SETUID is missing/unavailable 34 | # 0.14 - add support for servers where UDP is missing/available 35 | # 0.15 - update copyright year 36 | # 0.16 - force warnings to be errors 37 | # 0.17 - update copyright year 38 | # 0.18 - update copyright year 39 | # 0.19 - add debug build capability, update copyright year 40 | # 0.20 - update copyright year 41 | # 0.21 - update copyright year 42 | # 0.22 - update copyright year 43 | # 0.23 - update copyright year 44 | 45 | # Support servers where SETUID is not available 46 | # Set this variable to 0 if you don't have permissions to call SETUID 47 | SETUID_AVAILABLE=1 48 | 49 | # Support servers where UDP port access is disabled 50 | # Set this variable to 0 if you don't have permissions to access UDP ports 51 | UDP_AVAILABLE=1 52 | 53 | # General build variables 54 | SHELL=/bin/sh 55 | LIBPATHS=-L/usr/lib 56 | INCLUDES=-I/usr/include 57 | LIBS= 58 | CC=gcc 59 | CFLAGS=-Wall -Wextra -Werror -Wshadow -Wpointer-arith -Wwrite-strings -Wformat -Wformat-security -O2 -D_FORTIFY_SOURCE=2 60 | CFLAGS+= -fstack-protector-all -fstack-clash-protection -Wstack-protector --param ssp-buffer-size=4 61 | CFLAGS+= -ftrapv -fexceptions -fPIE -fpie -Wl,-pie -Wl,-z,relro -Wl,-z,now -Werror=implicit-function-declaration 62 | # testing CFLAGS+= -D_TIME_BITS=64 63 | 64 | # Install location for the CGI files 65 | TARGETDIR=/var/www/cgi-bin6 66 | 67 | # HTTP URI PATH by which external hosts will access the CGI files. 68 | # This may well be unrelated to the installation path if Apache is configured 69 | # to provide CGI access via an alias. 70 | # NB : the path should begin with a / but must NOT end with one .... 71 | URIPATH=/cgi-bin6 72 | 73 | # Text-version target executable name 74 | TXTTARGET=ipscantxt.cgi 75 | FASTTXTTARGET=ipscanfasttxt.cgi 76 | 77 | # Javascript-version target executable name 78 | JSTARGET=ipscanjs.cgi 79 | FASTJSTARGET=ipscanfastjs.cgi 80 | 81 | ############################################################################## 82 | # 83 | # Hopefully nothing below this point will need changing .... 84 | # 85 | ############################################################################## 86 | 87 | # Determine the appropriate database related include/library paths 88 | # as well as any necessary libraries 89 | LIBS+=$(shell mysql_config --libs) 90 | CFLAGS+=$(shell mysql_config --cflags) 91 | INCLUDES+=$(shell mysql_config --include) 92 | 93 | # No debug by default 94 | DEBUG= 95 | # Determine effective user-id - likely to work in all shells 96 | MYEUID=$(shell id -u) 97 | 98 | # Concatenate the necessary parameters for the two targets 99 | CMNPARAMS= $(DEBUG) -DEXEDIR=\"$(TARGETDIR)\" -DEXETXTNAME=\"$(TXTTARGET)\" -DEXEJSNAME=\"$(JSTARGET)\" 100 | CMNPARAMS+= -DEXEFASTTXTNAME=\"$(FASTTXTTARGET)\" -DEXEFASTJSNAME=\"$(FASTJSTARGET)\" 101 | CMNPARAMS+= -DURIPATH=\"$(URIPATH)\" -DSETUID_AVAILABLE=$(SETUID_AVAILABLE) 102 | CMNPARAMS+= -DUDP_AVAILABLE=$(UDP_AVAILABLE) 103 | TXTPARAMS=$(CFLAGS) -DTEXTMODE=1 -DFAST=0 $(CMNPARAMS) 104 | JSPARAMS =$(CFLAGS) -DTEXTMODE=0 -DFAST=0 $(CMNPARAMS) 105 | FASTTXTPARAMS=$(CFLAGS) -DTEXTMODE=1 -DFAST=1 $(CMNPARAMS) 106 | FASTJSPARAMS =$(CFLAGS) -DTEXTMODE=0 -DFAST=1 $(CMNPARAMS) 107 | 108 | # Common header files which are always a dependancy 109 | HEADERFILES=ipscan.h ipscan_portlist.h 110 | # Any other files on which we depend 111 | DEPENDFILE=Makefile 112 | 113 | # Generate the list of text-version and javascript-version objects from the source files 114 | TXTOBJS=$(patsubst %.c,%-txt.o,$(wildcard *.c)) 115 | JSOBJS=$(patsubst %.c,%-js.o,$(wildcard *.c)) 116 | FASTTXTOBJS=$(patsubst %.c,%-fast-txt.o,$(wildcard *.c)) 117 | FASTJSOBJS=$(patsubst %.c,%-fast-js.o,$(wildcard *.c)) 118 | 119 | # default target builds everything 120 | .PHONY: all 121 | all : $(TXTTARGET) $(JSTARGET) $(FASTTXTTARGET) $(FASTJSTARGET) 122 | 123 | # debug target builds objects with debug, defined in ipscan.h, enabled 124 | # Not intended for production use 125 | .PHONY: debug 126 | debug : clean 127 | debug : DEBUG = -DDEBUG=1 128 | debug : $(TXTTARGET) $(JSTARGET) $(FASTTXTTARGET) $(FASTJSTARGET) 129 | 130 | # Rules to build an individual text-version object and the overall text-version target 131 | %-txt.o: %.c $(HEADERFILES) $(DEPENDFILE) 132 | $(CC) $(TXTPARAMS) -c $(INCLUDES) $(LIBPATHS) -o $@ $< 133 | $(TXTTARGET) : $(TXTOBJS) $(HEADERFILES) $(DEPENDFILE) 134 | $(CC) $(TXTPARAMS) -o $(TXTTARGET) $(INCLUDES) $(LIBPATHS) $(TXTOBJS) $(LIBS) 135 | 136 | # Rules to build an individual text-version object and the overall text-version target 137 | %-fast-txt.o: %.c $(HEADERFILES) $(DEPENDFILE) 138 | $(CC) $(FASTTXTPARAMS) -c $(INCLUDES) $(LIBPATHS) -o $@ $< 139 | $(FASTTXTTARGET) : $(FASTTXTOBJS) $(HEADERFILES) $(DEPENDFILE) 140 | $(CC) $(FASTTXTPARAMS) -o $(FASTTXTTARGET) $(INCLUDES) $(LIBPATHS) $(FASTTXTOBJS) $(LIBS) 141 | 142 | # Rules to build an individual jscript-version object and the overall jscript-version target 143 | %-js.o: %.c $(HEADERFILES) $(DEPENDFILE) 144 | $(CC) $(JSPARAMS) -c $(INCLUDES) $(LIBPATHS) -o $@ $< 145 | $(JSTARGET) : $(JSOBJS) $(HEADERFILES) $(DEPENDFILE) 146 | $(CC) $(JSPARAMS) -o $(JSTARGET) $(INCLUDES) $(LIBPATHS) $(JSOBJS) $(LIBS) 147 | 148 | # Rules to build an individual jscript-version object and the overall jscript-version target 149 | %-fast-js.o: %.c $(HEADERFILES) $(DEPENDFILE) 150 | $(CC) $(FASTJSPARAMS) -c $(INCLUDES) $(LIBPATHS) -o $@ $< 151 | $(FASTJSTARGET) : $(FASTJSOBJS) $(HEADERFILES) $(DEPENDFILE) 152 | $(CC) $(FASTJSPARAMS) -o $(FASTJSTARGET) $(INCLUDES) $(LIBPATHS) $(FASTJSOBJS) $(LIBS) 153 | 154 | # Rules to copy the built objects to the target installation directory 155 | # optionally set setuid bit on targets if required 156 | .PHONY: install 157 | install : $(TXTTARGET) $(JSTARGET) $(FASTTXTTARGET) $(FASTJSTARGET) 158 | ifeq ($(UDP_AVAILABLE),1) 159 | @echo 160 | @echo Running with UDP_AVAILABLE in the Makefile set to 1 161 | @echo If you do NOT have root permissions or UDP sockets are NOT available then 162 | @echo please set UDP_AVAILABLE to 0 and re-make. 163 | @echo 164 | else 165 | @echo 166 | @echo Running with UDP_AVAILABLE in the Makefile set to 0 167 | @echo If you do have permissions to create UDP sockets then 168 | @echo please set SETUID_AVAILABLE to 1 and re-make. 169 | @echo 170 | endif 171 | # Strip un-needed symbols from the binaries and copy them to their 172 | # target location 173 | strip --strip-unneeded $(TXTTARGET) $(JSTARGET) $(FASTTXTTARGET) $(FASTJSTARGET) 174 | cp $(TXTTARGET) $(FASTTXTTARGET) $(TARGETDIR) 175 | cp $(JSTARGET) $(FASTJSTARGET) $(TARGETDIR) 176 | ifeq ($(SETUID_AVAILABLE),1) 177 | @echo 178 | @echo Running with SETUID_AVAILABLE in the Makefile set to 1 179 | @echo If you do NOT have root permissions or chmod/setuid is NOT available then 180 | @echo please set SETUID_AVAILABLE to 0 and re-make. 181 | @echo 182 | ifeq ($(MYEUID),0) 183 | chmod 4555 $(TARGETDIR)/$(TXTTARGET) 184 | chmod 4555 $(TARGETDIR)/$(JSTARGET) 185 | chmod 4555 $(TARGETDIR)/$(FASTTXTTARGET) 186 | chmod 4555 $(TARGETDIR)/$(FASTJSTARGET) 187 | else 188 | @echo 189 | @echo ERROR: install must be run as root in order to setuid. 190 | @echo ERROR: user-id is currently $(MYEUID) 191 | @echo 192 | endif 193 | else 194 | @echo 195 | @echo Running with SETUID_AVAILABLE in the Makefile set to 0 196 | @echo If you do have root permissions AND chmod/setuid is available then 197 | @echo please set SETUID_AVAILABLE to 1 and re-make. 198 | @echo 199 | endif 200 | 201 | # Rule to clean the source directory 202 | .PHONY: clean 203 | clean : 204 | rm -f $(TXTTARGET) $(JSTARGET) $(FASTTXTTARGET) $(FASTJSTARGET) 205 | rm -f $(TXTOBJS) $(JSOBJS) $(FASTTXTOBJS) $(FASTJSOBJS) 206 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IPscan 2 | ### An HTTP-initiated IPv6 port scanner, offering text-only and javascript browser compatible versions. 3 | 4 | Copyright (C) 2011-2025 Tim Chappell. 5 | 6 | This file is part of IPscan. 7 | 8 | IPscan is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with IPscan. If not, see . 20 | 21 | --- 22 | 23 | IPscan requires access to a MySQL, or MariaDB, database and the associated client development libraries 24 | (libmysqlclient-dev or similar) to be installed on the server which will act as your scanner. The database 25 | is used to *temporarily* hold scan results until shortly after the test completes. 26 | IPscan is known to build on: openSUSE versions 11.1/11.4/12.1/13.1, Centos 7, Fedora 16, 27 | Ubuntu 12.04, Mint 12, FreeBSD 9, Arch Linux ARM (Raspberry Pi) and Raspbian and run alongside 28 | Apache versions 2.2 and 2.4. Please let me know of any other build successes/failures on 29 | unlisted platforms. 30 | 31 | NOTE: IPscan logging has been updated to aid operators needing to comply with regulatory 32 | requirements for the protection of end-users, e.g. GDPR. Where applicable, the logging-related 33 | recommendations outlined in: https://tools.ietf.org/id/draft-andersdotter-intarea-update-to-rfc6302-00.html#RFC6302 34 | have been implemented, for unmodified ipscan.h configurations. 35 | 36 | Installation Steps: 37 | =================== 38 | IMPORTANT: when UPGRADING from versions before 1.97: a database change has occurred and consequently 39 | it is necessary that you remove your existing database prior to building and installing 40 | versions 1.97 and later. See step 4 below for details. 41 | 42 | 1. edit the Makefile and adjust the following entries as required: 43 | a. TARGETDIR - this should be set to the desired location for the cgi files (e.g. /srv/www/cgi-bin6) 44 | Ensure that the selected target directory exists, with appropriate permissions, before 45 | attempting to install the final executables. 46 | b. URIPATH - this is the request URI by which the cgi files will be accessed from your webserver 47 | e.g. https://www64.chappell-family.co.uk/cgi-bin6/ipscanjs.cgi then set URIPATH=/cgi-bin6 48 | c. TXTTARGET and JSTARGET - these define the names of the two cgi objects that will be created 49 | d. SETUID_AVAILABLE and UDP_AVAILABLE - if you're running the service on a machine where you, or 50 | the web server, don't have permissions to call setuid() or create UDP sockets then these features 51 | need to be disabled. 52 | 53 | 2. edit ipscan.h and adjust *at least* the following entries: 54 | a. EMAILADDRESS - suggest you use a non-personal email address if the webserver will be world-accessible 55 | b. INCLUDETERMSOFUSE and TERMSOFUSEURL if you wish to reference a terms of use page on your website. 56 | c. IPSCAN_INTERFACE_NAME - modify this to match the server's interface to which clients will browse. 57 | d. MYSQL_XXXX - Adjust the following constants to match the settings of your database server: 58 | MYSQL_HOST - the hostname or IP address of the machine hosting the MySQL database 59 | MYSQL_USER - the username used to access the IPscan database. 60 | MYSQL_PASSWD - the password used to identify the MySQL user. 61 | MYSQL_DBNAME - the name of the IPscan database. 62 | MYSQL_TBLNAME - the name of the table in which IPscan results will reside. 63 | 64 | 3. edit ipscan_portlist.h and change the list of ports to be tested, if required. Note that if you add 65 | new UDP ports then you must also add a matching packet generator function to ipscan_udp.c 66 | 67 | 4. Create the database and user and allocate appropriate user privileges, using the following commands within the mysql shell: 68 | 69 | NB: adjust the host, user name, password and database name to match the globals you've edited in step 2 above: 70 | 71 | mysql> create database ipscan; 72 | Query OK, 1 row affected (0.00 sec) 73 | 74 | Note: it is unnecessary to re-create the user if upgrading from a previous version. 75 | 76 | mysql> create user 'ipscan-user'@'localhost' identified by 'ipscan-passwd'; 77 | Query OK, 0 rows affected (0.01 sec) 78 | 79 | mysql> grant all privileges on ipscan.* to 'ipscan-user'@'localhost' identified by 'ipscan-passwd'; 80 | Query OK, 0 rows affected (0.01 sec) 81 | 82 | mysql> exit 83 | Bye 84 | 85 | If performing an upgrade from an earlier version of IPscan then either drop the table within a mysql shell, e.g. : 86 | 87 | mysql> use ipscan; 88 | mysql> drop table if exists results; 89 | 90 | or use the BASH upgrade script within the IPscan source directory: 91 | 92 | $ ./upgrade.bsh 93 | 94 | 95 | 5. make && make install 96 | 97 | Given that the suid bit is set on the installed executables, in order to support raw sockets for ICMPv6 testing, 98 | it is necessary to perform the 'make install' stage as root user. 99 | 100 | Note: when updating an existing installation to version 1.10 and beyond it may be necessary to manually 101 | remove the ipscan_checks.c file, if it remains in your install directory, prior to building. 102 | The functionality within ipscan_checks.c has been redistributed to separate files which 103 | handle TCP, UDP and ICMPv6 testing. 104 | 105 | Note: please use gmake under FreeBSD. 106 | 107 | 6. Make sure that the URI path directory (which may well be accessed via an Apache alias) is enabled to execute cgi: 108 | 109 | ScriptAlias /cgi-bin6/ "/srv/www/cgi-bin6/" 110 | 111 | AllowOverride None 112 | Options +ExecCGI -Includes 113 | Order allow,deny 114 | Allow from 2000::/3 115 | 116 | 117 | Also disable client caching, having enabled the loading of mod_headers: 118 | 119 | 120 | Header set Cache-Control "private, no-cache, no-store, must-revalidate" 121 | Header set Pragma "no-cache" 122 | Header set Expires "0" 123 | 124 | 125 | Don't forget to restart your web server after making the appropriate modifications. 126 | 127 | 7. If you are using an SELinux-enabled distribution (e.g. Fedora) then it may be necessary to perform additional 128 | steps similar to those outlined below: 129 | a. Ensure that your Apache server is enabled to support cgi, as root type: 130 | # setsebool -P httpd_enable_cgi on 131 | b. Enable the correct execution permissions to the cgi scripts, as root type: 132 | # cd /srv/www/cgi-bin6/ (use your selected installation path) 133 | # chcon -t httpd_unconfined_script_exec_t *.cgi 134 | 135 | IMPORTANT NOTE: the steps listed in step 7 above are only indicative of what may be required, and 136 | depend upon your existing installation. Please consult the SELinux documentation for further details. 137 | 138 | 8. Browse from a machine that you want testing towards your servers' IPv6 address, e.g. 139 | w3m https://www66.chappell-family.co.uk/cgi-bin6/ipscanfasttxt.cgi 140 | or: 141 | w3m https://[2001:470:971f:99::6]/cgi-bin6/ipscantxt.cgi 142 | 143 | 9. Check the web server access/error logs or syslog for messages. IPscan will place summary messages in the 144 | web server error log or syslog if enabled to do so (this is NOT the default option - change 145 | IPSCAN_LOGVERBOSITY to 1 to enable this). It is possible to enable copious amounts of debug by 146 | uncommenting the debug #define statements in ipscan.h. 147 | 148 | 10. If you're providing public access to IPscan then please ensure that you disable verbose reporting, 149 | the summary option and ALL debug facilities. 150 | 151 | Note: versions v1.42 and later of IPscan automatically delete the scan results, for both javascript 152 | and text-only clients, after reporting them to the user. Earlier versions relied on a cron job 153 | to achieve the same end, but this is no longer required for current versions. 154 | 155 | 11. For those considering providing IPscan access on the public internet then consider adding a 156 | landing page which will check for host IP address suitability prior to allowing access to the 157 | cgi script(s) - most (apart from google) search engine spiders/robots currently only use IPv4. 158 | It may be advisable to only offer direct links to the cgi scripts if the address checks 159 | were successful. See https://ipv6.chappell-family.com/ipv6tcptest/ as an example. 160 | 161 | 12. Notes on IPscan binaries: IPscan is provided in two basic versions, one supporting 162 | javascript-enabled browsers and the other for text-based browsers. Additionally, the standard 163 | build provides fast and standard versions of both of these tests. The fast version tests 164 | multiple TCP or UDP ports in parallel, whereas the standard version tests only 1 port at a time, 165 | at a default rate of 1 port per second. Please be aware that some OSes and firewalls apply 166 | rate-limiting to their generation, or passing, of ICMPv6 responses on the basis that this 167 | behaviour is indicative of a port scan being performed. Consequently such rate-limiting might 168 | cause a port which would normally generate an ICMPv6 response (e.g. PHBTD) to send no response 169 | at all, which IPscan would report as STEALTHed. If you are testing a host or firewall (whether 170 | on the client under test or elsewhere in the path between your client and test server) which 171 | implements such rate-limiting then you are advised to use the standard, slower versions of IPscan 172 | which should not trigger the rate-limiting behaviour. If you're unsure which version is appropriate 173 | for your device, then try both and compare the results. Some Linux distributions and some ISP firewalls 174 | are known to implement such rate-limiting. 175 | 176 | 177 | Getting further help: 178 | ===================== 179 | A demonstration Raspberry Pi IPv6 firewall checker is available to IPv6 enabled clients at: . If you need further help then please email me at: or visit my IPscan wiki at: 180 | 181 | --- 182 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | The following versions of this project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 1.97 | :white_check_mark: | 11 | | < 1.97 | :x: | 12 | 13 | ## Reporting a Vulnerability 14 | 15 | Please see: 16 | --- 17 | -------------------------------------------------------------------------------- /ipscan.h: -------------------------------------------------------------------------------- 1 | // IPscan - an HTTP-initiated IPv6 port scanner. 2 | // 3 | // Copyright (C) 2011-2025 Tim Chappell. 4 | // 5 | // This file is part of IPscan. 6 | // 7 | // IPscan is free software: you can redistribute it and/or modify 8 | // it under the terms of the GNU General Public License as published by 9 | // the Free Software Foundation, either version 3 of the License, or 10 | // (at your option) any later version. 11 | // 12 | // This program is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | // GNU General Public License for more details. 16 | // 17 | // You should have received a copy of the GNU General Public License 18 | // along with IPscan. If not, see . 19 | 20 | #include 21 | #include 22 | 23 | #ifndef IPSCAN_H 24 | #define IPSCAN_H 1 25 | 26 | // Handle DEBUG flag 27 | #ifndef DEBUG 28 | #define DEBUG 0 29 | #endif 30 | 31 | // Build-mode for executable 32 | // Note this is controlled by the makefile, but a default is defined here for safety 33 | // 34 | // TEXTMODE == 1 => Text Browser compatible (e.g. lynx or w3m) 35 | // TEXTMODE == 0 => Browser supports Javascript 36 | // 37 | #ifndef TEXTMODE 38 | #define TEXTMODE 0 39 | #endif 40 | 41 | // Parallel scan-mode for executable 42 | // Note this is controlled by the makefile, but a default is defined here for safety 43 | #ifndef FAST 44 | #define FAST 0 45 | #endif 46 | 47 | // Determine which logging target to use stderr (0) or syslog(1) 48 | #define LOGMODE 1 49 | 50 | // Create the appropriate logging macro 51 | #if (LOGMODE == 0) 52 | #define IPSCAN_LOG(...) fprintf(stderr, __VA_ARGS__ ) 53 | #else 54 | #define IPSCAN_LOG(...) syslog(LOG_NOTICE, __VA_ARGS__ ) 55 | #endif 56 | 57 | // 58 | // VERSION HISTORY 59 | // 60 | // 0.5 first combined text/javascript version 61 | // 0.61 separate closed/timeout [CLOSED] from closed/rejected [FILTER] 62 | // 0.63 further response states 63 | // 0.64 Open, Closed or detailed response names 64 | // 0.65 Added results key 65 | // 0.66 Added Prohibited failure case (ICMPv6 administratively prohibited) 66 | // 0.67 Add ability to create database directory path assuming only 1 additional directory is required to be created 67 | // 0.68 Added unreachable icmpv6 type 1 code 0 68 | // 0.69 Add unreachable stats 69 | // 0.70 Add further potential connect errors 70 | // 0.71 Clean logging output and web reporting 71 | // 0.72 Updated txt browser output and offer email feedback link. 72 | // 0.73 add hostname, time into feedback email body 73 | // 0.74 tidy up noscript link to text-only version, move to structure driven results classification 74 | // 0.75 improved scan summary logging for structure driven approach 75 | // 0.76 improved query string error checking, handling and reporting 76 | // 0.77 added link to source code on github to results page. 77 | // 0.78 added support for HEAD method 78 | // 0.79 Minor tweaks to ipscan_web.c and ipscan.c to remove set but unused variables 79 | // 0.80 include optional MySQL support which touches Makefile, ipscan.h and ipscan_db.c 80 | // 0.81 added Microsoft RDP protocol, port 3389, to list of default ports 81 | // 0.82 added/modified some Apple related ports 82 | // 0.83 added support for syslog logging 83 | // 0.84 renumbered default ports so they are monotonic 84 | // 0.85 tidied up HTML to make Opera happy 85 | // 0.86 added ICMPv6 ping 86 | // 0.87 tidied ipscan_checks 87 | // 0.88 ping logging improvements 88 | // 0.89 further logging improvements for ICMPv6 responses 89 | // 0.90 INNER ICMPv6 packet logging, checking and reporting 90 | // 0.91 further default logging improvements 91 | // 0.92 removal of empty HTML paragraph 92 | // 0.93 default to MySQL, potential query string overflow caught 93 | // 0.94 improve buffer overflow protection, remove SQLITE support 94 | // 0.95 tidy up HTML error reporting for buffer overflow cases. 95 | // 0.96 fix some printf casts 96 | // 0.97 slight improvement to logging for ICMPv6 cases 97 | // 0.98 tweaks for FreeBSD9 support (build under gmake) 98 | // 0.99 first build supporting parallel port scanning 99 | // 1.00 further code improvements, add HTTP-EQUIV to force IE7 mimicry 100 | // 1.01 Minor tweak to add further windows related ports 101 | // 1.02 Minor tweak to non-javascript browser message 102 | // 1.03 Minor tweak to add further parameter checking for customports 103 | // 1.04 Include port descriptive text 104 | // 1.05 Compress kickoff form 105 | // 1.06 Tidy up requestmethod declaration 106 | // 1.07 Introduction of UDP port scans 107 | // 1.08 Estimated run time improvement 108 | // 1.09 UDP responses renamed for improved consistency, ipscan_checks.c split 109 | // 1.10 Parallel UDP processing support added 110 | // 1.11 Separate TCP/UDP logging, all disabled by default 111 | // 1.12 Runtime estimate improvement - separate calc per protocol type 112 | // 1.13 Logging improvement 113 | // 1.14 Add support for scan automation help when offered a bad query string 114 | // 1.15 Incorporate further UDP support 115 | // 1.16 support optional ping for deployment on servers where setuid not possible 116 | // 1.17 support optional UDP for deployment on controlled servers 117 | // 1.18 move to use memset() 118 | // 1.19 support for special test cases 119 | // 1.20 support for TCP/32764 (Router backdoor) and special case debug logging improvements 120 | // 1.21 add minimum per-port timings to ensure Linux 1s ratelimit is not hit 121 | // 1.22 add completion indication to support quicker results deletion 122 | // 1.23 enable automatic results deletion 123 | // 1.24 further javascript improvements and fix for custom ports 124 | // 1.25 fix tidy-up reporting 125 | // 1.26 javascript lint check 126 | // 1.27 move final (javascript) fetch earlier 127 | // 1.28 further javascript improvements 128 | // 1.29 additional debug support to aid javascript optimisation 129 | // 1.30 additional javascript optimisation 130 | // 1.31 removed unused javascript functions 131 | // 1.32 auto-generate normal and fast versions 132 | // 1.33 improved error reporting 133 | // 1.34 added SNMPv2c and SNMPv3 support 134 | // 1.35 move to random(ish) sessions rather than pid() 135 | // 1.36 tidy up for push to github 136 | // 1.37 move to single XML HTTP Request object 137 | // 1.38 Variety of minor tweaks (CGI environment variable parsing) 138 | // 1.39 Add 'navigate away' detection to javascript version 139 | // 1.40 Correct some Coverity reported issues 140 | // 1.41 Add fork() issue reporting to aid debug 141 | // 1.42 Add automatic deletion of all results 142 | // 1.43 Add support for automatic deletion of orphaned results 143 | // 1.44 Add support for RIPng and IKEv2 SA_INIT 144 | // 1.45 Reintroduce MPLS LSP Ping 145 | // 1.46 Further DNS test error handling 146 | // 1.47 SNMP error handling improvement 147 | // 1.48 Different community strings for SNMPv1 and SNMPv2c 148 | // 1.49 Add DHCPv6 support 149 | // 1.50 Use memory engine table by default 150 | // 1.51 Change TCP getaddrinfo call to request AF_INET6 151 | // 1.52 Reduce the debug logging to make testing easier 152 | // 1.53 Add some Microsft Message Queuing ports which appear 153 | // to be open in some Windows 10 installations 154 | // 1.54 Add Intel AMT ports 155 | // 1.55 Remove exit() calls to simplify fuzzing 156 | // 1.56 Add basic HTML5/CSS support for javascript binaries 157 | // 1.57 Add termsaccepted value and further HTML tag tweaks 158 | // 1.58 Add memcache to list of default TCP ports 159 | // 1.59 Add memcache to list of default UDP ports 160 | // 1.60 Reduced logging option by default 161 | // 1.61 Additional JS version debugging 162 | // 1.62 Fixed logging typos 163 | // 1.63 Further client debug logging improvements 164 | // 1.64 Yet more client debug logging improvements 165 | // 1.65 signed/unsigned conflicts corrected 166 | // 1.66 extern redefined 167 | // 1.67 Debug-only build for client debug improvements 168 | // 1.68 Debug-only build for client debug improvements 169 | // 1.69 URL corrections 170 | // 1.70 Fixes for servers without UDP or SUID support 171 | // 1.71 Fixes for warnings raised by Semmle (re-entrant time functions) 172 | // 1.72 Minor HTML fixes - robots and optional icon support 173 | // plus javascript changes to remove eval() 174 | // 1.73 improved tidy_up_db() logging 175 | // 1.74 add missing logs for failed time_r conversions 176 | // 1.75 change text for initiations missing termsaccepted query 177 | // 1.76 add a separate debug build target, 178 | // improved client debug and copyright dates update 179 | // 1.77 Removed summarise_db() functionality - no longer used or desirable 180 | // 1.78 Add update_db to correctly handle test state logging 181 | // 1.79 Changes to use client determined starttime 182 | // 1.80 Additional debug for end-of-test checking 183 | // 1.81 Javascript improvements 184 | // 1.82 Add comments to disregard LGTM SQL injection false positives 185 | // 1.83 Further Javascript improvements 186 | // 1.84 Delete unused code, further Javascript improvements and remove LGTM pragmas 187 | // 1.85 define database delete wait-period separately 188 | // 1.86 Add some LGTM pragmas to hide cross-site scripting false positives 189 | // 1.87 Add some missing inet_ntop return-value checks, 190 | // further database debug and remove LGTM CGI cross-site scripting pragmas 191 | // 1.88 remove LGTM pragmas 192 | // 1.89 further User Agent validation 193 | // 1.90 Adjustments to help text and addition of TCP/20005 (KCodes NetUSB) 194 | // CVE-2021-45608 195 | // 1.91 Fix portlist size calculation and user-defined port value masking 196 | // 1.92 Move to consistent unsigned masks approach (for C, not generated Javscript) 197 | // 1.93 Update copyright year 198 | // 1.94 User-agent reporting improvements - only at scan initialisation, plus support 199 | // for Chrome UA strings 200 | // 1.95 Added count_rows_db() function to improve checking/reporting 201 | // 1.96 increase FETCHEVERY to 6s 202 | // 1.97 add a server timestamp to the database to fix an issue with client timestamps being wrong/offset 203 | // A database update is mandatory - see README.md for details. 204 | 205 | // ipscan Version Number 206 | #define IPSCAN_VERNUM "1.97" 207 | 208 | // ipscan type 209 | #if (TEXTMODE == 0) 210 | #define IPSCAN_VERTYPE "JS-" 211 | #else 212 | #define IPSCAN_VERTYPE "TXT-" 213 | #endif 214 | 215 | // Determine reported version string 216 | // and include a hint if parallel scanning (FAST) is enabled 217 | // 218 | #if (FAST == 1) 219 | #define IPSCAN_VERFAST "-FAST" 220 | #define IPSCAN_VER IPSCAN_VERTYPE IPSCAN_VERNUM IPSCAN_VERFAST 221 | #else 222 | #define IPSCAN_VER IPSCAN_VERTYPE IPSCAN_VERNUM 223 | #endif 224 | // 225 | 226 | // 227 | #define IPSCAN_H_VER IPSCAN_VERNUM 228 | // 229 | 230 | // Email address 231 | #define EMAILADDRESS "webmaster@chappell-family.com" 232 | 233 | // Determine whether to include terms of use link (0 = don't include; 1 = include) 234 | #define INCLUDETERMSOFUSE 1 235 | // Link for terms of use - please update to reference a page from your website 236 | #define TERMSOFUSEURL "https://wiki.chappell-family.com/wiki/index.php?title=Timswiki:About" 237 | 238 | // Determine whether to offer help for bad/incomplete/unrecognised URLs 239 | // 0=offer no help, 1=offer help - need to define URL 240 | #define IPSCAN_BAD_URL_HELP 1 241 | // The link that might provide some help ... 242 | #define IPSCAN_BAD_URL_LINK "https://wiki.chappell-family.com/wiki/index.php?title=ScanAutomation" 243 | 244 | // Determine whether to offer link for restart page if terms and conditions not accepted 245 | // 0=no offer, 1=offer - need to define URL too 246 | #define IPSCAN_TC_MISSING_LINK 1 247 | #define IPSCAN_TC_MISSING_LINK_URL "https://ipv6.chappell-family.com/ipv6tcptest/" 248 | 249 | // URL providing description special protocol tests 250 | #define IPSCAN_SPECIALTESTS_URL "https://wiki.chappell-family.com/wiki/index.php?title=IPv6_SpecialTests" 251 | 252 | // Interface name on which the test server listens 253 | // Note this is only used to determine the IPv6 address inserted in MPLS LSP Ping packets 254 | // and the Link-local address sent in DHCPv6 requests. 255 | #define IPSCAN_INTERFACE_NAME "eth0" 256 | 257 | // MySQL database-related globals 258 | #define MYSQL_HOST "localhost" 259 | #define MYSQL_USER "ipscan-user" 260 | #define MYSQL_PASSWD "ipscan-passwd" 261 | #define MYSQL_DBNAME "ipscan" 262 | #define MYSQL_TBLNAME "results" 263 | 264 | // MySQL - maximum number of rows expected per unique client session (IP/session/starttime) 265 | // expected maximum is TCP+UDP+ICMP+state 266 | // MUST be less than INT_MAX (so can add one futher) to return successfully from count_rows_db() 267 | #define IPSCAN_DB_MAX_EXPECTED_ROWS (999) 268 | 269 | // MySQL - use the InnoDB engine type by default 270 | // You can verify the engine type using: 271 | // mysql --user="ipscan-user" --password="ipscan-passwd" --host=localhost ipscan 272 | // SHOW TABLE STATUS WHERE Name = 'results'; 273 | // 274 | // Steps for creating the MySQL database - this MUST be done before tests are performed! 275 | // ------------------------------------------------------------------------------------- 276 | // 277 | // NB: adjust the user name, password and database name to match the globals you've edited above: 278 | // 279 | // mysql> create database ipscan; 280 | // Query OK, 1 row affected (0.00 sec) 281 | // 282 | // mysql> create user 'ipscan-user'@'localhost' identified by 'ipscan-passwd'; 283 | // Query OK, 0 rows affected (0.01 sec) 284 | // 285 | // mysql> grant all privileges on ipscan.* to 'ipscan-user'@'localhost' identified by 'ipscan-passwd'; 286 | // Query OK, 0 rows affected (0.01 sec) 287 | // 288 | // mysql> exit 289 | // Bye 290 | // 291 | // ------------------------------------------------------------------------------------- 292 | 293 | // ************************************************************************************* 294 | // * * 295 | // * Nothing below this line should need changing * 296 | // * * 297 | // ************************************************************************************* 298 | 299 | // DEBUG build options - uncommenting these #defines will result in copious amounts of information 300 | // IMPORTANT NOTE: None of these debug options should be uncommented on internet-facing servers. 301 | // 302 | #if (DEBUG == 1) 303 | // Common options for testing - do NOT use in production 304 | #define IPSCAN_LOGVERBOSITY 3 305 | #define CLIENTDEBUG 1 306 | #endif 307 | // 308 | // database (NOT port scan results) related debug: 309 | // #define DBDEBUG 1 310 | // 311 | // database (port scan results) related debug: 312 | // #define DBPSRDEBUG 1 313 | // 314 | // ICMPv6 ping related debug: 315 | // #define PINGDEBUG 1 316 | // 317 | // Parallel processing related debug: 318 | // #define PARLLDEBUG 1 319 | // 320 | // UDP checks related debug: 321 | // #define UDPDEBUG 1 322 | // 323 | // UDP Parallel processing related debug: 324 | // #define UDPPARLLDEBUG 1 325 | // 326 | // Query string debug: 327 | // #define QUERYDEBUG 1 328 | // 329 | // Results debug: 330 | // #define RESULTSDEBUG 1 331 | // 332 | // Client (remote) debug - signalling, etc. 333 | // Primarily for troublesome Javascript clients. 334 | // #define CLIENTDEBUG 1 335 | 336 | // Decide whether to include ping support (requires setuid which some servers don't allow) 337 | // Do not modify this statement - adjust SETUID_AVAILABLE in the Makefile instead 338 | #ifndef SETUID_AVAILABLE 339 | #define IPSCAN_INCLUDE_PING 0 340 | #else 341 | #define IPSCAN_INCLUDE_PING SETUID_AVAILABLE 342 | #endif 343 | 344 | // Decide whether to include UDP support (access can be restricted on some servers) 345 | // Do not modify this statement - adjust UDP_AVAILABLE in the Makefile instead 346 | #ifndef UDP_AVAILABLE 347 | #define IPSCAN_INCLUDE_UDP 0 348 | #else 349 | #define IPSCAN_INCLUDE_UDP UDP_AVAILABLE 350 | #endif 351 | 352 | // Logging verbosity: 353 | // 354 | // (0) Quiet - program/unexpected response errors only 355 | // (1) Verbose - port scan summary of states is logged (ie number of ports of type OPEN, STLTH, RFSD, etc.) 356 | // 357 | // Do NOT change this value as your server's syslog may then contain personal information 358 | // which you need to obtain permission to capture in order to satisfy your GDPR obligations 359 | // 360 | // #define IPSCAN_LOGVERBOSITY 0 361 | 362 | // Magic number requesting the start of a scan 363 | #define MAGICBEGIN 123456 364 | 365 | // Maximum number of ports to be tested - this should exceed the sum of the default port list 366 | // and the allowed user-defined ports 367 | #define MAXPORTS ( DEFNUMPORTS + NUMUDPPORTS + NUMUSERDEFPORTS + 1 ) 368 | 369 | // Define the min/max valid port ranges. This could be used to restrict testing (e.g. >= 1024) 370 | // as long as the default port list is updated as well 371 | #define MINVALIDPORT 0 372 | #define MAXVALIDPORT 65535 373 | #define VALIDPORTMASK ((unsigned)(65535)) 374 | 375 | // Enable HTML5 for Javscript 376 | #define IPSCAN_HTML5_ENABLED 1 377 | // Maximum HTML5 body div width (pixels) 378 | #define IPSCAN_BODYDIV_WIDTH 800 379 | 380 | // Ensure IPSCAN_HTML5_ENABLED is defined 381 | #ifndef IPSCAN_HTML5_ENABLED 382 | #define IPSCAN_HTML5_ENABLED 0 383 | #endif 384 | 385 | // Call different HTML headers 386 | #if (IPSCAN_HTML5_ENABLED == 0) 387 | // Default to HTML 4.01 388 | #define HTML_HEADER() create_html_common_header() 389 | #else 390 | // Use HTML 5 everywhere 391 | #define HTML_HEADER() create_html5_common_header() 392 | #endif 393 | 394 | // Enable(1) or disable(0) favicon support 395 | #define IPSCAN_ICON_ENABLED 1 396 | // Icon type - common values include image/x-icon (.ico) and image/png (.png) 397 | #define IPSCAN_ICON_TYPE "image/x-icon" 398 | // Where to find your site icon 399 | #define IPSCAN_ICON_HREF "/favicon.ico" 400 | 401 | // Number of columns for HTML output: 402 | #define MAXCOLS 5 403 | #define COLUMNPCT (100/MAXCOLS) 404 | 405 | // Number of columns for UDP HTML output: 406 | #define MAXUDPCOLS 4 407 | #define COLUMNUDPPCT (100/MAXCOLS) 408 | 409 | // Number of columns for text-only browser output case 410 | #define TXTMAXCOLS 5 411 | 412 | // Number of columns per line in log outputs 413 | #define LOGMAXCOLS 4 414 | 415 | // Maximum size for buffer used to assemble log entries, 20 characters per "column" should be plenty 416 | #define LOGENTRYLEN (20* LOGMAXCOLS) 417 | 418 | // Number of octets per line in log outputs 419 | #define LOGMAXOCTETS 16 420 | 421 | // Maximum size for buffer used to assemble UDP packet debug entries 422 | #define LOGENTRYSIZE (64 + (4 * LOGMAXOCTETS)) 423 | 424 | // Maximum number of octets of any UDP packet that can be logged when 425 | // in UDPDEBUG mode and IPSCAN_LOGVERBOSITY = 1 426 | #define UDPMAXLOGOCTETS 128 427 | 428 | // Maximum number of supported query parameters 429 | // Must ensure MAXQUERIES exceeds NUMUSERDEFPORTS by sufficient amount! 430 | #define MAXQUERIES 16 431 | #define MAXQUERYSTRLEN 255 432 | #define MAXQUERYNAMELEN 32 433 | #define MAXQUERYVALLEN 64 434 | 435 | // Maximum length of request-method string 436 | // should be one of GET, HEADER, POST, OPTIONS, etc. so 16 sufficient 437 | #define MAXREQMETHODLEN 16 438 | 439 | // Maximum length of HTTP_USER_AGENT string 440 | #define MAXUSERAGENTLEN 1024 441 | 442 | // Magic to convert from #defined integers to strings (used to protect sscanf) 443 | #define TOSTR1(i) #i 444 | #define TO_STR(i) TOSTR1(i) 445 | 446 | // Determine the executable CGI script filenames 447 | // These SHOULD be defined in the makefile, but provide some defaults in case 448 | #ifndef EXETXTNAME 449 | #define EXETXTNAME "ipscan-txt.cgi" 450 | #endif 451 | #ifndef EXEJSNAME 452 | #define EXEJSNAME "ipscan-js.cgi" 453 | #endif 454 | #ifndef EXEFASTTXTNAME 455 | #define EXETXTNAME "ipscan-fast-txt.cgi" 456 | #endif 457 | #ifndef EXEFASTJSNAME 458 | #define EXEJSNAME "ipscan-fast-js.cgi" 459 | #endif 460 | 461 | 462 | // Determine the executable file name 463 | #if (TEXTMODE == 1) 464 | #if (FAST == 1) 465 | #define EXENAME EXEFASTTXTNAME 466 | #else 467 | #define EXENAME EXETXTNAME 468 | #endif 469 | #else 470 | #if (FAST == 1) 471 | #define EXENAME EXEFASTJSNAME 472 | #else 473 | #define EXENAME EXEJSNAME 474 | #endif 475 | #endif 476 | 477 | // Served HTTP URI directory path - needs a leading /, but not a trailing one ... 478 | // This SHOULD be defined in the makefile, but provide a default here just in case 479 | #ifndef URIPATH 480 | #define URIPATH "/cgi-bin6" 481 | #endif 482 | 483 | // Maximum number of user-defined TCP ports 484 | // Must ensure MAXQUERIES exceeds NUMUSERDEFPORTS by sufficient amount! 485 | #define NUMUSERDEFPORTS 4 486 | 487 | // Logging prefix (goes into apache error_log or syslog) 488 | // #define LOGPREFIX EXENAME" : Version "IPSCAN_VER" : " 489 | #define LOGPREFIX 490 | 491 | // 492 | // Parallel port scanning related 493 | // 494 | 495 | // Determine the maximum number of children and therefore the maximum number of 496 | // port scans that can be running in parallel 497 | // Determine the maximum number of port scans that can be allocated to each child 498 | #if (FAST == 1) 499 | #define MAXCHILDREN 7 500 | #define MAXPORTSPERCHILD 9 501 | #else 502 | #define MAXCHILDREN 1 503 | #define MAXPORTSPERCHILD 9 504 | #endif 505 | 506 | // Determine the maximum number of children and therefore the maximum number of 507 | // UDP port scans that can be running in parallel 508 | // Determine the maximum number of UDP port scans that can be allocated to each child 509 | #if (FAST == 1) 510 | #define MAXUDPCHILDREN 3 511 | #define MAXUDPPORTSPERCHILD 3 512 | #else 513 | #define MAXUDPCHILDREN 1 514 | #define MAXUDPPORTSPERCHILD 9 515 | #endif 516 | 517 | 518 | // 519 | // Database related 520 | // 521 | 522 | // Determine the maximum length of the query-string which is used to insert and select 523 | // results into/out of the database. Currently queries are slightly in excess of 250 characters. 524 | #define MAXDBQUERYSIZE 512 525 | 526 | // Timeout for port response (in seconds) 527 | #define TIMEOUTSECS 1 528 | #define TIMEOUTMICROSECS 20000 529 | 530 | // Minimum time between ports (s) 531 | #define IPSCAN_MINTIME_PER_PORT 1 532 | 533 | // JSON fetch period (seconds) - tradeoff between update rate and webserver load 534 | #define JSONFETCHEVERY 6 535 | 536 | // ICMPv6 ECHO REQUEST packet size - suggest larger than 64 byte minimum is sensible, but as a minimum 537 | // needs to support magic string insertion anyway 538 | #define ICMPV6_PACKET_SIZE 128 539 | 540 | // Size to be allocated for transmit/receive buffer 541 | #define ICMPV6_PACKET_BUFFER_SIZE 2048 542 | 543 | // Magic constants intended to uniquify our packets; 544 | // process id and session start time are also included 545 | #define ICMPV6_MAGIC_SEQ 12478 546 | #define ICMPV6_MAGIC_VALUE1 1289 547 | #define ICMPV6_MAGIC_VALUE2 12569 548 | 549 | // UDP buffer size 550 | #define UDP_BUFFER_SIZE 512 551 | 552 | // UDP timeout (seconds) - needs to exceed UPnP/SSDP response request time (MX field) which is 1 553 | #define UDPTIMEOUTSECS 2 554 | #define UDPTIMEOUTMICROSECS 20000 555 | 556 | // An estimate of the time to perform the test - assumes num ports is always 557 | // smaller than (MAXPORTSPERCHILD * MAX_CHILDREN) for each protocol 558 | #define UDPSTATICTIME 2 559 | #define TCPSTATICTIME 2 560 | #define ICMP6STATICTIME 2 561 | 562 | #if (IPSCAN_INCLUDE_UDP == 1) 563 | #define UDPRUNTIME ((MAXUDPCHILDREN == 1) ? (numudpports * UDPTIMEOUTSECS + UDPSTATICTIME) : ( (numudpports > MAXUDPPORTSPERCHILD) ? (MAXUDPPORTSPERCHILD * UDPTIMEOUTSECS + UDPSTATICTIME) : ( numudpports * UDPTIMEOUTSECS + UDPSTATICTIME) ) ) 564 | #else 565 | #define UDPRUNTIME 0 566 | #endif 567 | 568 | #define TCPRUNTIME ( (MAXCHILDREN == 1) ? (numports * TIMEOUTSECS + TCPSTATICTIME) : ( (numports > MAXPORTSPERCHILD) ? (MAXPORTSPERCHILD * TIMEOUTSECS + TCPSTATICTIME) : ( numports * TIMEOUTSECS + TCPSTATICTIME) ) ) 569 | #define ICMP6RUNTIME (ICMP6STATICTIME + TIMEOUTSECS) 570 | #define ESTIMATEDTIMETORUN ( UDPRUNTIME + TCPRUNTIME + ICMP6RUNTIME ) 571 | 572 | // NTP constants - setup as client (mode 3), unsynchronised, poll interval 8, precision 1 second 573 | #define NTP_LI 0 574 | #define NTP_VN 4 575 | #define NTP_MODE 3 576 | #define NTP_STRATUM 16 577 | #define NTP_POLL 8 578 | #define NTP_PRECISION 2 579 | 580 | // Protocol mappings (stored in database) 581 | // Port number (0-65535) stored in lowest 16 bits, 15-0 582 | // Special case tests indicated by value in bits 17-16 583 | // This allows multiple tests to be targetted at the same port 584 | #define IPSCAN_PORT_WIDTH (16U) 585 | #define IPSCAN_SPECIAL_WIDTH (2U) 586 | #define IPSCAN_PROTO_WIDTH (4U) 587 | 588 | #define IPSCAN_PORT_MASK ((unsigned)((1< this value 634 | // 635 | #define IPSCAN_DELETE_MINIMUM_TIME (1746449000) 636 | 637 | // TIDY UP - either delete everything in the database or 'just' results 638 | #define IPSCAN_DELETE_EVERYTHING (1) 639 | #define IPSCAN_DELETE_RESULTS_ONLY (0) 640 | 641 | 642 | // Flag indicating that the response was indirect rather than from the host under test 643 | // This may be the case if the host under test is behind a firewall or router 644 | #define IPSCAN_INDIRECT_RESPONSE 256 645 | // Mask to extract the response code - used in created Javascript 646 | #define IPSCAN_INDIRECT_MASK ((unsigned)255) 647 | 648 | // Completion indicators (passed in fetch querystring) 649 | // 650 | // IPSCAN_SUCCESSFUL_COMPLETION is used as a marker such that any query string fetch which 651 | // exceeds this value will be assumed to be indicating feedback from the javascript client 652 | // 653 | // IPSCAN_UNEXPECTED_CHANGE MUST be the last entry in the enumerated list 654 | // 655 | enum COMPLETIONSTATE 656 | { 657 | IPSCAN_SUCCESSFUL_COMPLETION = 990, 658 | IPSCAN_HTTPTIMEOUT_COMPLETION, 659 | IPSCAN_EVAL_ERROR, 660 | IPSCAN_OTHER_ERROR, 661 | IPSCAN_UNSUCCESSFUL_COMPLETION, 662 | IPSCAN_NAVIGATE_AWAY, 663 | IPSCAN_BAD_JSON_ERROR, 664 | IPSCAN_DB_ERROR, 665 | IPSCAN_UNEXPECTED_CHANGE, 666 | }; 667 | 668 | // 669 | // TESTSTATE browser-signalled values - helps to debug javascript failures 670 | // Mapped to high values so they are all out of range of PORTSTATE 671 | // 672 | // Size of buffer holding the flag descriptions 673 | // Typically each flag is 11 characturs including trailing comma and space 674 | // 675 | #define IPSCAN_FLAGSBUFFER_SIZE (128) 676 | // 677 | #define IPSCAN_TESTSTATE_IDLE (0) 678 | #define IPSCAN_TESTSTATE_RUNNING_BIT (32) 679 | #define IPSCAN_TESTSTATE_COMPLETE_BIT (64) 680 | #define IPSCAN_TESTSTATE_HTTPTIMEOUT_BIT (128) 681 | #define IPSCAN_TESTSTATE_EVALERROR_BIT (256) 682 | #define IPSCAN_TESTSTATE_OTHERERROR_BIT (512) 683 | #define IPSCAN_TESTSTATE_NAVAWAY_BIT (1024) 684 | #define IPSCAN_TESTSTATE_UNEXPCHANGE_BIT (2048) 685 | #define IPSCAN_TESTSTATE_BADCOMPLETE_BIT (4096) 686 | #define IPSCAN_TESTSTATE_DATABASE_ERROR_BIT (8192) 687 | 688 | // Mapping for connection attempt results 689 | // To add a new entry first insert a new internal state in the PORTSTATE enumeration and then add a 690 | // matching entry in the results structure in ipscan.c 691 | // Both should be inserted before the unexpected/unknown, etc. entries 692 | enum PORTSTATE 693 | { 694 | PORTOPEN = 0, 695 | PORTABORT, 696 | PORTREFUSED, 697 | PORTCRESET, 698 | PORTNRESET, 699 | PORTINPROGRESS, 700 | PORTPROHIBITED, 701 | PORTUNREACHABLE, 702 | PORTNOROUTE, 703 | PORTPKTTOOBIG, 704 | PORTPARAMPROB, 705 | ECHONOREPLY, 706 | ECHOREPLY, 707 | /* Addition for UDP port respond/doesn't */ 708 | UDPOPEN, 709 | UDPSTEALTH, 710 | /* Unexpected and Unknown error response cases, do NOT change */ 711 | PORTUNEXPECTED, 712 | PORTUNKNOWN, 713 | PORTINTERROR, 714 | /* End of list marker, do NOT change */ 715 | PORTEOL 716 | }; 717 | 718 | // Determine the number of entries 719 | #define NUMRESULTTYPES PORTEOL 720 | 721 | // Results structure 722 | struct rslt_struc 723 | { 724 | int returnval; 725 | int connrc; 726 | int connerrno; 727 | char label[32]; 728 | char colour[32]; 729 | char description[384]; 730 | }; 731 | 732 | // Single definition of external : resultsstruct 733 | extern const struct rslt_struc resultsstruct[]; 734 | 735 | // Default ports structure 736 | // 737 | // This constant defines the maximum port description size. Bear in mind, irrespective of the 738 | // description used in ipscan_portlist.h it also needs to support the text inserted for 739 | // user specified ports "User-specified: %d" (21 characters plus trailing \0), and so should not be 740 | // reduced below 22. 741 | #define PORTDESCSIZE 48 742 | // 743 | // the structure - consists of a port number, a "special case" indicator and a text description 744 | // 745 | struct portlist_struc 746 | { 747 | uint16_t port_num; 748 | uint8_t special; 749 | char port_desc[PORTDESCSIZE]; 750 | }; 751 | 752 | // End of defines 753 | #endif 754 | -------------------------------------------------------------------------------- /ipscan_general.c: -------------------------------------------------------------------------------- 1 | // IPscan - an HTTP-initiated IPv6 port scanner. 2 | // 3 | // Copyright (C) 2011-2025 Tim Chappell. 4 | // 5 | // This file is part of IPscan. 6 | // 7 | // IPscan is free software: you can redistribute it and/or modify 8 | // it under the terms of the GNU General Public License as published by 9 | // the Free Software Foundation, either version 3 of the License, or 10 | // (at your option) any later version. 11 | // 12 | // This program is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | // GNU General Public License for more details. 16 | // 17 | // You should have received a copy of the GNU General Public License 18 | // along with IPscan. If not, see . 19 | 20 | // ipscan_general.c version 21 | // 0.01 - first released version 22 | // 0.02 - update copyright dates 23 | // 0.03 - slight logic change 24 | // 0.04 - update copyright dates 25 | // 0.05 - add proto_to_string() 26 | // 0.06 - add fetch_to_string() 27 | // 0.07 - add state_to_string() 28 | // 0.08 - add result_to_string() 29 | // 0.09 - update copyright dates 30 | // 0.10 - update copyright year 31 | // 0.11 - reorder entries to match definitions, add database error 32 | // 0.12 - update copyright year 33 | // 0.13 - moved to unsigned proto 34 | // 0.14 - update copyright year 35 | // 0.15 - add report_useragent_strings() 36 | // 0.16 - hide leading and trailing spaces 37 | // 0.17 - added flag values 38 | // 0.18 - added report_ipscan_versions() 39 | // 0.19 - CodeQL improvements 40 | // 0.20 - add querystring checkers 41 | 42 | // 43 | #define IPSCAN_GENERAL_VER "0.20" 44 | // 45 | 46 | #include "ipscan.h" 47 | // 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | // toupper/tolower routines 58 | #include 59 | 60 | // Others that FreeBSD highlighted 61 | #include 62 | 63 | // IPv6 address conversion 64 | #include 65 | 66 | // String comparison 67 | #include 68 | 69 | // errors 70 | #include 71 | 72 | // Logging with syslog requires additional include 73 | #if (LOGMODE == 1) 74 | #include 75 | #endif 76 | 77 | // 78 | // report version 79 | // 80 | const char* ipscan_general_ver(void) 81 | { 82 | return IPSCAN_GENERAL_VER; 83 | } 84 | // 85 | // ----------------------------------------------------------------------------- 86 | // 87 | uint64_t get_session(void) 88 | { 89 | uint64_t sessionnum = 0; 90 | uint64_t fetchedsession = 0; 91 | FILE *fp; 92 | fp = fopen("/dev/urandom", "r"); 93 | 94 | if (NULL == fp) 95 | { 96 | sessionnum = (uint64_t)getpid(); 97 | IPSCAN_LOG( LOGPREFIX "ipscan: ERROR : Cannot open /dev/urandom, %d (%s), defaulting session to getpid() = %"PRIu64"\n", errno, strerror(errno), sessionnum); 98 | } 99 | else 100 | { 101 | size_t numitems = fread( &fetchedsession, sizeof(fetchedsession), 1, fp); 102 | fclose(fp); 103 | if (1 == numitems) 104 | { 105 | // Clear the MSB of the random session ID so that we're sure it will fit 106 | // into an int64_t which the QUERY_STRING parser assumes 107 | sessionnum = fetchedsession & ( ((uint64_t)~0) >> 1); 108 | 109 | #ifdef QUERYDEBUG 110 | IPSCAN_LOG( LOGPREFIX "ipscan: Session number modification check, before = %"PRIu64" after = %"PRIu64"\n", fetchedsession, sessionnum); 111 | #endif 112 | } 113 | else 114 | { 115 | sessionnum = (uint64_t)getpid(); 116 | IPSCAN_LOG( LOGPREFIX "ipscan: ERROR : Cannot read /dev/urandom, defaulting session to getpid() = %"PRIu64"\n", sessionnum); 117 | } 118 | } 119 | return (sessionnum); 120 | } 121 | 122 | // 123 | // ----------------------------------------------------------------------------- 124 | // 125 | void proto_to_string(uint32_t proto, char * retstring) 126 | { 127 | int rc = 0; 128 | switch (proto) 129 | { 130 | case IPSCAN_PROTO_TCP: 131 | rc = snprintf(retstring, IPSCAN_PROTO_STRING_MAX, "%s", "TCPv6"); 132 | break; 133 | 134 | case IPSCAN_PROTO_UDP: 135 | rc = snprintf(retstring, IPSCAN_PROTO_STRING_MAX, "%s", "UDPv6"); 136 | break; 137 | 138 | case IPSCAN_PROTO_ICMPV6: 139 | rc = snprintf(retstring, IPSCAN_PROTO_STRING_MAX, "%s", "ICMPv6"); 140 | break; 141 | 142 | case IPSCAN_PROTO_TESTSTATE: 143 | rc = snprintf(retstring, IPSCAN_PROTO_STRING_MAX, "%s", "TESTSTATE"); 144 | break; 145 | 146 | default: 147 | rc = snprintf(retstring, IPSCAN_PROTO_STRING_MAX, "%s", "UNDEFINED"); 148 | break; 149 | 150 | } 151 | // Report error - does IPSCAN_PROTO_STRING_MAX need increasing? 152 | if (rc < 0 || rc >= IPSCAN_PROTO_STRING_MAX) 153 | { 154 | IPSCAN_LOG( LOGPREFIX "ipscan: ERROR : Cannot fit protocol string into buffer, returned %d\n", rc); 155 | } 156 | return; 157 | } 158 | 159 | // 160 | // ----------------------------------------------------------------------------- 161 | // 162 | void fetch_to_string(int fetchnum, char * retstring) 163 | { 164 | int rc; 165 | if (IPSCAN_SUCCESSFUL_COMPLETION == fetchnum) 166 | { 167 | rc = snprintf(retstring, IPSCAN_FETCHNUM_STRING_MAX, "%s", "SUCCESSFUL"); 168 | } 169 | else if (IPSCAN_HTTPTIMEOUT_COMPLETION == fetchnum) 170 | { 171 | rc = snprintf(retstring, IPSCAN_FETCHNUM_STRING_MAX, "%s", "HTTP-TIMEOUT"); 172 | } 173 | else if (IPSCAN_EVAL_ERROR == fetchnum) 174 | { 175 | rc = snprintf(retstring, IPSCAN_FETCHNUM_STRING_MAX, "%s", "EVAL ERROR"); 176 | } 177 | else if (IPSCAN_OTHER_ERROR == fetchnum) 178 | { 179 | rc = snprintf(retstring, IPSCAN_FETCHNUM_STRING_MAX, "%s", "OTHER ERROR"); 180 | } 181 | else if (IPSCAN_UNSUCCESSFUL_COMPLETION == fetchnum) 182 | { 183 | rc = snprintf(retstring, IPSCAN_FETCHNUM_STRING_MAX, "%s", "UNSUCCESSFUL"); 184 | } 185 | else if (IPSCAN_NAVIGATE_AWAY == fetchnum) 186 | { 187 | rc = snprintf(retstring, IPSCAN_FETCHNUM_STRING_MAX, "%s", "NAVIGATEAWAY"); 188 | } 189 | else if (IPSCAN_BAD_JSON_ERROR == fetchnum) 190 | { 191 | rc = snprintf(retstring, IPSCAN_FETCHNUM_STRING_MAX, "%s", "BAD JSON ERR"); 192 | } 193 | else if (IPSCAN_DB_ERROR == fetchnum) 194 | { 195 | rc = snprintf(retstring, IPSCAN_FETCHNUM_STRING_MAX, "%s", "DATABASE ERR"); 196 | } 197 | else if (IPSCAN_UNEXPECTED_CHANGE == fetchnum) 198 | { 199 | rc = snprintf(retstring, IPSCAN_FETCHNUM_STRING_MAX, "%s", "UNEXP CHANGE"); 200 | } 201 | else 202 | { 203 | rc = snprintf(retstring, IPSCAN_FETCHNUM_STRING_MAX, "%s:%d", "UNKNOWN", fetchnum); 204 | } 205 | // Report error - does IPSCAN_FETCHNUM_STRING_MAX need increasing? 206 | if (rc < 0 || rc >= IPSCAN_FETCHNUM_STRING_MAX) 207 | { 208 | IPSCAN_LOG( LOGPREFIX "ipscan: ERROR : Cannot fit fetchnum string into buffer, returned %d\n", rc); 209 | } 210 | 211 | return; 212 | } 213 | 214 | 215 | // 216 | // ----------------------------------------------------------------------------- 217 | // 218 | char * state_to_string(int statenum, char * retstringptr, int retstringfree) 219 | { 220 | if (0 >= retstringfree) return (char *)NULL; 221 | char * retstringptrstart = retstringptr; 222 | int rc = 0; 223 | rc = snprintf(retstringptr, retstringfree, "%s", "flags: "); 224 | if (rc < 0 || rc >= retstringfree) return (char *)NULL; 225 | retstringptr += rc; 226 | retstringfree -= rc; 227 | 228 | if (0 != (statenum & PORTUNKNOWN)) 229 | { 230 | rc = snprintf(retstringptr, retstringfree, "%s", "UNKNOWN, "); 231 | if (rc < 0 || rc >= retstringfree) return (char *)NULL; 232 | retstringptr += rc; 233 | retstringfree -= rc; 234 | } 235 | if (0 != (statenum & IPSCAN_TESTSTATE_RUNNING_BIT)) 236 | { 237 | rc = snprintf(retstringptr, retstringfree, "%s", "RUNNING, "); 238 | if (rc < 0 || rc >= retstringfree) return (char *)NULL; 239 | retstringptr += rc; 240 | retstringfree -= rc; 241 | } 242 | if (0 != (statenum & IPSCAN_TESTSTATE_COMPLETE_BIT)) 243 | { 244 | rc = snprintf(retstringptr, retstringfree, "%s", "COMPLETE, "); 245 | if (rc < 0 || rc >= retstringfree) return (char *)NULL; 246 | retstringptr += rc; 247 | retstringfree -= rc; 248 | } 249 | if (0 != (statenum & IPSCAN_TESTSTATE_HTTPTIMEOUT_BIT)) 250 | { 251 | rc = snprintf(retstringptr, retstringfree, "%s", "TIMEOUT, "); 252 | if (rc < 0 || rc >= retstringfree) return (char *)NULL; 253 | retstringptr += rc; 254 | retstringfree -= rc; 255 | } 256 | if (0 != (statenum & IPSCAN_TESTSTATE_EVALERROR_BIT)) 257 | { 258 | rc = snprintf(retstringptr, retstringfree, "%s", "EVALERROR, "); 259 | if (rc < 0 || rc >= retstringfree) return (char *)NULL; 260 | retstringptr += rc; 261 | retstringfree -= rc; 262 | } 263 | if (0 != (statenum & IPSCAN_TESTSTATE_OTHERERROR_BIT)) 264 | { 265 | rc = snprintf(retstringptr, retstringfree, "%s", "OTHERERROR, "); 266 | if (rc < 0 || rc >= retstringfree) return (char *)NULL; 267 | retstringptr += rc; 268 | retstringfree -= rc; 269 | } 270 | if (0 != (statenum & IPSCAN_TESTSTATE_NAVAWAY_BIT)) 271 | { 272 | rc = snprintf(retstringptr, retstringfree, "%s", "NAVAWAY, "); 273 | if (rc < 0 || rc >= retstringfree) return (char *)NULL; 274 | retstringptr += rc; 275 | retstringfree -= rc; 276 | } 277 | if (0 != (statenum & IPSCAN_TESTSTATE_UNEXPCHANGE_BIT)) 278 | { 279 | rc = snprintf(retstringptr, retstringfree, "%s", "UNEXPECTED, "); 280 | if (rc < 0 || rc >= retstringfree) return (char *)NULL; 281 | retstringptr += rc; 282 | retstringfree -= rc; 283 | } 284 | if (0 != (statenum & IPSCAN_TESTSTATE_BADCOMPLETE_BIT)) 285 | { 286 | rc = snprintf(retstringptr, retstringfree, "%s", "BADCOMPLETE, "); 287 | if (rc < 0 || rc >= retstringfree) return (char *)NULL; 288 | retstringptr += rc; 289 | retstringfree -= rc; 290 | } 291 | if (0 != (statenum & IPSCAN_TESTSTATE_DATABASE_ERROR_BIT)) 292 | { 293 | rc = snprintf(retstringptr, retstringfree, "%s", "DB ERROR, "); 294 | if (rc < 0 || rc >= retstringfree) return (char *)NULL; 295 | retstringptr += rc; 296 | retstringfree -= rc; 297 | } 298 | rc = snprintf(retstringptr, retstringfree, "%s", "\n\0"); 299 | if (rc < 0 || rc >= retstringfree) return (char *)NULL; 300 | retstringptr += rc; 301 | retstringfree -= rc; 302 | if (0 > retstringfree) return (char *)NULL; 303 | return retstringptrstart; 304 | } 305 | 306 | 307 | // 308 | // ----------------------------------------------------------------------------- 309 | // 310 | void result_to_string(int result, char * retstring) 311 | { 312 | int rc; 313 | char hosttype[16]; 314 | if (IPSCAN_INDIRECT_RESPONSE <= result) 315 | { 316 | result -= IPSCAN_INDIRECT_RESPONSE; 317 | strncpy(hosttype, "indirect:", 15); 318 | } 319 | else 320 | { 321 | strncpy(hosttype, "", 15); 322 | } 323 | 324 | if (PORTOPEN == result) 325 | { 326 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "OPEN"); 327 | } 328 | else if (PORTABORT == result) 329 | { 330 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "ABORT"); 331 | } 332 | else if (PORTREFUSED == result) 333 | { 334 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "REFUSED"); 335 | } 336 | else if (PORTCRESET == result) 337 | { 338 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "CRESET"); 339 | } 340 | else if (PORTNRESET == result) 341 | { 342 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "NRESET"); 343 | } 344 | else if (PORTINPROGRESS == result) 345 | { 346 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "IN-PROGRESS"); 347 | } 348 | else if (PORTPROHIBITED == result) 349 | { 350 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "PROHIBITED"); 351 | } 352 | else if (PORTUNREACHABLE == result) 353 | { 354 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "UNREACHABLE"); 355 | } 356 | else if (PORTNOROUTE == result) 357 | { 358 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "NO ROUTE"); 359 | } 360 | else if (PORTPKTTOOBIG == result) 361 | { 362 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "PKT TOO BIG"); 363 | } 364 | else if (PORTPARAMPROB == result) 365 | { 366 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "PARAM PROBLEM"); 367 | } 368 | else if (ECHONOREPLY == result) 369 | { 370 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "ECHO NO-REPLY"); 371 | } 372 | else if (ECHOREPLY == result) 373 | { 374 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "ECHO REPLY"); 375 | } 376 | else if (UDPOPEN == result) 377 | { 378 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "UDP OPEN"); 379 | } 380 | else if (UDPSTEALTH == result) 381 | { 382 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "UDP STEALTH"); 383 | } 384 | else if (PORTUNEXPECTED == result) 385 | { 386 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "UNEXPECTED"); 387 | } 388 | else if (PORTUNKNOWN == result) 389 | { 390 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "UNKNOWN"); 391 | } 392 | else if (PORTINTERROR == result) 393 | { 394 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, "INTERNAL ERROR"); 395 | } 396 | else if (PORTEOL == result) 397 | { 398 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s%s", hosttype, ""); 399 | } 400 | else 401 | { 402 | rc = snprintf(retstring, IPSCAN_RESULT_STRING_MAX, "%s-%s:%d", "", hosttype, result); 403 | } 404 | // Report error - does IPSCAN_RESULT_STRING_MAX need increasing? 405 | if (rc < 0 || rc >= IPSCAN_RESULT_STRING_MAX) 406 | { 407 | IPSCAN_LOG( LOGPREFIX "ipscan: ERROR : Cannot fit result string into buffer, returned %d\n", rc); 408 | } 409 | 410 | return; 411 | } 412 | 413 | // 414 | // ----------------------------------------------------------------------------- 415 | // 416 | void report_agent_string(char * agentstringvar, const char *varname, unsigned int error1ignore0) 417 | { 418 | // Note that none of this content can be trusted - so agressively limit the character set 419 | char agentstring[ (MAXUSERAGENTLEN + 1) ]; 420 | unsigned int i; 421 | // Pre-clear array since using sscanf with %Nc doesn't guarantee string will be 0 terminated 422 | memset(agentstring, 0, sizeof(agentstring)); 423 | 424 | if ( NULL == agentstringvar ) 425 | { 426 | if (1 == error1ignore0) 427 | { 428 | IPSCAN_LOG( LOGPREFIX "ipscan: ERROR : %s variable lookup returned NULL.\n", varname); 429 | } 430 | } 431 | else if ( strnlen(agentstringvar, (MAXUSERAGENTLEN+1)) > MAXUSERAGENTLEN ) 432 | { 433 | IPSCAN_LOG( LOGPREFIX "ipscan: ERROR: %s variable string is longer than allocated buffer (%d > %d)\n", varname,\ 434 | (int)strnlen(agentstringvar, (MAXUSERAGENTLEN+1)), MAXUSERAGENTLEN); 435 | } 436 | else if ( sscanf(agentstringvar,"%"TO_STR(MAXUSERAGENTLEN)"c",agentstring) != EOF ) 437 | { 438 | if (strnlen(agentstring, MAXUSERAGENTLEN+1) > MAXUSERAGENTLEN) 439 | { 440 | agentstring[0] = 0; // truncate string 441 | } 442 | else 443 | { 444 | for ( i = 0 ; i < strnlen(agentstring, MAXUSERAGENTLEN+1) ; i++ ) 445 | { 446 | // Clamp to printable ASCII range - but ensure 0 is not corrupted 447 | if ( (agentstring[i] > 0 && agentstring[i] < 32) || agentstring[i] > 126 ) agentstring[i] = 32; 448 | // and also protect against special characters which could be used for XSS 449 | switch (agentstring[i]) 450 | { 451 | case '<': 452 | case '>': 453 | case ':': 454 | case ';': 455 | case '&': 456 | case '\\': 457 | case '\"': 458 | case '/': 459 | case '=': 460 | case '*': 461 | case ',': 462 | case '^': 463 | case '$': 464 | case '|': 465 | case '%': 466 | case '{': 467 | case '}': 468 | case '!': 469 | case '[': 470 | case ']': 471 | case '?': 472 | agentstring[i] = ' '; 473 | break; 474 | 475 | default: 476 | // do nothing 477 | break; 478 | } 479 | } 480 | } 481 | size_t left = 0; 482 | size_t right = strnlen(agentstring,MAXUSERAGENTLEN+1); 483 | if (MAXUSERAGENTLEN < right) 484 | { 485 | // no end-of-string '0' found, so insert one 486 | agentstring[MAXUSERAGENTLEN] = 0; 487 | right = strnlen(agentstring,MAXUSERAGENTLEN+1); 488 | } 489 | // skip left-leading spaces 490 | while (left < right && left < MAXUSERAGENTLEN && agentstring[left]==' ') 491 | { 492 | left++; 493 | } 494 | // truncate right-trailing spaces and zeroes 495 | while ((agentstring[right]==' ' || agentstring[right]==0) && right > left && right > 0) 496 | { 497 | agentstring[right] = 0; 498 | right--; 499 | } 500 | IPSCAN_LOG( LOGPREFIX "ipscan: INFO: %s = '%s'\n", varname, &agentstring[left]); 501 | } 502 | else 503 | { 504 | IPSCAN_LOG( LOGPREFIX "ipscan: ERROR: %s variable not reportable.\n", varname); 505 | } 506 | } 507 | 508 | // 509 | // ----------------------------------------------------------------------------- 510 | // 511 | void report_useragent_strings(char *uavar, char *secchuavar, char *secchuaarchvar, char *secchuaarchplatvar) 512 | { 513 | // Note that content cannot be trusted - so agressively limit the character set 514 | report_agent_string(uavar, "HTTP_USER_AGENT", 1); 515 | report_agent_string(secchuavar, "HTTP_SEC_CH_UA", 0); 516 | report_agent_string(secchuaarchvar, "HTTP_SEC_CH_UA_ARCH", 0); 517 | report_agent_string(secchuaarchplatvar, "HTTP_SEC_CH_UA_PLATFORM", 0); 518 | } 519 | 520 | // 521 | // ----------------------------------------------------------------------------- 522 | // 523 | void report_ipscan_versions(const char *mainver, const char *generalver, const char *tcpver, const char *udpver, const char *icmpv6ver, const char *dbver,\ 524 | const char *webver, const char *hver, const char *plver) 525 | { 526 | IPSCAN_LOG( LOGPREFIX "ipscan: INFO: IPSCAN_MAIN_VER = %-4s, IPSCAN_GENERAL_VER = %-4s, IPSCAN_WEB_VER = %-4s, IPSCAN_H_VER = %-4s\n", mainver, generalver, webver, hver); 527 | IPSCAN_LOG( LOGPREFIX "ipscan: INFO: IPSCAN_TCP_VER = %-4s, IPSCAN_UDP_VER = %-4s, IPSCAN_ICMPV6_VER = %-4s, IPSCAN_DB_VER = %-4s\n", tcpver, udpver, icmpv6ver, dbver); 528 | IPSCAN_LOG( LOGPREFIX "ipscan: INFO: IPSCAN_PORTLIST_VER = %-4s\n", plver); 529 | } 530 | 531 | // 532 | // ----------------------------------------------------------------------------- 533 | // 534 | int querystring_is_alphanum(char check) 535 | { 536 | int retval = 0; 537 | // allow a-z,0-9 538 | if ((check >= 'a' && check <= 'z') || (check >= '0' && check <= '9')) 539 | { 540 | retval = 1; 541 | } 542 | return (retval); 543 | } 544 | 545 | // 546 | // ----------------------------------------------------------------------------- 547 | // 548 | int querystring_is_valid(char check) 549 | { 550 | int retval = 0; 551 | // allow &,=,a-z,0-9,+,- 552 | if (check == '&' || check == '=' || (check >= 'a' && check <= 'z') || (check >= '0' && check <= '9') || check == '+' || check == '-') 553 | { 554 | retval = 1; 555 | } 556 | return (retval); 557 | } 558 | 559 | // 560 | // ----------------------------------------------------------------------------- 561 | // 562 | int querystring_is_number(char check) 563 | { 564 | int retval = 0; 565 | // allow 0-9,+,- 566 | if ( (check >= '0' && check <= '9') || check == '+' || check == '-' ) 567 | { 568 | retval = 1; 569 | } 570 | return (retval); 571 | } 572 | 573 | -------------------------------------------------------------------------------- /ipscan_icmpv6.c: -------------------------------------------------------------------------------- 1 | // IPscan - an HTTP-initiated IPv6 port scanner. 2 | // 3 | // Copyright (C) 2011-2025 Tim Chappell. 4 | // 5 | // This file is part of IPscan. 6 | // 7 | // IPscan is free software: you can redistribute it and/or modify 8 | // it under the terms of the GNU General Public License as published by 9 | // the Free Software Foundation, either version 3 of the License, or 10 | // (at your option) any later version. 11 | // 12 | // This program is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | // GNU General Public License for more details. 16 | // 17 | // You should have received a copy of the GNU General Public License 18 | // along with IPscan. If not, see . 19 | 20 | // ipscan_icmpv6.c version 21 | // 0.1 initial version after splitting from ipscan_checks.c 22 | // 0.2 add prefixes to debug log output 23 | // 0.3 move to memset() 24 | // 0.4 ensure minimum timings are met 25 | // 0.5 ensure txid doesn't exceed 16-bits (move to random session ID) 26 | // 0.6 clear msghdr.msg_flags 27 | // 0.7 add time() checks 28 | // 0.8 update copyright year 29 | // 0.9 update copyright year 30 | // 0.10 update copyright year 31 | // 0.11 extern no longer defined here 32 | // 0.12 correct signedness of sprintf/sscanf used for packet data 33 | // 0.13 update copyright year 34 | // 0.14 swap comparison terms, where appropriate 35 | // 0.15 delete old comments, update copyright year 36 | // 0.16 add missing error checks for inet_ntop calls 37 | // 0.17 and snprintf for router too 38 | // 0.18 update copyright year 39 | // 0.19 update copyright year 40 | // 0.20 add (potentially) missing length check 41 | 42 | // 43 | #define IPSCAN_ICMPV6_VER "0.20" 44 | // 45 | 46 | #include "ipscan.h" 47 | // 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | 59 | // IPv6 address conversion 60 | #include 61 | 62 | // String comparison 63 | #include 64 | 65 | // Logging with syslog requires additional include 66 | #if (LOGMODE == 1) 67 | #include 68 | #endif 69 | 70 | // Others that FreeBSD highlighted 71 | #include 72 | #include 73 | #include 74 | 75 | // Other IPv6 related 76 | #include 77 | #include 78 | 79 | //Poll support 80 | #include 81 | 82 | // Define offset into ICMPv6 packet where user-defined data resides 83 | #define ICMP6DATAOFFSET sizeof(struct icmp6_hdr) 84 | 85 | // 86 | // report version 87 | // 88 | const char* ipscan_icmpv6_ver(void) 89 | { 90 | return IPSCAN_ICMPV6_VER; 91 | } 92 | 93 | // 94 | // Send an ICMPv6 ECHO-REQUEST and see whether we receive an ECHO-REPLY in response 95 | // 96 | 97 | uint32_t check_icmpv6_echoresponse(char * hostname, uint64_t starttime, uint64_t session, char * router) 98 | { 99 | struct addrinfo *res; 100 | struct addrinfo hints; 101 | 102 | struct sockaddr_in6 destination; 103 | struct sockaddr_in6 source; 104 | 105 | int sock = -1; 106 | int errsv; 107 | int rc; 108 | int error; 109 | unsigned int sendsize; 110 | const char * rccharptr; 111 | 112 | struct timeval timeout; 113 | 114 | struct icmp6_hdr *txicmp6hdr_ptr; 115 | struct icmp6_hdr *rxicmp6hdr_ptr; 116 | 117 | struct icmp6_filter myfilter; 118 | // reply tracker 119 | unsigned int foundit = 0; 120 | 121 | // send and receive message headers 122 | struct msghdr smsghdr; 123 | struct msghdr rmsghdr; 124 | struct iovec txiov[2], rxiov[2]; 125 | char txpackdata[ICMPV6_PACKET_BUFFER_SIZE]; 126 | char rxpackdata[ICMPV6_PACKET_BUFFER_SIZE]; 127 | char *rxpacket = &rxpackdata[0]; 128 | char rxbuf[ICMPV6_PACKET_BUFFER_SIZE]; 129 | char tmpbuf[128]; 130 | 131 | // set return value to a known default 132 | int retval = PORTUNKNOWN; 133 | 134 | txicmp6hdr_ptr = (struct icmp6_hdr *)txpackdata; 135 | 136 | struct pollfd pollfiledesc[1]; 137 | 138 | unsigned int txid = (unsigned int)(session & 0xFFFF); // Maximum 16 bits 139 | unsigned int rxid; 140 | unsigned int txseqno = ICMPV6_MAGIC_SEQ; // MAGIC number - assume no reason to start at 1? 141 | unsigned int rxseqno; 142 | 143 | unsigned int rxicmp6_type, rxicmp6_code; 144 | 145 | memset(&hints, 0, sizeof(hints)); 146 | hints.ai_family = AF_INET6; 147 | hints.ai_flags = AI_CANONNAME; 148 | hints.ai_socktype = SOCK_RAW; 149 | hints.ai_protocol = IPPROTO_ICMPV6; 150 | 151 | error = getaddrinfo(hostname, NULL, &hints, &res); 152 | if (error != 0) 153 | { 154 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: getaddrinfo: failed1 %s for host %s\n", gai_strerror(error), hostname); 155 | return (PORTINTERROR); 156 | } 157 | 158 | if (!res->ai_addr) 159 | { 160 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: getaddrinfo: failed2 %s for host %s\n",gai_strerror(error), hostname); 161 | freeaddrinfo(res); 162 | return (PORTINTERROR); 163 | } 164 | 165 | // Copy the resulting address into our destination if there is sufficient room 166 | memset(&destination, 0, sizeof(struct sockaddr_in6)); 167 | if (res->ai_addrlen <= sizeof(struct sockaddr_in6)) 168 | { 169 | memcpy(&destination, res->ai_addr, res->ai_addrlen); 170 | } 171 | // Done with the address info now, so free the area 172 | freeaddrinfo(res); 173 | 174 | // Set default logged router address to dead::1 (valid format IPv6 address) 175 | rc = snprintf(router, INET6_ADDRSTRLEN, "dead::1"); 176 | if (rc < 0 || rc >= INET6_ADDRSTRLEN) 177 | { 178 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: Failed to unset logged router address, rc was %d\n", rc); 179 | memset(router, 0, INET6_ADDRSTRLEN); 180 | retval = PORTINTERROR; 181 | } 182 | 183 | // Get root privileges in order to create the raw socket 184 | 185 | uid_t uid = getuid(); 186 | uid_t gid = getgid(); 187 | 188 | #ifdef PINGDEBUG 189 | uid_t euid = geteuid(); 190 | uid_t egid = getegid(); 191 | #endif 192 | 193 | #ifdef PINGDEBUG 194 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: Entered with real UID %d real GID %d effective UID %d effective GID %d\n", uid, gid, euid, egid); 195 | #endif 196 | 197 | rc = setuid(0); 198 | if (rc != 0) 199 | { 200 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: setuid: failed to gain root privileges - is setuid permission set?\n"); 201 | retval = PORTINTERROR; 202 | } 203 | 204 | rc = setgid(0); 205 | if (rc != 0) 206 | { 207 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: setgid: failed to gain root privileges - is setgid permission set?\n"); 208 | retval = PORTINTERROR; 209 | } 210 | 211 | // run with ROOT privileges, keep section to a minimum 212 | if (PORTUNKNOWN == retval) 213 | { 214 | sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 215 | errsv = errno; 216 | if (sock < 0) 217 | { 218 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: socket: Error : %s (%d) for host %s\n", strerror(errsv), errsv, hostname); 219 | retval = PORTINTERROR; 220 | } 221 | else 222 | { 223 | memset(&timeout, 0, sizeof(timeout)); 224 | timeout.tv_sec = TIMEOUTSECS; 225 | timeout.tv_usec = TIMEOUTMICROSECS; 226 | 227 | rc = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); 228 | errsv = errno; 229 | if (rc < 0) 230 | { 231 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: Bad setsockopt SO_SNDTIMEO set, returned %d (%s)\n", errsv, strerror(errsv)); 232 | retval = PORTINTERROR; 233 | } 234 | 235 | memset(&timeout, 0, sizeof(timeout)); 236 | timeout.tv_sec = TIMEOUTSECS; 237 | timeout.tv_usec = TIMEOUTMICROSECS; 238 | 239 | rc = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); 240 | errsv = errno; 241 | if (rc < 0) 242 | { 243 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: Bad setsockopt SO_RCVTIMEO set, returned %d (%s)\n", errsv, strerror(errsv)); 244 | retval = PORTINTERROR; 245 | } 246 | 247 | // Filter out everything except the responses we're looking for 248 | // taken from RFC3542 249 | ICMP6_FILTER_SETBLOCKALL(&myfilter); 250 | ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &myfilter); 251 | ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &myfilter); 252 | ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &myfilter); 253 | ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &myfilter); 254 | ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &myfilter); 255 | rc = setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &myfilter, sizeof(myfilter)); 256 | errsv = errno; 257 | if (rc < 0) 258 | { 259 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: setsockopt: Error setting ICMPv6 filter: %s (%d)\n", strerror(errsv), errsv); 260 | retval = PORTINTERROR; 261 | } 262 | 263 | #ifdef PINGDEBUG 264 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: Exiting privileged user code section\n"); 265 | #endif 266 | 267 | } // end if (socket created successfully) 268 | } 269 | 270 | // END OF ROOT PRIVILEGES - Revert to previous privilege level 271 | rc = setgid(gid); 272 | if (rc != 0) 273 | { 274 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: setgid: failed to revoke root gid privileges\n"); 275 | retval = PORTINTERROR; 276 | } 277 | 278 | rc = setuid(uid); 279 | if (rc != 0) 280 | { 281 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: setuid: failed to revoke root uid privileges\n"); 282 | retval = PORTINTERROR; 283 | } 284 | 285 | // If something bad has happened then return now ... 286 | // mustn't return to caller with root privileges, hence done here ... 287 | if (PORTUNKNOWN != retval) 288 | { 289 | if (-1 != sock) close(sock); // close socket if appropriate 290 | return(retval); 291 | } 292 | 293 | #ifdef PINGDEBUG 294 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: Post-revoke real UID %d real GID %d effective UID %d effective GID %d\n", getuid (), getgid (), geteuid(), getegid()); 295 | #endif 296 | 297 | // ----------------------------------------------- 298 | // 299 | // ICMPv6 ECHO-REQUEST TRANSMIT 300 | // 301 | // ----------------------------------------------- 302 | 303 | memset( txicmp6hdr_ptr, 0, sizeof(struct icmp6_hdr)); 304 | txicmp6hdr_ptr->icmp6_cksum = 0; 305 | txicmp6hdr_ptr->icmp6_type = ICMP6_ECHO_REQUEST; 306 | txicmp6hdr_ptr->icmp6_code = 0; 307 | txicmp6hdr_ptr->icmp6_id = htons(txid); 308 | txicmp6hdr_ptr->icmp6_seq = htons(txseqno); 309 | 310 | // socket address 311 | memset(&smsghdr, 0, sizeof(smsghdr)); 312 | smsghdr.msg_name = (caddr_t)&destination; 313 | smsghdr.msg_namelen = sizeof(destination); 314 | 315 | // Insert the unique data 316 | #ifdef PINGDEBUG 317 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: Sending PING unique data starttime=%"PRId64" session=%"PRId64"\n", starttime, session); 318 | #endif 319 | 320 | rc = snprintf(&txpackdata[ICMP6DATAOFFSET],(ICMPV6_PACKET_SIZE-ICMP6DATAOFFSET),"%"PRIu64" %"PRIu64" %u %u", starttime, session, ICMPV6_MAGIC_VALUE1, ICMPV6_MAGIC_VALUE2); 321 | if (rc < (int)0 || rc >= (int)(ICMPV6_PACKET_SIZE-ICMP6DATAOFFSET)) 322 | { 323 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: txpackdata snprintf returned %d, expected >=0 but < %d\n", rc, (int)(ICMPV6_PACKET_SIZE-ICMP6DATAOFFSET)); 324 | retval = PORTINTERROR; 325 | if (-1 != sock) close(sock); // close socket if appropriate 326 | return(retval); 327 | } 328 | 329 | // Choose a packet slightly bigger than minimum size 330 | sendsize = ICMPV6_PACKET_SIZE; 331 | 332 | rc = getnameinfo((struct sockaddr *)&destination, sizeof(destination), tmpbuf, sizeof(tmpbuf), NULL, 0, NI_NUMERICHOST); 333 | errsv = errno; 334 | if (0 == rc) 335 | { 336 | #ifdef PINGDEBUG 337 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: Transmitted destination address was %s\n", tmpbuf); 338 | #endif 339 | } 340 | else 341 | { 342 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: RESTART: getnameinfo returned bad indication %d (%s)\n",errsv, gai_strerror(errsv)); 343 | retval = PORTINTERROR; 344 | if (-1 != sock) close(sock); // close socket if appropriate 345 | return(retval); 346 | } 347 | 348 | // scatter/gather array 349 | memset(&txiov, 0, sizeof(txiov)); 350 | txiov[0].iov_base = (caddr_t)&txpackdata; 351 | txiov[0].iov_len = sendsize; 352 | smsghdr.msg_iov = txiov; 353 | smsghdr.msg_iovlen = 1; 354 | 355 | rc = sendmsg(sock, &smsghdr, 0); 356 | errsv = errno; 357 | 358 | if (rc < 0) 359 | { 360 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: sendmsg returned error, with errno %d (%s)\n", errsv, strerror(errsv)); 361 | retval = PORTINTERROR; 362 | if (-1 != sock) close(sock); // close socket if appropriate 363 | return(retval); 364 | } 365 | 366 | if (rc != (int)sendsize) 367 | { 368 | IPSCAN_LOG( LOGPREFIX"check_icmpv6_echoresponse: requested sendmsg sent %d chars to %s but sendmsg returned %d\n", sendsize, hostname, rc); 369 | retval = PORTINTERROR; 370 | if (-1 != sock) close(sock); // close socket if appropriate 371 | return(retval); 372 | } 373 | 374 | // ----------------------------------------------- 375 | // 376 | // // ICMPv6 ECHO-REPLY RECEIVE 377 | // 378 | // ----------------------------------------------- 379 | 380 | // indirect determines whether a host other than the intended target has replied 381 | int indirect = 0; 382 | time_t timestart = time(0); 383 | if (timestart < 0) 384 | { 385 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: ERROR: time() returned bad value for timestart %d (%s)\n", errno, strerror(errno)); 386 | } 387 | time_t timenow = timestart; 388 | unsigned int loopcount = 0; 389 | 390 | // Effectively a promiscuous receive of ICMPv6 packets, so need to discern which are for us 391 | // ... may need to go round this loop more than once ... 392 | 393 | while ( ((timenow - timestart) <= 1+TIMEOUTSECS) && foundit == 0) 394 | { 395 | loopcount++; 396 | #ifdef PINGDEBUG 397 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: Beginning time %d through the loop.\n", loopcount); 398 | #endif 399 | 400 | pollfiledesc[0].fd = sock; 401 | // Want indication that there is something to read 402 | pollfiledesc[0].events = POLLIN; 403 | rc = poll(pollfiledesc, 1, 1000*TIMEOUTSECS); 404 | errsv = errno; 405 | // Capture current time for next timeout comparison 406 | timenow = time(0); 407 | if (timenow < 0) 408 | { 409 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: ERROR: time() returned bad value for timenow %d (%s)\n", errno, strerror(errno)); 410 | } 411 | 412 | if (rc < 0) 413 | { 414 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: RESTART: poll returned bad things : %d (%s)\n", errsv, strerror(errsv)); 415 | continue; 416 | } 417 | else if (rc == 0) 418 | { 419 | #ifdef PINGDEBUG 420 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: RESTART: poll returned 0 results\n"); 421 | #endif 422 | continue; 423 | } 424 | 425 | #ifdef PINGDEBUG 426 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: poll returned events = %d\n", pollfiledesc[0].revents); 427 | #endif 428 | 429 | if ( (pollfiledesc[0].revents & POLLIN) != POLLIN) 430 | { 431 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: RESTART: poll returned but failed to find POLLIN set: %d\n",pollfiledesc[0].revents); 432 | continue; 433 | } 434 | 435 | rmsghdr.msg_name = (caddr_t)&source; 436 | rmsghdr.msg_namelen = sizeof(source); 437 | memset(&rxiov, 0, sizeof(rxiov)); 438 | rxiov[0].iov_base = (caddr_t)rxpacket; 439 | rxiov[0].iov_len = ICMPV6_PACKET_BUFFER_SIZE; 440 | rmsghdr.msg_iov = rxiov; 441 | rmsghdr.msg_iovlen = 1; 442 | rmsghdr.msg_control = (caddr_t)rxbuf; 443 | rmsghdr.msg_controllen = sizeof(rxbuf); 444 | rmsghdr.msg_flags = 0; // filled on receive 445 | rc = recvmsg(sock, &rmsghdr, 0); 446 | errsv = errno; 447 | if (rc < 0) 448 | { 449 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: RESTART: recvmsg returned bad things : %d (%s)\n", errsv, strerror(errsv)); 450 | continue; 451 | } 452 | else if (rc == 0) 453 | { 454 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: RESTART: recvmsg returned 0 - is this a control message?\n"); 455 | continue; 456 | } 457 | else 458 | { 459 | int rxpacketsize = rc; 460 | #ifdef PINGDEBUG 461 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: recvmsg returned indicating %d bytes received\n",rc); 462 | #endif 463 | 464 | if (rxpacketsize < (int)sizeof(struct icmp6_hdr)) 465 | { 466 | #ifdef PINGDEBUG 467 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: Received packet too small - expected at least %d, got %d\n",(int)sizeof(struct icmp6_hdr),rxpacketsize); 468 | #endif 469 | continue; 470 | } 471 | 472 | if (rmsghdr.msg_namelen != sizeof(struct sockaddr_in6)) 473 | { 474 | #ifdef PINGDEBUG 475 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: received bad peername length (namelen %d)\n",rmsghdr.msg_namelen); 476 | #endif 477 | continue; 478 | } 479 | 480 | if (((struct sockaddr *)rmsghdr.msg_name)->sa_family != AF_INET6) 481 | { 482 | #ifdef PINGDEBUG 483 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: received bad peername family (sa_family %d)\n",((struct sockaddr *)rmsghdr.msg_name)->sa_family); 484 | #endif 485 | continue; 486 | } 487 | 488 | rc = getnameinfo((struct sockaddr *)&source, sizeof(source), tmpbuf, sizeof(tmpbuf), NULL, 0, NI_NUMERICHOST); 489 | errsv = errno; 490 | if (0 == rc) 491 | { 492 | #ifdef PINGDEBUG 493 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: Received source address was %s\n", tmpbuf); 494 | #endif 495 | } 496 | else 497 | { 498 | #ifdef PINGDEBUG 499 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: getnameinfo returned bad indication %d (%s)\n",errsv, gai_strerror(errsv)); 500 | #endif 501 | continue; 502 | } 503 | 504 | // Store the outer packet address in case we do have a valid response from a machine(router) other than 505 | // the intended target 506 | rccharptr = inet_ntop(AF_INET6, &(source.sin6_addr), router, INET6_ADDRSTRLEN); 507 | errsv = errno; 508 | if (NULL == rccharptr) 509 | { 510 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: ERROR: inet_ntop() for router returned bad indication %d (%s)\n", errsv, strerror(errsv)); 511 | memset(router, 0, INET6_ADDRSTRLEN); 512 | } 513 | 514 | // Extract ICMPv6 type and code for checking and reporting 515 | rxicmp6hdr_ptr = (struct icmp6_hdr *)rxpacket; 516 | rxicmp6_type = rxicmp6hdr_ptr->icmp6_type; 517 | rxicmp6_code = rxicmp6hdr_ptr->icmp6_code; 518 | // Extract sequence number and ID 519 | rxseqno = htons(rxicmp6hdr_ptr->icmp6_seq); 520 | rxid = htons(rxicmp6hdr_ptr->icmp6_id); 521 | 522 | #ifdef PINGDEBUG 523 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 524 | #endif 525 | 526 | // Check whether our tx destination address equals our rx source 527 | // RFC3542 section 2.3 macro returns non-zero if addresses equal, otherwise 0 528 | if ( IN6_ARE_ADDR_EQUAL( &(source.sin6_addr), &(destination.sin6_addr) ) == 0 ) 529 | { 530 | 531 | #ifdef PINGDEBUG 532 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: OUTER IPv6 hdr src address (%s) did not match our tx dest address\n", router); 533 | #endif 534 | 535 | // if a router replied instead of the host under test then size will be original packet plus an IPv6 header 536 | if ( rxpacketsize == (int)(sizeof(struct ip6_hdr) + 8 + sendsize) ) 537 | { 538 | char tx_dst_addr[INET6_ADDRSTRLEN], orig_src_addr[INET6_ADDRSTRLEN], orig_dst_addr[INET6_ADDRSTRLEN]; 539 | struct ip6_hdr *rx2ip6hdr_ptr; 540 | struct icmp6_hdr *rx2icmp6hdr_ptr; 541 | rx2ip6hdr_ptr = (struct ip6_hdr *)&rxpacket[sizeof(struct icmp6_hdr)]; 542 | // struct in6_addr ip6_src and ip6_dst 543 | struct in6_addr orig_dst = rx2ip6hdr_ptr->ip6_dst; 544 | struct in6_addr orig_src = rx2ip6hdr_ptr->ip6_src; 545 | unsigned int nextheader = rx2ip6hdr_ptr->ip6_nxt; 546 | 547 | rccharptr = inet_ntop(AF_INET6, &orig_src, orig_src_addr, INET6_ADDRSTRLEN); 548 | errsv = errno; 549 | if (NULL == rccharptr) 550 | { 551 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: ERROR: inet_ntop() for orig_src_addr returned bad indication %d (%s)\n", errsv, strerror(errsv)); 552 | memset(orig_src_addr, 0, INET6_ADDRSTRLEN); 553 | } 554 | // original source address would be our IPv6 address 555 | // TODO - perhaps we should be checking this for completeness ... 556 | 557 | rccharptr = inet_ntop(AF_INET6, &orig_dst, orig_dst_addr, INET6_ADDRSTRLEN); 558 | errsv = errno; 559 | if (NULL == rccharptr) 560 | { 561 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: ERROR: inet_ntop() for orig_dst_addr returned bad indication %d (%s)\n", errsv, strerror(errsv)); 562 | memset(orig_dst_addr, 0, INET6_ADDRSTRLEN); 563 | } 564 | // original destination should match our transmitted destination address 565 | 566 | rccharptr = inet_ntop(AF_INET6, &(destination.sin6_addr), tx_dst_addr, INET6_ADDRSTRLEN); 567 | errsv = errno; 568 | if (NULL == rccharptr) 569 | { 570 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: ERROR: inet_ntop() for tx_dst_addr returned bad indication %d (%s)\n", errsv, strerror(errsv)); 571 | memset(tx_dst_addr, 0, INET6_ADDRSTRLEN); 572 | } 573 | 574 | #ifdef PINGDEBUG 575 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: INNER packet details: src %s ; dst %s; nextheader %d\n", orig_src_addr, orig_dst_addr, nextheader); 576 | #endif 577 | 578 | // if addresses don't match then it was returned in response to another packet, 579 | // so this packet is not relevant to us ... 580 | if ( IN6_ARE_ADDR_EQUAL( &orig_dst, &(destination.sin6_addr) ) == 0) 581 | { 582 | #ifdef PINGDEBUG 583 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: INNER IPv6 hdr dst %s was != our Tx dst %s\n", orig_dst_addr, tx_dst_addr); 584 | #endif 585 | continue; 586 | } 587 | 588 | // Check that the next header is ICMPv6, otherwise not in response to our tx 589 | if (nextheader == IPPROTO_ICMPV6) 590 | { 591 | rx2icmp6hdr_ptr = (struct icmp6_hdr *)&rxpacket[sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr)]; 592 | unsigned int rx2icmp6_type = rx2icmp6hdr_ptr->icmp6_type; 593 | unsigned int rx2icmp6_code = rx2icmp6hdr_ptr->icmp6_code; 594 | // Extract sequence number and ID 595 | unsigned int rx2seqno = htons(rx2icmp6hdr_ptr->icmp6_seq); 596 | unsigned int rx2id = htons(rx2icmp6hdr_ptr->icmp6_id); 597 | 598 | // Check inner ICMPv6 packet was an ECHO_REQUEST 599 | if (rx2icmp6_type != ICMP6_ECHO_REQUEST) 600 | { 601 | #ifdef PINGDEBUG 602 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: INNER ICMPv6_TYPE was not ECHO_REQUEST : %d\n", rx2icmp6_type); 603 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 604 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet details: src %s ; dst %s; nextheader %d\n", orig_src_addr, orig_dst_addr, nextheader); 605 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet icmp6 details: type %d; code %d; seq %d; id %d\n", rx2icmp6_type, rx2icmp6_code, rx2seqno, rx2id); 606 | #endif 607 | continue; 608 | } 609 | 610 | // Check inner ICMPv6 code was 0 611 | if (rx2icmp6_code != 0) 612 | { 613 | #ifdef PINGDEBUG 614 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: INNER ICMPv6_CODE was not 0\n"); 615 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 616 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet details: src %s ; dst %s; nextheader %d\n", orig_src_addr, orig_dst_addr, nextheader); 617 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet icmp6 details: type %d; code %d; seq %d; id %d\n", rx2icmp6_type, rx2icmp6_code, rx2seqno, rx2id); 618 | #endif 619 | continue; 620 | } 621 | 622 | // Check sequence number matches what we transmitted 623 | if (rx2seqno != txseqno) 624 | { 625 | #ifdef PINGDEBUG 626 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: INNER ICMPv6_SEQN was not %d\n", txseqno); 627 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 628 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet details: src %s ; dst %s; nextheader %d\n", orig_src_addr, orig_dst_addr, nextheader); 629 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet icmp6 details: type %d; code %d; seq %d; id %d\n", rx2icmp6_type, rx2icmp6_code, rx2seqno, rx2id); 630 | #endif 631 | continue; 632 | } 633 | 634 | // Check ID matches what we transmitted 635 | if (rx2id != txid) 636 | { 637 | #ifdef PINGDEBUG 638 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: INNER ICMPv6_ID was not %d\n", txid); 639 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 640 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet details: src %s ; dst %s; nextheader %d\n", orig_src_addr, orig_dst_addr, nextheader); 641 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet icmp6 details: type %d; code %d; seq %d; id %d\n", rx2icmp6_type, rx2icmp6_code, rx2seqno, rx2id); 642 | #endif 643 | continue; 644 | } 645 | 646 | // Check for the expected received data 647 | // sent: 648 | // "%"PRIu64" %"PRIu64" %u %u", starttime, session, ICMPV6_MAGIC_VALUE1, ICMPV6_MAGIC_VALUE2 649 | uint64_t rx2starttime, rx2session; 650 | unsigned int rx2magic1, rx2magic2; 651 | 652 | rc = sscanf(&rxpackdata[sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr)+ICMP6DATAOFFSET], "%"PRIu64" %"PRIu64" %u %u", &rx2starttime, &rx2session, &rx2magic1, &rx2magic2); 653 | if (rc == 4) 654 | { 655 | if (rx2starttime != starttime) 656 | { 657 | #ifdef PINGDEBUG 658 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: INNER ICMPv6 magic data rx2starttime (%"PRId64") != starttime (%"PRId64")\n", rx2starttime, starttime); 659 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 660 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet details: src %s ; dst %s; nextheader %d\n", orig_src_addr, orig_dst_addr, nextheader); 661 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet icmp6 details: type %d; code %d; seq %d; id %d\n", rx2icmp6_type, rx2icmp6_code, rx2seqno, rx2id); 662 | #endif 663 | continue; 664 | } 665 | if (rx2session != session) 666 | { 667 | #ifdef PINGDEBUG 668 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: INNER ICMPv6 magic data rx2session (%"PRId64") != session (%"PRId64")\n", rx2session, session); 669 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 670 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet details: src %s ; dst %s; nextheader %d\n", orig_src_addr, orig_dst_addr, nextheader); 671 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet icmp6 details: type %d; code %d; seq %d; id %d\n", rx2icmp6_type, rx2icmp6_code, rx2seqno, rx2id); 672 | #endif 673 | continue; 674 | } 675 | if (ICMPV6_MAGIC_VALUE1 != rx2magic1) 676 | { 677 | #ifdef PINGDEBUG 678 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: INNER ICMPv6 magic data rx2magic1 (%d) != expected %d\n", rx2magic1, ICMPV6_MAGIC_VALUE1); 679 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 680 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet details: src %s ; dst %s; nextheader %d\n", orig_src_addr, orig_dst_addr, nextheader); 681 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet icmp6 details: type %d; code %d; seq %d; id %d\n", rx2icmp6_type, rx2icmp6_code, rx2seqno, rx2id); 682 | #endif 683 | continue; 684 | } 685 | if (ICMPV6_MAGIC_VALUE2 != rx2magic2) 686 | { 687 | #ifdef PINGDEBUG 688 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: INNER ICMPv6 magic data rx2magic2 (%d) != expected %d\n", rx2magic2, ICMPV6_MAGIC_VALUE2); 689 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 690 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet details: src %s ; dst %s; nextheader %d\n", orig_src_addr, orig_dst_addr, nextheader); 691 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet icmp6 details: type %d; code %d; seq %d; id %d\n", rx2icmp6_type, rx2icmp6_code, rx2seqno, rx2id); 692 | #endif 693 | continue; 694 | } 695 | 696 | // 697 | // If we get to this point then the returned packet was in response to the packet we originally 698 | // transmitted 699 | // 700 | #ifdef PINGDEBUG 701 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: Packet from %s contained our tx ECHO-REQUEST, so flagging INDIRECT response\n", router); 702 | #endif 703 | indirect = IPSCAN_INDIRECT_RESPONSE; 704 | } 705 | else 706 | { 707 | // wrong number of parameters 708 | #ifdef PINGDEBUG 709 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: INNER ICMPv6 packet returned number of magic parameters (%d) != 4\n", rc); 710 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 711 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet details: src %s ; dst %s; nextheader %d\n", orig_src_addr, orig_dst_addr, nextheader); 712 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED INNER packet icmp6 details: type %d; code %d; seq %d; id %d\n", rx2icmp6_type, rx2icmp6_code, rx2seqno, rx2id); 713 | #endif 714 | continue; 715 | } 716 | } 717 | else 718 | { 719 | #ifdef PINGDEBUG 720 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: INNER IPv6 next header didn't indicate an ICMPv6 packet inside\n"); 721 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 722 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: INNER packet details: src %s ; dst %s; nextheader %d\n", orig_src_addr, orig_dst_addr, nextheader); 723 | #endif 724 | continue; 725 | } 726 | } 727 | else 728 | { 729 | #ifdef PINGDEBUG 730 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: OUTER address mismatch with INNER unexpected size : %d\n", rxpacketsize); 731 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 732 | #endif 733 | continue; 734 | } 735 | 736 | } 737 | 738 | // 739 | // Check what type of ICMPv6 packet we received and set return value appropriately ... 740 | // 741 | if (rxicmp6_type == ICMP6_ECHO_REPLY) 742 | { 743 | #ifdef PINGDEBUG 744 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: ICMP6_TYPE was ICMP6_ECHO_REPLY, with code %d\n", rxicmp6_code); 745 | #endif 746 | } 747 | else if ( rxicmp6_type == ICMP6_DST_UNREACH ) 748 | { 749 | switch ( rxicmp6_code ) 750 | { 751 | case ICMP6_DST_UNREACH_NOROUTE: 752 | retval = PORTUNREACHABLE; 753 | break; 754 | case ICMP6_DST_UNREACH_ADMIN: 755 | retval = PORTPROHIBITED; 756 | break; 757 | case ICMP6_DST_UNREACH_ADDR: 758 | retval = PORTNOROUTE; 759 | break; 760 | case ICMP6_DST_UNREACH_NOPORT: 761 | retval = PORTREFUSED; 762 | break; 763 | default: 764 | retval = PORTUNREACHABLE; 765 | break; 766 | } 767 | 768 | #ifdef PINGDEBUG 769 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: ICMP6_TYPE was DST_UNREACH, with code %d (%s)\n", rxicmp6_code, resultsstruct[retval].label); 770 | #endif 771 | 772 | if (-1 != sock) close(sock); // close socket if appropriate 773 | return(retval+indirect); 774 | } 775 | else if (rxicmp6_type == ICMP6_PARAM_PROB) 776 | { 777 | #ifdef PINGDEBUG 778 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: ICMP6_TYPE was PARAM_PROB, with code %d\n", rxicmp6_code); 779 | #endif 780 | 781 | retval = PORTPARAMPROB; 782 | if (-1 != sock) close(sock); // close socket if appropriate 783 | return(retval+indirect); 784 | } 785 | else if (rxicmp6_type == ICMP6_TIME_EXCEEDED) 786 | { 787 | #ifdef PINGDEBUG 788 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: ICMP6_TYPE was TIME_EXCEEDED, with code %d\n", rxicmp6_code); 789 | #endif 790 | 791 | retval = PORTNOROUTE; 792 | if (-1 != sock) close(sock); // close socket if appropriate 793 | return(retval+indirect); 794 | } 795 | else if (rxicmp6_type == ICMP6_PACKET_TOO_BIG) 796 | { 797 | #ifdef PINGDEBUG 798 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: ICMP6_TYPE was PACKET_TOO_BIG, with code %d\n", rxicmp6_code); 799 | #endif 800 | 801 | retval = PORTPKTTOOBIG; 802 | if (-1 != sock) close(sock); // close socket if appropriate 803 | return(retval+indirect); 804 | } 805 | else 806 | { 807 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: RESTART: unhandled ICMPv6 packet TYPE was %d CODE was %d\n", rxicmp6_type, rxicmp6_code); 808 | continue; 809 | } 810 | 811 | // 812 | // If we get this far then packet is a direct ECHO-REPLY, so we can check the contents 813 | // 814 | 815 | if (rxseqno != txseqno) 816 | { 817 | #ifdef PINGDEBUG 818 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: Sequence number mismatch - expected %d\n", txseqno); 819 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 820 | #endif 821 | continue; 822 | } 823 | 824 | if (rxid != txid) 825 | { 826 | #ifdef PINGDEBUG 827 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: ICMP6 id mismatch - expected %d\n", txid); 828 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 829 | #endif 830 | continue; 831 | } 832 | 833 | // Check for the expected received data 834 | // sent: 835 | // "%"PRIu64" %"PRIu64" %u %u", starttime, session, ICMPV6_MAGIC_VALUE1, ICMPV6_MAGIC_VALUE2 836 | uint64_t rxstarttime, rxsession; 837 | unsigned int rxmagic1, rxmagic2; 838 | 839 | rc = sscanf(&rxpackdata[ICMP6DATAOFFSET], "%"PRIu64" %"PRIu64" %u %u", &rxstarttime, &rxsession, &rxmagic1, &rxmagic2); 840 | if (rc == 4) 841 | { 842 | if (rxstarttime != starttime) 843 | { 844 | #ifdef PINGDEBUG 845 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: magic data rxstarttime (%"PRId64") != starttime (%"PRId64")\n", rxstarttime, starttime); 846 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 847 | #endif 848 | continue; 849 | } 850 | if (rxsession != session) 851 | { 852 | #ifdef PINGDEBUG 853 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: magic data rxsession (%"PRId64") != session (%"PRId64")\n", rxsession, session); 854 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 855 | #endif 856 | continue; 857 | } 858 | if (ICMPV6_MAGIC_VALUE1 != rxmagic1) 859 | { 860 | #ifdef PINGDEBUG 861 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: RX magic data 1 (%d) != expected %d\n", rxmagic1, ICMPV6_MAGIC_VALUE1); 862 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 863 | #endif 864 | continue; 865 | } 866 | if (ICMPV6_MAGIC_VALUE2 != rxmagic2) 867 | { 868 | #ifdef PINGDEBUG 869 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: RX magic data 2 (%d) != expected %d\n", rxmagic2, ICMPV6_MAGIC_VALUE2); 870 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 871 | #endif 872 | continue; 873 | } 874 | 875 | // 876 | // if we get to this point then everything matches ... 877 | // 878 | #ifdef PINGDEBUG 879 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: Everything matches - it was our expected ICMPv6 ECHO_RESPONSE\n"); 880 | #endif 881 | foundit = 1; 882 | } 883 | else 884 | { 885 | #ifdef PINGDEBUG 886 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARD: number of magic parameters mismatched, got %d, expected 4\n", rc); 887 | IPSCAN_LOG( LOGPREFIX "check_icmpv6_echoresponse: DISCARDED OUTER packet details: src %s; type %d; code %d; id %d; seqno %d\n", router, rxicmp6_type, rxicmp6_code, rxid, rxseqno); 888 | #endif 889 | continue; 890 | } 891 | 892 | } // end of if (received some bytes) 893 | 894 | } // end of while 895 | 896 | if (foundit == 1) retval = ECHOREPLY; else retval = ECHONOREPLY; 897 | 898 | // return the status 899 | if (-1 != sock) close(sock); // close socket if appropriate 900 | 901 | // Make sure we wait long enough in all cases 902 | sleep(IPSCAN_MINTIME_PER_PORT); 903 | 904 | return(retval); 905 | } 906 | 907 | -------------------------------------------------------------------------------- /ipscan_portlist.h: -------------------------------------------------------------------------------- 1 | // IPscan - an HTTP-initiated IPv6 port scanner. 2 | // 3 | // Copyright (C) 2011-2025 Tim Chappell. 4 | // 5 | // This file is part of IPscan. 6 | // 7 | // IPscan is free software: you can redistribute it and/or modify 8 | // it under the terms of the GNU General Public License as published by 9 | // the Free Software Foundation, either version 3 of the License, or 10 | // (at your option) any later version. 11 | // 12 | // This program is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | // GNU General Public License for more details. 16 | // 17 | // You should have received a copy of the GNU General Public License 18 | // along with IPscan. If not, see . 19 | // 20 | // Version Change 21 | // 0.01 Original 22 | // 0.02 Added additional Windows related ports 23 | // 2869 - SSDP event notification 24 | // 5357 - WSDAPI HTTP 25 | // 10243 - WMP HTTP 26 | // 0.03 - add service names to results table (modification to portlist, now structure) 27 | // 0.04 - add UDP ports and service names 28 | // 0.05 - add SNMP (UDP port 161) support 29 | // 0.06 - add NTP special case 30 | // 0.07 - add TCP/32764 router backdoor port (may be IPv4 only) 31 | // 0.08 - add SNMPv2c and SNMPv3 32 | // 0.09 - slight tweaks to a few Microsoft ports 33 | // as per https://msdn.microsoft.com/en-us/library/cc875824.aspx 34 | // 0.10 - added Intel AMT ports 35 | // 0.11 - update copyright dates 36 | // 0.12 - add memcached check (TCP only, UDP not supported for IPv6) 37 | // 0.13 - add memcached UDP check 38 | // 0.14 - update copyright dates 39 | // 0.15 - update copyright dates 40 | // 0.16 - update copyright year 41 | // 0.17 - add whois, TCP/43 42 | // 0.18 - update copyright year 43 | // 0.19 - add TCP/20005 (for KCodes NetUSB - see CVE-2021-45608) 44 | // 0.20 - update copyright year 45 | // 0.21 - const portlist structs 46 | 47 | // 48 | #define IPSCAN_PORTLIST_VER "0.21" 49 | // 50 | 51 | #include "ipscan.h" 52 | 53 | #ifndef IPSCAN_PORTLIST_H 54 | #define IPSCAN_PORTLIST_H 1 55 | 56 | // Determine the default list of ports to be tested 57 | // Note: each entry includes its port number followed by 58 | // a text description (up to PORTDESCSIZE-1 characters long) 59 | // 60 | const struct portlist_struc defportlist[] = 61 | { 62 | { 7, 0, "Echo"},\ 63 | { 21, 0, "FTP" },\ 64 | { 22, 0, "SSH" },\ 65 | { 23, 0, "Telnet" },\ 66 | { 25, 0, "SMTP" },\ 67 | { 37, 0, "Time" },\ 68 | { 43, 0, "WHOIS" },\ 69 | { 53, 0, "DNS" },\ 70 | { 79, 0, "Finger" },\ 71 | { 80, 0, "HTTP" },\ 72 | { 110, 0, "POP3" },\ 73 | { 111, 0, "SUN-RPC" },\ 74 | { 113, 0, "Ident, Auth" },\ 75 | { 119, 0, "NNTP" },\ 76 | { 135, 0, "Microsoft-EPMAP" },\ 77 | { 139, 0, "NetBIOS Session" },\ 78 | { 143, 0, "IMAP" },\ 79 | { 179, 0, "BGP" },\ 80 | { 311, 0, "Apple-WebAdmin" },\ 81 | { 389, 0, "LDAP" },\ 82 | { 427, 0, "SLP" },\ 83 | { 443, 0, "HTTPS" },\ 84 | { 445, 0, "Microsoft-DS" },\ 85 | { 515, 0, "LPD" },\ 86 | { 543, 0, "Kerberos Login" },\ 87 | { 544, 0, "Kerberos RSH" },\ 88 | { 548, 0, "Apple-File" },\ 89 | { 587, 0, "ESMTP" },\ 90 | { 631, 0, "IPP" },\ 91 | { 749, 0, "Kerberos Admin" },\ 92 | { 873, 0, "Rsync" },\ 93 | { 993, 0, "IMAPS" },\ 94 | { 995, 0, "POP3S" },\ 95 | { 1025, 0, "Blackjack, NFS, IIS or RFS" },\ 96 | { 1026, 0, "CAP, Microsoft DCOM" },\ 97 | { 1029, 0, "Microsoft DCOM" },\ 98 | { 1030, 0, "BBN IAD" },\ 99 | { 1080, 0, "Socks" },\ 100 | { 1720, 0, "H323, Microsoft Netmeeting" },\ 101 | { 1723, 0, "PPTP" },\ 102 | { 1801, 0, "MSMQ" },\ 103 | { 2103, 0, "MSMQ-RPC" },\ 104 | { 2105, 0, "MSMQ-RPC" },\ 105 | { 2107, 0, "MSMQ-Mgmt" },\ 106 | { 2869, 0, "SSDP Event Notification" },\ 107 | { 3128, 0, "Active API, or Squid Proxy" },\ 108 | { 3306, 0, "MySQL" },\ 109 | { 3389, 0, "Microsoft RDP" },\ 110 | { 3689, 0, "DAAP, iTunes" },\ 111 | { 5000, 0, "UPNP" },\ 112 | { 5060, 0, "SIP" },\ 113 | { 5100, 0, "Service Mux, Yahoo Messenger" },\ 114 | { 5357, 0, "WSDAPI HTTP" },\ 115 | { 5900, 0, "VNC" },\ 116 | { 8080, 0, "HTTP alternate" },\ 117 | { 9090, 0, "WebSM" },\ 118 | {10243, 0, "Microsoft WMP HTTP"},\ 119 | {11211, 0, "memcache" },\ 120 | {16992, 0, "Intel AMT SOAP/HTTP"},\ 121 | {16993, 0, "Intel AMT SOAP/HTTPS"},\ 122 | {16994, 0, "Intel AMT Redir/TCP"},\ 123 | {16995, 0, "Intel AMT Redir/TLS"},\ 124 | {20005, 0, "Router KCodes NetUSB port, see CVE-2021-45608"},\ 125 | {32764, 0, "Router Backdoor"}\ 126 | }; 127 | 128 | 129 | // Calculate and record the number of default ports to be tested 130 | #define DEFNUMPORTS ( sizeof(defportlist) / sizeof(struct portlist_struc) ) 131 | 132 | const struct portlist_struc udpportlist[] = 133 | { 134 | { 53, 0, "DNS" },\ 135 | { 69, 0, "TFTP" },\ 136 | { 123, 0, "NTP" },\ 137 | { 123, 1, "NTP MONLIST" },\ 138 | { 161, 0, "SNMPv1" },\ 139 | { 161, 1, "SNMPv2c" },\ 140 | { 161, 2, "SNMPv3" },\ 141 | { 500, 0, "IKEv2 SA_INIT" },\ 142 | { 521, 0, "RIPng" },\ 143 | { 547, 0, "DHCPv6" },\ 144 | { 1900, 0, "UPnP SSDP" },\ 145 | { 3503, 0, "MPLS LSP Ping" },\ 146 | { 4500, 0, "IKEv2 NAT-T SA_INIT" },\ 147 | {11211, 0, "memcache ASCII" },\ 148 | {11211, 1, "memcache binary" },\ 149 | }; 150 | 151 | #if (IPSCAN_INCLUDE_UDP == 1) 152 | #define NUMUDPPORTS ( sizeof(udpportlist) / sizeof(struct portlist_struc) ) 153 | #else 154 | #define NUMUDPPORTS 0 155 | #endif 156 | 157 | #endif /* IPSCAN_PORTLIST_H */ 158 | -------------------------------------------------------------------------------- /ipscan_tcp.c: -------------------------------------------------------------------------------- 1 | // IPscan - an HTTP-initiated IPv6 port scanner. 2 | // 3 | // Copyright (C) 2011-2025 Tim Chappell. 4 | // 5 | // This file is part of IPscan. 6 | // 7 | // IPscan is free software: you can redistribute it and/or modify 8 | // it under the terms of the GNU General Public License as published by 9 | // the Free Software Foundation, either version 3 of the License, or 10 | // (at your option) any later version. 11 | // 12 | // This program is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | // GNU General Public License for more details. 16 | // 17 | // You should have received a copy of the GNU General Public License 18 | // along with IPscan. If not, see . 19 | 20 | // ipscan_tcp.c version 21 | // 0.01 initial version after split from ipscan_checks.c 22 | // 0.02 tidy up logging prefixes 23 | // 0.03 move to memset() 24 | // 0.04 add support for special cases 25 | // 0.05 ensure minimum timings are met 26 | // 0.06 improve error reporting 27 | // 0.07 ensure fd closure is handled cleanly 28 | // 0.08 add null termination to unusedfield 29 | // 0.09 enforce use of AF_INET6 30 | // 0.10 update copyright date 31 | // 0.11 update copyright date 32 | // 0.12 update copyright date 33 | // 0.13 extern updated 34 | // 0.14 update copyright date 35 | // 0.15 update copyright year 36 | // 0.16 update copyright year 37 | // 0.17 update copyright year 38 | // 0.18 reduce scope of multiple variables 39 | 40 | // 41 | #define IPSCAN_TCP_VER "0.18" 42 | // 43 | 44 | #include "ipscan.h" 45 | // 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | // IPv6 address conversion 58 | #include 59 | 60 | // String comparison 61 | #include 62 | 63 | // Logging with syslog requires additional include 64 | #if (LOGMODE == 1) 65 | #include 66 | #endif 67 | 68 | // Others that FreeBSD highlighted 69 | #include 70 | #include 71 | #include 72 | 73 | // Other IPv6 related 74 | #include 75 | #include 76 | 77 | //Poll support 78 | #include 79 | 80 | // Parallel processing related 81 | #include 82 | 83 | // Define offset into ICMPv6 packet where user-defined data resides 84 | #define ICMP6DATAOFFSET sizeof(struct icmp6_hdr) 85 | 86 | // 87 | // Prototype declarations 88 | // 89 | int write_db(uint64_t host_msb, uint64_t host_lsb, uint64_t timestamp, uint64_t session, uint32_t port, int32_t result, const char *indirecthost ); 90 | 91 | // 92 | // report version 93 | // 94 | const char* ipscan_tcp_ver(void) 95 | { 96 | return IPSCAN_TCP_VER; 97 | } 98 | 99 | // 100 | // Check an individual TCP port 101 | // 102 | 103 | int check_tcp_port(char * hostname, uint16_t port, uint8_t special) 104 | { 105 | struct addrinfo *res, *aip; 106 | struct addrinfo hints; 107 | int error; 108 | struct timeval timeout; 109 | char portnum[8]; 110 | 111 | memset(&hints, 0, sizeof(hints)); 112 | hints.ai_family = AF_INET6; 113 | hints.ai_flags = AI_NUMERICSERV; 114 | hints.ai_socktype = SOCK_STREAM; 115 | 116 | // set return value to a known default 117 | int retval = PORTUNKNOWN; 118 | 119 | error = snprintf(portnum, 8,"%d", port); 120 | if (error < 0 || error >= 8) 121 | { 122 | IPSCAN_LOG( LOGPREFIX "check_tcp_port: Failed to write portnum, rc was %d\n", error); 123 | retval = PORTINTERROR; 124 | } 125 | 126 | error = getaddrinfo(hostname, portnum, &hints, &res); 127 | if (error != 0) 128 | { 129 | IPSCAN_LOG( LOGPREFIX "check_tcp_port: getaddrinfo: %s for host %s port %d\n", gai_strerror(error), hostname, port); 130 | retval = PORTINTERROR; 131 | } 132 | else 133 | { 134 | 135 | // cycle around the results ... 136 | for (aip = res; (NULL != aip && PORTUNKNOWN == retval) ; aip = aip->ai_next) 137 | { 138 | // If this is not an IPv6 address then skip, should never happen now AF family specified ... 139 | if (aip->ai_family != AF_INET6) 140 | { 141 | // IPSCAN_LOG( LOGPREFIX "Skipping, because ai_family != AF_INET6 (actually %d)\n",aip->ai_family); 142 | continue; 143 | } 144 | 145 | // Attempt to create a socket 146 | int sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol); 147 | if (sock == -1) 148 | { 149 | int errsv = errno ; 150 | IPSCAN_LOG( LOGPREFIX "check_tcp_port: Bad socket call, returned %d (%s)\n", errsv, strerror(errsv)); 151 | retval = PORTINTERROR; 152 | } 153 | 154 | // Assuming something bad hasn't already happened then attempt to set the receive timeout 155 | if (PORTUNKNOWN == retval) 156 | { 157 | // Set send timeout 158 | memset(&timeout, 0, sizeof(timeout)); 159 | timeout.tv_sec = TIMEOUTSECS; 160 | timeout.tv_usec = TIMEOUTMICROSECS; 161 | int timeo = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); 162 | if (timeo < 0) 163 | { 164 | int errsv = errno ; 165 | IPSCAN_LOG( LOGPREFIX "check_tcp_port: Bad setsockopt SO_SNDTIMEO set, returned %d (%s)\n", errsv, strerror(errsv)); 166 | retval = PORTINTERROR; 167 | } 168 | } 169 | 170 | // Assuming something bad hasn't already happened then attempt to set the receive timeout 171 | if (PORTUNKNOWN == retval) 172 | { 173 | // Set receive timeout 174 | memset(&timeout, 0, sizeof(timeout)); 175 | timeout.tv_sec = TIMEOUTSECS; 176 | timeout.tv_usec = TIMEOUTMICROSECS; 177 | int timeo = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); 178 | if (timeo < 0) 179 | { 180 | int errsv = errno ; 181 | IPSCAN_LOG( LOGPREFIX "check_tcp_port: Bad setsockopt SO_RCVTIMEO set, returned %d (%s)\n", errsv, strerror(errsv)); 182 | retval = PORTINTERROR; 183 | } 184 | } 185 | 186 | // Assuming something bad hasn't already happened then attempt to connect 187 | if (PORTUNKNOWN == retval) 188 | { 189 | // attempt to connect 190 | int conn = connect(sock, aip->ai_addr, aip->ai_addrlen); 191 | int errsv = errno ; 192 | // cycle through the expected list of results 193 | for (int i = 0; PORTEOL != resultsstruct[i].returnval && PORTUNKNOWN == retval ; i++) 194 | { 195 | 196 | // Find a matching connect returncode and also errno, if appropriate 197 | if (resultsstruct[i].connrc == conn) 198 | { 199 | // Set the returnvalue if we find a match 200 | if ( conn == 0 || (conn == -1 && resultsstruct[i].connerrno == errsv) ) 201 | { 202 | retval = resultsstruct[i].returnval; 203 | } 204 | } 205 | } 206 | 207 | #ifdef RESULTSDEBUG 208 | if (0 != special) 209 | { 210 | IPSCAN_LOG( LOGPREFIX "check_tcp_port: found port %d:%d returned conn = %d, errsv = %d(%s)\n", port, special, conn, errsv, strerror(errsv)); 211 | } 212 | else 213 | { 214 | IPSCAN_LOG( LOGPREFIX "check_tcp_port: found port %d returned conn = %d, errsv = %d(%s)\n", port, conn, errsv, strerror(errsv)); 215 | } 216 | #endif 217 | 218 | // If we haven't found a matching returncode/errno then log this .... 219 | if (PORTUNKNOWN == retval) 220 | { 221 | if (0 != special) 222 | { 223 | IPSCAN_LOG( LOGPREFIX "check_tcp_port: connect unexpected response, errno is : %d (%s) for host %s port %d:%d\n", \ 224 | errsv, strerror(errsv), hostname, port, special); 225 | } 226 | else 227 | { 228 | IPSCAN_LOG( LOGPREFIX "check_tcp_port: connect unexpected response, errno is : %d (%s) for host %s port %d\n", \ 229 | errsv, strerror(errsv), hostname, port); 230 | } 231 | retval = PORTUNEXPECTED; 232 | } 233 | 234 | int cl = close(sock); 235 | if (cl == -1) 236 | { 237 | IPSCAN_LOG( LOGPREFIX "check_tcp_port: close unexpected failure : %d (%s)\n", errno, strerror(errno)); 238 | } 239 | 240 | } 241 | else 242 | { 243 | // Something bad has happened during setsockopts, but ensure we close an open socket anyway 244 | if (-1 != sock) 245 | { 246 | int cl = close(sock); 247 | if (cl == -1) 248 | { 249 | IPSCAN_LOG( LOGPREFIX "check_tcp_port: close unexpected failure : %d (%s)\n", errno, strerror(errno)); 250 | } 251 | } 252 | } 253 | 254 | } // end for loop 255 | freeaddrinfo(res); 256 | } 257 | 258 | // If we received any non-positive feedback then make sure we wait at least IPSCAN_MINTIME_PER_PORT secs 259 | if ((PORTOPEN != retval) && (PORTINPROGRESS != retval)) sleep(IPSCAN_MINTIME_PER_PORT); 260 | 261 | return(retval); 262 | } 263 | 264 | 265 | int check_tcp_ports_parll(char * hostname, unsigned int portindex, unsigned int todo, uint64_t host_msb, uint64_t host_lsb, uint64_t timestamp, uint64_t session, struct portlist_struc *portlist) 266 | { 267 | int rc,result; 268 | pid_t childpid = fork(); 269 | if (childpid > 0) 270 | { 271 | // parent 272 | #ifdef PARLLDEBUG 273 | IPSCAN_LOG( LOGPREFIX "check_tcp_ports_parll(): forked and started child PID=%d\n",childpid); 274 | #endif 275 | } 276 | else if (childpid == 0) 277 | { 278 | #ifdef PARLLDEBUG 279 | IPSCAN_LOG( LOGPREFIX "check_tcp_ports_parll(): startindex %d, todo %d\n",portindex,todo); 280 | #endif 281 | // child - actually do the work here - and then exit successfully 282 | const char unusedfield[8] = "unused\0"; 283 | for (unsigned int i = 0 ; i < todo ; i++) 284 | { 285 | uint16_t port = portlist[portindex+i].port_num; 286 | uint8_t special = portlist[portindex+i].special; 287 | #ifdef TCPDEBUG 288 | IPSCAN_LOG( LOGPREFIX "check_tcp_ports_parll(): DEBUG: portindex = %d, i = %d, port_num = %d, special = %d\n", portindex, i, portlist[portindex+i].port_num, portlist[portindex+i].special); 289 | IPSCAN_LOG ( LOGPREFIX "check_tcp_ports_parll(): DEBUG: hostname = %s, port = %d, special = %d\n", hostname, port, special); 290 | #endif 291 | result = check_tcp_port(hostname, port, special); 292 | // Put results into database 293 | rc = write_db(host_msb, host_lsb, timestamp, session, (uint32_t)(port + ((special & IPSCAN_SPECIAL_MASK) << IPSCAN_SPECIAL_SHIFT) + (IPSCAN_PROTO_TCP << IPSCAN_PROTO_SHIFT)), result, unusedfield ); 294 | if (rc != 0) 295 | { 296 | IPSCAN_LOG( LOGPREFIX "check_tcp_ports_parll(): ERROR: check_tcp_port_parll() write_db returned %d\n", rc); 297 | } 298 | } 299 | // Usual practice to have children _exit() whilst the parent calls exit() 300 | _exit(EXIT_SUCCESS); 301 | } 302 | else 303 | { 304 | IPSCAN_LOG( LOGPREFIX "check_tcp_ports_parll(): fork() failed childpid=%d, errno=%d(%s)\n", childpid, errno, strerror(errno)); 305 | exit(EXIT_FAILURE); 306 | } 307 | return( (int)childpid ); 308 | } 309 | -------------------------------------------------------------------------------- /ipscan_web.c: -------------------------------------------------------------------------------- 1 | // IPscan - an HTTP-initiated IPv6 port scanner. 2 | // 3 | // Copyright (C) 2011-2025 Tim Chappell. 4 | // 5 | // This file is part of IPscan. 6 | // 7 | // IPscan is free software: you can redistribute it and/or modify 8 | // it under the terms of the GNU General Public License as published by 9 | // the Free Software Foundation, either version 3 of the License, or 10 | // (at your option) any later version. 11 | // 12 | // This program is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | // GNU General Public License for more details. 16 | // 17 | // You should have received a copy of the GNU General Public License 18 | // along with IPscan. If not, see . 19 | 20 | // ipscan_web.c version 21 | // 0.01 - initial version 22 | // 0.02 - improved HTML (transition to styles, general compliance) 23 | // 0.03 - addition of ping functionality 24 | // 0.04 - addition of indirect host support 25 | // 0.05 - removal of empty HTML paragraph 26 | // 0.06 - tidy up URIPATH and comparisons 27 | // 0.07 - move to JSON array which supports port number and result 28 | // 0.08 - remove unused parameters 29 | // 0.09 - add http-equiv to force IE7 mimicry 30 | // 0.10 - minor tweak to expected run-time for non-javascript browser message 31 | // 0.11 - add service names to results table (modification to portlist, now structure) 32 | // 0.12 - compress form vertically 33 | // 0.13 - introduce UDP support 34 | // 0.14 - support the optional removal of ping functionality 35 | // 0.15 - support the optional removal of UDP functionality 36 | // 0.16 - add special case support 37 | // 0.17 - add end of test signalling 38 | // 0.18 - lint improvements 39 | // 0.19 - correct position of request.send() 40 | // 0.20 - handle failure case when HTTP return-code is not 200 41 | // 0.21 - lint check and improvements 42 | // 0.22 - move final fetch earlier 43 | // 0.23 - further javascript improvements 44 | // 0.24 - remove commented-out javascript code 45 | // 0.25 - move to single XML HHTP Request object 46 | // 0.26 - add 'navigate away' handler to javascript version 47 | // 0.27 - fix cut'n'paste error, spotted by coverity 48 | // 0.28 - update copyright year, and ensure charset=iso-8859-1 49 | // 0.29 - update copyright year 50 | // 0.30 - add basic HTML5/CSS support for javascript binaries 51 | // 0.31 - specify value if terms accepted 52 | // 0.32 - update copyright year 53 | // 0.33 - slight tweak to error reporting (myReadyState and myStatus) 54 | // 0.34 - update copyright year 55 | // 0.35 - extern udpated 56 | // 0.36 - semmle re-entrant time functions added 57 | // 0.37 - javascript updates (removal of eval) and tidy 58 | // 0.38 - add log for time_r failures 59 | // 0.39 - update copyright year 60 | // 0.40 - move to use client starttime to ensure unique parameters 61 | // 0.41 - convert some variables to const, re-scope others, update copyright year 62 | // 0.42 - move to client session/starttime generation 63 | // 0.43 - catch bad JSON parse result, return to const and var 64 | // 0.44 - remove commented out code 65 | // 0.45 - make Javascript style more consistent 66 | // 0.46 - add cache-control private 67 | // 0.47 - add LGTM pragmas to ignore cross-site scripting false positives 68 | // 0.48 - remove LGTM pragmas once false positives resolved 69 | // 0.49 - add an additional note regarding normal TCP/UDP port tests 70 | // 0.50 - further clarifications regarding normal TCP/UDP port tests 71 | // 0.51 - move to unsigned shift right (should be of no consequence) 72 | // 0.52 - update copyright year 73 | // 0.53 - change colour of text and buttons to blue (better readability), results still use red 74 | // 0.54 - make robots reponse an optional include 75 | // 0.55 - add a missing clearInterval() 76 | // 0.56 - correct time into seconds since epoch rather than ms 77 | // 0.57 - HTML and javascript improvements/modernisations - use const, let 78 | // 0.58 - javascript changes to handle reporting of current state (hover over scan status cell) 79 | // 0.59 - change timeout calculation to give larger window 80 | // 0.60 - ontimeout change 81 | // 0.61 - further tidying 82 | // 0.62 - portlist structs are now consts 83 | // 0.63 - further CodeQL improvements 84 | // 0.64 - even more CodeQL improvements 85 | // 0.65 - various code quality improvements (scope reductions) 86 | 87 | #define IPSCAN_WEB_VER "0.65" 88 | 89 | #include "ipscan.h" 90 | 91 | #include 92 | #include 93 | #include 94 | #include 95 | #include 96 | #include 97 | #include 98 | #include 99 | #include 100 | #include 101 | 102 | // Logging with syslog requires additional include 103 | #if (1 == LOGMODE) 104 | #include 105 | #endif 106 | 107 | // 108 | // report version 109 | // 110 | const char* ipscan_web_ver(void) 111 | { 112 | return IPSCAN_WEB_VER; 113 | } 114 | 115 | // 116 | // --------------------------------- 117 | // 118 | 119 | void create_html_common_header(void) 120 | { 121 | printf("%s%c%c\n","content-type:text/html;charset=utf-8",13,10); 122 | printf("\n"); 123 | printf("\n"); 124 | printf("\n"); 125 | // Force later IE browsers to mimic IE7 as detailed in http://msdn.microsoft.com/library/cc288325.aspx 126 | printf("\n"); 127 | printf("\n"); 128 | printf("\n"); 129 | printf("\n"); 130 | printf("\n"); 131 | #ifdef IPSCAN_ICON_ENABLED 132 | printf("\n", IPSCAN_ICON_TYPE, IPSCAN_ICON_HREF); 133 | #endif 134 | #ifdef IPSCAN_NOROBOTS_INCLUDE 135 | printf("\n"); 136 | #endif 137 | printf("\n"); 138 | } 139 | 140 | #ifdef IPSCAN_HTML5_ENABLED 141 | void create_html5_common_header(void) 142 | { 143 | printf("%s%c%c\n","content-type:text/html;charset=utf-8",13,10); 144 | printf("\n"); 145 | printf("\n"); 146 | printf("\n"); 147 | printf("\n"); 148 | printf("\n"); 149 | printf("\n"); 150 | printf("\n"); 151 | #ifdef IPSCAN_ICON_ENABLED 152 | printf("\n", IPSCAN_ICON_TYPE, IPSCAN_ICON_HREF); 153 | #endif 154 | #ifdef IPSCAN_NOROBOTS_INCLUDE 155 | printf("\n"); 156 | #endif 157 | printf("\n"); 158 | 159 | printf("\n"); 200 | } 201 | #endif 202 | 203 | void create_json_header(void) 204 | { 205 | printf("%s%c%c\n","Content-type:application/json;charset=utf-8",13,10); 206 | } 207 | 208 | void create_html_header(uint16_t numports, uint16_t numudpports, char * reconquery) 209 | { 210 | uint16_t i; 211 | 212 | HTML_HEADER(); 213 | 214 | printf("IPv6 Port Scanner Version %s\n", IPSCAN_VER); 215 | printf("\n"); 635 | printf("\n"); 636 | } 637 | 638 | 639 | void create_results_key_table(char * hostname, time_t timestamp) 640 | { 641 | int i; 642 | struct tm timestampbdt; // broken dowm time 643 | struct tm * tsptr = NULL; 644 | tsptr = localtime_r(×tamp, ×tampbdt); 645 | 646 | printf("

"); 647 | if (NULL != tsptr) 648 | { 649 | char tstring[64]; 650 | if (0 != strftime(tstring, sizeof(tstring),"%a,%%20%d%%20%b%%20%Y%%20%T%%20%z", ×tampbdt)) 651 | { 652 | printf("Special protocol tests, signified by [x] after a port number, test for known protocol weaknesses. "); 653 | printf("Further details of these tests can be found at Special protocol tests.\n", IPSCAN_SPECIALTESTS_URL); 654 | // Offer the opportunity for feedback and a link to the source 655 | printf("If you have any queries related to the results of this scan, or suggestions for improvement/additions to its functionality"); 656 | printf(" then please email me. ",\ 657 | EMAILADDRESS, hostname, tstring ); 658 | } 659 | } 660 | else 661 | { 662 | IPSCAN_LOG( LOGPREFIX "ipscan_web: ERROR: localtime_r() in create_results_key_table() returned NULL\n"); 663 | } 664 | 665 | printf("The source code for this scanner is freely available at github.

\n"); 666 | 667 | printf("\n"); 668 | printf("\n"); 669 | printf("\n"); 670 | printf("\n"); 671 | 672 | for (i=0; PORTEOL != resultsstruct[i].returnval; i++) 673 | { 674 | printf("\n"); 675 | printf("\n",resultsstruct[i].colour,\ 676 | resultsstruct[i].label, resultsstruct[i].description); 677 | printf("\n"); 678 | } 679 | printf("
REPORTED STATEMEANING
%s %s
\n"); 680 | // Only include if ping is supported 681 | #if (1 == IPSCAN_INCLUDE_PING) 682 | printf("

NOTE: Results in the ICMPv6 ECHO REQUEST test marked as INDIRECT indicate an ICMPv6 error response was received from another host (e.g. a router or firewall) rather"); 683 | printf(" than the host under test. In this case the address of the responding host is also displayed.

\n"); 684 | printf("

NOTE2: TCP/UDP tests which elicit an active negative response (coloured YELLOW) may come from either the host under test OR another device in the path (e.g. a firewall/router). An indirect response to the ICMPv6 ECHO REQUEST test increases the likelihood that another device may have responded to the TCP/UDP probes.

\n"); 685 | #else 686 | printf("

NOTE: TCP/UDP tests which elicit an active negative response (coloured YELLOW) may come from either the host under test OR another device in the path (e.g. a firewall/router).

\n"); 687 | #endif 688 | } 689 | 690 | void create_html_body(char * hostname, time_t timestamp, uint16_t numports, uint16_t numudpports, const struct portlist_struc *portlist, const struct portlist_struc *udpportlist) 691 | { 692 | uint16_t portindex; 693 | uint16_t port; 694 | uint8_t special; 695 | int position = 0; 696 | int last; 697 | char starttime[32]; // ctime requires 26 chars 698 | char * stptr = NULL; 699 | stptr = ctime_r(×tamp, starttime); 700 | 701 | printf("\n"); 702 | 703 | printf("\n"); 711 | 712 | printf("
\n"); 713 | 714 | printf("

IPv6 Port Scanner Version %s, results for host %s

\n", IPSCAN_VER, hostname); 715 | 716 | if (NULL == stptr) 717 | { 718 | IPSCAN_LOG( LOGPREFIX "ipscan_web: ERROR: ctime_r() in create_html_body() returned NULL\n"); 719 | } 720 | 721 | printf("

Scan beginning at: %s, expected to take up to %d seconds ...

\n", starttime, (int)ESTIMATEDTIMETORUN ); 722 | 723 | printf("\n"); 724 | // ongoing status ROW 725 | printf("\n"); 726 | printf("\n"); 727 | printf("\n"); 728 | 729 | // Only include the PING result row if necessary 730 | #if (1 == IPSCAN_INCLUDE_PING) 731 | printf("\n"); 732 | printf("\n",resultsstruct[PORTUNKNOWN].colour,resultsstruct[PORTUNKNOWN].label); 733 | printf("\n"); 734 | #endif 735 | printf("
Scan status is : IDLE.
ICMPv6 ECHO REQUEST returned : %s
\n"); 736 | 737 | if (0 < numudpports) 738 | { 739 | printf("

Individual IPv6 UDP port scan results (hover for service names):

\n"); 740 | // Start of UDP table 741 | printf("\n"); 742 | 743 | for (portindex= 0; portindex < numudpports ; portindex++) 744 | { 745 | port = udpportlist[portindex].port_num; 746 | special = udpportlist[portindex].special; 747 | last = (portindex == (numudpports-1)) ? 1 : 0 ; 748 | 749 | if (0 == position) printf("\n"); 750 | if (0 != special) 751 | { 752 | printf("\n",COLUMNUDPPCT,udpportlist[portindex].port_desc, resultsstruct[PORTUNKNOWN].colour, \ 753 | port, special, port, special, resultsstruct[PORTUNKNOWN].label ); 754 | } 755 | else 756 | { 757 | printf("\n",COLUMNUDPPCT,udpportlist[portindex].port_desc, resultsstruct[PORTUNKNOWN].colour, \ 758 | port, port, resultsstruct[PORTUNKNOWN].label ); 759 | } 760 | position++; 761 | if (MAXUDPCOLS <= position || 1 == last) { printf("\n"); position=0; }; 762 | } 763 | // end of table 764 | printf("
Port %d[%d] = %sPort %d = %s
\n"); 765 | } 766 | 767 | printf("

Individual IPv6 TCP port scan results (hover for service names):

\n"); 768 | // Start of table 769 | printf("\n"); 770 | position = 0; 771 | 772 | for (portindex= 0; portindex < numports ; portindex++) 773 | { 774 | port = portlist[portindex].port_num; 775 | special = portlist[portindex].special; 776 | last = (portindex == (numports-1)) ? 1 : 0 ; 777 | 778 | if (0 == position) printf("\n"); 779 | if (0 != special) 780 | { 781 | printf("\n",COLUMNPCT,portlist[portindex].port_desc, resultsstruct[PORTUNKNOWN].colour, port, special, port, special, resultsstruct[PORTUNKNOWN].label ); 782 | } 783 | else 784 | { 785 | printf("\n",COLUMNPCT,portlist[portindex].port_desc, resultsstruct[PORTUNKNOWN].colour, port, port, resultsstruct[PORTUNKNOWN].label ); 786 | } 787 | position++; 788 | if (MAXCOLS <= position || 1 == last) { printf("\n"); position=0; }; 789 | } 790 | 791 | // end of table 792 | printf("
Port %d[%d] = %sPort %d = %s
\n"); 793 | printf("
\n"); 794 | 795 | // Create results key table 796 | create_results_key_table(hostname, timestamp); 797 | 798 | printf("
\n"); 799 | 800 | } 801 | 802 | void create_html_body_end(void) 803 | { 804 | printf("\n"); 805 | printf("\n"); 806 | } 807 | 808 | void create_html_form(uint16_t numports, uint16_t numudpports, const struct portlist_struc *portlist, const struct portlist_struc *udpportlist) 809 | { 810 | int i; 811 | uint16_t port,portindex; 812 | uint8_t special; 813 | int position = 0; 814 | 815 | printf("IPv6 Port Scanner Version %s\n", IPSCAN_VER); 816 | printf("\n"); 817 | printf("\n"); 818 | printf("

IPv6 Port Scanner Version %s by Tim Chappell

\n", IPSCAN_VER); 819 | 820 | printf("

Please note that this test may take up to %d seconds to complete.

\n", (int) ESTIMATEDTIMETORUN); 821 | // Useful source http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#successful-controls 822 | 823 | if (0 < numudpports) 824 | { 825 | printf("

The list of UDP ports that will be tested are:

\n"); 826 | 827 | // Start of table 828 | printf("\n"); 829 | for (portindex= 0; portindex < numudpports ; portindex++) 830 | { 831 | port = udpportlist[portindex].port_num; 832 | special = udpportlist[portindex].special; 833 | int last = (portindex == (numudpports-1)) ? 1 : 0 ; 834 | 835 | if (position == 0) printf("\n"); 836 | if (0 != special) 837 | { 838 | printf("\n",COLUMNUDPPCT, udpportlist[portindex].port_desc, port, special); 839 | } 840 | else 841 | { 842 | printf("\n",COLUMNUDPPCT, udpportlist[portindex].port_desc, port); 843 | } 844 | position++; 845 | if (position >= MAXUDPCOLS || last == 1) { printf("\n"); position=0; }; 846 | } 847 | // end of table 848 | printf("
Port %d[%d]Port %d
\n"); 849 | } 850 | 851 | // Useful source http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#successful-controls 852 | printf("

The default list of TCP ports that will be tested are:

\n"); 853 | 854 | // Start of table 855 | printf("\n"); 856 | position = 0; 857 | for (portindex= 0; portindex < numports ; portindex++) 858 | { 859 | port = portlist[portindex].port_num; 860 | special = portlist[portindex].special; 861 | int last = (portindex == (numports-1)) ? 1 : 0 ; 862 | 863 | if (0 == position) printf("\n"); 864 | if (0 != special) 865 | { 866 | printf("\n",COLUMNPCT, portlist[portindex].port_desc, port, special); 867 | } 868 | else 869 | { 870 | printf("\n",COLUMNPCT, portlist[portindex].port_desc, port); 871 | } 872 | 873 | position++; 874 | if (MAXCOLS <= position || 1 == last) { printf("\n"); position=0; }; 875 | } 876 | // end of table 877 | printf("
Port %d[%d]Port %d
\n"); 878 | 879 | printf("

1. Select whether to include the default list of TCP ports, or not:

\n"); 880 | 881 | printf("
\n"); 882 | printf(" Include default TCP ports listed above in the scan
\n"); 883 | printf(" Exclude default TCP ports, test only those specified below
\n"); 884 | printf("

2. Enter any custom TCP ports you wish to scan (%d-%d inclusive). Duplicate or invalid ports will be discarded:

\n", MINVALIDPORT, MAXVALIDPORT); 885 | 886 | printf("\n"); 887 | position = 0; 888 | for (i = 0; i < NUMUSERDEFPORTS ; i++) 889 | { 890 | // Start of a new row, so insert the appropriate tag if required 891 | int last = (i == (NUMUSERDEFPORTS-1)) ? 1 : 0; 892 | if (position == 0) printf("\n"); 893 | 894 | printf("\n", COLUMNPCT, i, i); 895 | 896 | // Get ready for the next cell, add the end of row tag if required 897 | position++; 898 | if (position >= MAXCOLS || last == 1) { printf("\n"); position=0; }; 899 | } 900 | printf("
\n"); 901 | #if (INCLUDETERMSOFUSE != 0) 902 | printf("

3. and finally, confirming that you accept the terms of usage, please click on the Begin scan button:

\n", TERMSOFUSEURL); 903 | #else 904 | printf("

3. and finally, please click on the Begin scan button:

\n"); 905 | #endif 906 | 907 | printf("\n"); 908 | printf("
\n"); 909 | } 910 | 911 | #ifdef IPSCAN_HTML5_ENABLED 912 | void create_html5_form(uint16_t numports, uint16_t numudpports, const struct portlist_struc *portlist, const struct portlist_struc *udpportlist) 913 | { 914 | int i; 915 | uint16_t port,portindex; 916 | uint8_t special; 917 | int position = 0; 918 | 919 | printf("IPv6 Port Scanner Version %s\n", IPSCAN_VER); 920 | printf("\n"); 921 | printf("\n"); 922 | printf("
\n"); 923 | 924 | printf("

IPv6 Port Scanner Version %s by Tim Chappell

\n", IPSCAN_VER); 925 | 926 | printf("

Please note that this test may take up to %d seconds to complete.

\n", (int) ESTIMATEDTIMETORUN); 927 | // Useful source http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#successful-controls 928 | 929 | if (numudpports > 0) 930 | { 931 | printf("

The list of UDP ports that will be tested are:

\n"); 932 | 933 | // Start of table 934 | printf("\n", IPSCAN_BODYDIV_WIDTH); 935 | for (portindex= 0; portindex < numudpports ; portindex++) 936 | { 937 | port = udpportlist[portindex].port_num; 938 | special = udpportlist[portindex].special; 939 | int last = (portindex == (numudpports-1)) ? 1 : 0 ; 940 | 941 | if (position == 0) printf("\n"); 942 | 943 | if (0 != special) 944 | { 945 | printf("\n", udpportlist[portindex].port_desc, port, special); 946 | } 947 | else 948 | { 949 | printf("\n", udpportlist[portindex].port_desc, port); 950 | } 951 | position++; 952 | if (position >= MAXUDPCOLS || last == 1) { printf("\n"); position=0; }; 953 | } 954 | // end of table 955 | printf("
Port %d[%d]Port %d
\n"); 956 | } 957 | 958 | // Useful source http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#successful-controls 959 | printf("

The default list of TCP ports that will be tested are:

\n"); 960 | 961 | // Start of table 962 | printf("\n", IPSCAN_BODYDIV_WIDTH); 963 | position = 0; 964 | for (portindex= 0; portindex < numports ; portindex++) 965 | { 966 | port = portlist[portindex].port_num; 967 | special = portlist[portindex].special; 968 | int last = (portindex == (numports-1)) ? 1 : 0 ; 969 | 970 | if (position == 0) printf("\n"); 971 | if (0 != special) 972 | { 973 | printf("\n", portlist[portindex].port_desc, port, special); 974 | } 975 | else 976 | { 977 | printf("\n", portlist[portindex].port_desc, port); 978 | } 979 | 980 | position++; 981 | if (position >= MAXCOLS || last == 1) { printf("\n"); position=0; }; 982 | } 983 | // end of table 984 | printf("
Port %d[%d]Port %d
\n"); 985 | 986 | printf("

1. Select whether to include the default list of TCP ports, or not:

\n"); 987 | printf("
\n"); 988 | printf(" Include default TCP ports listed above in the scan
\n"); 989 | printf(" Exclude default TCP ports, test only those specified below
\n"); 990 | printf("

2. Enter any custom TCP ports you wish to scan (%d-%d inclusive). Duplicate or invalid ports will be discarded:

\n", MINVALIDPORT, MAXVALIDPORT); 991 | 992 | printf("\n", IPSCAN_BODYDIV_WIDTH); 993 | position = 0; 994 | for (i = 0; i < NUMUSERDEFPORTS ; i++) 995 | { 996 | // Start of a new row, so insert the appropriate tag if required 997 | int last = (i == (NUMUSERDEFPORTS-1)) ? 1 : 0; 998 | if (position == 0) printf("\n"); 999 | 1000 | printf("\n", MINVALIDPORT, MAXVALIDPORT, i, i); 1001 | 1002 | // Get ready for the next cell, add the end of row tag if required 1003 | position++; 1004 | if (position >= MAXCOLS || last == 1) { printf("\n"); position=0; }; 1005 | } 1006 | printf("
\n"); 1007 | 1008 | #if (INCLUDETERMSOFUSE != 0) 1009 | printf("

3. Accept the Terms and Conditions by ticking this box .

\n",TERMSOFUSEURL); 1010 | #else 1011 | printf("

3. and finally, please click on the Begin Scan button:

\n"); 1012 | #endif 1013 | 1014 | printf("\n"); 1015 | printf("
\n"); 1016 | printf("
\n"); 1017 | } 1018 | #endif 1019 | -------------------------------------------------------------------------------- /upgrade.bsh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # IPscan - an HTTP-initiated IPv6 port scanner. 4 | # 5 | # (C) Copyright 2011-2025 Tim Chappell. 6 | # 7 | # This file is part of IPscan. 8 | # 9 | # IPscan is free software: you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation, either version 3 of the License, or 12 | # (at your option) any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with IPscan. If not, see . 21 | # 22 | # upgrade.bsh 23 | # version description 24 | # 0.01 initial version 25 | # 0.02 update copyright year 26 | # 0.03 update copyright year 27 | # 0.04 update copyright year 28 | # 0.05 update copyright year 29 | # 0.06 update copyright year 30 | # 0.07 update copyright year 31 | 32 | SRC=./ipscan.h 33 | if [ -r "${SRC}" ] ; then 34 | echo "Found file containing credentials: "${SRC} 35 | MYSQL_HOST=$(awk 'BEGIN{u="TJC369"};{if ($1 == "#define" && $2 == "MYSQL_HOST") {u=$3;gsub("\"","",u)}};END{print u}' ${SRC}) 36 | MYSQL_USER=$(awk 'BEGIN{u="TJC369"};{if ($1 == "#define" && $2 == "MYSQL_USER") {u=$3;gsub("\"","",u)}};END{print u}' ${SRC}) 37 | MYSQL_PASSWD=$(awk 'BEGIN{u="TJC369"};{if ($1 == "#define" && $2 == "MYSQL_PASSWD") {u=$3;gsub("\"","",u)}};END{print u}' ${SRC}) 38 | MYSQL_DBNAME=$(awk 'BEGIN{u="TJC369"};{if ($1 == "#define" && $2 == "MYSQL_DBNAME") {u=$3;gsub("\"","",u)}};END{print u}' ${SRC}) 39 | MYSQL_TBLNAME=$(awk 'BEGIN{u="TJC369"};{if ($1 == "#define" && $2 == "MYSQL_TBLNAME") {u=$3;gsub("\"","",u)}};END{print u}' ${SRC}) 40 | if [[ "${MYSQL_HOST}" = "TJC369" || "${MYSQL_USER}" = "TJC369" || "${MYSQL_PASSWD}" = "TJC369" || "${MYSQL_DBNAME}" = "TJC369" || "${MYSQL_TBLNAME}" = "TJC369" ]] ; then 41 | echo "" 42 | echo "ERROR: Failed to find a complete set of MYSQL_ variables:" 43 | echo "MYSQL_HOST ="$MYSQL_HOST 44 | echo "MYSQL_USER ="$MYSQL_USER 45 | echo "MYSQL_PASSWD ="$MYSQL_PASSWD 46 | echo "MYSQL_DBNAME ="$MYSQL_DBNAME 47 | echo "MYSQL_TBLNAME="$MYSQL_TBLNAME 48 | exit 1 49 | fi 50 | # dropping the results table is sufficient to cause the upgrade - it will be automatically created in the new format 51 | mysql --user=${MYSQL_USER} --password=${MYSQL_PASSWD} --host=${MYSQL_HOST} --execute='drop table if exists '${MYSQL_TBLNAME}';' ${MYSQL_DBNAME} 52 | RC=$? 53 | if [ "${RC}" -eq 0 ] ; then 54 | echo "MySQL command finished successfully" 55 | else 56 | echo "MySQL command finished unsuccessfully, with RC="${RC} 57 | fi 58 | else 59 | echo "Failed to find file containing credentials, looking for: "${SRC} 60 | fi 61 | --------------------------------------------------------------------------------