Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
320 changes: 188 additions & 132 deletions lib/go-atscfg/ipallowdotyaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package atscfg
*/

import (
"errors"
"net"
"sort"
"strconv"
Expand Down Expand Up @@ -73,62 +74,20 @@ func MakeIPAllowDotYAML(
return Cfg{}, makeErr(warnings, "this server missing HostName")
}

params := paramsToMultiMap(filterParams(serverParams, IPAllowConfigFileName, "", "", ""))

ipAllowDat := []ipAllowYAMLData{}

// localhost is trusted.
ipAllowDat = append([]ipAllowYAMLData{yamlAllowAll(`127.0.0.1`)}, ipAllowDat...)
ipAllowDat = append([]ipAllowYAMLData{yamlAllowAll(`::1`)}, ipAllowDat...)

// default for coalesce_ipv4 = 24, 5 and for ipv6 48, 5; override with the parameters in the server profile.
coalesceMaskLenV4 := DefaultCoalesceMaskLenV4
coalesceNumberV4 := DefaultCoalesceNumberV4
coalesceMaskLenV6 := DefaultCoalesceMaskLenV6
coalesceNumberV6 := DefaultCoalesceNumberV6
ips := GetPurgeIPs(serverParams)

for name, vals := range params {
for _, val := range vals {
switch name {
case ParamPurgeAllowIP:
for _, ip := range strings.Split(val, ",") {
ipAllowDat = append(ipAllowDat, yamlAllowAll(strings.TrimSpace(ip)))
}
case ParamCoalesceMaskLenV4:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")
} else if coalesceMaskLenV4 != DefaultCoalesceMaskLenV4 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")
} else {
coalesceMaskLenV4 = vi
}
case ParamCoalesceNumberV4:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")
} else if coalesceNumberV4 != DefaultCoalesceNumberV4 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")
} else {
coalesceNumberV4 = vi
}
case ParamCoalesceMaskLenV6:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")
} else if coalesceMaskLenV6 != DefaultCoalesceMaskLenV6 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")
} else {
coalesceMaskLenV6 = vi
}
case ParamCoalesceNumberV6:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")
} else if coalesceNumberV6 != DefaultCoalesceNumberV6 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")
} else {
coalesceNumberV6 = vi
}
}
}
for _, ip := range ips {
ipAllowDat = append(ipAllowDat, yamlAllowAll(strings.TrimSpace(ip)))
}
coalesceMaskLenV4, coalesceNumberV4, coalesceMaskLenV6, coalesceNumberV6, ws := GetCoalesceMaskAndNumber(serverParams)

warnings = append(warnings, ws...)

