Resolve issue with localhost/local network redirects
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Tyler 2019-10-16 19:12:29 -04:00
parent 5fe59dddab
commit c3935b1d3c

View File

@ -6,6 +6,7 @@ import (
"github.com/PuerkitoBio/goquery"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"path"
@ -19,6 +20,35 @@ const (
maxBodySizeBytes = 20971520
)
var privateIPBlocks []*net.IPNet
func init() {
for _, cidr := range []string{
"127.0.0.0/8", // IPv4 loopback
"10.0.0.0/8", // RFC1918
"172.16.0.0/12", // RFC1918
"192.168.0.0/16", // RFC1918
"::1/128", // IPv6 loopback
"fe80::/10", // IPv6 link-local
"fc00::/7", // IPv6 unique local addr
} {
_, block, err := net.ParseCIDR(cidr)
if err != nil {
panic(fmt.Errorf("parse error on %q: %v", cidr, err))
}
privateIPBlocks = append(privateIPBlocks, block)
}
}
func isPrivateIP(ip net.IP) bool {
for _, block := range privateIPBlocks {
if block.Contains(ip) {
return true
}
}
return false
}
func (api *LinkInfoApi) DefaultLinkHandler(link string) (*LinkInfo, error) {
redirects := make([]string, 0)
@ -28,6 +58,12 @@ func (api *LinkInfoApi) DefaultLinkHandler(link string) (*LinkInfo, error) {
return nil, err
}
if u.Host == "localhost" {
return nil, errors.New("url is localhost")
} else if ip := net.ParseIP(u.Host); ip != nil && isPrivateIP(ip) {
return nil, errors.New("url is a local ip address")
}
var res *http.Response
for i := 0; i < 10; i++ {
@ -39,6 +75,19 @@ func (api *LinkInfoApi) DefaultLinkHandler(link string) (*LinkInfo, error) {
if (res.StatusCode == 301 || res.StatusCode == 302) && res.Header.Get("Location") != "" {
link = res.Header.Get("Location")
redirectUrl, err := url.Parse(link)
if err != nil {
return nil, err
}
if redirectUrl.Host == "localhost" {
return nil, errors.New("url attempted to redirect to localhost")
} else if ip := net.ParseIP(redirectUrl.Host); ip != nil && isPrivateIP(ip) {
return nil, errors.New("host is a local ip address")
}
redirects = append(redirects, link)
} else {
break
@ -140,7 +189,7 @@ func (api *LinkInfoApi) retrieveHtmlLinkTitle(i *LinkInfo, link string) error {
metaTags := make(map[string]string)
meta.Each(func(_ int, s *goquery.Selection) {
var key string
var key, value string
var exists bool
for _, k := range attrKeys {
@ -154,6 +203,14 @@ func (api *LinkInfoApi) retrieveHtmlLinkTitle(i *LinkInfo, link string) error {
if key == "" {
return
}
value, exists = s.Attr("content")
if !exists {
return
}
metaTags[key] = value
})
var attr string
@ -161,7 +218,7 @@ func (api *LinkInfoApi) retrieveHtmlLinkTitle(i *LinkInfo, link string) error {
if attr, exists = metaTags["og:title"]; exists {
i.Title = attr
} else if tag := q.Find("title"); tag.Length() > 0 {
} else if tag := q.Find("head > title"); tag.Length() > 0 {
i.Title = strings.TrimSpace(tag.Text())
}