Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Go CI

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout source code
uses: actions/checkout@v6

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache: true
cache-dependency-path: go.sum

- name: Verify dependencies
run: go mod verify

- name: Build
run: go build -v ./...

- name: Test
run: go test -v ./...
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ jobs:
go-version-file: go.mod
id: go

- name: Wait for tag to propagate
run: sleep 15

- name: run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
Expand Down
68 changes: 55 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
<h1 align="center">
<br>
<a href="https://github.com/s0md3v/smap"><img src="/static/smap-logo.png" alt="Smap logo"></a>
<a href="https://github.com/dylan1501/Smap"><img src="/static/smap-logo.png" alt="Smap logo"></a>
</h1>

<h4 align="center">passive Nmap like scanner built with shodan.io</h4>

<p align="center">
<a href="https://github.com/s0md3v/Smap/releases">
<img src="https://img.shields.io/github/release/s0md3v/Smap.svg?label=version">
<a href="https://github.com/dylan1501/Smap/releases">
<img src="https://img.shields.io/github/release/dylan1501/Smap.svg?label=version">
</a>
<a href="https://github.com/s0md3v/Smap/releases">
<img src="https://img.shields.io/github/downloads/s0md3v/Smap/total">
<a href="https://github.com/dylan1501/Smap/releases">
<img src="https://img.shields.io/github/downloads/dylan1501/Smap/total">
</a>
<a href="https://github.com/s0md3v/SMap/issues?q=is%3Aissue+is%3Aclosed">
<img src="https://img.shields.io/github/issues-closed-raw/s0md3v/Smap?color=dark-green&label=issues%20fixed">
<a href="https://github.com/dylan1501/Smap/issues?q=is%3Aissue+is%3Aclosed">
<img src="https://img.shields.io/github/issues-closed-raw/dylan1501/Smap?color=dark-green&label=issues%20fixed">
</a>
<a href="https://travis-ci.com/s0md3v/Smap">
<img src="https://img.shields.io/travis/com/s0md3v/Smap.svg?color=dark-green&label=tests">
<a href="https://github.com/dylan1501/Smap/actions/workflows/go.yml">
<img src="https://img.shields.io/github/actions/workflow/status/dylan1501/Smap/go.yml?branch=main&label=tests">
</a>
</p>

Expand All @@ -37,12 +37,12 @@ Smap is a port scanner built with shodan.io's free API. It takes same command li

