并发写入 csv:“切片边界超出范围”

我正在尝试从网站列表中提取证书信息并将其写入 csv。我不断遇到同样的错误,但并不总是在同一时间和在不同的域上。


我在第 63 行收到错误:err := writer.Write(data)


main.analyzeDomains(0xc0000840c0, 0xc0000126c0)

        /root/BreakCert/SSLCert/src/main.go:95 +0x5f

created by main.main

        /root/BreakCert/SSLCert/src/main.go:113 +0x1bf

panic: runtime error: slice bounds out of range


goroutine 35 [running]:

bufio.(*Writer).Flush(0xc000024140, 0x400002400, 0x0)

        /usr/local/go/src/bufio/bufio.go:590 +0x1c0

bufio.(*Writer).WriteByte(0xc000024140, 0xc0000aa92c, 0xc000452500, 0x4d1)

        /usr/local/go/src/bufio/bufio.go:645 +0x96

bufio.(*Writer).WriteRune(0xc000024140, 0xc00000002c, 0x4d1, 0x4d1, 0x0)

        /usr/local/go/src/bufio/bufio.go:657 +0x1aa

encoding/csv.(*Writer).Write(0xc0000126c0, 0xc00060a000, 0x5, 0x8, 0x2, 0x1a)

        /usr/local/go/src/encoding/csv/writer.go:47 +0x4b8

main.storeCertificate(0xc00018cb00, 0xc0000126c0, 0xc000396380, 0x12)

        /root/BreakCert/SSLCert/src/main.go:63 +0x3e9

main.analyzeDomain(0xc000396380, 0x12, 0xc0000126c0)

        /root/BreakCert/SSLCert/src/main.go:88 +0x19d

main.analyzeDomains(0xc0000840c0, 0xc0000126c0)

        /root/BreakCert/SSLCert/src/main.go:95 +0x5f

created by main.main

        /root/BreakCert/SSLCert/src/main.go:113 +0x1bf

exit status 2

并像这样使用

cat domains | go run main.go

域每行包含一个 url。


慕神8447489
浏览 75回答 1
1回答

哆啦的时光机

