Skip to content

Commit

Permalink
This adds the initial code for egress (SNAT).
Browse files Browse the repository at this point in the history
  • Loading branch information
thebsdbox committed Sep 6, 2022
1 parent bb4c815 commit ba20ae1
Show file tree
Hide file tree
Showing 7 changed files with 488 additions and 1 deletion.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ replace github.com/insomniacslk/dhcp => github.com/harvester/dhcp v0.0.0-2022042
require (
github.com/cloudflare/ipvs v0.8.0
github.com/davecgh/go-spew v1.1.1
github.com/florianl/go-conntrack v0.3.0
github.com/ghodss/yaml v1.0.0
github.com/golang/protobuf v1.5.2
github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd
Expand Down Expand Up @@ -38,6 +39,7 @@ require (
github.com/alessio/shellescape v1.4.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/coreos/go-iptables v0.6.0
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/eapache/channels v1.1.0 // indirect
github.com/eapache/queue v1.1.0 // indirect
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
Expand Down Expand Up @@ -146,6 +148,8 @@ github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:Pjfxu
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/florianl/go-conntrack v0.3.0 h1:DUY84Mce+/lE9dJi2EWvGYacQtX2X96J9aVWV99l8UE=
github.com/florianl/go-conntrack v0.3.0/go.mod h1:Q+Um4J/nWUXSbnyzQRMOP4eweSeEQ2G8sfCO5gMz6Pw=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
Expand Down Expand Up @@ -803,6 +807,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
67 changes: 67 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,73 @@ var Version string
var Build string

func main() {

// i, err := vip.CreateIptablesClient()
// if err != nil {
// panic(err)
// }
// if os.Getenv("CREATE") != "" {

// b, err := i.CheckMangleChain(vip.MangleChainName)
// if err != nil {
// panic(err)
// }
// if b == false {
// err = i.CreateMangleChain(vip.MangleChainName)
// if err != nil {
// panic(err)
// }
// }
// // Add entries to our mangle chaing
// err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, "10.0.0.0/16")
// if err != nil {
// panic(err)
// }
// err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, "10.96.0.0/12")
// if err != nil {
// panic(err)
// }
// err = i.AppendReturnRulesForMarking(vip.MangleChainName, "10.0.77.36/32")
// if err != nil {
// panic(err)
// }
// err = i.InsertMangeTableIntoPrerouting(vip.MangleChainName)
// if err != nil {
// panic(err)
// }
// err = i.InsertSourceNat("192.168.0.221", "10.0.77.36")
// if err != nil {
// panic(err)
// }

// err = i.DumpChain(vip.MangleChainName)
// vip.ExampleNfct_Dump()
// if err == nil {
// return
// }
// }
// if os.Getenv("DELETE") != "" {
// err = i.DeleteManglePrerouting(vip.MangleChainName)
// if err != nil {
// panic(err)
// }
// err = i.DeleteMangleChain(vip.MangleChainName)
// if err != nil {
// panic(err)
// }
// err = i.DeleteSourceNat("10.0.77.36", "192.168.0.221")
// if err != nil {
// panic(err)
// }
// //err = i.DumpChain(vip.MangleChainName)
// vip.ExampleNfct_Dump()
// if err == nil {
// return
// }
// if err != nil {
// panic(err)
// }
// }
cmd.Release.Version = Version
cmd.Release.Build = Build
cmd.Execute()
Expand Down
175 changes: 175 additions & 0 deletions pkg/egress/egress.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package egress

//https://github.com/Trojan295/kube-router/commit/d48fd0a275249eb44e272d7f936ac91610c987cd#diff-3b65e4098d69eede2c4abfedc10116dda8fa05b9e308c18c1cb62b1a3fc8c119

import (
"bufio"
"bytes"
"fmt"
"net"
"os"
"os/exec"
"regexp"
"strconv"
"strings"

"github.com/coreos/go-iptables/iptables"
log "github.com/sirupsen/logrus"
)

const (
preroutingMarkChain = "CHINCHILLA-PREROUTING-MARK"
postroutingSnatChain = "CHINCHILLA-POSTROUTING-SNAT"

egressIPAnnotation = "egressSNAT.IPAddress"
egressFixedPortsAnnotation = "egressSNAT.FixedPorts"

routingTableFile = "/opt/rt_tables"
)

func iptablesChainExists(table string, chain string, it *iptables.IPTables) (bool, error) {
chains, err := it.ListChains(table)
if err != nil {
return false, err
}

for _, c := range chains {
if c == chain {
return true, nil
}
}
return false, nil
}

func iptablesEnsureChain(table string, chain string, it *iptables.IPTables) error {
if exists, err := iptablesChainExists(table, chain, it); err != nil {
return nil
} else if !exists {
return it.NewChain(table, chain)
}
return nil
}

func iptablesEnsureRuleAtPosition(table, chain string, position int, it *iptables.IPTables, rule ...string) error {
if exists, err := it.Exists(table, chain, rule...); err != nil {
return err
} else if exists {
if err2 := it.Delete(table, chain, rule...); err2 != nil {
return err2
}
}

return it.Insert(table, chain, position, rule...)
}

type routeTable struct {
ID int
Name string
Subnet net.IPNet
}

func FindRouteTableForIP(ip net.IP, rts []routeTable) *routeTable {
for _, rt := range rts {
if rt.Subnet.Contains(ip) {
return &rt
}
}
return nil
}

func EnsureRouteRule(rt *routeTable) error {
fwmark := fmt.Sprintf("%x/0xff", rt.ID)

out, err := exec.Command("ip", "rule", "show", "fwmark", fwmark, "table", rt.Name).Output()
if err != nil {
return err
}

if string(out) != "" {
return nil
}

_, err = exec.Command("ip", "rule", "add", "fwmark", fwmark, "table", rt.Name).Output()
if err != nil {
return err
}

return nil
}

func GetRouteTables() ([]routeTable, error) {
tables := make([]routeTable, 0)

fp, err := os.Open(routingTableFile)
if err != nil {
return tables, err
}
defer fp.Close()

r := bufio.NewScanner(fp)
for r.Scan() {
line := strings.Trim(r.Text(), " ")
if strings.HasPrefix(line, "#") {
continue
}

cols := strings.Fields(line)
name := cols[1]
ID, err := strconv.Atoi(cols[0])
if err != nil {
log.Error("invalid route table entry in /etc/iproute2/rt_tables")
continue
}

rt := routeTable{
ID: ID,
Name: name,
}

if rt.ID == 0 {
continue
}

cidr, err := getCIDRForRouteTable(&rt)
if err != nil || cidr == nil {
continue
}

rt.Subnet = *cidr

tables = append(tables, rt)
}

return tables, nil
}

func getCIDRForRouteTable(rt *routeTable) (*net.IPNet, error) {
tableID := fmt.Sprintf("%d", rt.ID)

out, err := exec.Command("ip", "rule", "show", "table", tableID).Output()
if err != nil {
return nil, err
}

r := bufio.NewScanner(bytes.NewBuffer(out))

var cidr *net.IPNet = nil

pattern := fmt.Sprintf(`\d+:.+from (.+) lookup.+`)
re := regexp.MustCompile(pattern)

for r.Scan() {
line := r.Text()
result := re.FindStringSubmatch(line)

if len(result) > 0 {
_, cidr, _ = net.ParseCIDR(result[1])
if cidr != nil {
break
}
}
}

return cidr, nil
}

90 changes: 90 additions & 0 deletions pkg/manager/service_egress.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package manager

import (
"context"
"fmt"
"strings"

"github.com/kube-vip/kube-vip/pkg/vip"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func (sm *Manager) configureEgress(vipIP, podIP string) error {
serviceCIDR, podCIDR, err := sm.AutoDiscoverCIDRs()
if err != nil {
serviceCIDR = "10.96.0.0/12"
podCIDR = "10.0.0.0/16"
}
i, err := vip.CreateIptablesClient()
if err != nil {
return fmt.Errorf("error Creating iptables client [%s]", err)
}
// Check if the kube-vip mangle chain exists, if not create it
exists, err := i.CheckMangleChain(vip.MangleChainName)
if err != nil {
return fmt.Errorf("error checking for existence of mangle chain [%s], error [%s]", vip.MangleChainName, err)
}
if !exists {
err = i.CreateMangleChain(vip.MangleChainName)
if err != nil {
return fmt.Errorf("error creating mangle chain [%s], error [%s]", vip.MangleChainName, err)
}
}
err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, podCIDR)
if err != nil {
panic(err)
}
err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, serviceCIDR)
if err != nil {
panic(err)
}
err = i.AppendReturnRulesForMarking(vip.MangleChainName, podIP+"/32")
if err != nil {
panic(err)
}

err = i.InsertMangeTableIntoPrerouting(vip.MangleChainName)
if err != nil {
panic(err)
}
err = i.InsertSourceNat(vipIP, podIP)
if err != nil {
panic(err)
}

_ = i.DumpChain(vip.MangleChainName)
err = vip.DeleteExistingSessions(podIP)
if err != nil {
return err
}

return nil
}

func (sm *Manager) AutoDiscoverCIDRs() (serviceCIDR, podCIDR string, err error) {
pod, err := sm.clientSet.CoreV1().Pods("kube-system").Get(context.TODO(), "kube-controller-manager", v1.GetOptions{})
if err != nil {
return "", "", err
}
for flags := range pod.Spec.Containers[0].Command {
if strings.Contains(pod.Spec.Containers[0].Command[flags], "--cluster-cidr=") {
podCIDR = strings.ReplaceAll(pod.Spec.Containers[0].Command[flags], "--cluster-cidr=", "")
}
if strings.Contains(pod.Spec.Containers[0].Command[flags], "--service-cluster-ip-range=") {
serviceCIDR = strings.ReplaceAll(pod.Spec.Containers[0].Command[flags], "--service-cluster-ip-range=", "")
}
}
if podCIDR == "" || serviceCIDR == "" {
err = fmt.Errorf("unable to fully determine cluster CIDR configurations")
}

return
}

func TeardownEgress(podIP, serviceIP string) error {
i, err := vip.CreateIptablesClient()
if err != nil {
return fmt.Errorf("error Creating iptables client [%s]", err)
}
return i.DeleteSourceNat(podIP, serviceIP)
}
Loading

0 comments on commit ba20ae1

Please sign in to comment.