Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 13, 21:45 UTC
caddyhttp: Support zone identifiers in remote_ip matcher (#4597)
* Update matchers.go * Update matchers.go * implementation of zone_id handling * last changes in zone handling * give return true values instead of bool * Apply suggestions from code review Co-authored-by: Francis Lavoie <lavofr@gmail.com> * changes as suggested * Apply suggestions from code review Co-authored-by: Francis Lavoie <lavofr@gmail.com> * Update matchers.go * shortened the Match function * changed mazcher handling * Update matchers.go * delete space Co-authored-by: Francis Lavoie <lavofr@gmail.com>
BitWuehler committed
Mar 1, 2022 at 23:50 UTC
ac14b64e08a6ea63067c62cf1bad9cd6ad823d60
1 file changed
+35
-7
modules/caddyhttp/matchers.go
+35
-7
@@ -131,7 +131,10 @@ type (
131
// to spoof request headers. Default: false
132
Forwarded bool `json:"forwarded,omitempty"`
133
134
+ // cidrs and zones vars should aligned always in the same
135
+ // length and indexes for matching later
136
cidrs []*net.IPNet
137
+ zones []string
138
logger *zap.Logger
139
}
140
@@ -877,10 +880,19 @@ func (m *MatchRemoteIP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
880
func (m *MatchRemoteIP) Provision(ctx caddy.Context) error {
881
m.logger = ctx.Logger(m)
882
for _, str := range m.Ranges {
883
+ // Exclude the zone_id from the IP
884
+ if strings.Contains(str, "%") {
885
+ split := strings.Split(str, "%")
886
+ str = split[0]
887
+ // write zone identifiers in m.zones for matching later
888
+ m.zones = append(m.zones, split[1])
889
+ } else {
890
+ m.zones = append(m.zones, "")
891
+ }
892
if strings.Contains(str, "/") {
893
_, ipNet, err := net.ParseCIDR(str)
894
if err != nil {
883
- return fmt.Errorf("parsing CIDR expression: %v", err)
895
+ return fmt.Errorf("parsing CIDR expression '%s': %v", str, err)
896
}
897
m.cidrs = append(m.cidrs, ipNet)
898
} else {
@@ -898,8 +910,9 @@ func (m *MatchRemoteIP) Provision(ctx caddy.Context) error {
910
return nil
911
}
912
901
-func (m MatchRemoteIP) getClientIP(r *http.Request) (net.IP, error) {
913
+func (m MatchRemoteIP) getClientIP(r *http.Request) (net.IP, string, error) {
914
remote := r.RemoteAddr
915
+ zoneID := ""
916
if m.Forwarded {
917
if fwdFor := r.Header.Get("X-Forwarded-For"); fwdFor != "" {
918
remote = strings.TrimSpace(strings.Split(fwdFor, ",")[0])
@@ -909,25 +922,40 @@ func (m MatchRemoteIP) getClientIP(r *http.Request) (net.IP, error) {
922
if err != nil {
923
ipStr = remote // OK; probably didn't have a port
924
}
925
+ // Some IPv6-Adresses can contain zone identifiers at the end,
926
+ // which are separated with "%"
927
+ if strings.Contains(ipStr, "%") {
928
+ split := strings.Split(ipStr, "%")
929
+ ipStr = split[0]
930
+ zoneID = split[1]
931
+ }
932
ip := net.ParseIP(ipStr)
933
if ip == nil {
914
- return nil, fmt.Errorf("invalid client IP address: %s", ipStr)
934
+ return nil, zoneID, fmt.Errorf("invalid client IP address: %s", ipStr)
935
}
916
- return ip, nil
936
+ return ip, zoneID, nil
937
}
938
939
// Match returns true if r matches m.
940
func (m MatchRemoteIP) Match(r *http.Request) bool {
921
- clientIP, err := m.getClientIP(r)
941
+ clientIP, zoneID, err := m.getClientIP(r)
942
if err != nil {
943
m.logger.Error("getting client IP", zap.Error(err))
944
return false
945
}
926
- for _, ipRange := range m.cidrs {
946
+ zoneFilter := true
947
+ for i, ipRange := range m.cidrs {
948
if ipRange.Contains(clientIP) {
928
- return true
949
+ // Check if there are zone filters assigned and if they match.
950
+ if m.zones[i] == "" || zoneID == m.zones[i] {
951
+ return true
952
+ }
953
+ zoneFilter = false
954
}
955
}
956
+ if !zoneFilter {
957
+ m.logger.Debug("zone ID from remote did not match", zap.String("zone", zoneID))
958
+ }
959
return false
960
}
961