这是OP问题的一种解决方案// echo -e "google.com\ncnn.com\nstackoverflow.com" | go run main.gopackage mainimport (&nbsp; "bufio"&nbsp; "crypto/rsa"&nbsp; "crypto/tls"&nbsp; "crypto/x509"&nbsp; "encoding/csv"&nbsp; "io"&nbsp; "log"&nbsp; "net"&nbsp; "os"&nbsp; "strconv"&nbsp; "strings"&nbsp; "sync"&nbsp; "time")func certToCSV(cert *x509.Certificate, domain string) []string {&nbsp; var data []string&nbsp; data = append(data, domain[:len(domain)-4])&nbsp; var org string&nbsp; if len(cert.Issuer.Organization) > 0 {&nbsp; &nbsp; org = cert.Issuer.Organization[0]&nbsp; }&nbsp; data = append(data, org)&nbsp; if cert.PublicKey != nil {&nbsp; &nbsp; rsaPublicKey := cert.PublicKey.(*rsa.PublicKey)&nbsp; &nbsp; data = append(data, rsaPublicKey.N.String())&nbsp; &nbsp; data = append(data, strconv.Itoa(rsaPublicKey.E))&nbsp; &nbsp; data = append(data, strconv.Itoa(rsaPublicKey.Size()))&nbsp; }&nbsp; return data}func getCerts(d string) ([]*x509.Certificate, error) {&nbsp; out := []*x509.Certificate{}&nbsp; dialer := net.Dialer{}&nbsp; dialer.Timeout = 10 * time.Second&nbsp; conn, err := tls.DialWithDialer(&dialer, "tcp", d, &tls.Config{&nbsp; &nbsp; InsecureSkipVerify: true,&nbsp; })&nbsp; if err != nil {&nbsp; &nbsp; return out, err&nbsp; }&nbsp; defer conn.Close()&nbsp; for _, cert := range conn.ConnectionState().PeerCertificates {&nbsp; &nbsp; if v := cert.PublicKeyAlgorithm.String(); v != "RSA" {&nbsp; &nbsp; &nbsp; log.Printf("%q not using RSA algorithm but %q", d, cert.PublicKeyAlgorithm)&nbsp; &nbsp; &nbsp; continue&nbsp; &nbsp; }&nbsp; &nbsp; if len(cert.Issuer.Organization) < 1 {&nbsp; &nbsp; &nbsp; log.Printf("%q does not have organization", d)&nbsp; &nbsp; &nbsp; continue&nbsp; &nbsp; }&nbsp; &nbsp; out = append(out, cert)&nbsp; }&nbsp; return out, err}func analyze(dst chan []string, src chan string, errs chan error) {&nbsp; for domain := range src {&nbsp; &nbsp; certs, err := getCerts(domain)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; errs <- err&nbsp; &nbsp; &nbsp; continue&nbsp; &nbsp; }&nbsp; &nbsp; for _, cert := range certs {&nbsp; &nbsp; &nbsp; record := certToCSV(cert, domain)&nbsp; &nbsp; &nbsp; dst <- record&nbsp; &nbsp; }&nbsp; }}func readCSVFile(dst chan string, fp string) error {&nbsp; file, err := os.Create(fp)&nbsp; if err != nil {&nbsp; &nbsp; return err&nbsp; }&nbsp; defer file.Close()&nbsp; scanner := bufio.NewScanner(os.Stdin)&nbsp; for scanner.Scan() {&nbsp; &nbsp; line := scanner.Text()&nbsp; &nbsp; if !strings.Contains(line, ":") {&nbsp; &nbsp; &nbsp; line = line + ":443"&nbsp; &nbsp; }&nbsp; &nbsp; dst <- line&nbsp; }&nbsp; return scanner.Err()}func readCSV(dst chan string, src io.Reader) error {&nbsp; scanner := bufio.NewScanner(src)&nbsp; for scanner.Scan() {&nbsp; &nbsp; line := scanner.Text()&nbsp; &nbsp; if !strings.Contains(line, ":") {&nbsp; &nbsp; &nbsp; line = line + ":443"&nbsp; &nbsp; }&nbsp; &nbsp; dst <- line&nbsp; }&nbsp; return scanner.Err()}func writeCSV(dst io.Writer, src chan []string, errs chan error) {&nbsp; w := csv.NewWriter(dst)&nbsp; for record := range src {&nbsp; &nbsp; if err := w.Write(record); err != nil {&nbsp; &nbsp; &nbsp; errs <- err&nbsp; &nbsp; }&nbsp; &nbsp; w.Flush()&nbsp; }&nbsp; if err := w.Error(); err != nil {&nbsp; &nbsp; errs <- err&nbsp; }}func main() {&nbsp; var wg sync.WaitGroup&nbsp; errs := make(chan error)&nbsp; src := make(chan string)&nbsp; t1 := make(chan []string)&nbsp; // synchronize all routines to close errs once&nbsp; go func() {&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; close(errs)&nbsp; }()&nbsp; var wg2 sync.WaitGroup&nbsp; // analyze multiple domains in //&nbsp; for i := 0; i < 4; i++ {&nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; wg2.Add(1)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; &nbsp; defer wg2.Done()&nbsp; &nbsp; &nbsp; analyze(t1, src, errs)&nbsp; &nbsp; }()&nbsp; }&nbsp; // synchronize with analyze routines to close t1&nbsp; go func() {&nbsp; &nbsp; wg2.Wait()&nbsp; &nbsp; close(t1)&nbsp; }()&nbsp; // write the csv file&nbsp; wg.Add(1)&nbsp; go func() {&nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; writeCSV(os.Stdout, t1, errs)&nbsp; }()&nbsp; // read the csv, fail if an error occurs reading the source&nbsp; wg.Add(1)&nbsp; go func() {&nbsp; &nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; &nbsp; err := readCSV(src, os.Stdin)&nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Fatal(err)&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; close(src)&nbsp; }()&nbsp; // read and print errors, adjust exit code&nbsp; var exitCode int&nbsp; for err := range errs {&nbsp; &nbsp; log.Println(err)&nbsp; &nbsp; exitCode = 1&nbsp; }&nbsp; os.Exit(exitCode)}
打开App,查看更多内容
随时随地看视频慕课网APP