Skip to content

Commit

Permalink
Add port changing with MFA authorisation and rule composition
Browse files Browse the repository at this point in the history
  • Loading branch information
NHAS committed May 3, 2023
1 parent fa8ad1c commit e46d81c
Show file tree
Hide file tree
Showing 11 changed files with 212 additions and 124 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"tcp.h": "c",
"ip.h": "c",
"typeinfo": "c",
"in.h": "c"
"in.h": "c",
"numbers": "c"
}
}
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LDFLAGS_RELEASE = $(LDFLAGS) -s -w
ID=$(shell id -u)
GID=$(shell id -g)

debug: .generate_ebpf .build_ui
debug: .generate_ebpf
go build -ldflags="$(LDFLAGS)"

release: .generate_ebpf .build_ui
Expand Down
28 changes: 7 additions & 21 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,14 +215,9 @@ func AddAcl(effects string, Rule Acl) error {
return fmt.Errorf("%s was already defined", effects)
}

err := routetypes.ValidateRules(Rule.Allow)
err := routetypes.ValidateRules(Rule.Mfa, Rule.Allow)
if err != nil {
return fmt.Errorf("Public rules were invalid: %s", err)
}

err = routetypes.ValidateRules(Rule.Mfa)
if err != nil {
return fmt.Errorf("MFA rules were invalid: %s", err)
return fmt.Errorf("rules were invalid: %s", err)
}

values.Acls.Policies[effects] = &Rule
Expand All @@ -239,16 +234,11 @@ func EditAcl(effects string, Rule Acl) error {
return fmt.Errorf("%s acl was not defined", effects)
}

err := routetypes.ValidateRules(Rule.Allow)
err := routetypes.ValidateRules(Rule.Mfa, Rule.Allow)
if err != nil {
return fmt.Errorf("Public rules were invalid: %s", err)
}

err = routetypes.ValidateRules(Rule.Mfa)
if err != nil {
return fmt.Errorf("MFA rules were invalid: %s", err)
}

values.Acls.Policies[effects] = &Rule

return save()
Expand Down Expand Up @@ -586,15 +576,11 @@ func load(path string) (c Config, err error) {
}
}

policies := []string{}
for _, acl := range c.Acls.Policies {
policies = append(policies, acl.Allow...)
policies = append(policies, acl.Mfa...)
}

err = routetypes.ValidateRules(policies)
if err != nil {
return c, fmt.Errorf("policies rules were invalid: %s", err)
err = routetypes.ValidateRules(acl.Mfa, acl.Allow)
if err != nil {
return c, fmt.Errorf("policy was invalid: %s", err)
}
}