// for edges deny "PUSH|PURGE|DELETE", allow everything else to everyone.
isMid := strings.HasPrefix(server.Type, tc.MidTypePrefix)
Expand All @@ -137,92 +96,22 @@ func MakeIPAllowDotYAML(
ipAllowDat = append(ipAllowDat, yamlAllowAllButPushPurgeDelete(`::/0`))
} else {

ips := []*net.IPNet{}
ip6s := []*net.IPNet{}

cgMap := map[string]tc.CacheGroupNullable{}
for _, cg := range cacheGroups {
if cg.Name == nil {
return Cfg{}, makeErr(warnings, "got cachegroup with nil name!")
}
cgMap[*cg.Name] = cg
}

if server.Cachegroup == nil {
return Cfg{}, makeErr(warnings, "server had nil Cachegroup!")
}

serverCG, ok := cgMap[*server.Cachegroup]
if !ok {
return Cfg{}, makeErr(warnings, "server cachegroup not in cachegroups!")
}

childCGNames := getTopologyDirectChildren(tc.CacheGroupName(*server.Cachegroup), topologies)

childCGs := map[string]tc.CacheGroupNullable{}
for cgName, _ := range childCGNames {
childCGs[string(cgName)] = cgMap[string(cgName)]
}

for cgName, cg := range cgMap {
if (cg.ParentName != nil && *cg.ParentName == *serverCG.Name) || (cg.SecondaryParentName != nil && *cg.SecondaryParentName == *serverCG.Name) {
childCGs[cgName] = cg
}
}

// sort servers, to guarantee things like IP coalescing are deterministic
sort.Sort(serversSortByName(servers))
for _, childServer := range servers {
if childServer.Cachegroup == nil {
warnings = append(warnings, "Servers had server with nil Cachegroup, skipping!")
continue
} else if childServer.HostName == nil {
warnings = append(warnings, "Servers had server with nil HostName, skipping!")
continue
}

// We need to add IPs to the allow of
// - all children of this server
// - all monitors, if this server is a Mid
//
_, isChild := childCGs[*childServer.Cachegroup]
if !isChild && !strings.HasPrefix(server.Type, tc.MidTypePrefix) && string(childServer.Type) != tc.MonitorTypeName {
continue
}

for _, svInterface := range childServer.Interfaces {
for _, svAddr := range svInterface.IPAddresses {
if ip := net.ParseIP(svAddr.Address); ip != nil {
// got an IP - convert it to a CIDR and add it to the list
if ip4 := ip.To4(); ip4 != nil {
ips = append(ips, util.IPToCIDR(ip4))
} else {
ip6s = append(ip6s, util.IPToCIDR(ip))
}
} else {
// not an IP, try a CIDR
if ip, cidr, err := net.ParseCIDR(svAddr.Address); err != nil {
// not a CIDR or IP - error out
warnings = append(warnings, "server '"+*server.HostName+"' IP '"+svAddr.Address+" is not an IP address or CIDR - skipping!")
} else if ip == nil {
// not a CIDR or IP - error out
warnings = append(warnings, "server '"+*server.HostName+"' IP '"+svAddr.Address+" failed to parse as IP or CIDR - skipping!")
} else {
// got a valid CIDR - add it to the list
if ip4 := ip.To4(); ip4 != nil {
ips = append(ips, cidr)
} else {
ip6s = append(ip6s, cidr)
}
}
}
}
}
cidrs, cidr6s, ws, err := GetAllowedCIDRsForMid(
server,
servers,
cacheGroups,
topologies,
coalesceNumberV4,
coalesceMaskLenV4,
coalesceNumberV6,
coalesceMaskLenV6,
)
warnings = append(warnings, ws...)

if err != nil {
return Cfg{}, makeErr(warnings, err.Error())
}

cidrs := util.CoalesceCIDRs(ips, coalesceNumberV4, coalesceMaskLenV4)
cidr6s := util.CoalesceCIDRs(ip6s, coalesceNumberV6, coalesceMaskLenV6)

for _, cidr := range cidrs {
ipAllowDat = append(ipAllowDat, yamlAllowAllButPushPurge(cidr.String()))
}
Expand Down Expand Up @@ -350,3 +239,170 @@ func yamlDenyAll(rangeStr string) ipAllowYAMLData {
Methods: []string{YAMLMethodAll},
}
}

// GetPurgeIPs returns IPs allowed for PURGE requests.
func GetPurgeIPs(serverParams []tc.Parameter) []string {
ips := make([]string, 0)

params := paramsToMultiMap(filterParams(serverParams, IPAllowConfigFileName, "", "", ""))

for _, val := range params[ParamPurgeAllowIP] {
ips = append(ips, strings.Split(val, ",")...)
}
return ips
}

// GetCoalesceMaskAndNumber returns coalesce mask length and number for ipv4 and ipv6.
func GetCoalesceMaskAndNumber(serverParams []tc.Parameter) (int, int, int, int, []string) {
warnings := make([]string, 0)

// default for coalesce_ipv4 = 24, 5 and for ipv6 48, 5; override with the parameters in the server profile.
coalesceMaskLenV4 := DefaultCoalesceMaskLenV4
coalesceNumberV4 := DefaultCoalesceNumberV4
coalesceMaskLenV6 := DefaultCoalesceMaskLenV6
coalesceNumberV6 := DefaultCoalesceNumberV6

params := paramsToMultiMap(filterParams(serverParams, IPAllowConfigFileName, "", "", ""))

for name, vals := range params {
for _, val := range vals {
switch name {
case ParamCoalesceMaskLenV4:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")
} else if coalesceMaskLenV4 != DefaultCoalesceMaskLenV4 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")
} else {
coalesceMaskLenV4 = vi
}
case ParamCoalesceNumberV4:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")
} else if coalesceNumberV4 != DefaultCoalesceNumberV4 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")
} else {
coalesceNumberV4 = vi
}
case ParamCoalesceMaskLenV6:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")
} else if coalesceMaskLenV6 != DefaultCoalesceMaskLenV6 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")
} else {
coalesceMaskLenV6 = vi
}
case ParamCoalesceNumberV6:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")
} else if coalesceNumberV6 != DefaultCoalesceNumberV6 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")
} else {
coalesceNumberV6 = vi
}
}
}
}
return coalesceMaskLenV4, coalesceNumberV4, coalesceMaskLenV6, coalesceNumberV6, nil
}

