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
48 changes: 48 additions & 0 deletions lib/go-util/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ package util

import (
"bytes"
"errors"
"net"
"strconv"
"strings"

"github.com/apache/trafficcontrol/lib/go-log"
)
Expand Down Expand Up @@ -200,3 +203,48 @@ func IPToCIDR(ip net.IP) *net.IPNet {
}
return &net.IPNet{IP: ip, Mask: fullMask}
}

func IP4ToNum(ip string) (uint32, error) {
parts := strings.Split(ip, `.`)
if len(parts) != 4 {
return 0, errors.New("malformed IPv4")
}
intParts := []uint32{}
for _, part := range parts {
i, err := strconv.ParseUint(part, 10, 32)
if err != nil {
return 0, errors.New("malformed IPv4")
}
intParts = append(intParts, uint32(i))
}

num := intParts[3]
num += intParts[2] << 8
num += intParts[1] << 16
num += intParts[0] << 24

return num, nil
}

func IP4InRange(ip, ipRange string) (bool, error) {
ab := strings.Split(ipRange, `-`)
if len(ab) != 2 {
if len(ab) == 1 { // no range check for equality
return ip == ipRange, nil
}
return false, errors.New("malformed range")
}
ipNum, err := IP4ToNum(ip)
if err != nil {
return false, errors.New("malformed ip")
}
aNum, err := IP4ToNum(ab[0])
if err != nil {
return false, errors.New("malformed range (first part)")
}
bNum, err := IP4ToNum(ab[1])
if err != nil {
return false, errors.New("malformed range (second part)")
}
return ipNum >= aNum && ipNum <= bNum, nil
}
49 changes: 49 additions & 0 deletions lib/go-util/net_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package util
// When adding symbols, document the RFC and section they correspond to.

import (
"fmt"
"net"
"testing"
)
Expand Down Expand Up @@ -190,3 +191,51 @@ func TestLastIP(t *testing.T) {
}
}
}

func TestIP4ToNum(t *testing.T) {
var tests = []struct {
ip string
number uint32
}{
{"127.0.0.1", uint32(2130706433)},
{"127.0.0.4", uint32(2130706436)},
{"127.255.255.255", uint32(2147483647)},
}
for _, tt := range tests {
t.Run(tt.ip, func(t *testing.T) {
n, err := IP4ToNum(tt.ip)
if err != nil {
t.Errorf("unexpected error: %v", err)

}
if n != tt.number {
t.Errorf("got %v, want %v", n, tt.number)
}
})
}
}

