2022-04-04 09:32:41 +02:00
|
|
|
package http
|
|
|
|
|
|
|
|
|
|
import (
|
2022-05-12 13:13:56 +02:00
|
|
|
"context"
|
2022-04-13 17:41:02 +02:00
|
|
|
"net"
|
2022-04-04 09:32:41 +02:00
|
|
|
"net/http"
|
|
|
|
|
"regexp"
|
|
|
|
|
"strings"
|
2022-04-13 17:41:02 +02:00
|
|
|
|
2022-05-12 13:13:56 +02:00
|
|
|
"github.com/projectdiscovery/fastdialer/fastdialer"
|
2022-04-13 17:41:02 +02:00
|
|
|
"github.com/projectdiscovery/iputil"
|
|
|
|
|
"github.com/projectdiscovery/stringsutil"
|
|
|
|
|
"github.com/projectdiscovery/urlutil"
|
2022-04-04 09:32:41 +02:00
|
|
|
)
|
|
|
|
|
|
2022-05-12 13:13:56 +02:00
|
|
|
var (
|
|
|
|
|
// @Host:target overrides the input target with the annotated one (similar to self-contained requests)
|
|
|
|
|
reHostAnnotation = regexp.MustCompile(`(?m)^@Host:\s*(.+)\s*$`)
|
|
|
|
|
// @tls-sni:target overrides the input target with the annotated one
|
|
|
|
|
// special values:
|
|
|
|
|
// request.host: takes the value from the host header
|
|
|
|
|
// target: overiddes with the specific value
|
|
|
|
|
reSniAnnotation = regexp.MustCompile(`(?m)^@tls-sni:\s*(.+)\s*$`)
|
|
|
|
|
)
|
2022-04-04 09:32:41 +02:00
|
|
|
|
|
|
|
|
// parseAnnotations and override requests settings
|
2022-05-12 13:13:56 +02:00
|
|
|
func parseAnnotations(rawRequest string, request *http.Request) (*http.Request, bool) {
|
2022-04-04 09:32:41 +02:00
|
|
|
// parse request for known ovverride annotations
|
2022-05-12 13:13:56 +02:00
|
|
|
var modified bool
|
|
|
|
|
// @Host:target
|
2022-04-04 09:32:41 +02:00
|
|
|
if hosts := reHostAnnotation.FindStringSubmatch(rawRequest); len(hosts) > 0 {
|
2022-04-13 17:41:02 +02:00
|
|
|
value := strings.TrimSpace(hosts[1])
|
|
|
|
|
// handle scheme
|
|
|
|
|
switch {
|
|
|
|
|
case stringsutil.HasPrefixI(value, "http://"):
|
|
|
|
|
request.URL.Scheme = urlutil.HTTP
|
|
|
|
|
case stringsutil.HasPrefixI(value, "https://"):
|
|
|
|
|
request.URL.Scheme = urlutil.HTTPS
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value = stringsutil.TrimPrefixAny(value, "http://", "https://")
|
|
|
|
|
|
|
|
|
|
if isHostPort(value) {
|
|
|
|
|
request.URL.Host = value
|
2022-04-14 12:59:21 +02:00
|
|
|
} else {
|
|
|
|
|
hostPort := value
|
|
|
|
|
port := request.URL.Port()
|
|
|
|
|
if port != "" {
|
|
|
|
|
hostPort = net.JoinHostPort(hostPort, port)
|
|
|
|
|
}
|
|
|
|
|
request.URL.Host = hostPort
|
2022-04-13 17:41:02 +02:00
|
|
|
}
|
2022-05-12 13:13:56 +02:00
|
|
|
modified = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// @tls-sni:target
|
|
|
|
|
if hosts := reSniAnnotation.FindStringSubmatch(rawRequest); len(hosts) > 0 {
|
|
|
|
|
value := strings.TrimSpace(hosts[1])
|
|
|
|
|
value = stringsutil.TrimPrefixAny(value, "http://", "https://")
|
|
|
|
|
if idxForwardSlash := strings.Index(value, "/"); idxForwardSlash >= 0 {
|
|
|
|
|
value = value[:idxForwardSlash]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if stringsutil.EqualFoldAny(value, "request.host") {
|
|
|
|
|
value = request.Host
|
|
|
|
|
}
|
|
|
|
|
ctx := context.WithValue(request.Context(), fastdialer.SniName, value)
|
|
|
|
|
request = request.Clone(ctx)
|
|
|
|
|
modified = true
|
2022-04-13 17:41:02 +02:00
|
|
|
}
|
2022-05-12 13:13:56 +02:00
|
|
|
return request, modified
|
2022-04-13 17:41:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func isHostPort(value string) bool {
|
|
|
|
|
_, port, err := net.SplitHostPort(value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if !iputil.IsPort(port) {
|
|
|
|
|
return false
|
2022-04-04 09:32:41 +02:00
|
|
|
}
|
2022-04-13 17:41:02 +02:00
|
|
|
return true
|
2022-04-04 09:32:41 +02:00
|
|
|
}
|