Skip to content
Merged
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
96 changes: 66 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,41 @@ Your ultimate IP dex!

## Table of Contents

- [Introduction](#introduction)
- [Prerequisites](#prerequisites)
- [Quickstart](#quickstart)
- [Install](#1-install)
- [Make sure the binary is in your PATH](#2-make-sure-the-binary-is-in-your-path)
- [Initialize the tool](#3-initialize-the-tool)
- [Query an IP](#4-query-an-ip)
- [Scan a file](#5-scan-a-file)
- [Configuration](#configuration)
- [User Guide](#user-guide)
- [Scan an IP](#scan-an-ip)
- [Refresh an IP](#refresh-an-ip)
- [Scan a file](#scan-a-file-1)
- [Refresh a file](#refresh-a-file)
- [Display all reports](#display-all-reports)
- [Showing a specific report](#showing-a-specific-report)
- [Commands](#commands)
- [`init`](#init)
- [`report`](#report)
- [List reports](#list-reports)
- [View a report](#view-a-report)
- [Delete a report](#delete-a-report)
- [`search`](#search)
- [Search IPs reported for a specific CVE](#search-ips-reported-for-a-specific-cve)
- [Search IPs reported for HTTP scan since 30 minutes](#search-ips-reported-for-http-scan-since-30-minutes)
- [Search malicious VPN or Proxy IPs since 1h and show all IPs](#search-malicious-vpn-or-proxy-ips-since-1h-and-show-all-ips)
- [`config`](#config)
- [Show config](#show-config)
- [Set a new API Key](#set-a-new-api-key)
- [License](#license)
- [ipdex](#ipdex)
- [Table of Contents](#table-of-contents)
- [Introduction](#introduction)
- [Prerequisites](#prerequisites)
- [Quickstart](#quickstart)
- [1. Install](#1-install)
- [Install with Go](#install-with-go)
- [macOS / Linux](#macos--linux)
- [Linux](#linux)
- [macOS](#macos)
- [Windows](#windows)
- [2. Make sure the binary is in your PATH](#2-make-sure-the-binary-is-in-your-path)
- [3. Initialize the tool](#3-initialize-the-tool)
- [4. Query an IP](#4-query-an-ip)
- [5. Scan a file](#5-scan-a-file)
- [Configuration](#configuration)
- [User Guide](#user-guide)
- [Scan an IP](#scan-an-ip)
- [Refresh an IP](#refresh-an-ip)
- [Scan a file](#scan-a-file)
- [Refresh a file](#refresh-a-file)
- [Output formats](#output-formats)
- [Saving reports to files](#saving-reports-to-files)
- [`report`](#report)
- [List reports](#list-reports)
- [View a report](#view-a-report)
- [Delete a report](#delete-a-report)
- [`search`](#search)
- [Search IPs reported for a specific CVE](#search-ips-reported-for-a-specific-cve)
- [Search IPs reported for HTTP scan since 30 minutes](#search-ips-reported-for-http-scan-since-30-minutes)
- [Search malicious VPN or Proxy IPs since 1h and show all IPs](#search-malicious-vpn-or-proxy-ips-since-1h-and-show-all-ips)
- [`config`](#config)
- [Show config](#show-config)
- [Set a new API Key](#set-a-new-api-key)
- [License](#license)

---

Expand Down Expand Up @@ -162,6 +167,8 @@ ipdex /var/log/nginx.log

<p align="center"> <img src="img/ipdex_file.svg" alt="ipdex scanning a file" width="900" /> </p>

**💡 Tip:** You can output results in different formats (`-o json`, `-o csv`) and save them to files using `--output-path`. See [Output formats](#output-formats) and [Saving reports to files](#saving-reports-to-files) for more details.

---

## Configuration
Expand Down Expand Up @@ -202,6 +209,31 @@ When running ipdex on a file that has been previously scanned, it will update th
ipdex <filepath> -r
```

### Output formats

ipdex supports multiple output formats to suit different use cases using the -o option:

- **human** (default): Interactive, colorized output optimized for terminal viewing
- **json**: `-o json` Machine-readable JSON format for programmatic processing
- **csv**: `-o csv` Comma-separated values format for spreadsheet analysis

### Saving reports to files

You can save reports to disk using the `--output-path` flag. This works with all output formats and automatically creates separate files for the report summary and the detailed IP information (if you used the -d option).

```bash
# Save report as CSV files report and details
ipdex ips.txt -o csv -d --output-path /path/to/output

# This creates:
# - /path/to/output/report_<id>.csv (summary statistics)
# - /path/to/output/report_<id>_details.csv (detailed IP information, when using -d flag)

# You can also do it for an existing report
ipdex report show 18 -o csv --output-path /path/to/output -d

**Note:** When using `--output-path`, reports are saved to files in addition to being displayed in the terminal.

### Display all reports

```
Expand Down Expand Up @@ -242,7 +274,11 @@ ipdex report list
#### View a report

```bash
# View a report in human-readable format
ipdex report show 2

# View report with details as CSV and save
ipdex report show 2 -o csv --output-path ./exports -d
```

#### Delete a report
Expand Down
13 changes: 7 additions & 6 deletions cmd/ipdex/config/global.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package config

var (
OutputFormat string
ForceRefresh bool
Yes bool
Detailed bool
ReportName string
Batching bool
OutputFormat string
OutputFilePath string
ForceRefresh bool
Yes bool
Detailed bool
ReportName string
Batching bool
)
2 changes: 1 addition & 1 deletion cmd/ipdex/config/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func GetConfigFolder() (string, error) {

func IsSupportedOutputFormat(outputFormat string) bool {
switch outputFormat {
case display.JSONFormat, display.HumanFormat:
case display.JSONFormat, display.HumanFormat, display.CSVFormat:
return true
default:
return false
Expand Down
2 changes: 1 addition & 1 deletion cmd/ipdex/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func FileCommand(file string, forceRefresh bool, yes bool) {
}
}
stats := reportClient.GetStats(report)
if err := reportClient.Display(report, stats, viper.GetString(config.OutputFormatOption), config.Detailed); err != nil {
if err := reportClient.Display(report, stats, viper.GetString(config.OutputFormatOption), config.Detailed, config.OutputFilePath); err != nil {
style.Fatal(err.Error())
}
if !reportExist && outputFormat == display.HumanFormat {
Expand Down
3 changes: 2 additions & 1 deletion cmd/ipdex/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ func init() {
rootCmd.Flags().BoolVarP(&config.ForceRefresh, "refresh", "r", false, "Force refresh an IP or all the IPs of a report")
rootCmd.Flags().BoolVarP(&config.Yes, "yes", "y", false, "Say automatically yes to the warning about the number of IPs to scan")
rootCmd.PersistentFlags().BoolVarP(&config.Detailed, "detailed", "d", false, "Show all informations about an IP or a report")
rootCmd.PersistentFlags().StringVarP(&config.OutputFormat, "output", "o", "", "Output format: human or json")
rootCmd.PersistentFlags().StringVarP(&config.OutputFormat, "output", "o", "", "Output format: human, json, or csv")
rootCmd.PersistentFlags().StringVar(&config.OutputFilePath, "output-path", "", "Output file path for saving reports in the format specified by -o (saves report and details files separately)")
rootCmd.Flags().StringVarP(&config.ReportName, "name", "n", "", "Report name when scanning a file or making a search query")
rootCmd.Flags().BoolVarP(&config.Batching, "batch", "b", false, "Use batching to request the CrowdSec API. Make sure you have a premium API key to use this feature.")
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/ipdex/report/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func NewShowCommand() *cobra.Command {
} else {
style.Fatal("Please provide a report ID or file used in the report you want to show with `ipdex report show 1`")
}
if err := reportClient.Display(report, report.Stats, viper.GetString(config.OutputFormatOption), config.Detailed); err != nil {
if err := reportClient.Display(report, report.Stats, viper.GetString(config.OutputFormatOption), config.Detailed, config.OutputFilePath); err != nil {
style.Fatal(err.Error())
}
fmt.Println()
Expand Down
2 changes: 1 addition & 1 deletion cmd/ipdex/search/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func SearchCommand(query string, since string, maxResult int) {
style.Fatalf("unable to create report: %s", err)
}
stats := reportClient.GetStats(report)
if err := reportClient.Display(report, stats, viper.GetString(config.OutputFormatOption), config.Detailed); err != nil {
if err := reportClient.Display(report, stats, viper.GetString(config.OutputFormatOption), config.Detailed, config.OutputFilePath); err != nil {
style.Fatal(err.Error())
}
if outputFormat == display.HumanFormat {
Expand Down
Loading