Repository: edoardottt/favirecon (language: go)

Issue:
Add Proxy option
Add Proxy option


Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index 41ebbe9c..d73ba808 100644
--- a/README.md
+++ b/README.md
@@ -78,6 +78,7 @@ CONFIGURATIONS:
    -c, -concurrency int  Concurrency level (default 50)
    -t, -timeout int      Connection timeout in seconds (default 10)
    -rl, -rate-limit int  Set a rate limit (per second)
+   -px, -proxy string    Set a proxy server (URL)
 
 OUTPUT:
    -o, -output string  File to write output results
@@ -120,6 +121,12 @@ Grab all possible results from single CIDR
 favirecon -u 192.168.1.0/24 -cidr
 ```
 
+Use a Proxy
+
+```console
+favirecon -u https://www.github.com -px http://127.0.0.1:8080
+```
+
 Changelog 📌
 -------
 
diff --git a/pkg/favirecon/favirecon.go b/pkg/favirecon/favirecon.go
index 4b9c856e..5386fd0a 100644
--- a/pkg/favirecon/favirecon.go
+++ b/pkg/favirecon/favirecon.go
@@ -140,16 +140,19 @@ func execute(r *Runner) {
 			for value := range r.Input {
 				targetURL, err := PrepareURL(value)
 				if err != nil {
-					if r.Options.Verbose {
-						gologger.Error().Msgf("%s", err)
-					}
+					gologger.Error().Msgf("%s", err)
 
 					return
 				}
 
 				rl.Take()
 
-				client := customClient(r.Options.Timeout)
+				client, err := customClient(&r.Options)
+				if err != nil {
+					gologger.Error().Msgf("%s", err)
+
+					return
+				}
 
 				result, err := getFavicon(targetURL, r.UserAgent, client)
 				if err != nil {
diff --git a/pkg/favirecon/utils.go b/pkg/favirecon/utils.go
index 310a6f89..3bbfb11b 100644
--- a/pkg/favirecon/utils.go
+++ b/pkg/favirecon/utils.go
@@ -19,6 +19,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/edoardottt/favirecon/pkg/input"
 	"github.com/projectdiscovery/gologger"
 	"github.com/projectdiscovery/mapcidr"
 	"github.com/twmb/murmur3"
@@ -122,23 +123,36 @@ func GetFaviconHash(input []byte) string {
 	return fmt.Sprint(int32(murmur3.Sum32(b64)))
 }
 
-func customClient(timeout int) *http.Client {
+func customClient(options *input.Options) (*http.Client, error) {
 	transport := http.Transport{
 		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
 		Proxy:           http.ProxyFromEnvironment,
 		Dial: (&net.Dialer{
-			Timeout:   time.Duration(timeout) * time.Second,
+			Timeout:   time.Duration(options.Timeout) * time.Second,
 			KeepAlive: KeepAlive * time.Second,
 		}).Dial,
 		TLSHandshakeTimeout: TLSHandshakeTimeout * time.Second,
 	}
 
+	if options.Proxy != "" {
+		u, err := url.Parse(options.Proxy)
+		if err != nil {
+			return nil, err
+		}
+
+		transport.Proxy = http.ProxyURL(u)
+
+		if options.Verbose {
+			gologger.Debug().Msgf("Using Proxy %s", options.Proxy)
+		}
+	}
+
 	client := http.Client{
 		Transport: &transport,
-		Timeout:   time.Duration(timeout) * time.Second,
+		Timeout:   time.Duration(options.Timeout) * time.Second,
 	}
 
-	return &client
+	return &client, nil
 }
 
 func handleCidrInput(inputCidr string) ([]string, error) {
diff --git a/pkg/input/check.go b/pkg/input/check.go
index d017e2fe..9df026c5 100644
--- a/pkg/input/check.go
+++ b/pkg/input/check.go
@@ -9,6 +9,7 @@ package input
 import (
 	"errors"
 	"fmt"
+	"net/url"
 
 	fileutil "github.com/projectdiscovery/utils/file"
 )
@@ -36,5 +37,20 @@ func (options *Options) validateOptions() error {
 		return fmt.Errorf("rate limit: %w", ErrNegativeValue)
 	}
 
+	if options.Proxy != "" && !checkProxy(options.Proxy) {
+		_, err := url.Parse(options.Proxy)
+		return fmt.Errorf("proxy URL: %w", err)
+	}
+
 	return nil
 }
+
+func checkProxy(proxy string) bool {
+	if len(proxy) == 0 {
+		return false
+	}
+
+	_, err := url.Parse(proxy)
+
+	return err == nil
+}
diff --git a/pkg/input/flags.go b/pkg/input/flags.go
index cd4efaba..8e9555f4 100644
--- a/pkg/input/flags.go
+++ b/pkg/input/flags.go
@@ -37,6 +37,7 @@ type Options struct {
 	Timeout     int
 	Cidr        bool
 	RateLimit   int
+	Proxy       string
 }
 
 // configureOutput configures the output on the screen.
@@ -67,6 +68,7 @@ func ParseOptions() *Options {
 		flagSet.IntVarP(&options.Concurrency, "concurrency", "c", DefaultConcurrency, `Concurrency level`),
 		flagSet.IntVarP(&options.Timeout, "timeout", "t", DefaultTimeout, `Connection timeout in seconds`),
 		flagSet.IntVarP(&options.RateLimit, "rate-limit", "rl", DefaultRateLimit, `Set a rate limit (per second)`),
+		flagSet.StringVarP(&options.Proxy, "proxy", "px", "", `Set a proxy server (URL)`),
 	)
 
 	// Output
diff --git a/pkg/output/banner.go b/pkg/output/banner.go
index df31152f..8461d711 100644
--- a/pkg/output/banner.go
+++ b/pkg/output/banner.go
@@ -12,7 +12,7 @@ import "github.com/projectdiscovery/gologger"
 var printed = false
 
 const (
-	Version = "v0.1.0"
+	Version = "v0.1.1"
 	banner  = `    ____            _                          
    / __/___  __  __(_)_______  _________  ____ 
   / /_/ __ ` + `\/ | / / / ___/ _ \/ ___/ __ \/ __ \
diff --git a/snapcraft.yaml b/snapcraft.yaml
index af091440..c9b39af9 100644
--- a/snapcraft.yaml
+++ b/snapcraft.yaml
@@ -3,7 +3,7 @@ summary: Use favicon.ico to improve your target recon phase
 description: |
       Use favicon.ico to improve your target recon phase. 
       Quickly detect technologies, WAF, exposed panels, known services.
-version: 0.1.0
+version: 0.1.1
 grade: stable
 base: core20
 


Test patch: