-
Notifications
You must be signed in to change notification settings - Fork 43
/
iptables.go
154 lines (117 loc) · 3.91 KB
/
iptables.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package iptables
import (
"fmt"
"os/exec"
"strings"
"github.com/go-logr/logr"
"github.com/jodevsa/wireguard-operator/pkg/agent"
"github.com/jodevsa/wireguard-operator/pkg/api/v1alpha1"
)
func ApplyRules(rules string) error {
cmd := exec.Command("iptables-restore")
cmd.Stdin = strings.NewReader(rules)
return cmd.Run()
}
type Iptables struct {
Logger logr.Logger
}
func (it *Iptables) Sync(state agent.State) error {
it.Logger.Info("syncing network policies")
wgHostName := state.Server.Status.Address
dns := state.Server.Status.Dns
peers := state.Peers
cfg := GenerateIptableRulesFromPeers(wgHostName, dns, peers)
err := ApplyRules(cfg)
if err != nil {
return err
}
return nil
}
func GenerateIptableRulesFromNetworkPolicies(policies v1alpha1.EgressNetworkPolicies, peerIp string, kubeDnsIp string, wgServerIp string) string {
peerChain := strings.ReplaceAll(peerIp, ".", "-")
rules := []string{
// add a comment
fmt.Sprintf("# start of rules for peer %s", peerIp),
// create chain for peer
fmt.Sprintf(":%s - [0:0]", peerChain),
// associate peer chain to FORWARD chain
fmt.Sprintf("-A FORWARD -s %s -j %s", peerIp, peerChain),
// allow peer to ping (ICMP) wireguard server for debugging purposes
fmt.Sprintf("-A %s -d %s -p icmp -j ACCEPT", peerChain, wgServerIp),
// allow peer to communicate with itself
fmt.Sprintf("-A %s -d %s -j ACCEPT", peerChain, peerIp),
// allow peer to communicate with kube-dns
fmt.Sprintf("-A %s -d %s -p UDP --dport 53 -j ACCEPT", peerChain, kubeDnsIp),
}
for _, policy := range policies {
rules = append(rules, EgressNetworkPolicyToIpTableRules(policy, peerChain)...)
}
// if policies are defined impose an implicit deny all
if len(policies) != 0 {
rules = append(rules, fmt.Sprintf("-A %s -j REJECT --reject-with icmp-port-unreachable", peerChain))
}
// add a comment
rules = append(rules, fmt.Sprintf("# end of rules for peer %s", peerIp))
return strings.Join(rules, "\n")
}
func GenerateIptableRulesFromPeers(wgHostName string, dns string, peers []v1alpha1.WireguardPeer) string {
var rules []string
var natTableRules = `
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
COMMIT`
for _, peer := range peers {
//tc(peer.Spec.DownloadSpeed, peer.Spec.UploadSpeed)
rules = append(rules, GenerateIptableRulesFromNetworkPolicies(peer.Spec.EgressNetworkPolicies, peer.Spec.Address, dns, wgHostName))
}
var filterTableRules = fmt.Sprintf(`
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
%s
COMMIT
`, strings.Join(rules, "\n"))
return fmt.Sprintf("%s\n%s", natTableRules, filterTableRules)
}
func EgressNetworkPolicyToIpTableRules(policy v1alpha1.EgressNetworkPolicy, peerChain string) []string {
var rules []string
if policy.Protocol == "" && policy.To.Port != 0 {
policy.Protocol = "TCP"
rules = append(rules, EgressNetworkPolicyToIpTableRules(policy, peerChain)[0])
policy.Protocol = "UDP"
rules = append(rules, EgressNetworkPolicyToIpTableRules(policy, peerChain)[0])
return rules
}
// customer rules
var rulePeerChain = "-A " + peerChain
var ruleAction = string("-j " + v1alpha1.EgressNetworkPolicyActionDeny)
var ruleProtocol = ""
var ruleDestIp = ""
var ruleDestPort = ""
if policy.To.Ip != "" {
ruleDestIp = "-d " + policy.To.Ip
}
if policy.Protocol != "" {
ruleProtocol = "-p " + strings.ToUpper(string(policy.Protocol))
}
if policy.To.Port != 0 {
ruleDestPort = "--dport " + fmt.Sprint(policy.To.Port)
}
if policy.Action != "" {
ruleAction = "-j " + strings.ToUpper(string(policy.Action))
}
var options = []string{rulePeerChain, ruleDestIp, ruleProtocol, ruleDestPort, ruleAction}
var filteredOptions []string
for _, option := range options {
if len(option) != 0 {
filteredOptions = append(filteredOptions, option)
}
}
rules = append(rules, strings.Join(filteredOptions, " "))
return rules
}