// GetAllowedCIDRsForMid returns CIDRs allowed for all methods other than Push and Purge to mid servers.
func GetAllowedCIDRsForMid(
server *Server,
servers []Server,
cacheGroups []tc.CacheGroupNullable,
topologies []tc.Topology,
coalesceNumberV4 int,
coalesceMaskLenV4 int,
coalesceNumberV6 int,
coalesceMaskLenV6 int,
) ([]*net.IPNet, []*net.IPNet, []string, error) {

ips := []*net.IPNet{}
ip6s := []*net.IPNet{}
warnings := make([]string, 0)

cgMap := map[string]tc.CacheGroupNullable{}
for _, cg := range cacheGroups {
if cg.Name == nil {
return nil, nil, warnings, errors.New("got cachegroup with nil name!")
}
cgMap[*cg.Name] = cg
}

if server.Cachegroup == nil {
return nil, nil, warnings, errors.New("server had nil Cachegroup!")
}

serverCG, ok := cgMap[*server.Cachegroup]
if !ok {
return nil, nil, warnings, errors.New("server cachegroup not in cachegroups!")
}

childCGNames := getTopologyDirectChildren(tc.CacheGroupName(*server.Cachegroup), topologies)

childCGs := map[string]tc.CacheGroupNullable{}
for cgName, _ := range childCGNames {
childCGs[string(cgName)] = cgMap[string(cgName)]
}

for cgName, cg := range cgMap {
if (cg.ParentName != nil && *cg.ParentName == *serverCG.Name) || (cg.SecondaryParentName != nil && *cg.SecondaryParentName == *serverCG.Name) {
childCGs[cgName] = cg
}
}

// sort servers, to guarantee things like IP coalescing are deterministic
sort.Sort(serversSortByName(servers))
for _, childServer := range servers {
if childServer.Cachegroup == nil {
warnings = append(warnings, "Servers had server with nil Cachegroup, skipping!")
continue
} else if childServer.HostName == nil {
warnings = append(warnings, "Servers had server with nil HostName, skipping!")
continue
}

// We need to add IPs to the allow of
// - all children of this server
// - all monitors, if this server is a Mid
//
_, isChild := childCGs[*childServer.Cachegroup]
if !isChild && !strings.HasPrefix(server.Type, tc.MidTypePrefix) && string(childServer.Type) != tc.MonitorTypeName {
continue
}

for _, svInterface := range childServer.Interfaces {
for _, svAddr := range svInterface.IPAddresses {
if ip := net.ParseIP(svAddr.Address); ip != nil {
// got an IP - convert it to a CIDR and add it to the list
if ip4 := ip.To4(); ip4 != nil {
ips = append(ips, util.IPToCIDR(ip4))
} else {
ip6s = append(ip6s, util.IPToCIDR(ip))
}
} else {
// not an IP, try a CIDR
if ip, cidr, err := net.ParseCIDR(svAddr.Address); err != nil {
// not a CIDR or IP - error out
warnings = append(warnings, "server '"+*server.HostName+"' IP '"+svAddr.Address+" is not an IP address or CIDR - skipping!")
} else if ip == nil {
// not a CIDR or IP - error out
warnings = append(warnings, "server '"+*server.HostName+"' IP '"+svAddr.Address+" failed to parse as IP or CIDR - skipping!")
} else {
// got a valid CIDR - add it to the list
if ip4 := ip.To4(); ip4 != nil {
ips = append(ips, cidr)
} else {
ip6s = append(ip6s, cidr)
}
}
}
}
}
}

cidrs := util.CoalesceCIDRs(ips, coalesceNumberV4, coalesceMaskLenV4)
cidr6s := util.CoalesceCIDRs(ip6s, coalesceNumberV6, coalesceMaskLenV6)

return cidrs, cidr6s, warnings, nil
}
Loading