From d8af60f9ee65f82f9c4c976ab688a7702b26c2d0 Mon Sep 17 00:00:00 2001 From: Jess Frazelle Date: Mon, 9 Jul 2018 11:40:45 -0400 Subject: [PATCH] add flags Signed-off-by: Jess Frazelle --- k8scan/main.go | 100 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 88 insertions(+), 12 deletions(-) diff --git a/k8scan/main.go b/k8scan/main.go index df031bb..49057c8 100644 --- a/k8scan/main.go +++ b/k8scan/main.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "encoding/json" "errors" + "flag" "fmt" "io/ioutil" "log" @@ -17,18 +18,56 @@ import ( "time" "github.com/Sirupsen/logrus" + mailgun "github.com/mailgun/mailgun-go" ) const ( - cidr = "0.0.0.0/0" + defaultCIDR = "0.0.0.0/0" arinAPIEndpoint = "http://whois.arin.net/rest/ip/%s" + + emailSender = "k8scan@jessfraz.com" ) var ( + timeoutPing time.Duration + timeoutGet time.Duration + + cidr string + ports = []int{80, 443, 9001, 8001} + + mailgunDomain string + mailgunAPIKey string + emailRecipient string + + debug bool ) +func init() { + flag.DurationVar(&timeoutPing, "timeout-ping", 2*time.Second, "Timeout for checking that the port is open") + flag.DurationVar(&timeoutGet, "timeout-get", 10*time.Second, "Timeout for getting the contents of the URL") + + flag.StringVar(&cidr, "cidr", defaultCIDR, "IP CIDR to scan") + + flag.StringVar(&mailgunAPIKey, "mailgun-api-key", "", "Mailgun API Key to use for sending email (optional)") + flag.StringVar(&mailgunDomain, "mailgun-domain", "", "Mailgun Domain to use for sending email (optional)") + flag.StringVar(&emailRecipient, "email-recipient", "", "Recipient for email notifications (optional)") + + flag.BoolVar(&debug, "d", false, "Run in debug mode") + + flag.Usage = func() { + flag.PrintDefaults() + } + + flag.Parse() + + // set log level + if debug { + logrus.SetLevel(logrus.DebugLevel) + } +} + func main() { // On ^C, or SIGTERM handle exit. c := make(chan os.Signal, 1) @@ -47,6 +86,9 @@ func main() { log.SetOutput(ioutil.Discard) logrus.Infof("Scanning for Kubernetes Dashboards and API Servers on %s over port range %#v", cidr, ports) + if len(mailgunDomain) > 0 && len(mailgunAPIKey) > 0 && len(emailRecipient) > 0 { + logrus.Infof("Using Mailgun Domain %s, API Key %s to send emails to %s", mailgunDomain, mailgunAPIKey, emailRecipient) + } logrus.Infof("This may take a bit...") startTime := time.Now() @@ -83,25 +125,31 @@ func scanIP(ip string, port int) { } // Check if it's a kubernetes dashboard. - ok = isKubernetesDashboard(ip, port) + ok, uri := isKubernetesDashboard(ip, port) if !ok { return } - fmt.Printf("%s:%d\n", ip, port) // Get the info for the ip address. info, err := getIPInfo(ip) if err != nil { logrus.Warnf("ip info err: %v", err) - return } + fmt.Printf("%s:%d\t%s\t%s\t%s\n", ip, port, info.Net.Organization.Handle, info.Net.Organization.Name, info.Net.Organization.Reference) + + // send an email + if len(mailgunDomain) > 0 && len(mailgunAPIKey) > 0 && len(emailRecipient) > 0 { + if err := sendEmail(uri, ip, port, info); err != nil { + logrus.Warn(err) + } + } } func portOpen(ip string, port int) bool { - c, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), 2*time.Second) + c, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), timeoutPing) if err != nil { // logrus.Warnf("listen at %s:%s failed: %v", ip, port, err) return false @@ -111,9 +159,9 @@ func portOpen(ip string, port int) bool { return true } -func isKubernetesDashboard(ip string, port int) bool { +func isKubernetesDashboard(ip string, port int) (bool, string) { client := &http.Client{ - Timeout: time.Second * 10, + Timeout: timeoutGet, Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, @@ -140,24 +188,23 @@ func isKubernetesDashboard(ip string, port int) bool { } if err != nil { //logrus.Warnf("getting %s:%s failed: %v", ip, port, err) - return false + return false, "" } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) if err != nil { - return false + return false, "" } body := strings.ToLower(string(b)) if (strings.Contains(body, "kubernetes") && strings.Contains(body, "dashboard")) || (strings.Contains(body, `"versions"`) && strings.Contains(body, `"serverAddress`)) || (strings.Contains(body, `"paths"`) && strings.Contains(body, `"/api"`)) { - logrus.Infof("uri: %s", uri) - return true + return true, uri } - return false + return false, "" } type ARINResponse struct { @@ -202,3 +249,32 @@ func inc(ip net.IP) { } } } + +func sendEmail(uri, ip string, port int, arinInfo ARINResponse) error { + mailgunClient := mailgun.NewMailgun(mailgunDomain, mailgunAPIKey, "") + + msg, _, err := mailgunClient.Send(mailgunClient.NewMessage( + /* From */ fmt.Sprintf("%s <%s>", emailSender, emailSender), + /* Subject */ fmt.Sprintf("[k8scan]: found dashboard %s", uri), + /* Body */ fmt.Sprintf(`Time: %s + +IP: %s:%d +URL: %s + +ARIN: %s + %s + %s +`, + time.Now().Format(time.UnixDate), + arinInfo.Net.Organization.Handle, + arinInfo.Net.Organization.Name, + arinInfo.Net.Organization.Reference, + ), + /* To */ emailRecipient, + )) + if err != nil { + return fmt.Errorf("sending Mailgun message failed: response: %#v error: %v", msg, err) + } + + return nil +}