diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml
new file mode 100644
index 00000000..f2067efd
--- /dev/null
+++ b/.github/workflows/unittests.yml
@@ -0,0 +1,27 @@
+name: masscan unit tests
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [master]
+
+permissions:
+ contents: read
+
+jobs:
+ regress:
+ name: Run regression tests
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest, macos-latest]
+ steps:
+ - name: Checkout masscan
+ uses: actions/checkout@v3
+ - name: Install libpcap-dev
+ if: ${{ vars.RUNNER_OS == 'Linux' }}
+ run: sudo apt-get install -y libpcap-dev
+ - name: Run regression tests
+ run: make test
diff --git a/.gitignore b/.gitignore
index 642828d0..94dc49c6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
paused.conf
.Makefile.swp
.vscode
+vs10/.vs/
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 701dbd56..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-# This is a build/test script for "travis-ci", a continuous
-# integration website that will build and test this project
-# every time something is submitted, and send me email if
-# the test breaks
-arch:
- - amd64
- - ppc64le
-language: c
-
-os:
- - linux
- - osx
-
-compiler:
- - gcc
- - clang
-
-before_install:
- - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y libpcap-dev; fi
-
-script:
- - make test
-
-
diff --git a/LICENSE b/LICENSE
index c2a4a626..be3f7b28 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,13 +1,661 @@
-Copyright (c) 2013 Robert David Graham
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
-You can use, redistribute, and/or modify
-this code under the terms of the GNU Affero General Public License
-version 3.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
+ Preamble
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+ .
diff --git a/Makefile b/Makefile
index 9c94cfe7..866be22d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,10 @@
+# If Windows, then assume the compiler is `gcc` for the
+# MinGW environment. I can't figure out how to tell if it's
+# actually MingGW. FIXME TODO
+ifeq ($(OS),Windows_NT)
+ CC = gcc
+endif
+
# Try to figure out the default compiler. I dont know the best
# way to do this with `gmake`. If you have better ideas, please
# submit a pull request on github.
@@ -55,7 +62,7 @@ endif
ifneq (, $(findstring mingw, $(SYS)))
INCLUDES = -Ivs10/include
LIBS = -L vs10/lib -lIPHLPAPI -lWs2_32
-FLAGS2 = -march=i686
+#FLAGS2 = -march=i686
endif
# Cygwin
diff --git a/README.md b/README.md
index 9f41fabd..f439690c 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[](https://travis-ci.org/robertdavidgraham/masscan.svg)
+[](https://github.com/robertdavidgraham/masscan/actions/workflows/unittests.yml/?branch=master)
# MASSCAN: Mass IP port scanner
@@ -152,11 +152,11 @@ On FreeBSD and older MacOS, use an `ipfw` command:
On newer MacOS and OpenBSD, use the `pf` packet-filter utility.
Edit the file `/etc/pf.conf` to add a line like the following:
- block in proto tcp from any to any port 40000
+ block in proto tcp from any to any port 40000:40015
Then to enable the firewall, run the command:
- # pfctrl -E
+ # pfctl -E
If the firewall is already running, then either reboot or reload the rules
with the following command:
@@ -504,7 +504,7 @@ probably faster than you want anyway.
A bounty is offered for vulnerabilities, see the VULNINFO.md file for more
information.
-This project uses safe functions like `strcpy_s()` instead of unsafe functions
+This project uses safe functions like `safe_strcpy()` instead of unsafe functions
like `strcpy()`.
This project has automated unit regression tests (`make regress`).
@@ -545,7 +545,7 @@ network needs to be able to route IPv6 packets.
## PF_RING
To get beyond 2 million packets/second, you need an Intel 10-gbps Ethernet
-adapter and a special driver known as ["PF_RING ZC" from ntop](http://www.ntop.org/products/packet-capture/pf_ring/pf_ring-zc-zero-copy/). Masscan doesn't need to be rebuilt in order to use PF_RING. To use PF_RING,
+adapter and a special driver known as ["PF_RING ZC" from ntop](https://www.ntop.org/installation-guide-for-pf_ring/). Masscan doesn't need to be rebuilt in order to use PF_RING. To use PF_RING,
you need to build the following components:
* `libpfring.so` (installed in /usr/lib/libpfring.so)
@@ -599,3 +599,19 @@ at which they perform this calculation, making `masscan` much faster.
This tool created by Robert Graham:
email: robert_david_graham@yahoo.com
twitter: @ErrataRob
+
+# License
+
+Copyright (c) 2013 Robert David Graham
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, version 3 of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
diff --git a/data/exclude.conf b/data/exclude.conf
index f6bd5890..480eeb21 100644
--- a/data/exclude.conf
+++ b/data/exclude.conf
@@ -77,7 +77,7 @@
#organization scan our network at all.
#
#If you fail to do that we will block whole traffic from ASN 10439, and we
-#will fail a police report after that.
+#will file a police report after that.
#
#Let me know when you stop, since we still receive the attack from you, and
#by the way your scan are not going anywhere, it's was dropped from our edge
diff --git a/doc/faq/FAQ0001-slow.md b/doc/faq/FAQ0001-slow.md
index ded1c92c..f1d406b5 100644
--- a/doc/faq/FAQ0001-slow.md
+++ b/doc/faq/FAQ0001-slow.md
@@ -21,9 +21,9 @@ The speed is determined by the operating system. The amount of CPU used by `mass
itself is insignificant.
My theory is various configuration options within the operating system that can make
-packet tranmission very slow. Simple features that would not otherwise impact network
+packet transmission very slow. Simple features that would not otherwise impact network
stacks that run at lower rates become really important at high rates.
-One way around this is to install `PF_RING` and decidate a network adapter to packet
+One way around this is to install `PF_RING` and dedicate a network adapter to packet
transmission completely bypassing the operating system. In that case, packet transmission
rates can reach 15 million packets-per-second.
diff --git a/doc/faq/FAQ0002-drops.md b/doc/faq/FAQ0002-drops.md
index 402d4e8e..0fb3d8c6 100644
--- a/doc/faq/FAQ0002-drops.md
+++ b/doc/faq/FAQ0002-drops.md
@@ -27,5 +27,5 @@ rates rather than overloading network equipment.
# Issues
-- (#546 fast scan get result)[https://github.com/robertdavidgraham/masscan/issues/546]
+- [#546 fast scan get result](https://github.com/robertdavidgraham/masscan/issues/546)
diff --git a/doc/faq/README.md b/doc/faq/README.md
index 5edd183e..b6345be6 100644
--- a/doc/faq/README.md
+++ b/doc/faq/README.md
@@ -5,5 +5,5 @@ questions
- 1 - [Why is it not as fast as I expect?](FAQ0001-slow.md)
- 2 - [Why are many results missing that I expect?](FAQ0002-drops.md)
- - 3 - [How can I add my IPs to an official exlude list, to get people to stop scanning me?](FAQ0003-excludelist.md)
+ - 3 - [How can I add my IPs to an official exclude list, to get people to stop scanning me?](FAQ0003-excludelist.md)
- 4 - [Why is this in my server logs?](FAQ0004-serverlogs.md)
diff --git a/doc/masscan.8 b/doc/masscan.8
index a1fd9346..3cd09f1e 100644
--- a/doc/masscan.8
+++ b/doc/masscan.8
@@ -7,7 +7,7 @@
\fBmasscan\fR \- Fast scan of the Internet
.
.SH "SYNOPSIS"
-masscan \-p \fIports\fR \fIoptions\fR
+masscan [\fIoptions\fR] [... \-p \fIPORT\fR[,\fIPORT\fR...]]
.
.SH "DESCRIPTION"
\fBmasscan\fR is an Internet\-scale port scanner, useful for large scale surveys of the Internet, or of internal networks\. While the default transmit rate is only 100 packets/second, it can optional go as fast as 25 million packets/second, a rate sufficient to scan the Internet in 3 minutes for one port\.
@@ -15,79 +15,79 @@ masscan \-p \fIports\fR \fIoptions\fR
.SH "OPTIONS"
.
.IP "\(bu" 4
-\fB\fR: anything on the command\-line not prefixed with a \'\-\' is assumed to be an IP address or range\. There are three valid formats\. The first is a single IPv4 address like "192\.168\.0\.1"\. The second is a range like "10\.0\.0\.1\-10\.0\.0\.100"\. The third is a CIDR address, like "0\.0\.0\.0/0"\. At least one target must be specified\. Multiple targets can be specified\. This can be specified as multiple options separated by space, or can be separated by a comma as a single option, such as \fB10\.0\.0\.0/8,192\.168\.0\.1\fR\.
+\fB\fR: anything on the command\-line not prefixed with a \'\-\' is assumed to be an IP address or range\. There are three valid formats\. The first is a single IPv4 address like "192\.168\.0\.1"\. The second is a range like "10\.0\.0\.1\-10\.0\.0\.100"\. The third is a CIDR address, like "0\.0\.0\.0/0"\. At least one target must be specified\. Multiple targets can be specified\. This can be specified as multiple options separated by space, or can be separated by a comma as a single option, such as \fB10\.0\.0\.0/8,192\.168\.0\.1\fR\.
.
.IP "\(bu" 4
-\fB\-\-range \fR: the same as target range spec described above, except as a named parameter instead of an unnamed one\.
+\fB\-\-range \fR: the same as target range spec described above, except as a named parameter instead of an unnamed one\.
.
.IP "\(bu" 4
-\fB\-p \fR: specifies the port(s) to be scanned\. A single port can be specified, like \fB\-p80\fR\. A range of ports can be specified, like \fB\-p 20\-25\fR\. A list of ports/ranges can be specified, like \fB\-p80,20\-25\fR\. UDP ports can also be specified, like \fB\-\-ports U:161,U:1024\-1100\fR\.
+\fB\-p PORT[,PORT...]\fR, \fB\-\-ports PORT[,PORT...]\fR: specifies the port(s) to be scanned\. A single port can be specified, like \fB\-p80\fR\. A range of ports can be specified, like \fB\-p 20\-25\fR\. A list of ports/ranges can be specified, like \fB\-p80,20\-25\fR\. UDP ports can also be specified, like \fB\-\-ports U:161,U:1024\-1100\fR\.
.
.IP "\(bu" 4
\fB\-\-banners\fR: specifies that banners should be grabbed, like HTTP server versions, HTML title fields, and so forth\. Only a few protocols are supported\.
.
.IP "\(bu" 4
-\fB\-\-rate \fR: specifies the desired rate for transmitting packets\. This can be very small numbers, like \fB0\.1\fR for transmitting packets at rates of one every 10 seconds, for very large numbers like 10000000, which attempts to transmit at 10 million packets/second\. In my experience, Windows and can do 250 thousand packets per second, and latest versions of Linux can do 2\.5 million packets per second\. The PF_RING driver is needed to get to 25 million packets/second\.
+\fB\-\-rate RATE\fR: specifies the desired rate for transmitting packets\. This can be very small numbers, like \fB0\.1\fR for transmitting packets at rates of one every 10 seconds, for very large numbers like 10000000, which attempts to transmit at 10 million packets/second\. In my experience, Windows and can do 250 thousand packets per second, and latest versions of Linux can do 2\.5 million packets per second\. The PF_RING driver is needed to get to 25 million packets/second\.
.
.IP "\(bu" 4
-\fB\-c \fR, \fB\-\-conf \fR: reads in a configuration file\. The format of the configuration file is described below\.
+\fB\-c FILE\fR, \fB\-\-conf FILE\fR: reads in a configuration file\. The format of the configuration file is described below\.
.
.IP "\(bu" 4
-\fB\-\-resume \fR: the same as \fB\-\-conf\fR, except that a few options are automatically set, such as \fB\-\-append\-output\fR\. The format of the configuration file is described below\.
+\fB\-\-resume FILE\fR: the same as \fB\-\-conf\fR, except that a few options are automatically set, such as \fB\-\-append\-output\fR\. The format of the configuration file is described below\.
.
.IP "\(bu" 4
\fB\-\-echo\fR: don\'t run, but instead dump the current configuration to a file\. This file can then be used with the \fB\-c\fR option\. The format of this output is described below under \'CONFIGURATION FILE\'\.
.
.IP "\(bu" 4
-\fB\-e \fR, \fB\-\-adapter \fR: use the named raw network interface, such as "eth0" or "dna1"\. If not specified, the first network interface found with a default gateway will be used\.
+\fB\-e IFNAME\fR, \fB\-\-adapter IFNAME\fR: use the named raw network interface, such as "eth0" or "dna1"\. If not specified, the first network interface found with a default gateway will be used\.
.
.IP "\(bu" 4
-\fB\-\-adapter\-ip \fR: send packets using this IP address\. If not specified, then the first IP address bound to the network interface will be used\. Instead of a single IP address, a range may be specified\. NOTE: The size of the range must be an even power of 2, such as 1, 2, 4, 8, 16, 1024 etc\. addresses\.
+\fB\-\-adapter\-ip IP\fR: send packets using this IP address\. If not specified, then the first IP address bound to the network interface will be used\. Instead of a single IP address, a range may be specified\. NOTE: The size of the range must be an even power of 2, such as 1, 2, 4, 8, 16, 1024 etc\. addresses\.
.
.IP "\(bu" 4
-\fB\-\-adapter\-port \fR: send packets using this port number as the source\. If not specified, a random port will be chosen in the range 40000 through 60000\. This port should be filtered by the host firewall (like iptables) to prevent the host network stack from interfering with arriving packets\. Instead of a single port, a range can be specified, like \fB40000\-40003\fR\. NOTE: The size of the range must be an even power of 2, such as the example above that has a total of 4 addresses\.
+\fB\-\-adapter\-port PORT\fR: send packets using this port number as the source\. If not specified, a random port will be chosen in the range 40000 through 60000\. This port should be filtered by the host firewall (like iptables) to prevent the host network stack from interfering with arriving packets\. Instead of a single port, a range can be specified, like \fB40000\-40003\fR\. NOTE: The size of the range must be an even power of 2, such as the example above that has a total of 4 addresses\.
.
.IP "\(bu" 4
-\fB\-\-adapter\-mac \fR: send packets using this as the source MAC address\. If not specified, then the first MAC address bound to the network interface will be used\.
+\fB\-\-adapter\-mac MAC\fR: send packets using this as the source MAC address\. If not specified, then the first MAC address bound to the network interface will be used\.
.
.IP "\(bu" 4
-\fB\-\-router\-mac \fR: send packets to this MAC address as the destination\. If not specified, then the gateway address of the network interface will be ARPed\.
+\fB\-\-router\-mac MAC\fR: send packets to this MAC address as the destination\. If not specified, then the gateway address of the network interface will be ARPed\.
.
.IP "\(bu" 4
\fB\-\-ping\fR: indicates that the scan should include an ICMP echo request\. This may be included with TCP and UDP scanning\.
.
.IP "\(bu" 4
-\fB\-\-exclude \fR: blacklist an IP address or range, preventing it from being scanned\. This overrides any target specification, guaranteeing that this address/range won\'t be scanned\. This has the same format as the normal target specification\.
+\fB\-\-exclude \fR: blacklist an IP address or range, preventing it from being scanned\. This overrides any target specification, guaranteeing that this address/range won\'t be scanned\. This has the same format as the normal target specification\.
.
.IP "\(bu" 4
-\fB\-\-excludefile \fR: reads in a list of exclude ranges, in the same target format described above\. These ranges override any targets, preventing them from being scanned\.
+\fB\-\-excludefile FILE\fR: reads in a list of exclude ranges, in the same target format described above\. These ranges override any targets, preventing them from being scanned\.
.
.IP "\(bu" 4
-\fB\-\-append\-output\fR: causes output to append to file, rather than overwriting the file\.
+\fB\-\-append\-output\fR: causes output to append to the file, rather than overwriting the file\.
.
.IP "\(bu" 4
\fB\-\-iflist\fR: list the available network interfaces, and then exits\.
.
.IP "\(bu" 4
-\fB\-\-retries\fR: the number of retries to send, at 1 second intervals\. Note that since this scanner is stateless, retries are sent regardless if replies have already been received\.
+\fB\-\-retries NUM\fR: the number of retries to send, at 1 second intervals\. Note that since this scanner is stateless, retries are sent regardless if replies have already been received\.
.
.IP "\(bu" 4
\fB\-\-nmap\fR: print help about nmap\-compatibility alternatives for these options\.
.
.IP "\(bu" 4
-\fB\-\-pcap\-payloads\fR: read packets from a libpcap file containing packets and extract the UDP payloads, and associate those payloads with the destination port\. These payloads will then be used when sending UDP packets with the matching destination port\. Only one payload will be remembered per port\. Similar to \fB\-\-nmap\-payloads\fR\.
+\fB\-\-pcap\-payloads FILE\fR: read packets from a libpcap file containing packets and extract the UDP payloads, and associate those payloads with the destination port\. These payloads will then be used when sending UDP packets with the matching destination port\. Only one payload will be remembered per port\. Similar to \fB\-\-nmap\-payloads\fR\.
.
.IP "\(bu" 4
-\fB\-\-nmap\-payloads \fR: read in a file in the same format as the nmap file \fBnmap\-payloads\fR\. This contains UDP payload, so that we can send useful UDP packets instead of empty ones\. Similar to \fB\-\-pcap\-payloads\fR\.
+\fB\-\-nmap\-payloads FILE\fR: read in a file in the same format as the nmap file \fBnmap\-payloads\fR\. This contains UDP payload, so that we can send useful UDP packets instead of empty ones\. Similar to \fB\-\-pcap\-payloads\fR\.
.
.IP "\(bu" 4
-\fB\-\-http\-user\-agent \fR: replaces the existing user\-agent field with the indicated value when doing HTTP requests\.
+\fB\-\-http\-user\-agent USER_AGENT\fR: replaces the existing user\-agent field with the indicated value when doing HTTP requests\.
.
.IP "\(bu" 4
\fB\-\-open\-only\fR: report only open ports, not closed ports\.
.
.IP "\(bu" 4
-\fB\-\-pcap \fR: saves received packets (but not transmitted packets) to the libpcap\-format file\.
+\fB\-\-pcap FILE\fR: saves received packets (but not transmitted packets) to the libpcap\-format file\.
.
.IP "\(bu" 4
\fB\-\-packet\-trace\fR: prints a summary of those packets sent and received\. This is useful at low rates, like a few packets per second, but will overwhelm the terminal at high rates\.
@@ -96,34 +96,34 @@ masscan \-p \fIports\fR \fIoptions\fR
\fB\-\-pfring\fR: force the use of the PF_RING driver\. The program will exit if PF_RING DNA drvers are not available\.
.
.IP "\(bu" 4
-\fB\-\-resume\-index\fR: the point in the scan at when it was paused\.
+\fB\-\-resume\-index INDEX\fR: the point in the scan at when it was paused\.
.
.IP "\(bu" 4
-\fB\-\-resume\-count\fR: the maximum number of probes to send before exiting\. This is useful with the \fB\-\-resume\-index\fR to chop up a scan and split it among multiple instances, though the \fB\-\-shards\fR option might be better\.
+\fB\-\-resume\-count NUM\fR: the maximum number of probes to send before exiting\. This is useful with the \fB\-\-resume\-index\fR to chop up a scan and split it among multiple instances, though the \fB\-\-shards\fR option might be better\.
.
.IP "\(bu" 4
-\fB\-\-shards /\fR: splits the scan among instances\. \fBx\fR is the id for this scan, while \fBy\fR is the total number of instances\. For example, \fB\-\-shards 1/2\fR tells an instance to send every other packet, starting with index 0\. Likewise, \fB\-\-shards 2/2\fR sends every other packet, but starting with index 1, so that it doesn\'t overlap with the first example\.
+\fB\-\-shards X/Y\fR: splits the scan among instances\. \fBx\fR is the id for this scan, while \fBy\fR is the total number of instances\. For example, \fB\-\-shards 1/2\fR tells an instance to send every other packet, starting with index 0\. Likewise, \fB\-\-shards 2/2\fR sends every other packet, but starting with index 1, so that it doesn\'t overlap with the first example\.
.
.IP "\(bu" 4
-\fB\-\-rotate \fR: rotates the output file, renaming it with the current timestamp, moving it to a separate directory\. The time is specified in number of seconds, like "3600" for an hour\. Or, units of time can be specified, such as "hourly", or "6hours", or "10min"\. Times are aligned on an even boundary, so if "daily" is specified, then the file will be rotated every day at midnight\.
+\fB\-\-rotate TIME\fR: rotates the output file, renaming it with the current timestamp, moving it to a separate directory\. The time is specified in number of seconds, like "3600" for an hour\. Or, units of time can be specified, such as "hourly", or "6hours", or "10min"\. Times are aligned on an even boundary, so if "daily" is specified, then the file will be rotated every day at midnight\.
.
.IP "\(bu" 4
-\fB\-\-rotate\-offset \fR: an offset in the time\. This is to accommodate timezones\.
+\fB\-\-rotate\-offset TIME\fR: an offset in the time\. This is to accommodate timezones\.
.
.IP "\(bu" 4
-\fB\-\-rotate\-dir \fR: when rotating the file, this specifies which directory to move the file to\. A useful directory is \fB/var/log/masscan\fR\.
+\fB\-\-rotate\-dir DIR\fR: when rotating the file, this specifies which directory to move the file to\. A useful directory is \fB/var/log/masscan\fR\.
.
.IP "\(bu" 4
-\fB\-\-seed \fR: an integer that seeds the random number generator\. Using a different seed will cause packets to be sent in a different random order\. Instead of an integer, the string \fBtime\fR can be specified, which seeds using the local timestamp, automatically generating a differnet random order of scans\. If no seed specified, \fBtime\fR is the default\.
+\fB\-\-seed INT\fR: an integer that seeds the random number generator\. Using a different seed will cause packets to be sent in a different random order\. Instead of an integer, the string \fBtime\fR can be specified, which seeds using the local timestamp, automatically generating a differnet random order of scans\. If no seed specified, \fBtime\fR is the default\.
.
.IP "\(bu" 4
\fB\-\-regress\fR: run a regression test, returns \'0\' on success and \'1\' on failure\.
.
.IP "\(bu" 4
-\fB\-\-ttl \fR: specifies the TTL of outgoing packets, defaults to 255\.
+\fB\-\-ttl NUM\fR: specifies the TTL of outgoing packets, defaults to 255\.
.
.IP "\(bu" 4
-\fB\-\-wait \fR: specifies the number of seconds after transmit is done to wait for receiving packets before exiting the program\. The default is 10 seconds\. The string \fBforever\fR can be specified to never terminate\.
+\fB\-\-wait SECONDS\fR: specifies the number of seconds after transmit is done to wait for receiving packets before exiting the program\. The default is 10 seconds\. The string \fBforever\fR can be specified to never terminate\.
.
.IP "\(bu" 4
\fB\-\-offline\fR: don\'t actually transmit packets\. This is useful with a low rate and \fB\-\-packet\-trace\fR to look at what packets might\'ve been transmitted\. Or, it\'s useful with \fB\-\-rate 100000000\fR in order to benchmark how fast transmit would work (assuming a zero\-overhead driver)\. PF_RING is about 20% slower than the benchmark result from offline mode\.
@@ -135,28 +135,28 @@ masscan \-p \fIports\fR \fIoptions\fR
\fB\-\-interactive\fR: show the results in realtime on the console\. It has no effect if used with \-\-output\-format or \-\-output\-filename\.
.
.IP "\(bu" 4
-\fB\-\-output\-format \fR: indicates the format of the output file, which can be \fBxml\fR, \fBbinary\fR, \fBgrepable\fR, \fBlist\fR, or \fBJSON\fR\. The option \fB\-\-output\-filename\fR must be specified\.
+\fB\-\-output\-format FMT\fR: indicates the format of the output file, which can be \fBxml\fR, \fBbinary\fR, \fBgrepable\fR, \fBlist\fR, or \fBJSON\fR\. The option \fB\-\-output\-filename\fR must be specified\.
.
.IP "\(bu" 4
-\fB\-\-output\-filename \fR: the file which to save results to\. If the parameter \fB\-\-output\-format\fR is not specified, then the default of \fBxml\fR will be used\.
+\fB\-\-output\-filename FILE\fR: the file which to save results to\. If the parameter \fB\-\-output\-format\fR is not specified, then the default of \fBxml\fR will be used\.
.
.IP "\(bu" 4
-\fB\-oB \fR: sets the output format to binary and saves the output in the given filename\. This is equivelent to using the \fB\-\-output\-format\fR and \fB\-\-output\-filename\fR parameters\. The option \fB\-\-readscan\fR can then be used to read the binary file\. Binary files are much smaller than their XML equivelents, but require a separate step to convert back into XML or another readable format\.
+\fB\-oB FILE\fR: sets the output format to binary and saves the output in the given filename\. This is equivelent to using the \fB\-\-output\-format\fR and \fB\-\-output\-filename\fR parameters\. The option \fB\-\-readscan\fR can then be used to read the binary file\. Binary files are much smaller than their XML equivelents, but require a separate step to convert back into XML or another readable format\.
.
.IP "\(bu" 4
-\fB\-oX \fR: sets the output format to XML and saves the output in the given filename\. This is equivelent to using the \fB\-\-output\-format xml\fR and \fB\-\-output\-filename\fR parameters\.
+\fB\-oX FILE\fR: sets the output format to XML and saves the output in the given filename\. This is equivelent to using the \fB\-\-output\-format xml\fR and \fB\-\-output\-filename\fR parameters\.
.
.IP "\(bu" 4
-\fB\-oG \fR: sets the output format to grepable and saves the output in the given filename\. This is equivelent to using the \-\-output\-format grepable and \-\-output\-filename parameters\.
+\fB\-oG FILE\fR: sets the output format to grepable and saves the output in the given filename\. This is equivelent to using the \-\-output\-format grepable and \-\-output\-filename parameters\.
.
.IP "\(bu" 4
-\fB\-oJ \fR: sets the output format to JSON and saves the output in the given filename\. This is equivelent to using the \-\-output\-format json and \-\-output\-filename parameters\.
+\fB\-oJ FILE\fR: sets the output format to JSON and saves the output in the given filename\. This is equivelent to using the \-\-output\-format json and \-\-output\-filename parameters\.
.
.IP "\(bu" 4
-\fB\-oL \fR: sets the output format to a simple list format and saves the output in the given filename\. This is equivelent to using the \-\-output\-format list and \-\-output\-filename parameters\.
+\fB\-oL FILE\fR: sets the output format to a simple list format and saves the output in the given filename\. This is equivelent to using the \-\-output\-format list and \-\-output\-filename parameters\.
.
.IP "\(bu" 4
-\fB\-\-readscan \fR: reads the files created by the \fB\-oB\fR option from a scan, then outputs them in one of the other formats, depending on command\-line parameters\. In other words, it can take the binary version of the output and convert it to an XML or JSON format\.
+\fB\-\-readscan FILE\fR: reads the files created by the \fB\-oB\fR option from a scan, then outputs them in one of the other formats, depending on command\-line parameters\. In other words, it can take the binary version of the output and convert it to an XML or JSON format\.
.
.IP "" 0
.
diff --git a/doc/masscan.8.markdown b/doc/masscan.8.markdown
index 6bf924ff..87ec9ca4 100644
--- a/doc/masscan.8.markdown
+++ b/doc/masscan.8.markdown
@@ -3,7 +3,7 @@ masscan(8) -- Fast scan of the Internet
## SYNOPSIS
-masscan -p
+masscan \[options\] \[... -p PORT\[,PORT...\]\]
## DESCRIPTION
@@ -15,7 +15,7 @@ one port.
## OPTIONS
- * ``: anything on the command-line not prefixed with a '-' is
+ * ``: anything on the command-line not prefixed with a '-' is
assumed to be an IP address or range. There are three valid formats.
The first is a single IP address like `192.168.0.1` or `2001:db8::1`. The second
is a range like `10.0.0.1-10.0.0.100`. The third is a CIDR address,
@@ -24,10 +24,10 @@ one port.
separated by space, or can be separated by a comma as a single option,
such as `10.0.0.0/8,192.168.0.1,2001:db8::1`.
- * `--range `: the same as target range spec described above,
+ * `--range `: the same as target range spec described above,
except as a named parameter instead of an unnamed one.
- * `-p `: specifies the port(s) to be scanned. A
+ * `-p PORT[,PORT..]`, `--ports PORT[,PORT...]`: specifies the port(s) to be scanned. A
single port can be specified, like `-p80`. A range of ports can be
specified, like `-p 20-25`. A list of ports/ranges can be specified, like
`-p80,20-25`. UDP ports can also be specified, like
@@ -35,9 +35,11 @@ one port.
* `--banners`: specifies that banners should be grabbed after establishing
a TCP connection. Protocols supported include HTTP, FTP, IMAP4, memcached,
- POP3, SMTP, SSH, SSL, SMB, Telnet, RDP, and VNC.
+ POP3, SMTP, SSH, SSL, SMB, Telnet, RDP, and VNC. Note that banner will be
+ grabbed on standard port of the service only.
+ You may change this behavior with `--hello-string` or `--hello-file` options.
- * `--rate `: specifies the desired rate for transmitting
+ * `--rate RATE`: specifies the desired rate for transmitting
packets. This can be very small numbers, like `0.1` for transmitting
packets at rates of one every 10 seconds, for very large numbers like
10000000, which attempts to transmit at 10 million packets/second. In my
@@ -45,11 +47,11 @@ one port.
versions of Linux can do 2.5 million packets per second. The PF_RING driver
is needed to get to 25 million packets/second.
- * `-c `, `--conf `: reads in a configuration file.
+ * `-c FILE`, `--conf FILE`: reads in a configuration file.
If not specified, then will read from `/etc/masscan/masscan.conf` by default.
The format is described below under 'CONFIGURATION FILE'.
- * `--resume `: the same as `--conf`, except that a few options
+ * `--resume FILE`: the same as `--conf`, except that a few options
are automatically set, such as `--append-output`. The format of the
configuration file is described below. The purpose is to resume a scan
saved in `paused.conf` that was interupted with [ctrl-c].
@@ -58,17 +60,17 @@ one port.
This file can then be used with the `-c` option. The format of this
output is described below under 'CONFIGURATION FILE'.
- * `-e `, `--adapter `: use the named raw network interface,
+ * `-e IFNAME`, `--adapter IFNAME`: use the named raw network interface,
such as "eth0" or "dna1". If not specified, the first network interface
found with a default gateway will be used.
- * `--adapter-ip `, `--source-ip`: send packets using this IP address. If not
+ * `--adapter-ip IP`, `--source-ip IP`: send packets using this IP address. If not
specified, then the first IP address bound to the network interface
will be used. Instead of a single IP address, a range may be specified.
NOTE: The size of the range must be an even power of 2, such as 1, 2, 4,
8, 16, 1024 etc. addresses.
- * `--adapter-port `: send packets using this port number as the
+ * `--adapter-port PORT`: send packets using this port number as the
source. If not specified, a random port will be chosen in the range 40000
through 60000. This port should be filtered by the host firewall (like
iptables) to prevent the host network stack from interfering with arriving
@@ -76,90 +78,90 @@ one port.
`40000-40003`. NOTE: The size of the range must be an even power of 2,
such as the example above that has a total of 4 addresses.
- * `--adapter-mac `: send packets using this as the source MAC
+ * `--adapter-mac MAC`: send packets using this as the source MAC
address. If not specified, then the first MAC address bound to the network
interface will be used.
- * `--adapter-vlan `: send packets using this 802.1q VLAN ID
+ * `--adapter-vlan VLANID`: send packets using this 802.1q VLAN ID
- * `--router-mac `: send packets to this MAC address as the
+ * `--router-mac MAC`: send packets to this MAC address as the
destination. If not specified, then the gateway address of the network
interface will be ARPed.
* `--ping`: indicates that the scan should include an ICMP echo request.
This may be included with TCP and UDP scanning.
- * `--exclude `: blacklist an IP address or range, preventing it
+ * `--exclude `: blacklist an IP address or range, preventing it
from being scanned. This overrides any target specification, guaranteeing
that this address/range won't be scanned. This has the same format
as the normal target specification.
- * `--excludefile `: reads in a list of exclude ranges, in the same
+ * `--excludefile FILE`: reads in a list of exclude ranges, in the same
target format described above. These ranges override any targets,
preventing them from being scanned.
- * `-iL `, `--includefile `: reads in a list of ranges to scan, in the same
+ * `-iL FILE`, `--includefile FILE`: reads in a list of ranges to scan, in the same
target format described above for IP addresses and ranges. This file can contain
millions of addresses and ranges.
- * `--append-output`: causes output to append to file, rather than
+ * `--append-output`: causes output to append to the file, rather than
overwriting the file. Useful for when resumeing scans (see `--resume`).
* `--iflist`: list the available network interfaces, and then exits. The
- `-e ` can then be used with one of the listed adapters.
+ `-e IFNAME` can then be used with one of the listed adapters.
- * `--retries`: the number of retries to send, at 1 second intervals. Note
+ * `--retries `: the number of retries to send, at 1 second intervals. Note
that since this scanner is stateless, retries are sent regardless if
replies have already been received.
* `--nmap`: print help about nmap-compatibility alternatives for these
options.
- * `--pcap-payloads`: read packets from a libpcap file containing packets
+ * `--pcap-payloads FILE`: read packets from a libpcap file containing packets
and extract the UDP payloads, and associate those payloads with the
destination port. These payloads will then be used when sending UDP
packets with the matching destination port. Only one payload will
be remembered per port. Similar to `--nmap-payloads`.
- * `--nmap-payloads `: read in a file in the same format as
+ * `--nmap-payloads FILE`: read in a file in the same format as
the nmap file `nmap-payloads`. This contains UDP payload, so that we
can send useful UDP packets instead of empty ones. Similar to
`--pcap-payloads`.
- * `--http-* `: replaces the existing field in the HTTP header
+ * `--http-* HEADER`: replaces the existing field in the HTTP header
with a new one. Fields that can be replaced are `--http-method`, `--http-url`,
`--http-version`,`--http-host`, and `--http-user-agent`.
Example: `--http-user-agent Keurig K575 Coffee Maker`. See also `--http-field` and `--http-cookie`.
- * `--http-field `: replaces the existing HTTP header field,
+ * `--http-field NAME:VALUE`: replaces the existing HTTP header field,
or inserts a new one if the field doesn't exist, given as a `name:value` pair.
Cannot be used to replace the fields in the request-line (method, url, version).
Example: `--http-field Accept:image/gif`.
- * `--http-field-remove `: removes the first field from the header that matches
+ * `--http-field-remove NAME`: removes the first field from the header that matches
(may be needed multiple times for fields like `Cookie` that can exist multiple times)
- * `--http-cookie `: adds a `Cookie:` field to the HTTP header, even
+ * `--http-cookie VALUE`: adds a `Cookie:` field to the HTTP header, even
if other cookie fields exist. The other `--http-*` options replace existing
fields in the HTTP header, this one adds more even if some already exist.
- *`--http-payload `: adds a payload string after the header; this will
- automatically add a `--http-field Content-Length:` field to match the length of the string,
- but the user will have to add their own `--http-field Content-Type:` field to match
+ * `--http-payload STR`: adds a payload string after the header; this will
+ automatically add a `--http-field Content-Length:LEN` field to match the length of the string,
+ but the user will have to add their own `--http-field Content-Type:TYPE` field to match
the string. Presumably, the user will also change the method to something like
`--http-method POST`. Common conntent types would be `application/x-www-form-urlencoded`,
`application/json`, or `text/xml`.
- * `--show [open,closed]`: tells which port status to display, such
+ * `--show [open|closed]`: tells which port status to display, such
as 'open' for those ports that respond with a SYN-ACK on TCP, or
'closed' for those ports that repsond with RST. The default is
only to display 'open' ports.
- * `--noshow [open,closed]`: disables a port status to display, such
+ * `--noshow [open|closed]`: disables a port status to display, such
as to no longer display 'open' ports.
- * `--pcap `: saves received packets (but not transmitted
+ * `--pcap FILE`: saves received packets (but not transmitted
packets) to the libpcap-format file.
* `--packet-trace`: prints a summary of those packets sent and received.
@@ -169,37 +171,37 @@ one port.
* `--pfring`: force the use of the PF_RING driver. The program will exit
if PF_RING DNA drvers are not available.
- * `--resume-index`: the point in the scan at when it was paused.
+ * `--resume-index INDEX`: the point in the scan at when it was paused.
- * `--resume-count`: the maximum number of probes to send before exiting.
+ * `--resume-count NUM`: the maximum number of probes to send before exiting.
This is useful with the `--resume-index` to chop up a scan and split
it among multiple instances, though the `--shards` option might be
better.
- * `--shards /`: splits the scan among instances. `x` is the id
+ * `--shards X/Y`: splits the scan among instances. `x` is the id
for this scan, while `y` is the total number of instances. For example,
`--shards 1/2` tells an instance to send every other packet, starting
with index 0. Likewise, `--shards 2/2` sends every other packet, but
starting with index 1, so that it doesn't overlap with the first example.
- * `--rotate `: rotates the output file, renaming it with the
+ * `--rotate TIME`: rotates the output file, renaming it with the
current timestamp, moving it to a separate directory. The time is
specified in number of seconds, like "3600" for an hour. Or, units
of time can be specified, such as "hourly", or "6hours", or "10min".
Times are aligned on an even boundary, so if "daily" is specified,
then the file will be rotated every day at midnight.
- * `--rotate-offset `: an offset in the time. This is to accomodate
+ * `--rotate-offset TIME`: an offset in the time. This is to accomodate
timezones.
- * `--rotate-size `: rotates the output file when it exceeds the
+ * `--rotate-size SIZE`: rotates the output file when it exceeds the
given size. Typical suffixes can be applied (k,m,g,t) for kilo, mega,
giga, tera.
- * `--rotate-dir `: when rotating the file, this specifies which
+ * `--rotate-dir DIR`: when rotating the file, this specifies which
directory to move the file to. A useful directory is `/var/log/masscan`.
- * `--seed `: an integer that seeds the random number generator.
+ * `--seed INT`: an integer that seeds the random number generator.
Using a different seed will cause packets to be sent in a different
random order. Instead of an integer, the string `time` can be specified,
which seeds using the local timestamp, automatically generating a
@@ -209,9 +211,9 @@ one port.
* `--regress`: run a regression test, returns '0' on success and '1' on
failure.
- * `--ttl `: specifies the TTL of outgoing packets, defaults to 255.
+ * `--ttl NUM`: specifies the TTL of outgoing packets, defaults to 255.
- * `--wait `: specifies the number of seconds after transmit is
+ * `--wait SECONDS`: specifies the number of seconds after transmit is
done to wait for receiving packets before exiting the program. The default
is 10 seconds. The string `forever` can be specified to never terminate.
@@ -230,44 +232,44 @@ one port.
* `--interactive`: show the results in realtime on the console. It has
no effect if used with --output-format or --output-filename.
- * `--output-format `: indicates the format of the output file, which
+ * `--output-format FMT`: indicates the format of the output file, which
can be `xml`, `binary`, `grepable`, `list`, or `JSON`. The
option `--output-filename` must be specified.
- * `--output-filename `: the file which to save results to. If
+ * `--output-filename FILE`: the file which to save results to. If
the parameter `--output-format` is not specified, then the default of
`xml` will be used.
- * `-oB `: sets the output format to binary and saves the output in
+ * `-oB FILE`: sets the output format to binary and saves the output in
the given filename. This is equivalent to using the `--output-format` and
`--output-filename` parameters. The option `--readscan` can then be used to
read the binary file. Binary files are mush smaller than their XML
equivalents, but require a separate step to convert back into XML or
another readable format.
- * `-oX `: sets the output format to XML and saves the output in the
+ * `-oX FILE`: sets the output format to XML and saves the output in the
given filename. This is equivalent to using the `--output-format xml` and
`--output-filename` parameters.
- * `-oG `: sets the output format to grepable and saves the output
+ * `-oG FILE`: sets the output format to grepable and saves the output
in the given filename. This is equivalent to using the --output-format grepable
and --output-filename parameters.
- * `-oJ `: sets the output format to JSON and saves the output in
+ * `-oJ FILE`: sets the output format to JSON and saves the output in
the given filename. This is equivalent to using the --output-format json
and --output-filename parameters.
- * `-oL `: sets the output format to a simple list format and saves
+ * `-oL FILE`: sets the output format to a simple list format and saves
the output in the given filename. This is equivalent to using
the --output-format list and --output-filename parameters.
- * `--readscan `: reads the files created by the `-oB` option
+ * `--readscan FILE`: reads the files created by the `-oB` option
from a scan, then outputs them in one of the other formats, depending
on command-line parameters. In other words, it can take the binary
version of the output and convert it to an XML or JSON format. When this option
is given, defaults from `/etc/masscan/masscan.conf` will not be read.
- * `--connection-timeout `: when doing banner checks, this specifies the
+ * `--connection-timeout SECS`: when doing banner checks, this specifies the
maximum number of seconds that a TCP connection can be held open. The default
is 30 seconds. Increase this time if banners are incomplete. For example,
we have to increase the timeout when downloading all the SSL certs from
@@ -276,17 +278,17 @@ one port.
consume a lot of memory on fast scans. While the code may handle millions of
open TCP connections, you may not have enough memory for that.
- * `--hello-file[] `: send the contents of the file once the
+ * `--hello-file[PORT] FILE`: send the contents of the file once the
TCP connection has been established with the given port. Requires that
`--banners` also be set. Heuristics will be performed on the reponse in
an attempt to discover what protocol, so HTTP responses will be parsed
differently than other protocols.
- * `--hello-string[] `: same as `--hello-file` except that the
+ * `--hello-string[PORT] BASE64`: same as `--hello-file` except that the
contents of the BASE64 encoded string are decoded, then used as the hello
string that greets the server.
- * `--capture ` or `--nocapture `: when doing banners (`--banner`), this
+ * `--capture TYPE` or `--nocapture TYPE`: when doing banners (`--banner`), this
determines what to capture from the banners. By default, only the TITLE field from
HTML documents is captured, to get the entire document, use `--capture html`.
By default, the entire certificate from SSL is captured, to disable this, use
@@ -342,11 +344,11 @@ stack. Normally, this works fine but sometimes can cause problems, especially
with the `--banners` option that establishes a TCP/IP connection. In some
cases, all the stack's parameters will have to be specified separately:
- --adapter-port
- --adapter-ip
- --adapter-mac
- --adapter-vlan
- --router-mac
+ --adapter-port PORT
+ --adapter-ip IP
+ --adapter-mac MAC
+ --adapter-vlan VLANID
+ --router-mac MAC
If the user-mode stack shares the same IP address as the operating-system,
then the kernel will send RST packets during a scan. This can cause
diff --git a/src/rand-blackrock.c b/src/crypto-blackrock.c
similarity index 99%
rename from src/rand-blackrock.c
rename to src/crypto-blackrock.c
index dc355261..eb36522c 100644
--- a/src/rand-blackrock.c
+++ b/src/crypto-blackrock.c
@@ -47,7 +47,7 @@
This is a class of "format-preserving encryption". There are
probably better constructions than what I'm using.
*/
-#include "rand-blackrock.h"
+#include "crypto-blackrock.h"
#include "pixie-timer.h"
#include "util-malloc.h"
#include
diff --git a/src/rand-blackrock.h b/src/crypto-blackrock.h
similarity index 100%
rename from src/rand-blackrock.h
rename to src/crypto-blackrock.h
diff --git a/src/crypto-blackrock2.c b/src/crypto-blackrock2.c
index 0ddc4b8b..db807c88 100644
--- a/src/crypto-blackrock2.c
+++ b/src/crypto-blackrock2.c
@@ -1,8 +1,8 @@
-#include "rand-blackrock.h"
+#include "crypto-blackrock.h"
#include "pixie-timer.h"
#include "unusedparm.h"
#include "util-malloc.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include
#include
#include
diff --git a/src/rand-lcg.c b/src/crypto-lcg.c
similarity index 99%
rename from src/rand-lcg.c
rename to src/crypto-lcg.c
index 9aa2a558..8082daab 100644
--- a/src/rand-lcg.c
+++ b/src/crypto-lcg.c
@@ -3,9 +3,9 @@
generator.
*/
-#include "rand-lcg.h"
-#include "rand-primegen.h" /* DJB's prime factoring code */
-#include "string_s.h"
+#include "crypto-lcg.h"
+#include "crypto-primegen.h" /* DJB's prime factoring code */
+#include "util-safefunc.h"
#include "util-malloc.h"
#include /* for 'sqrt()', may need -lm for gcc */
diff --git a/src/rand-lcg.h b/src/crypto-lcg.h
similarity index 100%
rename from src/rand-lcg.h
rename to src/crypto-lcg.h
diff --git a/src/rand-primegen.c b/src/crypto-primegen.c
similarity index 99%
rename from src/rand-primegen.c
rename to src/crypto-primegen.c
index fdb32423..62e6e16a 100644
--- a/src/rand-primegen.c
+++ b/src/crypto-primegen.c
@@ -3,7 +3,7 @@
such as making it work with Microsoft's compiler on Windows, and
getting rid of warnings.
*/
-#include "rand-primegen.h"
+#include "crypto-primegen.h"
/*
B is 32 times X.
diff --git a/src/rand-primegen.h b/src/crypto-primegen.h
similarity index 100%
rename from src/rand-primegen.h
rename to src/crypto-primegen.h
diff --git a/src/siphash24.c b/src/crypto-siphash24.c
similarity index 99%
rename from src/siphash24.c
rename to src/crypto-siphash24.c
index 01b9ec35..d6c5676d 100644
--- a/src/siphash24.c
+++ b/src/crypto-siphash24.c
@@ -15,7 +15,7 @@
#include
#include
#include
-#include "siphash24.h"
+#include "crypto-siphash24.h"
typedef uint64_t u64;
typedef uint32_t u32;
diff --git a/src/siphash24.h b/src/crypto-siphash24.h
similarity index 81%
rename from src/siphash24.h
rename to src/crypto-siphash24.h
index 656ef2d1..6f1b1f2e 100644
--- a/src/siphash24.h
+++ b/src/crypto-siphash24.h
@@ -1,5 +1,5 @@
-#ifndef SIPHASH24_H
-#define SIPHASH24_H
+#ifndef CRYPTO_SIPHASH24_H
+#define CRYPTO_SIPHASH24_H
#include
uint64_t
diff --git a/src/event-timeout.c b/src/event-timeout.c
index 8afbcdfc..d465edb1 100644
--- a/src/event-timeout.c
+++ b/src/event-timeout.c
@@ -24,7 +24,7 @@
code and causing the bug to come back again.
*/
#include "event-timeout.h"
-#include "logger.h"
+#include "util-logger.h"
#include "util-malloc.h"
#include
#include
@@ -48,6 +48,13 @@ struct Timeouts {
*/
uint64_t current_index;
+ /**
+ * Counts the number of outstanding timeouts. Adding a timeout increments
+ * this number, and removing a timeout decrements this number. The
+ * program shouldn't exit until this number is zero.
+ */
+ uint64_t outstanding_count;
+
/**
* The number of slots is a power-of-2, so the mask is just this
* number minus 1
@@ -104,6 +111,8 @@ timeouts_add(struct Timeouts *timeouts, struct TimeoutEntry *entry,
unsigned index;
/* Unlink from wherever the entry came from */
+ if (entry->timestamp)
+ timeouts->outstanding_count--;
timeout_unlink(entry);
if (entry->prev) {
@@ -122,6 +131,8 @@ timeouts_add(struct Timeouts *timeouts, struct TimeoutEntry *entry,
entry->prev = &timeouts->slots[index];
if (entry->next)
entry->next->prev = &entry->next;
+
+ timeouts->outstanding_count++;
}
/***************************************************************************
@@ -155,6 +166,7 @@ timeouts_remove(struct Timeouts *timeouts, uint64_t timestamp)
}
/* unlink this entry from the timeout system */
+ timeouts--;
timeout_unlink(entry);
/* return a pointer to the structure holding this entry */
diff --git a/src/event-timeout.h b/src/event-timeout.h
index f6eb351f..a5d9a186 100644
--- a/src/event-timeout.h
+++ b/src/event-timeout.h
@@ -3,6 +3,7 @@
#include
#include
#include /* offsetof*/
+#include "util-bool.h" /* */
#if defined(_MSC_VER)
#undef inline
#define inline _inline
@@ -34,6 +35,16 @@ struct TimeoutEntry {
unsigned offset;
};
+/***************************************************************************
+ ***************************************************************************/
+static inline bool
+timeout_is_unlinked(const struct TimeoutEntry *entry) {
+ if (entry->prev == 0 || entry->next == 0)
+ return true;
+ else
+ return false;
+}
+
/***************************************************************************
***************************************************************************/
static inline void
diff --git a/src/in-binary.c b/src/in-binary.c
index b79a7f92..2d12b904 100644
--- a/src/in-binary.c
+++ b/src/in-binary.c
@@ -9,14 +9,19 @@
#include "masscan-status.h"
#include "main-globals.h"
#include "output.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include "in-filter.h"
#include "in-report.h"
#include "util-malloc.h"
+#include "util-logger.h"
#include
#include
+#ifdef _MSC_VER
+#pragma warning(disable:4996)
+#endif
+
static const size_t BUF_MAX = 1024*1024;
struct MasscanRecord {
@@ -473,29 +478,36 @@ _binaryfile_parse(struct Output *out, const char *filename,
unsigned char *buf = 0;
size_t bytes_read;
uint64_t total_records = 0;
- int x;
/* Allocate a buffer of up to one megabyte per record */
buf = MALLOC(BUF_MAX);
/* Open the file */
- x = fopen_s(&fp, filename, "rb");
- if (x != 0 || fp == NULL) {
- perror(filename);
+ fp = fopen(filename, "rb");
+ if (fp == NULL) {
+ fprintf(stderr, "[-] FAIL: --readscan\n");
+ fprintf(stderr, "[-] %s: %s\n", filename, strerror(errno));
goto end;
}
+ LOG(0, "[+] --readscan %s\n", filename);
+
+ if (feof(fp)) {
+ LOG(0, "[-] %s: file is empty\n", filename);
+ goto end;
+ }
+
/* first record is pseudo-record */
bytes_read = fread(buf, 1, 'a'+2, fp);
if (bytes_read < 'a'+2) {
- perror(filename);
+ LOG(0, "[-] %s: %s\n", filename, strerror(errno));
goto end;
}
/* Make sure it's got the format string */
if (memcmp(buf, "masscan/1.1", 11) != 0) {
- fprintf(stderr,
- "%s: unknown file format (expeced \"masscan/1.1\")\n",
+ LOG(0,
+ "[-] %s: unknown file format (expected \"masscan/1.1\")\n",
filename);
goto end;
}
@@ -557,7 +569,7 @@ _binaryfile_parse(struct Output *out, const char *filename,
length = (length << 7) | (buf[0] & 0x7F);
}
if (length > BUF_MAX) {
- fprintf(stderr, "file corrupt\n");
+ LOG(0, "[-] file corrupt\n");
goto end;
}
@@ -582,7 +594,7 @@ _binaryfile_parse(struct Output *out, const char *filename,
break;
case 4:
if (fread(buf+bytes_read,1,1,fp) != 1) {
- fprintf(stderr, "read() error\n");
+ LOG(0, "[-] read() error\n");
exit(1);
}
bytes_read++;
@@ -617,12 +629,12 @@ _binaryfile_parse(struct Output *out, const char *filename,
//goto end;
break;
default:
- fprintf(stderr, "file corrupt: unknown type %u\n", type);
+ LOG(0, "[-] file corrupt: unknown type %u\n", type);
goto end;
}
total_records++;
if ((total_records & 0xFFFF) == 0)
- fprintf(stderr, "%s: %8" PRIu64 "\r", filename, total_records);
+ LOG(0, "[+] %s: %8" PRIu64 "\r", filename, total_records);
}
end:
@@ -641,15 +653,15 @@ _binaryfile_parse(struct Output *out, const char *filename,
* other formats. This preserves the original timestamps.
*****************************************************************************/
void
-read_binary_scanfile(struct Masscan *masscan,
+readscan_binary_scanfile(struct Masscan *masscan,
int arg_first, int arg_max, char *argv[])
{
struct Output *out;
int i;
- //readscan_report_init();
-
-
+ /*
+ * Create the output system, such as XML or JSON output
+ */
out = output_create(masscan, 0);
/*
@@ -672,10 +684,8 @@ read_binary_scanfile(struct Masscan *masscan,
_binaryfile_parse(out, argv[i], &masscan->targets, &masscan->banner_types);
}
+ /* Done! */
output_destroy(out);
-
- //readscan_report_print();
-
}
diff --git a/src/in-binary.h b/src/in-binary.h
index b8630eb1..f3930af7 100644
--- a/src/in-binary.h
+++ b/src/in-binary.h
@@ -9,7 +9,7 @@ struct Masscan;
* JSON or XML.
*/
void
-read_binary_scanfile(struct Masscan *masscan,
+readscan_binary_scanfile(struct Masscan *masscan,
int arg_first, int arg_max, char *argv[]);
#endif
diff --git a/src/main-conf.c b/src/main-conf.c
index 8053f258..5c53a4a7 100644
--- a/src/main-conf.c
+++ b/src/main-conf.c
@@ -14,8 +14,8 @@
#include "masscan.h"
#include "massip-addr.h"
#include "masscan-version.h"
-#include "string_s.h"
-#include "logger.h"
+#include "util-safefunc.h"
+#include "util-logger.h"
#include "proto-banner1.h"
#include "templ-payloads.h"
#include "crypto-base64.h"
@@ -27,6 +27,7 @@
#include "massip.h"
#include "massip-parse.h"
#include "massip-port.h"
+#include "templ-opts.h"
#include
#include
@@ -66,15 +67,20 @@ static struct Range top_ports_sctp[] = {
void
masscan_usage(void)
{
- printf("usage:\n");
- printf("masscan -p80,8000-8100 10.0.0.0/8 --rate=10000\n");
- printf(" scan some web ports on 10.x.x.x at 10kpps\n");
- printf("masscan --nmap\n");
- printf(" list those options that are compatible with nmap\n");
- printf("masscan -p80 10.0.0.0/8 --banners -oB \n");
- printf(" save results of scan in binary format to \n");
- printf("masscan --open --banners --readscan -oX \n");
- printf(" read binary scan results in and save them as xml in \n");
+ printf("usage: masscan [options] [... -pPORT[,PORT...]]\n");
+ printf("\n");
+ printf("examples:\n");
+ printf(" masscan -p80,8000-8100 10.0.0.0/8 --rate=10000\n");
+ printf(" scan some web ports on 10.x.x.x at 10kpps\n");
+ printf("\n");
+ printf(" masscan --nmap\n");
+ printf(" list those options that are compatible with nmap\n");
+ printf("\n");
+ printf(" masscan -p80 10.0.0.0/8 --banners -oB \n");
+ printf(" save results of scan in binary format to \n");
+ printf("\n");
+ printf(" masscan --open --banners --readscan -oX \n");
+ printf(" read binary scan results in and save them as xml in \n");
exit(1);
}
@@ -94,6 +100,10 @@ print_version()
);
printf("Compiled on: %s %s\n", __DATE__, __TIME__);
+#if defined(__x86_64) || defined(__x86_64__)
+ cpu = "x86";
+#endif
+
#if defined(_MSC_VER)
#if defined(_M_AMD64) || defined(_M_X64)
cpu = "x86";
@@ -122,9 +132,13 @@ print_version()
compiler_version = "post-2013";
}
-
+
#elif defined(__GNUC__)
+# if defined(__clang__)
+ compiler = "clang";
+# else
compiler = "gcc";
+# endif
compiler_version = __VERSION__;
#if defined(i386) || defined(__i386) || defined(__i386__)
@@ -204,6 +218,7 @@ print_nmap_help(void)
" -oL/-oJ/-oD/-oG/-oB/-oX/-oU : Output scan in List/JSON/nDjson/Grepable/Binary/XML/Unicornscan format,\n"
" respectively, to the given filename. Shortcut for\n"
" --output-format --output-file \n"
+" --output-flush: Flushes output per host found (recommended for real-time reading).\n"
" -v: Increase verbosity level (use -vv or more for greater effect)\n"
" -d: Increase debugging level (use -dd or more for greater effect)\n"
" --open: Only show open (or possibly open) ports\n"
@@ -223,46 +238,51 @@ print_nmap_help(void)
"\n");
}
-/***************************************************************************
- ***************************************************************************/
-static unsigned
-count_cidr_bits(struct Range range)
-{
- unsigned i;
-
- for (i=0; i<32; i++) {
- unsigned mask = 0xFFFFFFFF >> i;
-
- if ((range.begin & ~mask) == (range.end & ~mask)) {
- if ((range.begin & mask) == 0 && (range.end & mask) == mask)
- return i;
- }
- }
-
- return 0;
-}
/***************************************************************************
***************************************************************************/
static unsigned
-count_cidr6_bits(struct Range6 range)
+count_cidr6_bits(struct Range6 *range, bool *exact)
{
uint64_t i;
- /* Kludge: can't handle more than 64-bits of CIDR ranges */
- if (range.begin.hi != range.begin.lo)
- return 0;
-
- for (i=0; i<64; i++) {
- uint64_t mask = 0xFFFFFFFFffffffffull >> i;
-
- if ((range.begin.lo & ~mask) == (range.end.lo & ~mask)) {
- if ((range.begin.lo & mask) == 0 && (range.end.lo & mask) == mask)
- return (unsigned)i;
+ /* for the comments of this function, see count_cidr_bits */
+ *exact = false;
+
+ for (i=0; i<128; i++) {
+ uint64_t mask_hi;
+ uint64_t mask_lo;
+ if (i < 64) {
+ mask_hi = 0xFFFFFFFFffffffffull >> i;
+ mask_lo = 0xFFFFFFFFffffffffull;
+ } else {
+ mask_hi = 0;
+ mask_lo = 0xFFFFFFFFffffffffull >> (i - 64);
+ }
+ if ((range->begin.hi & mask_hi) != 0 || (range->begin.lo & mask_lo) != 0) {
+ continue;
+ }
+ if ((range->begin.hi & ~mask_hi) == (range->end.hi & ~mask_hi) &&
+ (range->begin.lo & ~mask_lo) == (range->end.lo & ~mask_lo)) {
+ if (((range->end.hi & mask_hi) == mask_hi) && ((range->end.lo & mask_lo) == mask_lo)) {
+ *exact = true;
+ return (unsigned) i;
+ }
+ } else {
+ *exact = false;
+ range->begin.hi = range->begin.hi + mask_hi;
+ if (range->begin.lo >= 0xffffffffffffffff - 1 - mask_lo) {
+ range->begin.hi += 1;
+ }
+ range->begin.lo = range->begin.lo + mask_lo + 1;
+ return (unsigned) i;
}
}
-
- return 0;
+ range->begin.lo = range->begin.lo + 1;
+ if (range->begin.lo == 0) {
+ range->begin.hi = range->begin.hi + 1;
+ }
+ return 128;
}
@@ -281,7 +301,7 @@ masscan_echo_nic(struct Masscan *masscan, FILE *fp, unsigned i)
if (masscan->nic_count <= 1)
idx_str[0] = '\0';
else
- sprintf_s(idx_str, sizeof(idx_str), "[%u]", i);
+ snprintf(idx_str, sizeof(idx_str), "[%u]", i);
if (masscan->nic[i].ifname[0])
fprintf(fp, "adapter%s = %s\n", idx_str, masscan->nic[i].ifname);
@@ -376,17 +396,16 @@ masscan_save_state(struct Masscan *masscan)
{
char filename[512];
FILE *fp;
- int err;
-
- strcpy_s(filename, sizeof(filename), "paused.conf");
+ safe_strcpy(filename, sizeof(filename), "paused.conf");
fprintf(stderr, " "
" \r");
fprintf(stderr, "saving resume file to: %s\n", filename);
- err = fopen_s(&fp, filename, "wt");
- if (err) {
- perror(filename);
+ fp = fopen(filename, "wt");
+ if (fp == NULL) {
+ fprintf(stderr, "[-] FAIL: saving resume file\n");
+ fprintf(stderr, "[-] %s: %s\n", filename, strerror(errno));
return;
}
@@ -413,11 +432,10 @@ static void
ranges_from_file(struct RangeList *ranges, const char *filename)
{
FILE *fp;
- errno_t err;
unsigned line_number = 0;
- err = fopen_s(&fp, filename, "rt");
- if (err) {
+ fp = fopen(filename, "rt");
+ if (fp) {
perror(filename);
exit(1); /* HARD EXIT: because if it's an exclusion file, we don't
* want to continue. We don't want ANY chance of
@@ -566,6 +584,75 @@ parseInt(const char *str)
return result;
}
+/**
+ * a stricter function for determining if something is boolean.
+ */
+static bool
+isBoolean(const char *str) {
+ size_t length = str?strlen(str):0;
+
+ if (length == 0)
+ return false;
+
+ /* "0" or "1" is boolean */
+ if (isdigit(str[0])) {
+ if (strtoul(str,0,0) == 0)
+ return true;
+ else if (strtoul(str,0,0) == 1)
+ return true;
+ else
+ return false;
+ }
+
+ switch (str[0]) {
+ case 'e':
+ case 'E':
+ if (memcasecmp("enable", str, length)==0)
+ return true;
+ if (memcasecmp("enabled", str, length)==0)
+ return true;
+ return false;
+ case 'd':
+ case 'D':
+ if (memcasecmp("disable", str, length)==0)
+ return true;
+ if (memcasecmp("disabled", str, length)==0)
+ return true;
+ return false;
+
+ case 't':
+ case 'T':
+ if (memcasecmp("true", str, length)==0)
+ return true;
+ return false;
+ case 'f':
+ case 'F':
+ if (memcasecmp("false", str, length)==0)
+ return true;
+ return false;
+
+ case 'o':
+ case 'O':
+ if (memcasecmp("on", str, length)==0)
+ return true;
+ if (memcasecmp("off", str, length)==0)
+ return true;
+ return false;
+ case 'Y':
+ case 'y':
+ if (memcasecmp("yes", str, length)==0)
+ return true;
+ return false;
+ case 'n':
+ case 'N':
+ if (memcasecmp("no", str, length)==0)
+ return true;
+ return false;
+ default:
+ return false;
+ }
+}
+
static unsigned
parseBoolean(const char *str)
{
@@ -578,23 +665,32 @@ parseBoolean(const char *str)
return 1;
}
switch (str[0]) {
- case 't':
+ case 'e': /* enable */
+ case 'E':
+ return 1;
+ case 'd': /* disable */
+ case 'D':
+ return 0;
+
+ case 't': /* true */
case 'T':
return 1;
- case 'f':
+ case 'f': /* false */
case 'F':
return 0;
- case 'o':
+
+ case 'o': /* on or off */
case 'O':
if (str[1] == 'f' || str[1] == 'F')
return 0;
else
return 1;
break;
- case 'Y':
+
+ case 'Y': /* yes */
case 'y':
return 1;
- case 'n':
+ case 'n': /* no */
case 'N':
return 0;
}
@@ -793,32 +889,96 @@ ARRAY(const char *rhs)
return (unsigned)parseInt(p);
}
+/**
+ * Called if user specified `--top-ports` on the command-line.
+ */
static void
-config_top_ports(struct Masscan *masscan, unsigned n)
+config_top_ports(struct Masscan *masscan, unsigned maxports)
{
unsigned i;
+ static const unsigned short top_udp_ports[] = {
+ 161, /* SNMP - should be found on all network equipment */
+ 135, /* MS-RPC - should be found on all modern Windows */
+ 500, /* ISAKMP - for establishing IPsec tunnels */
+ 137, /* NetBIOS-NameService - should be found on old Windows */
+ 138, /* NetBIOS-Datagram - should be found on old Windows */
+ 445, /* SMB datagram service */
+ 67, /* DHCP */
+ 53, /* DNS */
+ 1900, /* UPnP - Microsoft-focused local discovery */
+ 5353, /* mDNS - Apple-focused local discovery */
+ 4500, /* nat-t-ike - IPsec NAT traversal */
+ 514, /* syslog - all Unix machiens */
+ 69, /* TFTP */
+ 49152, /* first of modern ephemeral ports */
+ 631, /* IPP - printing protocol for Linux */
+ 123, /* NTP network time protocol */
+ 1434, /* MS-SQL server*/
+ 520, /* RIP - routers use this protocol sometimes */
+ 7, /* Echo */
+ 111, /* SunRPC portmapper */
+ 2049, /* SunRPC NFS */
+ 5683, /* COAP */
+ 11211, /* memcached */
+ 1701, /* L2TP */
+ 27960, /* quaked amplifier */
+ 1645, /* RADIUS */
+ 1812, /* RADIUS */
+ 1646, /* RADIUS */
+ 1813, /* RADIUS */
+ 3343, /* Microsoft Cluster Services */
+ 2535, /* MADCAP rfc2730 TODO FIXME */
+
+ };
+
static const unsigned short top_tcp_ports[] = {
- 1,3,4,6,7,9,13,17,19,20,21,22,23,24,25,26,30,32,33,37,42,43,49,53,70,
- 79,80,81,82,83,84,85,88,89,90,99,100,106,109,110,111,113,119,125,135,
- 139,143,144,146,161,163,179,199,211,212,222,254,255,256,259,264,280,
- 301,306,311,340,366,389,406,407,416,417,425,427,443,444,445,458,464,
- 465,481,497,500,512,513,514,515,524,541,543,544,545,548,554,555,563,
- 587,593,616,617,625,631,636,646,648,666,667,668,683,687,691,700,705,
+ 80, 443, 8080, /* also web */
+ 21, 990, /* FTP, oldie but goodie */
+ 22, /* SSH, so much infrastructure */
+ 23, 992, /* Telnet, oldie but still around*/
+ 24, /* people put things here instead of TelnetSSH*/
+ 25, 465, 587, 2525, /* SMTP email*/
+ 5800, 5900, 5901, /* VNC */
+ 111, /* SunRPC */
+ 139, 445, /* Microsoft Windows networking */
+ 135, /* DCEPRC, more Microsoft Windows */
+ 3389, /* Microsoft Windows RDP */
+ 88, /* Kerberos, also Microsoft windows */
+ 389, 636, /* LDAP and MS Win */
+ 1433, /* MS SQL */
+ 53, /* DNS */
+ 2083, 2096, /* cPanel */
+ 9050, /* ToR */
+ 8140, /* Puppet */
+ 11211, /* memcached */
+ 1098, 1099, /* Java RMI */
+ 6000, 6001, /* XWindows */
+ 5060, 5061, /* SIP - session initiation protocool */
+ 554, /* RTSP */
+ 548, /* AFP */
+
+
+ 1,3,4,6,7,9,13,17,19,20,26,30,32,33,37,42,43,49,70,
+ 79,81,82,83,84,85,89,90,99,100,106,109,110,113,119,125,
+ 143,144,146,161,163,179,199,211,212,222,254,255,256,259,264,280,
+ 301,306,311,340,366,406,407,416,417,425,427,444,458,464,
+ 465,481,497,500,512,513,514,515,524,541,543,544,545,554,555,563,
+ 593,616,617,625,631,646,648,666,667,668,683,687,691,700,705,
711,714,720,722,726,749,765,777,783,787,800,801,808,843,873,880,888,
- 898,900,901,902,903,911,912,981,987,990,992,993,995,999,1000,1001,
+ 898,900,901,902,903,911,912,981,987,993,995,999,1000,1001,
1002,1007,1009,1010,1011,1021,1022,1023,1024,1025,1026,1027,1028,
1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,
1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,
1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,
1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,
1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,
- 1094,1095,1096,1097,1098,1099,1100,1102,1104,1105,1106,1107,1108,
+ 1094,1095,1096,1097,1100,1102,1104,1105,1106,1107,1108,
1110,1111,1112,1113,1114,1117,1119,1121,1122,1123,1124,1126,1130,
1131,1132,1137,1138,1141,1145,1147,1148,1149,1151,1152,1154,1163,
1164,1165,1166,1169,1174,1175,1183,1185,1186,1187,1192,1198,1199,
1201,1213,1216,1217,1218,1233,1234,1236,1244,1247,1248,1259,1271,
1272,1277,1287,1296,1300,1301,1309,1310,1311,1322,1328,1334,1352,
- 1417,1433,1434,1443,1455,1461,1494,1500,1501,1503,1521,1524,1533,
+ 1417,1434,1443,1455,1461,1494,1500,1501,1503,1521,1524,1533,
1556,1580,1583,1594,1600,1641,1658,1666,1687,1688,1700,1717,1718,
1719,1720,1721,1723,1755,1761,1782,1783,1801,1805,1812,1839,1840,
1862,1863,1864,1875,1900,1914,1935,1947,1971,1972,1974,1984,1998,
@@ -827,7 +987,7 @@ config_top_ports(struct Masscan *masscan, unsigned n)
2046,2047,2048,2049,2065,2068,2099,2100,2103,2105,2106,2107,2111,
2119,2121,2126,2135,2144,2160,2161,2170,2179,2190,2191,2196,2200,
2222,2251,2260,2288,2301,2323,2366,2381,2382,2383,2393,2394,2399,
- 2401,2492,2500,2522,2525,2557,2601,2602,2604,2605,2607,2608,2638,
+ 2401,2492,2500,2522,2557,2601,2602,2604,2605,2607,2608,2638,
2701,2702,2710,2717,2718,2725,2800,2809,2811,2869,2875,2909,2910,
2920,2967,2968,2998,3000,3001,3003,3005,3006,3007,3011,3013,3017,
3030,3031,3052,3071,3077,3128,3168,3211,3221,3260,3261,3268,3269,
@@ -838,13 +998,13 @@ config_top_ports(struct Masscan *masscan, unsigned n)
3995,3998,4000,4001,4002,4003,4004,4005,4006,4045,4111,4125,4126,
4129,4224,4242,4279,4321,4343,4443,4444,4445,4446,4449,4550,4567,
4662,4848,4899,4900,4998,5000,5001,5002,5003,5004,5009,5030,5033,
- 5050,5051,5054,5060,5061,5080,5087,5100,5101,5102,5120,5190,5200,
+ 5050,5051,5054,5080,5087,5100,5101,5102,5120,5190,5200,
5214,5221,5222,5225,5226,5269,5280,5298,5357,5405,5414,5431,5432,
5440,5500,5510,5544,5550,5555,5560,5566,5631,5633,5666,5678,5679,
- 5718,5730,5800,5801,5802,5810,5811,5815,5822,5825,5850,5859,5862,
- 5877,5900,5901,5902,5903,5904,5906,5907,5910,5911,5915,5922,5925,
- 5950,5952,5959,5960,5961,5962,5963,5987,5988,5989,5998,5999,6000,
- 6001,6002,6003,6004,6005,6006,6007,6009,6025,6059,6100,6101,6106,
+ 5718,5730,5801,5802,5810,5811,5815,5822,5825,5850,5859,5862,
+ 5877,5902,5903,5904,5906,5907,5910,5911,5915,5922,5925,
+ 5950,5952,5959,5960,5961,5962,5963,5987,5988,5989,5998,5999,
+ 6002,6003,6004,6005,6006,6007,6009,6025,6059,6100,6101,6106,
6112,6123,6129,6156,6346,6389,6502,6510,6543,6547,6565,6566,6567,
6580,6646,6666,6667,6668,6669,6689,6692,6699,6779,6788,6789,6792,
6839,6881,6901,6969,7000,7001,7002,7004,7007,7019,7025,7070,7100,
@@ -854,7 +1014,7 @@ config_top_ports(struct Masscan *masscan, unsigned n)
8084,8085,8086,8087,8088,8089,8090,8093,8099,8100,8180,8181,8192,
8193,8194,8200,8222,8254,8290,8291,8292,8300,8333,8383,8400,8402,
8443,8500,8600,8649,8651,8652,8654,8701,8800,8873,8888,8899,8994,
- 9000,9001,9002,9003,9009,9010,9011,9040,9050,9071,9080,9081,9090,
+ 9000,9001,9002,9003,9009,9010,9011,9040,9071,9080,9081,9090,
9091,9099,9100,9101,9102,9103,9110,9111,9200,9207,9220,9290,9415,
9418,9485,9500,9502,9503,9535,9575,9593,9594,9595,9618,9666,9876,
9877,9878,9898,9900,9917,9929,9943,9944,9968,9998,9999,10000,10001,
@@ -876,14 +1036,24 @@ config_top_ports(struct Masscan *masscan, unsigned n)
57797,58080,60020,60443,61532,61900,62078,63331,64623,64680,65000,
65129,65389};
struct RangeList *ports = &masscan->targets.ports;
+ static const unsigned max_tcp_ports = sizeof(top_tcp_ports)/sizeof(top_tcp_ports[0]);
+ static const unsigned max_udp_ports = sizeof(top_udp_ports)/sizeof(top_udp_ports[0]);
+
if (masscan->scan_type.tcp) {
- for (i=0; iscan_type.udp) {
- for (i=0; iecho) {
+ if (masscan->is_banners_rawudp || masscan->echo_all)
+ fprintf(masscan->echo, "rawudp = %s\n", masscan->is_banners_rawudp?"true":"false");
+ return 0;
+ }
+ masscan->is_banners_rawudp = parseBoolean(value);
+ if (masscan->is_banners_rawudp)
+ masscan->is_banners = true;
+ return CONF_OK;
+}
+
static int SET_capture(struct Masscan *masscan, const char *name, const char *value)
{
if (masscan->echo) {
@@ -1024,7 +1208,6 @@ static int SET_hello_file(struct Masscan *masscan, const char *name, const char
{
unsigned index;
FILE *fp;
- int x;
char buf[16384];
char buf2[16384];
size_t bytes_read;
@@ -1044,10 +1227,10 @@ static int SET_hello_file(struct Masscan *masscan, const char *name, const char
}
/* When connecting via TCP, send this file */
- x = fopen_s(&fp, value, "rb");
- if (x != 0) {
- LOG(0, "[FAILED] could not read hello file\n");
- perror(value);
+ fp = fopen(value, "rb");
+ if (fp == NULL) {
+ LOG(0, "[-] [FAILED] --hello-file\n");
+ LOG(0, "[-] %s: %s\n", value, strerror(errno));
return CONF_ERR;
}
@@ -1063,7 +1246,7 @@ static int SET_hello_file(struct Masscan *masscan, const char *name, const char
bytes_encoded = base64_encode(buf2, sizeof(buf2)-1, buf, bytes_read);
buf2[bytes_encoded] = '\0';
- sprintf_s(foo, sizeof(foo), "hello-string[%u]", (unsigned)index);
+ snprintf(foo, sizeof(foo), "hello-string[%u]", (unsigned)index);
masscan_set_parameter(masscan, foo, buf2);
@@ -1445,6 +1628,18 @@ static int SET_output_append(struct Masscan *masscan, const char *name, const ch
return CONF_OK;
}
+static int SET_output_flush(struct Masscan *masscan, const char *name, const char *value)
+{
+ UNUSEDPARM(name);
+ if (masscan->echo) {
+ if (masscan->output.is_output_flush || masscan->echo_all)
+ fprintf(masscan->echo, "output-flush = %s\n", masscan->output.is_output_flush?"true":"false");
+ return 0;
+ }
+ masscan->output.is_output_flush = parseBoolean(value);
+ return CONF_OK;
+}
+
static int SET_output_filename(struct Masscan *masscan, const char *name, const char *value)
{
UNUSEDPARM(name);
@@ -1455,7 +1650,7 @@ static int SET_output_filename(struct Masscan *masscan, const char *name, const
}
if (masscan->output.format == 0)
masscan->output.format = Output_XML; /*TODO: Why is the default XML?*/
- strcpy_s(masscan->output.filename,
+ safe_strcpy(masscan->output.filename,
sizeof(masscan->output.filename),
value);
return CONF_OK;
@@ -1625,7 +1820,7 @@ static int SET_pcap_filename(struct Masscan *masscan, const char *name, const ch
return 0;
}
if (value)
- strcpy_s(masscan->pcap_filename, sizeof(masscan->pcap_filename), value);
+ safe_strcpy(masscan->pcap_filename, sizeof(masscan->pcap_filename), value);
return CONF_OK;
}
@@ -1779,7 +1974,7 @@ static int SET_rotate_directory(struct Masscan *masscan, const char *name, const
}
return 0;
}
- strcpy_s( masscan->output.rotate.directory,
+ safe_strcpy( masscan->output.rotate.directory,
sizeof(masscan->output.rotate.directory),
value);
/* strip trailing slashes */
@@ -1906,7 +2101,259 @@ static int SET_output_stylesheet(struct Masscan *masscan, const char *name, cons
if (masscan->output.format == 0)
masscan->output.format = Output_XML;
- strcpy_s(masscan->output.stylesheet, sizeof(masscan->output.stylesheet), value);
+ safe_strcpy(masscan->output.stylesheet, sizeof(masscan->output.stylesheet), value);
+ return CONF_OK;
+}
+
+static int SET_topports(struct Masscan *masscan, const char *name, const char *value)
+{
+ unsigned default_value = 20;
+
+ if (masscan->echo) {
+ /* don't echo: this instead triggers filling the `--port`
+ * list, so the ports themselves will be echoed, not this
+ * parameter */
+ return 0;
+ }
+
+ if (value == 0 || value[0] == '\0') {
+ /* can be specified by itself on the command-line, alone
+ * without a following parameter */
+ /* ex: `--top-ports` */
+ masscan->top_ports = default_value;
+ } else if (isBoolean(value)) {
+ /* ex: `--top-ports enable` */
+ if (parseBoolean(value))
+ masscan->top_ports = default_value;
+ else
+ masscan->top_ports = 0;
+ } else if (isInteger(value)) {
+ /* ex: `--top-ports 5` */
+ uint64_t num = parseInt(value);
+ masscan->top_ports = (unsigned)num;
+ } else {
+ fprintf(stderr, "[-] %s: bad value: %s\n", name, value);
+ return CONF_ERR;
+ }
+ return CONF_OK;
+}
+
+static int SET_tcp_mss(struct Masscan *masscan, const char *name, const char *value)
+{
+ /* h/t @IvreRocks */
+ static const unsigned default_mss = 1460;
+
+ if (masscan->echo) {
+ if (masscan->templ_opts) {
+ switch (masscan->templ_opts->tcp.is_mss) {
+ case Default:
+ break;
+ case Add:
+ if (masscan->templ_opts->tcp.mss == default_mss)
+ fprintf(masscan->echo, "tcp-mss = %s\n", "enable");
+ else
+ fprintf(masscan->echo, "tcp-mss = %u\n",
+ masscan->templ_opts->tcp.mss);
+ break;
+ case Remove:
+ fprintf(masscan->echo, "tcp-mss = %s\n", "disable");
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+ }
+
+ if (masscan->templ_opts == NULL)
+ masscan->templ_opts = calloc(1, sizeof(*masscan->templ_opts));
+
+ if (value == 0 || value[0] == '\0') {
+ /* no following parameter, so interpret this to mean "enable" */
+ masscan->templ_opts->tcp.is_mss = Add;
+ masscan->templ_opts->tcp.mss = default_mss; /* 1460 */
+ } else if (isBoolean(value)) {
+ /* looking for "enable" or "disable", but any boolean works,
+ * like "true/false" or "off/on" */
+ if (parseBoolean(value)) {
+ masscan->templ_opts->tcp.is_mss = Add;
+ masscan->templ_opts->tcp.mss = default_mss; /* 1460 */
+ } else
+ masscan->templ_opts->tcp.is_mss = Remove;
+ } else if (isInteger(value)) {
+ /* A specific number was specified */
+ uint64_t num = parseInt(value);
+ if (num >= 0x10000)
+ goto fail;
+ masscan->templ_opts->tcp.is_mss = Add;
+ masscan->templ_opts->tcp.mss = (unsigned)num;
+ } else
+ goto fail;
+
+ return CONF_OK;
+fail:
+ fprintf(stderr, "[-] %s: bad value: %s\n", name, value);
+ return CONF_ERR;
+}
+
+static int SET_tcp_wscale(struct Masscan *masscan, const char *name, const char *value)
+{
+ static const unsigned default_value = 3;
+
+ if (masscan->echo) {
+ if (masscan->templ_opts) {
+ switch (masscan->templ_opts->tcp.is_wscale) {
+ case Default:
+ break;
+ case Add:
+ if (masscan->templ_opts->tcp.wscale == default_value)
+ fprintf(masscan->echo, "tcp-wscale = %s\n", "enable");
+ else
+ fprintf(masscan->echo, "tcp-wscale = %u\n",
+ masscan->templ_opts->tcp.wscale);
+ break;
+ case Remove:
+ fprintf(masscan->echo, "tcp-wscale = %s\n", "disable");
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+ }
+
+ if (masscan->templ_opts == NULL)
+ masscan->templ_opts = calloc(1, sizeof(*masscan->templ_opts));
+
+ if (value == 0 || value[0] == '\0') {
+ masscan->templ_opts->tcp.is_wscale = Add;
+ masscan->templ_opts->tcp.wscale = default_value;
+ } else if (isBoolean(value)) {
+ if (parseBoolean(value)) {
+ masscan->templ_opts->tcp.is_wscale = Add;
+ masscan->templ_opts->tcp.wscale = default_value;
+ } else
+ masscan->templ_opts->tcp.is_wscale = Remove;
+ } else if (isInteger(value)) {
+ uint64_t num = parseInt(value);
+ if (num >= 255)
+ goto fail;
+ masscan->templ_opts->tcp.is_wscale = Add;
+ masscan->templ_opts->tcp.wscale = (unsigned)num;
+ } else
+ goto fail;
+
+ return CONF_OK;
+fail:
+ fprintf(stderr, "[-] %s: bad value: %s\n", name, value);
+ return CONF_ERR;
+}
+
+static int SET_tcp_tsecho(struct Masscan *masscan, const char *name, const char *value)
+{
+ static const unsigned default_value = 0x12345678;
+
+ if (masscan->echo) {
+ if (masscan->templ_opts) {
+ switch (masscan->templ_opts->tcp.is_tsecho) {
+ case Default:
+ break;
+ case Add:
+ if (masscan->templ_opts->tcp.tsecho == default_value)
+ fprintf(masscan->echo, "tcp-tsecho = %s\n", "enable");
+ else
+ fprintf(masscan->echo, "tcp-tsecho = %u\n",
+ masscan->templ_opts->tcp.tsecho);
+ break;
+ case Remove:
+ fprintf(masscan->echo, "tcp-tsecho = %s\n", "disable");
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+ }
+
+ if (masscan->templ_opts == NULL)
+ masscan->templ_opts = calloc(1, sizeof(*masscan->templ_opts));
+
+ if (value == 0 || value[0] == '\0') {
+ masscan->templ_opts->tcp.is_tsecho = Add;
+ masscan->templ_opts->tcp.tsecho = default_value;
+ } else if (isBoolean(value)) {
+ if (parseBoolean(value)) {
+ masscan->templ_opts->tcp.is_tsecho = Add;
+ masscan->templ_opts->tcp.tsecho = default_value;
+ } else
+ masscan->templ_opts->tcp.is_tsecho = Remove;
+ } else if (isInteger(value)) {
+ uint64_t num = parseInt(value);
+ if (num >= 255)
+ goto fail;
+ masscan->templ_opts->tcp.is_tsecho = Add;
+ masscan->templ_opts->tcp.tsecho = (unsigned)num;
+ } else
+ goto fail;
+
+ return CONF_OK;
+fail:
+ fprintf(stderr, "[-] %s: bad value: %s\n", name, value);
+ return CONF_ERR;
+}
+
+static int SET_tcp_sackok(struct Masscan *masscan, const char *name, const char *value)
+{
+ if (masscan->echo) {
+ if (masscan->templ_opts) {
+ switch (masscan->templ_opts->tcp.is_sackok) {
+ case Default:
+ break;
+ case Add:
+ fprintf(masscan->echo, "tcp-sackok = %s\n", "enable");
+ break;
+ case Remove:
+ fprintf(masscan->echo, "tcp-sackok = %s\n", "disable");
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+ }
+
+ if (masscan->templ_opts == NULL)
+ masscan->templ_opts = calloc(1, sizeof(*masscan->templ_opts));
+
+ if (value == 0 || value[0] == '\0') {
+ masscan->templ_opts->tcp.is_sackok = Add;
+ } else if (isBoolean(value)) {
+ if (parseBoolean(value)) {
+ masscan->templ_opts->tcp.is_sackok = Add;
+ } else
+ masscan->templ_opts->tcp.is_sackok = Remove;
+ } else if (isInteger(value)) {
+ if (parseInt(value) != 0)
+ masscan->templ_opts->tcp.is_sackok = Add;
+ } else
+ goto fail;
+
+ return CONF_OK;
+fail:
+ fprintf(stderr, "[-] %s: bad value: %s\n", name, value);
+ return CONF_ERR;
+}
+
+
+static int SET_debug_tcp(struct Masscan *masscan, const char *name, const char *value) {
+ extern int is_tcp_debug; /* global */
+ UNUSEDPARM(name);
+ UNUSEDPARM(masscan);
+
+ if (value == 0 || value[0] == '\0')
+ is_tcp_debug = 1;
+ else
+ is_tcp_debug = parseBoolean(value);
return CONF_OK;
}
@@ -1918,7 +2365,7 @@ struct ConfigParameter {
unsigned flags;
const char *alts[6];
};
-enum {F_NONE, F_BOOL};
+enum {F_NONE, F_BOOL=1, F_NUMABLE=2};
struct ConfigParameter config_parameters[] = {
{"resume-index", SET_resume_index, 0, {0}},
{"resume-count", SET_resume_count, 0, {0}},
@@ -1927,7 +2374,8 @@ struct ConfigParameter config_parameters[] = {
{"randomize-hosts", SET_randomize_hosts, F_BOOL, {0}},
{"rate", SET_rate, 0, {"max-rate",0}},
{"shard", SET_shard, 0, {"shards",0}},
- {"banners", SET_banners, F_BOOL, {"banner",0}},
+ {"banners", SET_banners, F_BOOL, {"banner",0}}, /* --banners */
+ {"rawudp", SET_banners_rawudp, F_BOOL, {"rawudp",0}}, /* --rawudp */
{"nobanners", SET_nobanners, F_BOOL, {"nobanner",0}},
{"retries", SET_retries, 0, {"retry", "max-retries", "max-retry", 0}},
{"noreset", SET_noreset, F_BOOL, {0}},
@@ -1960,6 +2408,7 @@ struct ConfigParameter config_parameters[] = {
{"output-noshow", SET_output_noshow, 0, {"noshow",0}},
{"output-show-open",SET_output_show_open, F_BOOL, {"open", "open-only", 0}},
{"output-append", SET_output_append, 0, {"append-output",0}},
+ {"output-flush", SET_output_flush, F_BOOL, {"output-flush",0}},
{"rotate", SET_rotate_time, 0, {"output-rotate", "rotate-output", "rotate-time", 0}},
{"rotate-dir", SET_rotate_directory, 0, {"output-rotate-dir", "rotate-directory", 0}},
{"rotate-offset", SET_rotate_offset, 0, {"output-rotate-offset", 0}},
@@ -1967,6 +2416,13 @@ struct ConfigParameter config_parameters[] = {
{"stylesheet", SET_output_stylesheet, 0, {0}},
{"script", SET_script, 0, {0}},
{"SPACE", SET_space, 0, {0}},
+ {"tcp-mss", SET_tcp_mss, F_NUMABLE, {"tcpmss",0}},
+ {"tcp-wscale", SET_tcp_wscale, F_NUMABLE, {0}},
+ {"tcp-tsecho", SET_tcp_tsecho, F_NUMABLE, {0}},
+ {"tcp-sackok", SET_tcp_sackok, F_BOOL, {0}},
+ {"top-ports", SET_topports, F_NUMABLE, {"top-port",0}},
+
+ {"debug-tcp", SET_debug_tcp, F_BOOL, {"tcp-debug", 0}},
{0}
};
@@ -2021,7 +2477,7 @@ masscan_set_parameter(struct Masscan *masscan,
}
if (masscan->nic_count < index + 1)
masscan->nic_count = index + 1;
- sprintf_s( masscan->nic[index].ifname,
+ snprintf( masscan->nic[index].ifname,
sizeof(masscan->nic[index].ifname),
"%s",
value);
@@ -2310,7 +2766,7 @@ masscan_set_parameter(struct Masscan *masscan,
/* The timeout for banners TCP connections */
masscan->tcp_connection_timeout = (unsigned)parseInt(value);
} else if (EQUALS("datadir", name)) {
- strcpy_s(masscan->nmap.datadir, sizeof(masscan->nmap.datadir), value);
+ safe_strcpy(masscan->nmap.datadir, sizeof(masscan->nmap.datadir), value);
} else if (EQUALS("data-length", name)) {
unsigned x = (unsigned)strtoul(value, 0, 0);
if (x >= 1514 - 14 - 40) {
@@ -2330,6 +2786,8 @@ masscan_set_parameter(struct Masscan *masscan,
masscan->op = Operation_Echo;
} else if (EQUALS("echo-all", name)) {
masscan->op = Operation_EchoAll;
+ } else if (EQUALS("echo-cidr", name)) {
+ masscan->op = Operation_EchoCidr;
} else if (EQUALS("excludefile", name)) {
unsigned count1 = masscan->exclude.ipv4.count;
unsigned count2;
@@ -2458,9 +2916,11 @@ masscan_set_parameter(struct Masscan *masscan,
masscan->redis.port = port;
masscan->output.format = Output_Redis;
- strcpy_s(masscan->output.filename,
+ safe_strcpy(masscan->output.filename,
sizeof(masscan->output.filename),
"");
+ } else if(EQUALS("redis-pwd", name)) {
+ masscan->redis.password = strdup(value);
} else if (EQUALS("release-memory", name)) {
fprintf(stderr, "nmap(%s): this is our default option\n", name);
} else if (EQUALS("resume", name)) {
@@ -2578,6 +3038,25 @@ masscan_set_parameter(struct Masscan *masscan,
}
}
+static bool
+is_numable(const char *name) {
+ size_t i;
+
+ for (i=0; config_parameters[i].name; i++) {
+ if (EQUALS(config_parameters[i].name, name)) {
+ return (config_parameters[i].flags & F_NUMABLE) == F_NUMABLE;
+ } else {
+ size_t j;
+ for (j=0; config_parameters[i].alts[j]; j++) {
+ if (EQUALS(config_parameters[i].alts[j], name)) {
+ return (config_parameters[i].flags & F_NUMABLE) == F_NUMABLE;
+ }
+ }
+ }
+ }
+ return false;
+}
+
/***************************************************************************
* Command-line parsing code assumes every --parm is followed by a value.
* This is a list of the parameters that don't follow the default.
@@ -2586,7 +3065,7 @@ static int
is_singleton(const char *name)
{
static const char *singletons[] = {
- "echo", "echo-all", "selftest", "self-test", "regress",
+ "echo", "echo-all", "echo-cidr", "selftest", "self-test", "regress",
"benchmark",
"system-dns", "traceroute", "version",
"version-light",
@@ -2631,32 +3110,43 @@ static void
masscan_help()
{
printf(
+"usage: masscan [options] [... -pPORT[,PORT...]]\n"
"MASSCAN is a fast port scanner. The primary input parameters are the\n"
"IP addresses/ranges you want to scan, and the port numbers. An example\n"
"is the following, which scans the 10.x.x.x network for web servers:\n"
-" masscan 10.0.0.0/8 -p80\n"
+"\n"
+" masscan 10.0.0.0/8 -p80\n"
+"\n"
"The program auto-detects network interface/adapter settings. If this\n"
"fails, you'll have to set these manually. The following is an\n"
"example of all the parameters that are needed:\n"
-" --adapter-ip 192.168.10.123\n"
-" --adapter-mac 00-11-22-33-44-55\n"
-" --router-mac 66-55-44-33-22-11\n"
+"\n"
+" --adapter-ip 192.168.10.123\n"
+" --adapter-mac 00-11-22-33-44-55\n"
+" --router-mac 66-55-44-33-22-11\n"
+"\n"
"Parameters can be set either via the command-line or config-file. The\n"
"names are the same for both. Thus, the above adapter settings would\n"
"appear as follows in a configuration file:\n"
-" adapter-ip = 192.168.10.123\n"
-" adapter-mac = 00-11-22-33-44-55\n"
-" router-mac = 66-55-44-33-22-11\n"
+"\n"
+" adapter-ip = 192.168.10.123\n"
+" adapter-mac = 00-11-22-33-44-55\n"
+" router-mac = 66-55-44-33-22-11\n"
+"\n"
"All single-dash parameters have a spelled out double-dash equivalent,\n"
"so '-p80' is the same as '--ports 80' (or 'ports = 80' in config file).\n"
"To use the config file, type:\n"
-" masscan -c \n"
+"\n"
+" masscan -c \n"
+"\n"
"To generate a config-file from the current settings, use the --echo\n"
"option. This stops the program from actually running, and just echoes\n"
"the current configuration instead. This is a useful way to generate\n"
"your first config file, or see a list of parameters you didn't know\n"
"about. I suggest you try it now:\n"
-" masscan -p1234 --echo\n");
+"\n"
+" masscan -p1234 --echo\n"
+"\n");
exit(1);
}
@@ -2681,17 +3171,16 @@ masscan_load_database_files(struct Masscan *masscan)
}
/*
- * "nmap-payloads"
+ * `--nmap-payloads`
*/
filename = masscan->payloads.nmap_payloads_filename;
if (filename) {
FILE *fp;
- int err;
-
- err = fopen_s(&fp, filename, "rt");
- if (err || fp == NULL) {
- perror(filename);
+ fp = fopen(filename, "rt");
+ if (fp == NULL) {
+ fprintf(stderr, "[-] FAIL: --nmap-payloads\n");
+ fprintf(stderr, "[-] %s:%s\n", filename, strerror(errno));
} else {
if (masscan->payloads.udp == NULL)
masscan->payloads.udp = payloads_udp_create();
@@ -2728,32 +3217,59 @@ masscan_command_line(struct Masscan *masscan, int argc, char *argv[])
/*
* --name=value
* --name:value
- * -- name value
+ * --name value
*/
if (argv[i][0] == '-' && argv[i][1] == '-') {
- if (strcmp(argv[i], "--help") == 0) {
+ const char *argname = argv[i] + 2;
+
+ if (EQUALS("help", argname)) {
masscan_help();
- } else if (EQUALS("top-ports", argv[i]+2)) {
- /* special handling here since the following parameter
- * is optional */
- const char *value = "1000";
- unsigned n;
-
- /* Only consume the next parameter if it's a number,
- * otherwise default to 10000 */
- if (i+1 < argc && isInteger(argv[i+1])) {
- value = argv[++i];
+ exit(1);
+ } else if (is_numable(argname)) {
+ /* May exist by itself like a bool or take an additional
+ * numeric argument */
+ char name2[64];
+ const char *name = argname;
+ unsigned name_length;
+ const char *value;
+
+ /* Look for:
+ * --name=value
+ * --name:value */
+ value = strchr(argname, '=');
+ if (value == NULL)
+ value = strchr(&argv[i][2], ':');
+ if (value) {
+ name_length = (unsigned)(value - name);
+ } else {
+ /* The next parameter contains the name */
+ if (i+1 < argc) {
+ value = argv[i+1];
+ if (isInteger(value) || isBoolean(value))
+ i++;
+ else
+ value = "";
+ } else
+ value = "";
+ name_length = (unsigned)strlen(argname);
}
- n = (unsigned)parseInt(value);
- LOG(2, "top-ports = %u\n", n);
- masscan->top_ports = n;
-
+
+ /* create a copy of the name */
+ if (name_length > sizeof(name2) - 1) {
+ fprintf(stderr, "%.*s: name too long\n", name_length, name);
+ name_length = sizeof(name2) - 1;
+ }
+ memcpy(name2, name, name_length);
+ name2[name_length] = '\0';
+
+ masscan_set_parameter(masscan, name2, value);
} else if (EQUALS("readscan", argv[i]+2)) {
/* Read in a binary file instead of scanning the network*/
masscan->op = Operation_ReadScan;
/* Default to reading banners */
- masscan->is_banners = 1;
+ masscan->is_banners = true;
+ masscan->is_banners_rawudp = true;
/* This option may be followed by many filenames, therefore,
* skip forward in the argument list until the next
@@ -3145,8 +3661,19 @@ masscan_echo(struct Masscan *masscan, FILE *fp, unsigned is_echo_all)
for (i=0; inic_count; i++)
masscan_echo_nic(masscan, fp, i);
}
-
-
+
+ /**
+ * Fix for #737, save adapter-port/source-port value or range
+ */
+ if (masscan->nic[0].src.port.first != 0) {
+ fprintf(fp, "adapter-port = %d", masscan->nic[0].src.port.first);
+ if (masscan->nic[0].src.port.first != masscan->nic[0].src.port.last) {
+ /* --adapter-port - */
+ fprintf(fp, "-%d", masscan->nic[0].src.port.last);
+ }
+ fprintf(fp, "\n");
+ }
+
/*
* Targets
*/
@@ -3194,39 +3721,54 @@ masscan_echo(struct Masscan *masscan, FILE *fp, unsigned is_echo_all)
} while (range.begin <= range.end);
}
fprintf(fp, "\n");
+
+ /*
+ * IPv4 address targets
+ */
for (i=0; itargets.ipv4.count; i++) {
+ unsigned prefix_bits;
struct Range range = masscan->targets.ipv4.list[i];
- fprintf(fp, "range = ");
- fprintf(fp, "%u.%u.%u.%u",
- (range.begin>>24)&0xFF,
- (range.begin>>16)&0xFF,
- (range.begin>> 8)&0xFF,
- (range.begin>> 0)&0xFF
- );
- if (range.begin != range.end) {
- unsigned cidr_bits = count_cidr_bits(range);
-
- if (cidr_bits) {
- fprintf(fp, "/%u", cidr_bits);
- } else
- fprintf(fp, "-%u.%u.%u.%u",
- (range.end>>24)&0xFF,
- (range.end>>16)&0xFF,
- (range.end>> 8)&0xFF,
- (range.end>> 0)&0xFF
- );
+
+ if (range.begin == range.end) {
+ fprintf(fp, "range = %u.%u.%u.%u",
+ (range.begin>>24)&0xFF,
+ (range.begin>>16)&0xFF,
+ (range.begin>> 8)&0xFF,
+ (range.begin>> 0)&0xFF
+ );
+ } else if (range_is_cidr(range, &prefix_bits)) {
+ fprintf(fp, "range = %u.%u.%u.%u/%u",
+ (range.begin>>24)&0xFF,
+ (range.begin>>16)&0xFF,
+ (range.begin>> 8)&0xFF,
+ (range.begin>> 0)&0xFF,
+ prefix_bits
+ );
+
+ } else {
+ fprintf(fp, "range = %u.%u.%u.%u-%u.%u.%u.%u",
+ (range.begin>>24)&0xFF,
+ (range.begin>>16)&0xFF,
+ (range.begin>> 8)&0xFF,
+ (range.begin>> 0)&0xFF,
+ (range.end>>24)&0xFF,
+ (range.end>>16)&0xFF,
+ (range.end>> 8)&0xFF,
+ (range.end>> 0)&0xFF
+ );
}
fprintf(fp, "\n");
}
for (i=0; itargets.ipv6.count; i++) {
+ bool exact = false;
struct Range6 range = masscan->targets.ipv6.list[i];
ipaddress_formatted_t fmt = ipv6address_fmt(range.begin);
fprintf(fp, "range = %s", fmt.string);
if (!ipv6address_is_equal(range.begin, range.end)) {
- unsigned cidr_bits = count_cidr6_bits(range);
+ unsigned cidr_bits = count_cidr6_bits(&range, &exact);
- if (cidr_bits) {
+ if (exact && cidr_bits) {
fprintf(fp, "/%u", cidr_bits);
} else {
fmt = ipv6address_fmt(range.end);
@@ -3234,10 +3776,92 @@ masscan_echo(struct Masscan *masscan, FILE *fp, unsigned is_echo_all)
}
}
fprintf(fp, "\n");
- }
+ }
}
+/***************************************************************************
+ * Prints the list of CIDR to scan to the command-line then exits.
+ * Use: provide this list to other tools. Unlike masscan -sL, it keeps
+ * the CIDR aggretated format, and does not randomize the order of output.
+ * For example, given the starting range of [10.0.0.1-10.0.0.255], this will
+ * print all the CIDR ranges that make this up:
+ * 10.0.0.1/32
+ * 10.0.0.2/31
+ * 10.0.0.4/30
+ * 10.0.0.8/29
+ * 10.0.0.16/28
+ * 10.0.0.32/27
+ * 10.0.0.64/26
+ * 10.0.0.128/25
+ ***************************************************************************/
+void
+masscan_echo_cidr(struct Masscan *masscan, FILE *fp, unsigned is_echo_all)
+{
+ unsigned i;
+ UNUSEDPARM(is_echo_all);
+
+ masscan->echo = fp;
+
+ /*
+ * For all IPv4 ranges ...
+ */
+ for (i=0; itargets.ipv4.count; i++) {
+
+ /* Get the next range in the list */
+ struct Range range = masscan->targets.ipv4.list[i];
+
+ /* If not a single CIDR range, print all the CIDR ranges
+ * needed to completely represent this addres */
+ for (;;) {
+ unsigned prefix_length;
+ struct Range cidr;
+
+ /* Find the largest CIDR range (one that can be specified
+ * with a /prefix) at the start of this range. */
+ cidr = range_first_cidr(range, &prefix_length);
+ fprintf(fp, "%u.%u.%u.%u/%u\n",
+ (cidr.begin>>24)&0xFF,
+ (cidr.begin>>16)&0xFF,
+ (cidr.begin>> 8)&0xFF,
+ (cidr.begin>> 0)&0xFF,
+ prefix_length
+ );
+
+ /* If this is the last range, then stop. There are multiple
+ * ways to gets to see if we get to the end, but I think
+ * this is the best. */
+ if (cidr.end >= range.end)
+ break;
+
+ /* If the CIDR range didn't cover the entire range,
+ * then remove it from the beginning of the range
+ * and process the remainder */
+ range.begin = cidr.end+1;
+ }
+ }
+
+ /*
+ * For all IPv6 ranges...
+ */
+ for (i=0; itargets.ipv6.count; i++) {
+ struct Range6 range = masscan->targets.ipv6.list[i];
+ bool exact = false;
+ while (!exact) {
+ ipaddress_formatted_t fmt = ipv6address_fmt(range.begin);
+ fprintf(fp, "%s", fmt.string);
+ if (range.begin.hi == range.end.hi && range.begin.lo == range.end.lo) {
+ fprintf(fp, "/128");
+ exact = true;
+ } else {
+ unsigned cidr_bits = count_cidr6_bits(&range, &exact);
+ fprintf(fp, "/%u", cidr_bits);
+ }
+ fprintf(fp, "\n");
+ }
+ }
+}
+
/***************************************************************************
* remove leading/trailing whitespace
***************************************************************************/
@@ -3259,14 +3883,16 @@ void
masscan_read_config_file(struct Masscan *masscan, const char *filename)
{
FILE *fp;
- errno_t err;
char line[65536];
- err = fopen_s(&fp, filename, "rt");
- if (err) {
+ fp = fopen(filename, "rt");
+ if (fp == NULL) {
char dir[512];
char *x;
- perror(filename);
+
+ fprintf(stderr, "[-] FAIL: reading configuration file\n");
+ fprintf(stderr, "[-] %s: %s\n", filename, strerror(errno));
+
x = getcwd(dir, sizeof(dir));
if (x)
fprintf(stderr, "[-] cwd = %s\n", dir);
@@ -3322,37 +3948,26 @@ mainconf_selftest()
char test[] = " test 1 ";
trim(test, sizeof(test));
- if (strcmp(test, "test 1") != 0)
- return 1; /* failure */
-
- {
- struct Range range;
-
- range.begin = 16;
- range.end = 32-1;
- if (count_cidr_bits(range) != 28)
- return 1;
-
- range.begin = 1;
- range.end = 13;
- if (count_cidr_bits(range) != 0)
- return 1;
-
-
+ if (strcmp(test, "test 1") != 0) {
+ goto failure;
}
+
/* */
{
int argc = 6;
char *argv[] = { "foo", "bar", "-ddd", "--readscan", "xxx", "--something" };
if (masscan_conf_contains("--nothing", argc, argv))
- return 1;
+ goto failure;
if (!masscan_conf_contains("--readscan", argc, argv))
- return 1;
+ goto failure;
}
return 0;
+failure:
+ fprintf(stderr, "[+] selftest failure: config subsystem\n");
+ return 1;
}
diff --git a/src/main-initadapter.c b/src/main-initadapter.c
index 47dec398..34898fa3 100755
--- a/src/main-initadapter.c
+++ b/src/main-initadapter.c
@@ -1,5 +1,5 @@
#include "masscan.h"
-#include "logger.h"
+#include "util-logger.h"
#include "rawsock.h"
#include "rawsock-adapter.h"
#include "stack-arpv4.h"
@@ -193,7 +193,7 @@ masscan_initialize_adapter(
if (macaddress_is_zero(*router_mac_ipv4)) {
fmt = ipv4address_fmt(masscan->nic[index].router_ip);
LOG(0, "[-] FAIL: ARP timed-out resolving MAC address for router %s: \"%s\"\n", ifname, fmt.string);
- LOG(0, " [hint] try \"--router ip 192.0.2.1\" to specify different router\n");
+ LOG(0, " [hint] try \"--router-ip 192.0.2.1\" to specify different router\n");
LOG(0, " [hint] try \"--router-mac 66-55-44-33-22-11\" instead to bypass ARP\n");
LOG(0, " [hint] try \"--interface eth0\" to change interface\n");
return -1;
diff --git a/src/main-listscan.c b/src/main-listscan.c
index 145a9d05..c4d0470d 100644
--- a/src/main-listscan.c
+++ b/src/main-listscan.c
@@ -1,6 +1,6 @@
#include "masscan.h"
-#include "logger.h"
-#include "rand-blackrock.h"
+#include "util-logger.h"
+#include "crypto-blackrock.h"
void
diff --git a/src/main-ptrace.c b/src/main-ptrace.c
index b14d839e..22eb1299 100644
--- a/src/main-ptrace.c
+++ b/src/main-ptrace.c
@@ -1,7 +1,7 @@
#include "main-ptrace.h"
#include "proto-preprocess.h"
#include "pixie-timer.h"
-#include "string_s.h"
+#include "util-safefunc.h"
/***************************************************************************
@@ -35,10 +35,10 @@ packet_trace(FILE *fp, double pt_start, const unsigned char *px, size_t length,
/* format the IP addresses into fixed-width fields */
fmt = ipaddress_fmt(parsed.src_ip);
- sprintf_s(from, sizeof(from), "[%s]:%u", fmt.string, parsed.port_src);
+ snprintf(from, sizeof(from), "[%s]:%u", fmt.string, parsed.port_src);
fmt = ipaddress_fmt(parsed.dst_ip);
- sprintf_s(to, sizeof(to), "[%s]:%u", fmt.string, parsed.port_dst);
+ snprintf(to, sizeof(to), "[%s]:%u", fmt.string, parsed.port_dst);
switch (parsed.found) {
case FOUND_ARP:
@@ -46,9 +46,9 @@ packet_trace(FILE *fp, double pt_start, const unsigned char *px, size_t length,
*strchr(to, ':') = '\0';
*strchr(from, ':') = '\0';
switch (type) {
- case 1:strcpy_s(sz_type, sizeof(sz_type), "request"); break;
- case 2:strcpy_s(sz_type, sizeof(sz_type), "response"); break;
- default: sprintf_s(sz_type, sizeof(sz_type), "unknown(%u)", type); break;
+ case 1:safe_strcpy(sz_type, sizeof(sz_type), "request"); break;
+ case 2:safe_strcpy(sz_type, sizeof(sz_type), "response"); break;
+ default: snprintf(sz_type, sizeof(sz_type), "unknown(%u)", type); break;
}
fprintf(fp, "%s (%5.4f) ARP %-21s > %-21s %s\n", direction,
timestamp - pt_start, from, to, sz_type);
@@ -65,19 +65,19 @@ packet_trace(FILE *fp, double pt_start, const unsigned char *px, size_t length,
case FOUND_TCP:
type = px[offset+13];
switch (type) {
- case 0x00: strcpy_s(sz_type, sizeof(sz_type), "NULL"); break;
- case 0x01: strcpy_s(sz_type, sizeof(sz_type), "FIN"); break;
- case 0x11: strcpy_s(sz_type, sizeof(sz_type), "FIN-ACK"); break;
- case 0x19: strcpy_s(sz_type, sizeof(sz_type), "FIN-ACK-PSH"); break;
- case 0x02: strcpy_s(sz_type, sizeof(sz_type), "SYN"); break;
- case 0x12: strcpy_s(sz_type, sizeof(sz_type), "SYN-ACK"); break;
- case 0x04: strcpy_s(sz_type, sizeof(sz_type), "RST"); break;
- case 0x14: strcpy_s(sz_type, sizeof(sz_type), "RST-ACK"); break;
- case 0x15: strcpy_s(sz_type, sizeof(sz_type), "RST-FIN-ACK"); break;
- case 0x10: strcpy_s(sz_type, sizeof(sz_type), "ACK"); break;
- case 0x18: strcpy_s(sz_type, sizeof(sz_type), "ACK-PSH"); break;
+ case 0x00: safe_strcpy(sz_type, sizeof(sz_type), "NULL"); break;
+ case 0x01: safe_strcpy(sz_type, sizeof(sz_type), "FIN"); break;
+ case 0x11: safe_strcpy(sz_type, sizeof(sz_type), "FIN-ACK"); break;
+ case 0x19: safe_strcpy(sz_type, sizeof(sz_type), "FIN-ACK-PSH"); break;
+ case 0x02: safe_strcpy(sz_type, sizeof(sz_type), "SYN"); break;
+ case 0x12: safe_strcpy(sz_type, sizeof(sz_type), "SYN-ACK"); break;
+ case 0x04: safe_strcpy(sz_type, sizeof(sz_type), "RST"); break;
+ case 0x14: safe_strcpy(sz_type, sizeof(sz_type), "RST-ACK"); break;
+ case 0x15: safe_strcpy(sz_type, sizeof(sz_type), "RST-FIN-ACK"); break;
+ case 0x10: safe_strcpy(sz_type, sizeof(sz_type), "ACK"); break;
+ case 0x18: safe_strcpy(sz_type, sizeof(sz_type), "ACK-PSH"); break;
default:
- sprintf_s(sz_type, sizeof(sz_type),
+ snprintf(sz_type, sizeof(sz_type),
"%s%s%s%s%s%s%s%s",
(type&0x01)?"FIN":"",
(type&0x02)?"SYN":"",
diff --git a/src/main-readrange.c b/src/main-readrange.c
index c5dbd2ee..43737edf 100644
--- a/src/main-readrange.c
+++ b/src/main-readrange.c
@@ -4,7 +4,7 @@
/***************************************************************************
***************************************************************************/
-static unsigned
+/*static unsigned
count_cidr_bits(struct Range range)
{
unsigned i;
@@ -19,7 +19,7 @@ count_cidr_bits(struct Range range)
}
return 0;
-}
+}*/
/***************************************************************************
***************************************************************************/
@@ -55,28 +55,36 @@ main_readrange(struct Masscan *masscan)
FILE *fp = stdout;
for (i=0; icount; i++) {
+ unsigned prefix_length;
struct Range range = list4->list[i];
- fprintf(fp, "%u.%u.%u.%u",
- (range.begin>>24)&0xFF,
- (range.begin>>16)&0xFF,
- (range.begin>> 8)&0xFF,
- (range.begin>> 0)&0xFF
- );
- if (range.begin != range.end) {
- unsigned cidr_bits = count_cidr_bits(range);
- if (cidr_bits) {
- fprintf(fp, "/%u", cidr_bits);
- } else {
- fprintf(fp, "-%u.%u.%u.%u",
+ if (range.begin == range.end) {
+ fprintf(fp, "%u.%u.%u.%u\n",
+ (range.begin>>24)&0xFF,
+ (range.begin>>16)&0xFF,
+ (range.begin>> 8)&0xFF,
+ (range.begin>> 0)&0xFF
+ );
+ } else if (range_is_cidr(range, &prefix_length)) {
+ fprintf(fp, "%u.%u.%u.%u/%u\n",
+ (range.begin>>24)&0xFF,
+ (range.begin>>16)&0xFF,
+ (range.begin>> 8)&0xFF,
+ (range.begin>> 0)&0xFF,
+ prefix_length
+ );
+ } else {
+ fprintf(fp, "%u.%u.%u.%u-%u.%u.%u.%u\n",
+ (range.begin>>24)&0xFF,
+ (range.begin>>16)&0xFF,
+ (range.begin>> 8)&0xFF,
+ (range.begin>> 0)&0xFF,
(range.end>>24)&0xFF,
(range.end>>16)&0xFF,
(range.end>> 8)&0xFF,
(range.end>> 0)&0xFF
);
- }
}
- fprintf(fp, "\n");
}
for (i=0; icount; i++) {
diff --git a/src/main-status.c b/src/main-status.c
index fe07aaa0..2cd15623 100644
--- a/src/main-status.c
+++ b/src/main-status.c
@@ -12,7 +12,7 @@
#include "pixie-timer.h"
#include "unusedparm.h"
#include "main-globals.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include "util-bool.h"
#include
diff --git a/src/main-throttle.c b/src/main-throttle.c
index e84b8e02..cce132c0 100644
--- a/src/main-throttle.c
+++ b/src/main-throttle.c
@@ -18,7 +18,7 @@
*/
#include "main-throttle.h"
#include "pixie-timer.h"
-#include "logger.h"
+#include "util-logger.h"
#include
#include
diff --git a/src/main.c b/src/main.c
index 3a9e7891..d7ca483d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -18,54 +18,54 @@
#include "masscan.h"
#include "masscan-version.h"
#include "masscan-status.h" /* open or closed */
-#include "rand-blackrock.h" /* the BlackRock shuffling func */
-#include "rand-lcg.h" /* the LCG randomization func */
-#include "templ-pkt.h" /* packet template, that we use to send */
-#include "rawsock.h" /* API on top of Linux, Windows, Mac OS X*/
-#include "logger.h" /* adjust with -v command-line opt */
+#include "massip-parse.h"
+#include "massip-port.h"
#include "main-status.h" /* printf() regular status updates */
#include "main-throttle.h" /* rate limit */
#include "main-dedup.h" /* ignore duplicate responses */
#include "main-ptrace.h" /* for nmap --packet-trace feature */
-#include "proto-arp.h" /* for responding to ARP requests */
+#include "main-globals.h" /* all the global variables in the program */
+#include "main-readrange.h"
+#include "crypto-siphash24.h" /* hash function, for hash tables */
+#include "crypto-blackrock.h" /* the BlackRock shuffling func */
+#include "crypto-lcg.h" /* the LCG randomization func */
+#include "crypto-base64.h" /* base64 encode/decode */
+#include "templ-pkt.h" /* packet template, that we use to send */
+#include "util-logger.h" /* adjust with -v command-line opt */
#include "stack-ndpv6.h" /* IPv6 Neighbor Discovery Protocol */
#include "stack-arpv4.h" /* Handle ARP resolution and requests */
-#include "rawsock-adapter.h"
-#include "proto-banner1.h" /* for snatching banners from systems */
-#include "proto-tcp.h" /* for TCP/IP connection table */
-#include "proto-preprocess.h" /* quick parse of packets */
-#include "proto-icmp.h" /* handle ICMP responses */
-#include "proto-udp.h" /* handle UDP responses */
+#include "rawsock.h" /* API on top of Linux, Windows, Mac OS X*/
+#include "rawsock-adapter.h" /* Get Ethernet adapter configuration */
+#include "rawsock-pcapfile.h" /* for saving pcap files w/ raw packets */
#include "syn-cookie.h" /* for SYN-cookies on send */
#include "output.h" /* for outputting results */
#include "rte-ring.h" /* producer/consumer ring buffer */
-#include "rawsock-pcapfile.h" /* for saving pcap files w/ raw packets */
#include "stub-pcap.h" /* dynamically load libpcap library */
#include "smack.h" /* Aho-corasick state-machine pattern-matcher */
#include "pixie-timer.h" /* portable time functions */
#include "pixie-threads.h" /* portable threads */
+#include "pixie-backtrace.h" /* maybe print backtrace on crash */
#include "templ-payloads.h" /* UDP packet payloads */
+#include "in-binary.h" /* convert binary output to XML/JSON */
+#include "vulncheck.h" /* checking vulns like monlist, poodle, heartblee */
+#include "scripting.h"
+#include "read-service-probes.h"
+#include "misc-rstfilter.h"
+#include "proto-x509.h"
+#include "proto-arp.h" /* for responding to ARP requests */
+#include "proto-banner1.h" /* for snatching banners from systems */
+#include "stack-tcp-core.h" /* for TCP/IP connection table */
+#include "proto-preprocess.h" /* quick parse of packets */
+#include "proto-icmp.h" /* handle ICMP responses */
+#include "proto-udp.h" /* handle UDP responses */
#include "proto-snmp.h" /* parse SNMP responses */
#include "proto-ntp.h" /* parse NTP responses */
#include "proto-coap.h" /* CoAP selftest */
-#include "in-binary.h" /* convert binary output to XML/JSON */
-#include "main-globals.h" /* all the global variables in the program */
#include "proto-zeroaccess.h"
-#include "siphash24.h"
-#include "proto-x509.h"
-#include "crypto-base64.h" /* base64 encode/decode */
-#include "pixie-backtrace.h"
#include "proto-sctp.h"
#include "proto-oproto.h" /* Other protocols on top of IP */
-#include "vulncheck.h" /* checking vulns like monlist, poodle, heartblee */
-#include "main-readrange.h"
-#include "scripting.h"
-#include "read-service-probes.h"
-#include "misc-rstfilter.h"
#include "util-malloc.h"
#include "util-checksum.h"
-#include "massip-parse.h"
-#include "massip-port.h"
#include
#include
@@ -158,7 +158,14 @@ struct ThreadPair {
size_t thread_handle_recv;
};
-
+struct source_t {
+ unsigned ipv4;
+ unsigned ipv4_mask;
+ unsigned port;
+ unsigned port_mask;
+ ipv6address ipv6;
+ ipv6address ipv6_mask;
+};
/***************************************************************************
* We support a range of source IP/port. This function converts that
@@ -167,29 +174,25 @@ struct ThreadPair {
static void
adapter_get_source_addresses(const struct Masscan *masscan,
unsigned nic_index,
- unsigned *src_ipv4,
- unsigned *src_ipv4_mask,
- unsigned *src_port,
- unsigned *src_port_mask,
- ipv6address *src_ipv6,
- ipv6address *src_ipv6_mask)
+ struct source_t *src)
{
- const struct stack_src_t *src = &masscan->nic[nic_index].src;
+ const struct stack_src_t *ifsrc = &masscan->nic[nic_index].src;
static ipv6address mask = {~0ULL, ~0ULL};
- *src_ipv4 = src->ipv4.first;
- *src_ipv4_mask = src->ipv4.last - src->ipv4.first;
+ src->ipv4 = ifsrc->ipv4.first;
+ src->ipv4_mask = ifsrc->ipv4.last - ifsrc->ipv4.first;
- *src_port = src->port.first;
- *src_port_mask = src->port.last - src->port.first;
+ src->port = ifsrc->port.first;
+ src->port_mask = ifsrc->port.last - ifsrc->port.first;
- *src_ipv6 = src->ipv6.first;
+ src->ipv6 = ifsrc->ipv6.first;
/* TODO: currently supports only a single address. This needs to
* be fixed to support a list of addresses */
- *src_ipv6_mask = mask;
+ src->ipv6_mask = mask;
}
+
/***************************************************************************
* This thread spews packets as fast as it can
*
@@ -217,18 +220,15 @@ transmit_thread(void *v) /*aka. scanning_thread() */
struct TemplateSet pkt_template = templ_copy(parms->tmplset);
struct Adapter *adapter = parms->adapter;
uint64_t packets_sent = 0;
- unsigned increment = (masscan->shard.of-1) + masscan->nic_count;
- unsigned src_ipv4;
- unsigned src_ipv4_mask;
- unsigned src_port;
- unsigned src_port_mask;
- ipv6address src_ipv6;
- ipv6address src_ipv6_mask;
+ unsigned increment = masscan->shard.of * masscan->nic_count;
+ struct source_t src;
uint64_t seed = masscan->seed;
uint64_t repeats = 0; /* --infinite repeats */
uint64_t *status_syn_count;
uint64_t entropy = masscan->seed;
+ /* Wait to make sure receive_thread is ready */
+ pixie_usleep(1000000);
LOG(1, "[+] starting transmit thread #%u\n", parms->nic_index);
/* export a pointer to this variable outside this threads so
@@ -241,10 +241,7 @@ transmit_thread(void *v) /*aka. scanning_thread() */
/* Normally, we have just one source address. In special cases, though
* we can have multiple. */
- adapter_get_source_addresses(masscan, parms->nic_index,
- &src_ipv4, &src_ipv4_mask,
- &src_port, &src_port_mask,
- &src_ipv6, &src_ipv6_mask);
+ adapter_get_source_addresses(masscan, parms->nic_index, &src);
/* "THROTTLER" rate-limits how fast we transmit, set with the
@@ -269,7 +266,7 @@ transmit_thread(void *v) /*aka. scanning_thread() */
* a little bit past the end when we have --retries. Yet another
* thing to do here is deal with multiple network adapters, which
* is essentially the same logic as shards. */
- start = masscan->resume.index + (masscan->shard.one-1) + parms->nic_index;
+ start = masscan->resume.index + (masscan->shard.one-1) * masscan->nic_count + parms->nic_index;
end = range;
if (masscan->resume.count && end > start + masscan->resume.count)
end = start + masscan->resume.count;
@@ -345,8 +342,8 @@ transmit_thread(void *v) /*aka. scanning_thread() */
ip_them = range6list_pick(&masscan->targets.ipv6, xXx % count_ipv6);
port_them = rangelist_pick(&masscan->targets.ports, xXx / count_ipv6);
- ip_me = src_ipv6;
- port_me = src_port;
+ ip_me = src.ipv6;
+ port_me = src.port;
cookie = syn_cookie_ipv6(ip_them, port_them, ip_me, port_me, entropy);
@@ -378,16 +375,16 @@ transmit_thread(void *v) /*aka. scanning_thread() */
* SYN-COOKIE LOGIC
* Figure out the source IP/port, and the SYN cookie
*/
- if (src_ipv4_mask > 1 || src_port_mask > 1) {
+ if (src.ipv4_mask != 0 || src.port_mask != 0) {
uint64_t ck = syn_cookie_ipv4((unsigned)(i+repeats),
(unsigned)((i+repeats)>>32),
(unsigned)xXx, (unsigned)(xXx>>32),
entropy);
- port_me = src_port + (ck & src_port_mask);
- ip_me = src_ipv4 + ((ck>>16) & src_ipv4_mask);
+ port_me = src.port + (ck & src.port_mask);
+ ip_me = src.ipv4 + ((ck>>16) & src.ipv4_mask);
} else {
- ip_me = src_ipv4;
- port_me = src_port;
+ ip_me = src.ipv4;
+ port_me = src.port;
}
cookie = syn_cookie_ipv4(ip_them, port_them, ip_me, port_me, entropy);
@@ -548,6 +545,7 @@ receive_thread(void *v)
uint64_t entropy = masscan->seed;
struct ResetFilter *rf;
struct stack_t *stack = parms->stack;
+ struct source_t src = {0};
@@ -625,8 +623,14 @@ receive_thread(void *v)
* Initialize TCP scripting
*/
scripting_init_tcp(tcpcon, masscan->scripting.L);
-
-
+
+ /*
+ * Get the possible source IP addresses and ports that masscan
+ * might be using to transmit from.
+ */
+ adapter_get_source_addresses(masscan, parms->nic_index, &src);
+
+
/*
* Set some flags [kludge]
*/
@@ -683,7 +687,7 @@ receive_thread(void *v)
if (masscan->tcp_connection_timeout) {
char foo[64];
- sprintf_s(foo, sizeof(foo), "%u", masscan->tcp_connection_timeout);
+ snprintf(foo, sizeof(foo), "%u", masscan->tcp_connection_timeout);
tcpcon_set_parameter( tcpcon,
"timeout",
strlen(foo),
@@ -691,7 +695,7 @@ receive_thread(void *v)
}
if (masscan->tcp_hello_timeout) {
char foo[64];
- sprintf_s(foo, sizeof(foo), "%u", masscan->tcp_hello_timeout);
+ snprintf(foo, sizeof(foo), "%u", masscan->tcp_hello_timeout);
tcpcon_set_parameter( tcpcon,
"hello-timeout",
strlen(foo),
@@ -722,7 +726,7 @@ receive_thread(void *v)
for (pay = masscan->payloads.tcp; pay; pay = pay->next) {
char name[64];
- sprintf_s(name, sizeof(name), "hello-string[%u]", pay->port);
+ snprintf(name, sizeof(name), "hello-string[%u]", pay->port);
tcpcon_set_parameter( tcpcon,
name,
strlen(pay->payload_base64),
@@ -959,7 +963,7 @@ receive_thread(void *v)
struct TCP_Control_Block *tcb;
/* does a TCB already exist for this connection? */
- tcb = tcb_lookup(tcpcon,
+ tcb = tcpcon_lookup_tcb(tcpcon,
ip_me, ip_them,
port_me, port_them);
@@ -970,32 +974,30 @@ receive_thread(void *v)
fmt.string, seqno_me-1, cookie);
continue;
}
-
if (tcb == NULL) {
tcb = tcpcon_create_tcb(tcpcon,
ip_me, ip_them,
port_me, port_them,
seqno_me, seqno_them+1,
- parsed.ip_ttl);
+ parsed.ip_ttl, NULL,
+ secs, usecs);
(*status_tcb_count)++;
-
}
-
Q += stack_incoming_tcp(tcpcon, tcb, TCP_WHAT_SYNACK,
- 0, 0, secs, usecs, seqno_them+1);
+ 0, 0, secs, usecs, seqno_them+1, seqno_me);
} else if (tcb) {
/* If this is an ACK, then handle that first */
if (TCP_IS_ACK(px, parsed.transport_offset)) {
Q += stack_incoming_tcp(tcpcon, tcb, TCP_WHAT_ACK,
- 0, seqno_me, secs, usecs, seqno_them);
+ 0, 0, secs, usecs, seqno_them, seqno_me);
}
/* If this contains payload, handle that second */
if (parsed.app_length) {
Q += stack_incoming_tcp(tcpcon, tcb, TCP_WHAT_DATA,
px + parsed.app_offset, parsed.app_length,
- secs, usecs, seqno_them);
+ secs, usecs, seqno_them, seqno_me);
}
/* If this is a FIN, handle that. Note that ACK +
@@ -1003,13 +1005,16 @@ receive_thread(void *v)
if (TCP_IS_FIN(px, parsed.transport_offset)
&& !TCP_IS_RST(px, parsed.transport_offset)) {
Q += stack_incoming_tcp(tcpcon, tcb, TCP_WHAT_FIN,
- 0, parsed.app_length, secs, usecs, seqno_them);
+ 0, 0,
+ secs, usecs,
+ seqno_them + parsed.app_length, /* the FIN comes after any data in the packet */
+ seqno_me);
}
/* If this is a RST, then we'll be closing the connection */
if (TCP_IS_RST(px, parsed.transport_offset)) {
Q += stack_incoming_tcp(tcpcon, tcb, TCP_WHAT_RST,
- 0, 0, secs, usecs, seqno_them);
+ 0, 0, secs, usecs, seqno_them, seqno_me);
}
} else if (TCP_IS_FIN(px, parsed.transport_offset)) {
ipaddress_formatted_t fmt;
@@ -1042,7 +1047,6 @@ receive_thread(void *v)
if (TCP_IS_SYNACK(px, parsed.transport_offset)
|| TCP_IS_RST(px, parsed.transport_offset)) {
-
/* figure out the status */
status = PortStatus_Unknown;
if (TCP_IS_SYNACK(px, parsed.transport_offset))
@@ -1054,7 +1058,7 @@ receive_thread(void *v)
/* verify: syn-cookies */
if (cookie != seqno_me - 1) {
ipaddress_formatted_t fmt = ipaddress_fmt(ip_them);
- LOG(5, "%s - bad cookie: ackno=0x%08x expected=0x%08x\n",
+ LOG(2, "%s - bad cookie: ackno=0x%08x expected=0x%08x\n",
fmt.string, seqno_me-1, cookie);
continue;
}
@@ -1302,7 +1306,8 @@ main_scan(struct Masscan *masscan)
masscan->payloads.udp,
masscan->payloads.oproto,
stack_if_datalink(masscan->nic[index].adapter),
- masscan->seed);
+ masscan->seed,
+ masscan->templ_opts);
/*
* Set the "source port" of everything we transmit.
@@ -1310,8 +1315,8 @@ main_scan(struct Masscan *masscan)
if (masscan->nic[index].src.port.range == 0) {
unsigned port = 40000 + now % 20000;
masscan->nic[index].src.port.first = port;
- masscan->nic[index].src.port.last = port;
- masscan->nic[index].src.port.range = 1;
+ masscan->nic[index].src.port.last = port + 16;
+ masscan->nic[index].src.port.range = 16;
}
stack = stack_create(parms->source_mac, &masscan->nic[index].src);
@@ -1342,7 +1347,7 @@ main_scan(struct Masscan *masscan)
struct tm x;
now = time(0);
- gmtime_s(&x, &now);
+ safe_gmtime(&x, &now);
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S GMT", &x);
LOG(0, "Starting masscan " MASSCAN_VERSION " (http://bit.ly/14GZzcT) at %s\n",
buffer);
@@ -1596,9 +1601,10 @@ int main(int argc, char *argv[])
masscan->shard.one = 1;
masscan->shard.of = 1;
masscan->min_packet_size = 60;
+ masscan->redis.password = NULL;
masscan->payloads.udp = payloads_udp_create();
masscan->payloads.oproto = payloads_oproto_create();
- strcpy_s( masscan->output.rotate.directory,
+ safe_strcpy( masscan->output.rotate.directory,
sizeof(masscan->output.rotate.directory),
".");
masscan->is_capture_cert = 1;
@@ -1776,7 +1782,7 @@ int main(int argc, char *argv[])
* read the binary files, and output them again depending upon
* the output parameters
*/
- read_binary_scanfile(masscan, start, stop, argv);
+ readscan_binary_scanfile(masscan, start, stop, argv);
}
break;
@@ -1799,16 +1805,24 @@ int main(int argc, char *argv[])
exit(0);
break;
+ case Operation_EchoCidr:
+ masscan_echo_cidr(masscan, stdout, 0);
+ exit(0);
+ break;
+
case Operation_Selftest:
/*
* Do a regression test of all the significant units
*/
{
int x = 0;
+ extern int proto_isakmp_selftest(void);
+
x += massip_selftest();
x += ranges6_selftest();
x += dedup_selftest();
x += checksum_selftest();
+ x += ipv4address_selftest();
x += ipv6address_selftest();
x += proto_coap_selftest();
x += smack_selftest();
@@ -1819,7 +1833,8 @@ int main(int argc, char *argv[])
x += siphash24_selftest();
x += ntp_selftest();
x += snmp_selftest();
- x += payloads_udp_selftest();
+ x += proto_isakmp_selftest();
+ x += templ_payloads_selftest();
x += blackrock_selftest();
x += rawsock_selftest();
x += lcg_selftest();
@@ -1832,6 +1847,8 @@ int main(int argc, char *argv[])
x += zeroaccess_selftest();
x += nmapserviceprobes_selftest();
x += rstfilter_selftest();
+ x += masscan_app_selftest();
+ x += icmp_selftest();
if (x != 0) {
diff --git a/src/masscan-app.c b/src/masscan-app.c
index 7d326078..903015fb 100644
--- a/src/masscan-app.c
+++ b/src/masscan-app.c
@@ -1,5 +1,5 @@
#include "masscan-app.h"
-#include "string_s.h"
+#include "util-safefunc.h"
/******************************************************************************
* When outputting results, we call this function to print out the type of
@@ -27,13 +27,14 @@ masscan_app_to_string(enum ApplicationProtocol proto)
case PROTO_IMAP4: return "imap";
case PROTO_UDP_ZEROACCESS: return "zeroaccess";
case PROTO_X509_CERT: return "X509";
+ case PROTO_X509_CACERT: return "X509CA";
case PROTO_HTML_TITLE: return "title";
case PROTO_HTML_FULL: return "html";
case PROTO_NTP: return "ntp";
case PROTO_VULN: return "vuln";
case PROTO_HEARTBLEED: return "heartbleed";
case PROTO_TICKETBLEED: return "ticketbleed";
- case PROTO_VNC_RFB: return "vnc";
+ case PROTO_VNC_OLD: return "vnc";
case PROTO_SAFE: return "safe";
case PROTO_MEMCACHED: return "memcached";
case PROTO_SCRIPTING: return "scripting";
@@ -42,9 +43,15 @@ masscan_app_to_string(enum ApplicationProtocol proto)
case PROTO_TELNET: return "telnet";
case PROTO_RDP: return "rdp";
case PROTO_HTTP_SERVER: return "http.server";
+ case PROTO_MC: return "minecraft";
+ case PROTO_VNC_RFB: return "vnc";
+ case PROTO_VNC_INFO: return "vnc-info";
+ case PROTO_ISAKMP: return "isakmp";
+
+ case PROTO_ERROR: return "error";
default:
- sprintf_s(tmp, sizeof(tmp), "(%u)", proto);
+ snprintf(tmp, sizeof(tmp), "(%u)", proto);
return tmp;
}
}
@@ -65,7 +72,6 @@ masscan_string_to_app(const char *str)
{"ftp", PROTO_FTP},
{"dns-ver", PROTO_DNS_VERSIONBIND},
{"snmp", PROTO_SNMP},
- {"ssh2", PROTO_SSH2},
{"nbtstat", PROTO_NBTSTAT},
{"ssl", PROTO_SSL3},
{"smtp", PROTO_SMTP},
@@ -73,6 +79,7 @@ masscan_string_to_app(const char *str)
{"pop", PROTO_POP3},
{"imap", PROTO_IMAP4},
{"x509", PROTO_X509_CERT},
+ {"x509ca", PROTO_X509_CACERT},
{"zeroaccess", PROTO_UDP_ZEROACCESS},
{"title", PROTO_HTML_TITLE},
{"html", PROTO_HTML_FULL},
@@ -80,7 +87,7 @@ masscan_string_to_app(const char *str)
{"vuln", PROTO_VULN},
{"heartbleed", PROTO_HEARTBLEED},
{"ticketbleed", PROTO_TICKETBLEED},
- {"vnc", PROTO_VNC_RFB},
+ {"vnc-old", PROTO_VNC_OLD},
{"safe", PROTO_SAFE},
{"memcached", PROTO_MEMCACHED},
{"scripting", PROTO_SCRIPTING},
@@ -89,13 +96,50 @@ masscan_string_to_app(const char *str)
{"telnet", PROTO_TELNET},
{"rdp", PROTO_RDP},
{"http.server", PROTO_HTTP_SERVER},
+ {"minecraft", PROTO_MC},
+ {"vnc", PROTO_VNC_RFB},
+ {"vnc-info", PROTO_VNC_INFO},
+ {"isakmp", PROTO_ISAKMP},
{0,0}
};
size_t i;
-
+
for (i=0; list[i].name; i++) {
if (strcmp(str, list[i].name) == 0)
return list[i].value;
}
return 0;
}
+
+int
+masscan_app_selftest(void) {
+ static const struct {
+ unsigned enumid;
+ unsigned expected;
+ } tests[] = {
+ {PROTO_SNMP, 7},
+ {PROTO_X509_CERT, 15},
+ {PROTO_HTTP_SERVER, 31},
+ {0,0}
+ };
+ size_t i;
+
+ /* The ENUM contains fixed values in external files,
+ * so programmers should only add onto its end, not
+ * the middle. This self-test will verify that
+ * a programmer hasn't made this mistake.
+ */
+ for (i=0; tests[i].enumid != 0; i++) {
+ unsigned enumid = tests[i].enumid;
+ unsigned expected = tests[i].expected;
+
+ /* YOU ADDED AN ENUM IN THE MIDDLE INSTEAD ON THE END OF THE LIST */
+ if (enumid != expected) {
+ fprintf(stderr, "[-] %s:%u fail\n", __FILE__, (unsigned)__LINE__);
+ fprintf(stderr, "[-] enum expected=%u, found=%u\n", 30, PROTO_HTTP_SERVER);
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/masscan-app.h b/src/masscan-app.h
index fb4a4415..56871419 100644
--- a/src/masscan-app.h
+++ b/src/masscan-app.h
@@ -13,31 +13,38 @@ enum ApplicationProtocol {
PROTO_HTTP,
PROTO_FTP,
PROTO_DNS_VERSIONBIND,
- PROTO_SNMP, /* simple network management protocol, udp/161 */
- PROTO_NBTSTAT, /* netbios, udp/137 */
+ PROTO_SNMP, /* 7 - simple network management protocol, udp/161 */
+ PROTO_NBTSTAT, /* 8 - netbios, udp/137 */
PROTO_SSL3,
- PROTO_SMB, /* SMB tcp/139 and tcp/445 */
- PROTO_SMTP,
- PROTO_POP3,
- PROTO_IMAP4,
+ PROTO_SMB, /* 10 - SMB tcp/139 and tcp/445 */
+ PROTO_SMTP, /* 11 - transfering email */
+ PROTO_POP3, /* 12 - fetching email */
+ PROTO_IMAP4, /* 13 - fetching email */
PROTO_UDP_ZEROACCESS,
- PROTO_X509_CERT,
+ PROTO_X509_CERT, /* 15 - just the cert */
+ PROTO_X509_CACERT,
PROTO_HTML_TITLE,
PROTO_HTML_FULL,
- PROTO_NTP, /* network time protocol, udp/123 */
+ PROTO_NTP, /* 19 - network time protocol, udp/123 */
PROTO_VULN,
PROTO_HEARTBLEED,
PROTO_TICKETBLEED,
- PROTO_VNC_RFB,
+ PROTO_VNC_OLD,
PROTO_SAFE,
- PROTO_MEMCACHED,
+ PROTO_MEMCACHED, /* 25 - memcached */
PROTO_SCRIPTING,
PROTO_VERSIONING,
- PROTO_COAP, /* constrained app proto, udp/5683, RFC7252 */
- PROTO_TELNET,
- PROTO_RDP, /* Microsoft Remote Desktop Protocol tcp/3389 */
- PROTO_HTTP_SERVER, /* HTTP "Server:" field */
+ PROTO_COAP, /* 28 - constrained app proto, udp/5683, RFC7252 */
+ PROTO_TELNET, /* 29 - ye old remote terminal */
+ PROTO_RDP, /* 30 - Microsoft Remote Desktop Protocol tcp/3389 */
+ PROTO_HTTP_SERVER, /* 31 - HTTP "Server:" field */
+ PROTO_MC, /* 32 - Minecraft server */
+ PROTO_VNC_RFB,
+ PROTO_VNC_INFO,
+ PROTO_ISAKMP, /* 35 - IPsec key exchange */
+ PROTO_ERROR,
+
PROTO_end_of_list /* must be last one */
};
@@ -47,4 +54,7 @@ masscan_app_to_string(enum ApplicationProtocol proto);
enum ApplicationProtocol
masscan_string_to_app(const char *str);
+int
+masscan_app_selftest(void);
+
#endif
diff --git a/src/masscan-version.h b/src/masscan-version.h
index 74d3d0f3..24f902ac 100644
--- a/src/masscan-version.h
+++ b/src/masscan-version.h
@@ -1,6 +1,6 @@
#ifndef MASSCAN_VERSION
-#define MASSCAN_VERSION "1.3.2"
+#define MASSCAN_VERSION "1.3.9-integration"
#endif
diff --git a/src/masscan.h b/src/masscan.h
index 369dcc14..ca43cf34 100644
--- a/src/masscan.h
+++ b/src/masscan.h
@@ -1,7 +1,7 @@
#ifndef MASSCAN_H
#define MASSCAN_H
#include "massip-addr.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include "stack-src.h"
#include "massip.h"
#include "util-bool.h"
@@ -16,6 +16,7 @@
struct Adapter;
struct TemplateSet;
struct Banner1;
+struct TemplateOptions;
/**
* This is the "operation" to be performed by masscan, which is almost always
@@ -36,6 +37,7 @@ enum Operation {
Operation_Benchmark = 8, /* --benchmark */
Operation_Echo = 9, /* --echo */
Operation_EchoAll = 10, /* --echo-all */
+ Operation_EchoCidr = 11, /* --echo-cidr */
};
/**
@@ -111,7 +113,9 @@ struct Masscan
} scan_type;
/**
- * After scan type has been configured, add these ports
+ * After scan type has been configured, add these ports. In other words,
+ * the user may specify `-sU` or `-sT` after the `--top-ports` parameter,
+ * so we have to wait until after parsing arguments to fill in the ports.
*/
unsigned top_ports;
@@ -183,6 +187,7 @@ struct Masscan
unsigned is_pfring:1; /* --pfring */
unsigned is_sendq:1; /* --sendq */
unsigned is_banners:1; /* --banners */
+ unsigned is_banners_rawudp:1; /* --rawudp */
unsigned is_offline:1; /* --offline */
unsigned is_noreset:1; /* --noreset, don't transmit RST */
unsigned is_gmt:1; /* --gmt, all times in GMT */
@@ -201,7 +206,11 @@ struct Masscan
unsigned is_hello_http:1; /* --hello=http, use HTTP on all ports */
unsigned is_scripting:1; /* whether scripting is needed */
unsigned is_capture_servername:1; /* --capture servername */
-
+
+ /** Packet template options, such as whether we should add a TCP MSS
+ * value, or remove it from the packet */
+ struct TemplateOptions *templ_opts; /* e.g. --tcpmss */
+
/**
* Wait forever for responses, instead of the default 10 seconds
*/
@@ -272,7 +281,7 @@ struct Masscan
* rather than to a file.
*/
char filename[256];
-
+
/**
* A feature of the XML output where we can insert an optional
* stylesheet into the file for better rendering on web browsers
@@ -335,6 +344,12 @@ struct Masscan
*/
unsigned is_status_updates:1;
+ /**
+ * --output-flush
+ * Flush the file with every host/banner found
+ */
+ unsigned is_output_flush:1;
+
struct {
/**
* When we should rotate output into the target directory
@@ -448,6 +463,7 @@ struct Masscan
struct {
ipaddress ip;
+ char *password;
unsigned port;
} redis;
@@ -535,4 +551,10 @@ masscan_initialize_adapter(
void
masscan_echo(struct Masscan *masscan, FILE *fp, unsigned is_echo_all);
+/**
+ * Echoes the list of CIDR ranges to scan.
+ */
+void
+masscan_echo_cidr(struct Masscan *masscan, FILE *fp, unsigned is_echo_all);
+
#endif
diff --git a/src/massip-addr.c b/src/massip-addr.c
index c90cb297..dcc491f0 100644
--- a/src/massip-addr.c
+++ b/src/massip-addr.c
@@ -227,6 +227,13 @@ static unsigned _count_long(uint64_t number)
return count;
}
+/**
+ * Find the number of bits needed to hold the integer. In other words,
+ * the number 0x64 would need 7 bits to store it.
+ *
+ * We use this to count the size of scans. We currently only support
+ * scan sizes up to 63 bits.
+ */
unsigned massint128_bitcount(massint128_t number)
{
if (number.hi)
@@ -235,7 +242,69 @@ unsigned massint128_bitcount(massint128_t number)
return _count_long(number.lo);
}
+ipv6address_t ipv6address_add_uint64(ipv6address_t lhs, uint64_t rhs) {
+ lhs.lo += rhs;
+ if (lhs.lo < rhs) {
+ lhs.hi += 1;
+ }
+ return lhs;
+}
+
+ipv6address_t ipv6address_subtract(ipv6address_t lhs, ipv6address_t rhs) {
+ ipv6address_t difference;
+ difference.hi = lhs.hi - rhs.hi;
+ difference.lo = lhs.lo - rhs.lo;
+
+ /* check for underflow */
+ if (difference.lo > lhs.lo)
+ difference.hi -= 1;
+ return difference;
+}
+
+ipv6address_t ipv6address_add(ipv6address_t lhs, ipv6address_t rhs) {
+ ipv6address_t sum;
+ sum.hi = lhs.hi + rhs.hi;
+ sum.lo = lhs.lo - rhs.lo;
+
+ /* check for underflow */
+ if (sum.lo > lhs.lo)
+ sum.hi += 1;
+ return sum;
+}
+
+
int ipv6address_selftest(void)
+{
+ struct test_pair {
+ const char *name; // Human-readable IPv6 address string
+ struct ipaddress ip_addr; // IP address (union)
+ };
+ /* Probably overkill, added while investigating issue #796 */
+ struct test_pair tests[] = {
+ {"2001:db8:ac10:fe01::2", {.ipv6 = {0x20010db8ac10fe01, 0x0000000000000002}, .version = 6}},
+ {"2607:f8b0:4000::1", {.ipv6 = {0x2607f8b040000000, 0x0000000000000001}, .version = 6}},
+ {"fd12:3456:7890:abcd:ef00::1", {.ipv6 = {0xfd1234567890abcd, 0xef00000000000001}, .version = 6}},
+ {"::1", {.ipv6 = {0x0000000000000000, 0x0000000000000001}, .version = 6}},
+ {"1::", {.ipv6 = {0x0001000000000000, 0x0000000000000000}, .version = 6}},
+ {"1::2", {.ipv6 = {0x0001000000000000, 0x0000000000000002}, .version = 6}},
+ {"2::1", {.ipv6 = {0x0002000000000000, 0x0000000000000001}, .version = 6}},
+ {"1:2::", {.ipv6 = {0x0001000200000000, 0x0000000000000000}, .version = 6}},
+ {NULL, {{0, 0}, 0}}
+ };
+
+ int x = 0;
+ ipaddress ip;
+ struct ipaddress_formatted fmt;
+
+ for (int i = 0; tests[i].name != NULL; i++) {
+ fmt = ipaddress_fmt(tests[i].ip_addr);
+ if (strcmp(fmt.string, tests[i].name) != 0)
+ x++;
+ }
+ return x;
+}
+
+int ipv4address_selftest(void)
{
int x = 0;
ipaddress ip;
diff --git a/src/massip-addr.h b/src/massip-addr.h
index 571641f6..56d3a127 100644
--- a/src/massip-addr.h
+++ b/src/massip-addr.h
@@ -67,24 +67,55 @@ struct ipaddress {
};
typedef struct ipaddress ipaddress;
+/** @return true if the IPv6 address is zero [::] */
static inline int ipv6address_is_zero(ipv6address_t a) {
return a.hi == 0 && a.lo == 0;
}
#define massint128_is_zero ipv6address_is_zero
+/** The IPv6 address [FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF]
+ * is invalid */
static inline int ipv6address_is_invalid(ipv6address_t a) {
return a.hi == ~0ULL && a.lo == ~0ULL;
}
+
+
+/** Compare two IPv6 addresses */
static inline int ipv6address_is_equal(ipv6address_t a, ipv6address_t b) {
return a.hi == b.hi && a.lo == b.lo;
}
+
+static inline int ipaddress_is_equal(ipaddress a, ipaddress b) {
+ if (a.version != b.version)
+ return 0;
+ if (a.version == 4) {
+ return a.ipv4 == b.ipv4;
+ } else if (a.version == 6) {
+ return ipv6address_is_equal(a.ipv6, b.ipv6);
+ } else
+ return 0;
+}
+
+/** Compare two IPv6 addresses, to see which one comes frist. This is used
+ * in sorting the addresses
+ * @return true if a < b, false otherwise */
static inline int ipv6address_is_lessthan(ipv6address_t a, ipv6address_t b) {
return (a.hi == b.hi)?(a.lo < b.lo):(a.hi < b.hi);
}
+/**
+ * Mask the lower bits of each address and test if the upper bits are equal
+ */
int ipv6address_is_equal_prefixed(ipv6address_t lhs, ipv6address_t rhs, unsigned prefix);
+ipv6address_t ipv6address_add_uint64(ipv6address_t lhs, uint64_t rhs);
+ipv6address_t ipv6address_subtract(ipv6address_t lhs, ipv6address_t rhs);
+ipv6address_t ipv6address_add(ipv6address_t lhs, ipv6address_t rhs);
+/**
+ * Given a typical EXTERNAL representation of an IPv6 address, which is
+ * an array of 16 bytes, convert to the canonical INTERNAL address.
+ */
static inline ipv6address ipv6address_from_bytes(const unsigned char *buf) {
ipv6address addr;
addr.hi = (uint64_t)buf[ 0] << 56
@@ -105,6 +136,11 @@ static inline ipv6address ipv6address_from_bytes(const unsigned char *buf) {
| (uint64_t)buf[15] << 0;
return addr;
}
+
+/**
+ * Given a typical EXTERNAL representation of an Ethernet MAC address,
+ * which is an array of 6 bytes, convert to the canonical INTERNAL address.
+ */
static inline macaddress_t macaddress_from_bytes(const void *vbuf)
{
const unsigned char *buf = (const unsigned char *)vbuf;
@@ -117,6 +153,8 @@ static inline macaddress_t macaddress_from_bytes(const void *vbuf)
result.addr[5] = buf[5];
return result;
}
+
+/** Test if the Ethernet MAC address is all zeroes */
static inline int macaddress_is_zero(macaddress_t mac)
{
return mac.addr[0] == 0
@@ -126,6 +164,8 @@ static inline int macaddress_is_zero(macaddress_t mac)
&& mac.addr[4] == 0
&& mac.addr[5] == 0;
}
+
+/** Compare two Ethernet MAC addresses to see if they are equal */
static inline int macaddress_is_equal(macaddress_t lhs, macaddress_t rhs)
{
return lhs.addr[0] == rhs.addr[0]
@@ -154,5 +194,6 @@ unsigned massint128_bitcount(massint128_t num);
* @return 0 on success, 1 on failure
*/
int ipv6address_selftest(void);
+int ipv4address_selftest(void);
#endif
diff --git a/src/massip-parse.c b/src/massip-parse.c
index 0c173b93..f3c77ed8 100644
--- a/src/massip-parse.c
+++ b/src/massip-parse.c
@@ -11,10 +11,10 @@
#include "massip-parse.h"
#include "massip-rangesv4.h"
#include "massip-rangesv6.h"
-#include "logger.h"
+#include "util-logger.h"
#include "util-bool.h"
#include "util-malloc.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include "unusedparm.h"
#include
@@ -826,22 +826,28 @@ massip_parse_file(struct MassIP *massip, const char *filename)
struct massip_parser p[1];
char buf[65536];
FILE *fp = NULL;
- int err;
bool is_error = false;
unsigned addr_count = 0;
unsigned long long line_number, char_number;
+ /* Kludge: should never happen, should fix this when reading in
+ * config, not this deep in the code. */
+ if (filename == 0 || filename[0] == '\0') {
+ fprintf(stderr, "[-] missing filename for ranges\n");
+ exit(1);
+ }
+
/*
* Open the file containing IP addresses, which can potentially be
* many megabytes in size
*/
if (strcmp(filename, "-") == 0) {
fp = stdin;
- err = 0;
} else {
- err = fopen_s(&fp, filename, "rb");
- if (err || fp == NULL) {
- perror(filename);
+ fp = fopen(filename, "rb");
+ if (fp == NULL) {
+ fprintf(stderr, "[-] FAIL: parsing IP addresses\n");
+ fprintf(stderr, "[-] %s: %s\n", filename, strerror(errno));
exit(1);
}
}
@@ -867,6 +873,7 @@ massip_parse_file(struct MassIP *massip, const char *filename)
offset = 0;
while (offset < count) {
unsigned begin, end;
+ int err;
err = _parser_next(p, buf, &offset, count, &begin, &end);
switch (err) {
@@ -909,6 +916,7 @@ massip_parse_file(struct MassIP *massip, const char *filename)
if (!is_error) {
size_t offset = 0;
unsigned begin, end;
+ int err;
err = _parser_next(p, "\n", &offset, 1, &begin, &end);
switch (err) {
case Still_Working:
diff --git a/src/massip-rangesv4.c b/src/massip-rangesv4.c
index 3108760b..fa6fda96 100644
--- a/src/massip-rangesv4.c
+++ b/src/massip-rangesv4.c
@@ -28,7 +28,7 @@
*/
#include "massip-rangesv4.h"
#include "massip-port.h"
-#include "logger.h"
+#include "util-logger.h"
#include "util-bool.h"
#include "util-malloc.h"
@@ -39,6 +39,10 @@
#include
#include
+#ifdef _MSC_VER
+#pragma warning(disable:4204)
+#endif
+
#define BUCKET_COUNT 16
#define REGRESS(x) if (!(x)) return (fprintf(stderr, "regression failed %s:%d\n", __FILE__, __LINE__)|1)
@@ -65,6 +69,116 @@ rangelist_is_contains(const struct RangeList *targets, unsigned addr)
return 0;
}
+/***************************************************************************
+ * Returns the first CIDR range (which can be specified with prefix bits)
+ * that fits within the input range. For example, consider the range
+ * [10.0.0.4->10.0.0.255]. This does't match the bigger CIDR range.
+ * The first range that would fit would be [10.0.0.04/30], or
+ * [10.0.0.4->10.0.0.7].
+ *
+ * Using this function allows us to decompose
+ ***************************************************************************/
+struct Range
+range_first_cidr(const struct Range range, unsigned *prefix_bits) {
+ struct Range result = {range.begin, range.end};
+ unsigned zbits = 0;
+
+ /* Kludge: Special Case:
+ * All inputs work but the boundary case of [0.0.0.0/0] or
+ * [0.0.0.0-255.255.255.255]. I can't be bothered to figure out
+ * why the algorithm doesn't work with this range, so I'm just
+ * going to special case it here*/
+ if (range.begin == 0 && range.end == 0xFFFFffff) {
+ if (prefix_bits != NULL)
+ *prefix_bits = 0;
+ return range;
+ }
+
+ /* Count the number of trailing/suffix zeros, which may be range
+ * from none (0) to 32 (all bits are 0) */
+ for (zbits = 0; zbits <= 32; zbits++) {
+ if ((range.begin & (1< 0) {
+ unsigned mask = ~(0xFFFFFFFF << zbits);
+
+ if (range.begin + mask > range.end)
+ zbits--;
+ else
+ break;
+ }
+
+ result.begin = range.begin;
+ result.end = range.begin + ~(0xFFFFffff << zbits);
+ if (prefix_bits != NULL)
+ *prefix_bits = 32-zbits;
+
+ return result;
+}
+
+bool
+range_is_cidr(const struct Range range, unsigned *prefix_bits) {
+ struct Range out = range_first_cidr(range, prefix_bits);
+ if (out.begin == range.begin && out.end == range.end)
+ return true;
+ else {
+ if (prefix_bits != NULL)
+ *prefix_bits = 0xFFFFFFFF;
+ return false;
+ }
+}
+
+/***************************************************************************
+ * Selftest for the above function.
+ ***************************************************************************/
+static int
+selftest_range_first_cidr(void) {
+ static struct {
+ struct Range in;
+ struct Range out;
+ unsigned prefix_bits;
+ } tests[] = {
+ {{0x00000000, 0xffffffff}, {0x00000000, 0xffffffff}, 0},
+ {{0x00000001, 0xffffffff}, {0x00000001, 0x00000001}, 32},
+ {{0xffffffff, 0xffffffff}, {0xffffffff, 0xffffffff}, 32},
+ {{0xfffffffe, 0xfffffffe}, {0xfffffffe, 0xfffffffe}, 32},
+ {{0x0A000000, 0x0A0000Ff}, {0x0A000000, 0x0A0000ff}, 24},
+ {{0x0A0000ff, 0x0A0000Ff}, {0x0A0000ff, 0x0A0000ff}, 32},
+ {{0x0A000000, 0x0A0000Ff}, {0x0A000000, 0x0A0000Ff}, 24},
+ {{0x0A000001, 0x0A0000Fe}, {0x0A000001, 0x0A000001}, 32},
+ {{0x0A000008, 0x0A0000Fe}, {0x0A000008, 0x0A00000f}, 29},
+ {{0x0A000080, 0x0A0000Fe}, {0x0A000080, 0x0A0000bf}, 26},
+ {{0x0A0000c0, 0x0A0000Fe}, {0x0A0000c0, 0x0A0000df}, 27},
+ {{0x0A0000c1, 0x0A0000Fe}, {0x0A0000c1, 0x0A0000c1}, 32},
+ {{0x0A0000fe, 0x0A0000Fe}, {0x0A0000fe, 0x0A0000fe}, 32},
+ {{0,0}, {0,0}}
+ };
+ size_t i;
+
+ for (i=0; tests[i].in.end != 0; i++) {
+ unsigned prefix_bits = 0xFFFFFFFF;
+ struct Range out = range_first_cidr(tests[i].in, &prefix_bits);
+ if (out.begin != tests[i].out.begin
+ || out.end != tests[i].out.end
+ || prefix_bits != tests[i].prefix_bits) {
+ fprintf(stderr, "[%u] 0x%08x->0x%08x /%u 0x%08x->0x%08x /%u\n",
+ (unsigned)i,
+ out.begin,
+ out.end,
+ prefix_bits,
+ tests[i].out.begin,
+ tests[i].out.end,
+ tests[i].prefix_bits);
+ return 1;
+ }
+ }
+
+ return 0;
+}
/***************************************************************************
* Test if two ranges overlap.
@@ -229,6 +343,25 @@ rangelist_add_range(struct RangeList *targets, unsigned begin, unsigned end)
targets->is_sorted = 0;
}
+/** Use this when adding TCP ports, to avoid the comoplication of how
+ * ports are stored */
+void
+rangelist_add_range_tcp(struct RangeList *targets, unsigned begin, unsigned end) {
+ rangelist_add_range(targets,
+ Templ_TCP + begin,
+ Templ_TCP + end);
+}
+
+/** Use this when adding UDP ports, to avoid the comoplication of how
+ * ports are stored */
+void
+rangelist_add_range_udp(struct RangeList *targets, unsigned begin, unsigned end) {
+ rangelist_add_range(targets,
+ Templ_UDP + begin,
+ Templ_UDP + end);
+}
+
+
/***************************************************************************
* This is the "free" function for the list, freeing up any memory we've
* allocated.
@@ -1247,5 +1380,10 @@ ranges_selftest(void)
}
}
+ if (selftest_range_first_cidr() != 0) {
+ ERROR();
+ return 1;
+ }
+
return 0;
}
diff --git a/src/massip-rangesv4.h b/src/massip-rangesv4.h
index 83871a37..5cad6697 100644
--- a/src/massip-rangesv4.h
+++ b/src/massip-rangesv4.h
@@ -2,6 +2,7 @@
#define RANGES_H
#include
#include
+#include "util-bool.h" /**/
/**
* A range of either IP addresses or ports
@@ -12,6 +13,48 @@ struct Range
unsigned end; /* inclusive, so [n..m] includes both 'n' and 'm' */
};
+
+/**
+ * Find the first CIDR range (one that can be specified with a /prefix)
+ * inside the current range. If the current range can already be
+ * specified with a CIDR /prefix, then the entire range is returned.
+ * Examples:
+ * [10.0.0.0->10.0.0.255] returns [10.0.0.0->10.0.0.255] (no change)
+ * [10.0.0.1->10.0.0.255] returns [10.0.0.1->10.0.0.1]
+ * [10.0.0.2->10.0.0.255] returns [10.0.0.2->10.0.0.3]
+ * [10.0.0.4->10.0.0.255] returns [10.0.0.4->10.0.0.7]
+ * [10.0.0.248->10.0.0.254] returns [10.0.0.248->10.0.0.251]
+ * [10.0.0.252->10.0.0.254] returns [10.0.0.252->10.0.0.253]
+ * [10.0.0.254->10.0.0.254] returns [10.0.0.254->10.0.0.254]
+ * @param range
+ * A range specified by a starting IPv4 address and an ending
+ * IPv4 address, like [10.0.0.4->10.0.0.255].
+ * @param prefix_length
+ * An out-only parameter that receives the CIDR prefix length
+ * (number of bits) of the resulting range. This parameter is
+ * optional (may be NULL).
+ * @return the smaller range, and the number of prefix bits in the range.
+ */
+struct Range
+range_first_cidr(const struct Range range, unsigned *prefix_length /*out*/);
+
+/**
+ * Test if the range can instead be expressed using a CIDR /prefix.
+ * In other words, [10.0.0.0-10.0.0.255] can be expressed as [10.0.0.0/24].
+ * @param range to be tested
+ * @param prefix_length receivesoutput of the number of prefix bits if
+ * successful, otherwise set to 0xFFFFFFFF. This is optional, may
+ * be NULL and receive no output.
+ * @return True if the range can be expressed in CIDR notation, in
+ * which case `prefix_length` is set to the number of bits in the prefix
+ * for printing in that notation. False otherwise, in which case
+ * `prefix_length` is set to 0xFFFFFFFF (an invalid value).
+ */
+bool range_is_cidr(const struct Range range, unsigned *prefix_length /*out*/);
+
+
+
+
/**
* An array of ranges in sorted order
*/
@@ -38,6 +81,11 @@ struct RangeList
void
rangelist_add_range(struct RangeList *task, unsigned begin, unsigned end);
+void
+rangelist_add_range_tcp(struct RangeList *targets, unsigned begin, unsigned end);
+void
+rangelist_add_range_udp(struct RangeList *targets, unsigned begin, unsigned end);
+
/**
* Returns 'true' is the indicated port or IP address is in one of the task
diff --git a/src/massip-rangesv6.c b/src/massip-rangesv6.c
index 3dc11677..6d50c59c 100644
--- a/src/massip-rangesv6.c
+++ b/src/massip-rangesv6.c
@@ -4,7 +4,7 @@
#include "massip-rangesv6.h"
#include "massip-rangesv4.h"
#include "util-malloc.h"
-#include "logger.h"
+#include "util-logger.h"
#include "massip.h"
#include "massip-parse.h"
@@ -572,7 +572,7 @@ range6list_optimize(struct Range6List *targets)
for (i=0; icount; i++) {
ipv6address x;
- picker[i] = total.lo;
+ picker[i] = (size_t)total.lo;
x = _int128_subtract(targets->list[i].end, targets->list[i].begin);
x = _int128_add64(x, 1);
total = _int128_add(total, x);
diff --git a/src/misc-rstfilter.c b/src/misc-rstfilter.c
index 9d919a5e..80f90aed 100644
--- a/src/misc-rstfilter.c
+++ b/src/misc-rstfilter.c
@@ -1,6 +1,6 @@
#include "misc-rstfilter.h"
#include "util-malloc.h"
-#include "siphash24.h"
+#include "crypto-siphash24.h"
#include
struct ResetFilter
diff --git a/src/out-binary.c b/src/out-binary.c
index 2372cd6a..0c759151 100644
--- a/src/out-binary.c
+++ b/src/out-binary.c
@@ -2,7 +2,7 @@
#include "masscan-app.h"
#include "masscan-status.h"
#include "out-record.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include
/****************************************************************************
@@ -17,7 +17,7 @@ binary_out_open(struct Output *out, FILE *fp)
memset(firstrecord, 0, 2+'a');
- sprintf_s(firstrecord, 2+'a', "masscan/1.1\ns:%u\n",
+ snprintf(firstrecord, 2+'a', "masscan/1.1\ns:%u\n",
(unsigned)out->when_scan_started);
bytes_written = fwrite(firstrecord, 1, 2+'a', fp);
if (bytes_written != 2+'a') {
@@ -40,7 +40,7 @@ binary_out_close(struct Output *out, FILE *fp)
UNUSEDPARM(out);
memset(firstrecord, 0, 2+'a');
- sprintf_s(firstrecord, 2+'a', "masscan/1.1");
+ snprintf(firstrecord, 2+'a', "masscan/1.1");
bytes_written = fwrite(firstrecord, 1, 2+'a', fp);
if (bytes_written != 2+'a') {
perror("output");
@@ -103,8 +103,8 @@ static void
binary_out_status_ipv6(struct Output *out, FILE *fp, time_t timestamp,
int status, ipaddress ip, unsigned ip_proto, unsigned port, unsigned reason, unsigned ttl)
{
- unsigned char buf[256];
- size_t max = sizeof(buf);
+ unsigned char buf[256+1];
+ size_t max = sizeof(buf)-1;
size_t offset = 0;
size_t bytes_written;
diff --git a/src/out-certs.c b/src/out-certs.c
index 214eb587..5e0705ac 100644
--- a/src/out-certs.c
+++ b/src/out-certs.c
@@ -1,7 +1,7 @@
#include "output.h"
#include "masscan-app.h"
#include "masscan-status.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include
diff --git a/src/out-grepable.c b/src/out-grepable.c
index 931349d4..30d89fc3 100644
--- a/src/out-grepable.c
+++ b/src/out-grepable.c
@@ -4,7 +4,7 @@
#include "masscan-status.h"
#include "out-tcp-services.h"
#include "massip-port.h"
-#include "string_s.h"
+#include "util-safefunc.h"
/****************************************************************************
@@ -75,7 +75,7 @@ grepable_out_open(struct Output *out, FILE *fp)
unsigned count;
- gmtime_s(&tm, &out->when_scan_started);
+ safe_gmtime(&tm, &out->when_scan_started);
//Tue Jan 21 20:23:22 2014
//%a %b %d %H:%M:%S %Y
@@ -122,7 +122,7 @@ grepable_out_close(struct Output *out, FILE *fp)
UNUSEDPARM(out);
- gmtime_s(&tm, &now);
+ safe_gmtime(&tm, &now);
//Tue Jan 21 20:23:22 2014
//%a %b %d %H:%M:%S %Y
@@ -154,7 +154,7 @@ grepable_out_status(struct Output *out, FILE *fp, time_t timestamp,
else
service = oproto_service_name(ip_proto);
- fprintf(fp, "Timestamp: %lu", timestamp);
+ fprintf(fp, "Timestamp: %llu", (unsigned long long)timestamp);
fmt = ipaddress_fmt(ip);
fprintf(fp, "\tHost: %s ()", fmt.string);
@@ -181,9 +181,9 @@ grepable_out_banner(struct Output *out, FILE *fp, time_t timestamp,
enum ApplicationProtocol proto, unsigned ttl,
const unsigned char *px, unsigned length)
{
- char banner_buffer[4096];
+ char banner_buffer[MAX_BANNER_LENGTH];
ipaddress_formatted_t fmt;
-
+
UNUSEDPARM(ttl);
UNUSEDPARM(timestamp);
UNUSEDPARM(out);
diff --git a/src/out-json.c b/src/out-json.c
index 5d91e436..21b2b83d 100644
--- a/src/out-json.c
+++ b/src/out-json.c
@@ -1,7 +1,7 @@
#include "output.h"
#include "masscan-app.h"
#include "masscan-status.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include
diff --git a/src/out-ndjson.c b/src/out-ndjson.c
index 56fd3211..c128b892 100644
--- a/src/out-ndjson.c
+++ b/src/out-ndjson.c
@@ -1,7 +1,7 @@
#include "output.h"
#include "masscan-app.h"
#include "masscan-status.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include
@@ -129,7 +129,7 @@ ndjson_out_banner(struct Output *out, FILE *fp, time_t timestamp,
UNUSEDPARM(out);
/* fprintf(fp, ""
- ""
+ ""
""
""
" "
@@ -143,6 +143,7 @@ ndjson_out_banner(struct Output *out, FILE *fp, time_t timestamp,
(ip>>16)&0xFF,
(ip>> 8)&0xFF,
(ip>> 0)&0xFF,
+ name_from_ip_version(ip.version),
name_from_ip_proto(ip_proto),
port,
reason, ttl,
diff --git a/src/out-redis.c b/src/out-redis.c
index fd88ad1a..e06ddd1f 100644
--- a/src/out-redis.c
+++ b/src/out-redis.c
@@ -1,7 +1,7 @@
#include "output.h"
#include "masscan.h"
#include "pixie-sockets.h"
-#include "logger.h"
+#include "util-logger.h"
#include
/****************************************************************************
@@ -149,11 +149,34 @@ clean_response_queue(struct Output *out, SOCKET fd)
static void
redis_out_open(struct Output *out, FILE *fp)
{
+ /*FIXME: why did I write this code using ptrdiff_t? */
ptrdiff_t fd = (ptrdiff_t)fp;
size_t count;
- unsigned char line[1024];
+ char line[1024];
UNUSEDPARM(out);
+ if (out->redis.password != NULL)
+ {
+ snprintf(line, sizeof(line),
+ "*2\r\n"
+ "$4\r\nAUTH\r\n"
+ "$%u\r\n%s\r\n",
+ (unsigned)strlen(out->redis.password), out->redis.password);
+
+ count = send((SOCKET)fd, line, (int)strlen(line), 0);
+ if (count != strlen(line))
+ {
+ LOG(0, "redis: error auth\n");
+ exit(1);
+ }
+
+ count = recv_line((SOCKET)fd, line, sizeof(line));
+ if (count != 5 && memcmp(line, "+OK\r\n", 5) != 0)
+ {
+ LOG(0, "redis: unexpected response from redis server: %s\n", line);
+ exit(1);
+ }
+ }
count = send((SOCKET)fd, "PING\r\n", 6, 0);
if (count != 6) {
@@ -210,8 +233,8 @@ redis_out_status(struct Output *out, FILE *fp, time_t timestamp,
int values_length;
ipaddress_formatted_t fmt = ipaddress_fmt(ip);
- ip_string_length = sprintf_s(ip_string, sizeof(ip_string), "%s", fmt.string);
- port_string_length = sprintf_s(port_string, sizeof(port_string), "%u/%s", port, name_from_ip_proto(ip_proto));
+ ip_string_length = snprintf(ip_string, sizeof(ip_string), "%s", fmt.string);
+ port_string_length = snprintf(port_string, sizeof(port_string), "%u/%s", port, name_from_ip_proto(ip_proto));
/**3
$3
@@ -226,7 +249,7 @@ myvalue
* KEY: "host"
* VALUE: ip
*/
- sprintf_s(line, sizeof(line),
+ snprintf(line, sizeof(line),
"*3\r\n"
"$4\r\nSADD\r\n"
"$%d\r\n%s\r\n"
@@ -247,7 +270,7 @@ myvalue
* KEY: ip
* VALUE: port
*/
- sprintf_s(line, sizeof(line),
+ snprintf(line, sizeof(line),
"*3\r\n"
"$4\r\nSADD\r\n"
"$%d\r\n%s\r\n"
@@ -268,9 +291,9 @@ myvalue
* KEY: ip:port
* VALUE: timestamp:status:reason:ttl
*/
- values_length = sprintf_s(values, sizeof(values), "%u:%u:%u:%u",
+ values_length = snprintf(values, sizeof(values), "%u:%u:%u:%u",
(unsigned)timestamp, status, reason, ttl);
- line_length = sprintf_s(line, sizeof(line),
+ line_length = snprintf(line, sizeof(line),
"*3\r\n"
"$4\r\nSADD\r\n"
"$%d\r\n%s:%s\r\n"
diff --git a/src/out-tcp-services.c b/src/out-tcp-services.c
index 4f1694da..f34149c3 100644
--- a/src/out-tcp-services.c
+++ b/src/out-tcp-services.c
@@ -18,7 +18,7 @@
*/
static unsigned short my_htons(unsigned port)
{
- static const char test[2] = "\x11\x22";
+ static const char test[3] = "\x11\x22";
if (*(unsigned short*)test == 0x1122)
return (unsigned short)(0xFFFF & port);
else
diff --git a/src/out-text.c b/src/out-text.c
index ba3346e9..1a2856b4 100644
--- a/src/out-text.c
+++ b/src/out-text.c
@@ -54,7 +54,7 @@ text_out_banner(struct Output *out, FILE *fp, time_t timestamp,
enum ApplicationProtocol proto, unsigned ttl,
const unsigned char *px, unsigned length)
{
- char banner_buffer[4096];
+ char banner_buffer[MAX_BANNER_LENGTH];
ipaddress_formatted_t fmt = ipaddress_fmt(ip);
diff --git a/src/out-xml.c b/src/out-xml.c
index ce23f6a7..a826a9e8 100644
--- a/src/out-xml.c
+++ b/src/out-xml.c
@@ -1,7 +1,7 @@
#include "output.h"
#include "masscan-app.h"
#include "masscan-status.h"
-#include "string_s.h"
+#include "util-safefunc.h"
@@ -39,9 +39,9 @@ xml_out_close(struct Output *out, FILE *fp)
struct tm tm;
if (out->is_gmt)
- gmtime_s(&tm, &now);
+ safe_gmtime(&tm, &now);
else
- localtime_s(&tm, &now);
+ safe_localtime(&tm, &now);
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm);
fprintf(fp,
@@ -71,7 +71,7 @@ xml_out_status(struct Output *out, FILE *fp, time_t timestamp, int status,
UNUSEDPARM(out);
fprintf(fp, ""
- ""
+ ""
""
""
""
@@ -81,6 +81,7 @@ xml_out_status(struct Output *out, FILE *fp, time_t timestamp, int status,
"\r\n",
(unsigned)timestamp,
fmt.string,
+ name_from_ip_version(ip.version),
name_from_ip_proto(ip_proto),
port,
status_string(status),
@@ -98,7 +99,7 @@ xml_out_banner(struct Output *out, FILE *fp, time_t timestamp,
unsigned ttl,
const unsigned char *px, unsigned length)
{
- char banner_buffer[4096];
+ char banner_buffer[MAX_BANNER_LENGTH];
const char *reason;
ipaddress_formatted_t fmt = ipaddress_fmt(ip);
@@ -110,7 +111,7 @@ xml_out_banner(struct Output *out, FILE *fp, time_t timestamp,
UNUSEDPARM(out);
fprintf(fp, ""
- ""
+ ""
""
""
" "
@@ -121,6 +122,7 @@ xml_out_banner(struct Output *out, FILE *fp, time_t timestamp,
"\r\n",
(unsigned)timestamp,
fmt.string,
+ name_from_ip_version(ip.version),
name_from_ip_proto(ip_proto),
port,
reason, ttl,
diff --git a/src/output.c b/src/output.c
index 05c420ff..6d39ddec 100644
--- a/src/output.c
+++ b/src/output.c
@@ -34,19 +34,22 @@
#include "output.h"
#include "masscan.h"
#include "masscan-status.h"
-#include "string_s.h"
-#include "logger.h"
#include "proto-banner1.h"
#include "masscan-app.h"
#include "main-globals.h"
#include "pixie-file.h"
#include "pixie-sockets.h"
#include "util-malloc.h"
+#include "util-errormsg.h"
+#include "util-logger.h"
#include
#include
#include
+/* Put this at the bottom of the include lists because of warnings */
+#include "util-safefunc.h"
+
/*****************************************************************************
*****************************************************************************/
@@ -78,6 +81,19 @@ name_from_ip_proto(unsigned ip_proto)
}
}
+/*****************************************************************************
+ * This function converts the version of the ipaddress struct back into a
+ * readable string.
+ *****************************************************************************/
+const char *
+name_from_ip_version(unsigned char version)
+{
+ switch (version) {
+ case 4: return "ipv4";
+ case 6: return "ipv6";
+ default: return "err";
+ }
+}
/*****************************************************************************
* The actual 'status' variable is narrowly defined depending on the
@@ -102,7 +118,7 @@ status_string(enum PortStatus status)
const char *
reason_string(int x, char *buffer, size_t sizeof_buffer)
{
- sprintf_s(buffer, sizeof_buffer, "%s%s%s%s%s%s%s%s",
+ snprintf(buffer, sizeof_buffer, "%s%s%s%s%s%s%s%s",
(x&0x01)?"fin-":"",
(x&0x02)?"syn-":"",
(x&0x04)?"rst-":"",
@@ -356,7 +372,7 @@ indexed_filename(const char *filename, unsigned index)
/* format the new name */
- sprintf_s(new_filename, new_length, "%.*s.%02u%s",
+ snprintf(new_filename, new_length, "%.*s.%02u%s",
(unsigned)ext, filename,
index,
filename+ext);
@@ -390,13 +406,16 @@ output_create(const struct Masscan *masscan, unsigned thread_index)
out->rotate.filesize = masscan->output.rotate.filesize;
out->redis.port = masscan->redis.port;
out->redis.ip = masscan->redis.ip;
- out->is_banner = masscan->is_banners;
+ out->redis.password = masscan ->redis.password;
+ out->is_banner = masscan->is_banners; /* --banners */
+ out->is_banner_rawudp = masscan->is_banners_rawudp; /* --rawudp */
out->is_gmt = masscan->is_gmt;
out->is_interactive = masscan->output.is_interactive;
out->is_show_open = masscan->output.is_show_open;
out->is_show_closed = masscan->output.is_show_closed;
out->is_show_host = masscan->output.is_show_host;
out->is_append = masscan->output.is_append;
+ out->is_output_flush = masscan->output.is_output_flush;
out->xml.stylesheet = duplicate_string(masscan->output.stylesheet);
out->rotate.directory = duplicate_string(masscan->output.rotate.directory);
if (masscan->nic_count <= 1)
@@ -547,9 +566,9 @@ output_do_rotate(struct Output *out, int is_closing)
/* Get the proper timestamp for the file */
if (out->is_gmt) {
- err = gmtime_s(&tm, &out->rotate.last);
+ err = safe_gmtime(&tm, &out->rotate.last);
} else {
- err = localtime_s(&tm, &out->rotate.last);
+ err = safe_localtime(&tm, &out->rotate.last);
}
if (err != 0) {
free(new_filename);
@@ -572,7 +591,7 @@ output_do_rotate(struct Output *out, int is_closing)
x_off = strlen(filename);
x_len = 0;
}
- sprintf_s(new_filename, new_filename_size,
+ snprintf(new_filename, new_filename_size,
"%s/%.*s-%05u%.*s",
dir,
(unsigned)x_off, filename,
@@ -580,7 +599,7 @@ output_do_rotate(struct Output *out, int is_closing)
(unsigned)x_len, filename + x_off
);
} else {
- sprintf_s(new_filename, new_filename_size,
+ snprintf(new_filename, new_filename_size,
"%s/%02u%02u%02u-%02u%02u%02u" "-%s",
dir,
tm.tm_year % 100,
@@ -633,7 +652,7 @@ output_do_rotate(struct Output *out, int is_closing)
fp = open_rotate(out, filename);
if (fp == NULL) {
- LOG(0, "rotate: %s: failed: %s\n", filename, strerror_x(errno));
+ LOG(0, "rotate: %s: failed: %s\n", filename, strerror(errno));
} else {
close_rotate(out, out->fp);
out->fp = fp;
@@ -777,11 +796,11 @@ output_report_status(struct Output *out, time_t timestamp, int status,
fprintf(stdout, "\n");
fflush(stdout);
- }
-
-
- if (fp == NULL)
+ } else if (fp == NULL) {
+ ERRMSG("no output file, use `--output-filename ` to set one\n");
+ ERRMSG("for `stdout`, use `--output-filename -`\n");
return;
+ }
/* Rotate, if we've pass the time limit. Rotating the log files happens
* inline while writing output, whenever there's output to write to the
@@ -855,6 +874,9 @@ output_report_status(struct Output *out, time_t timestamp, int status,
* and so on.
*/
out->funcs->status(out, fp, timestamp, status, ip, ip_proto, port, reason, ttl);
+
+ if (out->is_output_flush)
+ fflush(fp);
}
@@ -880,7 +902,7 @@ output_report_banner(struct Output *out, time_t now,
* line screen */
if (out->is_interactive || out->format == 0 || out->format == Output_Interactive) {
unsigned count;
- char banner_buffer[4096];
+ char banner_buffer[MAX_BANNER_LENGTH];
count = fprintf(stdout, "Banner on port %u/%s on %s: [%s] %s",
port,
@@ -929,6 +951,8 @@ output_report_banner(struct Output *out, time_t now,
*/
out->funcs->banner(out, fp, now, ip, ip_proto, port, proto, ttl, px, length);
+ if (out->is_output_flush)
+ fflush(fp);
}
diff --git a/src/output.h b/src/output.h
index 432f33ee..87ba37b5 100644
--- a/src/output.h
+++ b/src/output.h
@@ -9,6 +9,8 @@
#include "unusedparm.h"
#include "masscan-app.h"
+#define MAX_BANNER_LENGTH 8192
+
struct Masscan;
struct Output;
enum ApplicationProtocol;
@@ -79,7 +81,9 @@ struct Output
char *directory;
} rotate;
- unsigned is_banner:1;
+ unsigned is_banner:1; /* --banners */
+ unsigned is_banner_rawudp:1; /* --rawudp */
+ unsigned is_output_flush:1; /* --output-flush */
unsigned is_gmt:1; /* --gmt */
unsigned is_interactive:1; /* echo to command line */
unsigned is_show_open:1; /* show open ports (default) */
@@ -116,6 +120,7 @@ struct Output
struct {
ipaddress ip;
unsigned port;
+ char *password;
ptrdiff_t fd;
uint64_t outstanding;
unsigned state;
@@ -126,6 +131,7 @@ struct Output
};
const char *name_from_ip_proto(unsigned ip_proto);
+const char *name_from_ip_version(unsigned char version);
const char *status_string(enum PortStatus x);
const char *reason_string(int x, char *buffer, size_t sizeof_buffer);
const char *normalize_string(const unsigned char *px, size_t length,
diff --git a/src/pixie-threads.c b/src/pixie-threads.c
index 48283a1b..f085d230 100644
--- a/src/pixie-threads.c
+++ b/src/pixie-threads.c
@@ -5,7 +5,8 @@
#include
#include
#endif
-#if defined(__GNUC__)
+
+#if defined(__GNUC__) && !defined(WIN32)
#include
#include
#include
diff --git a/src/pixie-timer.c b/src/pixie-timer.c
index e84eca01..cccd9c58 100644
--- a/src/pixie-timer.c
+++ b/src/pixie-timer.c
@@ -55,7 +55,7 @@ getFILETIMEoffset(void)
}
int
-clock_gettime(int X, struct timeval *tv)
+win_clock_gettime(int X, struct timeval *tv)
{
LARGE_INTEGER t;
FILETIME f;
@@ -254,6 +254,19 @@ pixie_nanotime(void)
}
#endif
+/*
+ * Timing is incredibly importatn to masscan because we need to throttle
+ * how fast we spew packets. Every platofrm has slightly different timing
+ * even given standard APIs. We need to make sure we have an accurate
+ * timing function.
+ *
+ * This function tests betwe [0.9, 1.9] the expected results. I want something
+ * tight, like [0.99,1.01] (plus/minus 1%), but unfortunately automated
+ * testing platforms, like GitHub Actions, are overloaded, so when I wait
+ * for half a second, they might actually wait for 0.7 seconds, causing
+ * this test to fail. Thus, I have to greatly expand the range that passes
+ * this test.
+ */
int pixie_time_selftest(void)
{
static const uint64_t duration = 456789;
@@ -269,7 +282,7 @@ int pixie_time_selftest(void)
fprintf(stderr, "timing error, long delay\n");
return 1;
}
- if (1.2 * duration < elapsed) {
+ if (1.9 * duration < elapsed) {
fprintf(stderr, "timing error, long delay %5.0f%%\n", elapsed*100.0/duration);
return 1;
}
diff --git a/src/proto-arp.c b/src/proto-arp.c
index 0f67c408..5abbbae0 100644
--- a/src/proto-arp.c
+++ b/src/proto-arp.c
@@ -1,6 +1,6 @@
#include "proto-arp.h"
#include "proto-preprocess.h"
-#include "logger.h"
+#include "util-logger.h"
#include "output.h"
#include "masscan-status.h"
#include "unusedparm.h"
diff --git a/src/proto-banner1.c b/src/proto-banner1.c
index 08f8b838..ddcd5ae4 100644
--- a/src/proto-banner1.c
+++ b/src/proto-banner1.c
@@ -4,7 +4,7 @@
#include "smack.h"
#include "rawsock-pcapfile.h"
#include "proto-preprocess.h"
-#include "proto-interactive.h"
+#include "stack-tcp-api.h"
#include "proto-banner1.h"
#include "proto-http.h"
#include "proto-ssl.h"
@@ -18,10 +18,12 @@
#include "proto-pop3.h"
#include "proto-vnc.h"
#include "proto-memcached.h"
+#include "proto-mc.h"
+#include "proto-versioning.h"
#include "masscan-app.h"
#include "scripting.h"
-#include "versioning.h"
#include "util-malloc.h"
+#include "util-logger.h"
#include
#include
#include
@@ -42,6 +44,7 @@ struct Patterns patterns[] = {
{"\x83\x00\x00\x01\x8f", 5, PROTO_SMB, SMACK_ANCHOR_BEGIN, 0}, /* Unspecified error */
/* ...the remainder can be in any order */
+ {"{\x22", 2, PROTO_MC, 0, 0},
{"SSH-1.", 6, PROTO_SSH1, SMACK_ANCHOR_BEGIN, 0},
{"SSH-2.", 6, PROTO_SSH2, SMACK_ANCHOR_BEGIN, 0},
{"HTTP/1.", 7, PROTO_HTTP, SMACK_ANCHOR_BEGIN, 0},
@@ -110,10 +113,10 @@ struct Patterns patterns[] = {
unsigned
banner1_parse(
const struct Banner1 *banner1,
- struct ProtocolState *tcb_state,
+ struct StreamState *tcb_state,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
size_t x;
unsigned offset = 0;
@@ -127,10 +130,10 @@ banner1_parse(
banner1->smack,
&tcb_state->state,
px, &offset, (unsigned)length);
- if (x != SMACK_NOT_FOUND)
- proto = patterns[x].id;
- else
+ if (x == SMACK_NOT_FOUND)
proto = 0xFFFFFFFF;
+ else
+ proto = patterns[x].id;
if (proto != 0xFFFFFFFF
&& !(proto == PROTO_SSL3 && !tcb_state->is_sent_sslhello)) {
unsigned i;
@@ -169,14 +172,14 @@ banner1_parse(
tcb_state,
s, s_len,
banout,
- more);
+ socket);
}
banner1_parse(
banner1,
tcb_state,
px, length,
banout,
- more);
+ socket);
} else {
banout_append(banout, PROTO_HEUR, px, length);
}
@@ -187,7 +190,7 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
break;
case PROTO_SMTP:
banner_smtp.parse( banner1,
@@ -195,7 +198,7 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
break;
case PROTO_TELNET:
@@ -204,7 +207,7 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
break;
case PROTO_RDP:
banner_rdp.parse( banner1,
@@ -212,7 +215,7 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
break;
case PROTO_POP3:
banner_pop3.parse( banner1,
@@ -220,7 +223,7 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
break;
case PROTO_IMAP4:
banner_imap4.parse(banner1,
@@ -228,7 +231,7 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
break;
case PROTO_SSH1:
@@ -241,7 +244,7 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
break;
case PROTO_HTTP:
banner_http.parse(
@@ -250,7 +253,7 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
break;
case PROTO_SSL3:
banner_ssl.parse(
@@ -259,7 +262,7 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
break;
case PROTO_SMB:
banner_smb1.parse(
@@ -268,7 +271,7 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
break;
case PROTO_VNC_RFB:
banner_vnc.parse( banner1,
@@ -276,7 +279,7 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
break;
case PROTO_MEMCACHED:
banner_memcached.parse( banner1,
@@ -284,7 +287,7 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
break;
case PROTO_SCRIPTING:
banner_scripting.parse( banner1,
@@ -292,7 +295,7 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
break;
case PROTO_VERSIONING:
banner_versioning.parse( banner1,
@@ -300,7 +303,16 @@ banner1_parse(
tcb_state,
px, length,
banout,
- more);
+ socket);
+ break;
+ case PROTO_MC:
+ banner_mc.parse(
+ banner1,
+ banner1->http_fields,
+ tcb_state,
+ px, length,
+ banout,
+ socket);
break;
default:
@@ -312,6 +324,170 @@ banner1_parse(
return tcb_state->app_proto;
}
+/*
+ * Simple banners with hello probes from nmap-service-probes
+ */
+
+static const char
+genericlines_hello[] = "\r\n\r\n";
+
+struct ProtocolParserStream banner_genericlines = {
+ "banner-GenericLines", 1098, genericlines_hello, sizeof(genericlines_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+x11_hello[] = "\x6C\0\x0B\0\0\0\0\0\0\0\0\0";
+
+struct ProtocolParserStream banner_x11 = {
+ "banner-X11Probe", 6000, x11_hello, sizeof(x11_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+javarmi_hello[] = "\x4a\x52\x4d\x49\0\x02\x4b";
+
+struct ProtocolParserStream banner_javarmi = {
+ "banner-JavaRMI", 1098, javarmi_hello, sizeof(javarmi_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+mongodb_hello[] = "\x41\0\0\0\x3a\x30\0\0\xff\xff\xff\xff\xd4\x07\0\0\0\0\0\0test.$cmd\0\0\0\0\0\xff\xff\xff\xff\x1b\0\0\0\x01serverStatus\0\0\0\0\0\0\0\xf0\x3f\0";
+
+struct ProtocolParserStream banner_mongodb = {
+ "banner-mongodb", 27017, mongodb_hello, sizeof(mongodb_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+kerberos_hello[] = "\0\0\0\x71\x6a\x81\x6e\x30\x81\x6b\xa1\x03\x02\x01\x05\xa2\x03\x02\x01\x0a\xa4\x81\x5e\x30\x5c\xa0\x07\x03\x05\0\x50\x80\0\x10\xa2\x04\x1b\x02NM\xa3\x17\x30\x15\xa0\x03\x02\x01\0\xa1\x0e\x30\x0c\x1b\x06krbtgt\x1b\x02NM\xa5\x11\x18\x0f""19700101000000Z\xa7\x06\x02\x04\x1f\x1e\xb9\xd9\xa8\x17\x30\x15\x02\x01\x12\x02\x01\x11\x02\x01\x10\x02\x01\x17\x02\x01\x01\x02\x01\x03\x02\x01\x02";
+
+struct ProtocolParserStream banner_kerberos = {
+ "banner-Kerberos", 88, kerberos_hello, sizeof(kerberos_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+dicom_hello[] = "\x01\x00\x00\x00\x00\xcd\x00\x01\x00\x00""ANY-SCP ECHOSCU 0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x15""1.2.840.10008.3.1.1.1 \x00\x00.\x01\x00\x00\x00""0\x00\x00\x11""1.2.840.10008.1.1@\x00\x00\x11""1.2.840.10008.1.2P\x00\x00:Q\x00\x00\x04\x00\x00@\x00R\x00\x00\x1b""1.2.276.0.7230010.3.0.3.6.2U\x00\x00\x0fOFFIS_DCMTK_362";
+
+struct ProtocolParserStream banner_dicom = {
+ "banner-dicom", 104, dicom_hello, sizeof(dicom_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+ldap_hello[] = "\x30\x84\x00\x00\x00\x2d\x02\x01\x07\x63\x84\x00\x00\x00\x24\x04\x00\x0a\x01\x00\x0a\x01\x00\x02\x01\x00\x02\x01\x64\x01\x01\x00\x87\x0b\x6f\x62\x6a\x65\x63\x74\x43\x6c\x61\x73\x73\x30\x84\x00\x00\x00\x00";
+
+struct ProtocolParserStream banner_ldap = {
+ "banner-LDAPSearchReq", 389, ldap_hello, sizeof(ldap_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+sip_hello[] = "OPTIONS sip:nm SIP/2.0\r\nVia: SIP/2.0/TCP nm;branch=foo\r\nFrom: ;tag=root\r\nTo: \r\nCall-ID: 50000\r\nCSeq: 42 OPTIONS\r\nMax-Forwards: 70\r\nContent-Length: 0\r\nContact: \r\nAccept: application/sdp\r\n\r\n";
+
+struct ProtocolParserStream banner_sip = {
+ "banner-SIPOptions", 5060, sip_hello, sizeof(sip_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+rtsp_hello[] = "OPTIONS / RTSP/1.0\r\n\r\n";
+
+struct ProtocolParserStream banner_rtsp = {
+ "banner-RTSPRequest", 554, rtsp_hello, sizeof(rtsp_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+rpc_hello[] = "\x80\0\0\x28\x72\xFE\x1D\x13\0\0\0\0\0\0\0\x02\0\x01\x86\xA0\0\x01\x97\x7C\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+
+struct ProtocolParserStream banner_rpc = {
+ "banner-RPCCheck", 111, rpc_hello, sizeof(rpc_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+dns_hello[] = "\0\x1E\0\x06\x01\0\0\x01\0\0\0\0\0\0\x07version\x04""bind\0\0\x10\0\x03";
+
+struct ProtocolParserStream banner_dns = {
+ "banner-DNSVersionBindReqTCP", 53, dns_hello, sizeof(dns_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+docker_hello[] = "GET /version HTTP/1.1\r\n\r\n";
+
+struct ProtocolParserStream banner_docker = {
+ "banner-docker", 2375, docker_hello, sizeof(docker_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+redis_hello[] = "*1\r\n$4\r\ninfo\r\n";
+
+struct ProtocolParserStream banner_redis = {
+ "banner-redis-server", 6379, redis_hello, sizeof(redis_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+notes_rpc_hello[] = "\x3A\x00\x00\x00\x2F\x00\x00\x00\x02\x00\x00\x40\x02\x0F\x00\x01\x00\x3D\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x1F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
+
+struct ProtocolParserStream banner_notes_rpc = {
+ "banner-NotesRPC", 6379, notes_rpc_hello, sizeof(notes_rpc_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+ms_sql_s_hello[] = "\x12\x01\x00\x34\x00\x00\x00\x00\x00\x00\x15\x00\x06\x01\x00\x1b\x00\x01\x02\x00\x1c\x00\x0c\x03\x00\x28\x00\x04\xff\x08\x00\x01\x55\x00\x00\x00\x4d\x53\x53\x51\x4c\x53\x65\x72\x76\x65\x72\x00\x48\x0f\x00\x00";
+
+struct ProtocolParserStream banner_ms_sql_s = {
+ "banner-ms-sql-s", 6379, ms_sql_s_hello, sizeof(ms_sql_s_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const char
+afp_hello[] = "\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x0f\x00";
+
+struct ProtocolParserStream banner_afp = {
+ "banner-afp", 548, afp_hello, sizeof(afp_hello) - 1, 0,
+ NULL,
+ NULL,
+ NULL,
+};
+
/***************************************************************************
* Create the --banners systems
@@ -347,6 +523,10 @@ banner1_create(void)
b->payloads.tcp[8080] = &banner_http;
b->payloads.tcp[139] = (void*)&banner_smb0;
b->payloads.tcp[445] = (void*)&banner_smb1;
+ b->payloads.tcp[8530] = (void*)&banner_http; /* WSUS */
+ b->payloads.tcp[8531] = (void*)&banner_ssl; /* WSUS/s */
+ /* https://www.nomotion.net/blog/sharknatto/ */
+ b->payloads.tcp[49955] = (void*)&banner_ssl; /* AT&T box */
b->payloads.tcp[443] = (void*)&banner_ssl; /* HTTP/s */
b->payloads.tcp[465] = (void*)&banner_ssl; /* SMTP/s */
b->payloads.tcp[990] = (void*)&banner_ssl; /* FTP/s */
@@ -364,7 +544,69 @@ banner1_create(void)
b->payloads.tcp[11211] = (void*)&banner_memcached;
b->payloads.tcp[23] = (void*)&banner_telnet;
b->payloads.tcp[3389] = (void*)&banner_rdp;
-
+
+ b->payloads.tcp[1098] = (void*)&banner_javarmi;
+ b->payloads.tcp[1099] = (void*)&banner_javarmi;
+ for (i=0; i < 20; i++) {
+ b->payloads.tcp[6000 + i] = (void*)&banner_x11;
+ }
+ b->payloads.tcp[88] = (void*)&banner_kerberos;
+ b->payloads.tcp[9001] = (void*)&banner_mongodb;
+ b->payloads.tcp[27017] = (void*)&banner_mongodb;
+ b->payloads.tcp[49153] = (void*)&banner_mongodb;
+ b->payloads.tcp[104] = (void*)&banner_dicom;
+ b->payloads.tcp[2345] = (void*)&banner_dicom;
+ b->payloads.tcp[2761] = (void*)&banner_dicom;
+ b->payloads.tcp[2762] = (void*)&banner_dicom;
+ b->payloads.tcp[4242] = (void*)&banner_dicom;
+ b->payloads.tcp[11112] = (void*)&banner_dicom;
+ b->payloads.tcp[256] = (void*)&banner_ldap;
+ b->payloads.tcp[257] = (void*)&banner_ldap;
+ b->payloads.tcp[389] = (void*)&banner_ldap;
+ b->payloads.tcp[390] = (void*)&banner_ldap;
+ b->payloads.tcp[1702] = (void*)&banner_ldap;
+ b->payloads.tcp[3268] = (void*)&banner_ldap;
+ b->payloads.tcp[3892] = (void*)&banner_ldap;
+ b->payloads.tcp[11711] = (void*)&banner_ldap;
+ /* LDAP/s */
+ b->payloads.tcp[636] = (void*)&banner_ssl;
+ b->payloads.tcp[637] = (void*)&banner_ssl;
+ b->payloads.tcp[3269] = (void*)&banner_ssl;
+ b->payloads.tcp[11712] = (void*)&banner_ssl;
+ b->payloads.tcp[406] = (void*)&banner_sip;
+ b->payloads.tcp[5060] = (void*)&banner_sip;
+ b->payloads.tcp[8081] = (void*)&banner_sip;
+ b->payloads.tcp[31337] = (void*)&banner_sip;
+ /* SIP/s */
+ b->payloads.tcp[5061] = (void*)&banner_ssl;
+ b->payloads.tcp[554] = (void*)&banner_rtsp;
+ b->payloads.tcp[8554] = (void*)&banner_rtsp;
+ /* RTSP/s */
+ b->payloads.tcp[322] = (void*)&banner_ssl;
+ b->payloads.tcp[111] = (void*)&banner_rpc;
+ b->payloads.tcp[2049] = (void*)&banner_rpc;
+ b->payloads.tcp[53] = (void*)&banner_dns;
+ b->payloads.tcp[135] = (void*)&banner_dns;
+ b->payloads.tcp[50000] = (void*)&banner_dns;
+ b->payloads.tcp[50001] = (void*)&banner_dns;
+ b->payloads.tcp[50002] = (void*)&banner_dns;
+ b->payloads.tcp[2375] = (void*)&banner_docker;
+ /* Docker/s */
+ b->payloads.tcp[2376] = (void*)&banner_ssl;
+ b->payloads.tcp[2379] = (void*)&banner_docker;
+ b->payloads.tcp[2380] = (void*)&banner_docker;
+ b->payloads.tcp[6379] = (void*)&banner_redis;
+ b->payloads.tcp[130] = (void*)&banner_notes_rpc;
+ b->payloads.tcp[427] = (void*)&banner_notes_rpc;
+ b->payloads.tcp[1352] = (void*)&banner_notes_rpc;
+ b->payloads.tcp[1972] = (void*)&banner_notes_rpc;
+ b->payloads.tcp[7171] = (void*)&banner_notes_rpc;
+ b->payloads.tcp[8728] = (void*)&banner_notes_rpc;
+ b->payloads.tcp[22001] = (void*)&banner_notes_rpc;
+ b->payloads.tcp[1433] = (void*)&banner_ms_sql_s;
+ /* AFP */
+ b->payloads.tcp[548] = (void*)&banner_afp;
+
/*
* This goes down the list of all the TCP protocol handlers and initializes
* them.
@@ -377,15 +619,17 @@ banner1_create(void)
banner_smtp.init(b);
banner_ssh.init(b);
banner_ssl.init(b);
+ banner_ssl_12.init(b);
banner_smb0.init(b);
banner_smb1.init(b);
banner_telnet.init(b);
banner_rdp.init(b);
banner_vnc.init(b);
-
+ banner_mc.init(b);
+
/* scripting/versioning come after the rest */
- banner_scripting.init(b);
- banner_versioning.init(b);
+ //banner_scripting.init(b);
+ //banner_versioning.init(b);
return b;
@@ -463,7 +707,7 @@ banner1_selftest()
{
unsigned i;
struct Banner1 *b;
- struct ProtocolState tcb_state[1];
+ struct StreamState tcb_state[1];
const unsigned char *px;
unsigned length;
struct BannerOutput banout[1];
@@ -483,6 +727,8 @@ banner1_selftest()
length = (unsigned)strlen(http_header);
+ LOG(1, "[ ] banners: selftesting\n");
+
/*
* First, test the "banout" subsystem
*/
@@ -501,7 +747,7 @@ banner1_selftest()
memset(tcb_state, 0, sizeof(tcb_state[0]));
for (i=0; i
#include
#include
+#include
/***************************************************************************
***************************************************************************/
@@ -284,6 +285,44 @@ banout_expand(struct BannerOutput *banout, struct BannerOutput *p)
return n;
}
+
+
+
+
+
+/***************************************************************************
+ ***************************************************************************/
+static void
+banout_vprintf(struct BannerOutput *banout, unsigned proto,
+ const char *fmt, va_list marker) {
+ char str[10];
+ int len;
+ va_list marker_cpy; // a va_list is consumed when passed to vsnprintf.
+
+ va_copy(marker_cpy, marker);
+ len = vsnprintf(str, sizeof(str), fmt, marker_cpy);
+ va_end(marker_cpy);
+ if (len > sizeof(str)-1) {
+ char *tmp = malloc(len+1);
+ vsnprintf(tmp, len+1, fmt, marker);
+ banout_append(banout, proto, tmp, len);
+ free(tmp);
+ } else {
+ banout_append(banout, proto, str, len);
+ }
+}
+
+/***************************************************************************
+ ***************************************************************************/
+void
+banout_printf(struct BannerOutput *banout, unsigned proto, const char *fmt, ...) {
+ va_list marker;
+
+ va_start(marker, fmt);
+ banout_vprintf(banout, proto, fmt, marker);
+ va_end(marker);
+}
+
/***************************************************************************
***************************************************************************/
void
diff --git a/src/proto-banout.h b/src/proto-banout.h
index d583efc8..6c5361c2 100644
--- a/src/proto-banout.h
+++ b/src/proto-banout.h
@@ -59,6 +59,9 @@ void
banout_append(struct BannerOutput *banout, unsigned proto, const void *px, size_t length);
#define AUTO_LEN ((size_t)~0)
+void
+banout_printf(struct BannerOutput *banout, unsigned proto, const char *fmt, ...);
+
/**
* Append a single character to the banner.
*/
diff --git a/src/proto-coap.c b/src/proto-coap.c
index c9a7c9a1..ea2bfdc3 100644
--- a/src/proto-coap.c
+++ b/src/proto-coap.c
@@ -30,17 +30,17 @@
#include "proto-banner1.h"
#include "smack.h"
#include "unusedparm.h"
-#include "logger.h"
+#include "util-logger.h"
#include "masscan-app.h"
#include "output.h"
-#include "proto-interactive.h"
+#include "stack-tcp-api.h"
#include "proto-preprocess.h"
#include "proto-ssl.h"
#include "proto-udp.h"
#include "syn-cookie.h"
#include "massip-port.h"
#include "util-malloc.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include "util-bool.h"
#include
#include
@@ -352,7 +352,7 @@ coap_parse(const unsigned char *px, size_t length, struct BannerOutput *banout,
/* Response code */
{
char buf[64];
- sprintf_s(buf, sizeof(buf), "rsp=%u.%u(%s)", code>>5, code&0x1F, response_code(code));
+ snprintf(buf, sizeof(buf), "rsp=%u.%u(%s)", code>>5, code&0x1F, response_code(code));
banout_append(banout, PROTO_COAP, buf, AUTO_LEN);
//code >>= 5;
}
@@ -361,7 +361,7 @@ coap_parse(const unsigned char *px, size_t length, struct BannerOutput *banout,
/* If there was a token, the print it. */
if (token) {
char buf[64];
- sprintf_s(buf, sizeof(buf), " token=0x%llu", token);
+ snprintf(buf, sizeof(buf), " token=0x%llu", token);
banout_append(banout, PROTO_COAP, buf, AUTO_LEN);
}
diff --git a/src/proto-dns.c b/src/proto-dns.c
index 95817b6a..9f391333 100644
--- a/src/proto-dns.c
+++ b/src/proto-dns.c
@@ -10,7 +10,7 @@
#include "proto-dns-parse.h"
#include "proto-preprocess.h"
#include "syn-cookie.h"
-#include "logger.h"
+#include "util-logger.h"
#include "output.h"
#include "masscan-app.h"
#include "proto-banner1.h"
@@ -444,8 +444,6 @@ handle_dns(struct Output *out, time_t timestamp,
PROTO_DNS_VERSIONBIND,
parsed->ip_ttl,
px + offset, txtlen);
+ return 1;
}
-
-
- return 0;
}
diff --git a/src/proto-ftp.c b/src/proto-ftp.c
index 94cbb9c0..45dc9bd5 100644
--- a/src/proto-ftp.c
+++ b/src/proto-ftp.c
@@ -2,7 +2,7 @@
#include "proto-banner1.h"
#include "unusedparm.h"
#include "masscan-app.h"
-#include "proto-interactive.h"
+#include "stack-tcp-api.h"
#include "proto-ssl.h"
#include
#include
@@ -13,10 +13,10 @@
static void
ftp_parse( const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
unsigned state = pstate->state;
unsigned i;
@@ -42,7 +42,7 @@ ftp_parse( const struct Banner1 *banner1,
case 103:
if (!isdigit(px[i]&0xFF)) {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
} else {
ftp->code *= 10;
ftp->code += (px[i] - '0');
@@ -62,7 +62,7 @@ ftp_parse( const struct Banner1 *banner1,
banout_append_char(banout, PROTO_FTP, px[i]);
} else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 5:
@@ -70,7 +70,7 @@ ftp_parse( const struct Banner1 *banner1,
continue;
else if (px[i] == '\n') {
if (ftp->is_last) {
- tcp_transmit(more, "AUTH TLS\r\n", 10, 0);
+ tcpapi_send(socket, "AUTH TLS\r\n", 10, 0);
state = 100;
banout_append_char(banout, PROTO_FTP, px[i]);
} else {
@@ -79,7 +79,7 @@ ftp_parse( const struct Banner1 *banner1,
}
} else if (px[i] == '\0' || !isprint(px[i])) {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
continue;
} else {
banout_append_char(banout, PROTO_FTP, px[i]);
@@ -100,15 +100,15 @@ ftp_parse( const struct Banner1 *banner1,
pstate->port = (unsigned short)port;
state = 0;
- tcp_transmit(more, banner_ssl.hello, banner_ssl.hello_length, 0);
+ tcpapi_send(socket, banner_ssl.hello, banner_ssl.hello_length, 0);
} else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
} else if (px[i] == '\0' || !isprint(px[i])) {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
continue;
} else {
banout_append_char(banout, PROTO_FTP, px[i]);
@@ -128,6 +128,7 @@ static void *
ftp_init(struct Banner1 *banner1)
{
UNUSEDPARM(banner1);
+ //banner1->payloads.tcp[21] = &banner_ftp;
return 0;
}
diff --git a/src/proto-http.c b/src/proto-http.c
index 4bb2a62c..671b5099 100644
--- a/src/proto-http.c
+++ b/src/proto-http.c
@@ -1,13 +1,13 @@
#include "proto-http.h"
#include "proto-banner1.h"
-#include "proto-interactive.h"
+#include "stack-tcp-api.h"
#include "smack.h"
#include "unusedparm.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include "masscan-app.h"
#include "util-malloc.h"
#include "util-bool.h"
-#include "proto-tcp.h"
+#include "stack-tcp-core.h"
#include
#include
#include
@@ -61,7 +61,8 @@ _http_append(unsigned char **inout_header, size_t length1, size_t length2, const
}
enum What {spaces, notspaces, end_of_line, end_of_field};
-size_t _skip(enum What what, const unsigned char *hdr, size_t offset, size_t header_length)
+static size_t
+_skip(enum What what, const unsigned char *hdr, size_t offset, size_t header_length)
{
switch (what) {
case notspaces:
@@ -221,7 +222,8 @@ http_change_requestline(unsigned char **hdr, size_t header_length,
return header_length;
}
-size_t _field_length(const unsigned char *hdr, size_t offset, size_t hdr_length)
+static size_t
+_field_length(const unsigned char *hdr, size_t offset, size_t hdr_length)
{
size_t original_offset = offset;
@@ -383,7 +385,11 @@ http_change_field(unsigned char **inout_header, size_t header_length,
***************************************************************************/
static const char
http_hello[] = "GET / HTTP/1.0\r\n"
- "User-Agent: masscan/1.3 (https://github.com/robertdavidgraham/masscan)\r\n"
+#ifdef IVRE_BUILD
+ "User-Agent: ivre-masscan/1.3 https://ivre.rocks/\r\n"
+#else
+ "User-Agent: ivre-masscan/1.3 https://github.com/robertdavidgraham/\r\n"
+#endif
"Accept: */*\r\n"
//"Connection: Keep-Alive\r\n"
//"Content-Length: 0\r\n"
@@ -482,10 +488,10 @@ static void
http_parse(
const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
unsigned state = pstate->state;
unsigned i;
@@ -506,7 +512,7 @@ http_parse(
};
UNUSEDPARM(banner1_private);
- UNUSEDPARM(more);
+ UNUSEDPARM(socket);
state2 = (state>>16) & 0xFFFF;
id = (state>>8) & 0xFF;
@@ -517,7 +523,7 @@ http_parse(
case 0: case 1: case 2: case 3: case 4:
if (toupper(px[i]) != "HTTP/"[state]) {
state = DONE_PARSING;
- tcp_close(more);
+ tcpapi_close(socket);
} else
state++;
break;
@@ -526,7 +532,7 @@ http_parse(
state++;
else if (!isdigit(px[i])) {
state = DONE_PARSING;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 6:
@@ -534,7 +540,7 @@ http_parse(
state++;
else if (!isdigit(px[i])) {
state = DONE_PARSING;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 7:
@@ -707,13 +713,12 @@ static int
http_selftest_parser(void)
{
struct Banner1 *banner1 = NULL;
- struct ProtocolState pstate[1];
+ struct StreamState pstate[1];
struct BannerOutput banout[1];
- struct InteractiveData more[1];
+
memset(pstate, 0, sizeof(pstate[0]));
memset(banout, 0, sizeof(banout[0]));
- memset(more, 0, sizeof(more[0]));
/*
* Test start
@@ -726,7 +731,7 @@ http_selftest_parser(void)
/*
* Run Test
*/
- http_parse(banner1, 0, pstate, (const unsigned char *)test_response, strlen(test_response), banout, more);
+ http_parse(banner1, 0, pstate, (const unsigned char *)test_response, strlen(test_response), banout, 0);
/*
diff --git a/src/proto-icmp.c b/src/proto-icmp.c
index 9c1bff7d..902c05a8 100644
--- a/src/proto-icmp.c
+++ b/src/proto-icmp.c
@@ -1,7 +1,7 @@
#include "proto-icmp.h"
#include "proto-preprocess.h"
#include "syn-cookie.h"
-#include "logger.h"
+#include "util-logger.h"
#include "output.h"
#include "masscan-status.h"
#include "massip-port.h"
@@ -36,8 +36,8 @@ parse_port_unreachable(const unsigned char *px, unsigned length,
*r_ip_them = px[16]<<24 | px[17]<<16 | px[18]<<8 | px[19];
*r_ip_proto = px[9]; /* TCP=6, UDP=17 */
- px += (px[0]&0xF)<<2;
length -= (px[0]&0xF)<<2;
+ px += (px[0]&0xF)<<2;
if (length < 4)
return -1;
@@ -53,6 +53,43 @@ parse_port_unreachable(const unsigned char *px, unsigned length,
* will be due to scans we are doing, like pings (echoes). Some will
* be inadvertent, such as "destination unreachable" messages.
***************************************************************************/
+int
+icmp_selftest(void)
+{
+ unsigned ip_me, ip_them, port_me, port_them, ip_proto;
+ int err;
+
+ /* bug 1: length inflated by 16 (+ instead of - 8 in handle_icmp).
+ * 16 bytes must be rejected; the bug would pass 32. */
+ static const unsigned char short_blob[] = {
+ 0x45, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x11, 0x00, 0x00,
+ 0x0a, 0x00, 0x00, 0x01, /* src IP only, dst IP absent */
+ };
+ err = parse_port_unreachable(short_blob, sizeof(short_blob),
+ &ip_me, &ip_them, &port_me, &port_them,
+ &ip_proto);
+ if (err != -1) return 1;
+
+ /* bug 2: px advanced before length decremented, using the wrong px[0].
+ * src-port high byte 0x06 (nibble=6): wrong order gives length 24-24=0 < 4. */
+ static const unsigned char blob[] = {
+ 0x45, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x11, 0x00, 0x00,
+ 0x0a, 0x00, 0x00, 0x01, /* src = 10.0.0.1 */
+ 0xc0, 0x00, 0x02, 0x01, /* dst = 192.0.2.1 */
+ 0x06, 0x40, /* src port = 1600 */
+ 0x00, 0x35, /* dst port = 53 */
+ };
+ err = parse_port_unreachable(blob, sizeof(blob),
+ &ip_me, &ip_them, &port_me, &port_them,
+ &ip_proto);
+ if (err != 0) return 1;
+ if (port_me != 1600) return 1;
+ if (port_them != 53) return 1;
+ return 0;
+}
+
void
handle_icmp(struct Output *out, time_t timestamp,
const unsigned char *px, unsigned length,
@@ -130,7 +167,7 @@ handle_icmp(struct Output *out, time_t timestamp,
err = parse_port_unreachable(
px + parsed->transport_offset + 8,
- length - parsed->transport_offset + 8,
+ length - parsed->transport_offset - 8,
&ip_me2.ipv4, &ip_them2.ipv4, &port_me2, &port_them2,
&ip_proto);
diff --git a/src/proto-icmp.h b/src/proto-icmp.h
index 0d4e8b2b..ce71abb3 100644
--- a/src/proto-icmp.h
+++ b/src/proto-icmp.h
@@ -6,8 +6,10 @@ struct PreprocessedInfo;
struct Output;
void handle_icmp(struct Output *out, time_t timestamp,
- const unsigned char *px, unsigned length,
+ const unsigned char *px, unsigned length,
struct PreprocessedInfo *parsed,
uint64_t entropy);
+int icmp_selftest(void);
+
#endif
diff --git a/src/proto-imap4.c b/src/proto-imap4.c
index fc0c2e3d..58c83883 100644
--- a/src/proto-imap4.c
+++ b/src/proto-imap4.c
@@ -9,7 +9,7 @@
#include "proto-banner1.h"
#include "unusedparm.h"
#include "masscan-app.h"
-#include "proto-interactive.h"
+#include "stack-tcp-api.h"
#include "proto-ssl.h"
#include
#include
@@ -20,10 +20,10 @@
static void
imap4_parse( const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
unsigned state = pstate->state;
unsigned i;
@@ -43,7 +43,7 @@ imap4_parse( const struct Banner1 *banner1,
state++;
else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 1:
@@ -52,7 +52,7 @@ imap4_parse( const struct Banner1 *banner1,
continue;
} else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
/* fall through */
case 2:
@@ -61,7 +61,7 @@ imap4_parse( const struct Banner1 *banner1,
state++;
else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 3:
@@ -70,7 +70,7 @@ imap4_parse( const struct Banner1 *banner1,
state++;
else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 4:
@@ -89,7 +89,7 @@ imap4_parse( const struct Banner1 *banner1,
case 5:
banout_append_char(banout, PROTO_IMAP4, px[i]);
if (px[i] == '\n') {
- tcp_transmit(more, "a001 CAPABILITY\r\n", 17, 0);
+ tcpapi_send(socket, "a001 CAPABILITY\r\n", 17, 0);
state = 100;
}
break;
@@ -102,7 +102,7 @@ imap4_parse( const struct Banner1 *banner1,
state++;
else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 101:
@@ -112,7 +112,7 @@ imap4_parse( const struct Banner1 *banner1,
state++;
else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 102:
@@ -122,7 +122,7 @@ imap4_parse( const struct Banner1 *banner1,
state++;
else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 103:
@@ -131,7 +131,7 @@ imap4_parse( const struct Banner1 *banner1,
state++;
else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 303:
@@ -140,7 +140,7 @@ imap4_parse( const struct Banner1 *banner1,
state++;
else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 104:
@@ -150,13 +150,13 @@ imap4_parse( const struct Banner1 *banner1,
state++;
else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 105:
banout_append_char(banout, PROTO_IMAP4, px[i]);
if (px[i] == '\n') {
- tcp_transmit(more, "a002 STARTTLS\r\n", 15, 0);
+ tcpapi_send(socket, "a002 STARTTLS\r\n", 15, 0);
state = 300;
}
break;
@@ -178,7 +178,7 @@ imap4_parse( const struct Banner1 *banner1,
pstate->port = (unsigned short)port;
state = 0;
- tcp_transmit(more, banner_ssl.hello, banner_ssl.hello_length, 0);
+ tcpapi_send(socket, banner_ssl.hello, banner_ssl.hello_length, 0);
break;
}
break;
diff --git a/src/proto-interactive.c b/src/proto-interactive.c
deleted file mode 100644
index 9a3d4ac8..00000000
--- a/src/proto-interactive.c
+++ /dev/null
@@ -1,41 +0,0 @@
-#include "proto-interactive.h"
-#include "unusedparm.h"
-#include "util-malloc.h"
-#include
-
-/*
- * TODO: we need to track the memory used for this better than with malloc(), such
- * as using a preallocated array of packet buffers. But for now, I'm just using
- * malloc() 'cause I'm a lazy programmer.
- */
-unsigned char *
-tcp_transmit_alloc(struct InteractiveData *more, size_t length)
-{
- /* Note using this parameter yet, but in the future, we are going to have
- * memory pools instead of heap malloc(), which will use this parameter */
- UNUSEDPARM(more);
-
- return MALLOC(length);
-}
-
-void
-tcp_close(struct InteractiveData *more)
-{
- if (more == NULL)
- return;
- more->is_closing = 1;
-}
-
-/*
- * This doesn't actually transmit right now. Instead, marks the payload as ready
- * to transmit, which will be transmitted later
- */
-void
-tcp_transmit(struct InteractiveData *more, const void *payload, size_t length, unsigned flags)
-{
- more->m_payload = payload;
- more->m_length = (unsigned)length;
-
- if (flags & TCPTRAN_DYNAMIC)
- more->is_payload_dynamic = 1;
-}
diff --git a/src/proto-interactive.h b/src/proto-interactive.h
deleted file mode 100644
index 4813f3ea..00000000
--- a/src/proto-interactive.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef PROTO_INTERACTIVE_H
-#define PROTO_INTERACTIVE_H
-#include
-
-struct InteractiveData {
- const void *m_payload;
- unsigned m_length;
- unsigned is_payload_dynamic:1;
- unsigned is_closing:1;
-};
-enum {
- TCPTRAN_DYNAMIC = 0x0001,
-};
-
-/**
- * Called to 'transmit' TCP packet payload.
- */
-void
-tcp_transmit(struct InteractiveData *more, const void *data, size_t length, unsigned flags);
-
-/**
- * Called to close the connection
- */
-void
-tcp_close(struct InteractiveData *more);
-
-/**
- * Called to allocate a TCP buffer.
- */
-unsigned char *
-tcp_transmit_alloc(struct InteractiveData *more, size_t length);
-
-#endif
diff --git a/src/proto-isakmp.c b/src/proto-isakmp.c
new file mode 100644
index 00000000..b3cd9087
--- /dev/null
+++ b/src/proto-isakmp.c
@@ -0,0 +1,580 @@
+/* ISAKMP protocol support
+
+ 1 2 3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+! Initiator !
+! Cookie !
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+! Responder !
+! Cookie !
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags !
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+! Message ID !
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+! Length !
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+ */
+
+#include "proto-isakmp.h"
+#include "proto-banout.h"
+#include "proto-preprocess.h"
+#include "syn-cookie.h"
+#include "massip-port.h"
+#include "output.h"
+#include "util-extract.h"
+#include "util-logger.h"
+#include
+#include
+
+typedef struct payload_t {
+ unsigned char next;
+ unsigned char reserved;
+ size_t length;
+ struct ebuf_t ebuf;
+} payload_t;
+
+static payload_t
+_get_payload(const struct ebuf_t *ebuf) {
+ payload_t result = {0};
+ result.ebuf = *ebuf;
+ result.next = e_next_byte(&result.ebuf);
+ result.reserved = e_next_byte(&result.ebuf);
+ result.length = e_next_short16(&result.ebuf, EBUF_BE);
+
+ if (result.length >= 4) {
+ result.ebuf.max = result.ebuf.offset + result.length - 4;
+ }
+ return result;
+}
+
+static unsigned
+_parse_transform(struct BannerOutput *banout,
+ unsigned proto,
+ struct ebuf_t in_ebuf) {
+ struct ebuf_t *ebuf = &in_ebuf;
+ unsigned transform_id;
+
+
+ e_next_byte(ebuf); /* transform number */
+ transform_id = e_next_byte(ebuf);
+ switch (transform_id) {
+ case 1: {
+ banout_printf(banout, proto, "trans=IKE ");
+ e_next_short16(ebuf, EBUF_BE); /* reserved */
+ while (ebuf->offset < ebuf->max) {
+ unsigned x = e_next_short16(ebuf, EBUF_BE);
+ unsigned val = e_next_short16(ebuf, EBUF_BE);
+ if ((x & 0x8000) == 0)
+ return 1;
+ switch (x&0x7fff) {
+ case 1: /* encryption algorithm */
+ switch (val) {
+ case 5:
+ banout_printf(banout, proto, "%s ", "3DES-CBC");
+ break;
+ case 7:
+ banout_printf(banout, proto, "%s ", "AES-CBC");
+ break;
+ default:
+ banout_printf(banout, proto, "encrypt=0x%x ", val);
+ break;
+ }
+ break;
+ case 2: /* hash algorithm */
+ switch (val) {
+ case 2:
+ banout_printf(banout, proto, "%s ", "SHA");
+ break;
+ default:
+ banout_printf(banout, proto, "hash=0x%x ", val);
+ break;
+ }
+ break;
+ case 3: /* auth */
+ switch (val) {
+ case 1:
+ banout_printf(banout, proto, "%s ", "PSK");
+ break;
+ case 5:
+ banout_printf(banout, proto, "%s ", "PSK");
+ break;
+ default:
+ banout_printf(banout, proto, "auth=0x%x ", val);
+ break;
+ }
+ break;
+ case 4: /* group */
+ break;
+ case 11: /* life type */
+ break;
+ case 12: /* life duration*/
+ break;
+ case 14: /* key length */
+ banout_printf(banout, proto, "key=%ubits ", val);
+ break;
+ default:
+ banout_printf(banout, proto, "val=0x%04x%04x ", x&0x7fff, val);
+ break;
+
+ }
+ }
+ }
+ break;
+ default:
+ banout_printf(banout, proto, "trans=%u ", transform_id);
+ break;
+ }
+ return 1;
+}
+
+static unsigned
+_parse_transforms(struct BannerOutput *banout,
+ unsigned proto,
+ struct ebuf_t ebuf,
+ unsigned next_payload
+ ) {
+
+ while (ebuf.offset + 4 <= ebuf.max) {
+ payload_t payload = _get_payload(&ebuf);
+ _parse_transform(banout, proto, payload.ebuf);
+
+ /* loop around */
+ ebuf.offset += payload.length;
+ next_payload = payload.next;
+ if (next_payload == 0)
+ break;
+ }
+ return 0;
+}
+
+static unsigned
+_parse_proposal(struct BannerOutput *banout,
+ unsigned proto,
+ struct ebuf_t ebuf) {
+ unsigned proto_id;
+
+
+ banout_printf(banout, proto, "%u ", e_next_byte(&ebuf));
+ proto_id = e_next_byte(&ebuf);
+ switch (proto_id) {
+ case 1:
+ banout_printf(banout, proto, "id=ISAKMP ");
+ break;
+ default:
+ banout_printf(banout, proto, "id=%u ", proto_id);
+ break;
+ }
+ e_next_byte(&ebuf); /* spi size */
+ e_next_byte(&ebuf); /* proposal transforms */
+
+ _parse_transforms(banout, proto, ebuf, 0);
+
+ return 1;
+}
+
+static unsigned
+_parse_proposals(struct BannerOutput *banout,
+ unsigned proto,
+ struct ebuf_t ebuf,
+ unsigned next_payload
+ ) {
+
+ while (ebuf.offset + 4 <= ebuf.max) {
+ payload_t payload = _get_payload(&ebuf);
+ _parse_proposal(banout, proto, payload.ebuf);
+
+ /* loop around */
+ ebuf.offset += payload.length;
+ next_payload = payload.next;
+ if (next_payload == 0)
+ break;
+ }
+ return 0;
+}
+
+static unsigned
+_payload_security_association(struct BannerOutput *banout, unsigned proto, struct ebuf_t ebuf) {
+ unsigned doi;
+ unsigned bitmap;
+
+ doi = e_next_int32(&ebuf, EBUF_BE);
+ bitmap = e_next_int32(&ebuf, EBUF_BE);
+ switch (doi) {
+ case 0: /* generic */
+ banout_printf(banout, proto, "DOI=generic ");
+ break;
+ case 1: /* IPsec */
+ banout_printf(banout, proto, "DOI=ipsec ");
+ if (bitmap & 0x00000001)
+ banout_printf(banout, proto, "IDENTITY ");
+ if (bitmap & 0x00000002)
+ banout_printf(banout, proto, "SECRECY ");
+ if (bitmap & 0x00000004)
+ banout_printf(banout, proto, "INTEGRITY ");
+ _parse_proposals(banout, proto, ebuf, 0);
+ break;
+ default:
+ banout_printf(banout, proto, "DOI=%u ", doi);
+ break;
+ }
+ return 1;
+}
+
+static unsigned
+_payload_vendor_id(struct BannerOutput *banout, unsigned proto, struct ebuf_t ebuf) {
+ size_t i;
+ size_t length = ebuf.max - ebuf.offset;
+ struct {
+ unsigned length;
+ const char *vendor;
+ const char *name;
+ } vendors[] = {
+ {16, "\x4a\x13\x1c\x81\x07\x03\x58\x45\x5c\x57\x28\xf2\x0e\x95\x45\x2f", "RFC-39947-NAT"},
+ {16, "\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00", "CISCO-UNITY"},
+ {16, "\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00", "RFC3706-DPD"},
+ {8, "\x09\x00" "&\x89\xdf\xd6\xb7\x12", "XAUTH"},
+ {0,0}
+ };
+
+ for (i=0; vendors[i].length; i++) {
+ if (length != vendors[i].length)
+ continue;
+ if (memcmp(vendors[i].vendor, ebuf.buf + ebuf.offset, length) == 0) {
+ banout_printf(banout, proto, "{%s} ", vendors[i].name);
+ break;
+ }
+ }
+ return 1;
+}
+
+
+static unsigned
+_parse_response(struct BannerOutput *banout, unsigned proto,
+ const unsigned char *px, size_t length
+ ) {
+ struct ebuf_t ebuf[1] = {{px, 0, length}};
+ unsigned next_payload;
+ unsigned version;
+ unsigned flags;
+ unsigned exchange_type;
+ unsigned my_length;
+ static const char *payload_names[] = {
+ "[0]", "[SEC-ASSOC]", "[2]", "[3]",
+ "[KEY-XCHG]", "[5]", "[6]", "[7]",
+ "[8]", "[9]", "[NONCE]", "[11]",
+ "[12]", ""/*vendor-id*/, "[14]", "[15]",
+ "[16]", "[17]", "[18]", "[19]",
+ "[NAT-D]", "[21]", "[22]", "[23]",
+ "[24]", "[25]", "[26]", "[27]",
+ "[28]", "[29]", "[30]", "[31]",
+ };
+
+
+
+ /*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Initiator !
+ ! Cookie !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Responder !
+ ! Cookie !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Message ID !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ /* Skip the cookies */
+ e_next_long64(ebuf, EBUF_BE);
+ e_next_long64(ebuf, EBUF_BE);
+
+ /* Parse the header */
+ next_payload = e_next_byte(ebuf);
+ version = e_next_byte(ebuf);
+ exchange_type = e_next_byte(ebuf);
+ flags = e_next_byte(ebuf); /* flags */
+ e_next_int32(ebuf, 0);
+ my_length = e_next_int32(ebuf, EBUF_BE);
+ if (ebuf->max >= my_length)
+ ebuf->max = my_length;
+ banout_printf(banout, proto, "v%u.%u ", (version>>4)&0xF, version&0xF);
+ switch (exchange_type) {
+ case 2:
+ banout_printf(banout, proto, "xchg=id-prot ");
+ break;
+ default:
+ banout_printf(banout, proto, "xchg=%u ", exchange_type);
+ break;
+ }
+
+ if (flags & 1) {
+ banout_printf(banout, proto, "ENCRYPTED ", exchange_type);
+ return 1;
+ }
+
+ /*
+ * Enumerate all the payloads
+ */
+ while (next_payload && ebuf->offset + 4 <= ebuf->max) {
+
+ /*
+ * Parse this payload-header
+ */
+ payload_t payload = _get_payload(ebuf);
+
+
+ /*
+ * Print the payload name if it's in our list of known names,
+ * or print a number if it isn't
+ */
+ if (next_payload < sizeof(payload_names)/sizeof(payload_names[0]))
+ banout_printf(banout, proto, "%s ", payload_names[next_payload]);
+ else
+ banout_printf(banout, proto, "[%u] ", next_payload);
+
+
+ /*
+ * Handle the individual payload if it's a known type
+ */
+ switch (next_payload) {
+ case 1:
+ _payload_security_association(banout, proto, payload.ebuf);
+ break;
+ case 4: /* key exchange */
+ //banout_printf(banout, proto, "KEY-EXCH ");
+ break;
+ case 10: /* nonce */
+ //banout_printf(banout, proto, "NONCE ");
+ break;
+ case 13: /* vendir id */
+ _payload_vendor_id(banout, proto, payload.ebuf);
+ break;
+ case 20:
+ //banout_printf(banout, proto, "NAT-D ");
+ break;
+ default:
+ break;
+
+ }
+
+ /*
+ * Loop around to the next payload
+ */
+ ebuf->offset += payload.length;
+ next_payload = payload.next;
+ }
+ return 1;
+}
+
+unsigned
+isakmp_parse(struct Output *out, time_t timestamp,
+ const unsigned char *px, unsigned length,
+ struct PreprocessedInfo *parsed,
+ uint64_t entropy
+ )
+{
+ ipaddress ip_them;
+ ipaddress ip_me;
+ unsigned port_them = parsed->port_src;
+ unsigned port_me = parsed->port_dst;
+ uint64_t cookie;
+ uint64_t resp_cookie;
+
+ /* All responses will be at least 8 bytes */
+ if (length < 16)
+ return 0;
+
+ /* Grab IP addresses */
+ ip_them = parsed->src_ip;
+ ip_me = parsed->dst_ip;
+
+ /* Calculate the expected SYN-cookie */
+ cookie = (unsigned)syn_cookie(ip_them, port_them | Templ_UDP, ip_me, port_me, entropy);
+
+ /* Extract the SYN-cookie from the response. We just do this byte-by-byte */
+ resp_cookie = (uint64_t)px[0] << 56ull;
+ resp_cookie |= (uint64_t)px[1] << 48ull;
+ resp_cookie |= (uint64_t)px[2] << 40ull;
+ resp_cookie |= (uint64_t)px[3] << 32ull;
+ resp_cookie |= (uint64_t)px[4] << 24ull;
+ resp_cookie |= (uint64_t)px[5] << 16ull;
+ resp_cookie |= (uint64_t)px[6] << 8ull;
+ resp_cookie |= (uint64_t)px[7] << 0ull;
+
+ if (resp_cookie != cookie) {
+ /* If they aren't equal, then this is some other protocol.
+ * TODO: we should use a heuristic on these bytes to
+ * discover what the protocol probably is */
+ /*output_report_banner(out, timestamp, ip_them, 17, port_them,
+ PROTO_ERROR, parsed->ip_ttl,
+ (unsigned char *) "IP-MISSMATCH", 12);*/
+ return 0;
+ } else {
+ /* We've found our protocol, so report the banner
+ * TODO: we should parse this better. */
+ struct BannerOutput banout[1];
+ banout_init(banout);
+
+ /* Parse the packet and generate strings */
+ _parse_response(banout, PROTO_ISAKMP, px, length);
+
+ /* Print the banner to the output */
+ output_report_banner(
+ out, timestamp,
+ ip_them, 17, port_them,
+ PROTO_ISAKMP,
+ parsed->ip_ttl,
+ banout_string(banout, PROTO_ISAKMP),
+ banout_string_length(banout, PROTO_ISAKMP));
+
+ banout_release(banout);
+ return 1;
+ }
+
+}
+
+unsigned
+isakmp_set_cookie(unsigned char *px, size_t length, uint64_t seqno)
+{
+ /*
+ The frame header starts with an 8 bytes init cookie, which is just
+ fine for us
+ */
+
+ unsigned char i;
+
+ if (length < 8)
+ return 0;
+
+ for(i = 0; i < 8; i++)
+ px[i] = (unsigned char)(seqno >> (56 - 8 * i));
+
+ return 0;
+}
+
+static const unsigned char
+sample1[] =
+ "\x00\x00\x00\x00\xc1\x18"
+ "\x84\xda\xbe\x3d\xc6\x8e\xea\xf2\xda\xac\x01\x10\x02\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x50\x00\x00\x00\x34\x00\x00\x00\x01\x00\x00"
+ "\x00\x01\x00\x00\x00\x28\x01\x01\x00\x01\x00\x00\x00\x20\x01\x01"
+ "\x00\x00\x80\x01\x00\x05\x80\x02\x00\x02\x80\x04\x00\x02\x80\x03"
+ "\x00\x01\x80\x0b\x00\x01\x80\x0c\x00\x01";
+
+static const unsigned char
+sample2[] = "\xe4\x7a\x59\x1f\xd0\x57"
+ "\x58\x7f\xa0\x0b\x8e\xf0\x90\x2b\xb8\xec\x01\x10\x02\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x6c\x0d\x00\x00\x3c\x00\x00\x00\x01\x00\x00"
+ "\x00\x01\x00\x00\x00\x30\x01\x01\x00\x01\x00\x00\x00\x28\x01\x01"
+ "\x00\x00\x80\x01\x00\x07\x80\x0e\x00\x80\x80\x02\x00\x02\x80\x04"
+ "\x00\x02\x80\x03\x00\x01\x80\x0b\x00\x01\x00\x0c\x00\x04\x00\x01"
+ "\x51\x80\x00\x00\x00\x14\x4a\x13\x1c\x81\x07\x03\x58\x45\x5c\x57"
+ "\x28\xf2\x0e\x95\x45\x2f";
+
+static const unsigned char sample3[] =
+"\xe4\x7a\x59\x1f\xd0\x57\x58\x7f\xa0\x0b\x8e\xf0\x90\x2b\xb8\xec"
+"\x04\x10\x02\x00\x00\x00\x00\x00\x00\x00\x01\x30\x0a\x00\x00\x84"
+"\x6d\x02\x6d\x56\x16\xc4\x5b\xe0\x5e\x5b\x89\x84\x11\xe9\xf9\x5d"
+"\x19\x5c\xea\x00\x9a\xd2\x2c\x62\xbe\xf0\x6c\x57\x1b\x7c\xfb\xc4"
+"\x79\x2f\x45\x56\x4e\xc7\x10\xac\x58\x4a\xa1\x8d\x20\xcb\xc8\xf5"
+"\xf8\x91\x06\x66\xb8\x9e\x4e\xe2\xf9\x5a\xbc\x02\x30\xe2\xcb\xa1"
+"\xb8\x8a\xc4\xbb\xa7\xfc\xc8\x18\xa9\x86\xc0\x1a\x4c\xa8\x65\xa5"
+"\xeb\x82\x88\x4d\xbe\xc8\x5b\xfd\x7d\x1a\x30\x3b\x09\x89\x4d\xcf"
+"\x2e\x37\x85\xfd\x79\xdb\xa2\x25\x37\x7c\xf8\xcc\xa0\x09\xce\xff"
+"\xbb\x6a\xa3\x8b\x64\x8c\x4b\x05\x40\x4f\x1c\xfa\xac\x36\x1a\xff"
+"\x0d\x00\x00\x18\x15\xb6\x88\x42\x1e\xd5\xc3\xdd\x92\xd3\xb8\x6e"
+"\x47\xa7\x6f\x0d\x39\xcc\x09\xe0\x0d\x00\x00\x14\x12\xf5\xf2\x8c"
+"\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00\x0d\x00\x00\x14"
+"\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00"
+"\x0d\x00\x00\x14\x55\xcc\x29\xed\x90\x2a\xb8\xec\x53\xb1\xdf\x86"
+"\x7c\x61\x09\x29\x14\x00\x00\x0c\x09\x00\x26\x89\xdf\xd6\xb7\x12"
+"\x14\x00\x00\x18\xfe\xbf\x46\x2f\x1c\xd7\x58\x05\xa7\xba\xa2\x87"
+"\x47\xe7\x69\xd6\x74\xf8\x56\x00\x00\x00\x00\x18\x15\x74\xd6\x4c"
+"\x01\x65\xba\xd1\x6a\x02\x3f\x03\x8d\x45\xa0\x74\x98\xd8\xd0\x51";
+
+const char sample4[] =
+"\xe4\x7a\x59\x1f\xd0\x57\x58\x7f\xa0\x0b\x8e\xf0\x90\x2b\xb8\xec"
+"\x05\x10\x02\x01\x00\x00\x00\x00\x00\x00\x00\x4c\xb0\x32\xaa\xa6"
+"\x2a\x70\x71\x8e\xf2\xf0\x99\xcd\xd8\xbf\x6e\xb9\x04\x42\xed\x9d"
+"\x72\x6d\xaa\x6b\x6d\xad\x62\x40\x26\xf5\xfb\xb1\x73\xd9\xf7\x75"
+"\x71\xc2\x32\xa5\x6a\xcf\xe1\x2c\x74\x03\xe9\x53";
+
+static int
+_test_sample(const void *sample, size_t sizeof_sample, const char *expected) {
+ int is_valid;
+ struct BannerOutput banout[1];
+
+ /* Initialize printing banners */
+ banout_init(banout);
+
+ /* Parse the sample */
+ is_valid = _parse_response(banout, PROTO_ISAKMP,
+ (const unsigned char*)sample,
+ sizeof_sample);
+
+ /* If there was a parse error, then*/
+ if (!is_valid)
+ goto fail;
+
+
+ {
+ const unsigned char *str = banout_string(banout, PROTO_ISAKMP);
+ size_t str_length = banout_string_length(banout, PROTO_ISAKMP);
+ //printf("%.*s\n", (unsigned)str_length, str);
+ if (str_length < strlen(expected) || memcmp(str, expected, strlen(expected)) != 0)
+ goto fail;
+ }
+
+ banout_release(banout);
+ return 0;
+fail:
+ banout_release(banout);
+ return 0;
+}
+
+/****************************************************************************
+ ****************************************************************************/
+int
+proto_isakmp_selftest(void)
+{
+ unsigned fail_count = 0;
+
+ LOG(1, "[ ] ISAKMP: selftesting...\n");
+
+
+ fail_count += _test_sample(
+ sample1, sizeof(sample1)-1,
+ "v1.0 xchg=id-prot [SEC-ASSOC] DOI=ipsec IDENTITY 1 id=ISAKMP trans=IKE 3DES-CBC SHA PSK");
+ fail_count += _test_sample(
+ sample2, sizeof(sample2)-1,
+ "v1.0 xchg=id-prot [SEC-ASSOC] DOI=ipsec IDENTITY 1 id=ISAKMP trans=IKE AES-CBC key=128bits SHA PSK {RFC-39947-NAT}");
+
+
+ fail_count += _test_sample(
+ sample3, sizeof(sample3)-1,
+ "v1.0 xchg=id-prot [KEY-XCHG] [NONCE] {CISCO-UNITY} {RFC3706-DPD} {XAUTH} [NAT-D] [NAT-D]");
+
+ fail_count += _test_sample(
+ sample4, sizeof(sample4)-1,
+ "v1.0 xchg=id-prot ENCRYPTED");
+
+
+ if (fail_count)
+ goto fail;
+
+ LOG(1, "[-] ISAKMP: success\n");
+ return 0;
+fail:
+ LOG(1, "[-] ISAKMP: fail\n");
+ return 1;
+}
+
diff --git a/src/proto-isakmp.h b/src/proto-isakmp.h
new file mode 100644
index 00000000..69458e25
--- /dev/null
+++ b/src/proto-isakmp.h
@@ -0,0 +1,18 @@
+#ifndef PROTO_ISAKMP_H
+#define PROTO_ISAKMP_H
+#include
+#include
+#include
+struct Output;
+struct PreprocessedInfo;
+
+unsigned isakmp_parse(struct Output *out, time_t timestamp,
+ const unsigned char *px, unsigned length,
+ struct PreprocessedInfo *parsed, uint64_t entropy);
+
+unsigned isakmp_set_cookie(unsigned char *px, size_t length, uint64_t seqno);
+
+int
+proto_isakmp_selftest(void);
+
+#endif
diff --git a/src/proto-mc.c b/src/proto-mc.c
new file mode 100644
index 00000000..90e7be64
--- /dev/null
+++ b/src/proto-mc.c
@@ -0,0 +1,121 @@
+#include "proto-mc.h"
+#include "proto-banner1.h"
+#include "unusedparm.h"
+#include "masscan-app.h"
+#include "stack-tcp-api.h"
+#include "output.h"
+#include
+#include
+#include
+
+static unsigned char hand_shake_ptr[128];
+
+static unsigned char *
+hand_shake(uint16_t port, const char* ip, size_t ip_len)
+{
+ size_t tlen = 10+ip_len;
+ unsigned char * ret = (unsigned char *)calloc(1,tlen);
+ ret[0] = (unsigned char)(7+ip_len);
+ ret[2] = 0xf7;
+ ret[3] = 5;
+ ret[4] = (unsigned char)ip_len;
+ memcpy(ret+5,ip,ip_len);
+ ret[tlen-5] = (unsigned char)(port>>8);
+ ret[tlen-4] = (unsigned char)(port&0xff);
+ ret[tlen-3] = 1;
+ ret[tlen-2] = 1;
+ ret[tlen-1] = 0;
+ return ret;
+}
+
+static void *
+memstr(void * mem, size_t len, char * str)
+{
+ size_t i;
+ size_t stlen = strlen(str);
+ if(len < stlen)
+ return 0;
+ for(i = 0; i < len-stlen; i++) {
+ if(!memcmp((char*)mem+i,str,stlen))
+ return (char*)mem+i;
+ }
+ return 0;
+}
+
+/***************************************************************************
+ ***************************************************************************/
+static void
+mc_parse( const struct Banner1 *banner1,
+ void *banner1_private,
+ struct StreamState *pstate,
+ const unsigned char *px, size_t length,
+ struct BannerOutput *banout,
+ struct stack_handle_t *socket)
+{
+ size_t i;
+ struct MCSTUFF *mc = &pstate->sub.mc;
+ UNUSEDPARM(banner1_private);
+ UNUSEDPARM(banner1);
+ for(i = 0; i < length; i++) {
+ if(px[i] == '{')
+ mc->brackcount++;
+ if(px[i] == '}')
+ mc->brackcount--;
+ }
+ if(mc->brackcount <= 0)
+ tcpapi_close(socket);
+
+ if((mc->imgstart&&mc->imgend) || mc->brackcount <= 0) { // we already found and removed image data
+ banout_append(banout, PROTO_MC,px,length);
+ } else {
+ mc->banmem = realloc(mc->banmem,mc->totalLen+length+1); // expand to add new memory for added paket
+ memcpy(mc->banmem+mc->totalLen,px,length); // copy in new packet
+ mc->banmem[mc->totalLen] = 0; // add ending 0 for str
+ mc->totalLen+=length;
+ if(!mc->imgstart) { // dont search again if we found start
+ mc->imgstart = (size_t)memstr(mc->banmem,mc->totalLen,"data:image/png;base64");
+ if(mc->imgstart)
+ mc->imgstart-=(size_t)mc->banmem;
+ } else { // we found start but not the end
+ mc->imgend = (size_t)memchr(mc->banmem+mc->imgstart,'\"',mc->totalLen-mc->imgstart);
+ if(mc->imgend){ // we found the end
+ mc->imgend-=(size_t)mc->banmem;
+ memcpy(mc->banmem+mc->imgstart,mc->banmem+mc->imgend,(mc->totalLen-mc->imgend)+1); // copy data after B64
+ mc->totalLen=mc->imgstart+(mc->totalLen-mc->imgend); // shrink length to subtract B64 image
+ banout_append(banout, PROTO_MC,mc->banmem,mc->totalLen); // print out banner minus image data
+ free(mc->banmem); // we dont need to keep track of this any more.
+ }
+ }
+ }
+}
+
+/***************************************************************************
+ ***************************************************************************/
+static void *
+mc_init(struct Banner1 *banner1)
+{
+ unsigned char * tmp = hand_shake(25565,"localhost",9);
+ memcpy(hand_shake_ptr,tmp,tmp[0]+3);
+ free(tmp);
+ banner_mc.hello = hand_shake_ptr;
+ banner_mc.hello_length = hand_shake_ptr[0]+3;
+ banner1->payloads.tcp[25565] = (void*)&banner_mc;
+ return 0;
+}
+
+/***************************************************************************
+ ***************************************************************************/
+static int
+mc_selftest(void)
+{
+ return 0;
+}
+
+/***************************************************************************
+ ***************************************************************************/
+struct ProtocolParserStream banner_mc = {
+ "mc", 25565, 0, 0, 0,
+ mc_selftest,
+ mc_init,
+ mc_parse,
+};
diff --git a/src/proto-mc.h b/src/proto-mc.h
new file mode 100644
index 00000000..137a357b
--- /dev/null
+++ b/src/proto-mc.h
@@ -0,0 +1,8 @@
+#ifndef PROTO_MC_H
+#define PROTO_MC_H
+#include "proto-banner1.h"
+#include "util-bool.h"
+
+extern struct ProtocolParserStream banner_mc;
+
+#endif
diff --git a/src/proto-memcached.c b/src/proto-memcached.c
index 8e72fce2..68cec957 100644
--- a/src/proto-memcached.c
+++ b/src/proto-memcached.c
@@ -8,7 +8,7 @@
#include "unusedparm.h"
#include "masscan-app.h"
#include "output.h"
-#include "proto-interactive.h"
+#include "stack-tcp-api.h"
#include "proto-preprocess.h"
#include "proto-ssl.h"
#include "proto-udp.h"
@@ -107,10 +107,10 @@ static void
memcached_tcp_parse(
const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
unsigned state = pstate->state;
unsigned i;
@@ -119,7 +119,7 @@ memcached_tcp_parse(
UNUSEDPARM(banner1_private);
UNUSEDPARM(banner1);
- UNUSEDPARM(more);
+ UNUSEDPARM(socket);
if (sm_memcached_responses == 0)
return;
@@ -360,7 +360,7 @@ memcached_udp_parse(struct Output *out, time_t timestamp,
/* Parse the remainder of the packet as if this were TCP */
{
- struct ProtocolState stuff[1];
+ struct StreamState stuff[1];
memset(stuff, 0, sizeof(stuff[0]));
diff --git a/src/proto-netbios.c b/src/proto-netbios.c
index 8bb6bed2..19174a16 100644
--- a/src/proto-netbios.c
+++ b/src/proto-netbios.c
@@ -3,7 +3,7 @@
#include "proto-dns-parse.h"
#include "proto-preprocess.h"
#include "syn-cookie.h"
-#include "logger.h"
+#include "util-logger.h"
#include "output.h"
#include "masscan-app.h"
#include "proto-banner1.h"
diff --git a/src/proto-ntlmssp.c b/src/proto-ntlmssp.c
index 37a99b65..b37dedfe 100644
--- a/src/proto-ntlmssp.c
+++ b/src/proto-ntlmssp.c
@@ -1,7 +1,7 @@
#include "proto-ntlmssp.h"
#include "masscan-app.h"
#include "proto-banout.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include "util-malloc.h"
#include
#include
@@ -96,7 +96,7 @@ append_unicode_string(struct BannerOutput *banout, unsigned proto, const char *n
banout_append_char(banout, proto, ' ');
banout_append(banout, PROTO_SMB, name, AUTO_LEN);
banout_append_char(banout, proto, '=');
- for (j=0; j
#include
#include "smack.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include "output.h"
#include "masscan-app.h"
#include "proto-preprocess.h"
@@ -122,7 +122,7 @@ ntp_modlist_parse(const unsigned char *px,
const char *errmsg = val2string_lookup(error_codes, errcode);
if (errmsg == 0)
errmsg = "Bogus Error Code";
- sprintf_s(foo, sizeof(foo), "%u", errcode);
+ snprintf(foo, sizeof(foo), "%u", errcode);
banout_append(banout, PROTO_NTP, "Response was NTP Error Code ", AUTO_LEN);
banout_append(banout, PROTO_NTP, foo, AUTO_LEN);
banout_append(banout, PROTO_NTP, " - \"", AUTO_LEN);
@@ -145,7 +145,7 @@ ntp_modlist_parse(const unsigned char *px,
{
char msg[128];
- sprintf_s(msg, sizeof(msg), " response-size=%u-bytes more=%s",
+ snprintf(msg, sizeof(msg), " response-size=%u-bytes more=%s",
record_count * record_size, ((px[0]>>6)&1)?"true":"false");
banout_append(banout, PROTO_NTP, msg, AUTO_LEN);
diff --git a/src/proto-pop3.c b/src/proto-pop3.c
index 45519aa6..96841bd6 100644
--- a/src/proto-pop3.c
+++ b/src/proto-pop3.c
@@ -9,7 +9,7 @@
#include "proto-banner1.h"
#include "unusedparm.h"
#include "masscan-app.h"
-#include "proto-interactive.h"
+#include "stack-tcp-api.h"
#include "proto-ssl.h"
#include
#include
@@ -20,10 +20,10 @@
static void
pop3_parse( const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
unsigned state = pstate->state;
unsigned i;
@@ -42,14 +42,14 @@ pop3_parse( const struct Banner1 *banner1,
banout_append_char(banout, PROTO_POP3, px[i]);
if ("+OK"[state] != px[i]) {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
} else
state++;
break;
case 3:
banout_append_char(banout, PROTO_POP3, px[i]);
if (px[i] == '\n') {
- tcp_transmit(more, "CAPA\r\n", 6, 0);
+ tcpapi_send(socket, "CAPA\r\n", 6, 0);
state++;
}
break;
@@ -62,7 +62,7 @@ pop3_parse( const struct Banner1 *banner1,
state++;
else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 5:
@@ -72,7 +72,7 @@ pop3_parse( const struct Banner1 *banner1,
state++;
else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 6:
@@ -82,7 +82,7 @@ pop3_parse( const struct Banner1 *banner1,
state += 2; /* oops, I had too many states here */
else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 8:
@@ -108,7 +108,7 @@ pop3_parse( const struct Banner1 *banner1,
continue;
banout_append_char(banout, PROTO_POP3, px[i]);
if (px[i] == '\n') {
- tcp_transmit(more, "STLS\r\n", 6, 0);
+ tcpapi_send(socket, "STLS\r\n", 6, 0);
state = 204;
} else {
state = 8;
@@ -128,7 +128,7 @@ pop3_parse( const struct Banner1 *banner1,
pstate->port = (unsigned short)port;
state = 0;
- tcp_transmit(more, banner_ssl.hello, banner_ssl.hello_length, 0);
+ tcpapi_send(socket, banner_ssl.hello, banner_ssl.hello_length, 0);
break;
}
@@ -140,7 +140,7 @@ pop3_parse( const struct Banner1 *banner1,
banout_append_char(banout, PROTO_POP3, px[i]);
if (px[i] == '\n') {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
default:
diff --git a/src/proto-smb.c b/src/proto-smb.c
index a2c88c65..a811f6a5 100644
--- a/src/proto-smb.c
+++ b/src/proto-smb.c
@@ -3,11 +3,11 @@
*/
#include "proto-smb.h"
-#include "proto-interactive.h"
+#include "stack-tcp-api.h"
#include "unusedparm.h"
#include "masscan-app.h"
-#include "siphash24.h"
-#include "string_s.h"
+#include "crypto-siphash24.h"
+#include "util-safefunc.h"
#include "unusedparm.h"
#include
#include
@@ -1006,7 +1006,7 @@ smb2_parse_negotiate(struct SMBSTUFF *smb, const unsigned char *px, size_t offse
struct tm tm = {0};
size_t len;
- gmtime_s(&tm, ×tamp);
+ safe_gmtime(&tm, ×tamp);
len = strftime(str, sizeof(str), " time=%Y-%m-%d %H:%M:%S ", &tm);
banout_append(banout, PROTO_SMB, str, len);
smb->is_printed_time = 1;
@@ -1015,7 +1015,18 @@ smb2_parse_negotiate(struct SMBSTUFF *smb, const unsigned char *px, size_t offse
break;
case N_BOOT1: case N_BOOT2: case N_BOOT3: case N_BOOT4:
case N_BOOT5: case N_BOOT6: case N_BOOT7: case N_BOOT8:
- smb->parms.negotiate2.boot_time |= (px[offset]<<((state-N_BOOT1)*8));
+ smb->parms.negotiate2.boot_time |= ((uint64_t)px[offset]<<(uint64_t)((state-N_BOOT1)*8));
+ if (state == N_BOOT8 && !smb->is_printed_boottime) {
+ char str[64] = "(err)";
+ time_t timestamp = convert_windows_time(smb->parms.negotiate2.boot_time);
+ struct tm tm = {0};
+ size_t len;
+
+ safe_gmtime(&tm, ×tamp);
+ len = strftime(str, sizeof(str), " boottime=%Y-%m-%d %H:%M:%S ", &tm);
+ banout_append(banout, PROTO_SMB, str, len);
+ smb->is_printed_boottime = 1;
+ }
state++;
break;
case N_BLOB_OFFSET1:
@@ -1229,7 +1240,7 @@ smb2_parse_header(struct SMBSTUFF *smb, const unsigned char *px, size_t offset,
*****************************************************************************/
static size_t
smb_parse_smb(struct SMBSTUFF *smb, const unsigned char *px, size_t max, struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
size_t len; /*scratch variables used in a couple places */
unsigned state = smb->nbt_state;
@@ -1399,7 +1410,7 @@ smb_parse_smb(struct SMBSTUFF *smb, const unsigned char *px, size_t max, struct
break;
case SMB1_PARAMETERS:
/* Transfer control to a sub-parser, which may consume zero
- * or more bytes, up to the end of the parameters field
+ * or greater bytes, up to the end of the parameters field
* (meaning, up to word_count*2 bytes) */
len = smb_params_parse(smb, px, i, max);
i += len;
@@ -1428,11 +1439,11 @@ smb_parse_smb(struct SMBSTUFF *smb, const unsigned char *px, size_t max, struct
time_t timestamp = convert_windows_time(smb->parms.negotiate.SystemTime);
struct tm tm = {0};
- gmtime_s(&tm, ×tamp);
+ safe_gmtime(&tm, ×tamp);
len = strftime(str, sizeof(str), " time=%Y-%m-%d %H:%M:%S", &tm);
banout_append(banout, PROTO_SMB, str, len);
- sprintf_s(str, sizeof(str), " TZ=%+d ", (short)smb->parms.negotiate.ServerTimeZone);
+ snprintf(str, sizeof(str), " TZ=%+d ", (short)smb->parms.negotiate.ServerTimeZone);
banout_append(banout, PROTO_SMB, str, AUTO_LEN);
smb->is_printed_time = 1;
@@ -1440,26 +1451,23 @@ smb_parse_smb(struct SMBSTUFF *smb, const unsigned char *px, size_t max, struct
smb->hdr.smb1.byte_state = 0;
if (smb->hdr.smb1.flags2 & 0x0800) {
- tcp_transmit(more, smb1_null_session_setup_ex, sizeof(smb1_null_session_setup_ex), 0);
+ tcpapi_send(socket, smb1_null_session_setup_ex, sizeof(smb1_null_session_setup_ex), 0);
} else {
if (smb->parms.negotiate.SessionKey) {
unsigned char *buf;
- buf = tcp_transmit_alloc(more, sizeof(smb1_null_session_setup));
+ buf = malloc(sizeof(smb1_null_session_setup));
memcpy(buf, smb1_null_session_setup, sizeof(smb1_null_session_setup));
buf[0x2f] = (unsigned char)(smb->parms.negotiate.SessionKey>> 0) & 0xFF;
buf[0x30] = (unsigned char)(smb->parms.negotiate.SessionKey>> 8) & 0xFF;
buf[0x31] = (unsigned char)(smb->parms.negotiate.SessionKey>>16) & 0xFF;
buf[0x32] = (unsigned char)(smb->parms.negotiate.SessionKey>>24) & 0xFF;
- tcp_transmit(more, buf, sizeof(smb1_null_session_setup), TCPTRAN_DYNAMIC);
-
- /* NOTE: the following line is here to silence LLVM warnings about a potential
- * memory leak. The 'tcp_transmit' function 'adopts' the pointer and will be
- * responsible for freeing it after the packet gets successfully transmitted */
- buf = 0;
+ tcpapi_send(socket, buf, sizeof(smb1_null_session_setup), TCP__copy);
+ free(buf);
} else {
- tcp_transmit(more, smb1_null_session_setup, sizeof(smb1_null_session_setup), 0);
+ tcpapi_send(socket,
+ smb1_null_session_setup, sizeof(smb1_null_session_setup), TCP__static);
}
}
@@ -1504,7 +1512,7 @@ smb_parse_smb(struct SMBSTUFF *smb, const unsigned char *px, size_t max, struct
/* close the connection, we've found all we can */
if (smb->hdr.smb1.command == 0x73)
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
@@ -1582,9 +1590,9 @@ smb_parse_smb(struct SMBSTUFF *smb, const unsigned char *px, size_t max, struct
switch (smb->hdr.smb2.opcode) {
case 0x00: /* negotiate response */
if (smb->hdr.smb2.seqno == 0) {
- tcp_transmit(more, smb2_negotiate_request, sizeof(smb2_negotiate_request), 0);
+ tcpapi_send(socket, smb2_negotiate_request, sizeof(smb2_negotiate_request), 0);
} else if (smb->hdr.smb2.seqno == 1) {
- tcp_transmit(more, smb2_null_session_setup, sizeof(smb2_null_session_setup), 0);
+ tcpapi_send(socket, smb2_null_session_setup, sizeof(smb2_null_session_setup), 0);
}
break;
default:
@@ -1631,7 +1639,7 @@ smb_parse_smb(struct SMBSTUFF *smb, const unsigned char *px, size_t max, struct
/* Close the connection when we get a SessionSetup response */
if (smb->hdr.smb2.opcode == 1)
- tcp_close(more);
+ tcpapi_close(socket);
}
}
break;
@@ -1663,10 +1671,10 @@ static void
smb_parse_record(
const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t max,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
size_t i;
unsigned state = pstate->state;
@@ -1729,7 +1737,7 @@ smb_parse_record(
state = NBT_UNKNOWN;
break;
case 0x82:
- tcp_transmit(more, smb1_hello_template, sizeof(smb1_hello_template), 0);
+ tcpapi_send(socket, smb1_hello_template, sizeof(smb1_hello_template), 0);
state = NBT_DRAIN;
break;
case 0x85:
@@ -1781,7 +1789,7 @@ smb_parse_record(
break;
case NBT_SMB:
- i += smb_parse_smb(smb, px+i, max-i, banout, more);
+ i += smb_parse_smb(smb, px+i, max-i, banout, socket);
if (smb->nbt_length == 0) {
state = 0;
i--;
@@ -1884,9 +1892,9 @@ static int
smb_do_test(const char *substring, const unsigned char *packet_bytes, size_t length)
{
struct Banner1 *banner1;
- struct ProtocolState state[1];
+ struct StreamState state[1];
struct BannerOutput banout1[1];
- struct InteractiveData more;
+ struct stack_handle_t socket = {0};
int x;
banner1 = banner1_create();
@@ -1899,7 +1907,7 @@ smb_do_test(const char *substring, const unsigned char *packet_bytes, size_t len
packet_bytes,
length,
banout1,
- &more);
+ &socket);
x = banout_is_contains(banout1, PROTO_SMB, substring);
if (x == 0)
printf("smb parser failure: %s\n", substring);
@@ -2017,7 +2025,7 @@ smb_selftest(void)
struct Banner1 *banner1;
struct ProtocolState state[1];
struct BannerOutput banout1[1];
- struct InteractiveData more;
+ struct InteractiveData socket;
size_t i;
/*
@@ -2045,7 +2053,7 @@ smb_selftest(void)
packet_bytes,
sizeof(packet_bytes),
banout1,
- &more);
+ &socket);
banner1_destroy(banner1);
banout_release(banout1);
@@ -2061,7 +2069,7 @@ smb_selftest(void)
/*****************************************************************************
*****************************************************************************/
static void
-smb_cleanup(struct ProtocolState *pstate)
+smb_cleanup(struct StreamState *pstate)
{
struct SMBSTUFF *smb = &pstate->sub.smb;
if (smb->spnego.ntlmssp.buf)
diff --git a/src/proto-smtp.c b/src/proto-smtp.c
index 9c3cb720..710050a9 100644
--- a/src/proto-smtp.c
+++ b/src/proto-smtp.c
@@ -23,7 +23,7 @@
#include "proto-banner1.h"
#include "unusedparm.h"
#include "masscan-app.h"
-#include "proto-interactive.h"
+#include "stack-tcp-api.h"
#include "proto-ssl.h"
#include
#include
@@ -34,10 +34,10 @@
static void
smtp_parse( const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
unsigned state = pstate->state;
unsigned i;
@@ -67,7 +67,7 @@ smtp_parse( const struct Banner1 *banner1,
case 203:
if (!isdigit(px[i]&0xFF)) {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
} else {
smtp->code *= 10;
smtp->code += (px[i] - '0');
@@ -88,7 +88,7 @@ smtp_parse( const struct Banner1 *banner1,
banout_append_char(banout, PROTO_SMTP, px[i]);
} else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
break;
case 5:
@@ -96,7 +96,7 @@ smtp_parse( const struct Banner1 *banner1,
continue;
else if (px[i] == '\n') {
if (smtp->is_last) {
- tcp_transmit(more, "EHLO masscan\r\n", 14, 0);
+ tcpapi_send(socket, "EHLO masscan\r\n", 14, 0);
state = 100;
banout_append_char(banout, PROTO_SMTP, px[i]);
} else {
@@ -105,7 +105,7 @@ smtp_parse( const struct Banner1 *banner1,
}
} else if (px[i] == '\0' || !isprint(px[i])) {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
continue;
} else {
banout_append_char(banout, PROTO_SMTP, px[i]);
@@ -116,7 +116,7 @@ smtp_parse( const struct Banner1 *banner1,
continue;
else if (px[i] == '\n') {
if (smtp->is_last) {
- tcp_transmit(more, "STARTTLS\r\n", 10, 0);
+ tcpapi_send(socket, "STARTTLS\r\n", 10, 0);
state = 200;
banout_append_char(banout, PROTO_SMTP, px[i]);
} else {
@@ -125,7 +125,7 @@ smtp_parse( const struct Banner1 *banner1,
}
} else if (px[i] == '\0' || !isprint(px[i])) {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
continue;
} else {
banout_append_char(banout, PROTO_SMTP, px[i]);
@@ -146,15 +146,15 @@ smtp_parse( const struct Banner1 *banner1,
pstate->port = (unsigned short)port;
state = 0;
- tcp_transmit(more, banner_ssl.hello, banner_ssl.hello_length, 0);
+ tcpapi_send(socket, banner_ssl.hello, banner_ssl.hello_length, 0);
} else {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
}
} else if (px[i] == '\0' || !isprint(px[i])) {
state = 0xffffffff;
- tcp_close(more);
+ tcpapi_close(socket);
continue;
} else {
banout_append_char(banout, PROTO_SMTP, px[i]);
diff --git a/src/proto-snmp.c b/src/proto-snmp.c
index a58a8023..53a869e2 100644
--- a/src/proto-snmp.c
+++ b/src/proto-snmp.c
@@ -41,7 +41,7 @@
#include
#include
#include "smack.h"
-#include "string_s.h"
+#include "util-safefunc.h"
#include "output.h"
#include "masscan-app.h"
#include "proto-preprocess.h"
@@ -245,7 +245,7 @@ snmp_banner_oid(const unsigned char *oid, size_t oid_length,
if (x == 0 && i >= oid_length)
break;
- sprintf_s(foo, sizeof(foo), ".%" PRIu64 "", x);
+ snprintf(foo, sizeof(foo), ".%" PRIu64 "", x);
banout_append(banout, PROTO_SNMP, foo, strlen(foo));
}
}
@@ -275,7 +275,7 @@ snmp_banner(const unsigned char *oid, size_t oid_length,
uint64_t result = 0;
for (i=0; i
+#define PAYLOAD_BANNER "SSH-2.0-OPENSSH_7.9\r\n"
+#define SIZE_BANNER 21
+#define PAYLOAD_KEY_EXHANGE_INIT "\x00\x00\x04\x4c" /* packet length: 1100 */ \
+ "\x04" /* padding_length (this value is include in the packet length) */ \
+ "\x14" /* message_code = 20 */ \
+ "\xf3\xca\xd2\x90\xec\xf4\x7c\x47\x55\x4c\x88\xcf\x3a\x72\x2b\xb2" /*cookie */ \
+ "\x00\x00\x00\xd8" /* kex_algorithms_length */ \
+ "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha1,diffie-hellman-group-exchange-sha256" /* kex_algorithms_string */ \
+ "\x00\x00\x00\x21" /* server_host_key_algorithms_length */ \
+ "ssh-rsa,rsa-sha2-512,rsa-sha2-256" /* server_host_key_algorithms_string */ \
+ "\x00\x00\x00\xaf" /* encryption_algorithms_client_to_server_length */ \
+ "chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,aes192-cbc,aes256-cbc,blowfish-cbc,cast128-cbc,3des-cbc" /* encryption_algorithms_client_to_server_string */ \
+ "\x00\x00\x00\xaf" /* encryption_algorithms_server_to_client_length */ \
+ "chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,aes192-cbc,aes256-cbc,blowfish-cbc,cast128-cbc,3des-cbc" /* encryption_algorithms_server_to_client_string */ \
+ "\x00\x00\x00\xd5" /* mac_algorithms_client_to_server_length */ \
+ "umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1" /* mac_algorithms_client_to_server_string */ \
+ "\x00\x00\x00\xd5" /* mac_algorithms_server_to_client_length */ \
+ "umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1" /* mac_algorithms_server_to_client_string */ \
+ "\x00\x00\x00\x04" /* compression_algorithms_client_to_server_length */ \
+ "none" /* compression_algorithms_client_to_server_string */ \
+ "\x00\x00\x00\x04" /* compression_algorithms_server_to_client_length */ \
+ "none" /* compression_algorithms_server_to_client_string */ \
+ "\x00\x00\x00\x00" /* languages_client_to_server_length */ \
+ "\x00\x00\x00\x00" /* languages_server_to_client_length */ \
+ "\x00" /* first_KEX_Packet_Follows */ \
+ "\x00\x00\x00\x00" /* reserved */ \
+ "\x00\x00\x00\x00" /* Padding_String */ \
+ "\x00\x00\x00\x8c" /* DH_packet_length */ \
+ "\x05" /* DH_padding_length */ \
+ "\x1e" /* DH_message_code */ \
+ "\x00\x00\x00\x81" /* DH_multiprecision_integer_length */ \
+ "\x00\xd4\x6e\xe0\x12\xa6\x56\x95\x37\xa0\x14\x2e\x4e\x4d\x57\x48\x1d\x4b\x80\x90\x1e\x61\x6f\x5c\xc4\xd7\xbc\x17\x25\xb7\x41\x8c\x6c\x8b\xed\x74\x2d\xc0\x54\xeb\x08\x3a\x79\x5e\x0c\xad\x04\xe8\xb7\xfb\xa1\x68\x62\x66\xd3\x9a\x26\x39\xaa\x6c\x89\x2f\x5c\x99\xab\xd2\x43\xda\xa7\xef\x1c\x19\xdc\xa6\x03\xc9\x8a\x56\x19\x74\xd1\xb8\x08\xdc\x76\x14\xe7\x86\x50\x74\x01\xed\xd4\xfb\x1a\x1a\x25\x5d\x1a\xc7\x5f\x0c\xb3\xcc\x58\x5a\x40\xd5\x04\xa5\xc1\x30\x14\x86\xf0\xb8\x33\x17\xb4\x23\x9d\x43\x6d\x38\x87\xec\xa9\xbc\x3b" /* DH_padding_string */ \
+ "\x00\x00\x00\x00\x00" /* DH_padding_string */
+#define SIZE_KEY_EXCHANGE_INIT (1100+4+140+4) //length_of_the_first_packet(packet_length + length of the packet_length_field(4)) + DH_packet_length (including the DH_padding_length) + the length of the DH_length_field (4).
+#define PAYLOAD_NEWKEYS "\x00\x00\x00\x0c" /* packet length */ \
+ "\x0a" /* padding length */ \
+ "\x15" /* message code */ \
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" /* padding string */
+#define SIZE_NEWKEYS (12+4)
+
+#define DEADSTORE(x) x=x
/***************************************************************************
***************************************************************************/
static void
ssh_parse( const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
unsigned state = pstate->state;
+ size_t packet_length = pstate -> sub.ssh.packet_length;
unsigned i;
+ enum{
+ BANNER = 0,
+ MSG_KEY_EXCHANGE_INIT = 1,
+ MSG_NEW_KEYS = 2,
+ MSG_UNKNOWN = 9,
+ PADDING_LENGTH = 10,
+ MESSAGE_CODE = 11,
+ CHECK_LENGTH = 20,
+ LENGTH_1 = 21,
+ LENGTH_2 = 22,
+ LENGTH_3 = 23,
+ LENGTH_4 = 24,
+ BEFORE_END = 29,
+ END = 30,
+ ERROR = 31,
+ };
UNUSEDPARM(banner1_private);
UNUSEDPARM(banner1);
- UNUSEDPARM(more);
-
- for (i=0; istate = state;
+ pstate->sub.ssh.packet_length = packet_length;
}
/***************************************************************************
diff --git a/src/proto-ssl.c b/src/proto-ssl.c
index dfbb0dde..5e392c2c 100644
--- a/src/proto-ssl.c
+++ b/src/proto-ssl.c
@@ -46,11 +46,11 @@
open TCP connections with minimal memory usage.
*/
#include "proto-ssl.h"
-#include "proto-interactive.h"
+#include "stack-tcp-api.h"
#include "unusedparm.h"
#include "masscan-app.h"
-#include "siphash24.h"
-#include "string_s.h"
+#include "crypto-siphash24.h"
+#include "util-safefunc.h"
#include "util-malloc.h"
#include
#include
@@ -72,7 +72,7 @@ BANNER_CIPHER(struct BannerOutput *banout, unsigned cipher_suite)
{
//const char *notes = "";
char foo[64];
- sprintf_s(foo, sizeof(foo), "cipher:0x%x", cipher_suite);
+ snprintf(foo, sizeof(foo), "cipher:0x%x", cipher_suite);
banout_append(banout, PROTO_SSL3, foo, AUTO_LEN);
/*switch (cipher_suite) {
@@ -110,7 +110,7 @@ BANNER_VERSION(struct BannerOutput *banout, unsigned version_major,
banout_append(banout, PROTO_SSL3, "TLS/1.3 ", AUTO_LEN);
break;
default:
- sprintf_s(foo, sizeof(foo), "SSLver[%u,%u] ",
+ snprintf(foo, sizeof(foo), "SSLver[%u,%u] ",
version_major,
version_minor);
banout_append(banout, PROTO_SSL3, foo, strlen(foo));
@@ -128,10 +128,10 @@ static void
parse_server_hello(
const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
struct SSL_SERVER_HELLO *hello = &pstate->sub.ssl.x.server_hello;
unsigned state = hello->state;
@@ -155,7 +155,7 @@ parse_server_hello(
UNUSEDPARM(banout);
UNUSEDPARM(banner1_private);
UNUSEDPARM(banner1);
- UNUSEDPARM(more);
+ UNUSEDPARM(socket);
/* What this structure looks like in ASN.1 format
struct {
@@ -371,10 +371,10 @@ static void
parse_server_cert(
const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
struct SSL_SERVER_CERT *data = &pstate->sub.ssl.x.server_cert;
unsigned state = data->state;
@@ -385,11 +385,14 @@ parse_server_cert(
LEN0, LEN1, LEN2,
CLEN0, CLEN1, CLEN2,
CERT,
+ CALEN0, CALEN1, CALEN2,
+ CACERT,
UNKNOWN,
};
UNUSEDPARM(banner1);
UNUSEDPARM(banner1_private);
+ UNUSEDPARM(socket);
for (i=0; iis_capture_cert) {
@@ -432,8 +438,10 @@ parse_server_cert(
DROPDOWN(i,length,state);
case CERT:
+ case CACERT:
{
unsigned len = (unsigned)length-i;
+ unsigned proto = (state == CERT ? PROTO_X509_CERT : PROTO_X509_CACERT);
if (len > remaining)
len = remaining;
if (len > cert_remaining)
@@ -442,7 +450,7 @@ parse_server_cert(
/* parse the certificate */
if (banner1->is_capture_cert) {
banout_append_base64(banout,
- PROTO_X509_CERT,
+ proto,
px+i, len,
&pstate->base64);
}
@@ -459,14 +467,17 @@ parse_server_cert(
* a record of it */
if (banner1->is_capture_cert) {
banout_finalize_base64(banout,
- PROTO_X509_CERT,
+ proto,
&pstate->base64);
- banout_end(banout, PROTO_X509_CERT);
+ banout_end(banout, proto);
}
- state = CLEN0;
+ state = CALEN0;
if (remaining == 0) {
- if (!banner1->is_heartbleed)
- tcp_close(more);
+ /* FIXME: reduce this logic, it should only flush the
+ * FIXME: ertificate, not close the connection*/
+ if (!banner1->is_heartbleed) {
+ ; //tcpapi_close(socket);
+ }
}
}
}
@@ -512,10 +523,10 @@ static void
parse_handshake(
const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
struct SSLRECORD *ssl = &pstate->sub.ssl;
unsigned state = ssl->handshake.state;
@@ -573,7 +584,7 @@ parse_handshake(
static const char heartbleed_request[] =
"\x15\x03\x02\x00\x02\x01\x80"
"\x18\x03\x02\x00\x03\x01" "\x40\x00";
- tcp_transmit(more, heartbleed_request, sizeof(heartbleed_request)-1, 0);
+ tcpapi_send(socket, heartbleed_request, sizeof(heartbleed_request)-1, 0);
}
DROPDOWN(i,length,state);
@@ -611,7 +622,7 @@ parse_handshake(
pstate,
px+i, len,
banout,
- more);
+ socket);
break;
case 11: /* server certificate */
parse_server_cert( banner1,
@@ -619,7 +630,7 @@ parse_handshake(
pstate,
px+i, len,
banout,
- more);
+ socket);
break;
}
@@ -658,10 +669,10 @@ static void
parse_heartbeat(
const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
struct SSLRECORD *ssl = &pstate->sub.ssl;
unsigned state = ssl->handshake.state;
@@ -674,7 +685,7 @@ parse_heartbeat(
UNKNOWN,
};
- UNUSEDPARM(more);
+ UNUSEDPARM(socket);
UNUSEDPARM(banner1_private);
/*
@@ -778,10 +789,10 @@ static void
parse_alert(
const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
struct SSLRECORD *ssl = &pstate->sub.ssl;
unsigned state = ssl->handshake.state;
@@ -793,7 +804,7 @@ parse_alert(
UNKNOWN,
};
- UNUSEDPARM(more);
+ UNUSEDPARM(socket);
UNUSEDPARM(banner1_private);
/*
@@ -826,7 +837,7 @@ parse_alert(
default:
banout_append(banout, PROTO_SAFE,
"poodle[no-SSLv3] ", AUTO_LEN);
- sprintf_s(foo, sizeof(foo), " ALERT(0x%02x%02x) ",
+ snprintf(foo, sizeof(foo), " ALERT(0x%02x%02x) ",
ssl->x.server_alert.level,
ssl->x.server_alert.description
);
@@ -836,7 +847,7 @@ parse_alert(
}
} else {
char foo[64];
- sprintf_s(foo, sizeof(foo), " ALERT(0x%02x%02x) ",
+ snprintf(foo, sizeof(foo), " ALERT(0x%02x%02x) ",
ssl->x.server_alert.level,
ssl->x.server_alert.description
);
@@ -882,10 +893,10 @@ static void
ssl_parse_record(
const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
unsigned state = pstate->state;
unsigned remaining = pstate->remaining;
@@ -909,7 +920,7 @@ ssl_parse_record(
/*
* The initial state parses the "type" byte. There are only a few types
- * defined so far, the values 20-25, but more can be defined in the
+ * defined so far, the values 20-25, but socket can be defined in the
* future. The standard explicitly says that they must be lower than 128,
* so if the high-order bit is set, we know that the byte is invalid,
* and that something is wrong.
@@ -992,7 +1003,7 @@ ssl_parse_record(
pstate,
px+i, len,
banout,
- more);
+ socket);
break;
case 22: /* handshake */
parse_handshake(banner1,
@@ -1000,7 +1011,7 @@ ssl_parse_record(
pstate,
px+i, len,
banout,
- more);
+ socket);
break;
case 23: /* application data */
/* encrypted, always*/
@@ -1012,7 +1023,7 @@ ssl_parse_record(
pstate,
px+i, len,
banout,
- more);
+ socket);
break;
}
@@ -1064,64 +1075,49 @@ ssl_init(struct Banner1 *banner1)
*****************************************************************************/
static const char
ssl_hello_template[] =
-"\x16\x03\x02\x01\x6f" /* TLSv1.1 record layer */
+"\x16\x03\x01\x00\xc1" /* TLSv1.0 record layer */
"\x01" /* type = client-hello */
-"\x00\x01\x6b" /* length = 363 */
-"\x03\x02" /* version = 3.02 (TLS 1.1) */
+"\x00\x00\xbd" /* length = 193 */
+"\x03\x03" /* version = 3.03 (TLS 1.2) */
-"\x52\x48\xc5\x1a\x23\xf7\x3a\x4e\xdf\xe2\xb4\x82\x2f\xff\x09\x54" /* random */
-"\x9f\xa7\xc4\x79\xb0\x68\xc6\x13\x8c\xa4\x1c\x3d\x22\xe1\x1a\x98" /* TODO: re-randomize for each request, or at least on startup */
+"\x97\xe5\x60\x50\xc4\xa5\x4a\xe0\xb9\x01\x75\x15\x31\x23\x27\x68" /* random */
+"\x87\xdc\x3d\x66\xec\x07\xdc\xa0\xe5\x1f\x1f\xa1\x3f\x49\xf8\xfc" /* TODO: re-randomize for each request, or at least on startup */
-"\x20" /* session-id-length = 32 */
-"\x84\xb4\x2c\x85\xaf\x6e\xe3\x59\xbb\x62\x68\x6c\xff\x28\x3d\x27" /* random */
-"\x3a\xa9\x82\xd9\x6f\xc8\xa2\xd7\x93\x98\xb4\xef\x80\xe5\xb9\x90" /* TODO: re-randomize for each request, or at least on startup */
+"\x00"/* session-id-length = 0 */
-"\x00\x28" /* cipher suites length */
-"\xc0\x0a\xc0\x14\x00\x39\x00\x6b\x00\x35\x00\x3d\xc0\x07\xc0\x09"
-"\xc0\x23\xc0\x11\xc0\x13\xc0\x27\x00\x33\x00\x67\x00\x32\x00\x05"
-"\x00\x04\x00\x2f\x00\x3c\x00\x0a"
+"\x00\x3c" /* cipher suites length */
+"\xc0\x2b\xcc\xa9\xc0\x2c\xc0\x09\xc0\x0a\xc0\x23\xc0\x24\xc0\x2f"
+"\xcc\xa8\xc0\x30\xc0\x13\xc0\x14\xc0\x27\xc0\x28\x00\x9e\xcc\xaa"
+"\x00\x9f\x00\x33\x00\x39\x00\x67\x00\x6b\x00\x9c\x00\x9d\x00\x3c"
+"\x00\x3d\x00\x2f\x00\x35\x00\x0a\x00\x05\x00\xff"
"\x01" /* compression-methods-length = 1 */
"\x00"
-"\x00\xfa" /* extensions length */
-
-/* server name */
-"\xef\x00"
-"\x00\x1a"
-"\x00\x18\x00\x00\x15\x73\x79\x6e\x64\x69\x63\x61\x74\x69\x6f\x6e"
-"\x2e\x74\x77\x69\x6d\x67\x2e\x63\x6f\x6d"
-
-"\xff\x01"
-"\x00\x01"
-"\x00"
-
-"\x00\x0a"
-"\x00\x08"
-"\x00\x06\x00\x17\x00\x18\x00\x19"
-
-"\x00\x0b"
-"\x00\x02"
-"\x01\x00"
-
-"\x00\x23"
-"\x00\xb0"
-"\x81\x01\x19\x67\x60\x1e\x04\x42\x9a\xf3\xe2\x3c\x86\x58\x4f\x87"
-"\x69\x44\xb0\x1d\x8e\x01\xfa\xa5\x87\x3d\x5d\xdc\x16\x4c\xb4\x20"
-"\xda\xd3\x42\xb0\x88\xec\x0a\x13\xc3\xc6\x4c\x44\x74\x7d\xf5\x83"
-"\x93\xeb\x16\x60\x7e\x47\x07\x15\xae\x68\x3f\x32\xfc\x28\x71\xdd"
-"\x8d\x2a\xe0\x9e\x03\xad\x28\xd9\x89\x2f\x0f\x07\xaf\xc1\x27\x8e"
-"\xf1\x57\xfb\xc6\xc4\xd4\x56\x3a\xf6\xed\x59\x61\x4a\x17\x14\x0b"
-"\xd7\x7c\xae\xfe\x55\xd9\x7a\xa6\xf6\xc6\x57\xb5\x3c\xed\x78\x9d"
-"\xee\x39\xd8\x67\x02\x09\x92\xcb\xa5\x66\xa3\x48\x3d\x06\xed\xa5"
-"\x02\x2e\x9b\x16\xf6\x2b\xe7\x3f\x79\x65\x1a\xcb\x6c\x5c\xbd\x6b"
-"\xad\x11\xde\xbe\xdf\x35\xdb\x0b\xff\x2c\x90\x94\x32\xb5\x94\x57"
-"\x3d\x5e\x25\xd2\x1b\xd2\x44\x85\x96\x31\x28\x69\xd7\x4a\x13\x0a"
-"\x33\x74\x00\x00\x75\x4f\x00\x00\x00\x05\x00\x05\x01\x00\x00\x00"
-"\x00"
+"\x00\x58" /* extensions length = 88 */
+/* extensions */
+"\x00\x0b\x00\x04\x03\x00\x01\x02\x00\x0a\x00\x0c\x00\x0a\x00\x1d"
+"\x00\x17\x00\x1e\x00\x19\x00\x18\x00\x23\x00\x00\x00\x16\x00\x00"
+"\x00\x17\x00\x00\x00\x0d\x00\x30\x00\x2e\x04\x03\x05\x03\x06\x03"
+"\x08\x07\x08\x08\x08\x09\x08\x0a\x08\x0b\x08\x04\x08\x05\x08\x06"
+"\x04\x01\x05\x01\x06\x01\x03\x03\x02\x03\x03\x01\x02\x01\x03\x02"
+"\x02\x02\x04\x02\x05\x02\x06\x02"
;
-
+/*****************************************************************************
+ * This is the template "Client Hello" packet that is sent to the server
+ * to initiate the SSL connection. Right now, it's statically just transmitted
+ * on to the wire.
+ * TODO: we need to make this dynamically generated, so that users can
+ * select various options.
+ *****************************************************************************/
+static const char
+ssl_12_hello_template[] =
+"\x16\x03\x01\x01\x1a"
+"\x01"
+"\x00\x01\x16"
+"\x03\x03\x02\x58\x33\x79\x5f\x71\x03\xef\x07\xfe\x36\x61\xb0\x32\x81\xaa\x99\x10\x87\x6a\x8e\x5b\xf9\x03\x93\x44\x58\x4b\x19\xff\x42\x6a\x20\x64\x84\xcd\x28\x9c\xe9\xb1\x9d\xcd\x8a\x11\x4c\x3b\x40\x1c\x90\x02\xf2\xb5\x1a\xf1\x7e\x5d\xb8\x42\xc2\x1e\x17\x1e\x59\xa4\xac\x00\x3e\x13\x02\x13\x03\x13\x01\xc0\x2c\xc0\x30\x00\x9f\xcc\xa9\xcc\xa8\xcc\xaa\xc0\x2b\xc0\x2f\x00\x9e\xc0\x24\xc0\x28\x00\x6b\xc0\x23\xc0\x27\x00\x67\xc0\x0a\xc0\x14\x00\x39\xc0\x09\xc0\x13\x00\x33\x00\x9d\x00\x9c\x00\x3d\x00\x3c\x00\x35\x00\x2f\x00\xff\x01\x00\x00\x8f\x00\x0b\x00\x04\x03\x00\x01\x02\x00\x0a\x00\x0c\x00\x0a\x00\x1d\x00\x17\x00\x1e\x00\x19\x00\x18\x00\x23\x00\x00\x00\x16\x00\x00\x00\x17\x00\x00\x00\x0d\x00\x2a\x00\x28\x04\x03\x05\x03\x06\x03\x08\x07\x08\x08\x08\x09\x08\x0a\x08\x0b\x08\x04\x08\x05\x08\x06\x04\x01\x05\x01\x06\x01\x03\x03\x03\x01\x03\x02\x04\x02\x05\x02\x06\x02\x00\x2b\x00\x09\x08\x03\x04\x03\x03\x03\x02\x03\x01\x00\x2d\x00\x02\x01\x01\x00\x33\x00\x26\x00\x24\x00\x1d\x00\x20\xb6\x87\xb7\x72\xb9\xcb\x07\xe0\x14\x0a\x14\x81\x3f\x3f\x0a\xcc\xc4\x7d\x80\xf7\xe8\xaa\x1e\x73\xb0\xa9\xad\xb8\x3a\xa7\x3c\x64";
+;
/*****************************************************************************
*****************************************************************************/
static char *
@@ -1274,11 +1270,11 @@ static int
ssl_selftest(void)
{
struct Banner1 *banner1;
- struct ProtocolState state[1];
+ struct StreamState state[1];
unsigned ii;
struct BannerOutput banout1[1];
struct BannerOutput banout2[1];
- struct InteractiveData more;
+
unsigned x;
/*
@@ -1353,7 +1349,7 @@ ssl_selftest(void)
ssl_test_case_3+i,
1,
banout1,
- &more
+ 0
);
}
/*if (0) {
@@ -1388,7 +1384,7 @@ ssl_selftest(void)
(const unsigned char *)ssl_test_case_3+ii,
1,
banout2,
- &more
+ 0
);
banner1_destroy(banner1);
banout_release(banout2);
@@ -1436,10 +1432,20 @@ ssl_selftest(void)
* This is the 'plugin' structure that registers callbacks for this parser in
* the main system.
*****************************************************************************/
-struct ProtocolParserStream banner_ssl = {
- "ssl", 443, ssl_hello_template, sizeof(ssl_hello_template)-1, 0,
+struct ProtocolParserStream banner_ssl_12 = {
+ "ssl", 443, ssl_12_hello_template, sizeof(ssl_12_hello_template)-1, 0,
ssl_selftest,
ssl_init,
ssl_parse_record,
};
+struct ProtocolParserStream banner_ssl = {
+ "ssl", 443, ssl_hello_template, sizeof(ssl_hello_template)-1,
+ SF__close, /* send FIN after the hello */
+ ssl_selftest,
+ ssl_init,
+ ssl_parse_record,
+ 0,
+ 0,
+ &banner_ssl_12,
+};
diff --git a/src/proto-ssl.h b/src/proto-ssl.h
index 72b9b4b8..9d726a54 100644
--- a/src/proto-ssl.h
+++ b/src/proto-ssl.h
@@ -3,6 +3,7 @@
#include "proto-banner1.h"
extern struct ProtocolParserStream banner_ssl;
+extern struct ProtocolParserStream banner_ssl_12;
extern const char *ssl_hello_heartbeat_template;
extern const char *ssl_hello_ticketbleed_template;
diff --git a/src/proto-tcp-rdp.c b/src/proto-tcp-rdp.c
index d5085a07..8ea2ae96 100644
--- a/src/proto-tcp-rdp.c
+++ b/src/proto-tcp-rdp.c
@@ -1,14 +1,14 @@
#include "proto-tcp-rdp.h"
#include "proto-banner1.h"
-#include "proto-interactive.h"
+#include "stack-tcp-api.h"
#include "unusedparm.h"
#include "masscan-app.h"
#include "util-malloc.h"
#include "assert.h"
#include
#include
-#include "string_s.h"
+#include "util-safefunc.h"
/***************************************************************************
* @param length
@@ -201,10 +201,10 @@ cotp_parse(struct BannerOutput *banout, struct RDPSTUFF *rdp, const unsigned cha
static void
rdp_parse( const struct Banner1 *banner1,
void *banner1_private,
- struct ProtocolState *pstate,
+ struct StreamState *pstate,
const unsigned char *px, size_t length,
struct BannerOutput *banout,
- struct InteractiveData *more)
+ struct stack_handle_t *socket)
{
unsigned state = pstate->state & 0xFFFFFF;
struct RDPSTUFF *rdp = &pstate->sub.rdp;
@@ -218,7 +218,7 @@ rdp_parse( const struct Banner1 *banner1,
};
UNUSEDPARM(banner1_private);
UNUSEDPARM(banner1);
- UNUSEDPARM(more);
+ UNUSEDPARM(socket);
for (offset=0; offset
#include