maraudir/common/net.go

145 lines
3.3 KiB
Go
Raw Normal View History

2024-11-21 06:16:20 +00:00
package common
import (
2024-11-30 22:11:38 +00:00
"crypto/tls"
"log/slog"
2024-11-21 06:16:20 +00:00
"net"
"strings"
"time"
"github.com/PuerkitoBio/goquery"
"github.com/valyala/fasthttp"
)
var (
// constants
Patterns = []string{"index of", "directory listing for"}
Ignore = []string{"..", ".", "../", "./", "parent directory", "last modified", "name", "size", "description"}
2024-11-21 06:16:20 +00:00
)
func ValidRange(r string) bool {
if _, _, err := net.ParseCIDR(r); err != nil {
return false
}
return true
}
func Entries(doc *goquery.Document) []string {
var list []string
doc.Find("a").Each(func(i int, s *goquery.Selection) {
if len(list) >= 100 {
return
}
text := strings.TrimSpace(s.Text())
for _, ig := range Ignore {
if text == ig {
return
}
}
list = append(list, text)
})
return list
}
func Checktitle(doc *goquery.Document) bool {
if title := doc.Find("title").Text(); len(title) > 0 {
for _, pattern := range Patterns {
if strings.Contains(title, pattern) {
return true
}
}
}
return false
}
func MkClient() *fasthttp.Client {
tmout := time.Duration(Conf.Tmout) * time.Millisecond
dialer := &fasthttp.TCPDialer{
Concurrency: 0,
}
return &fasthttp.Client{
MaxResponseBodySize: 10 * 1024 * 1024, // 10mb
ReadTimeout: 5 * time.Second,
2024-11-30 22:11:38 +00:00
WriteTimeout: 5 * time.Second,
2024-11-21 06:16:20 +00:00
MaxIdleConnDuration: 5 * time.Second,
MaxConnsPerHost: Conf.Threads,
NoDefaultUserAgentHeader: true,
DisableHeaderNamesNormalizing: true,
DisablePathNormalizing: true,
2024-11-30 22:11:38 +00:00
TLSConfig: &tls.Config{InsecureSkipVerify: true},
2024-11-21 06:16:20 +00:00
DialTimeout: func(addr string, timeout time.Duration) (net.Conn, error) {
return dialer.DialTimeout(addr, tmout)
},
}
}
func Hit(l *slog.Logger, c *fasthttp.Client, url string) error {
fallback, redirect := true, true
for {
if doc, redir, err := query(c, url); err == nil {
if doc != nil {
if Checktitle(doc) {
entries := Entries(doc)
l.Info("opendir", "url", url, "entries", entries)
}
} else if redir != "" && redirect {
url = redir
if !strings.HasPrefix(url, "https") {
fallback = false
}
redirect = false
continue
}
break
} else {
if !fallback {
return err
}
url = "http://" + url[8:]
fallback = false
}
}
return nil
}
func query(c *fasthttp.Client, url string) (*goquery.Document, string, error) {
2024-11-21 06:16:20 +00:00
req := fasthttp.AcquireRequest()
req.SetRequestURI(url)
req.Header.SetMethod(fasthttp.MethodGet)
req.Header.SetUserAgent(Conf.UserAgent)
2024-11-21 06:16:20 +00:00
defer fasthttp.ReleaseRequest(req)
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)
// goes to stderr for verbosity, not included when stdout is piped
if !Conf.Silent {
println("->", url)
}
var err error
if err = c.DoTimeout(req, resp, time.Duration(Conf.Tmout)*time.Millisecond); err == nil {
2024-11-30 22:11:38 +00:00
// check for redirect
if resp.StatusCode() >= 300 && resp.StatusCode() < 400 {
if location := resp.Header.Peek("Location"); len(location) > 0 {
redir := string(location)
if strings.HasPrefix(redir, "http") {
return nil, redir, nil
}
2024-11-21 06:16:20 +00:00
}
2024-11-30 22:11:38 +00:00
}
2024-11-21 06:16:20 +00:00
2024-11-30 22:11:38 +00:00
if body := strings.ToLower(string(resp.Body())); len(body) > 0 {
doc, err := goquery.NewDocumentFromReader(strings.NewReader(body))
return doc, "", err
2024-11-21 06:16:20 +00:00
}
}
2024-11-30 22:11:38 +00:00
return nil, "", err
2024-11-21 06:16:20 +00:00
}