如何在golang中查找和检查spf记录?

how to do spf record lookup and check in golang?

我需要进行域 spf 查找并且 return 通过/失败 如果失败,我需要 return SPF 记录以进一步诊断

github 上似乎有很多 golang 模块用于 SPF 检查,但它们似乎都没有维护 另外 "official" 支持的模块是什么

这是我的代码,请评论

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net"
    "os"

    "github.com/mileusna/spf"
)

func main() {
    domain := os.Args[1]
    log.SetOutput(ioutil.Discard)   // If I dont do this there are a lot of debug logs 
    ip := net.ParseIP("1.2.3.4")
    r := spf.CheckHost(ip, domain, "", "")
    fmt.Printf("Domain = %s\nSPF=%s", domain, r.String())   // I need to return the value , 
                                                           // How do I get the spf record 

}

如果我下载 github 模块并更改源代码是个好主意吗??

我考虑了几分钟是否可以回答这个问题。这样做的原因是您显然希望我们为您阅读该模块代码并提出解决方案。老实说,这有点被认为是你有 "requirements" 的事情,涉及业务。

但是,其他人可能会从中学习,您必须付出足够的努力才能使代码足够健壮(IPv6,有人吗?)。

基本上,您有两个问题:"How to get the SPF record for a domain and return it when there is one?" 和 "How to properly deal with code submissions on github (or git based code hosters in general)?"

如何获取域的 SPF 记录(如果有)?

归根结底,SPF 是一项利用现有技术的公约。 SPF 条目只不过是域中特殊格式的 TXT 资源记录。

因此,您不需要任何包来查找我们的域是否具有 SPF 条目:

package main

import (
    "flag"
    "log"
    "net"
    "os"
    "regexp"
)

var domain string

var spfPattern *regexp.Regexp
var verbose bool

func init() {

    // some flags to make the problem more usable.
    flag.StringVar(&domain, "domain", "", "the domain to check for SPF records")
    flag.BoolVar(&verbose, "verbose", false, "print moar!")

    // Obviously, this is a very, very simple pattern.
    // It lacks any true validation whether the TXT record
    // is in fact a valid SPF. Expanding the regex should
    // not be too hard and I leave it up to you.
    spfPattern = regexp.MustCompile(`\s*v=spf1.*`)
}

func main() {
    flag.Parse()

    // Lookup ALL resource records rs of type TXT for domain.
    rs, err := net.LookupTXT(domain)

    // If there was an error accessing the TXT records...
    if err != nil {
        // ...we inform the user and...
        log.Printf("accessing TXT records for %s", err)
        // ...inform the caller that something went wrong.
        os.Exit(1)
    }

    // Now we have all TXT records for the domain we iterate through them...
    for _, rr := range rs {
        // ... and if one of them matches the pattern of an SPF record...
        if spfPattern.MatchString(rr) {

            // ...we inform the user if the user requested it...
            if verbose {
                log.Printf("%s has a valid SPFv1 record: %s", domain, rr)
            }
            // ...or simply inform the caller, as per the UNIX convention
            // "No news is good news!"
            os.Exit(0)
        }
    }
    // We have iterated through all TXT records and did not find matching
    // the pattern of an SPF record, so we need to inform both the user...
    log.Println("No valid SPF record found.")

    // ...and the caller.
    os.Exit(2)
}

如何正确处理代码贡献

如果您看到您认为需要扩展的代码,或者您发现了一个错误并想要修复它,您首先想到的应该做的是 fork the original repository——基本上,您复制它,具有保留提交历史的优势。

接下来,您克隆您的分叉,并在该分叉上完成您想做的工作。您应该使用一个或多个 branches 进行更改。 每个提交都应该尽可能的原子化。理想情况下,库在任何提交之前和之后编译和测试 运行。

当你完成后,你认为你的代码可以发布了,你创建一个 pull request. A pull request basically says "Hey, owner of the original repository, I have made some changes and improved the code, you might want to consider merging 我对原始代码的更改!"

现在很多项目都用a branching model called "gitflow",我强烈建议大家背到背唱为止即使 BAC 非常高。

您可以参考这篇文章进行 SPF 查询。

https://ashish.one/gist/spf-lookup-in-go/

在此,它正在使用此 DNS 库:

https://github.com/miekg/dns

SPF 查找只不过是获取 TXT Records 并搜索您在问题中提到的字符串 v=spf1 。它也是这样做的。

您可以使用任何符合您要求的模块,并且可以对其进行更改。如果您发现您的更改对其他人也有帮助,并且它更通用,那么您应该为特定的 git 回购提出 PR(拉取请求)。

如果您的更改仅受您的要求限制,那么您应该将该代码仅供您使用。最好使用 fork,你可以用你的更改维护你自己的 repo。

如果你没有使用任何 fork 并且仍然使用原始项目,那么以后将很难更新特定的库。

我是您正在使用的软件包的作者https://github.com/mileusna/spf

程序包具有 LookupSPF(domain) 函数,它将 return SPF TXT 记录,请查看文档 https://pkg.go.dev/github.com/mileusna/spf#LookupSPF

对于维护,SPF 是根据最近未更新的 RFC 7208 实现的,并且没有人报告包有任何问题,因此实际上不需要维护。 :) 它很管用,至少满足我的需要。

顺便说一句,我刚刚添加了对 Go 模块的支持。

如果您有任何问题或建议,请 post 在 GitHub 上提出。 :)