func TestIP4InRange(t *testing.T) {
var tests = []struct {
ip string
ipRange string
inRange bool
}{
{"111.0.0.1", "127.0.0.0-127.255.255.255", false},
{"128.0.0.1", "127.0.0.0-127.255.255.255", false},
{"127.0.0.1", "127.0.0.0-127.255.255.255", true},
{"127.0.0.1", "127.0.0.1", true},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("%v in range %v", tt.ip, tt.inRange), func(t *testing.T) {
exists, err := IP4InRange(tt.ip, tt.ipRange)
if err != nil {
t.Errorf("unexpected error: %v", err)

}
if exists != tt.inRange {
t.Errorf("got %v, want %v", exists, tt.inRange)
}
})
}
}
7 changes: 4 additions & 3 deletions traffic_ops/ort/atstccfg/cfgfile/ipallowdotconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package cfgfile
import (
"errors"
"strconv"
"strings"

"github.com/apache/trafficcontrol/lib/go-atscfg"
"github.com/apache/trafficcontrol/lib/go-tc"
Expand Down Expand Up @@ -110,10 +111,10 @@ func GetConfigFileServerIPAllowDotConfig(cfg config.TCCfg, serverNameOrID string

childServers := map[tc.CacheName]atscfg.IPAllowServer{}
for _, sv := range servers {
if _, ok := childCGs[sv.Cachegroup]; !ok {
continue
_, ok := childCGs[sv.Cachegroup]
if ok || (strings.HasPrefix(string(serverType), tc.MidTypePrefix) && string(sv.Type) == tc.MonitorTypeName) {
childServers[tc.CacheName(sv.HostName)] = atscfg.IPAllowServer{IPAddress: sv.IPAddress, IP6Address: sv.IP6Address}
}
childServers[tc.CacheName(sv.HostName)] = atscfg.IPAllowServer{IPAddress: sv.IPAddress, IP6Address: sv.IP6Address}
}

txt := atscfg.MakeIPAllowDotConfig(serverName, serverType, toToolName, toURL, fileParams, childServers)
Expand Down
125 changes: 125 additions & 0 deletions traffic_ops/testing/api/v14/ip_allow_dot_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package v14

/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import (
"fmt"
"net/url"
"strings"
"testing"

"github.com/apache/trafficcontrol/lib/go-util"

"github.com/apache/trafficcontrol/lib/go-tc"
)

const ipAllow = "ip_allow.config"

var (
expectedRules = []string{
"src_ip=127.0.0.1 action=ip_allow method=ALL\n",
"src_ip=::1 action=ip_allow method=ALL\n",
}
midExpectedRules = []string{
"src_ip=10.0.0.0-10.255.255.255 action=ip_allow method=ALL\n",
"src_ip=172.16.0.0-172.31.255.255 action=ip_allow method=ALL\n",
"src_ip=192.168.0.0-192.168.255.255 action=ip_allow method=ALL\n",
"src_ip=::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff action=ip_deny method=ALL\n",
"src_ip=::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff action=ip_deny method=ALL\n",
}
edgeExpectedRules = []string{
"src_ip=0.0.0.0-255.255.255.255 action=ip_deny method=PUSH|PURGE|DELETE\n",
"src_ip=::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff action=ip_deny method=PUSH|PURGE|DELETE\n",
}
rascalServerIP = ""
rascalRule = "src_ip=%v action=ip_allow method=ALL"
)

func TestIPAllowDotConfig(t *testing.T) {
WithObjs(t, []TCObj{CDNs, Types, Tenants, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, DeliveryServices}, func() {
rascalServerIP = getServer(t, "RASCAL").IPAddress
// rascalRule = fmt.Sprintf("src_ip=%v action=ip_allow method=ALL", rascalServer.IPAddress)
GetTestIPAllowDotConfig(t)
GetTestIPAllowMidDotConfig(t)
})
}

func GetTestIPAllowDotConfig(t *testing.T) {
// Get edge server
s := getServer(t, "EDGE")
output, _, err := TOSession.GetATSServerConfig(s.ID, ipAllow)
if err != nil {
t.Fatalf("cannot GET server %v config %v: %v", s.HostName, ipAllow, err)
}
for _, r := range append(expectedRules, edgeExpectedRules...) {
if !strings.Contains(output, r) {
t.Errorf("expected rule %v not found in ip_allow config", r)
}
}
// Make sure edge does not contain rule for rascal server
exists, ipRange := getIPRule(output, rascalServerIP)
rascalRule := fmt.Sprintf(rascalRule, ipRange)
if exists && strings.Contains(output, rascalRule) {
t.Errorf("rascal IP was not supposed to be in an allowed rule: %v", rascalRule)
}
}

func GetTestIPAllowMidDotConfig(t *testing.T) {
// Get mid server
s := getServer(t, "MID")
output, _, err := TOSession.GetATSServerConfig(s.ID, ipAllow)
if err != nil {
t.Errorf("cannot GET server %v config %v: %v", s.HostName, ipAllow, err)
}
for _, r := range append(expectedRules, midExpectedRules...) {
if !strings.Contains(output, r) {
t.Errorf("expected rule %v not found in ip_allow config", r)
}
}

// Make sure mid contains an allowed rule that includes the rascal server
exists, ipRange := getIPRule(output, rascalServerIP)
rascalRule := fmt.Sprintf(rascalRule, ipRange)
if !(exists && strings.Contains(output, rascalRule)) {
t.Errorf("expected rascal to be include as allowed in mid ip allow config")
}
}

func getServer(t *testing.T, serverType string) tc.Server {
v := url.Values{}
v.Add("type", serverType)
servers, _, err := TOSession.GetServersByType(v)
if err != nil {
t.Fatalf("cannot GET Server by type %v: %v", serverType, err)
}
if len(servers) == 0 {
t.Fatalf("cannot find any Servers by type %v", serverType)
}
return servers[0]
}

// getIPRuleRange returns if the given IP is included in the set of rules and which ip range it is included in
func getIPRule(rules, ip string) (bool, string) {
for _, r := range strings.Split(rules, "\n")[1:] {
if !strings.Contains(r, "src_ip") {
continue
}
ipRange := r[7:strings.IndexAny(r, " ")]
if exists, _ := util.IP4InRange(ip, ipRange); exists {
return true, ipRange
}
}
return false, ""
}
4 changes: 2 additions & 2 deletions traffic_ops/testing/api/v14/tc-fixtures.json
Original file line number Diff line number Diff line change
Expand Up @@ -1828,7 +1828,7 @@
"routerPortName": "",
"status": "REPORTED",
"tcpPort": 81,
"type": "TRAFFIC_MONITOR",
"type": "RASCAL",
"updPending": false,
"xmppId": "",
"xmppPasswd": "X"
Expand Down Expand Up @@ -2301,7 +2301,7 @@
{
"description": "Traffic Monitor (Rascal)",
"lastUpdated": "2018-03-02T19:13:46.832327+00:00",
"name": "TRAFFIC_MONITOR",
"name": "RASCAL",
"useInTable": "server"
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,15 @@ FROM
JOIN type tp on tp.id = s.type
JOIN cachegroup cg on cg.id = s.cachegroup
WHERE
(tp.name = '` + tc.MonitorTypeName + `' OR tp.name LIKE '` + tc.EdgeTypePrefix + `%')
(tp.name = '` + tc.MonitorTypeName + `' OR ( tp.name LIKE '` + tc.EdgeTypePrefix + `%')
AND cg.id IN (
SELECT
cg2.id
FROM
server s2
JOIN cachegroup cg2 ON (cg2.parent_cachegroup_id = s2.cachegroup OR cg2.secondary_parent_cachegroup_id = s2.cachegroup)
WHERE
s2.host_name = $1
s2.host_name = $1 )
)
`
rows, err := tx.Query(qry, serverName)
Expand Down