From 5047064a017796e89bd4a3ebd5a0c29771d081ca Mon Sep 17 00:00:00 2001 From: C-Sto <7466346+C-Sto@users.noreply.github.com> Date: Fri, 17 Dec 2021 12:35:31 +0800 Subject: [PATCH 01/30] fart --- docker-compose.yaml | 2 +- libknary/certutil.go | 14 ++++++----- libknary/dns.go | 29 +++++++++++++-------- libknary/http.go | 3 ++- libknary/util.go | 60 ++++++++++++++++++++++++++++++++++++++++---- main.go | 29 +++++++++++++++------ 6 files changed, 107 insertions(+), 30 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index be58369..4956a37 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -10,7 +10,7 @@ services: # - DNS=true # - HTTP=true # - BIND_ADDR=127.0.0.1 - # - CANARY_DOMAIN=knary.tld + # - CANARY_DOMAIN=knary.tld,knary2.tld # (etc. etc.) build: . ports: diff --git a/libknary/certutil.go b/libknary/certutil.go index 45476d2..f1e258c 100644 --- a/libknary/certutil.go +++ b/libknary/certutil.go @@ -16,14 +16,16 @@ import ( // create domain list for certificates func getDomains() []string { var domainArray []string - domainArray = append(domainArray, "*."+os.Getenv("CANARY_DOMAIN")) + for _, cdomain := range GetDomains() { + domainArray = append(domainArray, "*."+cdomain) - if os.Getenv("BURP_DOMAIN") != "" { - domainArray = append(domainArray, "*."+os.Getenv("BURP_DOMAIN")) - } + if os.Getenv("BURP_DOMAIN") != "" { + domainArray = append(domainArray, "*."+cdomain) + } - if os.Getenv("DNS_SUBDOMAIN") != "" { - domainArray = append(domainArray, "*."+os.Getenv("DNS_SUBDOMAIN")+"."+os.Getenv("CANARY_DOMAIN")) + if os.Getenv("DNS_SUBDOMAIN") != "" { + domainArray = append(domainArray, "*."+os.Getenv("DNS_SUBDOMAIN")+"."+cdomain) + } } return domainArray } diff --git a/libknary/dns.go b/libknary/dns.go index 9313fac..10f02bb 100644 --- a/libknary/dns.go +++ b/libknary/dns.go @@ -72,14 +72,21 @@ func infoLog(ipaddr string, reverse string, name string) { } func goSendMsg(ipaddr, reverse, name, record string) bool { - if os.Getenv("DNS_SUBDOMAIN") != "" && - !stringContains(name, os.Getenv("DNS_SUBDOMAIN")+"."+os.Getenv("CANARY_DOMAIN")) { - // disregard unless subdomain we want to report on - return false + if os.Getenv("DNS_SUBDOMAIN") != "" { + found := false + for _, cdomain := range getDomains() { + if stringContains(name, os.Getenv("DNS_SUBDOMAIN")+"."+cdomain) { + // disregard unless subdomain we want to report on + found = true + } + } + if !found { + return false + } } if os.Getenv("DEBUG") == "true" { - Printy("Got A question for: " + name, 3) + Printy("Got A question for: "+name, 3) } if inBlacklist(name, ipaddr) { @@ -198,7 +205,8 @@ func parseDNS(m *dns.Msg, ipaddr string, EXT_IP string) { } case dns.TypeCNAME: - if strings.HasPrefix(strings.ToLower(q.Name), strings.ToLower(os.Getenv("CANARY_DOMAIN")+".")) { + if ok, _ := isRoot(q.Name); ok { + //if strings.HasPrefix(strings.ToLower(q.Name), strings.ToLower(os.Getenv("CANARY_DOMAIN")+".")) { // CNAME records cannot be returned for the root domain anyway. return } @@ -228,7 +236,8 @@ func parseDNS(m *dns.Msg, ipaddr string, EXT_IP string) { } if !foundInZone { - rr, _ := dns.NewRR(fmt.Sprintf("%s IN SOA %s %s (%s)", os.Getenv("CANARY_DOMAIN"), "ns."+os.Getenv("CANARY_DOMAIN"), "admin."+os.Getenv("CANARY_DOMAIN"), "2021041401 7200 3600 604800 300")) + //could probably return the query here rather than doxxing the first value in the monitored set, yolo + rr, _ := dns.NewRR(fmt.Sprintf("%s IN SOA %s %s (%s)", GetFirstDomain(), "ns."+GetFirstDomain(), "admin."+GetFirstDomain(), "2021041401 7200 3600 604800 300")) m.Answer = append(m.Answer, rr) } @@ -238,7 +247,7 @@ func parseDNS(m *dns.Msg, ipaddr string, EXT_IP string) { } if !foundInZone { - rr, _ := dns.NewRR(fmt.Sprintf("%s IN NS %s", q.Name, "ns."+os.Getenv("CANARY_DOMAIN"))) + rr, _ := dns.NewRR(fmt.Sprintf("%s IN NS %s", q.Name, "ns."+GetFirstDomain())) m.Answer = append(m.Answer, rr) } } @@ -311,9 +320,9 @@ func GuessIP(domain string) (string, error) { if IsIP(t.A.String()) { return t.A.String(), nil } else { - return "", errors.New("Couldn't get glue record for " + os.Getenv("CANARY_DOMAIN") + ". Have you configured a glue record for your domain? Has it propagated? You can set EXT_IP to bypass this but... do you know what you're doing?") + return "", errors.New("Couldn't get glue record for " + domain + ". Have you configured a glue record for your domain? Has it propagated? You can set EXT_IP to bypass this but... do you know what you're doing?") } } - return "", errors.New("Couldn't find glue record for " + os.Getenv("CANARY_DOMAIN") + ". You can set EXT_IP to bypass this but... do you know what you're doing?") + return "", errors.New("Couldn't find glue record for " + domain + ". You can set EXT_IP to bypass this but... do you know what you're doing?") } diff --git a/libknary/http.go b/libknary/http.go index d3df2f6..bf82df8 100644 --- a/libknary/http.go +++ b/libknary/http.go @@ -147,7 +147,8 @@ func handleRequest(conn net.Conn) bool { // search for our host header for _, header := range headers { - if stringContains(header, os.Getenv("CANARY_DOMAIN")) { + if ok, _ := containsSuffix(header); ok { + //if stringContains(header, os.Getenv("CANARY_DOMAIN")) { // a match made in heaven host := "" query := "" diff --git a/libknary/util.go b/libknary/util.go index ac45a70..3a4d6af 100644 --- a/libknary/util.go +++ b/libknary/util.go @@ -23,6 +23,48 @@ type blacklist struct { deny map[string]time.Time } +//domains to monitor +var domains []string + +func LoadDomains(domainlist string) error { + domains = strings.Split(domainlist, ",") + return nil +} + +func GetDomains() []string { + return domains +} + +func GetFirstDomain() string { + return domains[0] +} + +func containsSuffix(lookupval string) (bool, error) { + if len(domains) == 0 { + //FU + return false, fmt.Errorf("no domains to check") + } + for _, suffix := range domains { + if strings.HasSuffix(strings.ToLower(lookupval), strings.ToLower(suffix)) { + return true, nil + } + } + return false, nil +} + +func isRoot(lookupval string) (bool, error) { + if len(domains) == 0 { + //FU + return false, fmt.Errorf("no domains to check") + } + for _, prefix := range domains { + if strings.HasPrefix(strings.ToLower(lookupval), strings.ToLower(prefix+".")) { + return true, nil + } + } + return false, nil +} + var denied = blacklist{deny: make(map[string]time.Time)} var blacklistCount = 0 @@ -316,15 +358,23 @@ func HeartBeat(version string, firstrun bool) (bool, error) { // print usage domains if os.Getenv("HTTP") == "true" && (os.Getenv("TLS_CRT") == "" || os.Getenv("TLS_KEY") == "") { - beatMsg += "Listening for http://*." + os.Getenv("CANARY_DOMAIN") + " requests\n" + for _, cdomain := range getDomains() { + beatMsg += "Listening for http://*." + cdomain + " requests\n" + } } else { - beatMsg += "Listening for http(s)://*." + os.Getenv("CANARY_DOMAIN") + " requests\n" + for _, cdomain := range getDomains() { + beatMsg += "Listening for http(s)://*." + cdomain + " requests\n" + } } if os.Getenv("DNS") == "true" { - if os.Getenv("DNS_SUBDOMAIN") != "" { - beatMsg += "Listening for *." + os.Getenv("DNS_SUBDOMAIN")+"."+os.Getenv("CANARY_DOMAIN") + " DNS requests\n" + if os.Getenv("DNS_SUBDOMAIN") != "" { + for _, cdomain := range getDomains() { + beatMsg += "Listening for *." + os.Getenv("DNS_SUBDOMAIN") + "." + cdomain + " DNS requests\n" + } } else { - beatMsg += "Listening for *." + os.Getenv("CANARY_DOMAIN") + " DNS requests\n" + for _, cdomain := range getDomains() { + beatMsg += "Listening for *." + cdomain + " DNS requests\n" + } } } if os.Getenv("BURP_DOMAIN") != "" { diff --git a/main.go b/main.go index 4419bd2..a05cfe5 100644 --- a/main.go +++ b/main.go @@ -29,6 +29,11 @@ func main() { log.Fatal(err) } + err = libknary.LoadDomains(os.Getenv("CANARY_DOMAIN")) + if err != nil { + log.Fatal(err) + } + // start maintenance timers libknary.StartMaintenance(VERSION, GITHUBVERSION, GITHUB) @@ -36,7 +41,7 @@ func main() { var EXT_IP string if os.Getenv("EXT_IP") == "" { // try to guess the glue record - res, err := libknary.GuessIP(os.Getenv("CANARY_DOMAIN")) + res, err := libknary.GuessIP(libknary.GetFirstDomain()) if err != nil { libknary.Printy("Are you sure your DNS is configured correctly?", 2) @@ -82,16 +87,24 @@ func main() { go libknary.UsageStats(VERSION) if os.Getenv("HTTP") == "true" && os.Getenv("LETS_ENCRYPT") == "" && (os.Getenv("TLS_CRT") == "" || os.Getenv("TLS_KEY") == "") { - libknary.Printy("Listening for http://*."+os.Getenv("CANARY_DOMAIN")+" requests", 1) + for _, cdomain := range libknary.GetDomains() { + libknary.Printy("Listening for http://*."+cdomain+" requests", 1) + } libknary.Printy("Without LETS_ENCRYPT or TLS_* environment variables set you will only be able to make HTTP (port 80) requests to knary", 2) } else if os.Getenv("HTTP") == "true" && (os.Getenv("LETS_ENCRYPT") != "" || os.Getenv("TLS_KEY") != "") { - libknary.Printy("Listening for http(s)://*."+os.Getenv("CANARY_DOMAIN")+" requests", 1) + for _, cdomain := range libknary.GetDomains() { + libknary.Printy("Listening for http(s)://*."+cdomain+" requests", 1) + } } if os.Getenv("DNS") == "true" { - if os.Getenv("DNS_SUBDOMAIN") != "" { - libknary.Printy("Listening for *."+os.Getenv("DNS_SUBDOMAIN")+"."+os.Getenv("CANARY_DOMAIN")+" DNS requests", 1) + if os.Getenv("DNS_SUBDOMAIN") != "" { + for _, cdomain := range libknary.GetDomains() { + libknary.Printy("Listening for *."+os.Getenv("DNS_SUBDOMAIN")+"."+cdomain+" DNS requests", 1) + } } else { - libknary.Printy("Listening for *."+os.Getenv("CANARY_DOMAIN")+" DNS requests", 1) + for _, cdomain := range libknary.GetDomains() { + libknary.Printy("Listening for *."+cdomain+" DNS requests", 1) + } } } if os.Getenv("BURP_DOMAIN") != "" { @@ -124,7 +137,9 @@ func main() { wg.Add(1) // https://bl.ocks.org/tianon/063c8083c215be29b83a // There must be a better way to pass "EXT_IP" along without an anonymous function AND copied variable - dns.HandleFunc(os.Getenv("CANARY_DOMAIN")+".", func(w dns.ResponseWriter, r *dns.Msg) { libknary.HandleDNS(w, r, EXT_IP) }) + for _, cdomain := range libknary.GetDomains() { + dns.HandleFunc(cdomain+".", func(w dns.ResponseWriter, r *dns.Msg) { libknary.HandleDNS(w, r, EXT_IP) }) + } go libknary.AcceptDNS(&wg) } From fdefce556ec7b036eed951e392b617320405eb13 Mon Sep 17 00:00:00 2001 From: Ricardo Iramar dos Santos Date: Sat, 18 Dec 2021 19:07:22 -0300 Subject: [PATCH 02/30] Support telegram notification --- libknary/webhooks.go | 9 +++++++++ main.go | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/libknary/webhooks.go b/libknary/webhooks.go index c0e1c1e..5a28bd0 100644 --- a/libknary/webhooks.go +++ b/libknary/webhooks.go @@ -34,6 +34,15 @@ func sendMsg(msg string) { } } + if os.Getenv("TELEGRAM_CHATID") != "" && os.Getenv("TELEGRAM_BOT_TOKEN") != "" { + jsonMsg := []byte(`{"chat_id": "` + os.Getenv("TELEGRAM_CHATID") + `", "text": "` + msg + `"}`) + _, err := http.Post("https://api.telegram.org/bot" + os.Getenv("TELEGRAM_BOT_TOKEN") + "/sendMessage", "application/json", bytes.NewBuffer(jsonMsg)) + + if err != nil { + Printy(err.Error(), 2) + } + } + if os.Getenv("LARK_WEBHOOK") != "" { re = regexp.MustCompile("```\\n?") msg = re.ReplaceAllString(msg, "") diff --git a/main.go b/main.go index 4419bd2..a24e4a1 100644 --- a/main.go +++ b/main.go @@ -15,7 +15,7 @@ import ( ) const ( - VERSION = "3.3.1" + VERSION = "3.3.2" GITHUB = "https://github.com/sudosammy/knary" GITHUBVERSION = "https://raw.githubusercontent.com/sudosammy/knary/master/VERSION" ) @@ -116,6 +116,9 @@ func main() { if os.Getenv("LARK_WEBHOOK") != "" { libknary.Printy("Posting to webhook: "+os.Getenv("LARK_WEBHOOK"), 1) } + if os.Getenv("TELEGRAM_CHATID") != "" { + libknary.Printy("Posting to Telegram Chat ID: "+os.Getenv("TELEGRAM_CHATID"), 1) + } // setup waitgroups for DNS/HTTP go routines var wg sync.WaitGroup // there isn't actually any clean exit option, so we can just wait forever From 7d0169176cd482b43a2c3becc7117048532dfde6 Mon Sep 17 00:00:00 2001 From: Ricardo Iramar dos Santos Date: Sat, 18 Dec 2021 19:32:08 -0300 Subject: [PATCH 03/30] Support telegram notification --- libknary/webhooks.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libknary/webhooks.go b/libknary/webhooks.go index 5a28bd0..2e0cd71 100644 --- a/libknary/webhooks.go +++ b/libknary/webhooks.go @@ -35,6 +35,9 @@ func sendMsg(msg string) { } if os.Getenv("TELEGRAM_CHATID") != "" && os.Getenv("TELEGRAM_BOT_TOKEN") != "" { + re = regexp.MustCompile("```\\n?") + msg = re.ReplaceAllString(msg, "") + jsonMsg := []byte(`{"chat_id": "` + os.Getenv("TELEGRAM_CHATID") + `", "text": "` + msg + `"}`) _, err := http.Post("https://api.telegram.org/bot" + os.Getenv("TELEGRAM_BOT_TOKEN") + "/sendMessage", "application/json", bytes.NewBuffer(jsonMsg)) From 0cbf4f187ab971954c4196db5cf8fa2288ccd9be Mon Sep 17 00:00:00 2001 From: Ricardo Iramar dos Santos Date: Sat, 18 Dec 2021 19:42:13 -0300 Subject: [PATCH 04/30] Support telegram notification --- libknary/webhooks.go | 1 + 1 file changed, 1 insertion(+) diff --git a/libknary/webhooks.go b/libknary/webhooks.go index 2e0cd71..bcf6cc3 100644 --- a/libknary/webhooks.go +++ b/libknary/webhooks.go @@ -35,6 +35,7 @@ func sendMsg(msg string) { } if os.Getenv("TELEGRAM_CHATID") != "" && os.Getenv("TELEGRAM_BOT_TOKEN") != "" { + msg = strings.ReplaceAll(msg, "```From:", "\nFrom:") re = regexp.MustCompile("```\\n?") msg = re.ReplaceAllString(msg, "") From ffcbe3fb3ef0f9aacfbe14175d10bb7afb297fff Mon Sep 17 00:00:00 2001 From: Ricardo Iramar dos Santos Date: Sat, 18 Dec 2021 19:48:33 -0300 Subject: [PATCH 05/30] Support telegram notification --- README.md | 2 ++ VERSION | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cc3995..ad63c49 100644 --- a/README.md +++ b/README.md @@ -76,3 +76,5 @@ These are environment variables / `.env` file configurations. You can configure * `PUSHOVER_USER` The user token of the Pushover user you want knary to notify * `LARK_WEBHOOK` The full URL of the [webhook](https://www.feishu.cn/hc/en-US/articles/360024984973-Bot-Use-bots-in-groups) for the Lark/Feishu bot you want knary to notify * `LARK_SECRET` The [secret token](https://www.feishu.cn/hc/en-US/articles/360024984973-Bot-Use-bots-in-groups) used to sign messages to your Lark/Feishu bot +* `TELEGRAM_CHATID` The [Telegram Bot](https://core.telegram.org/bots) chat ID you want knary to notify +* `TELEGRAM_BOT_TOKEN` The Telegram Bot token diff --git a/VERSION b/VERSION index 712bd5a..5436ea0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.3.1 \ No newline at end of file +3.3.2 \ No newline at end of file From 3e4ed3223690d8cfa4b93d69ef352114972cd4e9 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Tue, 28 Dec 2021 13:29:46 +0800 Subject: [PATCH 06/30] begin allowlist functions --- examples/README.md | 1 + libknary/util.go | 72 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/examples/README.md b/examples/README.md index 827ebc4..3e36d6f 100644 --- a/examples/README.md +++ b/examples/README.md @@ -17,6 +17,7 @@ * `LETS_ENCRYPT` Enable Let's Encrypt management of your knary domain. If you do not configure this, or `TLS_*` as [detailed below](#optional-configurations), knary will only listen on port 80 and notify of HTTP hits. Example input: `myemailaddress@gmail.com` * `LOG_FILE` Location for a file that knary will log greppable and timestamped warnings/errors. Example input: `/var/log/knary.log` or `knary.log` for current working directory * `DENYLIST_FILE` Location for a file containing case-insensitive subdomains or IP addresses (separated by newlines) that should be ignored by knary and not logged or notified. Example input: `denylist.txt` +* `ALLOWLIST_FILE` Rather then denying certain matches, you can specify exact matches knary should alert on. This configuration takes precedence over a denylist. Location for a file containing case-insensitive subdomains (separated by newlines) that should trigger knary. Example input: `allowed.txt` ## Likely Recommended Optional Configurations * `DNS_SUBDOMAIN` Tell knary to only notify on `*..` DNS hits. This is useful if you your webhook is getting too noisy with DNS hits to your knary TLD. Setting this configuration will mimic how knary operated prior to version 3. Example input: `dns` diff --git a/libknary/util.go b/libknary/util.go index ac45a70..debac3d 100644 --- a/libknary/util.go +++ b/libknary/util.go @@ -33,7 +33,6 @@ func (a *blacklist) updateD(term string) bool { } item := standerdiseDenylistItem(term) a.mutex.Lock() - //a.deny[item] = time.Now() a.deny[item] = time.Now() a.mutex.Unlock() return true @@ -51,6 +50,44 @@ func (a *blacklist) searchD(term string) bool { return false } +/* + +Allowlist WIP functions + +*/ +// map for allowlist +type allowlist struct { + mutex sync.Mutex + deny map[string]time.Time +} + +var allowed = allowlist{deny: make(map[string]time.Time)} +var allowCount = 0 + +// add or update a denied domain/IP +func (a *blacklist) updateA(term string) bool { + if term == "" { + return false // would happen if there's no X-Forwarded-For header + } + item := standerdiseDenylistItem(term) + a.mutex.Lock() + a.deny[item] = time.Now() + a.mutex.Unlock() + return true +} + +// search for a denied domain/IP +func (a *blacklist) searchA(term string) bool { + item := standerdiseDenylistItem(term) + a.mutex.Lock() + defer a.mutex.Unlock() + + if _, ok := a.deny[item]; ok { + return true // found! + } + return false +} + func standerdiseDenylistItem(term string) string { d := strings.ToLower(term) // lowercase d = strings.TrimSpace(d) // remove any surrounding whitespaces @@ -210,6 +247,39 @@ func LoadBlacklist() (bool, error) { return true, nil } +/* + +Allowlist WIP functions + +*/ +func LoadAllowlist() (bool, error) { + // load denylist file into struct on startup + if _, err := os.Stat(os.Getenv("ALLOWLIST_FILE")); os.IsNotExist(err) { + return false, err + } + + alwlist, err := os.Open(os.Getenv("ALLOWLIST_FILE")) + defer alwlist.Close() + + if err != nil { + Printy(err.Error()+" - ignoring", 3) + return false, err + } + + scanner := bufio.NewScanner(alwlist) + + for scanner.Scan() { // foreach denied item + if scanner.Text() != "" { + denied.updateD(scanner.Text()) + blacklistCount++ + } + } + + Printy("Monitoring "+strconv.Itoa(blacklistCount)+" items in denylist", 1) + logger("INFO", "Monitoring "+strconv.Itoa(blacklistCount)+" items in denylist") + return true, nil +} + func checkLastHit() bool { // this runs once a day for subdomain := range denied.deny { expiryDate := denied.deny[subdomain].AddDate(0, 0, 14) From a7473e775aadfd153295762b5eaa6f8486b9cdd2 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Tue, 28 Dec 2021 22:11:39 +0800 Subject: [PATCH 07/30] begin multidomain LE support --- README.md | 19 ++++++++++++------- examples/README.md | 3 ++- examples/multidomain_env | 11 +++++++++++ libknary/certbot.go | 18 +++++++++--------- libknary/certutil.go | 32 +++++++++++++++++++++++++------- libknary/dns.go | 2 +- libknary/util.go | 10 +++++----- 7 files changed, 65 insertions(+), 30 deletions(-) create mode 100644 examples/multidomain_env diff --git a/README.md b/README.md index ad63c49..ea4429d 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,7 @@ >Like "Canary" but more hipster, which means better 😎😎😎 -⚠️ **Note: Upgrading from version 2? You need to change your DNS setup to make use of new knary features. See step [#2 and #3](#setup) below. You may also want to configure [DNS_SUBDOMAIN](https://github.com/sudosammy/knary/tree/master/examples#likely-recommended-optional-configurations) to mimic how knary operated previously.** ⚠️ - -knary is a canary token server that notifies a Slack/Discord/Teams/Lark channel (or other webhook) when incoming HTTP(S) or DNS requests match a given domain or any of its subdomains. It also supports functionality useful in offensive engagements including subdomain denylisting, working with Burp Collaborator, and easy TLS certificate creation. +knary is a canary token server that notifies a Slack/Discord/Teams/Lark channel (or other webhook) when incoming HTTP(S) or DNS requests match a given domain or any of its subdomains. It also supports functionality useful in offensive engagements including subdomain allow/denylisting, working with Burp Collaborator, and easy TLS certificate creation. ![knary canary-ing](https://github.com/sudosammy/knary/raw/master/screenshots/canary.gif "knary canary-ing") @@ -45,21 +43,28 @@ If your registry requires you to have multiple nameservers with different IP add ![knary go-ing](https://github.com/sudosammy/knary/raw/master/screenshots/run.png "knary go-ing") -## Denying matches +## Allowing or denying matches You **will** find systems that spam your knary even long after an engagement has ended. You will also find several DNS requests to mundane subdomains hitting your knary every day. To stop these from cluttering your notifications knary has two features: -1. A simple text-based denylist (location specified with `DENYLIST_FILE`). Add the offending subdomains or IP addresses separated by a newline (case-insensitive): +1. A simple text-based deny- and/or allowlist (location specified with `DENYLIST_FILE` or `ALLOWLIST_FILE`). Add the offending subdomains or IP addresses separated by a newline (case-insensitive): ``` knary.tld www.knary.tld 171.244.140.247 test.dns.knary.tld +engagement1337.knary.tld ``` -This would stop knary from alerting on `www.knary.tld` but not `another.www.knary.tld`. **Note:** wildcards are not supported. An entry of `*.knary.tld` will match that string exactly. +If this were a denylist, it would stop knary from alerting on `www.knary.tld` but not `another.www.knary.tld`. + +If this were an allowlist, knary would alert on exact matches such as `engagement1337.knary.tld` and subdomain matches `another.engagement1337.knary.tld`. + +You can use both a deny- and allowlist simultaneously. The allowlist takes precedence. + +**Note:** wildcards are not supported. An entry of `*.knary.tld` will match that string exactly. 2. The `DNS_SUBDOMAIN` configuration allows you to specify that knary should only alert on DNS hits that are `*..knary.tld`. -A configuration of `DNS_SUBDOMAIN=dns` would stop knary from alerting on DNS hits to `blah.knary.tld` but not `blah.dns.knary.tld`. This configuration only affects DNS traffic. A HTTP request to `blah.knary.tld` would still notify you unless prevented by the denylist. Use a combination of both deny methods if you wish to prevent this. +A configuration of `DNS_SUBDOMAIN=dns` would stop knary from alerting on DNS hits to `blah.knary.tld` but not `blah.dns.knary.tld`. This configuration only affects DNS traffic. A HTTP request to `blah.knary.tld` would still notify you unless prevented by an allow- or denylist. Sample configurations can be found [in the examples](https://github.com/sudosammy/knary/tree/master/examples) with common subdomains to deny. diff --git a/examples/README.md b/examples/README.md index 3e36d6f..fcad35e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -3,6 +3,7 @@ ## Sample Files * `default_env` - A recommended quick start configuration file with Let's Encrypt configuration. * `burp_env` - A recommended quick start configuration file if you are also using Burp Collaborator on the same server as knary. +* `multidomain_env` - A recommended quick start configuration file if you are using knary with several domains. * `denylist.txt` - This is a good starting set of subdomains you should consider denying from notifying your webhook. Setting [DNS_SUBDOMAIN](#likely-recommended-optional-configurations) will cut down the noise to your knary too. Find & Replace `knary.tld` with your knary domain. * `zone_file.txt` - Although an uncommon configuration, this file demonstrates the proper format for configuring a Zone file for custom responses to DNS queries made to knary. @@ -10,7 +11,7 @@ * `DNS` Enable/Disable the DNS canary (true/false) * `HTTP` Enable/Disable the HTTP canary (true/false) * `BIND_ADDR` The IP address you want knary to listen on. Example input: `0.0.0.0` to bind to all addresses available -* `CANARY_DOMAIN` The domain + TLD to match canary hits on. Example input: `mycanary.com` (knary will match `*.mycanary.com`) +* `CANARY_DOMAIN` The domain + TLD to match canary hits on. Example input: `mycanary.com` (knary will match `*.mycanary.com`). Multiple domains can be provided comma-delimited. Example input: `mycanary.com,knarytwo.zyz,knary3.io` * `*_WEBHOOK` One (or many) webhooks for knary to alert. Refer to the [webhook section in the README](https://github.com/sudosammy/knary#supported-webhook-configurations) for options ## Recommended Optional Configurations diff --git a/examples/multidomain_env b/examples/multidomain_env new file mode 100644 index 0000000..4c123cd --- /dev/null +++ b/examples/multidomain_env @@ -0,0 +1,11 @@ +# RENAME ME TO .env +DNS=true +HTTP=true +BIND_ADDR=0.0.0.0 +CANARY_DOMAIN=knary.tld,myknary.com,otherknary.io +LETS_ENCRYPT= +SLACK_WEBHOOK= + +DEBUG=false +LOG_FILE=knary.log +DENYLIST_FILE=denylist.txt diff --git a/libknary/certbot.go b/libknary/certbot.go index bed488e..00ee4ae 100644 --- a/libknary/certbot.go +++ b/libknary/certbot.go @@ -129,25 +129,25 @@ func StartLetsEncrypt() string { certsStorage := cmd.NewCertificatesStorage() // should only request certs if currently none exist - if fileExists(certsStorage.GetFileName(getDomains()[0], ".key")) && - fileExists(certsStorage.GetFileName(getDomains()[0], ".crt")) { + if fileExists(certsStorage.GetFileName(GetFirstDomain(), ".key")) && + fileExists(certsStorage.GetFileName(GetFirstDomain(), ".crt")) { if os.Getenv("DEBUG") == "true" { - Printy("TLS private key found: "+certsStorage.GetFileName(getDomains()[0], ".key"), 3) - Printy("TLS certificate found: "+certsStorage.GetFileName(getDomains()[0], ".crt"), 3) + Printy("TLS private key found: "+certsStorage.GetFileName(GetFirstDomain(), ".key"), 3) + Printy("TLS certificate found: "+certsStorage.GetFileName(GetFirstDomain(), ".crt"), 3) } - return cmd.SanitizedDomain(getDomains()[0]) + return cmd.SanitizedDomain(GetFirstDomain()) } if os.Getenv("DEBUG") == "true" { Printy("No existing certificates found at:", 3) - Printy(certsStorage.GetFileName(getDomains()[0], ".key"), 2) - Printy(certsStorage.GetFileName(getDomains()[0], ".crt"), 2) + Printy(certsStorage.GetFileName(GetFirstDomain(), ".key"), 2) + Printy(certsStorage.GetFileName(GetFirstDomain(), ".crt"), 2) Printy("Let's Encrypt ourselves some new ones!", 3) } request := certificate.ObtainRequest{ - Domains: getDomains(), + Domains: getDomainsForCert(), Bundle: true, } certificates, err := client.Certificate.Obtain(request) @@ -195,7 +195,7 @@ func renewLetsEncrypt() { } client.Challenge.SetDNS01Provider(knaryDNS) - certDomains := getDomains() + certDomains := getDomainsForCert() certsStorage := cmd.NewCertificatesStorage() var privateKey crypto.PrivateKey diff --git a/libknary/certutil.go b/libknary/certutil.go index f1e258c..4f7da3d 100644 --- a/libknary/certutil.go +++ b/libknary/certutil.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "strings" + "strconv" "time" "github.com/go-acme/lego/v4/certcrypto" @@ -14,19 +15,36 @@ import ( ) // create domain list for certificates -func getDomains() []string { +func getDomainsForCert() []string { var domainArray []string - for _, cdomain := range GetDomains() { - domainArray = append(domainArray, "*."+cdomain) + var numDomains = 0 - if os.Getenv("BURP_DOMAIN") != "" { - domainArray = append(domainArray, "*."+cdomain) - } + for _, cdomain := range GetDomains() { + domainArray = append(domainArray, cdomain) + numDomains++ if os.Getenv("DNS_SUBDOMAIN") != "" { - domainArray = append(domainArray, "*."+os.Getenv("DNS_SUBDOMAIN")+"."+cdomain) + domainArray = append(domainArray, os.Getenv("DNS_SUBDOMAIN")+"."+cdomain) + numDomains++ } } + + if os.Getenv("BURP_DOMAIN") != "" { + domainArray = append(domainArray, os.Getenv("BURP_DOMAIN")) + numDomains++ + } + + if os.Getenv("DEBUG") == "true" { + Printy("Domains for SAN certificate: "+strconv.Itoa(numDomains), 3) + } + + + if (numDomains > 100) { + msg := "Too many domains! Let's Encrypt only supports SAN certificates containing up to 100 domains & subdomains. Your configuration currently has: "+strconv.Itoa(numDomains)+". This may be due to configuring DNS_SUBDOMAIN which will double the number of SAN entries per knary domain." + logger("ERROR", msg) + GiveHead(2) + log.Fatal(msg) + } return domainArray } diff --git a/libknary/dns.go b/libknary/dns.go index 10f02bb..857f70c 100644 --- a/libknary/dns.go +++ b/libknary/dns.go @@ -74,7 +74,7 @@ func infoLog(ipaddr string, reverse string, name string) { func goSendMsg(ipaddr, reverse, name, record string) bool { if os.Getenv("DNS_SUBDOMAIN") != "" { found := false - for _, cdomain := range getDomains() { + for _, cdomain := range GetDomains() { if stringContains(name, os.Getenv("DNS_SUBDOMAIN")+"."+cdomain) { // disregard unless subdomain we want to report on found = true diff --git a/libknary/util.go b/libknary/util.go index d4c6316..8630d45 100644 --- a/libknary/util.go +++ b/libknary/util.go @@ -428,21 +428,21 @@ func HeartBeat(version string, firstrun bool) (bool, error) { // print usage domains if os.Getenv("HTTP") == "true" && (os.Getenv("TLS_CRT") == "" || os.Getenv("TLS_KEY") == "") { - for _, cdomain := range getDomains() { + for _, cdomain := range GetDomains() { beatMsg += "Listening for http://*." + cdomain + " requests\n" } - } else { - for _, cdomain := range getDomains() { + } else if (os.Getenv("HTTP") == "true" && (os.Getenv("TLS_CRT") != "" && os.Getenv("TLS_KEY") != "")) { + for _, cdomain := range GetDomains() { beatMsg += "Listening for http(s)://*." + cdomain + " requests\n" } } if os.Getenv("DNS") == "true" { if os.Getenv("DNS_SUBDOMAIN") != "" { - for _, cdomain := range getDomains() { + for _, cdomain := range GetDomains() { beatMsg += "Listening for *." + os.Getenv("DNS_SUBDOMAIN") + "." + cdomain + " DNS requests\n" } } else { - for _, cdomain := range getDomains() { + for _, cdomain := range GetDomains() { beatMsg += "Listening for *." + cdomain + " DNS requests\n" } } From e2266e9ddc0cd47aae70f59b66ce5412a5334840 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Tue, 28 Dec 2021 22:28:25 +0800 Subject: [PATCH 08/30] undo wildcard break --- libknary/certutil.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libknary/certutil.go b/libknary/certutil.go index 4f7da3d..dd8bc52 100644 --- a/libknary/certutil.go +++ b/libknary/certutil.go @@ -20,17 +20,17 @@ func getDomainsForCert() []string { var numDomains = 0 for _, cdomain := range GetDomains() { - domainArray = append(domainArray, cdomain) + domainArray = append(domainArray, "*."+cdomain) numDomains++ if os.Getenv("DNS_SUBDOMAIN") != "" { - domainArray = append(domainArray, os.Getenv("DNS_SUBDOMAIN")+"."+cdomain) + domainArray = append(domainArray, "*."+os.Getenv("DNS_SUBDOMAIN")+"."+cdomain) numDomains++ } } if os.Getenv("BURP_DOMAIN") != "" { - domainArray = append(domainArray, os.Getenv("BURP_DOMAIN")) + domainArray = append(domainArray, "*."+os.Getenv("BURP_DOMAIN")) numDomains++ } From b0264230bcf9f8df13522f554de25897449020c0 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Wed, 29 Dec 2021 00:40:28 +0800 Subject: [PATCH 09/30] multidomain support --- README.md | 22 +++++++++++++--------- libknary/certutil.go | 2 +- libknary/dns.go | 6 ++++-- libknary/http.go | 3 +-- libknary/util.go | 16 +++++++--------- 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index ea4429d..5e9db68 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ >Like "Canary" but more hipster, which means better 😎😎😎 -knary is a canary token server that notifies a Slack/Discord/Teams/Lark channel (or other webhook) when incoming HTTP(S) or DNS requests match a given domain or any of its subdomains. It also supports functionality useful in offensive engagements including subdomain allow/denylisting, working with Burp Collaborator, and easy TLS certificate creation. +knary is a canary token server that notifies a Slack/Discord/Teams/Lark/Telegram channel (or other webhook) when incoming HTTP(S) or DNS requests match a given domain or any of its subdomains. It also supports functionality useful in offensive engagements including subdomain allow/denylisting, working with Burp Collaborator, and automatic TLS certificate creation with Let's Encrypt. ![knary canary-ing](https://github.com/sudosammy/knary/raw/master/screenshots/canary.gif "knary canary-ing") @@ -23,23 +23,23 @@ __Prerequisite:__ You need Go >=1.16 to build knary. go get -u github.com/sudosammy/knary ``` -2. Set your chosen knary domain nameserver(s) to point to a subdomain under itself; such as `ns.knary.tld`. If required, set multiple nameserver records such as `ns1.knary.tld`, `ns2.knary.ltd`. +**Important:** The specifics of how to perform the next two steps will depend on your domain registrar. Google `How to set Glue Record on ` to get started. Ultimately, you need to configure your knary domain(s) to make use of itself as the nameserver (i.e. `ns1.knary.tld` and `ns2.knary.tld`) and configure Glue Records to point these nameservers back to your knary host. You may need to raise a support ticket to have this performed by your registrar. -3. Create a "Glue Record", sometimes referred to as "Nameserver Registration" or "Nameserver IP address" to point to your knary server. This is what it looks like in `name.com`: +2. Set your chosen knary domain(s) nameserver(s) to point to a subdomain under itself; such as `ns.knary.tld`. If required, set multiple nameserver records such as `ns1` and `ns2`. - ![Setting a glue record](https://github.com/sudosammy/knary/raw/master/screenshots/nameserver-ip.png "Setting a glue record") +3. Create a "Glue Record" (sometimes referred to as "Nameserver Registration" or "Nameserver IP address") to point to your knary server. This is what it looks like in `name.com`: -If your registry requires you to have multiple nameservers with different IP addresses, set the second nameserver to an IP address such as `8.8.8.8` or `1.1.1.1`. + ![Setting a glue record](https://github.com/sudosammy/knary/raw/master/screenshots/nameserver-ip.png "Setting a glue record") -**Note:** You may need to raise a support ticket to have step #2 and #3 performed by your registrar. +If your registry requires you to have multiple nameservers with **different** IP addresses, set the second nameserver to an IP address such as `8.8.8.8` or `1.1.1.1`. -4. This will take some time to propagate, so go setup your [webhook](#supported-webhook-configurations). +4. This **will** take time to propagate, so go setup your [webhook(s)](#supported-webhook-configurations) while you wait. You can use [this tool](https://www.whatsmydns.net/#NS/) to check the propagation. Within a few hours you should see some DNS servers reflecting your knary domain as the nameserver. 5. Create a `.env` file in the same directory as the knary binary and [configure](https://github.com/sudosammy/knary/tree/master/examples) it as necessary. You can also use environment variables to set these configurations. Environment variables will take precedence over the `.env` file. -6. __Optional__ For accepting TLS (HTTPS) connections set the `LETS_ENCRYPT=` variable and knary will automagically manage wildcard certificates for you. Otherwise, you can specify the path to your own certificates with `TLS_CRT=` and `TLS_KEY=`. +6. __Optional__ For accepting TLS (HTTPS) connections set the `LETS_ENCRYPT=` variable and knary will automagically manage wildcard certificates for you (see [OPSEC note](#opsec-notes) below). Otherwise, you can specify the path to your own certificates with `TLS_CRT=` and `TLS_KEY=`. -7. Run the binary (probably in `screen`, `tmux`, or similar) and hope for output that looks something like this: +7. Run the binary (via the provided [Docker container](#knary-docker), or in `tmux` / `screen`) and hope for output that looks something like this: ![knary go-ing](https://github.com/sudosammy/knary/raw/master/screenshots/run.png "knary go-ing") @@ -71,6 +71,10 @@ Sample configurations can be found [in the examples](https://github.com/sudosamm ## knary Docker Using knary in a container is as simple as creating your `.env` file (or setting environment variables in the `docker-compose.yaml` file) and running `sudo docker compose up -d` +## OPSEC notes +* Let's Encrypt will dox all the domains you are using with knary (and your `DNS_SUBDOMAIN` and `BURP_DOMAIN` if you are using those configurations). This is due to these domains being included in the SAN certificate generated for you. A remote adversary can read the certificate and extract the list of domains within it. To avoid this, don't configure `LETS_ENCRYPT`. You can use self-signed certificates with `TLS_CRT=` and `TLS_KEY=`; however, many hosts will refuse to connect reducing your visibility of incoming HTTPS connections. +* With enough effort, knary is likely fingerprint-able by a remote host. i.e. it's plausible an adversary could determine you are running knary on a given host. This is because knary is not an RFC compliant nameserver (because doing so involves dark magic) and it likely behaves in an unusual / unique manner when compared to other nameservers. + ## Supported Webhook Configurations These are environment variables / `.env` file configurations. You can configure none, one, or many. Most common usage would be to configure one. Refer to [the examples](https://github.com/sudosammy/knary/tree/master/examples) for usage help. diff --git a/libknary/certutil.go b/libknary/certutil.go index dd8bc52..9638f11 100644 --- a/libknary/certutil.go +++ b/libknary/certutil.go @@ -40,7 +40,7 @@ func getDomainsForCert() []string { if (numDomains > 100) { - msg := "Too many domains! Let's Encrypt only supports SAN certificates containing up to 100 domains & subdomains. Your configuration currently has: "+strconv.Itoa(numDomains)+". This may be due to configuring DNS_SUBDOMAIN which will double the number of SAN entries per knary domain." + msg := "Too many domains! Let's Encrypt only supports SAN certificates containing 100 domains & subdomains. Your configuration currently has: "+strconv.Itoa(numDomains)+". This may be due to configuring DNS_SUBDOMAIN which will double the number of SAN entries per knary domain." logger("ERROR", msg) GiveHead(2) log.Fatal(msg) diff --git a/libknary/dns.go b/libknary/dns.go index 857f70c..af96971 100644 --- a/libknary/dns.go +++ b/libknary/dns.go @@ -237,7 +237,8 @@ func parseDNS(m *dns.Msg, ipaddr string, EXT_IP string) { if !foundInZone { //could probably return the query here rather than doxxing the first value in the monitored set, yolo - rr, _ := dns.NewRR(fmt.Sprintf("%s IN SOA %s %s (%s)", GetFirstDomain(), "ns."+GetFirstDomain(), "admin."+GetFirstDomain(), "2021041401 7200 3600 604800 300")) + _, suffix := returnSuffix(q.Name) + rr, _ := dns.NewRR(fmt.Sprintf("%s IN SOA %s %s (%s)", suffix, "ns."+suffix, "admin."+suffix, "2021041401 7200 3600 604800 300")) m.Answer = append(m.Answer, rr) } @@ -247,7 +248,8 @@ func parseDNS(m *dns.Msg, ipaddr string, EXT_IP string) { } if !foundInZone { - rr, _ := dns.NewRR(fmt.Sprintf("%s IN NS %s", q.Name, "ns."+GetFirstDomain())) + _, suffix := returnSuffix(q.Name) + rr, _ := dns.NewRR(fmt.Sprintf("%s IN NS %s", q.Name, "ns."+suffix)) m.Answer = append(m.Answer, rr) } } diff --git a/libknary/http.go b/libknary/http.go index bf82df8..9e071bd 100644 --- a/libknary/http.go +++ b/libknary/http.go @@ -147,8 +147,7 @@ func handleRequest(conn net.Conn) bool { // search for our host header for _, header := range headers { - if ok, _ := containsSuffix(header); ok { - //if stringContains(header, os.Getenv("CANARY_DOMAIN")) { + if ok, _ := returnSuffix(header); ok { // a match made in heaven host := "" query := "" diff --git a/libknary/util.go b/libknary/util.go index 8630d45..c31b4f8 100644 --- a/libknary/util.go +++ b/libknary/util.go @@ -23,7 +23,7 @@ type blacklist struct { deny map[string]time.Time } -//domains to monitor +// domains to monitor var domains []string func LoadDomains(domainlist string) error { @@ -39,17 +39,15 @@ func GetFirstDomain() string { return domains[0] } -func containsSuffix(lookupval string) (bool, error) { - if len(domains) == 0 { - //FU - return false, fmt.Errorf("no domains to check") - } +func returnSuffix(lookupval string) (bool, string) { + // we return bool for the http handleRequest() + // we return string for the dns SOA and NS responses for _, suffix := range domains { - if strings.HasSuffix(strings.ToLower(lookupval), strings.ToLower(suffix)) { - return true, nil + if stringContains(lookupval, suffix) || stringContains(lookupval, suffix+".") { + return true, suffix } } - return false, nil + return false, "" } func isRoot(lookupval string) (bool, error) { From 422e2164d621be8579bf029f6bca5f250e093ec5 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Wed, 29 Dec 2021 01:07:05 +0800 Subject: [PATCH 10/30] neaten code & improve doco --- examples/README.md | 2 +- examples/multidomain_env | 2 +- libknary/dns.go | 2 -- libknary/util.go | 17 +++++++---------- main.go | 1 + 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/examples/README.md b/examples/README.md index fcad35e..1172f6b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -3,7 +3,7 @@ ## Sample Files * `default_env` - A recommended quick start configuration file with Let's Encrypt configuration. * `burp_env` - A recommended quick start configuration file if you are also using Burp Collaborator on the same server as knary. -* `multidomain_env` - A recommended quick start configuration file if you are using knary with several domains. +* `multidomain_env` - An example of how to specify multiple knary domains. Domains must be comma-delimited. Whitespace is stripped automatically. * `denylist.txt` - This is a good starting set of subdomains you should consider denying from notifying your webhook. Setting [DNS_SUBDOMAIN](#likely-recommended-optional-configurations) will cut down the noise to your knary too. Find & Replace `knary.tld` with your knary domain. * `zone_file.txt` - Although an uncommon configuration, this file demonstrates the proper format for configuring a Zone file for custom responses to DNS queries made to knary. diff --git a/examples/multidomain_env b/examples/multidomain_env index 4c123cd..b9dda13 100644 --- a/examples/multidomain_env +++ b/examples/multidomain_env @@ -2,7 +2,7 @@ DNS=true HTTP=true BIND_ADDR=0.0.0.0 -CANARY_DOMAIN=knary.tld,myknary.com,otherknary.io +CANARY_DOMAIN=knary.tld, myknary.com,otherknary.io,otherknary.com, mydomain.xyz LETS_ENCRYPT= SLACK_WEBHOOK= diff --git a/libknary/dns.go b/libknary/dns.go index af96971..58a149d 100644 --- a/libknary/dns.go +++ b/libknary/dns.go @@ -206,7 +206,6 @@ func parseDNS(m *dns.Msg, ipaddr string, EXT_IP string) { case dns.TypeCNAME: if ok, _ := isRoot(q.Name); ok { - //if strings.HasPrefix(strings.ToLower(q.Name), strings.ToLower(os.Getenv("CANARY_DOMAIN")+".")) { // CNAME records cannot be returned for the root domain anyway. return } @@ -236,7 +235,6 @@ func parseDNS(m *dns.Msg, ipaddr string, EXT_IP string) { } if !foundInZone { - //could probably return the query here rather than doxxing the first value in the monitored set, yolo _, suffix := returnSuffix(q.Name) rr, _ := dns.NewRR(fmt.Sprintf("%s IN SOA %s %s (%s)", suffix, "ns."+suffix, "admin."+suffix, "2021041401 7200 3600 604800 300")) m.Answer = append(m.Answer, rr) diff --git a/libknary/util.go b/libknary/util.go index c31b4f8..e442f9f 100644 --- a/libknary/util.go +++ b/libknary/util.go @@ -26,8 +26,9 @@ type blacklist struct { // domains to monitor var domains []string -func LoadDomains(domainlist string) error { - domains = strings.Split(domainlist, ",") +func LoadDomains(domainList string) error { + prepareSplit := strings.ReplaceAll(domainList, " ", "") + domains = strings.Split(prepareSplit, ",") return nil } @@ -39,24 +40,20 @@ func GetFirstDomain() string { return domains[0] } -func returnSuffix(lookupval string) (bool, string) { +func returnSuffix(lookupVal string) (bool, string) { // we return bool for the http handleRequest() // we return string for the dns SOA and NS responses for _, suffix := range domains { - if stringContains(lookupval, suffix) || stringContains(lookupval, suffix+".") { + if stringContains(lookupVal, suffix) || stringContains(lookupVal, suffix+".") { return true, suffix } } return false, "" } -func isRoot(lookupval string) (bool, error) { - if len(domains) == 0 { - //FU - return false, fmt.Errorf("no domains to check") - } +func isRoot(lookupVal string) (bool, error) { for _, prefix := range domains { - if strings.HasPrefix(strings.ToLower(lookupval), strings.ToLower(prefix+".")) { + if strings.HasPrefix(strings.ToLower(lookupVal), strings.ToLower(prefix+".")) { return true, nil } } diff --git a/main.go b/main.go index 69cad94..f6d34c8 100644 --- a/main.go +++ b/main.go @@ -31,6 +31,7 @@ func main() { err = libknary.LoadDomains(os.Getenv("CANARY_DOMAIN")) if err != nil { + libknary.GiveHead(2) log.Fatal(err) } From c333824b8aa188e7f81e257fbd57e9c0568dcbd7 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Sun, 2 Jan 2022 17:09:52 +0800 Subject: [PATCH 11/30] allowlist functionality --- .gitignore | 4 + README.md | 19 ++-- libknary/analytics.go | 10 +- libknary/certutil.go | 7 +- libknary/dns.go | 2 +- libknary/notificationctrl.go | 195 +++++++++++++++++++++++++++++++++ libknary/util.go | 202 +++-------------------------------- libknary/webhooks.go | 2 +- main.go | 3 +- 9 files changed, 237 insertions(+), 207 deletions(-) create mode 100644 libknary/notificationctrl.go diff --git a/.gitignore b/.gitignore index 9adab81..138a28e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,10 @@ .env dev knary.log +allowlist.txt +allowed.txt +denylist.txt +denied.txt blacklist.txt zone.txt knary.exe diff --git a/README.md b/README.md index 5e9db68..15ce28e 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ Redteamers use canaries to be notified when someone (or *something*) attempts to Defenders also use canaries as tripwires that can alert them of an attacker within their network by having the attacker announce themselves. If you are a defender, https://canarytokens.org might be what you’re looking for. +## Key features +* + ## Setup 1. Download the [applicable 64-bit knary binary](https://github.com/sudosammy/knary/releases) __OR__ build knary from source: @@ -44,27 +47,27 @@ If your registry requires you to have multiple nameservers with **different** IP ![knary go-ing](https://github.com/sudosammy/knary/raw/master/screenshots/run.png "knary go-ing") ## Allowing or denying matches -You **will** find systems that spam your knary even long after an engagement has ended. You will also find several DNS requests to mundane subdomains hitting your knary every day. To stop these from cluttering your notifications knary has two features: +You **will** find systems that spam your knary even long after an engagement has ended. You will also find several DNS requests to mundane subdomains hitting your knary every day. To stop these from cluttering your notifications knary has a few features: -1. A simple text-based deny- and/or allowlist (location specified with `DENYLIST_FILE` or `ALLOWLIST_FILE`). Add the offending subdomains or IP addresses separated by a newline (case-insensitive): +1. A simple text-based deny and/or allowlist (location specified with `DENYLIST_FILE` and/or `ALLOWLIST_FILE`). Add the subdomains or IP addresses separated by a newline (case-insensitive): ``` knary.tld www.knary.tld 171.244.140.247 test.dns.knary.tld -engagement1337.knary.tld +sam.knary.tld ``` If this were a denylist, it would stop knary from alerting on `www.knary.tld` but not `another.www.knary.tld`. -If this were an allowlist, knary would alert on exact matches such as `engagement1337.knary.tld` and subdomain matches `another.engagement1337.knary.tld`. +If this were an allowlist, knary would alert on exact matches (`sam.knary.tld`) and subdomain matches (`website1.sam.knary.tld`). Use `ALLOWLIST_STRICT=true` to prevent this fuzzy matching and only alert on hits to `sam.knary.tld`. -You can use both a deny- and allowlist simultaneously. The allowlist takes precedence. +You can use both a deny and allowlist simultaneously. -**Note:** wildcards are not supported. An entry of `*.knary.tld` will match that string exactly. +**Note:** wildcards in these files are not supported. An entry of `*.knary.tld` will match that string exactly. -2. The `DNS_SUBDOMAIN` configuration allows you to specify that knary should only alert on DNS hits that are `*..knary.tld`. +2. The `DNS_SUBDOMAIN` configuration allows you to specify a subdomain that knary must fuzzy match (i.e. `*.DNS_SUBDOMAIN.knary.tld`) before alerting on DNS hits. This configuration does not affect HTTP(S) requests and remains primarily to mimic legacy knary v2 functionality. **Consider using a deny/allowlist instead.** -A configuration of `DNS_SUBDOMAIN=dns` would stop knary from alerting on DNS hits to `blah.knary.tld` but not `blah.dns.knary.tld`. This configuration only affects DNS traffic. A HTTP request to `blah.knary.tld` would still notify you unless prevented by an allow- or denylist. +A configuration of `DNS_SUBDOMAIN=dns` would stop knary from alerting on DNS hits to `blah.knary.tld` but not `blah.dns.knary.tld`. A HTTP request to `blah.knary.tld` would still notify you unless prevented by an allow- or denylist. Sample configurations can be found [in the examples](https://github.com/sudosammy/knary/tree/master/examples) with common subdomains to deny. diff --git a/libknary/analytics.go b/libknary/analytics.go index f9ab9df..15e8b80 100644 --- a/libknary/analytics.go +++ b/libknary/analytics.go @@ -14,7 +14,11 @@ import ( This function collects very basic analytics to track knary usage. It does NOT collect anything that could be tied back to you easily; however, does take a SHA256 hash of your knary domain name. If you have any thoughts about knary you can contact me on Twitter: @sudosammy or GitHub: https://github.com/sudosammy/knary + + You can make the following variable an empty string to sinkole analytics. */ +var trackingDomain = "https://knary.sam.ooo" + type features struct { DNS bool `json:"dns"` HTTP bool `json:"http"` @@ -29,6 +33,7 @@ type analy struct { ID string `json:"id"` Version string `json:"version"` Status int `json:"day"` + Allowlist int `json:"allowlist"` Blacklist int `json:"blacklist"` Offset int `json:"offset"` Timezone string `json:"timezone"` @@ -38,8 +43,6 @@ type analy struct { var day = 0 func UsageStats(version string) bool { - trackingDomain := "https://knary.sam.ooo" // make this an empty string to sinkhole analytics - if os.Getenv("CANARY_DOMAIN") == "" || trackingDomain == "" { return false } @@ -81,7 +84,8 @@ func UsageStats(version string) bool { anonKnaryID, version, day, - blacklistCount, + allowCount, + denyCount, (offset / 60 / 60), zone, features{ diff --git a/libknary/certutil.go b/libknary/certutil.go index 9638f11..64a27f5 100644 --- a/libknary/certutil.go +++ b/libknary/certutil.go @@ -4,8 +4,8 @@ import ( "log" "os" "path/filepath" - "strings" "strconv" + "strings" "time" "github.com/go-acme/lego/v4/certcrypto" @@ -37,10 +37,9 @@ func getDomainsForCert() []string { if os.Getenv("DEBUG") == "true" { Printy("Domains for SAN certificate: "+strconv.Itoa(numDomains), 3) } - - if (numDomains > 100) { - msg := "Too many domains! Let's Encrypt only supports SAN certificates containing 100 domains & subdomains. Your configuration currently has: "+strconv.Itoa(numDomains)+". This may be due to configuring DNS_SUBDOMAIN which will double the number of SAN entries per knary domain." + if numDomains > 100 { + msg := "Too many domains! Let's Encrypt only supports SAN certificates containing 100 domains & subdomains. Your configuration currently has: " + strconv.Itoa(numDomains) + ". This may be due to configuring DNS_SUBDOMAIN which will double the number of SAN entries per knary domain." logger("ERROR", msg) GiveHead(2) log.Fatal(msg) diff --git a/libknary/dns.go b/libknary/dns.go index 58a149d..4323a30 100644 --- a/libknary/dns.go +++ b/libknary/dns.go @@ -89,7 +89,7 @@ func goSendMsg(ipaddr, reverse, name, record string) bool { Printy("Got A question for: "+name, 3) } - if inBlacklist(name, ipaddr) { + if !inAllowlist(name, ipaddr) || inBlacklist(name, ipaddr) { return false } diff --git a/libknary/notificationctrl.go b/libknary/notificationctrl.go new file mode 100644 index 0000000..228c9ee --- /dev/null +++ b/libknary/notificationctrl.go @@ -0,0 +1,195 @@ +package libknary + +import ( + "bufio" + "os" + "strconv" + "strings" + "sync" + "time" +) + +// Functions that control whether a match will notify a webhook. +// Currently the allow and denylists. + +// map for allowlist +type allowlist struct { + allow string +} + +var allowed = map[int]allowlist{} +var allowCount = 0 + +// map for denylist +type blacklist struct { + mutex sync.Mutex + deny map[string]time.Time +} + +var denied = blacklist{deny: make(map[string]time.Time)} +var denyCount = 0 + +// add or update a denied domain/IP +func (a *blacklist) updateD(term string) bool { + if term == "" { + return false // would happen if there's no X-Forwarded-For header + } + item := standerdiseListItem(term) + a.mutex.Lock() + a.deny[item] = time.Now() + a.mutex.Unlock() + return true +} + +// search for a denied domain/IP +func (a *blacklist) searchD(term string) bool { + item := standerdiseListItem(term) + a.mutex.Lock() + defer a.mutex.Unlock() + + if _, ok := a.deny[item]; ok { + return true // found! + } + return false +} + +func standerdiseListItem(term string) string { + d := strings.ToLower(term) // lowercase + d = strings.TrimSpace(d) // remove any surrounding whitespaces + var sTerm string + + if IsIP(d) { + sTerm, _ = splitPort(d) // yeet port off IP + } else { + domain := strings.Split(d, ":") // split on port number (if exists) + sTerm = strings.TrimSuffix(domain[0], ".") // remove trailing FQDN dot if present + } + + return sTerm +} + +func LoadAllowlist() (bool, error) { + // load allowlist file into struct on startup + if _, err := os.Stat(os.Getenv("ALLOWLIST_FILE")); os.IsNotExist(err) { + return false, err + } + + alwlist, err := os.Open(os.Getenv("ALLOWLIST_FILE")) + defer alwlist.Close() + + if err != nil { + Printy(err.Error()+" - ignoring", 3) + return false, err + } + + scanner := bufio.NewScanner(alwlist) + + for scanner.Scan() { // foreach allowed item + if scanner.Text() != "" { + allowed[allowCount] = allowlist{standerdiseListItem(scanner.Text())} + allowCount++ + } + } + + Printy("Monitoring "+strconv.Itoa(allowCount)+" items in allowlist", 1) + logger("INFO", "Monitoring "+strconv.Itoa(allowCount)+" items in allowlist") + return true, nil +} + +func LoadBlacklist() (bool, error) { + if os.Getenv("BLACKLIST_FILE") != "" { + // deprecation warning + Printy("The environment variable \"DENYLIST_FILE\" has superseded \"BLACKLIST_FILE\". Please update your configuration.", 2) + } + // load denylist file into struct on startup + if _, err := os.Stat(os.Getenv("DENYLIST_FILE")); os.IsNotExist(err) { + return false, err + } + + blklist, err := os.Open(os.Getenv("DENYLIST_FILE")) + defer blklist.Close() + + if err != nil { + Printy(err.Error()+" - ignoring", 3) + return false, err + } + + scanner := bufio.NewScanner(blklist) + + for scanner.Scan() { // foreach denied item + if scanner.Text() != "" { + denied.updateD(scanner.Text()) + denyCount++ + } + } + + Printy("Monitoring "+strconv.Itoa(denyCount)+" items in denylist", 1) + logger("INFO", "Monitoring "+strconv.Itoa(denyCount)+" items in denylist") + return true, nil +} + +func inAllowlist(needles ...string) bool { + if allowed[0].allow == "" { + return true // if there is no allowlist set, we skip this check + } + + for _, needle := range needles { + needle := standerdiseListItem(needle) + for i := range allowed { // foreach allowed item + if os.Getenv("ALLOWLIST_STRICT") == "true" { + // strict matching. don't match subdomains + if needle == allowed[i].allow { + if os.Getenv("DEBUG") == "true" { + Printy(allowed[i].allow+" found in allowlist", 3) + } + return true + } + } else { + // allow fuzzy matching + // technically, this could be bypassed with: knary.tld.permitted.knary.tld and + if stringContains(needle, allowed[i].allow) { + if os.Getenv("DEBUG") == "true" { + Printy(allowed[i].allow+" found in allowlist", 3) + } + return true + } + } + } + } + return false +} + +func inBlacklist(needles ...string) bool { + for _, needle := range needles { + if denied.searchD(needle) { + denied.updateD(needle) // found! + + if os.Getenv("DEBUG") == "true" { + logger("INFO", "Found "+needle+" in denylist") + Printy("Found "+needle+" in denylist", 3) + } + return true + } + } + return false +} + +func checkLastHit() bool { // this runs once a day + for subdomain := range denied.deny { + expiryDate := denied.deny[subdomain].AddDate(0, 0, 14) + + if time.Now().After(expiryDate) { // let 'em know it's old + msg := "Denied item `" + subdomain + "` hasn't had a hit in >14 days. Consider removing it." + go sendMsg(":wrench: " + msg + " Configure `DENYLIST_ALERTING` to supress.") + logger("INFO", msg) + Printy(msg, 1) + } + } + + if os.Getenv("DEBUG") == "true" { + logger("INFO", "Checked denylist...") + Printy("Checked for old denylist items", 3) + } + + return true +} diff --git a/libknary/util.go b/libknary/util.go index e442f9f..2a2be52 100644 --- a/libknary/util.go +++ b/libknary/util.go @@ -11,18 +11,11 @@ import ( "os" "strconv" "strings" - "sync" "time" "github.com/blang/semver/v4" ) -// map for denylist -type blacklist struct { - mutex sync.Mutex - deny map[string]time.Time -} - // domains to monitor var domains []string @@ -60,86 +53,6 @@ func isRoot(lookupVal string) (bool, error) { return false, nil } -var denied = blacklist{deny: make(map[string]time.Time)} -var blacklistCount = 0 - -// add or update a denied domain/IP -func (a *blacklist) updateD(term string) bool { - if term == "" { - return false // would happen if there's no X-Forwarded-For header - } - item := standerdiseDenylistItem(term) - a.mutex.Lock() - a.deny[item] = time.Now() - a.mutex.Unlock() - return true -} - -// search for a denied domain/IP -func (a *blacklist) searchD(term string) bool { - item := standerdiseDenylistItem(term) - a.mutex.Lock() - defer a.mutex.Unlock() - - if _, ok := a.deny[item]; ok { - return true // found! - } - return false -} - -/* - -Allowlist WIP functions - -*/ -// map for allowlist -type allowlist struct { - mutex sync.Mutex - deny map[string]time.Time -} - -var allowed = allowlist{deny: make(map[string]time.Time)} -var allowCount = 0 - -// add or update a denied domain/IP -func (a *blacklist) updateA(term string) bool { - if term == "" { - return false // would happen if there's no X-Forwarded-For header - } - item := standerdiseDenylistItem(term) - a.mutex.Lock() - a.deny[item] = time.Now() - a.mutex.Unlock() - return true -} - -// search for a denied domain/IP -func (a *blacklist) searchA(term string) bool { - item := standerdiseDenylistItem(term) - a.mutex.Lock() - defer a.mutex.Unlock() - - if _, ok := a.deny[item]; ok { - return true // found! - } - return false -} - -func standerdiseDenylistItem(term string) string { - d := strings.ToLower(term) // lowercase - d = strings.TrimSpace(d) // remove any surrounding whitespaces - var sTerm string - - if IsIP(d) { - sTerm, _ = splitPort(d) // yeet port off IP - } else { - domain := strings.Split(d, ":") // split on port number (if exists) - sTerm = strings.TrimSuffix(domain[0], ".") // remove trailing FQDN dot if present - } - - return sTerm -} - // https://github.com/dsanader/govalidator/blob/master/validator.go func IsIP(str string) bool { return net.ParseIP(str) != nil @@ -252,106 +165,6 @@ func CheckUpdate(version string, githubVersion string, githubURL string) (bool, return false, nil } -func LoadBlacklist() (bool, error) { - if os.Getenv("BLACKLIST_FILE") != "" { - // deprecation warning - Printy("The environment variable \"DENYLIST_FILE\" has superseded \"BLACKLIST_FILE\". Please update your configuration.", 2) - } - // load denylist file into struct on startup - if _, err := os.Stat(os.Getenv("DENYLIST_FILE")); os.IsNotExist(err) { - return false, err - } - - blklist, err := os.Open(os.Getenv("DENYLIST_FILE")) - defer blklist.Close() - - if err != nil { - Printy(err.Error()+" - ignoring", 3) - return false, err - } - - scanner := bufio.NewScanner(blklist) - - for scanner.Scan() { // foreach denied item - if scanner.Text() != "" { - denied.updateD(scanner.Text()) - blacklistCount++ - } - } - - Printy("Monitoring "+strconv.Itoa(blacklistCount)+" items in denylist", 1) - logger("INFO", "Monitoring "+strconv.Itoa(blacklistCount)+" items in denylist") - return true, nil -} - -/* - -Allowlist WIP functions - -*/ -func LoadAllowlist() (bool, error) { - // load denylist file into struct on startup - if _, err := os.Stat(os.Getenv("ALLOWLIST_FILE")); os.IsNotExist(err) { - return false, err - } - - alwlist, err := os.Open(os.Getenv("ALLOWLIST_FILE")) - defer alwlist.Close() - - if err != nil { - Printy(err.Error()+" - ignoring", 3) - return false, err - } - - scanner := bufio.NewScanner(alwlist) - - for scanner.Scan() { // foreach denied item - if scanner.Text() != "" { - denied.updateD(scanner.Text()) - blacklistCount++ - } - } - - Printy("Monitoring "+strconv.Itoa(blacklistCount)+" items in denylist", 1) - logger("INFO", "Monitoring "+strconv.Itoa(blacklistCount)+" items in denylist") - return true, nil -} - -func checkLastHit() bool { // this runs once a day - for subdomain := range denied.deny { - expiryDate := denied.deny[subdomain].AddDate(0, 0, 14) - - if time.Now().After(expiryDate) { // let 'em know it's old - msg := "Denied item `" + subdomain + "` hasn't had a hit in >14 days. Consider removing it." - go sendMsg(":wrench: " + msg + " Configure `DENYLIST_ALERTING` to supress.") - logger("INFO", msg) - Printy(msg, 1) - } - } - - if os.Getenv("DEBUG") == "true" { - logger("INFO", "Checked denylist...") - Printy("Checked for old denylist items", 3) - } - - return true -} - -func inBlacklist(needles ...string) bool { - for _, needle := range needles { - if denied.searchD(needle) { - denied.updateD(needle) // found! - - if os.Getenv("DEBUG") == "true" { - logger("INFO", "Found "+needle+" in denylist") - Printy("Found "+needle+" in denylist", 3) - } - return true - } - } - return false -} - func CheckTLSExpiry(days int) (bool, int) { if os.Getenv("TLS_CRT") != "" && os.Getenv("TLS_KEY") != "" { renew, expiry := needRenewal(days) @@ -413,8 +226,19 @@ func HeartBeat(version string, firstrun bool) (bool, error) { beatMsg += "Uptime: " + strconv.Itoa(day) + " days\n\n" } + // print allowed items + beatMsg += strconv.Itoa(allowCount) + " allowed subdomains / IPs: \n" + if os.Getenv("ALLOWLIST_STRICT") == "true" { + beatMsg += "(Operating in strict mode) \n" + } + beatMsg += "------------------------\n" + for i := range allowed { + beatMsg += allowed[i].allow + "\n" + } + beatMsg += "------------------------\n\n" + // print denied items - beatMsg += strconv.Itoa(blacklistCount) + " denied subdomains / IPs: \n" + beatMsg += strconv.Itoa(denyCount) + " denied subdomains / IPs: \n" beatMsg += "------------------------\n" for subdomain := range denied.deny { beatMsg += subdomain + "\n" @@ -426,7 +250,7 @@ func HeartBeat(version string, firstrun bool) (bool, error) { for _, cdomain := range GetDomains() { beatMsg += "Listening for http://*." + cdomain + " requests\n" } - } else if (os.Getenv("HTTP") == "true" && (os.Getenv("TLS_CRT") != "" && os.Getenv("TLS_KEY") != "")) { + } else if os.Getenv("HTTP") == "true" && (os.Getenv("TLS_CRT") != "" && os.Getenv("TLS_KEY") != "") { for _, cdomain := range GetDomains() { beatMsg += "Listening for http(s)://*." + cdomain + " requests\n" } diff --git a/libknary/webhooks.go b/libknary/webhooks.go index bcf6cc3..f6dd4b5 100644 --- a/libknary/webhooks.go +++ b/libknary/webhooks.go @@ -40,7 +40,7 @@ func sendMsg(msg string) { msg = re.ReplaceAllString(msg, "") jsonMsg := []byte(`{"chat_id": "` + os.Getenv("TELEGRAM_CHATID") + `", "text": "` + msg + `"}`) - _, err := http.Post("https://api.telegram.org/bot" + os.Getenv("TELEGRAM_BOT_TOKEN") + "/sendMessage", "application/json", bytes.NewBuffer(jsonMsg)) + _, err := http.Post("https://api.telegram.org/bot"+os.Getenv("TELEGRAM_BOT_TOKEN")+"/sendMessage", "application/json", bytes.NewBuffer(jsonMsg)) if err != nil { Printy(err.Error(), 2) diff --git a/main.go b/main.go index f6d34c8..1781eae 100644 --- a/main.go +++ b/main.go @@ -82,7 +82,8 @@ func main() { red.Println(`|_____|`) fmt.Println() - // load blacklist file, zone file & submit usage + // load lists, zone file & submit usage + libknary.LoadAllowlist() libknary.LoadBlacklist() libknary.LoadZone() go libknary.UsageStats(VERSION) From 5005c7086a1d19eb58362d341d9dc907fa5e14fa Mon Sep 17 00:00:00 2001 From: sudosammy Date: Sun, 2 Jan 2022 17:54:46 +0800 Subject: [PATCH 12/30] allowlist now works on HTTP(S) too --- README.md | 7 +------ examples/README.md | 27 +++++++++++++-------------- examples/burp_env | 4 +++- examples/default_env | 4 +++- examples/multidomain_env | 6 ++++-- libknary/http.go | 2 +- libknary/util.go | 34 +++++++++++++++++++--------------- 7 files changed, 44 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 15ce28e..04569c6 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,6 @@ Redteamers use canaries to be notified when someone (or *something*) attempts to Defenders also use canaries as tripwires that can alert them of an attacker within their network by having the attacker announce themselves. If you are a defender, https://canarytokens.org might be what you’re looking for. -## Key features -* - ## Setup 1. Download the [applicable 64-bit knary binary](https://github.com/sudosammy/knary/releases) __OR__ build knary from source: @@ -61,9 +58,7 @@ If this were a denylist, it would stop knary from alerting on `www.knary.tld` bu If this were an allowlist, knary would alert on exact matches (`sam.knary.tld`) and subdomain matches (`website1.sam.knary.tld`). Use `ALLOWLIST_STRICT=true` to prevent this fuzzy matching and only alert on hits to `sam.knary.tld`. -You can use both a deny and allowlist simultaneously. - -**Note:** wildcards in these files are not supported. An entry of `*.knary.tld` will match that string exactly. +You can use both a deny and allowlist simultaneously. **Note:** wildcards in these files are not supported. An entry of `*.knary.tld` will match that string exactly. 2. The `DNS_SUBDOMAIN` configuration allows you to specify a subdomain that knary must fuzzy match (i.e. `*.DNS_SUBDOMAIN.knary.tld`) before alerting on DNS hits. This configuration does not affect HTTP(S) requests and remains primarily to mimic legacy knary v2 functionality. **Consider using a deny/allowlist instead.** diff --git a/examples/README.md b/examples/README.md index 1172f6b..5a895ff 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,11 +1,12 @@ # Configuration Options & Example Files ## Sample Files -* `default_env` - A recommended quick start configuration file with Let's Encrypt configuration. -* `burp_env` - A recommended quick start configuration file if you are also using Burp Collaborator on the same server as knary. -* `multidomain_env` - An example of how to specify multiple knary domains. Domains must be comma-delimited. Whitespace is stripped automatically. -* `denylist.txt` - This is a good starting set of subdomains you should consider denying from notifying your webhook. Setting [DNS_SUBDOMAIN](#likely-recommended-optional-configurations) will cut down the noise to your knary too. Find & Replace `knary.tld` with your knary domain. -* `zone_file.txt` - Although an uncommon configuration, this file demonstrates the proper format for configuring a Zone file for custom responses to DNS queries made to knary. +* `default_env` - A recommended quick start configuration file with Let's Encrypt configuration +* `burp_env` - A recommended quick start configuration file if you are also using Burp Collaborator on the same server as knary +* `multidomain_env` - An example of how to specify multiple knary domains. Domains must be comma-delimited. Whitespace is stripped automatically +* `allowlist.txt` - This is an example allowlist showing how knary could be used with your team's names. This has the added benefit of allowing your team to configure [keyword notifications](https://slack.com/intl/en-au/help/articles/201355156-Configure-your-Slack-notifications#keyword-notifications) in Slack +* `denylist.txt` - If you are not going to use an allowlist, this is a good starting set of subdomains you should consider denying. Setting [DNS_SUBDOMAIN](#optional-configurations) will cut down the noise to your knary too. Find & Replace `knary.tld` with your knary domain +* `zone_file.txt` - Although an uncommon configuration, this file demonstrates the proper format for configuring a Zone file for custom responses to DNS queries made to knary ## Minimum Necessary Configuration * `DNS` Enable/Disable the DNS canary (true/false) @@ -17,13 +18,8 @@ ## Recommended Optional Configurations * `LETS_ENCRYPT` Enable Let's Encrypt management of your knary domain. If you do not configure this, or `TLS_*` as [detailed below](#optional-configurations), knary will only listen on port 80 and notify of HTTP hits. Example input: `myemailaddress@gmail.com` * `LOG_FILE` Location for a file that knary will log greppable and timestamped warnings/errors. Example input: `/var/log/knary.log` or `knary.log` for current working directory +* `ALLOWLIST_FILE` Location for a file containing case-insensitive subdomains or IP addresses (separated by newlines) that should trigger a notification for knary (unless also included in the denylist). Example input: `allowlist.txt` * `DENYLIST_FILE` Location for a file containing case-insensitive subdomains or IP addresses (separated by newlines) that should be ignored by knary and not logged or notified. Example input: `denylist.txt` -* `ALLOWLIST_FILE` Rather then denying certain matches, you can specify exact matches knary should alert on. This configuration takes precedence over a denylist. Location for a file containing case-insensitive subdomains (separated by newlines) that should trigger knary. Example input: `allowed.txt` - -## Likely Recommended Optional Configurations -* `DNS_SUBDOMAIN` Tell knary to only notify on `*..` DNS hits. This is useful if you your webhook is getting too noisy with DNS hits to your knary TLD. Setting this configuration will mimic how knary operated prior to version 3. Example input: `dns` - -**Note:** If you have previously been running knary with Let's Encrypt and have now configured `DNS_SUBDOMAIN`, you should delete the files in the `certs/` folder so that knary can re-generate certificates that include this subdomain as a SAN. Otherwise knary may exhibit strange behaviour / failures when attempting to renew the certificate. ## Burp Collaborator Configuration If you are running Burp Collaborator on the same server as knary, you will need to configure the following. @@ -33,12 +29,15 @@ If you are running Burp Collaborator on the same server as knary, you will need * `BURP_HTTPS_PORT` Much like the above - set to `8443` (or whatever you set the Burp HTTPS port to be) * `BURP_INT_IP` __Optional__ The internal IP address that Burp Collaborator is bound to. In most cases this will be `127.0.0.1` (which is the default); however, if you run knary in Docker you may need to set this to the Burp Collaborator IP address reachable from within the knary container -**Note:** If you have previously been running knary with Let's Encrypt and have now configured Burp Collaborator, you should delete the files in the `certs/` folder so that knary can re-generate certificates that include your Burp Collaborator subdomain as a SAN. Otherwise knary may exhibit strange behaviour / failures when attempting to renew the certificate. - ## Optional Configurations * `TLS_*` (CRT/KEY). If you're not using the `LETS_ENCRYPT` configuration use these environment variables to configure the location of your certificate and private key for accepting TLS (HTTPS) requests * `DEBUG` Enable/Disable displaying incoming requests in the terminal and some additional info. Default disabled (true/false) -* `LE_ENV` Set to `staging` to use the Let's Encrypt's staging environment. Useful if you are testing configurations with Let's Encrypt and do not want to hit the rate limit. +* `ALLOWLIST_STRICT` Set to `true` to prevent fuzzy matching on allowlist items and only alert on exact matches +* `LE_ENV` Set to `staging` to use the Let's Encrypt's staging environment. Useful if you are testing configurations with Let's Encrypt and do not want to hit the rate limit * `EXT_IP` The IP address the DNS canary will answer `A` questions with. By default knary will use the nameserver glue record. Setting this option will overrule that behaviour * `DENYLIST_ALERTING` By default knary will alert on items in the denylist that haven't triggered in >14 days. Set to `false` to disable this behaviour +* `DNS_SUBDOMAIN` Tell knary to only notify on `*..` DNS hits. This is useful if you your webhook is getting too noisy with DNS hits to your knary TLD and you do not maintain an allow or denylist. Setting this configuration will mimic how knary operated prior to version 3. Example input: `dns` * `ZONE_FILE` knary supports responding to DNS requests based on an RFC 1034/1035 compliant zone file. Example input: `zone_file.txt` + +## Note about editing configuration and Let's Encrypt +If you have previously been running knary with Let's Encrypt and have now configured Burp Collaborator or `DNS_SUBDOMAIN`, you should delete the files in the `certs/` folder so that knary can re-generate certificates that include these subdomains as a SAN. Otherwise knary may exhibit strange behaviour / failures when attempting to renew the certificate. \ No newline at end of file diff --git a/examples/burp_env b/examples/burp_env index 389295a..02f4944 100644 --- a/examples/burp_env +++ b/examples/burp_env @@ -8,7 +8,9 @@ SLACK_WEBHOOK= DEBUG=false LOG_FILE=knary.log -DENYLIST_FILE=denylist.txt + +#ALLOWLIST_FILE=allowlist.txt +#DENYLIST_FILE=denylist.txt BURP_DOMAIN= BURP_DNS_PORT=8053 diff --git a/examples/default_env b/examples/default_env index 3e72d06..6a9f35b 100644 --- a/examples/default_env +++ b/examples/default_env @@ -8,4 +8,6 @@ SLACK_WEBHOOK= DEBUG=false LOG_FILE=knary.log -DENYLIST_FILE=denylist.txt + +#ALLOWLIST_FILE=allowlist.txt +#DENYLIST_FILE=denylist.txt diff --git a/examples/multidomain_env b/examples/multidomain_env index b9dda13..60e6de3 100644 --- a/examples/multidomain_env +++ b/examples/multidomain_env @@ -2,10 +2,12 @@ DNS=true HTTP=true BIND_ADDR=0.0.0.0 -CANARY_DOMAIN=knary.tld, myknary.com,otherknary.io,otherknary.com, mydomain.xyz +CANARY_DOMAIN=knary.tld, myknary.com, otherknary.io, otherknary.com, mydomain.xyz LETS_ENCRYPT= SLACK_WEBHOOK= DEBUG=false LOG_FILE=knary.log -DENYLIST_FILE=denylist.txt + +#ALLOWLIST_FILE=allowlist.txt +#DENYLIST_FILE=denylist.txt diff --git a/libknary/http.go b/libknary/http.go index 9e071bd..218c80a 100644 --- a/libknary/http.go +++ b/libknary/http.go @@ -210,7 +210,7 @@ func handleRequest(conn net.Conn) bool { } hostDomain := strings.TrimPrefix(strings.ToLower(host), "host:") // trim off the "Host:" section of header - if !inBlacklist(hostDomain, conn.RemoteAddr().String(), fwd) { + if inAllowlist(hostDomain, conn.RemoteAddr().String(), fwd) && !inBlacklist(hostDomain, conn.RemoteAddr().String(), fwd) { var msg string if cookie != "" { msg = fmt.Sprintf("%s\n```Query: %s\n%s\n%s\nFrom: %s", host, query, userAgent, cookie, conn.RemoteAddr().String()) diff --git a/libknary/util.go b/libknary/util.go index 2a2be52..0469710 100644 --- a/libknary/util.go +++ b/libknary/util.go @@ -226,24 +226,28 @@ func HeartBeat(version string, firstrun bool) (bool, error) { beatMsg += "Uptime: " + strconv.Itoa(day) + " days\n\n" } - // print allowed items - beatMsg += strconv.Itoa(allowCount) + " allowed subdomains / IPs: \n" - if os.Getenv("ALLOWLIST_STRICT") == "true" { - beatMsg += "(Operating in strict mode) \n" - } - beatMsg += "------------------------\n" - for i := range allowed { - beatMsg += allowed[i].allow + "\n" + // print allowed items (if any) + if allowCount > 0 { + beatMsg += strconv.Itoa(allowCount) + " allowed subdomains / IPs: \n" + if os.Getenv("ALLOWLIST_STRICT") == "true" { + beatMsg += "(Operating in strict mode) \n" + } + beatMsg += "------------------------\n" + for i := range allowed { + beatMsg += allowed[i].allow + "\n" + } + beatMsg += "------------------------\n\n" } - beatMsg += "------------------------\n\n" - // print denied items - beatMsg += strconv.Itoa(denyCount) + " denied subdomains / IPs: \n" - beatMsg += "------------------------\n" - for subdomain := range denied.deny { - beatMsg += subdomain + "\n" + // print denied items (if any) + if denyCount > 0 { + beatMsg += strconv.Itoa(denyCount) + " denied subdomains / IPs: \n" + beatMsg += "------------------------\n" + for subdomain := range denied.deny { + beatMsg += subdomain + "\n" + } + beatMsg += "------------------------\n\n" } - beatMsg += "------------------------\n\n" // print usage domains if os.Getenv("HTTP") == "true" && (os.Getenv("TLS_CRT") == "" || os.Getenv("TLS_KEY") == "") { From 1d9ecdb8a6390a9a2857f227163e3f32f8da287a Mon Sep 17 00:00:00 2001 From: sudosammy Date: Sun, 2 Jan 2022 17:57:05 +0800 Subject: [PATCH 13/30] allowlist example file --- .gitignore | 2 -- examples/allowlist.txt | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 examples/allowlist.txt diff --git a/.gitignore b/.gitignore index 138a28e..82f1ef5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,9 +2,7 @@ .env dev knary.log -allowlist.txt allowed.txt -denylist.txt denied.txt blacklist.txt zone.txt diff --git a/examples/allowlist.txt b/examples/allowlist.txt new file mode 100644 index 0000000..aecca8e --- /dev/null +++ b/examples/allowlist.txt @@ -0,0 +1,5 @@ +sam.knary.tld +bob.knary.tld +alcie.knary.tld +eve.knary.tld +pea.knary.tld \ No newline at end of file From cf4f8cc5ce4b295aef1d8212917a1e475d7b1c7d Mon Sep 17 00:00:00 2001 From: sudosammy Date: Sun, 2 Jan 2022 17:57:32 +0800 Subject: [PATCH 14/30] allowlist example file --- examples/allowlist.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/allowlist.txt b/examples/allowlist.txt index aecca8e..a8a289f 100644 --- a/examples/allowlist.txt +++ b/examples/allowlist.txt @@ -1,5 +1,5 @@ sam.knary.tld bob.knary.tld -alcie.knary.tld +alice.knary.tld eve.knary.tld pea.knary.tld \ No newline at end of file From 3dc82f412567834e45ccce9d2bcc3cc0acd66fb6 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Sun, 2 Jan 2022 18:01:27 +0800 Subject: [PATCH 15/30] better error desc --- libknary/certutil.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libknary/certutil.go b/libknary/certutil.go index 64a27f5..d3ffab9 100644 --- a/libknary/certutil.go +++ b/libknary/certutil.go @@ -39,7 +39,7 @@ func getDomainsForCert() []string { } if numDomains > 100 { - msg := "Too many domains! Let's Encrypt only supports SAN certificates containing 100 domains & subdomains. Your configuration currently has: " + strconv.Itoa(numDomains) + ". This may be due to configuring DNS_SUBDOMAIN which will double the number of SAN entries per knary domain." + msg := "Too many domains! Let's Encrypt only supports SAN certificates containing 100 domains & subdomains. Your configuration currently has: " + strconv.Itoa(numDomains) + ". This may be due to configuring DNS_SUBDOMAIN which will double the number of SAN entries per CANARY_DOMAIN." logger("ERROR", msg) GiveHead(2) log.Fatal(msg) From 49534d1c06e687121baf86732b1afb8eb0980e21 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Fri, 7 Jan 2022 12:21:58 +0800 Subject: [PATCH 16/30] fix from IPs when burp collab enabled --- .travis.yml | 2 ++ libknary/http.go | 18 +++++++++++++----- libknary/notificationctrl.go | 7 +++---- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 488f3a2..494c13b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ language: go go: + - 1.19.x + - 1.18.x - 1.17.x - 1.16.x diff --git a/libknary/http.go b/libknary/http.go index 218c80a..7a6bc64 100644 --- a/libknary/http.go +++ b/libknary/http.go @@ -38,7 +38,7 @@ func PrepareRequest80() net.Listener { } else { // otherwise send it raw to the local knary port r.URL.Host = p80 - r.Header.Set("X-Forwarded-For", r.RemoteAddr) //add port version of x-fwded for + r.Header.Set("X-Forwarded-For", r.RemoteAddr) } }, }) @@ -198,7 +198,7 @@ func handleRequest(conn net.Conn) bool { mult := strings.Split(val, ",") if len(mult) > 1 { for _, srcaddr := range mult { - if strings.Contains(srcaddr, ":") { + if strings.Contains(srcaddr, ":") { // this probs breaks IPv6 srcAndPort = append(srcAndPort, srcaddr) } } @@ -212,16 +212,24 @@ func handleRequest(conn net.Conn) bool { hostDomain := strings.TrimPrefix(strings.ToLower(host), "host:") // trim off the "Host:" section of header if inAllowlist(hostDomain, conn.RemoteAddr().String(), fwd) && !inBlacklist(hostDomain, conn.RemoteAddr().String(), fwd) { var msg string + var fromIP string + + if fwd != "" { + fromIP = fwd // use this when burp collab mode is active + } else { + fromIP = conn.RemoteAddr().String() + } + if cookie != "" { - msg = fmt.Sprintf("%s\n```Query: %s\n%s\n%s\nFrom: %s", host, query, userAgent, cookie, conn.RemoteAddr().String()) + msg = fmt.Sprintf("%s\n```Query: %s\n%s\n%s\nFrom: %s", host, query, userAgent, cookie, fromIP) } else { - msg = fmt.Sprintf("%s\n```Query: %s\n%s\nFrom: %s", host, query, userAgent, conn.RemoteAddr().String()) + msg = fmt.Sprintf("%s\n```Query: %s\n%s\nFrom: %s", host, query, userAgent, fromIP) } go sendMsg(msg + "```") if os.Getenv("DEBUG") == "true" { - logger("INFO", conn.RemoteAddr().String()+" - "+host) + logger("INFO", fromIP+" - "+host) } } } diff --git a/libknary/notificationctrl.go b/libknary/notificationctrl.go index 228c9ee..14ee4b5 100644 --- a/libknary/notificationctrl.go +++ b/libknary/notificationctrl.go @@ -140,16 +140,15 @@ func inAllowlist(needles ...string) bool { // strict matching. don't match subdomains if needle == allowed[i].allow { if os.Getenv("DEBUG") == "true" { - Printy(allowed[i].allow+" found in allowlist", 3) + Printy(needle+" matches allowlist", 3) } return true } } else { // allow fuzzy matching - // technically, this could be bypassed with: knary.tld.permitted.knary.tld and - if stringContains(needle, allowed[i].allow) { + if strings.HasSuffix(needle, allowed[i].allow) { if os.Getenv("DEBUG") == "true" { - Printy(allowed[i].allow+" found in allowlist", 3) + Printy(needle+" matches allowlist", 3) } return true } From 5494ab6d875d1a5ff99ae0f37ad26fb2a6269563 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Sat, 8 Jan 2022 18:08:08 +0800 Subject: [PATCH 17/30] prep for bugfixes --- libknary/certutil.go | 2 +- libknary/http.go | 1 + libknary/lego/cert_storage.go | 9 +++++++++ libknary/maintenance.go | 2 +- main.go | 4 +--- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/libknary/certutil.go b/libknary/certutil.go index d3ffab9..b45e4c7 100644 --- a/libknary/certutil.go +++ b/libknary/certutil.go @@ -78,7 +78,7 @@ func needRenewal(days int) (bool, int) { certName := strings.TrimSuffix(filepath.Base(os.Getenv("TLS_CRT")), filepath.Ext(os.Getenv("TLS_CRT"))) certExt := filepath.Ext(os.Getenv("TLS_CRT")) - certsStorage := cmd.NewCertificatesStorage() + certsStorage := cmd.NewCertificatesStorage() // there's a bug here that forces certs to be in certs/ certificates, err := certsStorage.ReadCertificate(certName, certExt) if err != nil { logger("ERROR", err.Error()) diff --git a/libknary/http.go b/libknary/http.go index 7a6bc64..4ccd545 100644 --- a/libknary/http.go +++ b/libknary/http.go @@ -115,6 +115,7 @@ func PrepareRequest443() net.Listener { func AcceptRequest(ln net.Listener, wg *sync.WaitGroup) { for { + // wg.Done() - end waitgroup on first hit to knary conn, err := ln.Accept() // accept connections forever if err != nil { Printy(err.Error(), 2) diff --git a/libknary/lego/cert_storage.go b/libknary/lego/cert_storage.go index eade9f6..912c4c1 100644 --- a/libknary/lego/cert_storage.go +++ b/libknary/lego/cert_storage.go @@ -20,6 +20,15 @@ import ( "golang.org/x/net/idna" ) +func init() { + if os.Getenv("CERT_LOCATION") != "" { + // TODO + // something to correctly set baseCertificatesFolderName & baseArchivesFolderName + // doesn't need to be a env var, being able to read TLS_* env variable would work for non-LE genned certs + // but then LE genned certs would still be put in certs/ ... Probably not an issue though. + } +} + var baseCertificatesFolderName = "certs" var baseArchivesFolderName = filepath.Join(baseCertificatesFolderName, "archives") diff --git a/libknary/maintenance.go b/libknary/maintenance.go index 710e9e8..b64f4b1 100644 --- a/libknary/maintenance.go +++ b/libknary/maintenance.go @@ -10,7 +10,7 @@ func dailyTasks(version string, githubVersion string, githubURL string) bool { // check for updates CheckUpdate(version, githubVersion, githubURL) - // if blacklist alerting is enabled, flag any old blacklist items + // flag any denied items that haven't had a hit in >14 days if os.Getenv("DENYLIST_ALERTING") != "false" { checkLastHit() } diff --git a/main.go b/main.go index 1781eae..7458675 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,6 @@ import ( "fmt" "log" "os" - "strconv" "sync" "github.com/sudosammy/knary/libknary" @@ -178,8 +177,7 @@ func main() { wg.Add(1) go libknary.AcceptRequest(ln443, &wg) // check TLS expiry on first lauch of knary - _, expiry := libknary.CheckTLSExpiry(30) - libknary.Printy("TLS certificate expires in "+strconv.Itoa(expiry)+" days", 3) + _, _ = libknary.CheckTLSExpiry(30) } } From b8cd64b880c63d84c45a32e0ea4f77acc59350d0 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Sun, 9 Jan 2022 01:26:48 +0800 Subject: [PATCH 18/30] ensure knary restarts TLS listener on certificate change -- untested --- go.mod | 1 + go.sum | 1 + libknary/fsnotify.go | 51 ++++++++++++++++++++++++++++++++++++++++++++ libknary/http.go | 40 ++++++++++++++++++++++++++-------- main.go | 14 ++++++------ 5 files changed, 92 insertions(+), 15 deletions(-) create mode 100644 libknary/fsnotify.go diff --git a/go.mod b/go.mod index db44912..87c6b9c 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.16 require ( github.com/blang/semver/v4 v4.0.0 github.com/fatih/color v1.10.0 + github.com/fsnotify/fsnotify v1.4.9 github.com/go-acme/lego/v4 v4.3.1 github.com/joho/godotenv v1.3.0 github.com/miekg/dns v1.1.41 diff --git a/go.sum b/go.sum index b3afb54..bf61e93 100644 --- a/go.sum +++ b/go.sum @@ -100,6 +100,7 @@ github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= diff --git a/libknary/fsnotify.go b/libknary/fsnotify.go new file mode 100644 index 0000000..39911ab --- /dev/null +++ b/libknary/fsnotify.go @@ -0,0 +1,51 @@ +package libknary + +// Thanks https://medium.com/@skdomino/watch-this-file-watching-in-go-5b5a247cf71f +// Eventually this will support deny/allowlists too + +import ( + "log" + "os" + + "github.com/fsnotify/fsnotify" +) + +func TLSmonitor(restart chan bool) { + // creates a new file watcher + watcher, err := fsnotify.NewWatcher() + if err != nil { + logger("ERROR", err.Error()) + GiveHead(2) + log.Fatal(err) + } + defer watcher.Close() + done := make(chan bool) + + go func() { + for { + select { + // watch for events + case <-watcher.Events: + // trigger reload of certificates! + msg := "TLS key changed! The TLS listener will be restarted on next HTTPS request to knary." + logger("INFO", msg) + Printy(msg, 3) + go sendMsg(msg + "```") + + restart <- true // TODO: why does notification have to come first here... + + // watch for errors + case err := <-watcher.Errors: + logger("ERROR", err.Error()) + Printy(err.Error(), 2) + } + } + }() + + if err := watcher.Add(os.Getenv("TLS_KEY")); err != nil { + logger("ERROR", err.Error()) + Printy(err.Error(), 2) + } + + <-done +} diff --git a/libknary/http.go b/libknary/http.go index 4ccd545..d19da7d 100644 --- a/libknary/http.go +++ b/libknary/http.go @@ -14,7 +14,7 @@ import ( "time" ) -func PrepareRequest80() net.Listener { +func Listen80() net.Listener { p80 := os.Getenv("BIND_ADDR") + ":80" if os.Getenv("BURP_HTTP_PORT") != "" { @@ -58,7 +58,17 @@ func PrepareRequest80() net.Listener { return ln80 } -func PrepareRequest443() net.Listener { +func Accept80(ln net.Listener) { + for { + conn, err := ln.Accept() // accept connections forever + if err != nil { + Printy(err.Error(), 2) + } + go handleRequest(conn) + } +} + +func Listen443() net.Listener { p443 := os.Getenv("BIND_ADDR") + ":443" if os.Getenv("BURP_HTTPS_PORT") != "" { @@ -113,14 +123,26 @@ func PrepareRequest443() net.Listener { return ln443 } -func AcceptRequest(ln net.Listener, wg *sync.WaitGroup) { +func Accept443(ln net.Listener, wg *sync.WaitGroup, restart <-chan bool) { for { - // wg.Done() - end waitgroup on first hit to knary - conn, err := ln.Accept() // accept connections forever - if err != nil { - Printy(err.Error(), 2) + select { + case <-restart: + ln.Close() // close listener so we can restart it + ln443 := Listen443() // restart listener + go Accept443(ln443, wg, restart) + msg := "TLS server restarted." + logger("INFO", msg) + Printy(msg, 3) + go sendMsg(msg + "```") + return + + default: + conn, err := ln.Accept() // accept connections until channel says stop + if err != nil { + Printy(err.Error(), 2) + } + go handleRequest(conn) } - go handleRequest(conn) } } @@ -214,7 +236,7 @@ func handleRequest(conn net.Conn) bool { if inAllowlist(hostDomain, conn.RemoteAddr().String(), fwd) && !inBlacklist(hostDomain, conn.RemoteAddr().String(), fwd) { var msg string var fromIP string - + if fwd != "" { fromIP = fwd // use this when burp collab mode is active } else { diff --git a/main.go b/main.go index 7458675..f82edfc 100644 --- a/main.go +++ b/main.go @@ -166,18 +166,20 @@ func main() { } if os.Getenv("HTTP") == "true" { - ln80 := libknary.PrepareRequest80() // HTTP + ln80 := libknary.Listen80() wg.Add(1) - go libknary.AcceptRequest(ln80, &wg) + go libknary.Accept80(ln80) if os.Getenv("TLS_CRT") != "" && os.Getenv("TLS_KEY") != "" { // HTTPS - ln443 := libknary.PrepareRequest443() + restart := make(chan bool) + ln443 := libknary.Listen443() wg.Add(1) - go libknary.AcceptRequest(ln443, &wg) - // check TLS expiry on first lauch of knary - _, _ = libknary.CheckTLSExpiry(30) + go libknary.Accept443(ln443, &wg, restart) + + _, _ = libknary.CheckTLSExpiry(30) // check TLS expiry on first lauch of knary + libknary.TLSmonitor(restart) // monitor filesystem changes to the TLS cert to trigger a reboot } } From c66a21781839953dfe8fcf53263de04c803ebf55 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Sun, 9 Jan 2022 01:39:09 +0800 Subject: [PATCH 19/30] only trigger TLS listener restart on write operations to the key --- libknary/fsnotify.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/libknary/fsnotify.go b/libknary/fsnotify.go index 39911ab..8e6a112 100644 --- a/libknary/fsnotify.go +++ b/libknary/fsnotify.go @@ -25,14 +25,15 @@ func TLSmonitor(restart chan bool) { for { select { // watch for events - case <-watcher.Events: - // trigger reload of certificates! - msg := "TLS key changed! The TLS listener will be restarted on next HTTPS request to knary." - logger("INFO", msg) - Printy(msg, 3) - go sendMsg(msg + "```") - - restart <- true // TODO: why does notification have to come first here... + case event := <-watcher.Events: + if event.Op&fsnotify.Write == fsnotify.Write { // trigger reload of certificates! + msg := "TLS key changed! The TLS listener will be restarted on next HTTPS request to knary." + logger("INFO", msg) + Printy(msg, 3) + go sendMsg(msg + "```") + + restart <- true // TODO: why does notification have to come first here... + } // watch for errors case err := <-watcher.Errors: From 7ddf6981306af7b825f62119ec574d0beac8f78b Mon Sep 17 00:00:00 2001 From: sudosammy Date: Sun, 9 Jan 2022 03:33:37 +0800 Subject: [PATCH 20/30] minor changes prepping for more fsnotify work --- libknary/http.go | 6 +++--- main.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libknary/http.go b/libknary/http.go index d19da7d..a6c312f 100644 --- a/libknary/http.go +++ b/libknary/http.go @@ -130,11 +130,11 @@ func Accept443(ln net.Listener, wg *sync.WaitGroup, restart <-chan bool) { ln.Close() // close listener so we can restart it ln443 := Listen443() // restart listener go Accept443(ln443, wg, restart) - msg := "TLS server restarted." + msg := "TLS server successfully restarted." logger("INFO", msg) Printy(msg, 3) - go sendMsg(msg + "```") - return + go sendMsg(":lock: " + msg) + return // important default: conn, err := ln.Accept() // accept connections until channel says stop diff --git a/main.go b/main.go index f82edfc..1917e48 100644 --- a/main.go +++ b/main.go @@ -179,7 +179,7 @@ func main() { go libknary.Accept443(ln443, &wg, restart) _, _ = libknary.CheckTLSExpiry(30) // check TLS expiry on first lauch of knary - libknary.TLSmonitor(restart) // monitor filesystem changes to the TLS cert to trigger a reboot + go libknary.TLSmonitor(restart) // monitor filesystem changes to the TLS cert to trigger a reboot } } From c8e54c2af14e3514dca1fcaa759770d316f1605f Mon Sep 17 00:00:00 2001 From: sudosammy Date: Sun, 9 Jan 2022 21:14:16 +0800 Subject: [PATCH 21/30] fsnotify update --- go.mod | 2 +- go.sum | 3 ++- libknary/fsnotify.go | 55 ++++++++++++++++++++++---------------------- libknary/http.go | 2 +- 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 87c6b9c..67e8e0b 100644 --- a/go.mod +++ b/go.mod @@ -5,10 +5,10 @@ go 1.16 require ( github.com/blang/semver/v4 v4.0.0 github.com/fatih/color v1.10.0 - github.com/fsnotify/fsnotify v1.4.9 github.com/go-acme/lego/v4 v4.3.1 github.com/joho/godotenv v1.3.0 github.com/miekg/dns v1.1.41 + github.com/radovskyb/watcher v1.0.7 golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750 // indirect ) diff --git a/go.sum b/go.sum index bf61e93..3d014e1 100644 --- a/go.sum +++ b/go.sum @@ -100,7 +100,6 @@ github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -322,6 +321,8 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/radovskyb/watcher v1.0.7 h1:AYePLih6dpmS32vlHfhCeli8127LzkIgwJGcwwe8tUE= +github.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg= github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= diff --git a/libknary/fsnotify.go b/libknary/fsnotify.go index 8e6a112..9b838f1 100644 --- a/libknary/fsnotify.go +++ b/libknary/fsnotify.go @@ -1,52 +1,53 @@ package libknary -// Thanks https://medium.com/@skdomino/watch-this-file-watching-in-go-5b5a247cf71f // Eventually this will support deny/allowlists too import ( "log" "os" + "path/filepath" + "time" - "github.com/fsnotify/fsnotify" + "github.com/radovskyb/watcher" ) func TLSmonitor(restart chan bool) { - // creates a new file watcher - watcher, err := fsnotify.NewWatcher() - if err != nil { - logger("ERROR", err.Error()) - GiveHead(2) - log.Fatal(err) - } - defer watcher.Close() - done := make(chan bool) + w := watcher.New() + + // get filepath of certificate store + certDir := filepath.Dir(os.Getenv("TLS_KEY")) + + // Only notify write events. + w.FilterOps(watcher.Write) go func() { for { select { - // watch for events - case event := <-watcher.Events: - if event.Op&fsnotify.Write == fsnotify.Write { // trigger reload of certificates! - msg := "TLS key changed! The TLS listener will be restarted on next HTTPS request to knary." - logger("INFO", msg) - Printy(msg, 3) - go sendMsg(msg + "```") - - restart <- true // TODO: why does notification have to come first here... + case event := <-w.Event: + if event.Op == watcher.Write && event.IsDir() { + continue // skip on folder changes } - - // watch for errors - case err := <-watcher.Errors: + logger("INFO", "Server will reload on next HTTPS request to knary") + restart <- true + case err := <-w.Error: logger("ERROR", err.Error()) - Printy(err.Error(), 2) + GiveHead(2) + log.Fatal(err) + case <-w.Closed: + return } } }() - if err := watcher.Add(os.Getenv("TLS_KEY")); err != nil { + // Watch the certificate directory for changes. + if err := w.Add(certDir); err != nil { logger("ERROR", err.Error()) - Printy(err.Error(), 2) + GiveHead(2) + log.Fatal(err) } - <-done + // Start the watching process - it'll check for changes every 1000ms. + if err := w.Start(time.Millisecond * 1000); err != nil { + log.Fatalln(err) + } } diff --git a/libknary/http.go b/libknary/http.go index a6c312f..9457251 100644 --- a/libknary/http.go +++ b/libknary/http.go @@ -130,7 +130,7 @@ func Accept443(ln net.Listener, wg *sync.WaitGroup, restart <-chan bool) { ln.Close() // close listener so we can restart it ln443 := Listen443() // restart listener go Accept443(ln443, wg, restart) - msg := "TLS server successfully restarted." + msg := "HTTPS / TLS server successfully reloaded." logger("INFO", msg) Printy(msg, 3) go sendMsg(":lock: " + msg) From 377c308067085d1edc60243f0cad6bab829b4993 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Sun, 9 Jan 2022 21:59:24 +0800 Subject: [PATCH 22/30] LE fix: missing underscore on cert names in fileExists check --- libknary/certbot.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libknary/certbot.go b/libknary/certbot.go index 00ee4ae..c2f0d47 100644 --- a/libknary/certbot.go +++ b/libknary/certbot.go @@ -129,20 +129,20 @@ func StartLetsEncrypt() string { certsStorage := cmd.NewCertificatesStorage() // should only request certs if currently none exist - if fileExists(certsStorage.GetFileName(GetFirstDomain(), ".key")) && - fileExists(certsStorage.GetFileName(GetFirstDomain(), ".crt")) { + if fileExists(certsStorage.GetFileName("*."+GetFirstDomain(), ".key")) && + fileExists(certsStorage.GetFileName("*."+GetFirstDomain(), ".crt")) { if os.Getenv("DEBUG") == "true" { - Printy("TLS private key found: "+certsStorage.GetFileName(GetFirstDomain(), ".key"), 3) - Printy("TLS certificate found: "+certsStorage.GetFileName(GetFirstDomain(), ".crt"), 3) + Printy("TLS private key found: "+certsStorage.GetFileName("*."+GetFirstDomain(), ".key"), 3) + Printy("TLS certificate found: "+certsStorage.GetFileName("*."+GetFirstDomain(), ".crt"), 3) } return cmd.SanitizedDomain(GetFirstDomain()) } if os.Getenv("DEBUG") == "true" { Printy("No existing certificates found at:", 3) - Printy(certsStorage.GetFileName(GetFirstDomain(), ".key"), 2) - Printy(certsStorage.GetFileName(GetFirstDomain(), ".crt"), 2) + Printy(certsStorage.GetFileName("*."+GetFirstDomain(), ".key"), 2) + Printy(certsStorage.GetFileName("*."+GetFirstDomain(), ".crt"), 2) Printy("Let's Encrypt ourselves some new ones!", 3) } From 5ddf9b7845f1759412fd039292b9c9f659c8166f Mon Sep 17 00:00:00 2001 From: sudosammy Date: Sun, 9 Jan 2022 22:00:37 +0800 Subject: [PATCH 23/30] LE fix: missing underscore on cert names in fileExists check --- libknary/certbot.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libknary/certbot.go b/libknary/certbot.go index c2f0d47..d6001c3 100644 --- a/libknary/certbot.go +++ b/libknary/certbot.go @@ -136,7 +136,7 @@ func StartLetsEncrypt() string { Printy("TLS private key found: "+certsStorage.GetFileName("*."+GetFirstDomain(), ".key"), 3) Printy("TLS certificate found: "+certsStorage.GetFileName("*."+GetFirstDomain(), ".crt"), 3) } - return cmd.SanitizedDomain(GetFirstDomain()) + return cmd.SanitizedDomain("*." + GetFirstDomain()) } if os.Getenv("DEBUG") == "true" { From 91feea416cf181bec8892bd4c174f62422b54d84 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Sun, 9 Jan 2022 22:12:35 +0800 Subject: [PATCH 24/30] go-staticcheck --- libknary/certutil.go | 2 +- libknary/dns.go | 2 +- libknary/notificationctrl.go | 6 ++---- libknary/util.go | 2 +- libknary/zones.go | 3 +-- 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/libknary/certutil.go b/libknary/certutil.go index b45e4c7..79d753c 100644 --- a/libknary/certutil.go +++ b/libknary/certutil.go @@ -60,7 +60,7 @@ func loadMyUser() *cmd.Account { account = &cmd.Account{Email: accountStorage.GetUserID(), Key: privateKey} } - return &*account + return account } func registerAccount(client *lego.Client) *registration.Resource { diff --git a/libknary/dns.go b/libknary/dns.go index 4323a30..ba99bd8 100644 --- a/libknary/dns.go +++ b/libknary/dns.go @@ -310,7 +310,7 @@ func GuessIP(domain string) (string, error) { // query the tld's nameserver for our knary domain and extract the glue record from additional information kMsg := new(dns.Msg) kMsg.SetQuestion(dns.Fqdn(domain), dns.TypeNS) - answ, _, err := new(dns.Client).Exchange(kMsg, tldDNS+":53") + answ, _, _ := new(dns.Client).Exchange(kMsg, tldDNS+":53") if len(answ.Extra) == 0 { return "", errors.New("No 'Additional' section in NS lookup for: " + domain + " with nameserver: " + tldDNS + " Have you configured a glue record for your domain? Has it propagated? You can set EXT_IP to bypass this but... do you know what you're doing?") diff --git a/libknary/notificationctrl.go b/libknary/notificationctrl.go index 14ee4b5..d86d95a 100644 --- a/libknary/notificationctrl.go +++ b/libknary/notificationctrl.go @@ -75,12 +75,11 @@ func LoadAllowlist() (bool, error) { } alwlist, err := os.Open(os.Getenv("ALLOWLIST_FILE")) - defer alwlist.Close() - if err != nil { Printy(err.Error()+" - ignoring", 3) return false, err } + defer alwlist.Close() scanner := bufio.NewScanner(alwlist) @@ -107,12 +106,11 @@ func LoadBlacklist() (bool, error) { } blklist, err := os.Open(os.Getenv("DENYLIST_FILE")) - defer blklist.Close() - if err != nil { Printy(err.Error()+" - ignoring", 3) return false, err } + defer blklist.Close() scanner := bufio.NewScanner(blklist) diff --git a/libknary/util.go b/libknary/util.go index 0469710..0c56dc4 100644 --- a/libknary/util.go +++ b/libknary/util.go @@ -149,7 +149,7 @@ func CheckUpdate(version string, githubVersion string, githubURL string) (bool, return false, err } - if running.LT(current) == true { + if running.LT(current) { updMsg := "Your version of knary is *" + version + "* & the latest is *" + current.String() + "* - upgrade your binary here: " + githubURL Printy(updMsg, 2) logger("WARNING", updMsg) diff --git a/libknary/zones.go b/libknary/zones.go index ad5adf9..2417a19 100644 --- a/libknary/zones.go +++ b/libknary/zones.go @@ -24,12 +24,11 @@ func LoadZone() (bool, error) { } zlist, err := os.Open(os.Getenv("ZONE_FILE")) - defer zlist.Close() - if err != nil { Printy(err.Error()+" - ignoring", 3) return false, err } + defer zlist.Close() // https://pkg.go.dev/github.com/miekg/dns#ZoneParser zp := dns.NewZoneParser(bufio.NewReader(zlist), "", "") From 3c663c4c6bec1a97ce2181c5e129ef6a7342b6e2 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Mon, 10 Jan 2022 01:22:02 +0800 Subject: [PATCH 25/30] fix bug that prevented BYO certs not being in certs/ --- examples/README.md | 2 +- libknary/certutil.go | 2 +- libknary/fsnotify.go | 17 ++++++----- libknary/lego/accounts_storage.go | 4 +-- libknary/lego/cert_storage.go | 49 ++++++++++++++++++------------- libknary/lego/storage.go | 2 +- 6 files changed, 42 insertions(+), 34 deletions(-) diff --git a/examples/README.md b/examples/README.md index 5a895ff..a9bdd72 100644 --- a/examples/README.md +++ b/examples/README.md @@ -30,7 +30,7 @@ If you are running Burp Collaborator on the same server as knary, you will need * `BURP_INT_IP` __Optional__ The internal IP address that Burp Collaborator is bound to. In most cases this will be `127.0.0.1` (which is the default); however, if you run knary in Docker you may need to set this to the Burp Collaborator IP address reachable from within the knary container ## Optional Configurations -* `TLS_*` (CRT/KEY). If you're not using the `LETS_ENCRYPT` configuration use these environment variables to configure the location of your certificate and private key for accepting TLS (HTTPS) requests +* `TLS_*` (CRT/KEY). If you're not using the `LETS_ENCRYPT` configuration use these environment variables to configure the location of your certificate and private key for accepting TLS (HTTPS) requests. Example input `TLS_KEY=certs/knary.key` & `TLS_CRT=certs/knary.crt` * `DEBUG` Enable/Disable displaying incoming requests in the terminal and some additional info. Default disabled (true/false) * `ALLOWLIST_STRICT` Set to `true` to prevent fuzzy matching on allowlist items and only alert on exact matches * `LE_ENV` Set to `staging` to use the Let's Encrypt's staging environment. Useful if you are testing configurations with Let's Encrypt and do not want to hit the rate limit diff --git a/libknary/certutil.go b/libknary/certutil.go index 79d753c..aa10d24 100644 --- a/libknary/certutil.go +++ b/libknary/certutil.go @@ -78,7 +78,7 @@ func needRenewal(days int) (bool, int) { certName := strings.TrimSuffix(filepath.Base(os.Getenv("TLS_CRT")), filepath.Ext(os.Getenv("TLS_CRT"))) certExt := filepath.Ext(os.Getenv("TLS_CRT")) - certsStorage := cmd.NewCertificatesStorage() // there's a bug here that forces certs to be in certs/ + certsStorage := cmd.NewCertificatesStorage() certificates, err := certsStorage.ReadCertificate(certName, certExt) if err != nil { logger("ERROR", err.Error()) diff --git a/libknary/fsnotify.go b/libknary/fsnotify.go index 9b838f1..3e2f120 100644 --- a/libknary/fsnotify.go +++ b/libknary/fsnotify.go @@ -5,19 +5,17 @@ package libknary import ( "log" "os" - "path/filepath" "time" "github.com/radovskyb/watcher" + cmd "github.com/sudosammy/knary/libknary/lego" ) func TLSmonitor(restart chan bool) { w := watcher.New() - // get filepath of certificate store - certDir := filepath.Dir(os.Getenv("TLS_KEY")) - - // Only notify write events. + certDir := cmd.GetCertPath() + // Only notify write events w.FilterOps(watcher.Write) go func() { @@ -28,6 +26,9 @@ func TLSmonitor(restart chan bool) { continue // skip on folder changes } logger("INFO", "Server will reload on next HTTPS request to knary") + if os.Getenv("DEBUG") == "true" { + Printy("Server will reload on next HTTPS request to knary", 3) + } restart <- true case err := <-w.Error: logger("ERROR", err.Error()) @@ -39,15 +40,15 @@ func TLSmonitor(restart chan bool) { } }() - // Watch the certificate directory for changes. + // watch the certificate directory for changes. if err := w.Add(certDir); err != nil { logger("ERROR", err.Error()) GiveHead(2) log.Fatal(err) } - // Start the watching process - it'll check for changes every 1000ms. - if err := w.Start(time.Millisecond * 1000); err != nil { + // start the watching process - it'll check for changes every second. + if err := w.Start(time.Second * 1); err != nil { log.Fatalln(err) } } diff --git a/libknary/lego/accounts_storage.go b/libknary/lego/accounts_storage.go index ef8b030..4ff7025 100644 --- a/libknary/lego/accounts_storage.go +++ b/libknary/lego/accounts_storage.go @@ -30,8 +30,8 @@ func NewAccountsStorage() *AccountsStorage { email := os.Getenv("LETS_ENCRYPT") return &AccountsStorage{ userID: email, - accountFilePath: filepath.Join(baseCertificatesFolderName, "account.json"), - keyFilePath: filepath.Join(baseCertificatesFolderName, "knary.key"), + accountFilePath: filepath.Join(GetCertPath(), "account.json"), + keyFilePath: filepath.Join(GetCertPath(), "knary.key"), } } diff --git a/libknary/lego/cert_storage.go b/libknary/lego/cert_storage.go index 912c4c1..a65f92d 100644 --- a/libknary/lego/cert_storage.go +++ b/libknary/lego/cert_storage.go @@ -20,28 +20,36 @@ import ( "golang.org/x/net/idna" ) -func init() { - if os.Getenv("CERT_LOCATION") != "" { - // TODO - // something to correctly set baseCertificatesFolderName & baseArchivesFolderName - // doesn't need to be a env var, being able to read TLS_* env variable would work for non-LE genned certs - // but then LE genned certs would still be put in certs/ ... Probably not an issue though. - } -} - -var baseCertificatesFolderName = "certs" -var baseArchivesFolderName = filepath.Join(baseCertificatesFolderName, "archives") - -// CertificatesStorage a certificates storage. -// -// rootPath: +// GetCertPath(): // /knary/certs/ // └── root certificates directory // -// archivePath: +// archive file path: // /knary/certs/archives/ // └── archived certificates directory // +func GetCertPath() string { + var certFolderName string + + if !filepath.IsAbs(os.Getenv("TLS_CRT")) { + pwd, err := os.Getwd() + if err != nil { + log.Fatalf(err.Error()) + } + + path, err := filepath.Abs(filepath.Join(pwd, os.Getenv("TLS_CRT"))) + if err != nil { + log.Fatalf(err.Error()) + } + + certFolderName = filepath.Dir(path) + } else { + certFolderName = filepath.Dir(os.Getenv("TLS_CRT")) + } + + return certFolderName +} + type CertificatesStorage struct { rootPath string archivePath string @@ -51,8 +59,8 @@ type CertificatesStorage struct { // NewCertificatesStorage create a new certificates storage. func NewCertificatesStorage() *CertificatesStorage { return &CertificatesStorage{ - rootPath: filepath.Join(baseCertificatesFolderName), - archivePath: filepath.Join(baseArchivesFolderName), + rootPath: GetCertPath(), + archivePath: filepath.Join(GetCertPath(), "archives"), pem: true, } } @@ -137,11 +145,10 @@ func (s *CertificatesStorage) ReadCertificate(domain, extension string) ([]*x509 } func (s *CertificatesStorage) WriteFile(domain, extension string, data []byte) error { - var baseFileName string - baseFileName = SanitizedDomain(domain) + baseFileName := SanitizedDomain(domain) filePath := filepath.Join(s.rootPath, baseFileName+extension) - return ioutil.WriteFile(filePath, data, 400) + return ioutil.WriteFile(filePath, data, 0400) } func (s *CertificatesStorage) MoveToArchive(domain string) error { diff --git a/libknary/lego/storage.go b/libknary/lego/storage.go index b5f2d34..4c51eb7 100644 --- a/libknary/lego/storage.go +++ b/libknary/lego/storage.go @@ -7,7 +7,7 @@ import ( ) func CreateFolderStructure() { - folder := filepath.Join(baseArchivesFolderName) + folder := filepath.Join(GetCertPath() + "archives") err := os.MkdirAll(folder, os.ModePerm) if err != nil { log.Fatal(err) From de96834b4e2ff23feeaccf8fc1ba307818f47db2 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Tue, 11 Jan 2022 19:39:37 +0800 Subject: [PATCH 26/30] v3.4 prep. bump go.mod. add circleci. fix some tests --- .circleci/config.yml | 29 +++++ .travis.yml | 24 ---- VERSION | 2 +- examples/README.md | 2 +- go.mod | 16 ++- go.sum | 249 ++++++++++++++++++++++++++---------------- libknary/util_test.go | 30 +++-- main.go | 4 +- 8 files changed, 217 insertions(+), 139 deletions(-) create mode 100644 .circleci/config.yml delete mode 100644 .travis.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..da3d887 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,29 @@ +version: 2.1 +orbs: + coveralls: coveralls/coveralls@1.0.6 +jobs: + build: + working_directory: ~/repo + docker: + - image: cimg/go:1.16 + - image: cimg/go:1.17 + parallelism: 2 + steps: + - checkout + - restore_cache: + keys: + - go-mod-v4-{{ checksum "go.sum" }} + - run: + name: Install Dependencies + command: go get -u -t + - save_cache: + key: go-mod-v4-{{ checksum "go.sum" }} + paths: + - "/go/pkg/mod" + - run: + name: Run tests + command: go test -v ./... + - coveralls/upload + - run: + name: Run Go Vet + command: go vet ./... \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 494c13b..0000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: go - -go: - - 1.19.x - - 1.18.x - - 1.17.x - - 1.16.x - - -# only clone the latest commit -git: - depth: 1 - - -before_install: - - go get github.com/mattn/goveralls - -# to prevent sudo using the secure_path we using -E option -# and letting it use the users env variables, not doing this results in -# a PATH bug and go command not found -script: - - sudo -E env "PATH=$PATH" go test -v ./... - - sudo -E env "PATH=$PATH" $GOPATH/bin/goveralls -service=travis-ci - - sudo -E env "PATH=$PATH" go vet ./... diff --git a/VERSION b/VERSION index 5436ea0..fbcbf73 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.3.2 \ No newline at end of file +3.4.0 \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index a9bdd72..44eeab8 100644 --- a/examples/README.md +++ b/examples/README.md @@ -30,7 +30,7 @@ If you are running Burp Collaborator on the same server as knary, you will need * `BURP_INT_IP` __Optional__ The internal IP address that Burp Collaborator is bound to. In most cases this will be `127.0.0.1` (which is the default); however, if you run knary in Docker you may need to set this to the Burp Collaborator IP address reachable from within the knary container ## Optional Configurations -* `TLS_*` (CRT/KEY). If you're not using the `LETS_ENCRYPT` configuration use these environment variables to configure the location of your certificate and private key for accepting TLS (HTTPS) requests. Example input `TLS_KEY=certs/knary.key` & `TLS_CRT=certs/knary.crt` +* `TLS_*` (CRT/KEY). If you're not using the `LETS_ENCRYPT` configuration use these environment variables to configure the location of your certificate and private key for accepting TLS (HTTPS) requests. Example input `TLS_KEY=certs/knary.key` * `DEBUG` Enable/Disable displaying incoming requests in the terminal and some additional info. Default disabled (true/false) * `ALLOWLIST_STRICT` Set to `true` to prevent fuzzy matching on allowlist items and only alert on exact matches * `LE_ENV` Set to `staging` to use the Let's Encrypt's staging environment. Useful if you are testing configurations with Let's Encrypt and do not want to hit the rate limit diff --git a/go.mod b/go.mod index 67e8e0b..3ba3038 100644 --- a/go.mod +++ b/go.mod @@ -4,11 +4,15 @@ go 1.16 require ( github.com/blang/semver/v4 v4.0.0 - github.com/fatih/color v1.10.0 - github.com/go-acme/lego/v4 v4.3.1 - github.com/joho/godotenv v1.3.0 - github.com/miekg/dns v1.1.41 + github.com/cenkalti/backoff/v4 v4.1.2 // indirect + github.com/fatih/color v1.13.0 + github.com/go-acme/lego/v4 v4.5.3 + github.com/joho/godotenv v1.4.0 + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/miekg/dns v1.1.45 github.com/radovskyb/watcher v1.0.7 - golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 - golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750 // indirect + golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect + golang.org/x/net v0.0.0-20220111093109-d55c255bac03 + golang.org/x/sys v0.0.0-20220111092808-5a964db01320 // indirect + golang.org/x/tools v0.1.8 // indirect ) diff --git a/go.sum b/go.sum index 3d014e1..c86c228 100644 --- a/go.sum +++ b/go.sum @@ -21,38 +21,35 @@ cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIA cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/azure/auth v0.1.0/go.mod h1:Gf7/i2FUpyb/sGBLIFxTBzrNzBo7aPXXE3ZVeDRwdpM= -github.com/Azure/go-autorest/autorest/azure/cli v0.1.0/go.mod h1:Dk8CUAt/b/PzkfeRsWzVG9Yj3ps8mS8ECztu43rdU8U= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= -github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.17/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= +github.com/Azure/go-autorest/autorest v0.11.19/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.11/go.mod h1:nBKAnTomx8gDtl+3ZCJv2v0KACFHWTB2drffI1B68Pk= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.8/go.mod h1:kxyKZTSfKh8OVFWPAgOgQ/frrJgeYQJPyR5fLFmXko4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= +github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.0/go.mod h1:kX6YddBkXqqywAe8c9LyvgTCyFuZCTMF4cRPQhc3Fy8= +github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1/go.mod h1:kX6YddBkXqqywAe8c9LyvgTCyFuZCTMF4cRPQhc3Fy8= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/aliyun/alibaba-cloud-sdk-go v1.61.976/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/aliyun/alibaba-cloud-sdk-go v1.61.1183/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.37.27/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.39.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -62,16 +59,16 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw= -github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm4fSc= -github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= +github.com/cloudflare/cloudflare-go v0.20.0/go.mod h1:sPWL/lIC6biLEdyGZwBQ1rGQKF1FhM7N60fuNiFdYTI= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -84,28 +81,28 @@ github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deepmap/oapi-codegen v1.3.11/go.mod h1:suMvK7+rKlx3+tpa8ByptmvoXbAV70wERKTOGH3hLp0= +github.com/deepmap/oapi-codegen v1.6.1/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= -github.com/dnsimple/dnsimple-go v0.63.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/dnsimple/dnsimple-go v0.70.1/go.mod h1:F9WHww9cC76hrnwGFfAfrqdW99j3MOYasQcIwTS/aUk= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/exoscale/egoscale v0.46.0/go.mod h1:mpEXBpROAa/2i5GC0r33rfxG+TxSEka11g1PIXt9+zc= +github.com/exoscale/egoscale v0.67.0/go.mod h1:wi0myUxPsV8SdEtdJHQJxFLL/wEw9fiw9Gs1PWRkvkM= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= +github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-acme/lego/v4 v4.3.1 h1:rzmg0Gpy25B/exXjl+KgpG5Xt6wN5rFTLjRf/Uf3pfg= -github.com/go-acme/lego/v4 v4.3.1/go.mod h1:tySA24ifl6bI7kZ0+ocGtTIv4H1yhYVFAgyMHF2DSRg= -github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= +github.com/go-acme/lego/v4 v4.5.3 h1:v5RSN8l+RAeNHKTSL80eqLiec6q6UNaFpl2Df5x/5tM= +github.com/go-acme/lego/v4 v4.5.3/go.mod h1:mL1DY809LzjvRuaxINNxsI26f5oStVhBGTpJMiinkZM= +github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -114,11 +111,14 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -136,17 +136,27 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -162,13 +172,11 @@ github.com/gophercloud/gophercloud v0.15.1-0.20210202035223-633d73521055/go.mod github.com/gophercloud/gophercloud v0.16.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4= github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae/go.mod h1:wx8HMD8oQD0Ryhz6+6ykq75PJ79iPyEqYHfwZ4l7OsA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= @@ -179,7 +187,7 @@ github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrj github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= @@ -198,12 +206,14 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI= +github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jarcoal/httpmock v1.0.6/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -225,28 +235,33 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA= github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w= -github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= +github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/linode/linodego v0.25.3/go.mod h1:GSBKPpjoQfxEfryoCRcgkuUOCuVtGHWhzI8OMdycNTE= +github.com/linode/linodego v0.31.1/go.mod h1:BR0gVkCJffEdIGJSl6bHR80Ty+Uvg/2jkjmrWaFectM= github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs= github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs= github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ= github.com/liquidweb/liquidweb-go v1.6.3/go.mod h1:SuXXp+thr28LnjEw18AYtWwIbWMHSUiajPQs8T9c/Rc= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -254,9 +269,9 @@ github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4f github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/dns v1.1.45 h1:g5fRIhm9nx7g8osrAvgb16QJfmyMsyOCb+J7LSv+Qzk= +github.com/miekg/dns v1.1.45/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -267,6 +282,7 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -275,23 +291,28 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/nrdcg/auroradns v1.0.1/go.mod h1:y4pc0i9QXYlFCWrhWrUSIETnZgrf4KuwjDIWmmXo3JI= -github.com/nrdcg/desec v0.5.0/go.mod h1:2ejvMazkav1VdDbv2HeQO7w+Ta1CGHqzQr27ZBYTuEQ= +github.com/nrdcg/desec v0.6.0/go.mod h1:wybWg5cRrNmtXLYpUCPCLvz4jfFNEGZQEnoUiX9WqcY= github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ= +github.com/nrdcg/freemyip v0.2.0/go.mod h1:HjF0Yz0lSb37HD2ihIyGz9esyGcxbCrrGFLPpKevbx4= github.com/nrdcg/goinwx v0.8.1/go.mod h1:tILVc10gieBp/5PMvbcYeXM6pVQ+c9jxDZnpaR1UW7c= github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw= +github.com/nrdcg/porkbun v0.1.1/go.mod h1:JWl/WKnguWos4mjfp4YizvvToigk9qpQwrodOk+CPoA= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -302,21 +323,17 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= @@ -324,20 +341,25 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/radovskyb/watcher v1.0.7 h1:AYePLih6dpmS32vlHfhCeli8127LzkIgwJGcwwe8tUE= github.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg= github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/gunit v1.0.4/go.mod h1:EH5qMBab2UclzXUcpR8b93eHsIlp9u+pDQIRp5DZNzQ= +github.com/softlayer/softlayer-go v1.0.3/go.mod h1:6HepcfAXROz0Rf63krk5hPZyHT6qyx2MNvYyHof7ik4= +github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e/go.mod h1:fKZCUVdirrxrBpwd9wb+lSoVixvpwAu8eHzbQB2tums= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -358,26 +380,28 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/transip/gotransip/v6 v6.6.0/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g= +github.com/transip/gotransip/v6 v6.6.1/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g= github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/vultr/govultr/v2 v2.4.0/go.mod h1:U+dZLAmyGD62IGykgC9JYU/zQIOkIhf93nw6dJL/47M= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/vinyldns/go-vinyldns v0.0.0-20200917153823-148a5f6b8f14/go.mod h1:RWc47jtnVuQv6+lY3c768WtXCas/Xi+U5UFc5xULmYg= +github.com/vultr/govultr/v2 v2.7.1/go.mod h1:BvOhVe6/ZpjwcoL6/unkdQshmbS9VGbowI4QT+3DGVU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -391,17 +415,19 @@ golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -431,6 +457,10 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -439,7 +469,6 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -450,19 +479,27 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 h1:4qWs8cYYH6PoEFy4dfhDFgoMGkwAcETd+MmPdCPMzUc= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220111093109-d55c255bac03 h1:0FB83qp0AzVJm+0wcIlauAjJ+tNdh7jLuacRYCIVv7s= +golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -474,6 +511,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -484,11 +522,9 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -498,12 +534,11 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -514,15 +549,25 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201110211018-35f3e6cf4a65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750 h1:ZBu6861dZq7xBnG1bn5SRU0vA8nx42at4+kP07FMTog= -golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY= +golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -531,15 +576,17 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -562,7 +609,6 @@ golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -573,10 +619,16 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -610,15 +662,21 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4 google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -631,10 +689,10 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ns1/ns1-go.v2 v2.4.4/go.mod h1:GMnKY+ZuoJ+lVLL+78uSTjwTz2jMazq6AfGKQOYhsPk= +gopkg.in/ns1/ns1-go.v2 v2.6.2/go.mod h1:GMnKY+ZuoJ+lVLL+78uSTjwTz2jMazq6AfGKQOYhsPk= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= -gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -647,7 +705,6 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/libknary/util_test.go b/libknary/util_test.go index 02ded2c..553ff56 100644 --- a/libknary/util_test.go +++ b/libknary/util_test.go @@ -79,14 +79,16 @@ func TestCheckUpdate(t *testing.T) { func TestLoadBlackList(t *testing.T) { createFile() + f := openFile() + //case 1 when env variable is not even set val, err := LoadBlacklist() if val == true && err == nil { - t.Errorf("Expected to error out since BLACKLIST_FILE env variable not set") + t.Errorf("Expected to error out since DENYLIST_FILE env variable not set") } //second case env variable set but file not there - os.Setenv("BLACKLIST_FILE", "somerandomshit.txt") + os.Setenv("DENYLIST_FILE", "somerandomshit.txt") val, err = LoadBlacklist() if val == true && err == nil { @@ -94,14 +96,15 @@ func TestLoadBlackList(t *testing.T) { } //third case, everything in place including env var and blacklist filename - os.Setenv("BLACKLIST_FILE", "blacklist_test.txt") + os.Setenv("DENYLIST_FILE", "blacklist_test.txt") val, err = LoadBlacklist() if val == false { t.Errorf("Expected file to load without any errors, BUT got: %s", err) } - deleteFile() + f.Close() + deleteFile() } func TestStringContains(t *testing.T) { @@ -143,11 +146,19 @@ func writeDataToFile(data string, f *os.File) { } } -func createFile() *os.File { +func createFile() { f, err := os.Create("blacklist_test.txt") if err != nil { panic(err) } + f.Close() +} + +func openFile() *os.File { + f, err := os.OpenFile("blacklist_test.txt", os.O_WRONLY, 0666) + if err != nil { + panic(err) + } return f } @@ -159,9 +170,9 @@ func deleteFile() { } func TestInBlacklist(t *testing.T) { - os.Setenv("BLACKLIST_FILE", "blacklist_test.txt") - f := createFile() - defer f.Close() + os.Setenv("DENYLIST_FILE", "blacklist_test.txt") + createFile() + f := openFile() LoadBlacklist() dom := "mycanary.com" //first test is for empty blacklist file @@ -199,6 +210,7 @@ func TestInBlacklist(t *testing.T) { if val == true { t.Errorf("Expected false since it shouldnt match dns.mycanary.com when blacklist says mycanary.com") } - deleteFile() + f.Close() + deleteFile() } diff --git a/main.go b/main.go index 1917e48..a7ae197 100644 --- a/main.go +++ b/main.go @@ -14,7 +14,7 @@ import ( ) const ( - VERSION = "3.3.2" + VERSION = "3.4.0" GITHUB = "https://github.com/sudosammy/knary" GITHUBVERSION = "https://raw.githubusercontent.com/sudosammy/knary/master/VERSION" ) @@ -179,7 +179,7 @@ func main() { go libknary.Accept443(ln443, &wg, restart) _, _ = libknary.CheckTLSExpiry(30) // check TLS expiry on first lauch of knary - go libknary.TLSmonitor(restart) // monitor filesystem changes to the TLS cert to trigger a reboot + go libknary.TLSmonitor(restart) // monitor filesystem changes to the TLS cert to trigger a reboot } } From 736601c7380521ebccc987dc6dafdb21bff8cda8 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Tue, 11 Jan 2022 19:48:25 +0800 Subject: [PATCH 27/30] add build status badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 04569c6..8b0dc4b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # knary - A simple HTTP(S) and DNS Canary -[![Build Status](https://travis-ci.org/sudosammy/knary.svg?branch=master)](https://travis-ci.org/sudosammy/knary) [![Coverage Status](https://coveralls.io/repos/github/sudosammy/knary/badge.svg?branch=master)](https://coveralls.io/github/sudosammy/knary?branch=master) +[![Build Status](https://circleci.com/gh/sudosammy/knary/tree/master.svg?style=svg)](https://circleci.com/gh/sudosammy/knary/tree/master) [![Coverage Status](https://coveralls.io/repos/github/sudosammy/knary/badge.svg?branch=master)](https://coveralls.io/github/sudosammy/knary?branch=master) >Like "Canary" but more hipster, which means better 😎😎😎 From e5b1cf3a22264e1c8b2cc8b3ea2ef1196b24eacb Mon Sep 17 00:00:00 2001 From: sudosammy Date: Tue, 11 Jan 2022 19:55:46 +0800 Subject: [PATCH 28/30] add coveralls support --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index da3d887..248cd0c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,8 +5,8 @@ jobs: build: working_directory: ~/repo docker: - - image: cimg/go:1.16 - - image: cimg/go:1.17 + - image: cimg/go:1.16-node + - image: cimg/go:1.17-node parallelism: 2 steps: - checkout From 9e192bc3ae217237fe820011a13df8763d9c9423 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Tue, 11 Jan 2022 20:02:52 +0800 Subject: [PATCH 29/30] add coveralls support #2 --- .circleci/config.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 248cd0c..c2fb4a1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,13 +16,19 @@ jobs: - run: name: Install Dependencies command: go get -u -t + - run: + name: Install gcov2lcov + command: go install github.com/jandelgado/gcov2lcov@latest - save_cache: key: go-mod-v4-{{ checksum "go.sum" }} paths: - "/go/pkg/mod" - run: name: Run tests - command: go test -v ./... + command: go test -v -coverprofile=coverage.out ./... + - run: + name: Convert Coverage Profile to Coveralls + command: mkdir coverage && gcov2lcov -infile=coverage.out -outfile=coverage/lcov.info - coveralls/upload - run: name: Run Go Vet From 0cf42504b5c718875cd088f27d748563a167cdc1 Mon Sep 17 00:00:00 2001 From: sudosammy Date: Tue, 11 Jan 2022 20:07:52 +0800 Subject: [PATCH 30/30] change go get to go install --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8b0dc4b..2627af8 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Defenders also use canaries as tripwires that can alert them of an attacker with __Prerequisite:__ You need Go >=1.16 to build knary. ``` -go get -u github.com/sudosammy/knary +go install github.com/sudosammy/knary@latest ``` **Important:** The specifics of how to perform the next two steps will depend on your domain registrar. Google `How to set Glue Record on ` to get started. Ultimately, you need to configure your knary domain(s) to make use of itself as the nameserver (i.e. `ns1.knary.tld` and `ns2.knary.tld`) and configure Glue Records to point these nameservers back to your knary host. You may need to raise a support ticket to have this performed by your registrar.