Files
zitadel/internal/denylist/host_checker.go
T
Marco A.andGitHub b2532e9666 Merge commit from fork
* Inject DenyList from config to `StartCommands()`

* Implementation draft

* Move address checker to separate package

* Migrate usages of actions.AddressChecker to denylist.AddressChecker

* Rename denylist package files

* Pass []denylist.AddressChecker to StartCommand

* Add DenyList to defaults.yaml and add custom config parser

* net: add HostnameToIPList function

* denylist: Add IsHostBlocked()

* actions: use denylist.IsHostBlocked()

* command: Inject ip lookup function + extend add target validationt test

* command: Unexport ChangeTarget.IsValid()

* command: Add denyList check on ChangeTarget validation

* command: Export ActionsV2DenyList and IPLookupFunction params

* Lint fix

* Check denylist during action execution

* Fix integration tests

* Apply suggestions

* Add `mapstructure.StringToSliceHookFunc()` to decode `HTTPConfigDecodeHook`
2026-02-25 06:33:28 +01:00

70 lines
1.7 KiB
Go

package denylist
import (
"net"
"net/url"
internal_net "github.com/zitadel/zitadel/internal/net"
)
var _ AddressChecker = (*HostChecker)(nil)
type HostChecker struct {
Net *net.IPNet
IP net.IP
Domain string
}
func NewHostChecker(entry string) (AddressChecker, error) {
if entry == "" {
return nil, nil
}
_, network, err := net.ParseCIDR(entry)
if err == nil {
return &HostChecker{Net: network}, nil
}
if ip := net.ParseIP(entry); ip != nil {
return &HostChecker{IP: ip}, nil
}
return &HostChecker{Domain: entry}, nil
}
func (c *HostChecker) IsDenied(ips []net.IP, address string) error {
// if the address matches the domain, no additional checks as needed
if c.Domain == address {
return NewAddressDeniedError(c.Domain)
}
// otherwise we need to check on ips (incl. the resolved ips of the host)
for _, ip := range ips {
if c.Net != nil && c.Net.Contains(ip) {
return NewAddressDeniedError(c.Net.String())
}
if c.IP != nil && c.IP.Equal(ip) {
return NewAddressDeniedError(c.IP.String())
}
}
return nil
}
// IsHostBlocked checks address against denyList. If a match is found, an [AddressDeniedError] will be returned
// Takes an input lookupFunc to convert address to a list of IP addresses.
// If lookupFunc is nil, it defaults to [net.LookupIP]
func IsHostBlocked(denyList []AddressChecker, address *url.URL, lookupFunc internal_net.IPLookupFunc) error {
if lookupFunc == nil {
lookupFunc = net.LookupIP
}
host := address.Hostname()
ips, err := internal_net.HostnameToIPList(host, lookupFunc)
if err != nil {
return err
}
for _, denied := range denyList {
if err := denied.IsDenied(ips, host); err != nil {
return err
}
}
return nil
}