initial commit

This commit is contained in:
2026-06-19 07:07:20 +00:00
commit 33435ab4b4
258 changed files with 67880 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
paused.conf
.Makefile.swp
.vscode
vs10/.vs/

387
FORK.md Normal file
View File

@@ -0,0 +1,387 @@
# masscan fork — changelog
This is a modified fork of [robertdavidgraham/masscan](https://github.com/robertdavidgraham/masscan).
**Base commit:** `94e118c` (Merge pull request #844 from p-l-/fix-smb-segfault)
**Purpose of the fork:**
1. Remove every wire-level fingerprint that lets a passive observer say "this is masscan." All known signatures (TLS hardcoded random, ICMP `0x08..0x37` payload, UDP `masscan-test` literals, IP-ID XOR formula, default SYN template, banner-grab anomalies) have been replaced with values that look like a normal Linux or Windows host doing TLS 1.2 cert harvesting.
2. Greatly expand the set of services masscan can banner-grab out of the box — adds PostgreSQL, Cassandra, Modbus, Siemens S7, OPC UA, DNP3, EtherNet/IP, BACnet, plus 50+ HTTP/HTTPS bindings on alt ports (Grafana, Kibana, Prometheus, k8s, Docker, Elasticsearch, etc.).
3. Auto-discover and load nmap's `nmap-payloads` file if installed, giving UDP probe coverage on hundreds more ports without a CLI flag.
CLI is **100% backward-compatible** with upstream masscan. Drop in `bin/masscan` and existing config files / commands keep working. The OS-mimicry chosen at startup is silently picked between Linux (50%) and Windows (50%); no flag changes that.
---
## File-by-file changes
Diff stats vs. upstream:
| File | Lines added | Lines removed |
| --- | --- | --- |
| `src/main-conf.c` | +26 | -4 |
| `src/proto-banner1.c` | +229 | -0 |
| `src/proto-http.c` | +15 | -9 |
| `src/proto-ssl.c` | +84 | -29 |
| `src/stack-tcp-core.c` | +3 | -1 |
| `src/templ-payloads.c` | +57 | -10 |
| `src/templ-pkt.c` | +152 | -41 |
| **Total** | **+566** | **-94** |
---
### `src/templ-pkt.c` — Packet templates
This is the file that owns the byte-level templates masscan copies and rewrites at send time. Most of the fingerprint work landed here.
#### 1. Replaced the single SYN template with Linux + Windows variants
**Where:** Lines 30141 (was: lines 3054).
**What:**
- The original `default_tcp_template[]` (TTL=255, win=1024, DF clear, options = MSS=1460 only — every one of those is a known masscan tell) was replaced with two static templates:
- `linux_tcp_template[]` — TTL=64, win=64240, DF set, options = `MSS=1460, SAckOK, Timestamp(0/0), NOP, WScale=7` (full Linux 5.x/6.x SYN, 40-byte TCP header)
- `windows_tcp_template[]` — TTL=128, win=64240, DF set, options = `MSS=1460, NOP, WScale=8, NOP, NOP, SAckOK` (Windows 10/11 SYN, 32-byte TCP header)
- New function `mimicry_select_os()` picks one at startup using `time(NULL) ^ (getpid() << 16)` as the seed. Exported via `int g_masscan_mimic_os` (0=Linux, 1=Windows) so other code paths can match the chosen OS if needed.
- `default_tcp_template` is now a pointer set by `mimicry_select_os()`; `default_tcp_template_size` is the size of whichever was picked.
**Why:** The original masscan SYN signature (`win=1024 + TTL=255 + DF clear + opts=[MSS=1460]`) is detected by every "is this a scanner?" rule. Real Linux and Windows hosts never look like that.
**Callsite update at line 1525:** `template_packet_init()` now calls `mimicry_select_os()` before initializing the TCP template, then uses `default_tcp_template_size` instead of `sizeof(default_tcp_template) - 1`.
#### 2. IP-ID changed from XOR formula to random per packet
**Where:** Line 525 (function `tcp_create_packet`, IPv4 path) and line 1033 (function that builds outbound SYNs).
**Old:** `unsigned ip_id = ip_them.ipv4 ^ port_them ^ seqno;`
**New:** `unsigned ip_id = ((unsigned)rand() ^ ((unsigned)rand() << 8)) & 0xFFFF;`
**Why:** The XOR formula was masscan-unique and verifiable from a single packet. Real OS stacks emit random IP-IDs. Reply validation still works because masscan validates the SipHash cookie embedded in the TCP ackno, not the IP-ID.
#### 3. ICMP echo payload rewritten
**Where:** Lines 199224 (the `default_icmp_ping_template[]` array).
**Old:** 48 bytes of `0x08, 0x09, 0x0a, …, 0x37` (ascending starting at 0x08).
**New:** 8 zero bytes (placeholder for `struct timeval` like Linux ping uses) followed by 40 bytes of `0x10, 0x11, …, 0x37` (Linux ping ascending pattern).
**Why:** The exact `0x08..0x37` 48-byte payload is masscan's ICMP signature — neither Linux ping nor Windows ping nor nmap produces that pattern.
#### 4. ICMP / UDP IP header TTL and DF flag
**Where:** Lines 200, 201, 237, 238 (ICMP echo and timestamp templates), and lines 65, 66 (UDP template).
**Old:** TTL=255 (0xFF), DF flag clear.
**New:** TTL=64 (0x40), DF flag set.
**Why:** Match Linux defaults instead of masscan's high-TTL no-DF combo.
#### 5. Banner-grab packet construction (`tcp_create_packet`)
**Where:** Lines 519550 (the IPv4 branch start) and lines 605614 (window write site).
**Two problems fixed in one block:**
(a) Non-SYN segments were inheriting the SYN template's full TCP option block. That meant ACK / PSH-ACK / FIN packets carried an `MSS=1460` option — which is illegal per RFC and a masscan-specific banner-grab tell.
**Fix:** Detect SYN vs non-SYN via `(flags & 0x02)`. For non-SYN, force `tcp_header_len = 20` (no options) and overwrite `px[offset_tcp+12]` to data-offset 5.
(b) Window was hardcoded to 1200 on every non-SYN packet (and 600 for the "small-window" kludge).
**Fix:** Window now written as 64240 (realistic post-handshake Linux/Windows value).
**Why:** A non-SYN segment carrying MSS, combined with window=1200, was the smoking-gun signature for masscan's `--banners` mode. Both gone now.
#### 6. Added `<time.h>` and `<unistd.h>` for `time()` / `getpid()`
**Where:** Lines 2835.
**Why:** Needed by `mimicry_select_os()`. Wrapped in `#ifdef _WIN32` for Windows compat.
---
### `src/templ-payloads.c` — UDP probes
#### 1. Stripped masscan literal strings from UDP probes
**Where:** Lines 6774 (ports 7, 17, 19), line 90 (port 69 TFTP), line 130 (port 138 NetBIOS), line 243 (port 1701 L2TP), line 255 (port 1900 SSDP).
**What:**
| Port | Old payload | New payload |
| --- | --- | --- |
| 7 echo | `"masscan-test 0x00000000"` | 12 `\n` bytes |
| 17 qotd | `"masscan-test"` | 12 `\n` bytes |
| 19 chargen | `"masscan-test"` | 12 `\n` bytes |
| 69 TFTP | filename `"masscan-test"` | filename `"anonymous_cf"` |
| 138 SMB browser | NetBIOS-encoded `MASSCAN-TEST<00>` | NetBIOS-encoded `WORKSTATION<00>` |
| 1701 L2TP | hostname `"masscan1"` | hostname `"vpnhost1"` |
| 1900 SSDP | UA `unix/1.0 UPnP/1.1 masscan/1.x` | UA `unix/1.0 UPnP/1.1 Linux/1.0.0` |
**Why:** Any one of those literals appearing in a UDP probe is sufficient to fingerprint masscan instantly.
#### 2. Added `dtls_set_random` callback
**Where:** New function at lines 5169 (after the `PayloadUDP_Item` struct), wired into the UDP/443 DTLS probe at line 182.
**What:** Overwrites the 32 bytes of DTLS ClientHello `client_random` (at payload offset 27) with `rand()` bytes for every probe.
**Why:** The original DTLS template had a fixed hardcoded random `1d b1 e3 52 …` — a masscan signature. Now it's regenerated per probe like a real DTLS client.
#### 3. Added BACnet/IP Who-Is probe
**Where:** Lines 491504 (new entry in `hard_coded_udp_payloads[]`).
**Port:** 47808 UDP.
**What:** 12-byte BVLC Original-Broadcast-NPDU containing a Who-Is APDU. Response is an I-Am that reveals object ID, max APDU size, segmentation support, and vendor ID (which identifies the building automation manufacturer).
**Why:** Industrial protocol coverage. Before this masscan had zero BACnet support.
#### 4. Added EtherNet/IP UDP probe
**Where:** Lines 506516 (new entry).
**Port:** 44818 UDP.
**What:** 24-byte CIP List Identity packet. Response reveals vendor, product code, revision, serial number, device name, and the device's IP — extremely rich Allen-Bradley / Rockwell device fingerprint.
**Why:** Same reason as BACnet — industrial reconnaissance.
---
### `src/proto-ssl.c` — TLS ClientHello
#### 1. Removed `const` from both templates
**Where:** Lines 1098, 1129 (template declarations).
**Old:** `static const char ssl_hello_template[] = …`
**New:** `char ssl_hello_template[] = …` (file-scope, writable, externally visible via forward declarations).
**Why:** The `client_random` field has to be overwritten by `ssl_init()` at startup. `static const` couldn't be modified.
#### 2. `ssl_init()` randomizes `client_random` at startup
**Where:** Lines 10621086.
**What:** First call to `ssl_init()` (one-time, gated by `static int randomized` flag) overwrites bytes 11..42 of both `ssl_hello_template` and `ssl_12_hello_template` with `rand()` bytes.
**Why:** The original masscan random `97 e5 60 50 c4 a5 4a e0 …` is the single most reliable masscan signature on the wire — it's literally the same 32 bytes on every TLS probe from every masscan ever. Now each scan run has a fresh random, and the static byte sequence is gone.
**Trade-off documented:** All probes in one scan run still share the same random. Per-probe randomization would require switching from a static `stream->hello` buffer to a `transmit_hello` callback. Deferred — defeats the static-bytes fingerprint, which is the actual public detector.
#### 3. Replaced `ssl_hello_template` with curl-shape ClientHello + ALPN
**Where:** Lines 10981163 (the template body).
**What:**
- **Version:** TLS 1.2 only (no `supported_versions` extension → servers don't negotiate TLS 1.3 → certs come back in cleartext).
- **Ciphers:** 21 modern TLS 1.2 ciphers, AEAD-first ordering (`ECDHE-*-AES256-GCM-SHA384` first, RSA fallbacks last, `EMPTY_RENEGOTIATION_INFO_SCSV` always).
- **Extensions:** `ec_point_formats`, `supported_groups` (x25519, secp256r1, secp384r1), `session_ticket`, `extended_master_secret`, `encrypt_then_mac`, `signature_algorithms` (13 algos), and the new **`application_layer_protocol_negotiation` extension advertising `h2, http/1.1`**.
**Why:** Original masscan TLS hello had unique cipher ordering + extension set that produced a masscan-specific JA3 hash. New version matches the JA3 of a curl 8.x request — passes most "block known scanners" lists.
**Why TLS 1.2 only, not Chrome 120:** If we advertised TLS 1.3 (via `supported_versions`), modern servers would pick TLS 1.3 and encrypt the certificate. Defeats the whole point of cert harvesting. The trade-off is being slightly less browser-like.
**Validation:** Cloudflare DNS (1.1.1.1:443) handshakes successfully, returns cipher 0xc02b, full cert chain + SAN list. Frantech scan: cert records went from 29 → 40 (+38%) with this hello vs. upstream.
---
### `src/proto-http.c` — HTTP probe
#### Replaced HTTP request line and headers
**Where:** Lines 386401 (the `http_hello[]` static).
**Old:**
```
GET / HTTP/1.0\r\n
User-Agent: ivre-masscan/1.3 https://github.com/robertdavidgraham/\r\n
Accept: */*\r\n
\r\n
```
**New:** Full Chrome 120 (Linux) header set:
```
GET / HTTP/1.1\r\n
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8\r\n
Accept-Language: en-US,en;q=0.9\r\n
Accept-Encoding: gzip, deflate\r\n
Connection: close\r\n
\r\n
```
**Why:** The `ivre-masscan/1.3 https://github.com/robertdavidgraham/` User-Agent appearing in a web server log says "masscan" instantly. Chrome 120 with a full browser header set passes basic UA filters and looks like normal traffic in access logs. HTTP/1.0 → HTTP/1.1 because Chrome never sends 1.0.
---
### `src/stack-tcp-core.c` — Banner-grab TCP stack
#### Small-window kludge value changed
**Where:** Line 1167.
**Old:** `tcp_set_window(response->px, response->length, 600);`
**New:** `tcp_set_window(response->px, response->length, 32768);`
**Why:** The 600-byte window was a masscan-specific small-window kludge that combined with `MSS=1460` option in non-SYN segments to make the banner-grab signature trivially detectable. 32768 is a realistic Linux half-default.
---
### `src/proto-banner1.c` — Port → protocol bindings + new TCP hellos
This is the biggest single file change (+229 lines, no deletions). Everything is additive.
#### 1. New TCP hellos for application services
**Where:** Lines 487521 (after `banner_ms_sql_s`).
| Protocol | Port | Probe sent | Yields |
| --- | --- | --- | --- |
| PostgreSQL | 5432 | 8-byte SSLRequest packet `\x00\x00\x00\x08\x04\xd2\x16\x2f` | `S`/`N` response confirming postgres; on `N` often errors with version |
| Cassandra | 9042, 9160 | CQL v3 STARTUP frame with `CQL_VERSION=3.0.0` | READY or AUTHENTICATE frame revealing protocol version |
#### 2. New TCP hellos for industrial / SCADA
**Where:** Lines 525610.
| Protocol | Port | Probe | Yields |
| --- | --- | --- | --- |
| Siemens S7 | 102 | TPKT + COTP CR (rack 0, slot 0, dst TSAP = PG) | COTP CC with PLC presence |
| Modbus | 502 | MBAP + Read Device Identification (func 0x2B / 0x0E) | Vendor name, product code, revision |
| OPC UA | 4840 | HEL message with 1 MB receive buffer | ACK message with endpoint protocol version |
| DNP3 | 20000 | Link layer request, dst=0, src=1 | DNP3 link header revealing addresses |
| EtherNet/IP | 44818 | CIP List Identity command | Vendor, product, revision, serial, device name |
#### 3. Mass port → protocol registrations
**Where:** Lines 666784 (inside `banner1_create()`).
Added bindings for ~70 ports:
- **HTTP** on 81, 280, 591, 631, 2000, 3000, 3001, 3128, 4000, 4040, 4567, 5000, 5601, 5984, 6080, 7001, 7070, 7474, 7547, 8000, 8001, 8008, 8009, 8086, 8088, 8090, 8123, 8161, 8200, 8222, 8400, 8500, 8545, 8800, 8888, 8983, 9000, 9043, 9080, 9090, 9091, 9100, 9200, 9300, 9418, 9981, 10000, 10255, 15672, 18083, 26657, 50070, 50075
- **TLS** on 4443, 5044, 5223, 5986, 6443, 7443, 8243, 8333, 8443, 8834, 8843, 9443, 10250, 10443
- **Redis** on 16379, 26379 (cluster bus + Sentinel)
- **memcached** on 11212 (alt)
- **etcd HTTP** on 2379, 2380 (overrides upstream Docker registration for these)
- **PostgreSQL** on 5432
- **Cassandra** on 9042, 9160
- **Industrial:** 102, 502, 4840, 20000, 44818
**Why:** Stock masscan only had ~30 baked-in port→protocol bindings. Every additional binding means a probe gets sent on that port without the user passing a CLI flag — much higher banner capture rate on modern app servers (Grafana, Kibana, Prometheus, k8s, Docker, Elasticsearch, RabbitMQ, etc.) and on industrial systems.
---
### `src/main-conf.c` — Auto-load nmap-payloads
#### Auto-detect installed nmap and load its UDP payload database
**Where:** Lines 31743208.
**What:** If `--nmap-payloads` was not passed (or was passed as empty), check three standard install paths in order:
1. `/usr/share/nmap/nmap-payloads`
2. `/usr/local/share/nmap/nmap-payloads`
3. `/opt/nmap/share/nmap/nmap-payloads`
If any exists, log `[+] auto-loading nmap-payloads from <path>` and use it as if `--nmap-payloads <path>` had been passed.
**Why:** nmap's `nmap-payloads` file ships ~300 UDP probes for protocols masscan doesn't have built-in. Loading it adds full coverage of those services for free, without changing the user's CLI. (Note: modern nmap on some distros — Ubuntu 24.04 included — compiles the payloads into the binary instead of shipping the file, so the auto-load is a no-op there. Still works on Alpine and older systems.)
---
## What the fork does **not** change
These are deliberately deferred:
- **No SNI extension in TLS hello.** The `server_name` extension would significantly improve cert harvesting from CDN-fronted hosts, but per-target SNI requires switching from `static char hello[]` to a `transmit_hello` callback. ~half-day of work; not done yet.
- **No Chrome 120 ClientHello with GREASE.** The curl-shape hello defeats the "is this masscan?" detection, which was the goal. Full Chrome JA3 mimicry only helps if you specifically need to evade Cloudflare WAF / Imperva / Akamai bot blockers.
- **No per-connection TCP timestamp simulation.** The Linux SYN template includes a Timestamp option with zero placeholders. Real Linux uses a tcp_clock millisecond counter and echoes the peer's TSval. Adding this requires per-TCB state — not free.
- **No multi-threaded banner-grab.** The userland TCP stack in `stack-tcp-core.c` is single-threaded by design. At very high banner-grab rates (theoretically) the receive thread saturates. Multi-threading it is real work and we haven't proved it's actually the bottleneck in practice.
- **CLI unchanged.** No new flags. The OS-mimic chosen at startup is random (50% Linux, 50% Windows) and there's no `--mimic-os <linux|windows>` flag. Add one if you want determinism.
---
## Validation done
| Test | How | Result |
| --- | --- | --- |
| Build cleanly | `make` with `-Wall -O2` | ✅ no warnings beyond upstream's |
| Real-world scan | Frantech /9 (72k hosts), 8 ports, `--banners`, `--rate 3000` | ✅ 34,897 opens found, ~309 banners completed, TLS cert chains parsed from Let's Encrypt |
| Cloudflare DNS TLS handshake | `masscan 1.1.1.1 -p443 --banners` | ✅ TLS/1.2 cipher 0xc02b, full SAN list (`cloudflare-dns.com, *.cloudflare-dns.com`) |
| Fingerprint detection (own tool) | Run `masscanned.py` against 500-packet capture (310 SYNs + 41 PSH-ACKs from real scan) | ✅ 0 hits across all 9 detector categories |
| SYN shape check | Inspect outbound SYN with scapy | ✅ TTL=128, win=64240, DF set, dataofs=8, options match Windows 10 byte-for-byte |
The fingerprint detector ([`masscanned.py`](../masscan/research/masscanned.py)) is the same one used in our research to identify masscan packets — it knows every public masscan signature. On 500 packets from this build, zero signatures fire.
---
## Open issues
Documented honestly because they exist:
1. **Banner-grab completion rate at high `--rate` is low.** On 35k open ports we got ~309 banners. That's either (a) most of those ports aren't running services that respond to our default hellos, (b) masscan's single-threaded userland stack saturates somewhere below 510k banner-grabs/sec, or (c) `--wait 10` isn't enough for the tail of slow targets. Unverified — we haven't measured the actual saturation point. Workaround: two-pass scanning (SYN-only first, targeted banner-grab pass at lower rate on the open set).
2. **One occasional `UNHANDLED EVENT` warning** during banner-grab: `[-] <ip>:443: FIN-WAIT-1-SEND:SYNACK **** UNHANDLED EVENT ****`. Pre-existing upstream behavior — happens when a target sends SYN-ACK during connection teardown. Harmless.
3. **TLS 1.2-only ClientHello means TLS-1.3-mandatory servers don't return clear-text certs.** A small minority of modern sites (mostly Cloudflare with HTTP/3 priority). Workaround: send a follow-up probe with TLS 1.3 advertisement — but then certs are encrypted and you only get the JA3-S.
4. **Some hello-string probes overlap with masscan's built-in pattern matching.** When the user generates a config file from `nmap-service-probes` and includes it, ports may get an unexpected hello (e.g., port 80 gets `OPTIONS / RTSP/1.0` instead of `GET /`). Last-wins / first-wins semantics handled by the Python generator, but worth understanding.
---
## How to use
Identical to upstream masscan. Examples:
```sh
# Simple scan
sudo bin/masscan 10.0.0.0/8 -p80,443 --rate 100000
# With banners
sudo bin/masscan -iL targets.txt -p- --rate 50000 --banners \
--output-format ndjson --output-filename results.ndjson
# Distributed (32 shards)
sudo bin/masscan --shards 1/32 --seed 42 -iL all-v4.txt ...
sudo bin/masscan --shards 2/32 --seed 42 -iL all-v4.txt ...
# etc.
```
Which OS template got picked this run? Check the first outbound SYN's TTL:
- TTL = 64 → Linux template active
- TTL = 128 → Windows template active
---
## Building
Standard masscan build. From the repo root:
```sh
make # gcc, -Wall -O2, single-threaded build
make clean # nuke tmp/
```
Binary lands at `bin/masscan`. Drop-in replacement for `/usr/bin/masscan`.
Dependencies same as upstream: `libpcap-dev`, `gcc`, `make`. No new deps.
---
## Diff against upstream
```sh
# Quick stats
diff -r /home/acidvegas/masscan-src/src ./src | grep -c "^[<>]"
# Full diff
diff -r /home/acidvegas/masscan-src/src ./src
```

661
LICENSE Normal file
View File

@@ -0,0 +1,661 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.

138
Makefile Normal file
View File

@@ -0,0 +1,138 @@
# If Windows, then assume the compiler is `gcc` for the
# MinGW environment. I can't figure out how to tell if it's
# actually MingGW. FIXME TODO
ifeq ($(OS),Windows_NT)
CC = gcc
endif
# Try to figure out the default compiler. I dont know the best
# way to do this with `gmake`. If you have better ideas, please
# submit a pull request on github.
ifeq ($(CC),)
ifneq (, $(shell which clang))
CC = clang
else ifneq (, $(shell which gcc))
CC = gcc
else
CC = cc
endif
endif
PREFIX ?= /usr
BINDIR ?= $(PREFIX)/bin
SYS := $(shell $(CC) -dumpmachine)
GITVER := $(shell git describe --tags)
INSTALL_DATA := -pDm755
ifeq ($(GITVER),)
GITVER = "unknown"
endif
# LINUX
# The automated regression tests run on Linux, so this is the one
# environment where things likely will work -- as well as anything
# works on the bajillion of different Linux environments
ifneq (, $(findstring linux, $(SYS)))
ifneq (, $(findstring musl, $(SYS)))
LIBS =
else
LIBS = -lm -lrt -ldl -lpthread
endif
INCLUDES =
FLAGS2 =
endif
# MAC OS X
# I occassionally develope code on Mac OS X, but it's not part of
# my regularly regression-test environment. That means at any point
# in time, something might be minorly broken in Mac OS X.
ifneq (, $(findstring darwin, $(SYS)))
LIBS = -lm
INCLUDES = -I.
FLAGS2 =
INSTALL_DATA = -pm755
endif
# MinGW on Windows
# I develope on Visual Studio 2010, so that's the Windows environment
# that'll work. However, 'git' on Windows runs under MingGW, so one
# day I acccidentally typed 'make' instead of 'git, and felt compelled
# to then fix all the errors, so this kinda works now. It's not the
# intended environment, so it make break in the future.
ifneq (, $(findstring mingw, $(SYS)))
INCLUDES = -Ivs10/include
LIBS = -L vs10/lib -lIPHLPAPI -lWs2_32
#FLAGS2 = -march=i686
endif
# Cygwin
# I hate Cygwin, use Visual Studio or MingGW instead. I just put this
# second here for completeness, or in case I gate tired of hitting my
# head with a hammer and want to feel a different sort of pain.
ifneq (, $(findstring cygwin, $(SYS)))
INCLUDES = -I.
LIBS =
FLAGS2 =
endif
# OpenBSD
ifneq (, $(findstring openbsd, $(SYS)))
LIBS = -lm -lpthread
INCLUDES = -I.
FLAGS2 =
endif
# FreeBSD
ifneq (, $(findstring freebsd, $(SYS)))
LIBS = -lm -lpthread
INCLUDES = -I.
FLAGS2 =
endif
# NetBSD
ifneq (, $(findstring netbsd, $(SYS)))
LIBS = -lm -lpthread
INCLUDES = -I.
FLAGS2 =
endif
DEFINES =
CFLAGS = -g -ggdb $(FLAGS2) $(INCLUDES) $(DEFINES) -Wall -O2
.SUFFIXES: .c .cpp
all: bin/masscan
tmp/main-conf.o: src/main-conf.c src/*.h
$(CC) $(CFLAGS) -c $< -o $@ -DGIT=\"$(GITVER)\"
# just compile everything in the 'src' directory. Using this technique
# means that include file dependencies are broken, so sometimes when
# the program crashes unexpectedly, 'make clean' then 'make' fixes the
# problem that a .h file was out of date
tmp/%.o: src/%.c src/*.h
$(CC) $(CFLAGS) -c $< -o $@
SRC = $(sort $(wildcard src/*.c))
OBJ = $(addprefix tmp/, $(notdir $(addsuffix .o, $(basename $(SRC)))))
bin/masscan: $(OBJ)
$(CC) $(CFLAGS) -o $@ $(OBJ) $(LDFLAGS) $(LIBS)
clean:
rm -f tmp/*.o
rm -f bin/masscan
regress: bin/masscan
bin/masscan --selftest
test: regress
install: bin/masscan
install $(INSTALL_DATA) bin/masscan $(DESTDIR)$(BINDIR)/masscan
default: bin/masscan

617
README.md Normal file
View File

@@ -0,0 +1,617 @@
[![unittests](https://github.com/robertdavidgraham/masscan/actions/workflows/unittests.yml/badge.svg?branch=master)](https://github.com/robertdavidgraham/masscan/actions/workflows/unittests.yml/?branch=master)
# MASSCAN: Mass IP port scanner
This is an Internet-scale port scanner. It can scan the entire Internet
in under 5 minutes, transmitting 10 million packets per second,
from a single machine.
Its usage (parameters, output) is similar to `nmap`, the most famous port scanner.
When in doubt, try one of those features -- features that support widespread
scanning of many machines are supported, while in-depth scanning of single
machines aren't.
Internally, it uses asynchronous transmission, similar to port scanners
like `scanrand`, `unicornscan`, and `ZMap`. It's more flexible, allowing
arbitrary port and address ranges.
NOTE: masscan uses its own **ad hoc TCP/IP stack**. Anything other than
simple port scans may cause conflict with the local TCP/IP stack. This means you
need to use either the `--src-ip` option to run from a different IP address, or
use `--src-port` to configure which source ports masscan uses, then also
configure the internal firewall (like `pf` or `iptables`) to firewall those ports
from the rest of the operating system.
This tool is free, but consider contributing money to its development:
Bitcoin wallet address: 1MASSCANaHUiyTtR3bJ2sLGuMw5kDBaj4T
# Building
On Debian/Ubuntu, it goes something like the following. It doesn't
really have any dependencies other than a C compiler (such as `gcc`
or `clang`).
sudo apt-get --assume-yes install git make gcc
git clone https://github.com/robertdavidgraham/masscan
cd masscan
make
This puts the program in the `masscan/bin` subdirectory.
To install it (on Linux) run:
make install
The source consists of a lot of small files, so building goes a lot faster
by using the multi-threaded build. This requires more than 2gigs on a
Raspberry Pi (and breaks), so you might use a smaller number, like `-j4` rather than
all possible threads.
make -j
While Linux is the primary target platform, the code runs well on many other
systems (Windows, macOS, etc.). Here's some additional build info:
* Windows w/ Visual Studio: use the VS10 project
* Windows w/ MinGW: just type `make`
* Windows w/ cygwin: won't work
* Mac OS X /w XCode: use the XCode4 project
* Mac OS X /w cmdline: just type `make`
* FreeBSD: type `gmake`
* other: try just compiling all the files together, `cc src/*.c -o bin/masscan`
On macOS, the x86 binaries seem to work just as fast under ARM emulation.
# Usage
Usage is similar to `nmap`. To scan a network segment for some ports:
# masscan -p80,8000-8100 10.0.0.0/8 2603:3001:2d00:da00::/112
This will:
* scan the `10.x.x.x` subnet, and `2603:3001:2d00:da00::x` subnets
* scans port 80 and the range 8000 to 8100, or 102 ports total, on both subnets
* print output to `<stdout>` that can be redirected to a file
To see the complete list of options, use the `--echo` feature. This
dumps the current configuration and exits. This output can be used as input back
into the program:
# masscan -p80,8000-8100 10.0.0.0/8 2603:3001:2d00:da00::/112 --echo > xxx.conf
# masscan -c xxx.conf --rate 1000
## Banner checking
Masscan can do more than just detect whether ports are open. It can also
complete the TCP connection and interaction with the application at that
port in order to grab simple "banner" information.
Masscan supports banner checking on the following protocols:
* FTP
* HTTP
* IMAP4
* memcached
* POP3
* SMTP
* SSH
* SSL
* SMBv1
* SMBv2
* Telnet
* RDP
* VNC
The problem with this is that masscan contains its own TCP/IP stack
separate from the system you run it on. When the local system receives
a SYN-ACK from the probed target, it responds with a RST packet that kills
the connection before masscan can grab the banner.
The easiest way to prevent this is to assign masscan a separate IP
address. This would look like one of the following examples:
# masscan 10.0.0.0/8 -p80 --banners --source-ip 192.168.1.200
# masscan 2a00:1450:4007:810::/112 -p80 --banners --source-ip 2603:3001:2d00:da00:91d7:b54:b498:859d
The address you choose has to be on the local subnet and not otherwise
be used by another system. Masscan will warn you that you've made a
mistake, but you might've messed up the other machine's communications
for several minutes, so be careful.
In some cases, such as WiFi, this isn't possible. In those cases, you can
firewall the port that masscan uses. This prevents the local TCP/IP stack
from seeing the packet, but masscan still sees it since it bypasses the
local stack. For Linux, this would look like:
# iptables -A INPUT -p tcp --dport 61000 -j DROP
# masscan 10.0.0.0/8 -p80 --banners --source-port 61000
You probably want to pick ports that don't conflict with ports Linux might otherwise
choose for source-ports. You can see the range Linux uses, and reconfigure
that range, by looking in the file:
/proc/sys/net/ipv4/ip_local_port_range
On the latest version of Kali Linux (2018-August), that range is 32768 to 60999, so
you should choose ports either below 32768 or 61000 and above.
Setting an `iptables` rule only lasts until the next reboot. You need to lookup how to
save the configuration depending upon your distro, such as using `iptables-save`
and/or `iptables-persistent`.
On Mac OS X and BSD, there are similar steps. To find out the ranges to avoid,
use a command like the following:
# sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last
On FreeBSD and older MacOS, use an `ipfw` command:
# sudo ipfw add 1 deny tcp from any to any 40000 in
# masscan 10.0.0.0/8 -p80 --banners --source-port 40000
On newer MacOS and OpenBSD, use the `pf` packet-filter utility.
Edit the file `/etc/pf.conf` to add a line like the following:
block in proto tcp from any to any port 40000:40015
Then to enable the firewall, run the command:
# pfctl -E
If the firewall is already running, then either reboot or reload the rules
with the following command:
# pfctl -f /etc/pf.conf
Windows doesn't respond with RST packets, so neither of these techniques
are necessary. However, masscan is still designed to work best using its
own IP address, so you should run that way when possible, even when it is
not strictly necessary.
The same thing is needed for other checks, such as the `--heartbleed` check,
which is just a form of banner checking.
## How to scan the entire Internet
While useful for smaller, internal networks, the program is really designed
with the entire Internet in mind. It might look something like this:
# masscan 0.0.0.0/0 -p0-65535
Scanning the entire Internet is bad. For one thing, parts of the Internet react
badly to being scanned. For another thing, some sites track scans and add you
to a ban list, which will get you firewalled from useful parts of the Internet.
Therefore, you want to exclude a lot of ranges. To blacklist or exclude ranges,
you want to use the following syntax:
# masscan 0.0.0.0/0 -p0-65535 --excludefile exclude.txt
This just prints the results to the command-line. You probably want them
saved to a file instead. Therefore, you want something like:
# masscan 0.0.0.0/0 -p0-65535 -oX scan.xml
This saves the results in an XML file, allowing you to easily dump the
results in a database or something.
But, this only goes at the default rate of 100 packets/second, which will
take forever to scan the Internet. You need to speed it up as so:
# masscan 0.0.0.0/0 -p0-65535 --max-rate 100000
This increases the rate to 100,000 packets/second, which will scan the
entire Internet (minus excludes) in about 10 hours per port (or 655,360 hours
if scanning all ports).
The thing to notice about this command-line is that these are all `nmap`
compatible options. In addition, "invisible" options compatible with `nmap`
are also set for you: `-sS -Pn -n --randomize-hosts --send-eth`. Likewise,
the format of the XML file is inspired by `nmap`. There are, of course, a
lot of differences, because the *asynchronous* nature of the program
leads to a fundamentally different approach to the problem.
The above command-line is a bit cumbersome. Instead of putting everything
on the command-line, it can be stored in a file instead. The above settings
would look like this:
# My Scan
rate = 100000.00
output-format = xml
output-status = all
output-filename = scan.xml
ports = 0-65535
range = 0.0.0.0-255.255.255.255
excludefile = exclude.txt
To use this configuration file, use the `-c`:
# masscan -c myscan.conf
This also makes things easier when you repeat a scan.
By default, masscan first loads the configuration file
`/etc/masscan/masscan.conf`. Any later configuration parameters override what's
in this default configuration file. That's where I put my "excludefile"
parameter so that I don't ever forget it. It just works automatically.
## Getting output
By default, masscan produces fairly large text files, but it's easy
to convert them into any other format. There are five supported output formats:
1. xml: Just use the parameter `-oX <filename>`.
Or, use the parameters `--output-format xml` and `--output-filename <filename>`.
2. binary: This is the masscan builtin format. It produces much smaller files so that
when I scan the Internet my disk doesn't fill up. They need to be parsed,
though. The command-line option `--readscan` will read binary scan files.
Using `--readscan` with the `-oX` option will produce an XML version of the
results file.
3. grepable: This is an implementation of the Nmap -oG
output that can be easily parsed by command-line tools. Just use the
parameter `-oG <filename>`. Or, use the parameters `--output-format grepable` and
`--output-filename <filename>`.
4. json: This saves the results in JSON format. Just use the
parameter `-oJ <filename>`. Or, use the parameters `--output-format json` and
`--output-filename <filename>`.
5. list: This is a simple list with one host and port pair
per line. Just use the parameter `-oL <filename>`. Or, use the parameters
`--output-format list` and `--output-filename <filename>`. The format is:
```
<port state> <protocol> <port number> <IP address> <POSIX timestamp>
open tcp 80 XXX.XXX.XXX.XXX 1390380064
```
## Comparison with Nmap
Where reasonable, every effort has been taken to make the program familiar
to `nmap` users, even though it's fundamentally different. Masscan is tuned
for wide range scanning of a lot of machines, whereas nmap is designed for
intensive scanning of a single machine or a small range.
Two important differences are:
* no default ports to scan, you must specify `-p <ports>`
* target hosts are IP addresses or simple ranges, not DNS names, nor
the funky subnet ranges `nmap` can use (like `10.0.0-255.0-255`).
You can think of `masscan` as having the following settings permanently
enabled:
* `-sS`: this does SYN scan only (currently, will change in the future)
* `-Pn`: doesn't ping hosts first, which is fundamental to the async operation
* `-n`: no DNS resolution happens
* `--randomize-hosts`: scan completely randomized, always, you can't change this
* `--send-eth`: sends using raw `libpcap`
If you want a list of additional `nmap` compatible settings, use the following
command:
# masscan --nmap
## Transmit rate (IMPORTANT!!)
This program spews out packets very fast. On Windows, or from VMs,
it can do 300,000 packets/second. On Linux (no virtualization) it'll
do 1.6 million packets-per-second. That's fast enough to melt most networks.
Note that it'll only melt your own network. It randomizes the target
IP addresses so that it shouldn't overwhelm any distant network.
By default, the rate is set to 100 packets/second. To increase the rate to
a million use something like `--rate 1000000`.
When scanning the IPv4 Internet, you'll be scanning lots of subnets,
so even though there's a high rate of packets going out, each
target subnet will receive a small rate of incoming packets.
However, with IPv6 scanning, you'll tend to focus on a single
target subnet with billions of addresses. Thus, your default
behavior will overwhelm the target network. Networks often
crash under the load that masscan can generate.
# Design
This section describes the major design issues of the program.
## Code Layout
The file `main.c` contains the `main()` function, as you'd expect. It also
contains the `transmit_thread()` and `receive_thread()` functions. These
functions have been deliberately flattened and heavily commented so that you
can read the design of the program simply by stepping line-by-line through
each of these.
## Asynchronous
This is an *asynchronous* design. In other words, it is to `nmap` what
the `nginx` web-server is to `Apache`. It has separate transmit and receive
threads that are largely independent from each other. It's the same sort of
design found in `scanrand`, `unicornscan`, and `ZMap`.
Because it's asynchronous, it runs as fast as the underlying packet transmit
allows.
## Randomization
A key difference between Masscan and other scanners is the way it randomizes
targets.
The fundamental principle is to have a single index variable that starts at
zero and is incremented by one for every probe. In C code, this is expressed
as:
for (i = 0; i < range; i++) {
scan(i);
}
We have to translate the index into an IP address. Let's say that you want to
scan all "private" IP addresses. That would be the table of ranges like:
192.168.0.0/16
10.0.0.0/8
172.16.0.0/12
In this example, the first 64k indexes are appended to 192.168.x.x to form
the target address. Then, the next 16-million are appended to 10.x.x.x.
The remaining indexes in the range are applied to 172.16.x.x.
In this example, we only have three ranges. When scanning the entire Internet,
we have in practice more than 100 ranges. That's because you have to blacklist
or exclude a lot of sub-ranges. This chops up the desired range into hundreds
of smaller ranges.
This leads to one of the slowest parts of the code. We transmit 10 million
packets per second and have to convert an index variable to an IP address
for each and every probe. We solve this by doing a "binary search" in a small
amount of memory. At this packet rate, cache efficiencies start to dominate
over algorithm efficiencies. There are a lot of more efficient techniques in
theory, but they all require so much memory as to be slower in practice.
We call the function that translates from an index into an IP address
the `pick()` function. In use, it looks like:
for (i = 0; i < range; i++) {
ip = pick(addresses, i);
scan(ip);
}
Masscan supports not only IP address ranges, but also port ranges. This means
we need to pick from the index variable both an IP address and a port. This
is fairly straightforward:
range = ip_count * port_count;
for (i = 0; i < range; i++) {
ip = pick(addresses, i / port_count);
port = pick(ports, i % port_count);
scan(ip, port);
}
This leads to another expensive part of the code. The division/modulus
instructions are around 90 clock cycles, or 30 nanoseconds, on x86 CPUs. When
transmitting at a rate of 10 million packets/second, we have only
100 nanoseconds per packet. I see no way to optimize this any better. Luckily,
though, two such operations can be executed simultaneously, so doing two
of these, as shown above, is no more expensive than doing one.
There are actually some easy optimizations for the above performance problems,
but they all rely upon `i++`, the fact that the index variable increases one
by one through the scan. Actually, we need to randomize this variable. We
need to randomize the order of IP addresses that we scan or we'll blast the
heck out of target networks that aren't built for this level of speed. We
need to spread our traffic evenly over the target.
The way we randomize is simply by encrypting the index variable. By definition,
encryption is random and creates a 1-to-1 mapping between the original index
variable and the output. This means that while we linearly go through the
range, the output IP addresses are completely random. In code, this looks like:
range = ip_count * port_count;
for (i = 0; i < range; i++) {
x = encrypt(i);
ip = pick(addresses, x / port_count);
port = pick(ports, x % port_count);
scan(ip, port);
}
This also has a major cost. Since the range is an unpredictable size instead
of a nice even power of 2, we can't use cheap binary techniques like
AND (&) and XOR (^). Instead, we have to use expensive operations like
MODULUS (%). In my current benchmarks, it's taking 40 nanoseconds to
encrypt the variable.
This architecture allows for lots of cool features. For example, it supports
"shards". You can set up 5 machines each doing a fifth of the scan or
`range / shard_count`. Shards can be multiple machines, or simply multiple
network adapters on the same machine, or even (if you want) multiple IP
source addresses on the same network adapter.
Or, you can use a 'seed' or 'key' to the encryption function, so that you get
a different order each time you scan, like `x = encrypt(seed, i)`.
We can also pause the scan by exiting out of the program, and simply
remembering the current value of `i`, and restart it later. I do that a lot
during development. I see something going wrong with my Internet scan, so
I hit <ctrl-c> to stop the scan, then restart it after I've fixed the bug.
Another feature is retransmits/retries. Packets sometimes get dropped on the
Internet, so you can send two packets back-to-back. However, something that
drops one packet may drop the immediately following packet. Therefore, you
want to send the copy about 1 second apart. This is simple. We already have
a 'rate' variable, which is the number of packets-per-second rate we are
transmitting at, so the retransmit function is simply to use `i + rate`
as the index. One of these days I'm going to do a study of the Internet,
and differentiate "back-to-back", "1 second", "10 second", and "1 minute"
retransmits this way in order to see if there is any difference in what
gets dropped.
## C10 Scalability
The asynchronous technique is known as a solution to the "c10k problem".
Masscan is designed for the next level of scalability, the "C10M problem".
The C10M solution is to bypass the kernel. There are three primary kernel
bypasses in Masscan:
* custom network driver
* user-mode TCP stack
* user-mode synchronization
Masscan can use the PF_RING DNA driver. This driver DMAs packets directly
from user-mode memory to the network driver with zero kernel involvement.
That allows software, even with a slow CPU, to transmit packets at the maximum
rate the hardware allows. If you put 8 10-gbps network cards in a computer,
this means it could transmit at 100-million packets/second.
Masscan has its own built-in TCP stack for grabbing banners from TCP
connections. This means it can easily support 10 million concurrent TCP
connections, assuming of course that the computer has enough memory.
Masscan has no "mutex". Modern mutexes (aka. futexes) are mostly user-mode,
but they have two problems. The first problem is that they cause cache-lines
to bounce quickly back-and-forth between CPUs. The second is that when there
is contention, they'll do a system call into the kernel, which kills
performance. A mutex on the fast path of a program severely limits scalability.
Instead, Masscan uses "rings" to synchronize things, such as when the
user-mode TCP stack in the receive thread needs to transmit a packet without
interfering with the transmit thread.
## Portability
The code runs well on Linux, Windows, and Mac OS X. All the important bits are
in standard C (C90). Therefore, it compiles on Visual Studio with Microsoft's
compiler, the Clang/LLVM compiler on Mac OS X, and GCC on Linux.
Windows and Macs aren't tuned for packet transmit, and get only about 300,000
packets-per-second, whereas Linux can do 1,500,000 packets/second. That's
probably faster than you want anyway.
## Safe code
A bounty is offered for vulnerabilities, see the VULNINFO.md file for more
information.
This project uses safe functions like `safe_strcpy()` instead of unsafe functions
like `strcpy()`.
This project has automated unit regression tests (`make regress`).
## Compatibility
A lot of effort has gone into making the input/output look like `nmap`, which
everyone who does port scans is (or should be) familiar with.
## IPv6 and IPv4 coexistence
Masscan supports IPv6, but there is no special mode, both are supported
at the same time. (There is no `-6` option -- it's always available).
In any example you see of masscan usage,
simply put an IPv6 address where you see an IPv4 address. You can include
IPv4 and IPv6 addresses simultaneously in the same scan. Output includes
the appropriate address at the same location, with no special marking.
Just remember that IPv6 address space is really big. You probably don't want to scan
for big ranges, except maybe the first 64k addresses of a subnet that were assigned
via DHCPv6.
Instead, you'll probably want to scan large lists of addresses stored
in a file (`--include-file filename.txt`) that you got from other sources.
Like everywhere else, this file can contain lists of both IPv4 and IPv6 addresses.
The test file I use contains 8 million addresses. Files of that size need a couple
extra seconds to be read on startup (masscan sorts the addresses and removes
duplicates before scanning).
Remember that masscan contains its own network stack. Thus, the local machine
you run masscan from does not need to be IPv6 enabled -- though the local
network needs to be able to route IPv6 packets.
## PF_RING
To get beyond 2 million packets/second, you need an Intel 10-gbps Ethernet
adapter and a special driver known as ["PF_RING ZC" from ntop](https://www.ntop.org/installation-guide-for-pf_ring/). Masscan doesn't need to be rebuilt in order to use PF_RING. To use PF_RING,
you need to build the following components:
* `libpfring.so` (installed in /usr/lib/libpfring.so)
* `pf_ring.ko` (their kernel driver)
* `ixgbe.ko` (their version of the Intel 10-gbps Ethernet driver)
You don't need to build their version of `libpcap.so`.
When Masscan detects that an adapter is named something like `zc:enp1s0` instead
of something like `enp1s0`, it'll automatically switch to PF_RING ZC mode.
A more detail discussion can be found in **PoC||GTFO 0x15**.
## Regression testing
The project contains a built-in unit test:
$ make test
bin/masscan --selftest
selftest: success!
This tests a lot of tricky bits of the code. You should do this after building.
## Performance testing
To test performance, run something like the following to a throw-away address,
to avoid overloading your local router:
$ bin/masscan 0.0.0.0/4 -p80 --rate 100000000 --router-mac 66-55-44-33-22-11
The bogus `--router-mac` keeps packets on the local network segments so that
they won't go out to the Internet.
You can also test in "offline" mode, which is how fast the program runs
without the transmit overhead:
$ bin/masscan 0.0.0.0/4 -p80 --rate 100000000 --offline
This second benchmark shows roughly how fast the program would run if it were
using PF_RING, which has near zero overhead.
By the way, the randomization algorithm makes heavy use of "integer arithmetic",
a chronically slow operation on CPUs. Modern CPUs have doubled the speed
at which they perform this calculation, making `masscan` much faster.
# Authors
This tool created by Robert Graham:
email: robert_david_graham@yahoo.com
twitter: @ErrataRob
# License
Copyright (c) 2013 Robert David Graham
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

69
VULNINFO.md Normal file
View File

@@ -0,0 +1,69 @@
# Vulnerability Information and Policy
This document contains information about robustness of this project against
hacker attacks. It describes known vulnerabilities that have been found
in previous versions, and describes policies how vulnerabilities are handled.
## Security contact
robert_david_graham@yahoo.com
@ErrataRob on twitter
## Known vulnerabilities and advisories
none
## Bounty
I'm offering $100, payable in cash or Bitcoin, for security vulnerabilities.
This is primarily for remote vulnerabilities, such as the ability of a target
to buffer-overflow the scanner, or even cause it to crash.
But I'd consider other vulnerabilities as well. Does Kali ship this with suid
and there's a preload bug? That's not really a vuln in this code, but if it's
something I could fix, I'd consider paying a bounty for it.
## Disclosure policy
If you've got a vuln, just announce it. Please send info to the contact above
as well, please.
I'll probably get around to fixing it within a month or so. This really isn't
heavily used software, so I'm lax on this.
## Threats
The primary threat is from hostile targets on the Internet sending back
responses in order to:
* exploit a buffer-overflow vulnerability
* spoof packets trying to give fraudulent scan results (mitigated with our
SYN cookies)
* flood packets trying to overload bandwidth/storage
* bad data, such as corrupting banners or DNS names trying to exploit
downstream consumers with bad html or script tags.
The secondary threat is from use of the program. For example, when a bad
parameter is entered on the command-line, the program spits it back out
in a helpful error message. This is fine for a command-line program that
should run as `root` anyway, but if somebody tries to make it into a
scriptable service, this becomes a potential vulnerability.
## Safe code policy
Unsafe functions like `strcpy()` are banned.
The code contains an automated regression test by running with the
`--regress` option. However, currently the regression only tests
a small percentage of the code.

4
bin/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
*
!.gitignore

BIN
data/afl-http.pcap Normal file

Binary file not shown.

513
data/exclude.conf Normal file
View File

@@ -0,0 +1,513 @@
# http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
# http://tools.ietf.org/html/rfc5735
# "This" network
0.0.0.0/8
# Private networks
10.0.0.0/8
# Carrier-grade NAT - RFC 6598
100.64.0.0/10
# Host loopback
127.0.0.0/8
# Link local
169.254.0.0/16
# Private networks
172.16.0.0/12
# IETF Protocol Assignments
192.0.0.0/24
# DS-Lite
192.0.0.0/29
# NAT64
192.0.0.170/32
# DNS64
192.0.0.171/32
# Documentation (TEST-NET-1)
192.0.2.0/24
# 6to4 Relay Anycast
192.88.99.0/24
# Private networks
192.168.0.0/16
# Benchmarking
198.18.0.0/15
# Documentation (TEST-NET-2)
198.51.100.0/24
# Documentation (TEST-NET-3)
203.0.113.0/24
# Reserved
240.0.0.0/4
# Limited Broadcast
255.255.255.255/32
#Received: from elbmasnwh002.us-ct-eb01.gdeb.com ([153.11.13.41]
# helo=ebsmtp.gdeb.com) by mx1.gd-ms.com with esmtp (Exim 4.76) (envelope-from
# <bmandes@gdeb.com>) id 1VS55c-0004qL-0F for support@erratasec.com; Fri, 04
# Oct 2013 09:06:40 -0400
#To: <support@erratasec.com>
#CC: <ebsoc@gdeb.com>
#Subject: Scanning and Probing our network
#From: Robert Mandes <bmandes@gdeb.com>
#Date: Fri, 4 Oct 2013 09:06:36 -0400
#
#Stop scanning and probing our network, 153.11.0.0/16. We are a defense
#contractor and report to Federal law enforcement authorities when scans
#and probes are directed at our network. I assume you don't want to be
#part of that report. Please permanently remove our network range from
#your current and future research.
#
#Thank you
#
#Robert Mandes
#Information Security Officer
#General Dynamics
#Electric Boat
#
#C 860-625-0605
#P 860-433-1553
153.11.0.0/16
#Date: Mon, 7 Oct 2013 17:25:41 -0700
#Subject: Re: please stop the attack to our router
#From: Di Li <di@egihosting.com>
#
#Make sure you stop the scan immediately, that's not OK for any company or
#organization scan our network at all.
#
#If you fail to do that we will block whole traffic from ASN 10439, and we
#will file a police report after that.
#
#Let me know when you stop, since we still receive the attack from you, and
#by the way your scan are not going anywhere, it's was dropped from our edge
#since the first 5 scan
#
#Oct 7 17:17:32:I:SNMP: Auth. failure, intruder IP: 209.126.230.72
#...
#Oct 7 16:55:27:I:SNMP: Auth. failure, intruder IP: 209.126.230.72
#
#Di
4.53.201.0/24
5.152.179.0/24
8.12.162.0-8.12.164.255
8.14.84.0/22
8.14.145.0-8.14.147.255
8.17.250.0-8.17.252.255
23.27.0.0/16
23.231.128.0/17
37.72.172.0/23
38.72.200.0/22
50.93.192.0-50.93.197.255
50.115.128.0/20
50.117.0.0/17
50.118.128.0/17
63.141.222.0/24
64.62.253.0/24
64.92.96.0/19
64.145.79.0/24
64.145.82.0/23
64.158.146.0/23
65.49.24.0/24
65.49.93.0/24
65.162.192.0/22
66.79.160.0/19
66.160.191.0/24
68.68.96.0/20
69.46.64.0/19
69.176.80.0/20
72.13.80.0/20
72.52.76.0/24
74.82.43.0/24
74.82.160.0/19
74.114.88.0/22
74.115.0.0/24
74.115.2.0/24
74.115.4.0/24
74.122.100.0/22
75.127.0.0/24
103.251.91.0/24
108.171.32.0/24
108.171.42.0/24
108.171.52.0/24
108.171.62.0/24
118.193.78.0/23
130.93.16.0/23
136.0.0.0/16
142.111.0.0/16
142.252.0.0/16
146.82.55.93
149.54.136.0/21
149.54.152.0/21
166.88.0.0/16
172.252.0.0/16
173.245.64.0/19
173.245.194.0/23
173.245.220.0/22
173.252.192.0/18
178.18.16.0/22
178.18.26.0-178.18.29.255
183.182.22.0/24
192.92.114.0/24
192.155.160.0/19
192.177.0.0/16
192.186.0.0/18
192.249.64.0/20
192.250.240.0/20
194.110.214.0/24
198.12.120.0-198.12.122.255
198.144.240.0/20
199.33.120.0/24
199.33.124.0/22
199.48.147.0/24
199.68.196.0/22
199.127.240.0/21
199.187.168.0/22
199.188.238.0/23
199.255.208.0/24
203.12.6.0/24
204.13.64.0/21
204.16.192.0/21
204.19.238.0/24
204.74.208.0/20
205.159.189.0/24
205.164.0.0/18
205.209.128.0/18
206.108.52.0/23
206.165.4.0/24
208.77.40.0/21
208.80.4.0/22
208.123.223.0/24
209.51.185.0/24
209.54.48.0/20
209.107.192.0/23
209.107.210.0/24
209.107.212.0/24
211.156.110.0/23
216.83.33.0-216.83.49.255
216.83.51.0-216.83.63.255
216.151.183.0/24
216.151.190.0/23
216.172.128.0/19
216.185.36.0/24
216.218.233.0/24
216.224.112.0/20
#Received: from [194.77.40.242] (HELO samba.agouros.de)
# for abuse@erratasec.com; Sat, 12 Oct 2013 09:55:35 -0500
#Received: from rumba.agouros.de (rumba-internal [192.168.8.1]) by
# samba.agouros.de (Postfix) with ESMTPS id 9055FBAD1D for
# <abuse@erratasec.com>; Sat, 12 Oct 2013 16:55:32 +0200 (CEST)
#Received: from rumba.agouros.de (localhost [127.0.0.1]) by rumba.agouros.de
# (Postfix) with ESMTP id 7B5DD206099 for <abuse@erratasec.com>; Sat, 12 Oct
# 2013 16:55:32 +0200 (CEST)
#Received: from localhost.localdomain (localhost [127.0.0.1]) by
# rumba.agouros.de (Postfix) with ESMTP id 5FBC420601D for
# <abuse@erratasec.com>; Sat, 12 Oct 2013 16:55:32 +0200 (CEST)
#To: <abuse@erratasec.com>
#Subject: Loginattempts from Your net
#Message-ID: <20131012145532.5FBC420601D@rumba.agouros.de>
#Date: Sat, 12 Oct 2013 16:55:32 +0200
#From: <elwood@agouros.de>
#
#The address 209.126.230.72 from Your network tried to log in to
#our network using Port 22 (1)/tcp. Below You will find a listing of the dates and
#times the incidents occured as well as the attacked IP-Addresses.
#This is a matter of concern for us and continued tries might result in
#legal action. If the machine was victim to a hack take it offline, repair
#the damage and use better protection next time.
#The times included are in Central European (Summer) Time.
#Date Sourceip port destips
#
#07.10.2013 22:34:40 CEST 209.126.230.72 22 194.77.40.242 (1)
#08.10.2013 01:44:15 CEST 209.126.230.72 22 194.77.40.246 (1)
#
#Regards,
#Konstantin Agouros
194.77.40.242
194.77.40.246
#Received: from [165.160.9.58] (HELO mx2.cscinfo.com)
#X-Virus-Scanned: amavisd-new at cscinfo.com
#Received: from mx2.cscinfo.com ([127.0.0.1]) by localhost
# (plmail02.wil.csc.local [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id
# GGQ7EiQaK2P0 for <protodev@erratasec.com>; Wed, 30 Oct 2013 09:26:00 -0400
# (EDT)
#Received: from casarray.cscinfo.com (pwmailch02.cscinfo.com [172.20.53.94]) by
# mx2.cscinfo.com (Postfix) with ESMTPS id 4BA5E58170 for
# <protodev@erratasec.com>; Wed, 30 Oct 2013 09:26:00 -0400 (EDT)
#Received: from PWMAILM02.cscinfo.com ([169.254.7.52]) by
# PWMAILCH02.cscinfo.com ([172.20.53.94]) with mapi id 14.02.0247.003; Wed, 30
# Oct 2013 09:26:00 -0400
#From: "Derksen, Bill" <bderksen@cscinfo.com>
#Subject: Unauthorized Scanning
#Date: Wed, 30 Oct 2013 13:25:59 +0000
#Message-ID: <1F80316A0C861F40A9A88F18465F138E01EF885F@PWMAILM02.cscinfo.com>
#x-originating-ip: [172.31.252.72]
#
#We have detected unauthorized activity from your systems on our public netw=
#ork. Please suspend scanning of our networks immediately.
#
#Our network block is 165.160/16
#
#Further scanning will result in reports of unauthorized activity being file=
#d with law enforcement agencies.
#
#Corporation Service Company
#
#
#
#________________________________
#
#NOTICE: This e-mail and any attachments is intended only for use by the add=
#ressee(s) named herein and may contain legally privileged, proprietary or c=
#onfidential information. If you are not the intended recipient of this e-ma=
#il, you are hereby notified that any dissemination, distribution or copying=
# of this email, and any attachments thereto, is strictly prohibited. If you=
# receive this email in error please immediately notify me via reply email o=
#r at (800) 927-9800 and permanently delete the original copy and any copy o=
#f any e-mail, and any printout.
165.160.0.0/16
#******************************
#Greetings from the IT Security Team at Utah State University.
#
#We have detected network activity that might be suspicious or
#malicious. We think it might be sourced from your network. We
#include IP Addresses as well as description, log snippets, and
#other useful information.
#
#Please review this information or forward to the responsible person.
129.123.0.0/16
144.39.0.0/16
204.113.91.0/24
#On Friday, November 17th 2017 starting at 03:39 EST (UTC-5:00), part of the
#Physics Network at McGill University (132.206.9.0/24, 132.206.123.0/24
#and/or 132.206.125.0/24) was scanned from xxx.xxx.xxx.xxx (see syslog
#snippet below). The scan targetted the domain service (port 53/udp). We
#consider this scan to be an attempt to unlawfully access or abuse our
#network (intentionally or as a result of virus or worm activity).
132.206.9.0/24
132.206.123.0/24
132.206.125.0/24
#
# Add DOD + US Military, often not a great idea to scan military ranges.
# If you desire, you can comment these ranges out.
#
6.0.0.0/8
7.0.0.0/8
11.0.0.0/8
21.0.0.0/8
22.0.0.0/8
26.0.0.0/8
28.0.0.0/8
29.0.0.0/8
30.0.0.0/8
33.0.0.0/8
55.0.0.0/8
205.0.0.0/8
214.0.0.0/8
215.0.0.0/8
#******************************
#Janet is a UK research and education network!
#Please DO NOT scan, you been warned!
31.25.0.0/23
31.25.2.0/23
31.25.4.0/22
37.72.112.0/21
46.254.200.0/21
81.87.0.0/16
85.12.64.0/18
89.207.208.0/21
92.245.224.0/19
128.16.0.0/16
128.40.0.0/16
128.41.0.0/18
128.86.0.0/16
128.232.0.0/16
128.240.0.0/16
128.243.0.0/16
129.11.0.0/16
129.12.0.0/16
129.31.0.0/16
129.67.0.0/16
129.169.0.0/16
129.215.0.0/16
129.234.0.0/16
130.88.0.0/16
130.159.0.0/16
130.209.0.0/16
130.246.0.0/16
131.111.0.0/16
131.227.0.0/16
131.231.0.0/16
131.251.0.0/16
134.36.0.0/16
134.83.0.0/16
134.151.0.0/16
134.219.0.0/16
134.220.0.0/16
134.225.0.0/16
136.148.0.0/16
136.156.0.0/16
137.44.0.0/16
137.50.0.0/16
137.73.0.0/16
137.108.0.0/16
137.195.0.0/16
137.222.0.0/16
137.253.0.0/16
138.38.0.0/16
138.40.0.0/16
138.250.0.0/15
138.253.0.0/16
139.133.0.0/16
139.153.0.0/16
139.166.0.0/16
139.184.0.0/16
139.222.0.0/16
140.97.0.0/16
141.163.0.0/16
141.170.64.0/19
141.170.96.0/22
141.170.100.0/23
141.241.0.0/16
143.52.0.0/15
143.117.0.0/16
143.167.0.0/16
143.210.0.0/16
143.234.0.0/16
144.32.0.0/16
144.82.0.0/16
144.124.0.0/16
144.173.0.0/16
146.87.0.0/16
146.97.0.0/16
146.169.0.0/16
146.176.0.0/16
146.179.0.0/16
146.191.0.0/16
146.227.0.0/16
147.143.0.0/16
147.188.0.0/16
147.197.0.0/16
148.79.0.0/16
148.88.0.0/16
148.197.0.0/16
149.155.0.0/16
149.170.0.0/16
150.204.0.0/16
152.71.0.0/16
152.78.0.0/16
152.105.0.0/16
155.198.0.0/16
155.245.0.0/16
157.140.0.0/16
157.228.0.0/16
158.94.0.0/16
158.125.0.0/16
158.143.0.0/16
158.223.0.0/16
159.86.128.0/18
159.92.0.0/16
160.5.0.0/16
160.9.0.0/16
161.73.0.0/16
161.74.0.0/16
161.76.0.0/16
161.112.0.0/16
163.1.0.0/16
163.119.0.0/16
163.160.0.0/16
163.167.0.0/16
164.11.0.0/16
185.83.168.0/22
192.12.72.0/24
192.18.195.0/24
192.35.172.0/24
192.41.104.0/21
192.41.112.0/20
192.41.128.0/22
192.68.153.0/24
192.76.6.0/23
192.76.8.0/21
192.76.16.0/20
192.76.32.0/22
192.82.153.0/24
192.84.5.0/24
192.84.75.0/24
192.84.76.0/22
192.84.80.0/22
192.84.212.0/24
192.88.9.0/24
192.88.10.0/24
192.94.235.0/24
192.100.78.0/24
192.100.154.0/24
192.107.168.0/24
192.108.120.0/24
192.124.46.0/24
192.133.244.0/24
192.149.111.0/24
192.150.180.0/22
192.150.184.0/24
192.153.213.0/24
192.156.162.0/24
192.160.194.0/24
192.171.128.0/18
192.171.192.0/21
192.173.1.0/24
192.173.2.0/23
192.173.4.0/24
192.173.128.0/21
192.188.157.0/24
192.188.158.0/24
192.190.201.0/24
192.190.202.0/24
192.195.42.0/23
192.195.105.0/24
192.195.116.0/23
192.195.118.0/24
193.32.22.0/24
193.37.225.0/24
193.37.240.0/21
193.38.143.0/24
193.39.80.0/21
193.39.172.0/22
193.39.212.0/24
193.60.0.0/14
193.107.116.0/22
193.130.15.0/24
193.133.28.0/23
193.138.86.0/24
194.32.32.0/20
194.35.93.0/24
194.35.186.0/24
194.35.192.0/19
194.35.241.0/24
194.36.1.0/24
194.36.2.0/23
194.36.121.0/24
194.36.152.0/21
194.60.218.0/24
194.66.0.0/16
194.80.0.0/14
194.187.32.0/22
195.194.0.0/15
212.121.0.0/19
212.121.192.0/19
212.219.0.0/16

BIN
data/flush_all.pcap Normal file

Binary file not shown.

4
debian/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
files
masscan
masscan.debhelper.log
masscan.substvars

6
debian/README.Debian vendored Normal file
View File

@@ -0,0 +1,6 @@
masscan for Debian
------------------
Initial debianisation
-- Vladimir Vitkov <vvitkov@sdl.com> Fri, 24 Jan 2014 11:03:38 +0200

18
debian/changelog vendored Normal file
View File

@@ -0,0 +1,18 @@
masscan (1.0.3-46+gbbadb7b-1) precise; urgency=low
* Rebuild from current git
* Use propper git hash versioning
-- Vladimir Vitkov (Packaging Key) <vvitkov@sdl.com> Tue, 10 Jun 2014 12:11:04 +0300
masscan (1.0.1+git20140124-1) unstable; urgency=low
* Rebuild from current git
-- Vladimir Vitkov <vvitkov@sdl.com> Fri, 24 Jan 2014 14:37:30 +0200
masscan (1.0.1+git20140106-1) unstable; urgency=low
* Initial release
-- Vladimir Vitkov <vvitkov@sdl.com> Fri, 24 Jan 2014 11:03:38 +0200

1
debian/compat vendored Normal file
View File

@@ -0,0 +1 @@
8

24
debian/control vendored Normal file
View File

@@ -0,0 +1,24 @@
Source: masscan
Section: net
Priority: extra
Maintainer: Vladimir Vitkov <vvitkov@sdl.com>
Build-Depends: debhelper (>= 8.0.0), libpcap-dev
Standards-Version: 3.9.3
Homepage: https://github.com/robertdavidgraham/masscan
#Vcs-Git: https://github.com/robertdavidgraham/masscan.git
#Vcs-Browser: http://git.debian.org/?p=collab-maint/masscan.git;a=summary
Package: masscan
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Mass IP port scanner
This is the fastest Internet port scanner. It can scan the
entire Internet in under 6 minutes, transmitting 10 million
packets per second.
.
It produces results similar to nmap, the most famous port
scanner. Internally, it operates more like scanrand,
unicornscan, and ZMap, using asynchronous transmission.
The major difference is that it's faster than these other
scanners. In addition, it's more flexible, allowing
arbitrary address ranges and port ranges.

45
debian/copyright vendored Normal file
View File

@@ -0,0 +1,45 @@
Format: http://dep.debian.net/deps/dep5
Upstream-Name: masscan
Source: https://github.com/robertdavidgraham/masscan
Files: *
Copyright: 2013 Robert David Graham <robert_david_graham@yahoo.com>
License: AGPL
This program, "masscan", is not completely free software. It may not be
used by the United States Department of Defense (DoD) or National Security
Agency (NSA), or by agents acting on their behalf, such as contractors,
sub-contractors, and so on. These entitities must contact me to acquire
a different license.
.
Barring the above exception, you can use, redistribute, and/or modify
this code under the terms of the GNU Affero General Public License
version 3.
.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Files: debian/*
Copyright: 2014 Vladimir Vitkov <vvitkov@sdl.com>
License: GPL-3.0+
License: GPL-3.0+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".

1
debian/masscan.dirs vendored Normal file
View File

@@ -0,0 +1 @@
usr/bin

4
debian/masscan.docs vendored Normal file
View File

@@ -0,0 +1,4 @@
README.md
VULNINFO.md
doc/algorithm.js
doc/bot.html

1
debian/masscan.install vendored Normal file
View File

@@ -0,0 +1 @@
bin/masscan usr/bin/

1
debian/masscan.manpages vendored Normal file
View File

@@ -0,0 +1 @@
doc/masscan.8

16
debian/rules vendored Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
%:
dh $@
override_dh_auto_test:
$(MAKE) regress

1
debian/source/format vendored Normal file
View File

@@ -0,0 +1 @@
3.0 (quilt)

4
debian/watch vendored Normal file
View File

@@ -0,0 +1,4 @@
version=3
# use the github release pages
https://github.com/robertdavidgraham/masscan/releases .*/(\d\S*)\.(?:tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))

426
doc/algorithm.js Normal file
View File

@@ -0,0 +1,426 @@
/*
This is an implementation of the core Masscan scanning algorithm
in JavaScript/NodeJS. The core scanning algorithm is what makes
Masscan unique from other scanners, so it's worth highlighting
separately in a sample program.
REVIEW OF SCANNERS
The most famous port-scanner is "nmap". However, it is a
"host-at-a-time" scanner, and struggles at scanning large networks.
Masscan is an asynchronous, probe-at-a-time scanner. It spews out
probes to different ports, without caring if two probes happen to
be send to the same host. If the user wants a list of all ports
open on a single host, they have to post-process the masscan output
themselves, because masscan doesn't do it.
There are other asynchronous port-scanners, like scanrand, unicornscan,
and zmap. However, they have limitations in the way they do randomization
of their scans. They have limitations on the ranges of addresses and
ports that they'll accept, try to store an individual memory record
for everything scanned, or only partly randomize their scans.
THE WAY MASSCAN WORKS
Masscan first stores the targets as a "list of ranges". IP address
ranges are stored in one structure, and port ranges are stored
in another structure.
Then, a single index variable is used to enumerate the set of all
IP:port combinations. The scan works by simply incrementing the
index variable from 0 to the total number of probes (the 'range').
Then, before the enumeration step, the index is permuted into another
random index within the same range, in a 1-to-1 mapping. In other
words, the algorithm is theoretically reversable: given the output
of the permutation function, we can obtain the original index.
EXAMPLE
This program can be run like the following:
node patent.js 10.0.0.0-10.0.0.5 192.168.0.0/31 80,U:161
10.0.0.0-10.0.0.5
192.168.0.0-192.168.0.1
0.0.0.80-0.0.0.80
0.1.0.161-0.1.0.161
--> 10.0.0.4 udp:161
--> 10.0.0.0 udp:161
--> 10.0.0.1 udp:161
--> 10.0.0.4 tcp:80
--> 192.168.0.1 tcp:80
--> 10.0.0.0 tcp:80
--> 10.0.0.2 udp:161
--> 10.0.0.5 udp:161
--> 192.168.0.0 tcp:80
--> 192.168.0.0 udp:161
--> 10.0.0.1 tcp:80
--> 10.0.0.3 udp:161
--> 10.0.0.2 tcp:80
--> 10.0.0.5 tcp:80
--> 192.168.0.1 udp:161
--> 10.0.0.3 tcp:80
What you see first is the target ranges being echoed back that it scans,
first the IP address ranges, followed by the port ranges. The port ranges
are in weird decimal-dot notation because they share the same code
as for IPv4 addresses.
Then we see the randomized output, where individual probes are sent to a
random IP address and port.
TransmitThread
All the majic happens in the "TransmitThread()" function near the bottom
of this file.
We first see how the index variable 'i' is incremented from 0 to the
total number of packets that will be sent. We then see how first this
index is permuted to 'xXx', then this variable is separated into
one index for the IP address and another index for the port. Then,
those indexes are used to enumerate one of the IP addresses and
one of the ports.
Blackrock
This is the permutation function. It implements an encryption algorithm
based on DES (Data Encryption Standard). However, the use of real DES
would impose a restricting on the range that it be an even power of 2.
In the above example, with 14 total probes, this doesn't apply.
Therefore, we have to change binary operators like XOR with their
non-binary equivelents.
The upshot is that we first initialize Blackrock with the range (and
a seed/key), and then shuffle the index. The process is stateless,
meaning that any time we shuffle the number '5' we always get the
same result, regardless of what has happened before.
Targets, RangeList, Range
A Range is just a begin/end of an integer. We use this both for
IPv4 addresses (which are just 32-bit integers) and ports
(which are 16 bit integers).
A RangeList is just an array of Ranges. In Masscan, this object
sorts and combines ranges, making sure there are no duplicates,
but that isn't used in this example.
The RangeList object shows how an index can enumerate the
individual addresses/ports. This is down by walking the list
and subtracting from the index the size of each range, until
we reach a range that is larger than the index.
The Targets object just holds both the IP and port lists.
*/
function Range(begin, end) {
if (typeof begin == 'undefined' && typeof end == 'undefined') {
this.begin = 0xFFFFFFFF;
this.end = 0;
} else if (typeof end == 'undefined') {
this.begin = begin;
this.end = begin;
} else {
this.begin = begin;
this.end = end;
}
this.toString = function () {
return ((this.begin >> 24) & 0xFF)
+ "." + ((this.begin >> 16) & 0xFF)
+ "." + ((this.begin >> 8) & 0xFF)
+ "." + ((this.begin >> 0) & 0xFF)
+ "-" + ((this.end >> 24) & 0xFF)
+ "." + ((this.end >> 16) & 0xFF)
+ "." + ((this.end >> 8) & 0xFF)
+ "." + ((this.end >> 0) & 0xFF);
}
this.count = function () {
return this.end - this.begin + 1;
}
this.pick = function (index) {
return this.begin + index;
}
return this;
}
function RangeList() {
this.list = [];
this.total_count = 0;
this.push = function (range) {
this.list.push(range);
this.total_count += range.count();
}
this.count = function () {
return this.total_count;
}
this.pick = function (index) {
for (var i in this.list) {
var item = this.list[i];
if (index < item.count())
return item.pick(index);
else
index -= item.count();
}
return null;
}
}
function Targets() {
this.ports = new RangeList();
this.ips = new RangeList();
this.parse_ip = function (text) {
var x = text.split(".");
var result = 0;
result |= parseInt(x[0]) << 24;
result |= parseInt(x[1]) << 16;
result |= parseInt(x[2]) << 8;
result |= parseInt(x[3]) << 0;
return result;
}
this.parse_ports = function (arg) {
var offset = 0;
if (arg.indexOf(":") !== -1) {
var x = arg.split(":");
if (x[0] == "U")
offset = 65536;
else if (x[0] == "S")
offset = 65536 * 2;
arg = x[1];
}
var target;
if (arg.indexOf("-") !== -1) {
var x = arg.split("-");
target = new Range(parseInt(x[0]), parseInt(x[1]));
} else
target = new Range(parseInt(arg));
target.begin += offset;
target.end += offset;
this.ports.push(target);
}
this.parse_args = function (argv) {
for (var i in argv) {
var arg = argv[i];
if (arg.indexOf(",") !== -1) {
var x = arg.split(",");
for (var j in x)
this.parse_ports(x[j]);
} else if (arg.indexOf("/") !== -1) {
var x = arg.split("/");
var address = this.parse_ip(x[0]);
var prefix = parseInt(x[1]);
var mask = 0xFFFFFFFF << (32 - prefix);
address = address & mask;
var target = new Range(address, address | ~mask);
this.ips.push(target);
} else if (arg.indexOf("-") !== -1) {
var x = arg.split("-");
var begin = this.parse_ip(x[0]);
var end = this.parse_ip(x[1]);
var target = new Range(begin, end);
this.ips.push(target);
} else if (arg.indexOf(".") !== -1) {
var target = new Range(this.parse_ip(arg));
this.ips.push(target);
} else {
this.parse_ports(arg);
}
}
}
this.print = function () {
var i;
for (i in this.ips.list) {
console.log(this.ips.list[i].toString());
}
for (i in this.ports.list) {
console.log(this.ports.list[i].toString());
}
}
return this;
}
function Blackrock(range, seed) {
var split = Math.floor(Math.sqrt(range * 1.0));
this.rounds = 3;
this.seed = seed;
this.range = range;
this.a = split - 1;
this.b = split + 1;
while (this.a * this.b <= range)
this.b++;
/** Inner permutation function */
this.F = function (j, R, seed) {
var primes = [961752031, 982324657, 15485843, 961752031];
R = ((R << (R & 0x4)) + R + seed);
return Math.abs((((primes[j] * R + 25) ^ R) + j));
}
/** Outer feistal construction */
this.fe = function (r, a, b, m, seed) {
var L, R;
var j;
var tmp;
L = m % a;
R = Math.floor(m / a);
for (j = 1; j <= r; j++) {
if (j & 1) {
tmp = (L + this.F(j, R, seed)) % a;
} else {
tmp = (L + this.F(j, R, seed)) % b;
}
L = R;
R = tmp;
}
if (r & 1) {
return a * L + R;
} else {
return a * R + L;
}
}
/** Outer reverse feistal construction */
this.unfe = function (r, a, b, m, seed) {
var L, R;
var j;
var tmp;
if (r & 1) {
R = m % a;
L = Math.floor(m / a);
} else {
L = m % a;
R = Math.floor(m / a);
}
for (j = r; j >= 1; j--) {
if (j & 1) {
tmp = this.F(j, L, seed);
if (tmp > R) {
tmp = (tmp - R);
tmp = a - (tmp % a);
if (tmp == a)
tmp = 0;
} else {
tmp = (R - tmp);
tmp %= a;
}
} else {
tmp = this.F(j, L, seed);
if (tmp > R) {
tmp = (tmp - R);
tmp = b - (tmp % b);
if (tmp == b)
tmp = 0;
} else {
tmp = (R - tmp);
tmp %= b;
}
}
R = L;
L = tmp;
}
return a * R + L;
}
this.shuffle = function (m) {
var c;
c = this.fe(this.rounds, this.a, this.b, m, this.seed);
while (c >= this.range)
c = this.fe(this.rounds, this.a, this.b, c, this.seed);
return c;
}
this.unshuffle = function (m) {
var c;
c = unfe(this.rounds, this.a, this.b, m, this.seed);
while (c >= this.range)
c = unfe(this.rounds, this.a, this.b, c, this.seed);
return c;
}
return this;
}
function TransmitThread(targets, transmit, seed) {
var range = targets.ips.count() * targets.ports.count();
var b = Blackrock(range, seed);
for (var i = 0; i < range; i++) {
var xXx = b.shuffle(i);
var ip_index = Math.floor(xXx / targets.ports.count());
var port_index = Math.floor(xXx % targets.ports.count());
var ip = targets.ips.pick(ip_index);
var port = targets.ports.pick(port_index);
transmit(ip, port);
}
}
function Transmit2Thread(targets, transmit, seed, start, stop, increment) {
var range = targets.ips.count() * targets.ports.count();
var b = Blackrock(range, seed);
for (var i = start; i < range && i < stop; i += increment) {
var xXx = b.shuffle(i);
var ip_index = Math.floor(xXx / targets.ports.count());
var port_index = Math.floor(xXx % targets.ports.count());
var ip = targets.ips.pick(ip_index);
var port = targets.ports.pick(port_index);
transmit(ip, port);
}
}
function transmit(ip, port) {
var proto = "tcp";
if (port > 65536 * 2) {
proto = "sctp";
port -= 65536 * 2;
} else if (port > 65536) {
proto = "udp";
port -= 65536;
}
var ipstring = ((ip >> 24) & 0xFF)
+ "." + ((ip >> 16) & 0xFF)
+ "." + ((ip >> 8) & 0xFF)
+ "." + ((ip >> 0) & 0xFF)
console.log("--> " + ipstring + " " + proto + ":" + port);
}
var targets = new Targets();
targets.parse_args(process.argv.splice(2));
targets.print();
TransmitThread(targets, transmit, 42);

17
doc/bot.html Normal file
View File

@@ -0,0 +1,17 @@
<html>
<head>
<title>Masscan/1.0 - fast port scanner</title>
</head>
<body>
<h1>Masscan/1.0 - fast port scanner</h1>
<p>This tool is not a web spider, but a port scanner. It'll make only one request to a website, usually for the root / webpage. It then records the <b>Server:</b> field from the HTTP header, the <b>&lt;title&gt;</b> from the page contents, and possibly a few other interesting fields.</p>
<p>This does not follow links, it doesn't scan your web pages, but the ports on your machine.</p>
<p>The source code for this tool is at <a href="https://github.com/robertdavidgraham/masscan/">https://github.com/robertdavidgraham/masscan/</a>. This is an open source project, so that this means it's not me (Robert Graham) who is using this tool to scan your website, but likely somebody else. I can't speak for their intentions, but this tool is more useful at doing surveys of the Internet than trying to hack in (tools like 'nmap' or 'nessus' are more often used for that).</p>
</body>
</html>

29
doc/faq/FAQ0001-slow.md Normal file
View File

@@ -0,0 +1,29 @@
# Why is it not as fast as I expect?
## Question
Why is scanning speed only around 100,000 packets-per-second instead of a million packets-per-second?
## Answer
I don't know.
If you have the latest Linux distro on the latest hardware, you can sometime
see scanning speeds of 1 million packets-per-second, even when virtualized.
However, sometimes you also see only 100,000 packets-per-second.
I've spent a lot of time trying to diagnose this situation and cannot
figure out what's going on. The box I use in a colo does 500,000 packets-per-second.
A relatively slow machine in my home lab does 1.2 million packets-per-second.
The speed is determined by the operating system. The amount of CPU used by `masscan`
itself is insignificant.
My theory is various configuration options within the operating system that can make
packet transmission very slow. Simple features that would not otherwise impact network
stacks that run at lower rates become really important at high rates.
One way around this is to install `PF_RING` and dedicate a network adapter to packet
transmission completely bypassing the operating system. In that case, packet transmission
rates can reach 15 million packets-per-second.

31
doc/faq/FAQ0002-drops.md Normal file
View File

@@ -0,0 +1,31 @@
# Why are many results missing that I expect?
# Question
When I do a scan, results are missing that I know are there.
They show up when I repeat the scan, but then others are missing.
The faster I scan, the more results are missing.
# Answer
Network infrastructure does not like high rates of small packets.
Even though they can handle high **bit-rates** then cannot handle
high **packet-rates**.
This is what makes `masscan` so unique. It transmits packets at rates
far higher than other things can cope with. It often crashes networks.
Therefore, the faster you transmit packets, the more it overloads network
equipment, causing the packets to be dropped, causing probes to fail.
As the issue #546 below indicates, they are experiencing this at very low
rates of less than 10,000 packets-per-second. That seems excessively low.
I assume the actual reason is because of policy enforcement limiting traffic
rates rather than overloading network equipment.
# Issues
- [#546 fast scan get result](https://github.com/robertdavidgraham/masscan/issues/546)

View File

@@ -0,0 +1,25 @@
# How can I add my IP address to an exclude list so that people stop scanning me?
# Question
I hate everyone probing me all the time and want them to stop.
How can I add my IP address ranges to an exclude list?
# Answer
You can't.
First of all, nobody is going to pay attention to a sample exclude list
within this project. Sure, I can add IP addresses to the list, but that
won't help you.
Second, there's no way I can confirm who you are. So I can't simply
add to an exclude list just because you ask.
Thirdly, it'll just make you more of a target, as smart hackers know to
use the exclude-list as one of their first include-lists, as it marks
people who have something to hide.
Fourthly, and most importantly, it's Wrong Think on how to manage your
network.

View File

@@ -0,0 +1,28 @@
# Why is masscan in my server logs?
## Question
Some example questions:
* Why is `masscan` appearing in my server logs?
* Why are you scanning me?
* Why is my server trying to connect to this github repo?
## Answer
When `masscan` connections to a webserver, it puts a link
back to this repo in the `User-Agent` field.
Since lots of people run Internet-wide scans using this tool,
and an Internet wide scan hits every public web server, you'll
see this appear in your web server logs several times a day.
It's the **end-to-end** principle of the Internet. Having a public
webserver on the Internet means that anybody can and will try to
connect to the web server.
It's nothing necessarily malicious. Lots of people run Internet-wide
scans to gather information about the state of the Internet. Of course,
some are indeed malicious, scanning to find vulnerabilities. However,
even when malicious, they probably aren't targetting you in particular,
but are instead scanning everybody.

9
doc/faq/README.md Normal file
View File

@@ -0,0 +1,9 @@
# FAQs (frequently asked questions)
This directory contains some documents discussing frequently asked
questions
- 1 - [Why is it not as fast as I expect?](FAQ0001-slow.md)
- 2 - [Why are many results missing that I expect?](FAQ0002-drops.md)
- 3 - [How can I add my IPs to an official exclude list, to get people to stop scanning me?](FAQ0003-excludelist.md)
- 4 - [Why is this in my server logs?](FAQ0004-serverlogs.md)

151
doc/howto-afl.md Normal file
View File

@@ -0,0 +1,151 @@
Using afl fuzzer against masscan
================================
AFL (American-Fuzzy-Lop) is an automated *fuzzer*. It takes existing
input to a program, then morphs that input in order to test new
code paths through the code. It's extremely successful at finding
bugs as well as *vulnerabilities*.
There are two inputs to *masscan*. One is the files it reads, which
come in various formats. The second is input from the network, in
response to network probes, which consist of various network protocols.
For AFL, there is also the issue of how *masscan* crashes. It tries to
print a backtrace. This causes AFL to falsely mark this as a "hang"
rather than a "crash". To fix this, run *masscan* with the *--nobacktrace*
option.
## Fuzzing file formats ##
The *masscan* program reads the following files. You can set the fuzzer
at each one of these to fuzz how it parses the contents.
*-c <filename.conf>*
*Masscan* can read its configuration either from the command-line or from a file.
To create a file, run *masscan* as normal, then hit <ctrl-c>. This will save all
it's settings, even default values, into a file. It's a good starting point for
fuzzing.
*--readscan <filename.mass>*
One of the possible outputs of *masscan* is in a proprietary binary format. You
can then run *masscan* to convert to any other output format.
In other words, you can run masscan to output XML like:
masscan <blah blah blah> -oX scan.xml
Or, in a two step process:
masscan <blah blah blah> -ob scan.mass
masscan --readscan scan.mass -oX scan.xml
*--exclude-file <filename.ranges>*
*Masscan* can scan large ragnes, like *0.0.0.0/0* (the entire Internet). You may
want to exclude specific addresses or ranges. These are configured in the
"exclude file".
You can also read ranges using *--include-file <filename.ranges>* or
*-iL <filename.ranges>*, but as far as fuzzing, I'm pretty sure it'll
be the same results.
*--hello-file[<port>] <filename>*
This file is read, then dumped blindly across a TCP connection, in order
to say "hello" to a service. Since there's no parsing here, I'm not sure
you'll find anything fuzzing this.
*--nmap-payloads <filename>*
This file specifies the default payloads for UDP. It's in the same file
format as for *nmap*. There's some juicy parsing here that may lead
to bugs.
*--pcap-payloads <filename.pcap>*
This is the same as *--nmap-payloads*, but reads the UDP payloads from
a *libpcap* file.
## Fuzzing network protocols ##
*Masscan* parses several network protocols. It also must reassemble
fragmented responses over TCP for any application protocol. Remember:
*masscan* has it's own stack, so must parse everything that comes
over the network.
AFL has no ability to read from the network at this time. Moreover,
even then it wouldn't work easily, since *masscan* has a network stack
rather than just an application layer to deal with.
The trick is to first use *masscan* on a target that responds back
on a protocol, then save just the response side of the TCP connection
to a file. Then, when running *masscan* under AFL, read in that file
using the option *--adapter file:<filename.pcap>*. Then, and this is
critical, you must hard code all the TCP stack values to match those
of the original connection.
I generated the file *masscan/data/afl-http.pcap* as an example file
to read for fuzzing the parsing of HTTP. The command-line parameters
to use are:
bin/masscan --nobacktrace --adapter file:data/afl-http.pcap --source-ip 10.20.30.200 --source-port 6000 --source-mac 00-11-22-33-44-55 --router-mac c0-c1-c0-a0-9b-9d --seed 0 --banners -p80 74.125.196.147 --nostatus
The explanation are:
*--nobacktrace*: so that AFL correctly marks crashes as crashes
and not as hangs.
*--adapter file:*: This option normally specifies the adapter,
like *eth0* or *en1*. By putting the *file:* prefix on an adapter name,
it'll use a file (in *libpcap* format) to use instead. In this case,
transmits are dropped, and any packets are read from a file.
*--source-ip*, *--source-port*, *--source-mac*, *--router-mac*:
These are the hard-coded TCP/IP stack settings that must match the packets
in the file.
*--seed*: This must match the randomization seed in the packet file. Since
everything else is hardcoded, I think the only thing this will control
will be the sequence number of the TCP connection.
*--banners*: this tell the scanner to not simply find open ports, but also
establish a TCP connection and interact with the protocol, and report on
the results.
*-p<port>*: The destination IP address to connect to.
*<ip-address>*: The IP address to connect to
This should produce an output like the following. If you get the
banner back, then you know you've successfully done everything
correctly. Conversely, if you set *--seed 1*, then it won't work,
because it'll reject responses that match the wrong seed.
Starting masscan 1.0.3 (http://bit.ly/14GZzcT) at 2016-06-06 05:19:03 GMT
-- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [1 port/host]
Discovered open port 80/tcp on 74.125.196.147
Banner on port 80/tcp on 74.125.196.147: [title] Google
Banner on port 80/tcp on 74.125.196.147: [http] HTTP/1.0 200 OK\x0d\x0a...
...
(Additional output is truncated -- you get the idea).
The problem with this is that *masscan* will take about 10 seconds before it
produces the results. When it establishes a connection, it waits a few seconds
for the other side to transmit, then sends it's "hello", then waits many
seconds for all output to be received. I don't know if this messes AFL up,
whether I need to add additional options to truncate any waiting.

363
doc/masscan.8 Normal file
View File

@@ -0,0 +1,363 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "MASSCAN" "8" "January 2014" "" ""
.
.SH "NAME"
\fBmasscan\fR \- Fast scan of the Internet
.
.SH "SYNOPSIS"
masscan [\fIoptions\fR] [<IP|RANGE>... \-p \fIPORT\fR[,\fIPORT\fR...]]
.
.SH "DESCRIPTION"
\fBmasscan\fR is an Internet\-scale port scanner, useful for large scale surveys of the Internet, or of internal networks\. While the default transmit rate is only 100 packets/second, it can optional go as fast as 25 million packets/second, a rate sufficient to scan the Internet in 3 minutes for one port\.
.
.SH "OPTIONS"
.
.IP "\(bu" 4
\fB<IP|RANGE>\fR: anything on the command\-line not prefixed with a \'\-\' is assumed to be an IP address or range\. There are three valid formats\. The first is a single IPv4 address like "192\.168\.0\.1"\. The second is a range like "10\.0\.0\.1\-10\.0\.0\.100"\. The third is a CIDR address, like "0\.0\.0\.0/0"\. At least one target must be specified\. Multiple targets can be specified\. This can be specified as multiple options separated by space, or can be separated by a comma as a single option, such as \fB10\.0\.0\.0/8,192\.168\.0\.1\fR\.
.
.IP "\(bu" 4
\fB\-\-range <IP|RANGE>\fR: the same as target range spec described above, except as a named parameter instead of an unnamed one\.
.
.IP "\(bu" 4
\fB\-p PORT[,PORT...]\fR, \fB\-\-ports PORT[,PORT...]\fR: specifies the port(s) to be scanned\. A single port can be specified, like \fB\-p80\fR\. A range of ports can be specified, like \fB\-p 20\-25\fR\. A list of ports/ranges can be specified, like \fB\-p80,20\-25\fR\. UDP ports can also be specified, like \fB\-\-ports U:161,U:1024\-1100\fR\.
.
.IP "\(bu" 4
\fB\-\-banners\fR: specifies that banners should be grabbed, like HTTP server versions, HTML title fields, and so forth\. Only a few protocols are supported\.
.
.IP "\(bu" 4
\fB\-\-rate RATE\fR: specifies the desired rate for transmitting packets\. This can be very small numbers, like \fB0\.1\fR for transmitting packets at rates of one every 10 seconds, for very large numbers like 10000000, which attempts to transmit at 10 million packets/second\. In my experience, Windows and can do 250 thousand packets per second, and latest versions of Linux can do 2\.5 million packets per second\. The PF_RING driver is needed to get to 25 million packets/second\.
.
.IP "\(bu" 4
\fB\-c FILE\fR, \fB\-\-conf FILE\fR: reads in a configuration file\. The format of the configuration file is described below\.
.
.IP "\(bu" 4
\fB\-\-resume FILE\fR: the same as \fB\-\-conf\fR, except that a few options are automatically set, such as \fB\-\-append\-output\fR\. The format of the configuration file is described below\.
.
.IP "\(bu" 4
\fB\-\-echo\fR: don\'t run, but instead dump the current configuration to a file\. This file can then be used with the \fB\-c\fR option\. The format of this output is described below under \'CONFIGURATION FILE\'\.
.
.IP "\(bu" 4
\fB\-e IFNAME\fR, \fB\-\-adapter IFNAME\fR: use the named raw network interface, such as "eth0" or "dna1"\. If not specified, the first network interface found with a default gateway will be used\.
.
.IP "\(bu" 4
\fB\-\-adapter\-ip IP\fR: send packets using this IP address\. If not specified, then the first IP address bound to the network interface will be used\. Instead of a single IP address, a range may be specified\. NOTE: The size of the range must be an even power of 2, such as 1, 2, 4, 8, 16, 1024 etc\. addresses\.
.
.IP "\(bu" 4
\fB\-\-adapter\-port PORT\fR: send packets using this port number as the source\. If not specified, a random port will be chosen in the range 40000 through 60000\. This port should be filtered by the host firewall (like iptables) to prevent the host network stack from interfering with arriving packets\. Instead of a single port, a range can be specified, like \fB40000\-40003\fR\. NOTE: The size of the range must be an even power of 2, such as the example above that has a total of 4 addresses\.
.
.IP "\(bu" 4
\fB\-\-adapter\-mac MAC\fR: send packets using this as the source MAC address\. If not specified, then the first MAC address bound to the network interface will be used\.
.
.IP "\(bu" 4
\fB\-\-router\-mac MAC\fR: send packets to this MAC address as the destination\. If not specified, then the gateway address of the network interface will be ARPed\.
.
.IP "\(bu" 4
\fB\-\-ping\fR: indicates that the scan should include an ICMP echo request\. This may be included with TCP and UDP scanning\.
.
.IP "\(bu" 4
\fB\-\-exclude <IP|RANGE>\fR: blacklist an IP address or range, preventing it from being scanned\. This overrides any target specification, guaranteeing that this address/range won\'t be scanned\. This has the same format as the normal target specification\.
.
.IP "\(bu" 4
\fB\-\-excludefile FILE\fR: reads in a list of exclude ranges, in the same target format described above\. These ranges override any targets, preventing them from being scanned\.
.
.IP "\(bu" 4
\fB\-\-append\-output\fR: causes output to append to the file, rather than overwriting the file\.
.
.IP "\(bu" 4
\fB\-\-iflist\fR: list the available network interfaces, and then exits\.
.
.IP "\(bu" 4
\fB\-\-retries NUM\fR: the number of retries to send, at 1 second intervals\. Note that since this scanner is stateless, retries are sent regardless if replies have already been received\.
.
.IP "\(bu" 4
\fB\-\-nmap\fR: print help about nmap\-compatibility alternatives for these options\.
.
.IP "\(bu" 4
\fB\-\-pcap\-payloads FILE\fR: read packets from a libpcap file containing packets and extract the UDP payloads, and associate those payloads with the destination port\. These payloads will then be used when sending UDP packets with the matching destination port\. Only one payload will be remembered per port\. Similar to \fB\-\-nmap\-payloads\fR\.
.
.IP "\(bu" 4
\fB\-\-nmap\-payloads FILE\fR: read in a file in the same format as the nmap file \fBnmap\-payloads\fR\. This contains UDP payload, so that we can send useful UDP packets instead of empty ones\. Similar to \fB\-\-pcap\-payloads\fR\.
.
.IP "\(bu" 4
\fB\-\-http\-user\-agent USER_AGENT\fR: replaces the existing user\-agent field with the indicated value when doing HTTP requests\.
.
.IP "\(bu" 4
\fB\-\-open\-only\fR: report only open ports, not closed ports\.
.
.IP "\(bu" 4
\fB\-\-pcap FILE\fR: saves received packets (but not transmitted packets) to the libpcap\-format file\.
.
.IP "\(bu" 4
\fB\-\-packet\-trace\fR: prints a summary of those packets sent and received\. This is useful at low rates, like a few packets per second, but will overwhelm the terminal at high rates\.
.
.IP "\(bu" 4
\fB\-\-pfring\fR: force the use of the PF_RING driver\. The program will exit if PF_RING DNA drvers are not available\.
.
.IP "\(bu" 4
\fB\-\-resume\-index INDEX\fR: the point in the scan at when it was paused\.
.
.IP "\(bu" 4
\fB\-\-resume\-count NUM\fR: the maximum number of probes to send before exiting\. This is useful with the \fB\-\-resume\-index\fR to chop up a scan and split it among multiple instances, though the \fB\-\-shards\fR option might be better\.
.
.IP "\(bu" 4
\fB\-\-shards X/Y\fR: splits the scan among instances\. \fBx\fR is the id for this scan, while \fBy\fR is the total number of instances\. For example, \fB\-\-shards 1/2\fR tells an instance to send every other packet, starting with index 0\. Likewise, \fB\-\-shards 2/2\fR sends every other packet, but starting with index 1, so that it doesn\'t overlap with the first example\.
.
.IP "\(bu" 4
\fB\-\-rotate TIME\fR: rotates the output file, renaming it with the current timestamp, moving it to a separate directory\. The time is specified in number of seconds, like "3600" for an hour\. Or, units of time can be specified, such as "hourly", or "6hours", or "10min"\. Times are aligned on an even boundary, so if "daily" is specified, then the file will be rotated every day at midnight\.
.
.IP "\(bu" 4
\fB\-\-rotate\-offset TIME\fR: an offset in the time\. This is to accommodate timezones\.
.
.IP "\(bu" 4
\fB\-\-rotate\-dir DIR\fR: when rotating the file, this specifies which directory to move the file to\. A useful directory is \fB/var/log/masscan\fR\.
.
.IP "\(bu" 4
\fB\-\-seed INT\fR: an integer that seeds the random number generator\. Using a different seed will cause packets to be sent in a different random order\. Instead of an integer, the string \fBtime\fR can be specified, which seeds using the local timestamp, automatically generating a differnet random order of scans\. If no seed specified, \fBtime\fR is the default\.
.
.IP "\(bu" 4
\fB\-\-regress\fR: run a regression test, returns \'0\' on success and \'1\' on failure\.
.
.IP "\(bu" 4
\fB\-\-ttl NUM\fR: specifies the TTL of outgoing packets, defaults to 255\.
.
.IP "\(bu" 4
\fB\-\-wait SECONDS\fR: specifies the number of seconds after transmit is done to wait for receiving packets before exiting the program\. The default is 10 seconds\. The string \fBforever\fR can be specified to never terminate\.
.
.IP "\(bu" 4
\fB\-\-offline\fR: don\'t actually transmit packets\. This is useful with a low rate and \fB\-\-packet\-trace\fR to look at what packets might\'ve been transmitted\. Or, it\'s useful with \fB\-\-rate 100000000\fR in order to benchmark how fast transmit would work (assuming a zero\-overhead driver)\. PF_RING is about 20% slower than the benchmark result from offline mode\.
.
.IP "\(bu" 4
\fB\-sL\fR: this doesn\'t do a scan, but instead creates a list of random addresses\. This is useful for importing into other tools\. The options \fB\-\-shard\fR, \fB\-\-resume\-index\fR, and \fB\-\-resume\-count\fR can be useful with this feature\.
.
.IP "\(bu" 4
\fB\-\-interactive\fR: show the results in realtime on the console\. It has no effect if used with \-\-output\-format or \-\-output\-filename\.
.
.IP "\(bu" 4
\fB\-\-output\-format FMT\fR: indicates the format of the output file, which can be \fBxml\fR, \fBbinary\fR, \fBgrepable\fR, \fBlist\fR, or \fBJSON\fR\. The option \fB\-\-output\-filename\fR must be specified\.
.
.IP "\(bu" 4
\fB\-\-output\-filename FILE\fR: the file which to save results to\. If the parameter \fB\-\-output\-format\fR is not specified, then the default of \fBxml\fR will be used\.
.
.IP "\(bu" 4
\fB\-oB FILE\fR: sets the output format to binary and saves the output in the given filename\. This is equivelent to using the \fB\-\-output\-format\fR and \fB\-\-output\-filename\fR parameters\. The option \fB\-\-readscan\fR can then be used to read the binary file\. Binary files are much smaller than their XML equivelents, but require a separate step to convert back into XML or another readable format\.
.
.IP "\(bu" 4
\fB\-oX FILE\fR: sets the output format to XML and saves the output in the given filename\. This is equivelent to using the \fB\-\-output\-format xml\fR and \fB\-\-output\-filename\fR parameters\.
.
.IP "\(bu" 4
\fB\-oG FILE\fR: sets the output format to grepable and saves the output in the given filename\. This is equivelent to using the \-\-output\-format grepable and \-\-output\-filename parameters\.
.
.IP "\(bu" 4
\fB\-oJ FILE\fR: sets the output format to JSON and saves the output in the given filename\. This is equivelent to using the \-\-output\-format json and \-\-output\-filename parameters\.
.
.IP "\(bu" 4
\fB\-oL FILE\fR: sets the output format to a simple list format and saves the output in the given filename\. This is equivelent to using the \-\-output\-format list and \-\-output\-filename parameters\.
.
.IP "\(bu" 4
\fB\-\-readscan FILE\fR: reads the files created by the \fB\-oB\fR option from a scan, then outputs them in one of the other formats, depending on command\-line parameters\. In other words, it can take the binary version of the output and convert it to an XML or JSON format\.
.
.IP "" 0
.
.SH "CONFIGURATION FILE FORMAT"
The configuration file uses the same parameter names as on the commandline, but without the \fB\-\-\fR prefix, and with an \fB=\fR sign between the name and the value\. An example configuration file might be:
.
.IP "" 4
.
.nf
# targets
range = 10\.0\.0\.0/8,192\.168\.0\.0/16
range = 172\.16\.0\.0/14
ports = 20\-25,80,U:53
ping = true
# adapter
adapter = eth0
adapter\-ip = 192\.168\.0\.1
router\-mac = 66\-55\-44\-33\-22\-11
# other
exclude\-file = /etc/masscan/exludes\.txt
.
.fi
.
.IP "" 0
.
.P
By default, the program will read default configuration from the file \fB/etc/masscan/masscan\.conf\fR\. This is useful for system\-specific settings, such as the \fB\-\-adapter\-xxx\fR options\. This is also useful for excluded IP addresses, so that you can scan the entire Internet, while skipping dangerous addresses, like those owned by the DoD, and not make an accidental mistake\.
.
.SH "CONTROL\-C BEHAVIOR"
When the user presses \fIctrl\-c\fR, the scan will stop, and the current state of the scan will be saved in the file \'paused\.conf\'\. The scan can be resumed with the \fB\-\-resume\fR option:
.
.IP "" 4
.
.nf
# masscan \-\-resume paused\.conf
.
.fi
.
.IP "" 0
.
.P
The program will not exit immediately, but will wait a default of 10 seconds to receive results from the Internet and save the results before exiting completely\. This time can be changed with the \fB\-\-wait\fR option\.
.
.SH "SIMPLE EXAMPLES"
The following example scans all private networks for webservers, and prints all open ports that were found\.
.
.IP "" 4
.
.nf
# masscan 10\.0\.0\.0/8 192\.168\.0\.0/16 172\.16\.0\.0/12 \-p80 \-\-open\-only
.
.fi
.
.IP "" 0
.
.P
The following example scans the entire Internet for DNS servers, grabbing their versions, then saves the results in an XML file\.
.
.IP "" 4
.
.nf
# masscan 0\.0\.0\.0/0 \-\-excludefile no\-dod\.txt \-pU:53 \-\-banners \-\-output\-filename dns\.xml
.
.fi
.
.IP "" 0
.
.P
You should be able to import the XML into databases and such\.
.
.P
The following example reads a binary scan results file called bin\-test\.scan and prints results to console\.
.
.IP "" 4
.
.nf
# masscan \-\-readscan bin\-test\.scan
.
.fi
.
.IP "" 0
.
.P
The following example reads a binary scan results file called bin\-test\.scan and creates an XML output file called bin\-test\.xml\.
.
.IP "" 4
.
.nf
# masscan \-\-readscan bin\-test\.scan \-oX bin\-test\.xml
.
.fi
.
.IP "" 0
.
.SH "ADVANCED EXAMPLES"
Let\'s say that you want to scan the entire Internet and spread the scan across three machines\. Masscan would be launched on all three machines using the following command\-lines:
.
.IP "" 4
.
.nf
# masscan 0\.0\.0\.0/0 \-p0\-65535 \-\-shard 1/3
# masscan 0\.0\.0\.0/0 \-p0\-65535 \-\-shard 2/3
# masscan 0\.0\.0\.0/0 \-p0\-65535 \-\-shard 3/3
.
.fi
.
.IP "" 0
.
.P
An alternative is with the "resume" feature\. A scan has an internal index that goes from zero to the number of ports times then number of IP addresses\. The following example shows splitting up a scan into chunks of a 1000 items each:
.
.IP "" 4
.
.nf
# masscan 0\.0\.0\.0/0 \-p0\-65535 \-\-resume\-index 0 \-\-resume\-count 1000
# masscan 0\.0\.0\.0/0 \-p0\-65535 \-\-resume\-index 1000 \-\-resume\-count 1000
# masscan 0\.0\.0\.0/0 \-p0\-65535 \-\-resume\-index 2000 \-\-resume\-count 1000
# masscan 0\.0\.0\.0/0 \-p0\-65535 \-\-resume\-index 3000 \-\-resume\-count 1000
.
.fi
.
.IP "" 0
.
.P
A script can use this to split smaller tasks across many other machines, such as Amazon EC2 instances\. As each instance completes a job, the script might send a request to a central coordinating server for more work\.
.
.SH "SPURIOUS RESETS"
When scanning TCP using the default IP address of your adapter, the built\-in stack will generate RST packets\. This will prevent banner grabbing\. There are are two ways to solve this\. The first way is to create a firewall rule to block that port from being seen by the stack\. How this works is dependent on the operating system, but on Linux this looks something like:
.
.IP "" 4
.
.nf
# iptables \-A INPUT \-p tcp \-i eth0 \-\-dport 61234 \-j DROP
.
.fi
.
.IP "" 0
.
.P
Then, when scanning, that same port must be used as the source:
.
.IP "" 4
.
.nf
# masscan 10\.0\.0\.0/8 \-p80 \-\-banners \-\-adapter\-port 61234
.
.fi
.
.IP "" 0
.
.P
An alternative is to "spoof" a different IP address\. This IP address must be within the range of the local network, but must not otherwise be in use by either your own computer or another computer on the network\. An example of this would look like:
.
.IP "" 4
.
.nf
# masscan 10\.0\.0\.0/8 \-p80 \-\-banners \-\-adapter\-ip 192\.168\.1\.101
.
.fi
.
.IP "" 0
.
.P
Setting your source IP address this way is the preferred way of running this scanner\.
.
.SH "ABUSE COMPLAINTS"
This scanner is designed for large\-scale surveys, of either an organization, or of the Internet as a whole\. This scanning will be noticed by those monitoring their logs, which will generate complaints\.
.
.P
If you are scanning your own organization, this may lead to you being fired\. Never scan outside your local subnet without getting permission from your boss, with a clear written declaration of why you are scanning\.
.
.P
The same applies to scanning the Internet from your employer\. This is another good way to get fired, as your IT department gets flooded with complaints as to why your organization is hacking them\.
.
.P
When scanning on your own, such as your home Internet or ISP, this will likely cause them to cancel your account due to the abuse complaints\.
.
.P
One solution is to work with your ISP, to be clear about precisely what we are doing, to prove to them that we are researching the Internet, not "hacking" it\. We have our ISP send the abuse complaints directly to us\. For anyone that asks, we add them to our "\-\-excludefile", blacklisting them so that we won\'t scan them again\. While interacting with such people, some instead add us to their whitelist, so that their firewalls won\'t log us anymore (they\'ll still block us, of course, they just won\'t log that fact to avoid filling up their logs with our scans)\.
.
.P
Ultimately, I don\'t know if it\'s possible to completely solve this problem\. Despite the Internet being a public, end\-to\-end network, you are still "guilty until proven innocent" when you do a scan\.
.
.SH "COMPATIBILITY"
While not listed in this document, a lot of parameters compatible with \fBnmap\fR will also work\.
.
.SH "SEE ALSO"
nmap(8), pcap(3)
.
.SH "AUTHORS"
This tool was written by Robert Graham\. The source code is available at https://github\.com/robertdavidgraham/masscan\.

486
doc/masscan.8.markdown Normal file
View File

@@ -0,0 +1,486 @@
masscan(8) -- Fast scan of the Internet
=======================================
## SYNOPSIS
masscan \[options\] \[<IP|ranges>... -p PORT\[,PORT...\]\]
## DESCRIPTION
**masscan** is an Internet-scale port scanner, useful for large scale surveys
of the Internet, or of internal networks. While the default transmit rate
is only 100 packets/second, it can optionally go as fast as 25 million
packets/second, a rate sufficient to scan the Internet in 3 minutes for
one port.
## OPTIONS
* `<IP|RANGE>`: anything on the command-line not prefixed with a '-' is
assumed to be an IP address or range. There are three valid formats.
The first is a single IP address like `192.168.0.1` or `2001:db8::1`. The second
is a range like `10.0.0.1-10.0.0.100`. The third is a CIDR address,
like `0.0.0.0/0` or `2001:db8::/90`. At least one target must be specified. Multiple
targets can be specified. This can be specified as multiple options
separated by space, or can be separated by a comma as a single option,
such as `10.0.0.0/8,192.168.0.1,2001:db8::1`.
* `--range <IP|RANGE>`: the same as target range spec described above,
except as a named parameter instead of an unnamed one.
* `-p PORT[,PORT..]`, `--ports PORT[,PORT...]`: specifies the port(s) to be scanned. A
single port can be specified, like `-p80`. A range of ports can be
specified, like `-p 20-25`. A list of ports/ranges can be specified, like
`-p80,20-25`. UDP ports can also be specified, like
`--ports U:161,U:1024-1100`.
* `--banners`: specifies that banners should be grabbed after establishing
a TCP connection. Protocols supported include HTTP, FTP, IMAP4, memcached,
POP3, SMTP, SSH, SSL, SMB, Telnet, RDP, and VNC. Note that banner will be
grabbed on standard port of the service only.
You may change this behavior with `--hello-string` or `--hello-file` options.
* `--rate RATE`: specifies the desired rate for transmitting
packets. This can be very small numbers, like `0.1` for transmitting
packets at rates of one every 10 seconds, for very large numbers like
10000000, which attempts to transmit at 10 million packets/second. In my
experience, Windows and can do 250 thousand packets per second, and latest
versions of Linux can do 2.5 million packets per second. The PF_RING driver
is needed to get to 25 million packets/second.
* `-c FILE`, `--conf FILE`: reads in a configuration file.
If not specified, then will read from `/etc/masscan/masscan.conf` by default.
The format is described below under 'CONFIGURATION FILE'.
* `--resume FILE`: the same as `--conf`, except that a few options
are automatically set, such as `--append-output`. The format of the
configuration file is described below. The purpose is to resume a scan
saved in `paused.conf` that was interupted with [ctrl-c].
* `--echo`: don't run, but instead dump the current configuration to a file.
This file can then be used with the `-c` option. The format of this
output is described below under 'CONFIGURATION FILE'.
* `-e IFNAME`, `--adapter IFNAME`: use the named raw network interface,
such as "eth0" or "dna1". If not specified, the first network interface
found with a default gateway will be used.
* `--adapter-ip IP`, `--source-ip IP`: send packets using this IP address. If not
specified, then the first IP address bound to the network interface
will be used. Instead of a single IP address, a range may be specified.
NOTE: The size of the range must be an even power of 2, such as 1, 2, 4,
8, 16, 1024 etc. addresses.
* `--adapter-port PORT`: send packets using this port number as the
source. If not specified, a random port will be chosen in the range 40000
through 60000. This port should be filtered by the host firewall (like
iptables) to prevent the host network stack from interfering with arriving
packets. Instead of a single port, a range can be specified, like
`40000-40003`. NOTE: The size of the range must be an even power of 2,
such as the example above that has a total of 4 addresses.
* `--adapter-mac MAC`: send packets using this as the source MAC
address. If not specified, then the first MAC address bound to the network
interface will be used.
* `--adapter-vlan VLANID`: send packets using this 802.1q VLAN ID
* `--router-mac MAC`: send packets to this MAC address as the
destination. If not specified, then the gateway address of the network
interface will be ARPed.
* `--ping`: indicates that the scan should include an ICMP echo request.
This may be included with TCP and UDP scanning.
* `--exclude <IP|RANGE>`: blacklist an IP address or range, preventing it
from being scanned. This overrides any target specification, guaranteeing
that this address/range won't be scanned. This has the same format
as the normal target specification.
* `--excludefile FILE`: reads in a list of exclude ranges, in the same
target format described above. These ranges override any targets,
preventing them from being scanned.
* `-iL FILE`, `--includefile FILE`: reads in a list of ranges to scan, in the same
target format described above for IP addresses and ranges. This file can contain
millions of addresses and ranges.
* `--append-output`: causes output to append to the file, rather than
overwriting the file. Useful for when resumeing scans (see `--resume`).
* `--iflist`: list the available network interfaces, and then exits. The
`-e IFNAME` can then be used with one of the listed adapters.
* `--retries <num>`: the number of retries to send, at 1 second intervals. Note
that since this scanner is stateless, retries are sent regardless if
replies have already been received.
* `--nmap`: print help about nmap-compatibility alternatives for these
options.
* `--pcap-payloads FILE`: read packets from a libpcap file containing packets
and extract the UDP payloads, and associate those payloads with the
destination port. These payloads will then be used when sending UDP
packets with the matching destination port. Only one payload will
be remembered per port. Similar to `--nmap-payloads`.
* `--nmap-payloads FILE`: read in a file in the same format as
the nmap file `nmap-payloads`. This contains UDP payload, so that we
can send useful UDP packets instead of empty ones. Similar to
`--pcap-payloads`.
* `--http-* HEADER`: replaces the existing field in the HTTP header
with a new one. Fields that can be replaced are `--http-method`, `--http-url`,
`--http-version`,`--http-host`, and `--http-user-agent`.
Example: `--http-user-agent Keurig K575 Coffee Maker`. See also `--http-field` and `--http-cookie`.
* `--http-field NAME:VALUE`: replaces the existing HTTP header field,
or inserts a new one if the field doesn't exist, given as a `name:value` pair.
Cannot be used to replace the fields in the request-line (method, url, version).
Example: `--http-field Accept:image/gif`.
* `--http-field-remove NAME`: removes the first field from the header that matches
(may be needed multiple times for fields like `Cookie` that can exist multiple times)
* `--http-cookie VALUE`: adds a `Cookie:` field to the HTTP header, even
if other cookie fields exist. The other `--http-*` options replace existing
fields in the HTTP header, this one adds more even if some already exist.
* `--http-payload STR`: adds a payload string after the header; this will
automatically add a `--http-field Content-Length:LEN` field to match the length of the string,
but the user will have to add their own `--http-field Content-Type:TYPE` field to match
the string. Presumably, the user will also change the method to something like
`--http-method POST`. Common conntent types would be `application/x-www-form-urlencoded`,
`application/json`, or `text/xml`.
* `--show [open|closed]`: tells which port status to display, such
as 'open' for those ports that respond with a SYN-ACK on TCP, or
'closed' for those ports that repsond with RST. The default is
only to display 'open' ports.
* `--noshow [open|closed]`: disables a port status to display, such
as to no longer display 'open' ports.
* `--pcap FILE`: saves received packets (but not transmitted
packets) to the libpcap-format file.
* `--packet-trace`: prints a summary of those packets sent and received.
This is useful at low rates, like a few packets per second, but will
overwhelm the terminal at high rates.
* `--pfring`: force the use of the PF_RING driver. The program will exit
if PF_RING DNA drvers are not available.
* `--resume-index INDEX`: the point in the scan at when it was paused.
* `--resume-count NUM`: the maximum number of probes to send before exiting.
This is useful with the `--resume-index` to chop up a scan and split
it among multiple instances, though the `--shards` option might be
better.
* `--shards X/Y`: splits the scan among instances. `x` is the id
for this scan, while `y` is the total number of instances. For example,
`--shards 1/2` tells an instance to send every other packet, starting
with index 0. Likewise, `--shards 2/2` sends every other packet, but
starting with index 1, so that it doesn't overlap with the first example.
* `--rotate TIME`: rotates the output file, renaming it with the
current timestamp, moving it to a separate directory. The time is
specified in number of seconds, like "3600" for an hour. Or, units
of time can be specified, such as "hourly", or "6hours", or "10min".
Times are aligned on an even boundary, so if "daily" is specified,
then the file will be rotated every day at midnight.
* `--rotate-offset TIME`: an offset in the time. This is to accomodate
timezones.
* `--rotate-size SIZE`: rotates the output file when it exceeds the
given size. Typical suffixes can be applied (k,m,g,t) for kilo, mega,
giga, tera.
* `--rotate-dir DIR`: when rotating the file, this specifies which
directory to move the file to. A useful directory is `/var/log/masscan`.
* `--seed INT`: an integer that seeds the random number generator.
Using a different seed will cause packets to be sent in a different
random order. Instead of an integer, the string `time` can be specified,
which seeds using the local timestamp, automatically generating a
different random order of scans. If no seed specified, `time` is the
default.
* `--regress`: run a regression test, returns '0' on success and '1' on
failure.
* `--ttl NUM`: specifies the TTL of outgoing packets, defaults to 255.
* `--wait SECONDS`: specifies the number of seconds after transmit is
done to wait for receiving packets before exiting the program. The default
is 10 seconds. The string `forever` can be specified to never terminate.
* `--offline`: don't actually transmit packets. This is useful with
a low rate and `--packet-trace` to look at what packets might've been
transmitted. Or, it's useful with `--rate 100000000` in order to
benchmark how fast transmit would work (assuming a zero-overhead
driver). PF_RING is about 20% slower than the benchmark result from
offline mode.
* `-sL`: this doesn't do a scan, but instead creates a list of random
addresses. This is useful for importing into other tools. The options
`--shard`, `--resume-index`, and `--resume-count` can be useful with
this feature.
* `--interactive`: show the results in realtime on the console. It has
no effect if used with --output-format or --output-filename.
* `--output-format FMT`: indicates the format of the output file, which
can be `xml`, `binary`, `grepable`, `list`, or `JSON`. The
option `--output-filename` must be specified.
* `--output-filename FILE`: the file which to save results to. If
the parameter `--output-format` is not specified, then the default of
`xml` will be used.
* `-oB FILE`: sets the output format to binary and saves the output in
the given filename. This is equivalent to using the `--output-format` and
`--output-filename` parameters. The option `--readscan` can then be used to
read the binary file. Binary files are mush smaller than their XML
equivalents, but require a separate step to convert back into XML or
another readable format.
* `-oX FILE`: sets the output format to XML and saves the output in the
given filename. This is equivalent to using the `--output-format xml` and
`--output-filename` parameters.
* `-oG FILE`: sets the output format to grepable and saves the output
in the given filename. This is equivalent to using the --output-format grepable
and --output-filename parameters.
* `-oJ FILE`: sets the output format to JSON and saves the output in
the given filename. This is equivalent to using the --output-format json
and --output-filename parameters.
* `-oL FILE`: sets the output format to a simple list format and saves
the output in the given filename. This is equivalent to using
the --output-format list and --output-filename parameters.
* `--readscan FILE`: reads the files created by the `-oB` option
from a scan, then outputs them in one of the other formats, depending
on command-line parameters. In other words, it can take the binary
version of the output and convert it to an XML or JSON format. When this option
is given, defaults from `/etc/masscan/masscan.conf` will not be read.
* `--connection-timeout SECS`: when doing banner checks, this specifies the
maximum number of seconds that a TCP connection can be held open. The default
is 30 seconds. Increase this time if banners are incomplete. For example,
we have to increase the timeout when downloading all the SSL certs from
the Internet, because some sites take that long to deliver all the certs
in the chain. However, beware that when this is set to a large value, it'll
consume a lot of memory on fast scans. While the code may handle millions of
open TCP connections, you may not have enough memory for that.
* `--hello-file[PORT] FILE`: send the contents of the file once the
TCP connection has been established with the given port. Requires that
`--banners` also be set. Heuristics will be performed on the reponse in
an attempt to discover what protocol, so HTTP responses will be parsed
differently than other protocols.
* `--hello-string[PORT] BASE64`: same as `--hello-file` except that the
contents of the BASE64 encoded string are decoded, then used as the hello
string that greets the server.
* `--capture TYPE` or `--nocapture TYPE`: when doing banners (`--banner`), this
determines what to capture from the banners. By default, only the TITLE field from
HTML documents is captured, to get the entire document, use `--capture html`.
By default, the entire certificate from SSL is captured, to disable this, use
`--nocapture cert`. Currently, only the values `html` and `cert` are currently
supported for this option, but many more will be added in the future.
## CONFIGURATION FILE FORMAT
The configuration file uses the same parameter names as on the
commandline, but without the `--` prefix, and with an `=` sign
between the name and the value. An example configuration file
might be:
# targets
range = 10.0.0.0/8,192.168.0.0/16
range = 172.16.0.0/12
ports = 20-25,80,U:53
ping = true
# adapter
adapter = eth0
adapter-ip = 192.168.0.1
router-mac = 66-55-44-33-22-11
# other
exclude-file = /etc/masscan/exludes.txt
By default, the program will read default configuration from the file
`/etc/masscan/masscan.conf`. This is useful for system-specific settings,
such as the `--adapter-xxx` options. This is also useful for
excluded IP addresses, so that you can scan the entire Internet,
while skipping dangerous addresses, like those owned by the DoD,
and not make an accidental mistake.
## CONTROL-C BEHAVIOR
When the user presses <ctrl-c>, the scan will stop, and the current
state of the scan will be saved in the file 'paused.conf'. The scan
can be resumed with the `--resume` option:
# masscan --resume paused.conf
The program will not exit immediately, but will wait a default of 10
seconds to receive results from the Internet and save the results before
exiting completely. This time can be changed with the `--wait` option.
## USER-MODE STACK
Masscan has a user-mode TCP/IP stack that co-exists with the operating-system's
stack. Normally, this works fine but sometimes can cause problems, especially
with the `--banners` option that establishes a TCP/IP connection. In some
cases, all the stack's parameters will have to be specified separately:
--adapter-port PORT
--adapter-ip IP
--adapter-mac MAC
--adapter-vlan VLANID
--router-mac MAC
If the user-mode stack shares the same IP address as the operating-system,
then the kernel will send RST packets during a scan. This can cause
unnecessary traffic during a simple port scan, and will terminate TCP
connections when doing a `--banners` scan. To prevent, this, the built-in
firewall should be used to filter the source ports. On Linux, this can be done
by doing something like:
# iptables -A INPUT -i eth0 -p tcp --dport 44444 -j DROP
This will prevent the Linux kernel from processing incoming packets to port
44444, but `masscan` will still see the packets. Set the maching parameter
of `--adapter-port 44444` to force `masscan` to use that port instead of
a random port.
## SIMPLE EXAMPLES
The following example scans all private networks for webservers, and prints
all open ports that were found.
# masscan 10.0.0.0/8 192.168.0.0/16 172.16.0.0/12 -p80 --open-only
The following example scans the entire Internet for DNS servers, grabbing
their versions, then saves the results in an XML file.
# masscan 0.0.0.0/0 --excludefile no-dod.txt -pU:53 --banners --output-filename dns.xml
You should be able to import the XML into databases and such.
The following example reads a binary scan results file called bin-test.scan and prints
results to console.
# masscan --readscan bin-test.scan
The following example reads a binary scan results file called bin-test.scan and creates
an XML output file called bin-test.xml.
# masscan --readscan bin-test.scan -oX bin-test.xml
## ADVANCED EXAMPLES
Let's say that you want to scan the entire Internet and spread the scan
across three machines. Masscan would be launched on all three machines
using the following command-lines:
# masscan 0.0.0.0/0 -p0-65535 --shard 1/3
# masscan 0.0.0.0/0 -p0-65535 --shard 2/3
# masscan 0.0.0.0/0 -p0-65535 --shard 3/3
An alternative is with the "resume" feature. A scan has an internal index that
goes from zero to the number of ports times the number of IP addresses. The
following example shows splitting up a scan into chunks of a 1000 items each:
# masscan 0.0.0.0/0 -p0-65535 --resume-index 0 --resume-count 1000
# masscan 0.0.0.0/0 -p0-65535 --resume-index 1000 --resume-count 1000
# masscan 0.0.0.0/0 -p0-65535 --resume-index 2000 --resume-count 1000
# masscan 0.0.0.0/0 -p0-65535 --resume-index 3000 --resume-count 1000
A script can use this to split smaller tasks across many other machines,
such as Amazon EC2 instances. As each instance completes a job, the
script might send a request to a central coordinating server for more
work.
## SPURIOUS RESETS
When scanning TCP using the default IP address of your adapter, the built-in
stack will generate RST packets. This will prevent banner grabbing. There are
are two ways to solve this. The first way is to create a firewall rule
to block that port from being seen by the stack. How this works is dependent
on the operating system, but on Linux this looks something like:
# iptables -A INPUT -p tcp -i eth0 --dport 61234 -j DROP
Then, when scanning, that same port must be used as the source:
# masscan 10.0.0.0/8 -p80 --banners --adapter-port 61234
An alternative is to "spoof" a different IP address. This IP address must be
within the range of the local network, but must not otherwise be in use by
either your own computer or another computer on the network. An example of this
would look like:
# masscan 10.0.0.0/8 -p80 --banners --adapter-ip 192.168.1.101
Setting your source IP address this way is the preferred way of running this
scanner.
## ABUSE COMPLAINTS
This scanner is designed for large-scale surveys, of either an organization,
or of the Internet as a whole. This scanning will be noticed by those
monitoring their logs, which will generate complaints.
If you are scanning your own organization, this may lead to you being fired.
Never scan outside your local subnet without getting permission from your boss,
with a clear written declaration of why you are scanning.
The same applies to scanning the Internet from your employer. This is another
good way to get fired, as your IT department gets flooded with complaints as
to why your organization is hacking them.
When scanning on your own, such as your home Internet or ISP, this will likely
cause them to cancel your account due to the abuse complaints.
One solution is to work with your ISP, to be clear about precisely what we are
doing, to prove to them that we are researching the Internet, not "hacking" it.
We have our ISP send the abuse complaints directly to us. For anyone that asks,
we add them to our "--excludefile", blacklisting them so that we won't scan
them again. While interacting with such people, some instead add us to their
whitelist, so that their firewalls won't log us anymore (they'll still block
us, of course, they just won't log that fact to avoid filling up their logs
with our scans).
Ultimately, I don't know if it's possible to completely solve this problem.
Despite the Internet being a public, end-to-end network, you are still
"guilty until proven innocent" when you do a scan.
## COMPATIBILITY
While not listed in this document, a lot of parameters compatible with
`nmap` will also work. It runs on macOS, Linux, and Windows. It's compiled
in fairly portable C language. It supports IPv4 and IPv6.
## SEE ALSO
nmap(8), pcap(3)
## AUTHORS
This tool was written by Robert Graham. The source code is available at
https://github.com/robertdavidgraham/masscan.

225
src/crypto-base64.c Normal file
View File

@@ -0,0 +1,225 @@
#include "crypto-base64.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
/*****************************************************************************
*****************************************************************************/
size_t
base64_encode(void *vdst, size_t sizeof_dst,
const void *vsrc, size_t sizeof_src)
{
static const char *b64 =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"+/";
size_t i = 0;
size_t d = 0;
unsigned char *dst = (unsigned char *)vdst;
const unsigned char *src = (const unsigned char *)vsrc;
/* encode every 3 bytes of source into 4 bytes of destination text */
while (i + 3 <= sizeof_src) {
unsigned n;
/* make sure there is enough space */
if (d + 4 > sizeof_dst)
return d;
/* convert the chars */
n = src[i]<<16 | src[i+1]<<8 | src[i+2];
dst[d+0] = b64[ (n>>18) & 0x3F ];
dst[d+1] = b64[ (n>>12) & 0x3F ];
dst[d+2] = b64[ (n>> 6) & 0x3F ];
dst[d+3] = b64[ (n>> 0) & 0x3F ];
i += 3;
d += 4;
}
/* If the source text isn't an even multiple of 3 characters, then we'll
* have to append a '=' or '==' to the output to compensate */
if (i + 2 <= sizeof_src && d + 4 <= sizeof_dst) {
unsigned n = src[i]<<16 | src[i+1]<<8;
dst[d+0] = b64[ (n>>18) & 0x3F ];
dst[d+1] = b64[ (n>>12) & 0x3F ];
dst[d+2] = b64[ (n>> 6) & 0x3F ];
dst[d+3] = '=';
d += 4;
} else if (i + 1 <= sizeof_src && d + 4 <= sizeof_dst) {
unsigned n = src[i]<<16;
dst[d+0] = b64[ (n>>18) & 0x3F ];
dst[d+1] = b64[ (n>>12) & 0x3F ];
dst[d+2] = '=';
dst[d+3] = '=';
d += 4;
}
return d;
}
/*****************************************************************************
*****************************************************************************/
size_t
base64_decode(void *vdst, size_t sizeof_dst,
const void *vsrc, size_t sizeof_src)
{
static const unsigned char rstr[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 62, 0xFF, 0xFF, 0xFF, 63,
52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};
size_t i = 0;
size_t d = 0;
unsigned char *dst = (unsigned char *)vdst;
const unsigned char *src = (const unsigned char *)vsrc;
while (i < sizeof_src) {
unsigned b;
unsigned c=0;
/* byte#1 */
while (i<sizeof_src && (c = rstr[src[i]]) > 64)
i++;
if (src[i] == '=' || i++ >= sizeof_src)
break;
b = (c << 2) & 0xfc;
while (i<sizeof_src && (c = rstr[src[i]]) > 64)
i++;
if (src[i] == '=' || i++ >= sizeof_src)
break;
b |= (c>>4) & 0x03;
if (d<sizeof_dst)
dst[d++] = (unsigned char)b;
if (i>=sizeof_src)
break;
/* byte#2 */
b = (c<<4) & 0xF0;
while (i<sizeof_src && src[i] != '=' && (c = rstr[src[i]]) > 64)
;
if (src[i] == '=' || i++ >= sizeof_src)
break;
b |= (c>>2) & 0x0F;
if (d<sizeof_dst)
dst[d++] = (unsigned char)b;
if (i>=sizeof_src)
break;
/* byte#3*/
b = (c<<6) & 0xC0;
while (i<sizeof_src && src[i] != '=' && (c = rstr[src[i]]) > 64)
;
if (src[i] == '=' || i++ >= sizeof_src)
break;
b |= c;
if (d<sizeof_dst)
dst[d++] = (unsigned char)b;
if (i>=sizeof_src)
break;
}
if (d<sizeof_dst)
dst[d] = '\0';
return d;
}
/*****************************************************************************
* Provide my own rand() simply to avoid static-analysis warning me that
* 'rand()' is unrandom, when in fact we want the non-random properties of
* rand() for regression testing.
*****************************************************************************/
static unsigned
r_rand(unsigned *seed)
{
static const unsigned a = 214013;
static const unsigned c = 2531011;
*seed = (*seed) * a + c;
return (*seed)>>16 & 0x7fff;
}
/*****************************************************************************
*****************************************************************************/
int
base64_selftest(void)
{
char buf[100];
char buf2[100];
char buf3[100];
size_t buf_len;
size_t buf2_len;
unsigned i;
unsigned seed = (unsigned)time(0);
buf_len = base64_encode(buf, sizeof(buf), "hello", 5);
buf2_len = base64_decode(buf2, sizeof(buf2), buf, buf_len);
if (buf2_len != 5 && memcmp(buf2, "hello", 5) != 0) {
fprintf(stderr, "base64: selftest failed\n");
return 1;
}
/*
* Generate a bunch of random strings, encode them, then decode them,
* making sure the final result matches the original string
*/
for (i=0; i<100; i++) {
unsigned j;
size_t buf3_len;
/* create a string of random bytes */
buf_len = r_rand(&seed) % 50;
for (j=0; j<buf_len; j++) {
buf[j] = (char)r_rand(&seed);
}
/* encode it */
buf2_len = base64_encode(buf2, sizeof(buf2), buf, buf_len);
/* decode it back again */
buf3_len = base64_decode(buf3, sizeof(buf3), buf2, buf2_len);
/* now make sure result equals original */
if (buf3_len != buf_len && memcmp(buf3, buf, buf_len) != 0) {
fprintf(stderr, "base64: selftest failed\n");
return 1;
}
}
return 0;
}

10
src/crypto-base64.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef CRYPTO_BASE64_H
#define CRYPTO_BASE64_H
#include <stdio.h>
size_t base64_decode(void *dst, size_t sizeof_dst, const void *src, size_t sizeof_src);
size_t base64_encode(void *dst, size_t sizeof_dst, const void *src, size_t sizeof_src);
int base64_selftest(void);
#endif

420
src/crypto-blackrock.c Normal file
View File

@@ -0,0 +1,420 @@
/*
BlackRock cipher
(h/t Marsh Ray @marshray for this idea)
This is a randomization/reshuffling function based on a crypto
"Feistel network" as described in the paper:
'Ciphers with Arbitrary Finite Domains'
by John Black and Phillip Rogaway
http://www.cs.ucdavis.edu/~rogaway/papers/subset.pdf
This is a crypto-like construction that encrypts an arbitrary sized
range. Given a number in the range [0..9999], it'll produce a mapping
to a distinct different number in the same range (and back again).
In other words, it randomizes the order of numbers in a sequence.
For example, it can be used to randomize the sequence [0..9]:
0 -> 6
1 -> 4
2 -> 8
3 -> 1
4 -> 9
5 -> 3
6 -> 0
7 -> 5
8 -> 2
9 -> 7
As you can see on the right hand side, the numbers are in random
order, and they don't repeat.
This is create for port scanning. We can take an index variable
and increment it during a scan, then use this function to
randomize it, yet be assured that we've probed every IP and port
within the range.
The cryptographic strength of this construction depends upon the
number of rounds, and the exact nature of the inner "READ()" function.
Because it's a Feistel network, that "READ()" function can be almost
anything.
We don't care about cryptographic strength, just speed, so we are
using a trivial READ() function.
This is a class of "format-preserving encryption". There are
probably better constructions than what I'm using.
*/
#include "crypto-blackrock.h"
#include "pixie-timer.h"
#include "util-malloc.h"
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <time.h>
#if defined(_MSC_VER)
#define inline _inline
#endif
/***************************************************************************
* It's an s-box. You gotta have an s-box
***************************************************************************/
const unsigned char sbox[256] = {
0x91, 0x58, 0xb3, 0x31, 0x6c, 0x33, 0xda, 0x88,
0x57, 0xdd, 0x8c, 0xf2, 0x29, 0x5a, 0x08, 0x9f,
0x49, 0x34, 0xce, 0x99, 0x9e, 0xbf, 0x0f, 0x81,
0xd4, 0x2f, 0x92, 0x3f, 0x95, 0xf5, 0x23, 0x00,
0x0d, 0x3e, 0xa8, 0x90, 0x98, 0xdd, 0x20, 0x00,
0x03, 0x69, 0x0a, 0xca, 0xba, 0x12, 0x08, 0x41,
0x6e, 0xb9, 0x86, 0xe4, 0x50, 0xf0, 0x84, 0xe2,
0xb3, 0xb3, 0xc8, 0xb5, 0xb2, 0x2d, 0x18, 0x70,
0x0a, 0xd7, 0x92, 0x90, 0x9e, 0x1e, 0x0c, 0x1f,
0x08, 0xe8, 0x06, 0xfd, 0x85, 0x2f, 0xaa, 0x5d,
0xcf, 0xf9, 0xe3, 0x55, 0xb9, 0xfe, 0xa6, 0x7f,
0x44, 0x3b, 0x4a, 0x4f, 0xc9, 0x2f, 0xd2, 0xd3,
0x8e, 0xdc, 0xae, 0xba, 0x4f, 0x02, 0xb4, 0x76,
0xba, 0x64, 0x2d, 0x07, 0x9e, 0x08, 0xec, 0xbd,
0x52, 0x29, 0x07, 0xbb, 0x9f, 0xb5, 0x58, 0x6f,
0x07, 0x55, 0xb0, 0x34, 0x74, 0x9f, 0x05, 0xb2,
0xdf, 0xa9, 0xc6, 0x2a, 0xa3, 0x5d, 0xff, 0x10,
0x40, 0xb3, 0xb7, 0xb4, 0x63, 0x6e, 0xf4, 0x3e,
0xee, 0xf6, 0x49, 0x52, 0xe3, 0x11, 0xb3, 0xf1,
0xfb, 0x60, 0x48, 0xa1, 0xa4, 0x19, 0x7a, 0x2e,
0x90, 0x28, 0x90, 0x8d, 0x5e, 0x8c, 0x8c, 0xc4,
0xf2, 0x4a, 0xf6, 0xb2, 0x19, 0x83, 0xea, 0xed,
0x6d, 0xba, 0xfe, 0xd8, 0xb6, 0xa3, 0x5a, 0xb4,
0x48, 0xfa, 0xbe, 0x5c, 0x69, 0xac, 0x3c, 0x8f,
0x63, 0xaf, 0xa4, 0x42, 0x25, 0x50, 0xab, 0x65,
0x80, 0x65, 0xb9, 0xfb, 0xc7, 0xf2, 0x2d, 0x5c,
0xe3, 0x4c, 0xa4, 0xa6, 0x8e, 0x07, 0x9c, 0xeb,
0x41, 0x93, 0x65, 0x44, 0x4a, 0x86, 0xc1, 0xf6,
0x2c, 0x97, 0xfd, 0xf4, 0x6c, 0xdc, 0xe1, 0xe0,
0x28, 0xd9, 0x89, 0x7b, 0x09, 0xe2, 0xa0, 0x38,
0x74, 0x4a, 0xa6, 0x5e, 0xd2, 0xe2, 0x4d, 0xf3,
0xf4, 0xc6, 0xbc, 0xa2, 0x51, 0x58, 0xe8, 0xae,
};
/***************************************************************************
***************************************************************************/
void
blackrock_init(struct BlackRock *br, uint64_t range, uint64_t seed, unsigned rounds)
{
double foo = sqrt(range * 1.0);
/* This algorithm gets very non-random at small numbers, so I'm going
* to try to fix some constants here to make it work. It doesn't have
* to be good, since it's kinda pointless having ranges this small */
switch (range) {
case 0:
br->a = 0;
br->b = 0;
break;
case 1:
br->a = 1;
br->b = 1;
break;
case 2:
br->a = 1;
br->b = 2;
break;
case 3:
br->a = 2;
br->b = 2;
break;
case 4:
case 5:
case 6:
br->a = 2;
br->b = 3;
break;
case 7:
case 8:
br->a = 3;
br->b = 3;
break;
default:
br->range = range;
br->a = (uint64_t)(foo - 2);
br->b = (uint64_t)(foo + 3);
break;
}
while (br->a * br->b <= range)
br->b++;
br->rounds = rounds;
br->seed = seed;
br->range = range;
}
/***************************************************************************
* The inner round/mixer function. In DES, it's a series of S-box lookups,
* which
***************************************************************************/
static inline uint64_t
READ(uint64_t r, uint64_t R, uint64_t seed)
{
uint64_t r0, r1, r2, r3;
#define GETBYTE(R,n) ((((R)>>(n*8))^seed^r)&0xFF)
R ^= (seed << r) ^ (seed >> (64 - r));
r0 = sbox[GETBYTE(R,0)]<< 0 | sbox[GETBYTE(R,1)]<< 8;
r1 = (sbox[GETBYTE(R,2)]<<16UL | sbox[GETBYTE(R,3)]<<24UL)&0x0ffffFFFFUL;
r2 = sbox[GETBYTE(R,4)]<< 0 | sbox[GETBYTE(R,5)]<< 8;
r3 = (sbox[GETBYTE(R,6)]<<16UL | sbox[GETBYTE(R,7)]<<24UL)&0x0ffffFFFFUL;
R = r0 ^ r1 ^ r2<<23UL ^ r3<<33UL;
return R;
}
/***************************************************************************
*
* NOTE:
* the names in this function are cryptic in order to match as closely
* as possible the pseudocode in the following paper:
* http://www.cs.ucdavis.edu/~rogaway/papers/subset.pdf
* Read that paper in order to understand this code.
***************************************************************************/
static inline uint64_t
ENCRYPT(unsigned r, uint64_t a, uint64_t b, uint64_t m, uint64_t seed)
{
uint64_t L, R;
unsigned j;
uint64_t tmp;
L = m % a;
R = m / a;
for (j=1; j<=r; j++) {
if (j & 1) {
tmp = (L + READ(j, R, seed)) % a;
} else {
tmp = (L + READ(j, R, seed)) % b;
}
L = R;
R = tmp;
}
if (r & 1) {
return a * L + R;
} else {
return a * R + L;
}
}
/***************************************************************************
***************************************************************************/
static inline uint64_t
UNENCRYPT(unsigned r, uint64_t a, uint64_t b, uint64_t m, uint64_t seed)
{
uint64_t L, R;
unsigned j;
uint64_t tmp;
if (r & 1) {
R = m % a;
L = m / a;
} else {
L = m % a;
R = m / a;
}
for (j=r; j>=1; j--) {
if (j & 1) {
tmp = READ(j, L, seed);
if (tmp > R) {
tmp = (tmp - R);
tmp = a - (tmp%a);
if (tmp == a)
tmp = 0;
} else {
tmp = (R - tmp);
tmp %= a;
}
} else {
tmp = READ(j, L, seed);
if (tmp > R) {
tmp = (tmp - R);
tmp = b - (tmp%b);
if (tmp == b)
tmp = 0;
} else {
tmp = (R - tmp);
tmp %= b;
}
}
R = L;
L = tmp;
}
return a * R + L;
}
/***************************************************************************
***************************************************************************/
uint64_t
blackrock_shuffle(const struct BlackRock *br, uint64_t m)
{
uint64_t c;
c = ENCRYPT(br->rounds, br->a, br->b, m, br->seed);
while (c >= br->range)
c = ENCRYPT(br->rounds, br->a, br->b, c, br->seed);
return c;
}
/***************************************************************************
***************************************************************************/
uint64_t
blackrock_unshuffle(const struct BlackRock *br, uint64_t m)
{
uint64_t c;
c = UNENCRYPT(br->rounds, br->a, br->b, m, br->seed);
while (c >= br->range)
c = UNENCRYPT(br->rounds, br->a, br->b, c, br->seed);
return c;
}
/***************************************************************************
* This function called only during selftest/regression-test.
***************************************************************************/
static unsigned
blackrock_verify(struct BlackRock *br, uint64_t max)
{
unsigned char *list;
uint64_t i;
unsigned is_success = 1;
uint64_t range = br->range;
/* Allocate a list of 1-byte counters */
list = CALLOC(1, (size_t)((range<max)?range:max));
/* For all numbers in the range, verify increment the counter for
* the output. */
for (i=0; i<range; i++) {
uint64_t x = blackrock_shuffle(br, i);
if (x < max)
list[x]++;
}
/* Now check the output to make sure that every counter is set exactly
* to the value of '1'. */
for (i=0; i<max && i<range; i++) {
if (list[i] != 1)
is_success = 0;
}
free(list);
return is_success;
}
/***************************************************************************
***************************************************************************/
void
blackrock_benchmark(unsigned rounds)
{
struct BlackRock br;
uint64_t range = 0x012356789123ULL;
uint64_t i;
uint64_t result = 0;
uint64_t start, stop;
static const uint64_t ITERATIONS = 5000000ULL;
printf("-- blackrock-1 -- \n");
printf("rounds = %u\n", rounds);
blackrock_init(&br, range, 1, rounds);
/*
* Time the algorithm
*/
start = pixie_nanotime();
for (i=0; i<ITERATIONS; i++) {
result += blackrock_shuffle(&br, i);
}
stop = pixie_nanotime();
/*
* Print the results
*/
if (result) {
double elapsed = ((double)(stop - start))/(1000000000.0);
double rate = ITERATIONS/elapsed;
rate /= 1000000.0;
printf("iterations/second = %5.3f-million\n", rate);
}
printf("\n");
}
/***************************************************************************
***************************************************************************/
int
blackrock_selftest(void)
{
uint64_t i;
uint64_t range;
/* @marshray
* Basic test of decryption. I take the index, encrypt it, then decrypt it,
* which means I should get the original index back again. Only, it's not
* working. The decryption fails. The reason it's failing is obvious -- I'm
* just not seeing it though. The error is probably in the 'UNENCRYPT()'
* function above.
*/
{
struct BlackRock br;
blackrock_init(&br, 1000, 0, 4);
for (i=0; i<10; i++) {
uint64_t result, result2;
result = blackrock_shuffle(&br, i);
result2 = blackrock_unshuffle(&br, result);
if (i != result2)
return 1; /*fail*/
}
}
range = 3015 * 3;
for (i=0; i<5; i++) {
struct BlackRock br;
int is_success;
range += 10 + i;
range *= 2;
blackrock_init(&br, range, time(0), 4);
is_success = blackrock_verify(&br, range);
if (!is_success) {
fprintf(stderr, "BLACKROCK: randomization failed\n");
return 1; /*fail*/
}
}
return 0; /*success*/
}

79
src/crypto-blackrock.h Normal file
View File

@@ -0,0 +1,79 @@
#ifndef RAND_BLACKROCK_H
#define RAND_BLACKROCK_H
#include <stdint.h>
struct BlackRock {
uint64_t range;
uint64_t a;
uint64_t b;
uint64_t seed;
unsigned rounds;
uint64_t a_bits;
uint64_t a_mask;
uint64_t b_bits;
uint64_t b_mask;
};
/**
* Initializes a structure for shuffling numbers within
* a range.
*
* @param range
* The size of the range of numbers needing to be
* shuffled/randomized.
*/
void
blackrock_init(struct BlackRock *br, uint64_t range, uint64_t seed, unsigned rounds);
void
blackrock2_init(struct BlackRock *br, uint64_t range, uint64_t seed, unsigned rounds);
/**
* Given a number within a range, produce a different number with
* the same range. There is a 1-to-1 mapping between the two,
* so when linearly incrementing through the range, the output
* of this function won't repeat. In other words, encrypt the index variable.
* @param br
* The randomization parameters created with 'blackrock_init()'
* @param index
* An input within the specified range. We call it an 'index' variable
* because that's how we intend to use this function, shuffling a
* monotonically increasing index variable, but in truth, any sort
* of integer can be used. This must be within the 'range' specified
* during the call to blackrock_init(), or the results are undefined.
* @return
* A one-to-one matching index that's in the same range.
*/
uint64_t
blackrock_shuffle(const struct BlackRock *br, uint64_t index);
uint64_t
blackrock2_shuffle(const struct BlackRock *br, uint64_t index);
/**
* The reverse of the shuffle function above: given the shuffled/encrypted
* integer, return the original index value before the shuffling/encryption.
*/
uint64_t
blackrock_unshuffle(const struct BlackRock *br, uint64_t m);
uint64_t
blackrock2_unshuffle(const struct BlackRock *br, uint64_t m);
/**
* Do a regression test.
* @return
* 0 of the regression test succeeds or non-zero if it fails
*/
int
blackrock_selftest(void);
int
blackrock2_selftest(void);
/**
* Do a benchmark of this module regression test.
*/
void
blackrock_benchmark(unsigned rounds);
void
blackrock2_benchmark(unsigned rounds);
#endif

573
src/crypto-blackrock2.c Normal file
View File

@@ -0,0 +1,573 @@
#include "crypto-blackrock.h"
#include "pixie-timer.h"
#include "unusedparm.h"
#include "util-malloc.h"
#include "util-safefunc.h"
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <time.h>
#if defined(_MSC_VER)
#define inline _inline
#endif
/*
* Expanded DES S-boxes
*/
static const uint32_t SB1[64] =
{
0x01010400, 0x00000000, 0x00010000, 0x01010404,
0x01010004, 0x00010404, 0x00000004, 0x00010000,
0x00000400, 0x01010400, 0x01010404, 0x00000400,
0x01000404, 0x01010004, 0x01000000, 0x00000004,
0x00000404, 0x01000400, 0x01000400, 0x00010400,
0x00010400, 0x01010000, 0x01010000, 0x01000404,
0x00010004, 0x01000004, 0x01000004, 0x00010004,
0x00000000, 0x00000404, 0x00010404, 0x01000000,
0x00010000, 0x01010404, 0x00000004, 0x01010000,
0x01010400, 0x01000000, 0x01000000, 0x00000400,
0x01010004, 0x00010000, 0x00010400, 0x01000004,
0x00000400, 0x00000004, 0x01000404, 0x00010404,
0x01010404, 0x00010004, 0x01010000, 0x01000404,
0x01000004, 0x00000404, 0x00010404, 0x01010400,
0x00000404, 0x01000400, 0x01000400, 0x00000000,
0x00010004, 0x00010400, 0x00000000, 0x01010004
};
static const uint32_t SB2[64] =
{
0x80108020, 0x80008000, 0x00008000, 0x00108020,
0x00100000, 0x00000020, 0x80100020, 0x80008020,
0x80000020, 0x80108020, 0x80108000, 0x80000000,
0x80008000, 0x00100000, 0x00000020, 0x80100020,
0x00108000, 0x00100020, 0x80008020, 0x00000000,
0x80000000, 0x00008000, 0x00108020, 0x80100000,
0x00100020, 0x80000020, 0x00000000, 0x00108000,
0x00008020, 0x80108000, 0x80100000, 0x00008020,
0x00000000, 0x00108020, 0x80100020, 0x00100000,
0x80008020, 0x80100000, 0x80108000, 0x00008000,
0x80100000, 0x80008000, 0x00000020, 0x80108020,
0x00108020, 0x00000020, 0x00008000, 0x80000000,
0x00008020, 0x80108000, 0x00100000, 0x80000020,
0x00100020, 0x80008020, 0x80000020, 0x00100020,
0x00108000, 0x00000000, 0x80008000, 0x00008020,
0x80000000, 0x80100020, 0x80108020, 0x00108000
};
static const uint32_t SB3[64] =
{
0x00000208, 0x08020200, 0x00000000, 0x08020008,
0x08000200, 0x00000000, 0x00020208, 0x08000200,
0x00020008, 0x08000008, 0x08000008, 0x00020000,
0x08020208, 0x00020008, 0x08020000, 0x00000208,
0x08000000, 0x00000008, 0x08020200, 0x00000200,
0x00020200, 0x08020000, 0x08020008, 0x00020208,
0x08000208, 0x00020200, 0x00020000, 0x08000208,
0x00000008, 0x08020208, 0x00000200, 0x08000000,
0x08020200, 0x08000000, 0x00020008, 0x00000208,
0x00020000, 0x08020200, 0x08000200, 0x00000000,
0x00000200, 0x00020008, 0x08020208, 0x08000200,
0x08000008, 0x00000200, 0x00000000, 0x08020008,
0x08000208, 0x00020000, 0x08000000, 0x08020208,
0x00000008, 0x00020208, 0x00020200, 0x08000008,
0x08020000, 0x08000208, 0x00000208, 0x08020000,
0x00020208, 0x00000008, 0x08020008, 0x00020200
};
static const uint32_t SB4[64] =
{
0x00802001, 0x00002081, 0x00002081, 0x00000080,
0x00802080, 0x00800081, 0x00800001, 0x00002001,
0x00000000, 0x00802000, 0x00802000, 0x00802081,
0x00000081, 0x00000000, 0x00800080, 0x00800001,
0x00000001, 0x00002000, 0x00800000, 0x00802001,
0x00000080, 0x00800000, 0x00002001, 0x00002080,
0x00800081, 0x00000001, 0x00002080, 0x00800080,
0x00002000, 0x00802080, 0x00802081, 0x00000081,
0x00800080, 0x00800001, 0x00802000, 0x00802081,
0x00000081, 0x00000000, 0x00000000, 0x00802000,
0x00002080, 0x00800080, 0x00800081, 0x00000001,
0x00802001, 0x00002081, 0x00002081, 0x00000080,
0x00802081, 0x00000081, 0x00000001, 0x00002000,
0x00800001, 0x00002001, 0x00802080, 0x00800081,
0x00002001, 0x00002080, 0x00800000, 0x00802001,
0x00000080, 0x00800000, 0x00002000, 0x00802080
};
static const uint32_t SB5[64] =
{
0x00000100, 0x02080100, 0x02080000, 0x42000100,
0x00080000, 0x00000100, 0x40000000, 0x02080000,
0x40080100, 0x00080000, 0x02000100, 0x40080100,
0x42000100, 0x42080000, 0x00080100, 0x40000000,
0x02000000, 0x40080000, 0x40080000, 0x00000000,
0x40000100, 0x42080100, 0x42080100, 0x02000100,
0x42080000, 0x40000100, 0x00000000, 0x42000000,
0x02080100, 0x02000000, 0x42000000, 0x00080100,
0x00080000, 0x42000100, 0x00000100, 0x02000000,
0x40000000, 0x02080000, 0x42000100, 0x40080100,
0x02000100, 0x40000000, 0x42080000, 0x02080100,
0x40080100, 0x00000100, 0x02000000, 0x42080000,
0x42080100, 0x00080100, 0x42000000, 0x42080100,
0x02080000, 0x00000000, 0x40080000, 0x42000000,
0x00080100, 0x02000100, 0x40000100, 0x00080000,
0x00000000, 0x40080000, 0x02080100, 0x40000100
};
static const uint32_t SB6[64] =
{
0x20000010, 0x20400000, 0x00004000, 0x20404010,
0x20400000, 0x00000010, 0x20404010, 0x00400000,
0x20004000, 0x00404010, 0x00400000, 0x20000010,
0x00400010, 0x20004000, 0x20000000, 0x00004010,
0x00000000, 0x00400010, 0x20004010, 0x00004000,
0x00404000, 0x20004010, 0x00000010, 0x20400010,
0x20400010, 0x00000000, 0x00404010, 0x20404000,
0x00004010, 0x00404000, 0x20404000, 0x20000000,
0x20004000, 0x00000010, 0x20400010, 0x00404000,
0x20404010, 0x00400000, 0x00004010, 0x20000010,
0x00400000, 0x20004000, 0x20000000, 0x00004010,
0x20000010, 0x20404010, 0x00404000, 0x20400000,
0x00404010, 0x20404000, 0x00000000, 0x20400010,
0x00000010, 0x00004000, 0x20400000, 0x00404010,
0x00004000, 0x00400010, 0x20004010, 0x00000000,
0x20404000, 0x20000000, 0x00400010, 0x20004010
};
static const uint32_t SB7[64] =
{
0x00200000, 0x04200002, 0x04000802, 0x00000000,
0x00000800, 0x04000802, 0x00200802, 0x04200800,
0x04200802, 0x00200000, 0x00000000, 0x04000002,
0x00000002, 0x04000000, 0x04200002, 0x00000802,
0x04000800, 0x00200802, 0x00200002, 0x04000800,
0x04000002, 0x04200000, 0x04200800, 0x00200002,
0x04200000, 0x00000800, 0x00000802, 0x04200802,
0x00200800, 0x00000002, 0x04000000, 0x00200800,
0x04000000, 0x00200800, 0x00200000, 0x04000802,
0x04000802, 0x04200002, 0x04200002, 0x00000002,
0x00200002, 0x04000000, 0x04000800, 0x00200000,
0x04200800, 0x00000802, 0x00200802, 0x04200800,
0x00000802, 0x04000002, 0x04200802, 0x04200000,
0x00200800, 0x00000000, 0x00000002, 0x04200802,
0x00000000, 0x00200802, 0x04200000, 0x00000800,
0x04000002, 0x04000800, 0x00000800, 0x00200002
};
static const uint32_t SB8[64] =
{
0x10001040, 0x00001000, 0x00040000, 0x10041040,
0x10000000, 0x10001040, 0x00000040, 0x10000000,
0x00040040, 0x10040000, 0x10041040, 0x00041000,
0x10041000, 0x00041040, 0x00001000, 0x00000040,
0x10040000, 0x10000040, 0x10001000, 0x00001040,
0x00041000, 0x00040040, 0x10040040, 0x10041000,
0x00001040, 0x00000000, 0x00000000, 0x10040040,
0x10000040, 0x10001000, 0x00041040, 0x00040000,
0x00041040, 0x00040000, 0x10041000, 0x00001000,
0x00000040, 0x10040040, 0x00001000, 0x00041040,
0x10001000, 0x00000040, 0x10000040, 0x10040000,
0x10040040, 0x10000000, 0x00040000, 0x10001040,
0x00000000, 0x10041040, 0x00040040, 0x10000040,
0x10040000, 0x10001000, 0x10001040, 0x00000000,
0x10041040, 0x00041000, 0x00041000, 0x00001040,
0x00001040, 0x00040040, 0x10000000, 0x10041000
};
/***************************************************************************
* It's an s-box. You gotta have an s-box
***************************************************************************/
const unsigned char sbox2[] = {
0x91, 0x58, 0xb3, 0x31, 0x6c, 0x33, 0xda, 0x88,
0x57, 0xdd, 0x8c, 0xf2, 0x29, 0x5a, 0x08, 0x9f,
0x49, 0x34, 0xce, 0x99, 0x9e, 0xbf, 0x0f, 0x81,
0xd4, 0x2f, 0x92, 0x3f, 0x95, 0xf5, 0x23, 0x00,
0x0d, 0x3e, 0xa8, 0x90, 0x98, 0xdd, 0x20, 0x00,
0x03, 0x69, 0x0a, 0xca, 0xba, 0x12, 0x08, 0x41,
0x6e, 0xb9, 0x86, 0xe4, 0x50, 0xf0, 0x84, 0xe2,
0xb3, 0xb3, 0xc8, 0xb5, 0xb2, 0x2d, 0x18, 0x70,
0x0a, 0xd7, 0x92, 0x90, 0x9e, 0x1e, 0x0c, 0x1f,
0x08, 0xe8, 0x06, 0xfd, 0x85, 0x2f, 0xaa, 0x5d,
0xcf, 0xf9, 0xe3, 0x55, 0xb9, 0xfe, 0xa6, 0x7f,
0x44, 0x3b, 0x4a, 0x4f, 0xc9, 0x2f, 0xd2, 0xd3,
0x8e, 0xdc, 0xae, 0xba, 0x4f, 0x02, 0xb4, 0x76,
0xba, 0x64, 0x2d, 0x07, 0x9e, 0x08, 0xec, 0xbd,
0x52, 0x29, 0x07, 0xbb, 0x9f, 0xb5, 0x58, 0x6f,
0x07, 0x55, 0xb0, 0x34, 0x74, 0x9f, 0x05, 0xb2,
0xdf, 0xa9, 0xc6, 0x2a, 0xa3, 0x5d, 0xff, 0x10,
0x40, 0xb3, 0xb7, 0xb4, 0x63, 0x6e, 0xf4, 0x3e,
0xee, 0xf6, 0x49, 0x52, 0xe3, 0x11, 0xb3, 0xf1,
0xfb, 0x60, 0x48, 0xa1, 0xa4, 0x19, 0x7a, 0x2e,
0x90, 0x28, 0x90, 0x8d, 0x5e, 0x8c, 0x8c, 0xc4,
0xf2, 0x4a, 0xf6, 0xb2, 0x19, 0x83, 0xea, 0xed,
0x6d, 0xba, 0xfe, 0xd8, 0xb6, 0xa3, 0x5a, 0xb4,
0x48, 0xfa, 0xbe, 0x5c, 0x69, 0xac, 0x3c, 0x8f,
0x63, 0xaf, 0xa4, 0x42, 0x25, 0x50, 0xab, 0x65,
0x80, 0x65, 0xb9, 0xfb, 0xc7, 0xf2, 0x2d, 0x5c,
0xe3, 0x4c, 0xa4, 0xa6, 0x8e, 0x07, 0x9c, 0xeb,
0x41, 0x93, 0x65, 0x44, 0x4a, 0x86, 0xc1, 0xf6,
0x2c, 0x97, 0xfd, 0xf4, 0x6c, 0xdc, 0xe1, 0xe0,
0x28, 0xd9, 0x89, 0x7b, 0x09, 0xe2, 0xa0, 0x38,
0x74, 0x4a, 0xa6, 0x5e, 0xd2, 0xe2, 0x4d, 0xf3,
0xf4, 0xc6, 0xbc, 0xa2, 0x51, 0x58, 0xe8, 0xae,
0x91, 0x58, 0xb3, 0x31, 0x6c, 0x33, 0xda, 0x88,
};
/****************************************************************************
* Given a number, figure out the nearest power-of-two (16,32,64,128,etc.)
* that can hold that number. We do this so that we can convert multiplies
* into shifts.
****************************************************************************/
static uint64_t
next_power_of_two(uint64_t num)
{
uint64_t power_of_two = 1;
num++;
while ((uint64_t)(1ULL << power_of_two) < num)
power_of_two++;
return (1ULL << power_of_two);
}
static uint64_t
bit_count(uint64_t num)
{
uint64_t bits = 0;
while ((num >> bits) > 1)
bits++;
return bits;
}
/***************************************************************************
***************************************************************************/
void
blackrock2_init(struct BlackRock *br, uint64_t range, uint64_t seed, unsigned rounds)
{
uint64_t a;
uint64_t b;
a = next_power_of_two(
(uint64_t)sqrt(range * 1.0)
);
b = next_power_of_two(range/a);
//printf("a=%llu b=%llu seed = 0x%llu\n", a, b, seed);
br->range = range;
br->a = a;
br->a_bits = bit_count(br->a);
br->a_mask = br->a - 1ULL;
br->b = b;
br->b_bits = bit_count(br->b);
br->b_mask = br->b - 1ULL;
//printf("a: 0x%llx / %llu\n", br->a_mask, br->a_bits);
//printf("b: 0x%llx / %llu\n", br->b_mask, br->b_bits);
br->rounds = rounds;
br->seed = seed;
br->range = range;
}
/***************************************************************************
* The inner round/mixer function. In DES, it's a series of S-box lookups,
* which
***************************************************************************/
static inline uint64_t
ROUND(uint64_t r, uint64_t R, uint64_t seed)
{
#define GETBYTE(R,n) ((uint64_t)(((((R)>>(n*8ULL)))&0xFFULL)))
#if 0
uint64_t r0, r1, r2, r3;
#endif
uint64_t T, Y;
T = R ^ ((seed>>r) | (seed<<(64-r)));
if (r & 1) {
Y = SB8[ (T ) & 0x3F ] ^ \
SB6[ (T >> 8) & 0x3F ] ^ \
SB4[ (T >> 16) & 0x3F ] ^ \
SB2[ (T >> 24) & 0x3F ]; \
} else {
Y = SB7[ (T ) & 0x3F ] ^ \
SB5[ (T >> 8) & 0x3F ] ^ \
SB3[ (T >> 16) & 0x3F ] ^ \
SB1[ (T >> 24) & 0x3F ];
}
return Y;
#if 0
r0 = sbox2[GETBYTE(R,0)]<< 6 | sbox2[GETBYTE(R,1)]<< 0;
r1 = sbox2[GETBYTE(R,2)]<< 6 | sbox2[GETBYTE(R,5)]<< 0;
r2 = sbox2[GETBYTE(R,4)]<< 6 | sbox2[GETBYTE(R,5)]<< 0;
r3 = sbox2[GETBYTE(R,6)]<< 6 | sbox2[GETBYTE(R,7)]<< 0;
R = r0 ^ (r1<<12) * (r2 << 24) ^ (r3 << 36) * r;
return R;
/*return((uint64_t)sbox2[GETBYTE(R,7ULL)]<< 0ULL)
| ((uint64_t)sbox2[GETBYTE(R,6ULL)]<< 8ULL)
| ((uint64_t)sbox2[GETBYTE(R,5ULL)]<<16ULL)
| ((uint64_t)sbox2[GETBYTE(R,4ULL)]<<24ULL)
| ((uint64_t)sbox2[GETBYTE(R,3ULL)]<<32ULL)
| ((uint64_t)sbox2[GETBYTE(R,2ULL)]<<40ULL)
| ((uint64_t)sbox2[GETBYTE(R,1ULL)]<<48ULL)
| ((uint64_t)sbox2[GETBYTE(R,0ULL)]<<56ULL)
;*/
return R;
#endif
}
/***************************************************************************
***************************************************************************/
static inline uint64_t
ENCRYPT(unsigned r, uint64_t a_bits, uint64_t a_mask, uint64_t b_bits, uint64_t b_mask, uint64_t m, uint64_t seed)
{
uint64_t L, R;
unsigned j = 1;
uint64_t tmp;
UNUSEDPARM(b_bits);
L = m & a_mask;
R = m >> a_bits;
for (j=1; j<=r; j++) {
tmp = (L + ROUND(j, R, seed)) & a_mask;
L = R;
R = tmp;
j++;
tmp = (L + ROUND(j, R, seed)) & b_mask;
L = R;
R = tmp;
}
if ((j-1) & 1) {
return (L << (a_bits)) + R;
} else {
return (R << (a_bits)) + L;
}
}
static inline uint64_t
DECRYPT(unsigned r, uint64_t a, uint64_t b, uint64_t m, uint64_t seed)
{
uint64_t L, R;
unsigned j;
uint64_t tmp;
if (r & 1) {
R = m % a;
L = m / a;
} else {
L = m % a;
R = m / a;
}
for (j=r; j>=1; j--) {
if (j & 1) {
tmp = ROUND(j, L, seed);
if (tmp > R) {
tmp = (tmp - R);
tmp = a - (tmp%a);
if (tmp == a)
tmp = 0;
} else {
tmp = (R - tmp);
tmp %= a;
}
} else {
tmp = ROUND(j, L, seed);
if (tmp > R) {
tmp = (tmp - R);
tmp = b - (tmp%b);
if (tmp == b)
tmp = 0;
} else {
tmp = (R - tmp);
tmp %= b;
}
}
R = L;
L = tmp;
}
return a * R + L;
}
/***************************************************************************
***************************************************************************/
uint64_t
blackrock2_shuffle(const struct BlackRock *br, uint64_t m)
{
uint64_t c;
c = ENCRYPT(br->rounds, br->a_bits, br->a_mask, br->b_bits, br->b_mask, m, br->seed);
while (c >= br->range)
c = ENCRYPT(br->rounds, br->a_bits, br->a_mask, br->b_bits, br->b_mask, c, br->seed);
return c;
}
/***************************************************************************
***************************************************************************/
uint64_t
blackrock2_unshuffle(const struct BlackRock *br, uint64_t m)
{
uint64_t c;
c = DECRYPT(br->rounds, br->a, br->b, m, br->seed);
while (c >= br->range)
c = DECRYPT(br->rounds, br->a, br->b, c, br->seed);
return c;
}
/***************************************************************************
* This function called only during selftest/regression-test.
***************************************************************************/
static unsigned
verify(struct BlackRock *br, uint64_t max)
{
unsigned char *list;
uint64_t i;
unsigned is_success = 1;
uint64_t range = br->range;
/* Allocate a list of 1-byte counters */
list = CALLOC(1, (size_t)((range<max)?range:max));
/* For all numbers in the range, verify increment the counter for
* the output. */
for (i=0; i<range; i++) {
uint64_t x = blackrock2_shuffle(br, i);
if (x < max)
list[x]++;
}
/* Now check the output to make sure that every counter is set exactly
* to the value of '1'. */
for (i=0; i<max && i<range; i++) {
if (list[i] != 1)
is_success = 0;
}
free(list);
return is_success;
}
/***************************************************************************
* Benchmarks the crypto function.
***************************************************************************/
void
blackrock2_benchmark(unsigned rounds)
{
struct BlackRock br;
uint64_t range = 0x010356789123ULL;
uint64_t i;
uint64_t result = 0;
uint64_t start, stop;
static const uint64_t ITERATIONS = 5000000ULL;
printf("-- blackrock-2 -- \n");
printf("rounds = %u\n", rounds);
blackrock2_init(&br, range, 1, rounds);
/*printf("range = 0x%10" PRIx64 "\n", range);
printf("rangex= 0x%10" PRIx64 "\n", br.a*br.b);
printf(" a = 0x%10" PRIx64 "\n", br.a);
printf(" b = 0x%10" PRIx64 "\n", br.b);*/
/*
* Time the algorithm
*/
start = pixie_nanotime();
for (i=0; i<ITERATIONS; i++) {
result += blackrock2_shuffle(&br, i);
}
stop = pixie_nanotime();
/*
* Print the results
*/
if (result) {
double elapsed = ((double)(stop - start))/(1000000000.0);
double rate = ITERATIONS/elapsed;
rate /= 1000000.0;
printf("iterations/second = %5.3f-million\n", rate);
}
printf("\n");
}
/***************************************************************************
***************************************************************************/
int
blackrock2_selftest(void)
{
uint64_t i;
int is_success = 0;
uint64_t range;
/* @marshray
* Basic test of decryption. I take the index, encrypt it, then decrypt it,
* which means I should get the original index back again. Only, it's not
* working. The decryption fails. The reason it's failing is obvious -- I'm
* just not seeing it though. The error is probably in the 'unfe()'
* function above.
*/
{
struct BlackRock br;
uint64_t result, result2;
blackrock2_init(&br, 1000, 0, 6);
for (i=0; i<10; i++) {
result = blackrock2_shuffle(&br, i);
result2 = blackrock2_unshuffle(&br, result);
if (i != result2)
return 1; /*fail*/
}
}
range = 3015 * 3;
for (i=0; i<5; i++) {
struct BlackRock br;
range += 11 + i;
range *= 1 + i;
blackrock2_init(&br, range, time(0), 6);
is_success = verify(&br, range);
if (!is_success) {
fprintf(stderr, "BLACKROCK: randomization failed\n");
return 1; /*fail*/
}
}
return 0; /*success*/
}

390
src/crypto-lcg.c Normal file
View File

@@ -0,0 +1,390 @@
/*
This is a "linear-congruent-generator", a type of random number
generator.
*/
#include "crypto-lcg.h"
#include "crypto-primegen.h" /* DJB's prime factoring code */
#include "util-safefunc.h"
#include "util-malloc.h"
#include <math.h> /* for 'sqrt()', may need -lm for gcc */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/**
* A 64 bit number can't have more than 16 prime factors. The first factors
* are:
* 2*3*5*7*11*13*17*19*23*29*31*37*41*43*47*53 = 0xC443F2F861D29C3A
* 0123456789abcdef
* We zero termiante this list, so we are going to reserve 20 slots.
*/
typedef uint64_t PRIMEFACTORS[20];
/****************************************************************************
* Break down the number into prime factors using DJB's sieve code, which
* is about 5 to 10 times faster than the Sieve of Eratosthenes.
*
* @param number
* The integer that we are factoring. It can be any value up to 64 bits
* in size.
* @param factors
* The list of all the prime factors, zero terminated.
* @param non_factors
* A list of smallest numbers that aren't prime factors. We return
* this because we are going to use prime non-factors for finding
* interesting numbers.
****************************************************************************/
static unsigned
sieve_prime_factors(uint64_t number, PRIMEFACTORS factors,
PRIMEFACTORS non_factors, double *elapsed)
{
primegen pg;
clock_t start;
clock_t stop;
uint64_t prime;
uint64_t max;
unsigned factor_count = 0;
unsigned non_factor_count = 0;
/*
* We only need to sieve up to the square-root of the target number. Only
* one prime factor can be bigger than the square root, so once we find
* all the other primes, the square root is the only one left.
* Note: you have to link to the 'm' math library for some gcc platforms.
*/
max = (uint64_t)sqrt(number + 1.0);
/*
* Init the DJB primegen library.
*/
primegen_init(&pg);
/*
* Enumerate all the primes starting with 2
*/
start = clock();
for (;;) {
/* Sieve the next prime */
prime = primegen_next(&pg);
/* If we've reached the square root, then that's as far as we need
* to go */
if (prime > max)
break;
/* If this prime is not a factor (evenly divisible with no remainder)
* then loop back and get the next prime */
if ((number % prime) != 0) {
if (non_factor_count < 12)
non_factors[non_factor_count++] = prime;
continue;
}
/* Else we've found a prime factor, so add this to the list of primes */
factors[factor_count++] = prime;
/* At the end, we may have one prime factor left that's bigger than the
* sqrt. Therefore, as we go along, divide the original number
* (possibly several times) by the prime factor so that this large
* remaining factor will be the only one left */
while ((number % prime) == 0)
number /= prime;
/* exit early if we've found all prime factors. comment out this
* code if you want to benchmark it */
if (number == 1 && non_factor_count > 10)
break;
}
/*
* See if there is one last prime that's bigger than the square root.
* Note: This is the only number that can be larger than 32-bits in the
* way this code is written.
*/
if (number != 1)
factors[factor_count++] = number;
/*
* Zero terminate the results.
*/
factors[factor_count] = 0;
non_factors[non_factor_count] = 0;
/*
* Since prime factorization takes a long time, especially on slow
* CPUs, we benchmark it to keep track of performance.
*/
stop = clock();
if (elapsed)
*elapsed = ((double)stop - (double)start)/(double)CLOCKS_PER_SEC;
/* should always be at least 1, because if the number itself is prime,
* then that's it's only prime factor */
return factor_count;
}
/****************************************************************************
* Do a pseudo-random 1-to-1 translation of a number within a range to
* another number in that range.
*
* The constants 'a' and 'c' must be chosen to match the LCG algorithm
* to fit 'm' (range).
*
* This the same as the function 'rand()', except all the constants and
* seeds are specified as parameters.
*
* @param index
* The index within the range that we are randomizing.
* @param a
* The 'multiplier' of the LCG algorithm.
* @param c
* The 'increment' of the LCG algorithm.
* @param range
* The 'modulus' of the LCG algorithm.
****************************************************************************/
uint64_t
lcg_rand(uint64_t index, uint64_t a, uint64_t c, uint64_t range)
{
return (index * a + c) % range;
}
/****************************************************************************
* Verify the LCG algorithm. You shouldn't do this for large ranges,
* because we'll run out of memory. Therefore, this algorithm allocates
* a buffer only up to a smaller range. We still have to traverse the
* entire range of numbers, but we only need store values for a smaller
* range. If 10% of the range checks out, then there's a good chance
* it applies to the other 90% as well.
*
* This works by counting the results of rand(), which should be produced
* exactly once.
****************************************************************************/
static unsigned
lcg_verify(uint64_t a, uint64_t c, uint64_t range, uint64_t max)
{
unsigned char *list;
uint64_t i;
unsigned is_success = 1;
/* Allocate a list of 1-byte counters */
list = CALLOC(1, (size_t)((range<max)?range:max));
/* For all numbers in the range, verify increment the counter for the
* the output. */
for (i=0; i<range; i++) {
uint64_t x = lcg_rand(i, a, c, range);
if (x < max)
list[x]++;
}
/* Now check the output to make sure that every counter is set exactly
* to the value of '1'. */
for (i=0; i<max && i<range; i++) {
if (list[i] != 1)
is_success = 0;
}
free(list);
return is_success;
}
/****************************************************************************
* Count the number of digits in a number so that we can pretty-print a
* bunch of numbers in nice columns.
****************************************************************************/
static unsigned
count_digits(uint64_t num)
{
unsigned result = 0;
while (num) {
result++;
num /= 10;
}
return result;
}
/****************************************************************************
* Tell whether the number has any prime factors in common with the list
* of factors. In other words, if it's not coprime with the other number.
* @param c
* The number we want to see has common factors with the other number.
* @param factors
* The factors from the other number
* @return
* !is_coprime(c, factors)
****************************************************************************/
static uint64_t
has_factors_in_common(uint64_t c, PRIMEFACTORS factors)
{
unsigned i;
for (i=0; factors[i]; i++) {
if ((c % factors[i]) == 0)
return factors[i]; /* found a common factor */
}
return 0; /* no factors in common */
}
/****************************************************************************
* Given a range, calculate some possible constants for the LCG algorithm
* for randomizing the order of the array.
* @parm m
* The range for which we'll be finding random numbers. If we are
* looking for random numbers between [0..100), this number will
* be 100.
* @parm a
* The LCG 'a' constant that will be the result of this function.
* @param c
* The LCG 'c' constant that will be the result of this function. This
* should be set to 0 on the input to this function, or a suggested
* value.
****************************************************************************/
void
lcg_calculate_constants(uint64_t m, uint64_t *out_a, uint64_t *inout_c, int is_debug)
{
uint64_t a;
uint64_t c = *inout_c;
double elapsed = 0.0; /* Benchmark of 'sieve' algorithm */
PRIMEFACTORS factors; /* List of prime factors of 'm' */
PRIMEFACTORS non_factors;
unsigned i;
/*
* Find all the prime factors of the number. This step can take several
* seconds for 48 bit numbers, which is why we benchmark how long it
* takes.
*/
sieve_prime_factors(m, factors, non_factors, &elapsed);
/*
* Calculate the 'a-1' constant. It must share all the prime factors
* with the range, and if the range is a multiple of 4, must also
* be a multiple of 4
*/
if (factors[0] == m) {
/* this number has no prime factors, so we can choose anything.
* Therefore, we are going to pick something at random */
unsigned j;
a = 1;
for (j=0; non_factors[j] && j < 5; j++)
a *= non_factors[j];
} else {
//unsigned j;
a = 1;
for (i=0; factors[i]; i++)
a = a * factors[i];
if ((m % 4) == 0)
a *= 2;
/*for (j=0; j<0 && non_factors[j]; j++)
a *= non_factors[j];*/
}
a += 1;
/*
* Calculate the 'c' constant. It must have no prime factors in
* common with the range.
*/
if (c == 0)
c = 2531011 ; /* something random */
while (has_factors_in_common(c, factors))
c++;
if (is_debug) {
/*
* print the results
*/
//printf("sizeof(int) = %" PRIu64 "-bits\n", (uint64_t)(sizeof(size_t)*8));
printf("elapsed = %5.3f-seconds\n", elapsed);
printf("factors = ");
for (i=0; factors[i]; i++)
printf("%" PRIu64 " ", factors[i]);
printf("%s\n", factors[0]?"":"(none)");
printf("m = %-24" PRIu64 " (0x%" PRIx64 ")\n", m, m);
printf("a = %-24" PRIu64 " (0x%" PRIx64 ")\n", a, a);
printf("c = %-24" PRIu64 " (0x%" PRIx64 ")\n", c, c);
printf("c%%m = %-24" PRIu64 " (0x%" PRIx64 ")\n", c%m, c%m);
printf("a%%m = %-24" PRIu64 " (0x%" PRIx64 ")\n", a%m, a%m);
if (m < 1000000000) {
if (lcg_verify(a, c+1, m, 280))
printf("verify = success\n");
else
printf("verify = failure\n");
} else {
printf("verify = too big to check\n");
}
/*
* Print some first numbers. We use these to visually inspect whether
* the results are random or not.
*/
{
unsigned count = 0;
uint64_t x = 0;
unsigned digits = count_digits(m);
for (i=0; i<100 && i < m; i++) {
x = lcg_rand(x, a, c, m);
count += printf("%*" PRIu64 " ", digits, x);
if (count >= 70) {
count = 0;
printf("\n");
}
}
printf("\n");
}
}
*out_a = a;
*inout_c = c;
}
/***************************************************************************
***************************************************************************/
int
lcg_selftest(void)
{
unsigned i;
int is_success = 0;
uint64_t m, a, c;
m = 3015 * 3;
for (i=0; i<5; i++) {
a = 0;
c = 0;
m += 10 + i;
lcg_calculate_constants(m, &a, &c, 0);
is_success = lcg_verify(a, c, m, m);
if (!is_success) {
fprintf(stderr, "LCG: randomization failed\n");
return 1; /*fail*/
}
}
return 0; /*success*/
}

20
src/crypto-lcg.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef RAND_LCG_H
#define RAND_LCG_H
#include <stdint.h>
void
lcg_calculate_constants(uint64_t m, uint64_t *out_a, uint64_t *inout_c, int is_debug);
uint64_t
lcg_rand(uint64_t index, uint64_t a, uint64_t c, uint64_t range);
/**
* Performs a regression test on this module.
* @return
* 0 on success, or a positive integer on failure
*/
int
lcg_selftest(void);
#endif

716
src/crypto-primegen.c Normal file
View File

@@ -0,0 +1,716 @@
/*
This is DJB's code for calculating primes, with a few modifications,
such as making it work with Microsoft's compiler on Windows, and
getting rid of warnings.
*/
#include "crypto-primegen.h"
/*
B is 32 times X.
Total memory use for one generator is 2B bytes = 64X bytes.
Covers primes in an interval of length 1920X.
Working set size for one generator is B bits = 4X bytes.
Speedup by a factor of 2 or 3 for L1 cache instead of L2 cache.
Slowdown by a factor of roughly n for primes past (nB)^2.
Possible choices of X:
2002 to fit inside an 8K L1 cache (e.g., Pentium).
4004 to fit inside a 16K L1 cache (e.g., Pentium II).
64064 to fit inside a 256K L2 cache.
There are various word-size limits on X; 1000000 should still be okay.
*/
#define B32 PRIMEGEN_WORDS
#define B (PRIMEGEN_WORDS * 32)
#ifdef _MSC_VER
#pragma warning(disable:4244)
#endif
static const uint32_t two[32] = {
0x00000001 , 0x00000002 , 0x00000004 , 0x00000008
, 0x00000010 , 0x00000020 , 0x00000040 , 0x00000080
, 0x00000100 , 0x00000200 , 0x00000400 , 0x00000800
, 0x00001000 , 0x00002000 , 0x00004000 , 0x00008000
, 0x00010000 , 0x00020000 , 0x00040000 , 0x00080000
, 0x00100000 , 0x00200000 , 0x00400000 , 0x00800000
, 0x01000000 , 0x02000000 , 0x04000000 , 0x08000000
, 0x10000000 , 0x20000000 , 0x40000000 , 0x80000000
} ;
static void clear(register uint32_t (*buf)[B32])
{
register int i;
register int j;
for (j = 0;j < 16;++j) {
for (i = 0;i < B32;++i)
(*buf)[i] = (uint32_t)~0;
++buf;
}
}
static void doit4(register uint32_t *a,register long x,register long y,int64_t start)
{
long i0;
long y0;
register long i;
register uint32_t data;
register uint32_t pos;
register uint32_t bits;
x += x; x += 15;
y += 15;
start += 1000000000;
while (start < 0) { start += x; x += 30; }
start -= 1000000000;
i = start;
while (i < B) { i += x; x += 30; }
for (;;) {
x -= 30;
if (x <= 15) return;
i -= x;
while (i < 0) { i += y; y += 30; }
i0 = i; y0 = y;
while (i < B) {
pos = (uint32_t)i; data = (uint32_t)i;
pos >>= 5; data &= 31;
i += y; y += 30;
bits = a[pos]; data = two[data];
bits ^= data;
a[pos] = bits;
}
i = i0; y = y0;
}
}
static void doit6(register uint32_t *a,register long x,register long y,int64_t start)
{
long i0;
long y0;
register long i;
register uint32_t data;
register uint32_t pos;
register uint32_t bits;
x += 5;
y += 15;
start += 1000000000;
while (start < 0) { start += x; x += 10; }
start -= 1000000000;
i = start;
while (i < B) { i += x; x += 10; }
for (;;) {
x -= 10;
if (x <= 5) return;
i -= x;
while (i < 0) { i += y; y += 30; }
i0 = i; y0 = y;
while (i < B) {
pos = (uint32_t)i; data = (uint32_t)i;
pos >>= 5; data &= 31;
i += y; y += 30;
bits = a[pos]; data = two[data];
bits ^= data;
a[pos] = bits;
}
i = i0; y = y0;
}
}
static void doit12(register uint32_t *a,register long x,register long y,int64_t start)
{
register long i;
register uint32_t data;
register uint32_t bits;
x += 5;
start += 1000000000;
while (start < 0) { start += x; x += 10; }
start -= 1000000000;
i = start;
while (i < 0) { i += x; x += 10; }
y += 15;
x += 10;
for (;;) {
long i0;
long y0;
while (i >= B) {
if (x <= y) return;
i -= y;
y += 30;
}
i0 = i;
y0 = y;
while ((i >= 0) && (y < x)) {
register uint32_t pos;
pos = (uint32_t)i; data = (uint32_t)i;
pos >>= 5; data &= 31;
i -= y;
y += 30;
bits = a[pos]; data = two[data];
bits ^= data;
a[pos] = bits;
}
i = i0;
y = y0;
i += x - 10;
x += 10;
}
}
static const int deltainverse[60] = {
-1,B32 * 0,-1,-1,-1,-1,-1,B32 * 1,-1,-1,-1,B32 * 2,-1,B32 * 3,-1
,-1,-1,B32 * 4,-1,B32 * 5,-1,-1,-1,B32 * 6,-1,-1,-1,-1,-1,B32 * 7
,-1,B32 * 8,-1,-1,-1,-1,-1,B32 * 9,-1,-1,-1,B32 * 10,-1,B32 * 11,-1
,-1,-1,B32 * 12,-1,B32 * 13,-1,-1,-1,B32 * 14,-1,-1,-1,-1,-1,B32 * 15
} ;
static void squarefree1big(uint32_t (*buf)[B32],uint64_t base,uint32_t q,uint64_t qq)
{
uint64_t i;
uint32_t pos;
int n;
uint64_t bound = base + 60 * B;
while (qq < bound) {
if (bound < 2000000000)
i = qq - (((uint32_t) base) % ((uint32_t) qq));
else
i = qq - (base % qq);
if (!(i & 1)) i += qq;
if (i < B * 60) {
pos = (uint32_t)i;
n = deltainverse[pos % 60];
if (n >= 0) {
pos /= 60;
(*buf)[n + (pos >> 5)] |= two[pos & 31];
}
}
qq += q; q += 1800;
}
}
static void squarefree1(register uint32_t (*buf)[B32],uint64_t L,uint32_t q)
{
uint32_t qq;
register uint32_t qqhigh;
uint32_t i;
register uint32_t ilow;
register uint32_t ihigh;
register int n;
uint64_t base;
base = 60 * L;
qq = q * q;
q = 60 * q + 900;
while (qq < B * 60) {
if (base < 2000000000)
i = qq - (((uint32_t) base) % qq);
else
i = qq - (base % qq);
if (!(i & 1)) i += qq;
if (i < B * 60) {
qqhigh = qq / 60;
ilow = i % 60; ihigh = i / 60;
qqhigh += qqhigh;
while (ihigh < B) {
n = deltainverse[ilow];
if (n >= 0)
(*buf)[n + (ihigh >> 5)] |= two[ihigh & 31];
ilow += 2; ihigh += qqhigh;
if (ilow >= 60) { ilow -= 60; ihigh += 1; }
}
}
qq += q; q += 1800;
}
squarefree1big(buf,base,q,qq);
}
static void squarefree49big(uint32_t (*buf)[B32],uint64_t base,uint32_t q,uint64_t qq)
{
uint64_t i;
uint32_t pos;
int n;
uint64_t bound = base + 60 * B;
while (qq < bound) {
if (bound < 2000000000)
i = qq - (((uint32_t) base) % ((uint32_t) qq));
else
i = qq - (base % qq);
if (!(i & 1)) i += qq;
if (i < B * 60) {
pos = (uint32_t)i;
n = deltainverse[pos % 60];
if (n >= 0) {
pos /= 60;
(*buf)[n + (pos >> 5)] |= two[pos & 31];
}
}
qq += q; q += 1800;
}
}
static void squarefree49(register uint32_t (*buf)[B32],uint64_t L,uint32_t q)
{
uint32_t qq;
register uint32_t qqhigh;
uint32_t i;
register uint32_t ilow;
register uint32_t ihigh;
register int n;
uint64_t base = 60 * L;
qq = q * q;
q = 60 * q + 900;
while (qq < B * 60) {
if (base < 2000000000)
i = qq - (((uint32_t) base) % qq);
else
i = qq - (base % qq);
if (!(i & 1)) i += qq;
if (i < B * 60) {
qqhigh = qq / 60;
ilow = i % 60; ihigh = i / 60;
qqhigh += qqhigh;
qqhigh += 1;
while (ihigh < B) {
n = deltainverse[ilow];
if (n >= 0)
(*buf)[n + (ihigh >> 5)] |= two[ihigh & 31];
ilow += 38; ihigh += qqhigh;
if (ilow >= 60) { ilow -= 60; ihigh += 1; }
}
}
qq += q; q += 1800;
}
squarefree49big(buf,base,q,qq);
}
/* squares of primes >= 7, < 240 */
uint32_t qqtab[49] = {
49,121,169,289,361,529,841,961,1369,1681
,1849,2209,2809,3481,3721,4489,5041,5329,6241,6889
,7921,9409,10201,10609,11449,11881,12769,16129,17161,18769
,19321,22201,22801,24649,26569,27889,29929,32041,32761,36481
,37249,38809,39601,44521,49729,51529,52441,54289,57121
} ;
/* (qq * 11 + 1) / 60 or (qq * 59 + 1) / 60 */
uint32_t qq60tab[49] = {
9,119,31,53,355,97,827,945,251,1653
,339,405,515,3423,3659,823,4957,977,6137
,1263,7789,1725,10031,1945,2099,11683,2341,2957
,16875,3441,18999,21831,22421,4519,4871,5113,5487
,31507,32215,35873,6829,7115,38941,43779,9117,9447,51567,9953,56169
} ;
static void squarefreetiny(register uint32_t *a,uint32_t *Lmodqq,int d)
{
int j;
for (j = 0;j < 49;++j) {
register uint32_t k;
register uint32_t qq;
qq = qqtab[j];
k = qq - 1 - ((Lmodqq[j] + qq60tab[j] * d - 1) % qq);
while (k < B) {
register uint32_t pos;
register uint32_t data;
register uint32_t bits;
pos = k;
data = k;
pos >>= 5;
data &= 31;
k += qq;
bits = a[pos];
data = two[data];
bits |= data;
a[pos] = bits;
}
}
}
typedef struct { char index; char f; char g; char k; } todo;
static const todo for4[] = {
{0,2,15,4} , {0,3,5,1} , {0,3,25,11} , {0,5,9,3}
, {0,5,21,9} , {0,7,15,7} , {0,8,15,8} , {0,10,9,8}
, {0,10,21,14} , {0,12,5,10} , {0,12,25,20} , {0,13,15,15}
, {0,15,1,15} , {0,15,11,17} , {0,15,19,21} , {0,15,29,29}
, {3,1,3,0} , {3,1,27,12} , {3,4,3,1} , {3,4,27,13}
, {3,6,7,3} , {3,6,13,5} , {3,6,17,7} , {3,6,23,11}
, {3,9,7,6} , {3,9,13,8} , {3,9,17,10} , {3,9,23,14}
, {3,11,3,8} , {3,11,27,20} , {3,14,3,13} , {3,14,27,25}
, {4,2,1,0} , {4,2,11,2} , {4,2,19,6} , {4,2,29,14}
, {4,7,1,3} , {4,7,11,5} , {4,7,19,9} , {4,7,29,17}
, {4,8,1,4} , {4,8,11,6} , {4,8,19,10} , {4,8,29,18}
, {4,13,1,11} , {4,13,11,13} , {4,13,19,17} , {4,13,29,25}
, {7,1,5,0} , {7,1,25,10} , {7,4,5,1} , {7,4,25,11}
, {7,5,7,2} , {7,5,13,4} , {7,5,17,6} , {7,5,23,10}
, {7,10,7,7} , {7,10,13,9} , {7,10,17,11} , {7,10,23,15}
, {7,11,5,8} , {7,11,25,18} , {7,14,5,13} , {7,14,25,23}
, {9,2,9,1} , {9,2,21,7} , {9,3,1,0} , {9,3,11,2}
, {9,3,19,6} , {9,3,29,14} , {9,7,9,4} , {9,7,21,10}
, {9,8,9,5} , {9,8,21,11} , {9,12,1,9} , {9,12,11,11}
, {9,12,19,15} , {9,12,29,23} , {9,13,9,12} , {9,13,21,18}
, {10,2,5,0} , {10,2,25,10} , {10,5,1,1} , {10,5,11,3}
, {10,5,19,7} , {10,5,29,15} , {10,7,5,3} , {10,7,25,13}
, {10,8,5,4} , {10,8,25,14} , {10,10,1,6} , {10,10,11,8}
, {10,10,19,12} , {10,10,29,20} , {10,13,5,11} , {10,13,25,21}
, {13,1,15,3} , {13,4,15,4} , {13,5,3,1} , {13,5,27,13}
, {13,6,5,2} , {13,6,25,12} , {13,9,5,5} , {13,9,25,15}
, {13,10,3,6} , {13,10,27,18} , {13,11,15,11} , {13,14,15,16}
, {13,15,7,15} , {13,15,13,17} , {13,15,17,19} , {13,15,23,23}
, {14,1,7,0} , {14,1,13,2} , {14,1,17,4} , {14,1,23,8}
, {14,4,7,1} , {14,4,13,3} , {14,4,17,5} , {14,4,23,9}
, {14,11,7,8} , {14,11,13,10} , {14,11,17,12} , {14,11,23,16}
, {14,14,7,13} , {14,14,13,15} , {14,14,17,17} , {14,14,23,21}
} ;
static const todo for6[] = {
{1,1,2,0} , {1,1,8,1} , {1,1,22,8} , {1,1,28,13}
, {1,3,10,2} , {1,3,20,7} , {1,7,10,4} , {1,7,20,9}
, {1,9,2,4} , {1,9,8,5} , {1,9,22,12} , {1,9,28,17}
, {5,1,4,0} , {5,1,14,3} , {5,1,16,4} , {5,1,26,11}
, {5,5,2,1} , {5,5,8,2} , {5,5,22,9} , {5,5,28,14}
, {5,9,4,4} , {5,9,14,7} , {5,9,16,8} , {5,9,26,15}
, {8,3,2,0} , {8,3,8,1} , {8,3,22,8} , {8,3,28,13}
, {8,5,4,1} , {8,5,14,4} , {8,5,16,5} , {8,5,26,12}
, {8,7,2,2} , {8,7,8,3} , {8,7,22,10} , {8,7,28,15}
, {11,1,10,1} , {11,1,20,6} , {11,3,4,0} , {11,3,14,3}
, {11,3,16,4} , {11,3,26,11} , {11,7,4,2} , {11,7,14,5}
, {11,7,16,6} , {11,7,26,13} , {11,9,10,5} , {11,9,20,10}
} ;
static const todo for12[] = {
{2,2,1,0} , {2,2,11,-2} , {2,2,19,-6} , {2,2,29,-14}
, {2,3,4,0} , {2,3,14,-3} , {2,3,16,-4} , {2,3,26,-11}
, {2,5,2,1} , {2,5,8,0} , {2,5,22,-7} , {2,5,28,-12}
, {2,7,4,2} , {2,7,14,-1} , {2,7,16,-2} , {2,7,26,-9}
, {2,8,1,3} , {2,8,11,1} , {2,8,19,-3} , {2,8,29,-11}
, {2,10,7,4} , {2,10,13,2} , {2,10,17,0} , {2,10,23,-4}
, {6,1,10,-2} , {6,1,20,-7} , {6,2,7,-1} , {6,2,13,-3}
, {6,2,17,-5} , {6,2,23,-9} , {6,3,2,0} , {6,3,8,-1}
, {6,3,22,-8} , {6,3,28,-13} , {6,4,5,0} , {6,4,25,-10}
, {6,6,5,1} , {6,6,25,-9} , {6,7,2,2} , {6,7,8,1}
, {6,7,22,-6} , {6,7,28,-11} , {6,8,7,2} , {6,8,13,0}
, {6,8,17,-2} , {6,8,23,-6} , {6,9,10,2} , {6,9,20,-3}
, {12,1,4,-1} , {12,1,14,-4} , {12,1,16,-5} , {12,1,26,-12}
, {12,2,5,-1} , {12,2,25,-11} , {12,3,10,-2} , {12,3,20,-7}
, {12,4,1,0} , {12,4,11,-2} , {12,4,19,-6} , {12,4,29,-14}
, {12,6,1,1} , {12,6,11,-1} , {12,6,19,-5} , {12,6,29,-13}
, {12,7,10,0} , {12,7,20,-5} , {12,8,5,2} , {12,8,25,-8}
, {12,9,4,3} , {12,9,14,0} , {12,9,16,-1} , {12,9,26,-8}
, {15,1,2,-1} , {15,1,8,-2} , {15,1,22,-9} , {15,1,28,-14}
, {15,4,7,-1} , {15,4,13,-3} , {15,4,17,-5} , {15,4,23,-9}
, {15,5,4,0} , {15,5,14,-3} , {15,5,16,-4} , {15,5,26,-11}
, {15,6,7,0} , {15,6,13,-2} , {15,6,17,-4} , {15,6,23,-8}
, {15,9,2,3} , {15,9,8,2} , {15,9,22,-5} , {15,9,28,-10}
, {15,10,1,4} , {15,10,11,2} , {15,10,19,-2} , {15,10,29,-10}
} ;
void primegen_sieve(primegen *pg)
{
uint32_t (*buf)[B32];
uint64_t L;
int i;
uint32_t Lmodqq[49];
buf = pg->buf;
L = pg->L;
if (L > 2000000000)
for (i = 0;i < 49;++i)
Lmodqq[i] = L % qqtab[i];
else
for (i = 0;i < 49;++i)
Lmodqq[i] = ((uint32_t) L) % qqtab[i];
clear(buf);
for (i = 0;i < 16;++i)
doit4(buf[0],for4[i].f,for4[i].g,(int64_t) for4[i].k - L);
squarefreetiny(buf[0],Lmodqq,1);
for (;i < 32;++i)
doit4(buf[3],for4[i].f,for4[i].g,(int64_t) for4[i].k - L);
squarefreetiny(buf[3],Lmodqq,13);
for (;i < 48;++i)
doit4(buf[4],for4[i].f,for4[i].g,(int64_t) for4[i].k - L);
squarefreetiny(buf[4],Lmodqq,17);
for (;i < 64;++i)
doit4(buf[7],for4[i].f,for4[i].g,(int64_t) for4[i].k - L);
squarefreetiny(buf[7],Lmodqq,29);
for (;i < 80;++i)
doit4(buf[9],for4[i].f,for4[i].g,(int64_t) for4[i].k - L);
squarefreetiny(buf[9],Lmodqq,37);
for (;i < 96;++i)
doit4(buf[10],for4[i].f,for4[i].g,(int64_t) for4[i].k - L);
squarefreetiny(buf[10],Lmodqq,41);
for (;i < 112;++i)
doit4(buf[13],for4[i].f,for4[i].g,(int64_t) for4[i].k - L);
squarefreetiny(buf[13],Lmodqq,49);
for (;i < 128;++i)
doit4(buf[14],for4[i].f,for4[i].g,(int64_t) for4[i].k - L);
squarefreetiny(buf[14],Lmodqq,53);
for (i = 0;i < 12;++i)
doit6(buf[1],for6[i].f,for6[i].g,(int64_t) for6[i].k - L);
squarefreetiny(buf[1],Lmodqq,7);
for (;i < 24;++i)
doit6(buf[5],for6[i].f,for6[i].g,(int64_t) for6[i].k - L);
squarefreetiny(buf[5],Lmodqq,19);
for (;i < 36;++i)
doit6(buf[8],for6[i].f,for6[i].g,(int64_t) for6[i].k - L);
squarefreetiny(buf[8],Lmodqq,31);
for (;i < 48;++i)
doit6(buf[11],for6[i].f,for6[i].g,(int64_t) for6[i].k - L);
squarefreetiny(buf[11],Lmodqq,43);
for (i = 0;i < 24;++i)
doit12(buf[2],for12[i].f,for12[i].g,(int64_t) for12[i].k - L);
squarefreetiny(buf[2],Lmodqq,11);
for (;i < 48;++i)
doit12(buf[6],for12[i].f,for12[i].g,(int64_t) for12[i].k - L);
squarefreetiny(buf[6],Lmodqq,23);
for (;i < 72;++i)
doit12(buf[12],for12[i].f,for12[i].g,(int64_t) for12[i].k - L);
squarefreetiny(buf[12],Lmodqq,47);
for (;i < 96;++i)
doit12(buf[15],for12[i].f,for12[i].g,(int64_t) for12[i].k - L);
squarefreetiny(buf[15],Lmodqq,59);
squarefree49(buf,L,247);
squarefree49(buf,L,253);
squarefree49(buf,L,257);
squarefree49(buf,L,263);
squarefree1(buf,L,241);
squarefree1(buf,L,251);
squarefree1(buf,L,259);
squarefree1(buf,L,269);
}
void primegen_fill(primegen *pg)
{
int i;
uint32_t mask;
uint32_t bits0, bits1, bits2, bits3, bits4, bits5, bits6, bits7;
uint32_t bits8, bits9, bits10, bits11, bits12, bits13, bits14, bits15;
uint64_t base;
i = pg->pos;
if (i == B32) {
primegen_sieve(pg);
pg->L += B;
i = 0;
}
pg->pos = i + 1;
bits0 = ~pg->buf[0][i];
bits1 = ~pg->buf[1][i];
bits2 = ~pg->buf[2][i];
bits3 = ~pg->buf[3][i];
bits4 = ~pg->buf[4][i];
bits5 = ~pg->buf[5][i];
bits6 = ~pg->buf[6][i];
bits7 = ~pg->buf[7][i];
bits8 = ~pg->buf[8][i];
bits9 = ~pg->buf[9][i];
bits10 = ~pg->buf[10][i];
bits11 = ~pg->buf[11][i];
bits12 = ~pg->buf[12][i];
bits13 = ~pg->buf[13][i];
bits14 = ~pg->buf[14][i];
bits15 = ~pg->buf[15][i];
base = pg->base + 1920;
pg->base = base;
pg->num = 0;
for (mask = 0x80000000;mask;mask >>= 1) {
base -= 60;
if (bits15 & mask) pg->p[pg->num++] = base + 59;
if (bits14 & mask) pg->p[pg->num++] = base + 53;
if (bits13 & mask) pg->p[pg->num++] = base + 49;
if (bits12 & mask) pg->p[pg->num++] = base + 47;
if (bits11 & mask) pg->p[pg->num++] = base + 43;
if (bits10 & mask) pg->p[pg->num++] = base + 41;
if (bits9 & mask) pg->p[pg->num++] = base + 37;
if (bits8 & mask) pg->p[pg->num++] = base + 31;
if (bits7 & mask) pg->p[pg->num++] = base + 29;
if (bits6 & mask) pg->p[pg->num++] = base + 23;
if (bits5 & mask) pg->p[pg->num++] = base + 19;
if (bits4 & mask) pg->p[pg->num++] = base + 17;
if (bits3 & mask) pg->p[pg->num++] = base + 13;
if (bits2 & mask) pg->p[pg->num++] = base + 11;
if (bits1 & mask) pg->p[pg->num++] = base + 7;
if (bits0 & mask) pg->p[pg->num++] = base + 1;
}
}
uint64_t primegen_next(primegen *pg)
{
while (!pg->num)
primegen_fill(pg);
return pg->p[--pg->num];
}
uint64_t primegen_peek(primegen *pg)
{
while (!pg->num)
primegen_fill(pg);
return pg->p[pg->num - 1];
}
void primegen_init(primegen *pg)
{
pg->L = 1;
pg->base = 60;
pg->pos = PRIMEGEN_WORDS;
pg->p[0] = 59;
pg->p[1] = 53;
pg->p[2] = 47;
pg->p[3] = 43;
pg->p[4] = 41;
pg->p[5] = 37;
pg->p[6] = 31;
pg->p[7] = 29;
pg->p[8] = 23;
pg->p[9] = 19;
pg->p[10] = 17;
pg->p[11] = 13;
pg->p[12] = 11;
pg->p[13] = 7;
pg->p[14] = 5;
pg->p[15] = 3;
pg->p[16] = 2;
pg->num = 17;
}
static const unsigned long pop[256] = {
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5
,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6
,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6
,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7
,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6
,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7
,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7
,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
};
uint64_t primegen_count(primegen *pg,uint64_t to)
{
uint64_t count = 0;
for (;;) {
register int pos;
register int j;
register uint32_t bits;
register uint32_t smallcount;
while (pg->num) {
if (pg->p[pg->num - 1] >= to) return count;
++count;
--pg->num;
}
smallcount = 0;
pos = pg->pos;
while ((pos < B32) && (pg->base + 1920 < to)) {
for (j = 0;j < 16;++j) {
bits = ~pg->buf[j][pos];
smallcount += pop[bits & 255]; bits >>= 8;
smallcount += pop[bits & 255]; bits >>= 8;
smallcount += pop[bits & 255]; bits >>= 8;
smallcount += pop[bits & 255];
}
pg->base += 1920;
++pos;
}
pg->pos = pos;
count += smallcount;
if (pos == B32)
while (pg->base + B * 60 < to) {
primegen_sieve(pg);
pg->L += B;
smallcount = 0;
for (j = 0;j < 16;++j)
for (pos = 0;pos < B32;++pos) {
bits = ~pg->buf[j][pos];
smallcount += pop[bits & 255]; bits >>= 8;
smallcount += pop[bits & 255]; bits >>= 8;
smallcount += pop[bits & 255]; bits >>= 8;
smallcount += pop[bits & 255];
}
count += smallcount;
pg->base += B * 60;
}
primegen_fill(pg);
}
}
void primegen_skipto(primegen *pg,uint64_t to)
{
for (;;) {
int pos;
while (pg->num) {
if (pg->p[pg->num - 1] >= to) return;
--pg->num;
}
pos = pg->pos;
while ((pos < B32) && (pg->base + 1920 < to)) {
pg->base += 1920;
++pos;
}
pg->pos = pos;
if (pos == B32)
while (pg->base + B * 60 < to) {
pg->L += B;
pg->base += B * 60;
}
primegen_fill(pg);
}
}

44
src/crypto-primegen.h Normal file
View File

@@ -0,0 +1,44 @@
#ifndef PRIMEGEN_H
#define PRIMEGEN_H
#include <stdint.h>
/**
* This is B/32: the number of 32-bit words of space used in the primegen
* inner loop. This should fit into the CPU's level-1 cache.
*
* 2048 works well on a Pentium-100.
* 3600 works well on a Pentium II-350
* 4004 works well on an UltraSPARC-I/167
*
* 2012-nov (Rob): This code was written 15 years ago. Processor caches
* haven't really gotten any larger. A number like 8008 works slightly
* better on an Ivy Bridge CPU, but works noticeably worse on an Atom
* or ARM processor. The value 4004 seems to be a good compromise for
* all these processors. In any case, modern CPUs will automatically
* prefetch the buffers anyway, significantly lessoning the impact of
* having a poor number defined here. I tried 16016, but it crashed, and
* I don't know why, but I don't care because I'm not going to use such a
* large size.
*/
#define PRIMEGEN_WORDS 4004
typedef struct {
uint32_t buf[16][PRIMEGEN_WORDS];
uint64_t p[512]; /* p[num-1] ... p[0], in that order */
int num;
int pos; /* next entry to use in buf; WORDS to restart */
uint64_t base;
uint64_t L;
} primegen;
extern void primegen_sieve(primegen *);
extern void primegen_fill(primegen *);
extern void primegen_init(primegen *);
extern uint64_t primegen_next(primegen *);
extern uint64_t primegen_peek(primegen *);
extern uint64_t primegen_count(primegen *,uint64_t to);
extern void primegen_skipto(primegen *,uint64_t to);
#endif

252
src/crypto-siphash24.c Normal file
View File

@@ -0,0 +1,252 @@
/*
SipHash reference C implementation
Written in 2012 by
Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
Daniel J. Bernstein <djb@cr.yp.to>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "crypto-siphash24.h"
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint8_t u8;
#define ROTL(x,b) (u64)( ((x) << (b)) | ( (x) >> (64 - (b))) )
#define U32TO8_LE(p, v) \
(p)[0] = (u8)((v) ); (p)[1] = (u8)((v) >> 8); \
(p)[2] = (u8)((v) >> 16); (p)[3] = (u8)((v) >> 24);
#define U64TO8_LE(p, v) \
U32TO8_LE((p), (u32)((v) )); \
U32TO8_LE((p) + 4, (u32)((v) >> 32));
#define U8TO64_LE(p) \
(((u64)((p)[0]) ) | \
((u64)((p)[1]) << 8) | \
((u64)((p)[2]) << 16) | \
((u64)((p)[3]) << 24) | \
((u64)((p)[4]) << 32) | \
((u64)((p)[5]) << 40) | \
((u64)((p)[6]) << 48) | \
((u64)((p)[7]) << 56))
#define SIPROUND \
{ \
v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \
v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \
v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \
v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \
}
/* SipHash-2-4 */
static int crypto_auth( unsigned char *out, const unsigned char *in, unsigned long long inlen, const unsigned char *k )
{
/* "somepseudorandomlygeneratedbytes" */
u64 v0 = 0x736f6d6570736575ULL;
u64 v1 = 0x646f72616e646f6dULL;
u64 v2 = 0x6c7967656e657261ULL;
u64 v3 = 0x7465646279746573ULL;
u64 b;
u64 k0 = U8TO64_LE( k );
u64 k1 = U8TO64_LE( k + 8 );
const u8 *end = in + inlen - ( inlen % sizeof( u64 ) );
const int left = inlen & 7;
b = ( ( u64 )inlen ) << 56;
v3 ^= k1;
v2 ^= k0;
v1 ^= k1;
v0 ^= k0;
for ( ; in != end; in += 8 )
{
u64 m;
m = U8TO64_LE( in );
#ifdef xxxDEBUG
printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
printf( "(%3d) compress %08x %08x\n", ( int )inlen, ( u32 )( m >> 32 ), ( u32 )m );
#endif
v3 ^= m;
SIPROUND;
SIPROUND;
v0 ^= m;
}
switch( left )
{
case 7: b |= ( ( u64 )in[ 6] ) << 48;
case 6: b |= ( ( u64 )in[ 5] ) << 40;
case 5: b |= ( ( u64 )in[ 4] ) << 32;
case 4: b |= ( ( u64 )in[ 3] ) << 24;
case 3: b |= ( ( u64 )in[ 2] ) << 16;
case 2: b |= ( ( u64 )in[ 1] ) << 8;
case 1: b |= ( ( u64 )in[ 0] ); break;
case 0: break;
}
#ifdef xxxDEBUG
printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
printf( "(%3d) padding %08x %08x\n", ( int )inlen, ( u32 )( b >> 32 ), ( u32 )b );
#endif
v3 ^= b;
SIPROUND;
SIPROUND;
v0 ^= b;
#ifdef xxxDEBUG
printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
#endif
v2 ^= 0xff;
SIPROUND;
SIPROUND;
SIPROUND;
SIPROUND;
b = v0 ^ v1 ^ v2 ^ v3;
U64TO8_LE( out, b );
return 0;
}
uint64_t
siphash24(const void *in, size_t inlen, const uint64_t key[2])
{
uint64_t result;
crypto_auth((unsigned char*)&result,
(const unsigned char *)in,
inlen,
(const unsigned char *)&key[0]);
return result;
}
/*
SipHash-2-4 output with
k = 00 01 02 ...
and
in = (empty string)
in = 00 (1 byte)
in = 00 01 (2 bytes)
in = 00 01 02 (3 bytes)
...
in = 00 01 02 ... 3e (63 bytes)
*/
static u8 vectors[64][8] =
{
{ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, },
{ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, },
{ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, },
{ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, },
{ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, },
{ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, },
{ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, },
{ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, },
{ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, },
{ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, },
{ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, },
{ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, },
{ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, },
{ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, },
{ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, },
{ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, },
{ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, },
{ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, },
{ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, },
{ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, },
{ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, },
{ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, },
{ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, },
{ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, },
{ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, },
{ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, },
{ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, },
{ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, },
{ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, },
{ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, },
{ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, },
{ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, },
{ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, },
{ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, },
{ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, },
{ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, },
{ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, },
{ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, },
{ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, },
{ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, },
{ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, },
{ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, },
{ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, },
{ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, },
{ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, },
{ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, },
{ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, },
{ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, },
{ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, },
{ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, },
{ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, },
{ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, },
{ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, },
{ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, },
{ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, },
{ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, },
{ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, },
{ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, },
{ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, },
{ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, },
{ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, },
{ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, },
{ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, },
{ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, }
};
static int
test_vectors()
{
#define MAXLEN 64
u8 in[MAXLEN], out[8], k[16];
int i;
int ok = 1;
for( i = 0; i < 16; ++i ) k[i] = (u8)i;
for( i = 0; i < MAXLEN; ++i )
{
in[i] = (u8)i;
crypto_auth( out, in, i, k );
if ( memcmp( out, vectors[i], 8 ) )
{
printf( "test vector failed for %d bytes\n", i );
ok = 0;
}
}
return ok;
}
int
siphash24_selftest(void)
{
if (test_vectors())
return 0;
else
return 1;
}

17
src/crypto-siphash24.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef CRYPTO_SIPHASH24_H
#define CRYPTO_SIPHASH24_H
#include <stdint.h>
uint64_t
siphash24(const void *in, size_t inlen, const uint64_t key[2]);
/**
* Regression-test this module.
* @return
* 0 on success, a positive integer otherwise.
*/
int
siphash24_selftest(void);
#endif

176
src/event-timeout.c Normal file
View File

@@ -0,0 +1,176 @@
/*
Event timeout
This is for the user-mode TCP stack. We need to mark timeouts in the
future when we'll re-visit a connection/tcb. For example, when we
send a packet, we need to resend it in the future in case we don't
get a response.
This design creates a large "ring" of timeouts, and then cycles
again and again through the ring. This is a fairly high granularity,
just has hundreds, thousands, or 10 thousand entries per second.
(I keep adjusting the granularity up and down). Not that at any
slot in the ring, there may be entries from the far future.
NOTE: a big feature of this system is that the structure that tracks
the timeout is actually held within the TCB structure. In other
words, each TCB can have one-and-only-one timeout.
NOTE: a recurring bug is that the TCP code removes a TCB from the
timeout ring and forgets to put it back somewhere else. Since the
TCB is cleaned up on a timeout, such TCBs never get cleaned up,
leading to a memory leak. I keep fixing this bug, then changing the
code and causing the bug to come back again.
*/
#include "event-timeout.h"
#include "util-logger.h"
#include "util-malloc.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/***************************************************************************
* The timeout system is a circular ring. We move an index around the
* ring. At each slot in the ring is a linked-list of all entries at
* that time index. Because the ring can wrap, not everything at a given
* entry will be the same timestamp. Therefore, when doing the timeout
* logic at a slot, we have to doublecheck the actual timestamp, and skip
* those things that are further in the future.
***************************************************************************/
struct Timeouts {
/**
* This index is a monotonically increasing number, modulus the mask.
* Every time we check timeouts, we simply move it forward in time.
*/
uint64_t current_index;
/**
* Counts the number of outstanding timeouts. Adding a timeout increments
* this number, and removing a timeout decrements this number. The
* program shouldn't exit until this number is zero.
*/
uint64_t outstanding_count;
/**
* The number of slots is a power-of-2, so the mask is just this
* number minus 1
*/
unsigned mask;
/**
* The ring of entries.
*/
struct TimeoutEntry *slots[1024*1024];
};
/***************************************************************************
***************************************************************************/
struct Timeouts *
timeouts_create(uint64_t timestamp)
{
struct Timeouts *timeouts;
/*
* Allocate memory and initialize it to zero
*/
timeouts = CALLOC(1, sizeof(*timeouts));
/*
* We just mask off the low order bits to determine wrap. I'm using
* a variable here because one of these days I'm going to make
* the size of the ring dynamically adjustable depending upon
* the speed of the scan.
*/
timeouts->mask = sizeof(timeouts->slots)/sizeof(timeouts->slots[0]) - 1;
/*
* Set the index to the current time. Note that this timestamp is
* the 'time_t' value multiplied by the number of ticks-per-second,
* where 'ticks' is something I've defined for scanning. Right now
* I hard-code in the size of the ticks, but eventually they'll be
* dynamically resized depending upon the speed of the scan.
*/
timeouts->current_index = timestamp;
return timeouts;
}
/***************************************************************************
* This inserts the timeout entry into the appropriate place in the
* timeout ring.
***************************************************************************/
void
timeouts_add(struct Timeouts *timeouts, struct TimeoutEntry *entry,
size_t offset, uint64_t timestamp)
{
unsigned index;
/* Unlink from wherever the entry came from */
if (entry->timestamp)
timeouts->outstanding_count--;
timeout_unlink(entry);
if (entry->prev) {
LOG(1, "***CHANGE %d-seconds\n",
(int)((timestamp-entry->timestamp)/TICKS_PER_SECOND));
}
/* Initialize the new entry */
entry->timestamp = timestamp;
entry->offset = (unsigned)offset;
/* Link it into it's new location */
index = timestamp & timeouts->mask;
entry->next = timeouts->slots[index];
timeouts->slots[index] = entry;
entry->prev = &timeouts->slots[index];
if (entry->next)
entry->next->prev = &entry->next;
timeouts->outstanding_count++;
}
/***************************************************************************
* Remove the next event that it older than the specified timestamp
***************************************************************************/
void *
timeouts_remove(struct Timeouts *timeouts, uint64_t timestamp)
{
struct TimeoutEntry *entry = NULL;
/* Search until we find one */
while (timeouts->current_index <= timestamp) {
/* Start at the current slot */
entry = timeouts->slots[timeouts->current_index & timeouts->mask];
/* enumerate through the linked list until we find a used slot */
while (entry && entry->timestamp > timestamp)
entry = entry->next;
if (entry)
break;
/* found nothing at this slot, so move to next slot */
timeouts->current_index++;
}
if (entry == NULL) {
/* we've caught up to the current time, and there's nothing
* left to timeout, so return NULL */
return NULL;
}
/* unlink this entry from the timeout system */
timeouts--;
timeout_unlink(entry);
/* return a pointer to the structure holding this entry */
return ((char*)entry) - entry->offset;
}

132
src/event-timeout.h Normal file
View File

@@ -0,0 +1,132 @@
#ifndef EVENT_TIMEOUT_H
#define EVENT_TIMEOUT_H
#include <stdint.h>
#include <stdio.h>
#include <stddef.h> /* offsetof*/
#include "util-bool.h" /* <stdbool.h> */
#if defined(_MSC_VER)
#undef inline
#define inline _inline
#endif
struct Timeouts;
/***************************************************************************
***************************************************************************/
struct TimeoutEntry {
/**
* In units of 1/16384 of a second. We use power-of-two units here
* to make the "modulus" operation a simple binary "and".
* See the TICKS_FROM_TV() macro for getting the timestamp from
* the current time.
*/
uint64_t timestamp;
/** we build a doubly-linked list */
struct TimeoutEntry *next;
struct TimeoutEntry **prev;
/** The timeout entry is never allocated by itself, but instead
* lives inside another data structure. This stores the value of
* 'offsetof()', so given a pointer to this structure, we can find
* the original structure that contains it */
unsigned offset;
};
/***************************************************************************
***************************************************************************/
static inline bool
timeout_is_unlinked(const struct TimeoutEntry *entry) {
if (entry->prev == 0 || entry->next == 0)
return true;
else
return false;
}
/***************************************************************************
***************************************************************************/
static inline void
timeout_unlink(struct TimeoutEntry *entry)
{
if (entry->prev == 0 && entry->next == 0)
return;
*(entry->prev) = entry->next;
if (entry->next)
entry->next->prev = entry->prev;
entry->next = 0;
entry->prev = 0;
entry->timestamp = 0;
}
/***************************************************************************
***************************************************************************/
static inline void
timeout_init(struct TimeoutEntry *entry)
{
entry->next = 0;
entry->prev = 0;
}
/**
* Create a timeout subsystem.
* @param timestamp_now
* The current timestamp indicating "now" when the thing starts.
* This should be 'time(0) * TICKS_PER_SECOND'.
*/
struct Timeouts *
timeouts_create(uint64_t timestamp_now);
/**
* Insert the timeout 'entry' into the future location in the timeout
* ring, as determined by the timestamp.
* @param timeouts
* A ring of timeouts, with each slot corresponding to a specific
* time in the future.
* @param entry
* The entry that we are going to insert into the ring. If it's
* already in the ring, it'll be removed from the old location
* first before inserting into the new location.
* @param offset
* The 'entry' field above is part of an existing structure. This
* tells the offset_of() from the beginning of that structure.
* In other words, this tells us the pointer to the object that
* that is the subject of the timeout.
* @param timestamp_expires
* When this timeout will expire. This is in terms of internal
* ticks, which in units of TICKS_PER_SECOND.
*/
void
timeouts_add(struct Timeouts *timeouts, struct TimeoutEntry *entry,
size_t offset, uint64_t timestamp_expires);
/**
* Remove an object from the timestamp system that is older than than
* the specified timestamp. This function must be called repeatedly
* until it returns NULL to remove all the objects that are older
* than the given timestamp.
* @param timeouts
* A ring of timeouts. We'll walk the ring until we've caught
* up with the current time.
* @param timestamp_now
* Usually, this timestmap will be "now", the current time,
* and anything older than this will be aged out.
* @return
* an object older than the specified timestamp, or NULL
* if there are no more objects to be found
*/
void *
timeouts_remove(struct Timeouts *timeouts, uint64_t timestamp_now);
/*
* This macros convert a normal "timeval" structure into the timestamp
* that we use for timeouts. The timeval structure probably will come
* from the packets that we are capturing.
*/
#define TICKS_PER_SECOND (16384ULL)
#define TICKS_FROM_SECS(secs) ((secs)*16384ULL)
#define TICKS_FROM_USECS(usecs) ((usecs)/16384ULL)
#define TICKS_FROM_TV(secs,usecs) (TICKS_FROM_SECS(secs)+TICKS_FROM_USECS(usecs))
#endif

691
src/in-binary.c Normal file
View File

@@ -0,0 +1,691 @@
/*
Read in the binary file produced by "out-binary.c". This allows you to
translate the "binary" format into any of the other output formats.
*/
#include "massip-addr.h"
#include "in-binary.h"
#include "masscan.h"
#include "masscan-app.h"
#include "masscan-status.h"
#include "main-globals.h"
#include "output.h"
#include "util-safefunc.h"
#include "in-filter.h"
#include "in-report.h"
#include "util-malloc.h"
#include "util-logger.h"
#include <stdlib.h>
#include <assert.h>
#ifdef _MSC_VER
#pragma warning(disable:4996)
#endif
static const size_t BUF_MAX = 1024*1024;
struct MasscanRecord {
unsigned timestamp;
ipaddress ip;
unsigned char ip_proto;
unsigned short port;
unsigned char reason;
unsigned char ttl;
unsigned char mac[6];
enum ApplicationProtocol app_proto;
};
/***************************************************************************
***************************************************************************/
static void
parse_status(struct Output *out,
enum PortStatus status, /* open/closed */
const unsigned char *buf, size_t buf_length)
{
struct MasscanRecord record;
if (buf_length < 12)
return;
/* parse record */
record.timestamp = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3];
record.ip.ipv4 = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];
record.ip.version = 4;
record.port = buf[8]<<8 | buf[9];
record.reason = buf[10];
record.ttl = buf[11];
/* if ARP, then there will be a MAC address */
if (record.ip.ipv4 == 0 && buf_length >= 12+6)
memcpy(record.mac, buf+12, 6);
else
memset(record.mac, 0, 6);
if (out->when_scan_started == 0)
out->when_scan_started = record.timestamp;
switch (record.port) {
case 53:
case 123:
case 137:
case 161:
record.ip_proto = 17;
break;
case 36422:
case 36412:
case 2905:
record.ip_proto = 132;
break;
default:
record.ip_proto = 6;
break;
}
/*
* Now report the result
*/
output_report_status(out,
record.timestamp,
status,
record.ip,
record.ip_proto,
record.port,
record.reason,
record.ttl,
record.mac);
}
/***************************************************************************
***************************************************************************/
static void
parse_status2(struct Output *out,
enum PortStatus status, /* open/closed */
const unsigned char *buf, size_t buf_length,
struct MassIP *filter)
{
struct MasscanRecord record;
if (buf_length < 13)
return;
/* parse record */
record.timestamp = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3];
record.ip.ipv4 = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];
record.ip.version = 4;
record.ip_proto = buf[8];
record.port = buf[9]<<8 | buf[10];
record.reason = buf[11];
record.ttl = buf[12];
/* if ARP, then there will be a MAC address */
if (record.ip.ipv4 == 0 && buf_length >= 13+6)
memcpy(record.mac, buf+13, 6);
else
memset(record.mac, 0, 6);
if (out->when_scan_started == 0)
out->when_scan_started = record.timestamp;
/* Filter for known IP/ports, if specified on command-line */
if (filter && filter->count_ipv4s) {
if (!massip_has_ip(filter, record.ip))
return;
}
if (filter && filter->count_ports) {
if (!massip_has_port(filter, record.port))
return;
}
/*
* Now report the result
*/
output_report_status(out,
record.timestamp,
status,
record.ip,
record.ip_proto,
record.port,
record.reason,
record.ttl,
record.mac);
}
static unsigned char
_get_byte(const unsigned char *buf, size_t length, size_t *offset)
{
unsigned char result;
if (*offset < length) {
result = buf[*offset];
} else {
result = 0xFF;
}
(*offset)++;
return result;
}
static unsigned
_get_integer(const unsigned char *buf, size_t length, size_t *r_offset)
{
unsigned result;
size_t offset = *r_offset;
(*r_offset) += 4;
if (offset + 4 <= length) {
result = buf[offset+0]<<24
| buf[offset+1]<<16
| buf[offset+2]<<8
| buf[offset+3]<<0;
} else {
result = 0xFFFFFFFF;
}
return result;
}
static unsigned short
_get_short(const unsigned char *buf, size_t length, size_t *r_offset)
{
unsigned short result;
size_t offset = *r_offset;
(*r_offset) += 2;
if (offset + 2 <= length) {
result = buf[offset+0]<<8
| buf[offset+1]<<0;
} else {
result = 0xFFFF;
}
return result;
}
static unsigned long long
_get_long(const unsigned char *buf, size_t length, size_t *r_offset)
{
unsigned long long result;
size_t offset = *r_offset;
(*r_offset) += 8;
if (offset + 8 <= length) {
result =
(unsigned long long)buf[offset+0]<<56ULL
| (unsigned long long)buf[offset+1]<<48ULL
| (unsigned long long)buf[offset+2]<<40ULL
| (unsigned long long)buf[offset+3]<<32ULL
| (unsigned long long)buf[offset+4]<<24ULL
| (unsigned long long)buf[offset+5]<<16ULL
| (unsigned long long)buf[offset+6]<<8ULL
| (unsigned long long)buf[offset+7]<<0ULL;
} else {
result = 0xFFFFFFFFffffffffULL;
}
return result;
}
/***************************************************************************
***************************************************************************/
static void
parse_status6(struct Output *out,
enum PortStatus status, /* open/closed */
const unsigned char *buf, size_t length,
struct MassIP *filter)
{
struct MasscanRecord record;
size_t offset = 0;
/* parse record */
record.timestamp = _get_integer(buf, length, &offset);
record.ip_proto = _get_byte(buf, length, &offset);
record.port = _get_short(buf, length, &offset);
record.reason = _get_byte(buf, length, &offset);
record.ttl = _get_byte(buf, length, &offset);
record.ip.version= _get_byte(buf, length, &offset);
if (record.ip.version != 6) {
fprintf(stderr, "[-] corrupt record\n");
return;
}
record.ip.ipv6.hi = _get_long(buf, length, &offset);
record.ip.ipv6.lo = _get_long(buf, length, &offset);
if (out->when_scan_started == 0)
out->when_scan_started = record.timestamp;
/* Filter for known IP/ports, if specified on command-line */
if (filter && filter->count_ipv4s) {
if (!massip_has_ip(filter, record.ip))
return;
}
if (filter && filter->count_ports) {
if (!massip_has_port(filter, record.port))
return;
}
/*
* Now report the result
*/
output_report_status(out,
record.timestamp,
status,
record.ip,
record.ip_proto,
record.port,
record.reason,
record.ttl,
record.mac);
}
/***************************************************************************
***************************************************************************/
static void
parse_banner6(struct Output *out, unsigned char *buf, size_t length,
const struct MassIP *filter,
const struct RangeList *btypes)
{
struct MasscanRecord record;
size_t offset = 0;
/*
* Parse the parts that are common to most records
*/
record.timestamp = _get_integer(buf, length, &offset);
record.ip_proto = _get_byte(buf, length, &offset);
record.port = _get_short(buf, length, &offset);
record.app_proto = _get_short(buf, length, &offset);
record.ttl = _get_byte(buf, length, &offset);
record.ip.version= _get_byte(buf, length, &offset);
if (record.ip.version != 6) {
fprintf(stderr, "[-] corrupt record\n");
return;
}
record.ip.ipv6.hi = _get_long(buf, length, &offset);
record.ip.ipv6.lo = _get_long(buf, length, &offset);
if (out->when_scan_started == 0)
out->when_scan_started = record.timestamp;
/*
* Filter out records if requested
*/
if (!readscan_filter_pass(record.ip, record.port, record.app_proto,
filter, btypes))
return;
/*
* Now print the output
*/
if (offset > length)
return;
output_report_banner(
out,
record.timestamp,
record.ip,
record.ip_proto, /* TCP=6, UDP=17 */
record.port,
record.app_proto, /* HTTP, SSL, SNMP, etc. */
record.ttl, /* ttl */
buf+offset, (unsigned)(length-offset)
);
}
/***************************************************************************
* [OBSOLETE]
* This parses an old version of the banner record. I've still got files
* hanging around with this version, so I'm keeping it in the code for
* now, but eventually I'll get rid of it.
***************************************************************************/
static void
parse_banner3(struct Output *out, unsigned char *buf, size_t buf_length)
{
struct MasscanRecord record;
/*
* Parse the parts that are common to most records
*/
record.timestamp = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3];
record.ip.ipv4 = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];
record.ip.version = 4;
record.port = buf[8]<<8 | buf[9];
record.app_proto = buf[10]<<8 | buf[11];
if (out->when_scan_started == 0)
out->when_scan_started = record.timestamp;
/*
* Now print the output
*/
output_report_banner(
out,
record.timestamp,
record.ip,
6, /* this is always TCP */
record.port,
record.app_proto,
0, /* ttl */
buf+12, (unsigned)buf_length-12
);
}
/***************************************************************************
* Parse the BANNER record, extracting the timestamp, IP address, and port
* number. We also convert the banner string into a safer form.
***************************************************************************/
static void
parse_banner4(struct Output *out, unsigned char *buf, size_t buf_length)
{
struct MasscanRecord record;
if (buf_length < 13)
return;
/*
* Parse the parts that are common to most records
*/
record.timestamp = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3];
record.ip.ipv4 = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];
record.ip.version = 4;
record.ip_proto = buf[8];
record.port = buf[9]<<8 | buf[10];
record.app_proto = buf[11]<<8 | buf[12];
if (out->when_scan_started == 0)
out->when_scan_started = record.timestamp;
/*
* Now print the output
*/
output_report_banner(
out,
record.timestamp,
record.ip,
record.ip_proto, /* TCP=6, UDP=17 */
record.port,
record.app_proto, /* HTTP, SSL, SNMP, etc. */
0, /* ttl */
buf+13, (unsigned)buf_length-13
);
}
/***************************************************************************
***************************************************************************/
static void
parse_banner9(struct Output *out, unsigned char *buf, size_t buf_length,
const struct MassIP *filter,
const struct RangeList *btypes)
{
struct MasscanRecord record;
unsigned char *data = buf+14;
size_t data_length = buf_length-14;
if (buf_length < 14)
return;
/*
* Parse the parts that are common to most records
*/
record.timestamp = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3];
record.ip.ipv4 = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];
record.ip.version = 4;
record.ip_proto = buf[8];
record.port = buf[9]<<8 | buf[10];
record.app_proto = buf[11]<<8 | buf[12];
record.ttl = buf[13];
if (out->when_scan_started == 0)
out->when_scan_started = record.timestamp;
/*
* KLUDGE: when doing SSL stuff, add a IP:name pair to a database
* so we can annotate [VULN] strings with this information
*/
//readscan_report(record.ip, record.app_proto, &data, &data_length);
/*
* Filter out records if requested
*/
if (!readscan_filter_pass(record.ip, record.port, record.app_proto,
filter, btypes))
return;
/*
* Now print the output
*/
output_report_banner(
out,
record.timestamp,
record.ip,
record.ip_proto, /* TCP=6, UDP=17 */
record.port,
record.app_proto, /* HTTP, SSL, SNMP, etc. */
record.ttl, /* ttl */
data, (unsigned)data_length
);
}
/***************************************************************************
* Read in the file, one record at a time.
***************************************************************************/
static uint64_t
_binaryfile_parse(struct Output *out, const char *filename,
struct MassIP *filter,
const struct RangeList *btypes)
{
FILE *fp = 0;
unsigned char *buf = 0;
size_t bytes_read;
uint64_t total_records = 0;
/* Allocate a buffer of up to one megabyte per record */
buf = MALLOC(BUF_MAX);
/* Open the file */
fp = fopen(filename, "rb");
if (fp == NULL) {
fprintf(stderr, "[-] FAIL: --readscan\n");
fprintf(stderr, "[-] %s: %s\n", filename, strerror(errno));
goto end;
}
LOG(0, "[+] --readscan %s\n", filename);
if (feof(fp)) {
LOG(0, "[-] %s: file is empty\n", filename);
goto end;
}
/* first record is pseudo-record */
bytes_read = fread(buf, 1, 'a'+2, fp);
if (bytes_read < 'a'+2) {
LOG(0, "[-] %s: %s\n", filename, strerror(errno));
goto end;
}
/* Make sure it's got the format string */
if (memcmp(buf, "masscan/1.1", 11) != 0) {
LOG(0,
"[-] %s: unknown file format (expected \"masscan/1.1\")\n",
filename);
goto end;
}
/*
* Look for start time
*/
if (buf[11] == '.' && strtoul((char*)buf+12,0,0) >= 2) {
unsigned i;
/* move to next field */
for (i=0; i<'a' && buf[i] && buf[i] != '\n'; i++)
;
i++;
if (buf[i] == 's')
i++;
if (buf[i] == ':')
i++;
/* extract timestamp */
if (i < 'a')
out->when_scan_started = strtoul((char*)buf+i,0,0);
}
/* Now read all records */
for (;;) {
unsigned type;
unsigned length;
/* [TYPE]
* This is one or more bytes indicating the type of type of the
* record
*/
bytes_read = fread(buf, 1, 1, fp);
if (bytes_read != 1)
break;
type = buf[0] & 0x7F;
while (buf[0] & 0x80) {
bytes_read = fread(buf, 1, 1, fp);
if (bytes_read != 1)
break;
type = (type << 7) | (buf[0] & 0x7F);
}
/* [LENGTH]
* Is one byte for lengths smaller than 127 bytes, or two
* bytes for lengths up to 16384.
*/
bytes_read = fread(buf, 1, 1, fp);
if (bytes_read != 1)
break;
length = buf[0] & 0x7F;
while (buf[0] & 0x80) {
bytes_read = fread(buf, 1, 1, fp);
if (bytes_read != 1)
break;
length = (length << 7) | (buf[0] & 0x7F);
}
if (length > BUF_MAX) {
LOG(0, "[-] file corrupt\n");
goto end;
}
/* get the remainder of the record */
bytes_read = fread(buf, 1, length, fp);
if (bytes_read < length)
break; /* eof */
/* Depending on record type, do something different */
switch (type) {
case 1: /* STATUS: open */
if (!btypes->count)
parse_status(out, PortStatus_Open, buf, bytes_read);
break;
case 2: /* STATUS: closed */
if (!btypes->count)
parse_status(out, PortStatus_Closed, buf, bytes_read);
break;
case 3: /* BANNER */
parse_banner3(out, buf, bytes_read);
break;
case 4:
if (fread(buf+bytes_read,1,1,fp) != 1) {
LOG(0, "[-] read() error\n");
exit(1);
}
bytes_read++;
parse_banner4(out, buf, bytes_read);
break;
case 5:
parse_banner4(out, buf, bytes_read);
<