## Installation
### Binaries
You can download a pre-built binary from [here](https://github.com/s0md3v/Smap/releases) and use it right away.
You can download a pre-built binary from [here](https://github.com/dylan1501/Smap/releases) and use it right away.

### Manual
`go install -v github.com/s0md3v/smap/cmd/smap@latest`
`go install -v github.com/dylan1501/smap/cmd/smap@latest`

Confused or something not working? For more detailed instructions, [click here](https://github.com/s0md3v/Smap/wiki/FAQ#how-do-i-install-smap)
Confused or something not working? For more detailed instructions, [click here](https://github.com/dylan1501/Smap/wiki/FAQ#how-do-i-install-smap)
### AUR pacakge
Smap is available on AUR as [smap-git](https://aur.archlinux.org/packages/smap-git) (builds from source) and [smap-bin](https://aur.archlinux.org/packages/smap-bin) (pre-built binary).

Expand All @@ -55,7 +55,7 @@ brew install smap
```

## Usage
Smap takes the same arguments as Nmap but options other than `-p`, `-h`, `-o*`, `-iL`, `--concurrency`, `--append-output`, `--active` are ignored. If you are unfamiliar with Nmap, here's how to use Smap.
Smap takes the same arguments as Nmap but options other than `-p`, `-h`, `-o*`, `-iL`, `--concurrency`, `--append-output`, `--active`, `--shodan-key`, `--config` are ignored. If you are unfamiliar with Nmap, here's how to use Smap.

### Specifying targets
```
Expand Down Expand Up @@ -121,6 +121,48 @@ Smap defaults to `3` workers to avoid hitting Shodan too aggressively. You can c
smap --concurrency 5 -iL targets.txt
```

### Using the full Shodan API
By default Smap queries Shodan's free [InternetDB](https://internetdb.shodan.io) endpoint, which needs no account. If you have a [Shodan API key](https://account.shodan.io/), Smap can query the full [Host API](https://developer.shodan.io/api#host-information) at `api.shodan.io` instead, which returns richer data (org/ISP/geo info, per-service banners, etc.) at the cost of query credits.

Smap looks for a key in this order:
1. `--shodan-key <key>`
2. `$SHODAN_API_KEY` environment variable
3. A JSON config file

```
smap --shodan-key YOUR_API_KEY example.com
```

**Config file**

Copy [`configs/smap.example.json`](configs/smap.example.json) to your config directory and fill in your key:

```json
{
"shodan_api_key": "YOUR_SHODAN_API_KEY_HERE"
}
```

Without `--config`, Smap looks for `config.json` in the OS-standard per-user config directory:

| OS | Default path |
|----|---------------|
| Windows | `%AppData%\smap\config.json` |
| Linux | `~/.config/smap/config.json` |
| macOS | `~/Library/Application Support/smap/config.json` |

Use `--config <path>` (or the `$SMAP_CONFIG` environment variable) to point at a different file.

**Rate limiting**

Most Shodan API plans allow 1 request/second. `--concurrency` only controls how many workers run at once, not how fast they fire requests, so Smap paces its own requests to `api.shodan.io` (shared across all workers) at 1/sec by default and automatically retries a few times if it still gets HTTP 429. If your plan allows more, raise it with `--shodan-rate`:

```
smap --shodan-key YOUR_API_KEY --shodan-rate 5 -iL targets.txt
```

This limiter only applies to the full Shodan API; InternetDB is unaffected.

## Considerations
Since Smap simply fetches existent port data from shodan.io, it is super fast but there's more to it. You should use Smap if:

Expand Down
2 changes: 1 addition & 1 deletion cmd/smap/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package main

import (
"github.com/s0md3v/smap/internal/core"
"github.com/dylan1501/smap/internal/core"
)

func main() {
Expand Down
3 changes: 3 additions & 0 deletions configs/smap.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"shodan_api_key": "YOUR_SHODAN_API_KEY_HERE"
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/s0md3v/smap
module github.com/dylan1501/smap

go 1.25.0

Expand Down
2 changes: 1 addition & 1 deletion internal/core/active.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"time"
"unicode/utf8"

g "github.com/s0md3v/smap/internal/global"
g "github.com/dylan1501/smap/internal/global"
)

var execNmap = func(args []string) ([]byte, []byte, error) {
Expand Down
3 changes: 3 additions & 0 deletions internal/core/argparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ var validArgs = map[string]bool{ // name : is_boolean_type
"append-output": true,
"active": true,
"concurrency": false,
"shodan-key": false,
"shodan-rate": false,
"config": false,
"resume": false,
"stylesheet": false,
"webxml": true,
Expand Down
2 changes: 1 addition & 1 deletion internal/core/collector.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package core

import g "github.com/s0md3v/smap/internal/global"
import g "github.com/dylan1501/smap/internal/global"

func collectOutput(done chan<- []g.Output) {
results := []g.Output{}
Expand Down
14 changes: 13 additions & 1 deletion internal/core/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import (
"fmt"
"strconv"

g "github.com/s0md3v/smap/internal/global"
g "github.com/dylan1501/smap/internal/global"
)

const defaultConcurrency = 3
const defaultShodanRPS = 1.0

func parsePositiveInt(raw string, name string) (int, error) {
value, err := strconv.Atoi(raw)
Expand All @@ -23,3 +24,14 @@ func getConcurrency() (int, error) {
}
return defaultConcurrency, nil
}

func getShodanRPS() (float64, error) {
if value, ok := g.Args["shodan-rate"]; ok {
parsed, err := strconv.ParseFloat(value, 64)
if err != nil || parsed <= 0 {
return 0, fmt.Errorf("--shodan-rate must be a positive number")
}
return parsed, nil
}
return defaultShodanRPS, nil
}
2 changes: 1 addition & 1 deletion internal/core/correlate.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"strconv"
"strings"

g "github.com/s0md3v/smap/internal/global"
g "github.com/dylan1501/smap/internal/global"
)

var Probes []g.Contender
Expand Down
12 changes: 9 additions & 3 deletions internal/core/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import (
"sync"
"time"

"github.com/s0md3v/smap/internal/db"
g "github.com/s0md3v/smap/internal/global"
o "github.com/s0md3v/smap/internal/output"
"github.com/dylan1501/smap/internal/db"
g "github.com/dylan1501/smap/internal/global"
o "github.com/dylan1501/smap/internal/output"
"github.com/weppos/publicsuffix-go/publicsuffix"
)

Expand Down Expand Up @@ -373,6 +373,12 @@ func Init() {
os.Exit(1)
}
g.Concurrency = concurrency
shodanRPS, err := getShodanRPS()
if err != nil {
fmt.Fprintf(os.Stderr, "%s\nQUITTING!\n", err)
os.Exit(1)
}
g.ShodanRPS = shodanRPS
if err := json.Unmarshal(db.NmapSigs, &Probes); err != nil {
fmt.Fprintf(os.Stderr, "Failed to load embedded probe signatures: %v\nQUITTING!\n", err)
os.Exit(1)
Expand Down
Loading