if len(c.MFATemplatesDirectory) != 0 {
Expand Down
31 changes: 9 additions & 22 deletions internal/router/bpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,9 +387,9 @@ func xdpAddDevice(username, address string) error {
}

// Takes the LPM table and associates a route to a policy
func xdpAddRoute(policyType routetypes.PolicyType, usersRouteTable *ebpf.Map, ruleDefinitions []string) error {
func xdpAddRoute(usersRouteTable *ebpf.Map, userAcls config.Acl) error {

rules, err := routetypes.ParseRules(policyType, ruleDefinitions)
rules, err := routetypes.ParseRules(userAcls.Mfa, userAcls.Allow)
if err != nil {
return err
}
Expand Down Expand Up @@ -453,18 +453,14 @@ func AddUser(username string, acls config.Acl) error {
return setMaps(userid, acls)
}

func setMaps(userid [20]byte, acls config.Acl) error {
func setMaps(userid [20]byte, userAcls config.Acl) error {
// Adds LPM trie to existing map (hashmap to map)
policiesInnerTable, err := addInnerMapTo(userid, routesMapSpec, xdpObjects.PoliciesTable)
if err != nil {
return err
}

if err := xdpAddRoute(0, policiesInnerTable, acls.Mfa); err != nil {
return err
}

if err := xdpAddRoute(routetypes.PUBLIC, policiesInnerTable, acls.Allow); err != nil {
if err := xdpAddRoute(policiesInnerTable, userAcls); err != nil {
return err
}

Expand Down Expand Up @@ -598,8 +594,7 @@ func Deauthenticate(address string) error {
}

type FirewallRules struct {
MFA []string
Public []string
Policies []string
Devices []fwDevice
AccountLocked uint32
}
Expand Down Expand Up @@ -663,7 +658,6 @@ func GetRules() (map[string]FirewallRules, error) {
if err != nil {
return nil, errors.New("fw rule get all users: " + err.Error())
}

// This is less than optimal, but I'd prefer to be using something of static length in the ebpf code, and sha1 is a decent compression algorithm as well
hashToUsername := make(map[string]string)
for _, user := range users {
Expand All @@ -673,10 +667,10 @@ func GetRules() (map[string]FirewallRules, error) {

result := make(map[string]FirewallRules)

iterateSubmap := func(innerMapID ebpf.MapID) (isPublic bool, result []string, err error) {
iterateSubmap := func(innerMapID ebpf.MapID) (rules []string, err error) {
innerMap, err := ebpf.NewMapFromID(innerMapID)
if err != nil {
return false, nil, fmt.Errorf("map from id: %s", err)
return nil, fmt.Errorf("map from id: %s", err)
}

var (
Expand All @@ -692,11 +686,9 @@ func GetRules() (map[string]FirewallRules, error) {
actualPolicies = policies[:i]
break
}

isPublic = policies[i].Is(routetypes.PUBLIC)
}

result = append(result, k.String()+" policy "+fmt.Sprintf("%+v", actualPolicies))
rules = append(rules, k.String()+" policy "+fmt.Sprintf("%+v", actualPolicies))
}

innerMap.Close()
Expand Down Expand Up @@ -729,16 +721,11 @@ func GetRules() (map[string]FirewallRules, error) {

err = xdpObjects.PoliciesTable.Lookup(deviceStruct.user_id, &innerMapID)
if err == nil {
isPublic, policyRoutes, err := iterateSubmap(innerMapID)
fwRule.Policies, err = iterateSubmap(innerMapID)
if err != nil {
return nil, err
}

if isPublic {
fwRule.Public = policyRoutes
} else {
fwRule.MFA = policyRoutes
}
}

result[res] = fwRule
Expand Down
Binary file modified internal/router/bpf_bpfeb.o
Binary file not shown.
Binary file modified internal/router/bpf_bpfel.o
Binary file not shown.
118 changes: 101 additions & 17 deletions internal/router/ebpf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func TestAddUser(t *testing.T) {

acl := config.GetEffectiveAcl(device.Username)

results, err := routetypes.ParseRules(routetypes.PUBLIC, acl.Allow)
results, err := routetypes.ParseRules(acl.Mfa, acl.Allow)
if err != nil {
t.Fatal("parsing rules failed?:", err)
}
Expand All @@ -132,7 +132,7 @@ func TestAddUser(t *testing.T) {
}
}

results, err = routetypes.ParseRules(0, acl.Mfa)
results, err = routetypes.ParseRules(acl.Mfa, acl.Allow)
if err != nil {
t.Fatal("parsing rules failed?:", err)
}
Expand Down Expand Up @@ -315,21 +315,15 @@ func TestBasicAuthorise(t *testing.T) {
headers[5].String(): XDP_DROP,
}

mfas := config.GetEffectiveAcl(out[0].Username).Mfa
for i := range mfas {

rule, err := routetypes.ParseRule(0, mfas[i])
if err != nil {
t.Fatal("could not parse ip: ", err)
}

if len(rule.Keys) != 1 {
t.Fatal("expected to only have one key")
}
mfas, err := routetypes.ParseRules(config.GetEffectiveAcl(out[0].Username).Mfa, nil)
if err != nil {
t.Fatal("failed to parse mfa rules: ", err)
}

for i := range mfas {
newHeader := ipv4.Header{
Version: 4,
Dst: rule.Keys[0].AsIP(),
Dst: mfas[i].Keys[0].AsIP(),
Src: net.ParseIP(out[0].Address),
Len: ipv4.HeaderLen,
}
Expand Down Expand Up @@ -587,6 +581,91 @@ func TestSlidingWindow(t *testing.T) {
}
}

func TestCompositeRules(t *testing.T) {
if err := setup("../config/test_mutliple_rule_definitions_and_mfa_preference.json"); err != nil {
t.Fatal(err)
}
defer xdpObjects.Close()

out, err := addDevices()
if err != nil {
t.Fatal(err)
}

err = SetAuthorized(out[0].Address, out[0].Username)
if err != nil {
t.Fatal(err)
}

successPackets := [][]byte{
createPacket(net.ParseIP(out[0].Address), net.ParseIP("8.8.8.8"), routetypes.TCP, 11),
createPacket(net.ParseIP(out[0].Address), net.ParseIP("8.8.8.8"), routetypes.TCP, 8080),
createPacket(net.ParseIP(out[0].Address), net.ParseIP("8.8.8.8"), routetypes.UDP, 8080),
createPacket(net.ParseIP(out[0].Address), net.ParseIP("8.8.8.8"), routetypes.UDP, 9080),
createPacket(net.ParseIP(out[0].Address), net.ParseIP("8.8.8.8"), routetypes.TCP, 50),

createPacket(net.ParseIP(out[0].Address), net.ParseIP("7.7.7.7"), routetypes.ICMP, 0),
createPacket(net.ParseIP(out[0].Address), net.ParseIP("7.7.7.7"), routetypes.TCP, 22),
}

for i := range successPackets {

value, _, err := xdpObjects.bpfPrograms.XdpWagFirewall.Test(successPackets[i])
if err != nil {
t.Fatalf("program failed %s", err)
}

if value != XDP_PASS {
fw, _ := GetRules()
t.Logf("%+v", fw)
t.Fatalf("%d program did not XDP_PASS packet instead did: %s", i, result(value))
}
}

err = Deauthenticate(out[0].Address)
if err != nil {
t.Fatal(err)
}

expectedResults := []uint32{
XDP_DROP,
XDP_PASS,
XDP_PASS,

XDP_DROP,
XDP_DROP,

XDP_PASS,
}

packets := [][]byte{

createPacket(net.ParseIP(out[0].Address), net.ParseIP("8.8.8.8"), routetypes.TCP, 11),
createPacket(net.ParseIP(out[0].Address), net.ParseIP("8.8.8.8"), routetypes.TCP, 8080),
createPacket(net.ParseIP(out[0].Address), net.ParseIP("8.8.8.8"), routetypes.UDP, 8080),

createPacket(net.ParseIP(out[0].Address), net.ParseIP("8.8.8.8"), routetypes.UDP, 9080),
createPacket(net.ParseIP(out[0].Address), net.ParseIP("8.8.8.8"), routetypes.TCP, 50),

createPacket(net.ParseIP(out[0].Address), net.ParseIP("8.8.8.8"), routetypes.ICMP, 0),
}

for i := range packets {

value, _, err := xdpObjects.bpfPrograms.XdpWagFirewall.Test(packets[i])
if err != nil {
t.Fatalf("program failed %s", err)
}

if value != expectedResults[i] {
fw, _ := GetRules()
t.Logf("%s:%+v", out[0].Username, fw[out[0].Username])
t.Fatalf("%d program did not %s packet instead did: %s", i, result(expectedResults[i]), result(value))
}
}

}

func TestDisabledSlidingWindow(t *testing.T) {
if err := setup("../config/test_disabled_sliding_window.json"); err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -940,7 +1019,7 @@ func TestPortRestrictions(t *testing.T) {

acl := config.GetEffectiveAcl(out[0].Username)

rules, err := routetypes.ParseRules(routetypes.PUBLIC, acl.Allow)
rules, err := routetypes.ParseRules(acl.Mfa, acl.Allow)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -1066,7 +1145,7 @@ func TestAgnosticRuleOrdering(t *testing.T) {
for _, user := range out {
acl := config.GetEffectiveAcl(user.Username)

rules, err := routetypes.ParseRules(routetypes.PUBLIC, acl.Allow)
rules, err := routetypes.ParseRules(acl.Mfa, acl.Allow)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -1283,7 +1362,12 @@ func addDevices() ([]data.Device, error) {
}

for i := range devices {
err := AddUser(devices[i].Username, config.GetEffectiveAcl(devices[i].Username))
_, err := data.CreateUserDataAccount(devices[i].Username)
if err != nil {
return nil, err
}

err = AddUser(devices[i].Username, config.GetEffectiveAcl(devices[i].Username))
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit e46d81c

Please sign in to comment.