Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

secure farmer lan #2520

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions pkg/network/ndmz/dualstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,10 @@ func applyFirewall() error {
return errors.Wrap(err, "failed to apply nft rule set")
}

if err := nft.DropTrafficToLAN(dmzNamespace); err != nil {
return errors.Wrap(err, "failed to drop traffic to lan")
}

return nil
}

Expand Down
93 changes: 93 additions & 0 deletions pkg/network/nft/nft.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package nft

import (
"bytes"
"fmt"
"io"
"os/exec"

"github.com/rs/zerolog/log"
"github.com/vishvananda/netlink"

"github.com/pkg/errors"
)
Expand Down Expand Up @@ -32,3 +35,93 @@ func Apply(r io.Reader, ns string) error {
}
return nil
}

// DropTrafficToLAN drops all the outgoing traffic to any peers on
// the same lan network, but allow dicovery port for ygg/myc by accepting
// traffic to/from dest/src ports.
// @th,0,16 and @th,16,16 is raw expression for sport/dport in transport header
// used due to limitation on the installed nft v0.9.1
func DropTrafficToLAN(namesapce string) error {
dgw, err := getDefaultGW()
if err != nil {
return fmt.Errorf("failed to find default gateway: %w", err)
}

if !dgw.IP.IsPrivate() {
log.Warn().Msg("skip LAN security. default gateway is public")
return nil
}

ipAddr := dgw.IP.String()
netAddr := getNetworkRange(dgw)
macAddr := dgw.HardwareAddr.String()
log.Debug().
Str("ipAddr", ipAddr).
Str("netAddr", netAddr).
Str("macAddr", macAddr).
Msg("drop traffic to lan with the default gateway")

var buf bytes.Buffer
buf.WriteString("table inet filter {\n")
buf.WriteString(" chain forward {\n")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're missing the type here
type filter hook forward priority filter; policy accept;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is already handled in the initial nft setup

// allow traffic on sport ygg/myc discovery ports
buf.WriteString(" meta l4proto { tcp, udp } @th,0,16 { 9651, 9650 } accept;\n")
// allow traffic on dport ygg/myc discovery ports
buf.WriteString(" meta l4proto { tcp, udp } @th,16,16 { 9651, 9650 } accept;\n")
// allow traffic to the default gateway
buf.WriteString(fmt.Sprintf(" ip daddr %s accept;\n", ipAddr))
// allow traffic to any ip not in the network range
buf.WriteString(fmt.Sprintf(" ip daddr != %s accept;\n", netAddr))
// only drop traffic if it destined to mac addr other than the default gateway
buf.WriteString(fmt.Sprintf(" ether daddr != %s drop;\n", macAddr))
buf.WriteString(" }\n")
buf.WriteString("}\n")

// applied on the ndmz namespace
return Apply(&buf, namesapce)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

namesapce ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, where do you apply the new table ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in ndmz namespace

}

func getDefaultGW() (netlink.Neigh, error) {
routes, err := netlink.RouteList(nil, netlink.FAMILY_V4)
if err != nil {
return netlink.Neigh{}, fmt.Errorf("failed to list routes: %v", err)
}

var defaultRoute *netlink.Route
for _, route := range routes {
if route.Dst == nil {
defaultRoute = &route
break
}
}

if defaultRoute == nil {
return netlink.Neigh{}, fmt.Errorf("default route not found")
}

if defaultRoute.Gw == nil {
return netlink.Neigh{}, fmt.Errorf("default route has no gateway")
}

neighs, err := netlink.NeighList(0, netlink.FAMILY_V4)
if err != nil {
return netlink.Neigh{}, fmt.Errorf("failed to list neighbors: %v", err)
}

for _, neigh := range neighs {
if neigh.IP.Equal(defaultRoute.Gw) {
return neigh, nil
}
}

return netlink.Neigh{}, errors.New("failed to get default gw")
}

func getNetworkRange(ip netlink.Neigh) string {
mask := ip.IP.DefaultMask()
network := ip.IP.Mask(mask)
ones, _ := mask.Size()
networkRange := fmt.Sprintf("%s/%d", network.String(), ones)

return networkRange
}
Loading