feat(*): acl · webhookx-io/webhookx@d03d7db

@@ -3,33 +3,80 @@ package deliverer

33

import (

44

"bytes"

55

"context"

6+

"fmt"

67

"github.com/webhookx-io/webhookx/config"

78

"github.com/webhookx-io/webhookx/constants"

89

"io"

10+

"net"

911

"net/http"

12+

"net/url"

1013

"time"

1114

)

121516+

type key struct{}

17+1318

// HTTPDeliverer delivers via HTTP

1419

type HTTPDeliverer struct {

1520

defaultTimeout time.Duration

1621

client *http.Client

1722

}

182319-

func NewHTTPDeliverer(cfg *config.WorkerDeliverer) *HTTPDeliverer {

24+

func restrictedDialFunc(acl *ACL) func(context.Context, string, string) (net.Conn, error) {

25+

dialer := &net.Dialer{}

26+

return func(ctx context.Context, network, addr string) (net.Conn, error) {

27+

host, port, err := net.SplitHostPort(addr)

28+

if err != nil {

29+

return nil, err

30+

}

31+32+

ips, err := net.DefaultResolver.LookupNetIP(ctx, "ip", host)

33+

if err != nil {

34+

return nil, err

35+

}

36+37+

for _, ip := range ips {

38+

if acl.Allow(host, ip) {

39+

return dialer.DialContext(ctx, network, net.JoinHostPort(ip.String(), port))

40+

}

41+

}

42+43+

if res, ok := ctx.Value(key{}).(*Response); ok {

44+

res.ACL.Denied = true

45+

}

46+47+

return nil, fmt.Errorf("request to %s (IP=%s) denied by ACL", host, ips[0])

48+

}

49+

}

50+51+

func NewHTTPDeliverer(cfg *config.WorkerDeliverer) (*HTTPDeliverer, error) {

52+

transport := &http.Transport{

53+

MaxIdleConns: 1000,

54+

MaxIdleConnsPerHost: 1000,

55+

IdleConnTimeout: 30 * time.Second,

56+

TLSHandshakeTimeout: 5 * time.Second,

57+

ExpectContinueTimeout: 1 * time.Second,

58+

DialContext: restrictedDialFunc(NewACL(AclOptions{Rules: cfg.ACL.Deny})),

59+

}

60+

if cfg.HTTPProxy != "" {

61+

u, err := url.Parse(cfg.HTTPProxy)

62+

if err != nil {

63+

return nil, fmt.Errorf("invalid http proxy url '%s': %s", cfg.HTTPProxy, err)

64+

}

65+

if u.Scheme == "" || u.Host == "" {

66+

return nil, fmt.Errorf("invalid http proxy url: '%s'", cfg.HTTPProxy)

67+

}

68+

transport.Proxy = http.ProxyURL(u)

69+

transport.DialContext = nil

70+

}

71+2072

client := &http.Client{

21-

Transport: &http.Transport{

22-

MaxIdleConns: 1000,

23-

MaxIdleConnsPerHost: 1000,

24-

IdleConnTimeout: 30 * time.Second,

25-

TLSHandshakeTimeout: 5 * time.Second,

26-

ExpectContinueTimeout: 1 * time.Second,

27-

},

73+

Transport: transport,

2874

}

75+2976

return &HTTPDeliverer{

3077

defaultTimeout: time.Duration(cfg.Timeout) * time.Millisecond,

3178

client: client,

32-

}

79+

}, nil

3380

}

34813582

func timing(fn func()) time.Duration {

@@ -52,6 +99,7 @@ func (d *HTTPDeliverer) Deliver(ctx context.Context, req *Request) (res *Respons

5299

Request: req,

53100

}

54101102+

ctx = context.WithValue(ctx, key{}, res)

55103

request, err := http.NewRequestWithContext(ctx, req.Method, req.URL, bytes.NewBuffer(req.Payload))

56104

if err != nil {

57105

res.Error = err