summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorwxiaoguang <wxiaoguang@gmail.com>2021-11-01 16:39:52 +0800
committerGitHub <noreply@github.com>2021-11-01 16:39:52 +0800
commit599ff1c054e436daa4dc3f049aa8661d9c2395f9 (patch)
tree800983fd2e9d9de3dd1977738d18b64df34dd9ea /services
parent4e8a81780ed4ff0423e3a2ac7f75265e362ca46d (diff)
downloadgitea-599ff1c054e436daa4dc3f049aa8661d9c2395f9.tar.gz
gitea-599ff1c054e436daa4dc3f049aa8661d9c2395f9.zip
Only allow webhook to send requests to allowed hosts (#17482)
Diffstat (limited to 'services')
-rw-r--r--services/webhook/deliver.go26
1 files changed, 22 insertions, 4 deletions
diff --git a/services/webhook/deliver.go b/services/webhook/deliver.go
index 28c3b23b2f..04cec4c1c4 100644
--- a/services/webhook/deliver.go
+++ b/services/webhook/deliver.go
@@ -19,6 +19,7 @@ import (
"strconv"
"strings"
"sync"
+ "syscall"
"time"
"code.gitea.io/gitea/models"
@@ -29,6 +30,8 @@ import (
"github.com/gobwas/glob"
)
+var contextKeyWebhookRequest interface{} = "contextKeyWebhookRequest"
+
// Deliver deliver hook task
func Deliver(t *models.HookTask) error {
w, err := models.GetWebhookByID(t.HookID)
@@ -171,7 +174,7 @@ func Deliver(t *models.HookTask) error {
return fmt.Errorf("Webhook task skipped (webhooks disabled): [%d]", t.ID)
}
- resp, err := webhookHTTPClient.Do(req)
+ resp, err := webhookHTTPClient.Do(req.WithContext(context.WithValue(req.Context(), contextKeyWebhookRequest, req)))
if err != nil {
t.ResponseInfo.Body = fmt.Sprintf("Delivery: %v", err)
return err
@@ -293,14 +296,29 @@ func InitDeliverHooks() {
timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second
webhookHTTPClient = &http.Client{
+ Timeout: timeout,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify},
Proxy: webhookProxy(),
- Dial: func(netw, addr string) (net.Conn, error) {
- return net.DialTimeout(netw, addr, timeout) // dial timeout
+ DialContext: func(ctx context.Context, network, addrOrHost string) (net.Conn, error) {
+ dialer := net.Dialer{
+ Timeout: timeout,
+ Control: func(network, ipAddr string, c syscall.RawConn) error {
+ // in Control func, the addr was already resolved to IP:PORT format, there is no cost to do ResolveTCPAddr here
+ tcpAddr, err := net.ResolveTCPAddr(network, ipAddr)
+ req := ctx.Value(contextKeyWebhookRequest).(*http.Request)
+ if err != nil {
+ return fmt.Errorf("webhook can only call HTTP servers via TCP, deny '%s(%s:%s)', err=%v", req.Host, network, ipAddr, err)
+ }
+ if !setting.Webhook.AllowedHostList.MatchesHostOrIP(req.Host, tcpAddr.IP) {
+ return fmt.Errorf("webhook can only call allowed HTTP servers (check your webhook.ALLOWED_HOST_LIST setting), deny '%s(%s)'", req.Host, ipAddr)
+ }
+ return nil
+ },
+ }
+ return dialer.DialContext(ctx, network, addrOrHost)
},
},
- Timeout: timeout, // request timeout
}
go graceful.GetManager().RunWithShutdownContext(DeliverHooks)