Skip to content

Commit d7320a9

Browse files
Addressing security concerns in Linux Multitenancy (#387)
* Block IP Sppofing in linux multitenacy by verifying the source IP based on ovs port * removed tag while adding portto ovs bridge * addressed review comments * addressed review comments
1 parent 112a67f commit d7320a9

File tree

3 files changed

+55
-36
lines changed

3 files changed

+55
-36
lines changed

network/ovs_endpointclient_linux.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func (client *OVSEndpointClient) AddEndpointRules(epInfo *EndpointInfo) error {
9090
}
9191

9292
log.Printf("[ovs] Get ovs port for interface %v.", client.hostVethName)
93-
containerPort, err := ovsctl.GetOVSPortNumber(client.hostVethName)
93+
containerOVSPort, err := ovsctl.GetOVSPortNumber(client.hostVethName)
9494
if err != nil {
9595
log.Printf("[ovs] Get ofport failed with error %v", err)
9696
return err
@@ -103,22 +103,25 @@ func (client *OVSEndpointClient) AddEndpointRules(epInfo *EndpointInfo) error {
103103
return err
104104
}
105105

106-
// IP SNAT Rule
107-
log.Printf("[ovs] Adding IP SNAT rule for egress traffic on %v.", containerPort)
108-
if err := ovsctl.AddIpSnatRule(client.bridgeName, containerPort, client.hostPrimaryMac, ""); err != nil {
109-
return err
110-
}
111-
112106
for _, ipAddr := range epInfo.IPAddresses {
113107
// Add Arp Reply Rules
114108
// Set Vlan id on arp request packet and forward it to table 1
115109
if err := ovsctl.AddFakeArpReply(client.bridgeName, ipAddr.IP); err != nil {
116110
return err
117111
}
118112

119-
// Add IP DNAT rule based on dst ip and vlanid
120-
log.Printf("[ovs] Adding MAC DNAT rule for IP address %v on %v.", ipAddr.IP.String(), hostPort)
121-
if err := ovsctl.AddMacDnatRule(client.bridgeName, hostPort, ipAddr.IP, client.containerMac, client.vlanID); err != nil {
113+
// IP SNAT Rule - Change src mac to VM Mac for packets coming from container host veth port.
114+
// This rule also checks if packets coming from right source ip based on the ovs port to prevent ip spoofing.
115+
// Otherwise it drops the packet.
116+
log.Printf("[ovs] Adding IP SNAT rule for egress traffic on %v.", containerOVSPort)
117+
if err := ovsctl.AddIpSnatRule(client.bridgeName, ipAddr.IP, client.vlanID, containerOVSPort, client.hostPrimaryMac, hostPort); err != nil {
118+
return err
119+
}
120+
121+
// Add IP DNAT rule based on dst ip and vlanid - This rule changes the destination mac to corresponding container mac based on the ip and
122+
// forwards the packet to corresponding container hostveth port
123+
log.Printf("[ovs] Adding MAC DNAT rule for IP address %v on hostport %v, containerport: %v", ipAddr.IP.String(), hostPort, containerOVSPort)
124+
if err := ovsctl.AddMacDnatRule(client.bridgeName, hostPort, ipAddr.IP, client.containerMac, client.vlanID, containerOVSPort); err != nil {
122125
return err
123126
}
124127
}

network/ovsinfravnet/infravnet.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,14 @@ func (client *OVSInfraVnetClient) CreateInfraVnetRules(
6565
return err
6666
}
6767

68-
if err := ovsctl.AddIpSnatRule(bridgeName, infraContainerPort, hostPrimaryMac, hostPort); err != nil {
68+
// 0 signifies not to add vlan tag to this traffic
69+
if err := ovsctl.AddIpSnatRule(bridgeName, infraIP.IP, 0, infraContainerPort, hostPrimaryMac, hostPort); err != nil {
6970
log.Printf("[ovs] AddIpSnatRule failed with error %v", err)
7071
return err
7172
}
7273

73-
if err := ovsctl.AddMacDnatRule(bridgeName, hostPort, infraIP.IP, client.containerInfraMac, 0); err != nil {
74+
// 0 signifies not to match traffic based on vlan tag
75+
if err := ovsctl.AddMacDnatRule(bridgeName, hostPort, infraIP.IP, client.containerInfraMac, 0, infraContainerPort); err != nil {
7476
log.Printf("[ovs] AddMacDnatRule failed with error %v", err)
7577
return err
7678
}

ovsctl/ovsctl.go

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ const (
1414
defaultMacForArpResponse = "12:34:56:78:9a:bc"
1515
)
1616

17+
// Open flow rule priorities. Higher the number higher the priority
18+
const (
19+
low = 10
20+
mid = 15
21+
high = 20
22+
)
23+
1724
func CreateOVSBridge(bridgeName string) error {
1825
log.Printf("[ovs] Creating OVS Bridge %v", bridgeName)
1926

@@ -41,13 +48,7 @@ func DeleteOVSBridge(bridgeName string) error {
4148
}
4249

4350
func AddPortOnOVSBridge(hostIfName string, bridgeName string, vlanID int) error {
44-
cmd := ""
45-
46-
if vlanID == 0 {
47-
cmd = fmt.Sprintf("ovs-vsctl add-port %s %s", bridgeName, hostIfName)
48-
} else {
49-
cmd = fmt.Sprintf("ovs-vsctl add-port %s %s tag=%d", bridgeName, hostIfName, vlanID)
50-
}
51+
cmd := fmt.Sprintf("ovs-vsctl add-port %s %s", bridgeName, hostIfName)
5152
_, err := platform.ExecuteCommand(cmd)
5253
if err != nil {
5354
log.Printf("[ovs] Error while setting OVS as master to primary interface %v", err)
@@ -69,7 +70,7 @@ func GetOVSPortNumber(interfaceName string) (string, error) {
6970
}
7071

7172
func AddVMIpAcceptRule(bridgeName string, primaryIP string, mac string) error {
72-
cmd := fmt.Sprintf("ovs-ofctl add-flow %s ip,nw_dst=%s,dl_dst=%s,priority=20,actions=normal", bridgeName, primaryIP, mac)
73+
cmd := fmt.Sprintf("ovs-ofctl add-flow %s ip,nw_dst=%s,dl_dst=%s,priority=%d,actions=normal", bridgeName, primaryIP, mac, high)
7374
_, err := platform.ExecuteCommand(cmd)
7475
if err != nil {
7576
log.Printf("[ovs] Adding SNAT rule failed with error %v", err)
@@ -80,8 +81,8 @@ func AddVMIpAcceptRule(bridgeName string, primaryIP string, mac string) error {
8081
}
8182

8283
func AddArpSnatRule(bridgeName string, mac string, macHex string, ofport string) error {
83-
cmd := fmt.Sprintf(`ovs-ofctl add-flow %v table=1,priority=10,arp,arp_op=1,actions='mod_dl_src:%s,
84-
load:0x%s->NXM_NX_ARP_SHA[],output:%s'`, bridgeName, mac, macHex, ofport)
84+
cmd := fmt.Sprintf(`ovs-ofctl add-flow %v table=1,priority=%d,arp,arp_op=1,actions='mod_dl_src:%s,
85+
load:0x%s->NXM_NX_ARP_SHA[],output:%s'`, bridgeName, low, mac, macHex, ofport)
8586
_, err := platform.ExecuteCommand(cmd)
8687
if err != nil {
8788
log.Printf("[ovs] Adding ARP SNAT rule failed with error %v", err)
@@ -91,21 +92,32 @@ func AddArpSnatRule(bridgeName string, mac string, macHex string, ofport string)
9192
return nil
9293
}
9394

94-
func AddIpSnatRule(bridgeName string, port string, mac string, outport string) error {
95+
// IP SNAT Rule - Change src mac to VM Mac for packets coming from container host veth port.
96+
func AddIpSnatRule(bridgeName string, ip net.IP, vlanID int, port string, mac string, outport string) error {
97+
var cmd string
9598
if outport == "" {
9699
outport = "normal"
97100
}
98101

99-
cmd := fmt.Sprintf("ovs-ofctl add-flow %v priority=20,ip,in_port=%s,vlan_tci=0,actions=mod_dl_src:%s,strip_vlan,%v",
100-
bridgeName, port, mac, outport)
102+
commonPrefix := fmt.Sprintf("ovs-ofctl add-flow %v priority=%d,ip,nw_src=%s,in_port=%s,vlan_tci=0,actions=mod_dl_src:%s", bridgeName, high, ip.String(), port, mac)
103+
104+
// This rule also checks if packets coming from right source ip based on the ovs port to prevent ip spoofing.
105+
// Otherwise it drops the packet.
106+
if vlanID != 0 {
107+
cmd = fmt.Sprintf("%s,mod_vlan_vid:%v,%v", commonPrefix, vlanID, outport)
108+
} else {
109+
cmd = fmt.Sprintf("%s,strip_vlan,%v", commonPrefix, outport)
110+
}
111+
101112
_, err := platform.ExecuteCommand(cmd)
102113
if err != nil {
103114
log.Printf("[ovs] Adding IP SNAT rule failed with error %v", err)
104115
return err
105116
}
106117

107-
cmd = fmt.Sprintf("ovs-ofctl add-flow %v priority=10,ip,in_port=%s,actions=drop",
108-
bridgeName, port)
118+
// Drop other packets which doesn't satisfy above condition
119+
cmd = fmt.Sprintf("ovs-ofctl add-flow %v priority=%d,ip,in_port=%s,actions=drop",
120+
bridgeName, low, port)
109121
_, err = platform.ExecuteCommand(cmd)
110122
if err != nil {
111123
log.Printf("[ovs] Dropping vlantag packet rule failed with error %v", err)
@@ -134,11 +146,11 @@ func AddFakeArpReply(bridgeName string, ip net.IP) error {
134146
ipAddrInt := common.IpToInt(ip)
135147

136148
log.Printf("[ovs] Adding ARP reply rule for IP address %v ", ip.String())
137-
cmd := fmt.Sprintf(`ovs-ofctl add-flow %s arp,arp_op=1,priority=20,actions='load:0x2->NXM_OF_ARP_OP[],
149+
cmd := fmt.Sprintf(`ovs-ofctl add-flow %s arp,arp_op=1,priority=%d,actions='load:0x2->NXM_OF_ARP_OP[],
138150
move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:%s,
139151
move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],move:NXM_OF_ARP_TPA[]->NXM_OF_ARP_SPA[],
140152
load:0x%s->NXM_NX_ARP_SHA[],load:0x%x->NXM_OF_ARP_TPA[],IN_PORT'`,
141-
bridgeName, defaultMacForArpResponse, macAddrHex, ipAddrInt)
153+
bridgeName, high, defaultMacForArpResponse, macAddrHex, ipAddrInt)
142154
_, err := platform.ExecuteCommand(cmd)
143155
if err != nil {
144156
log.Printf("[ovs] Adding ARP reply rule failed with error %v", err)
@@ -163,11 +175,11 @@ func AddArpReplyRule(bridgeName string, port string, ip net.IP, mac string, vlan
163175

164176
// If arp fields matches, set arp reply rule for the request
165177
log.Printf("[ovs] Adding ARP reply rule for IP address %v and vlanid %v.", ip, vlanid)
166-
cmd = fmt.Sprintf(`ovs-ofctl add-flow %s table=1,arp,arp_tpa=%s,dl_vlan=%v,arp_op=1,priority=20,actions='load:0x2->NXM_OF_ARP_OP[],
178+
cmd = fmt.Sprintf(`ovs-ofctl add-flow %s table=1,arp,arp_tpa=%s,dl_vlan=%v,arp_op=1,priority=%d,actions='load:0x2->NXM_OF_ARP_OP[],
167179
move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:%s,
168180
move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],
169181
load:0x%s->NXM_NX_ARP_SHA[],load:0x%x->NXM_OF_ARP_SPA[],strip_vlan,IN_PORT'`,
170-
bridgeName, ip.String(), vlanid, mac, macAddrHex, ipAddrInt)
182+
bridgeName, ip.String(), vlanid, high, mac, macAddrHex, ipAddrInt)
171183
_, err = platform.ExecuteCommand(cmd)
172184
if err != nil {
173185
log.Printf("[ovs] Adding ARP reply rule failed with error %v", err)
@@ -177,15 +189,17 @@ func AddArpReplyRule(bridgeName string, port string, ip net.IP, mac string, vlan
177189
return nil
178190
}
179191

180-
func AddMacDnatRule(bridgeName string, port string, ip net.IP, mac string, vlanid int) error {
192+
// Add MAC DNAT rule based on dst ip and vlanid
193+
func AddMacDnatRule(bridgeName string, port string, ip net.IP, mac string, vlanid int, containerPort string) error {
181194
var cmd string
195+
// This rule changes the destination mac to speciifed mac based on the ip and vlanid.
196+
// and forwards the packet to corresponding container hostveth port
182197

198+
commonPrefix := fmt.Sprintf("ovs-ofctl add-flow %s ip,nw_dst=%s,in_port=%s", bridgeName, ip.String(), port)
183199
if vlanid != 0 {
184-
cmd = fmt.Sprintf("ovs-ofctl add-flow %s ip,nw_dst=%s,dl_vlan=%v,in_port=%s,actions=mod_dl_dst:%s,normal",
185-
bridgeName, ip.String(), vlanid, port, mac)
200+
cmd = fmt.Sprintf("%s,dl_vlan=%v,actions=mod_dl_dst:%s,strip_vlan,%s", commonPrefix, vlanid, mac, containerPort)
186201
} else {
187-
cmd = fmt.Sprintf("ovs-ofctl add-flow %s ip,nw_dst=%s,in_port=%s,actions=mod_dl_dst:%s,normal",
188-
bridgeName, ip.String(), port, mac)
202+
cmd = fmt.Sprintf("%s,actions=mod_dl_dst:%s,strip_vlan,%s", commonPrefix, mac, containerPort)
189203
}
190204
_, err := platform.ExecuteCommand(cmd)
191205
if err != nil {

0 commit comments

Comments
 (0)