Add output mark to XfrmController
Adds the ability for XfrmController to set output marks, to allow
support for VTIs. This change uses the underlying networkId field
(renamed from underlyingNetwork), for which the System Server currently
passes the netid of the underlying Network.
Bug: 72392543
Test: All tests (CTS + unit tests) passing
Change-Id: I76fe052ecf0fc193f07713a2ea31a4ad58fc9ff9
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 8e02e25..ac4e77f 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -487,7 +487,7 @@
int32_t mode,
const std::string& sourceAddress,
const std::string& destinationAddress,
- int64_t underlyingNetworkHandle,
+ int32_t underlyingNetId,
int32_t spi,
int32_t markValue,
int32_t markMask,
@@ -502,7 +502,7 @@
ALOGD("ipSecAddSecurityAssociation()");
return asBinderStatus(gCtls->xfrmCtrl.ipSecAddSecurityAssociation(
transformId, mode, sourceAddress, destinationAddress,
- underlyingNetworkHandle,
+ underlyingNetId,
spi, markValue, markMask,
authAlgo, authKey, authTruncBits,
cryptAlgo, cryptKey, cryptTruncBits,
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
index 5858588..dbf4b6c 100644
--- a/server/NetdNativeService.h
+++ b/server/NetdNativeService.h
@@ -113,7 +113,7 @@
int32_t mode,
const std::string& sourceAddress,
const std::string& destinationAddress,
- int64_t underlyingNetworkHandle,
+ int32_t underlyingNetId,
int32_t spi,
int32_t markValue,
int32_t markMask,
diff --git a/server/XfrmController.cpp b/server/XfrmController.cpp
index f34a33b..25d3bad 100644
--- a/server/XfrmController.cpp
+++ b/server/XfrmController.cpp
@@ -414,7 +414,7 @@
netdutils::Status XfrmController::ipSecAddSecurityAssociation(
int32_t transformId, int32_t mode, const std::string& sourceAddress,
- const std::string& destinationAddress, int64_t underlyingNetworkHandle, int32_t spi,
+ const std::string& destinationAddress, int32_t underlyingNetId, int32_t spi,
int32_t markValue, int32_t markMask, const std::string& authAlgo,
const std::vector<uint8_t>& authKey, int32_t authTruncBits, const std::string& cryptAlgo,
const std::vector<uint8_t>& cryptKey, int32_t cryptTruncBits, const std::string& aeadAlgo,
@@ -425,7 +425,7 @@
ALOGD("mode=%d", mode);
ALOGD("sourceAddress=%s", sourceAddress.c_str());
ALOGD("destinationAddress=%s", destinationAddress.c_str());
- ALOGD("underlyingNetworkHandle=%" PRIx64, underlyingNetworkHandle);
+ ALOGD("underlyingNetworkId=%d", underlyingNetId);
ALOGD("spi=%0.8x", spi);
ALOGD("markValue=%x", markValue);
ALOGD("markMask=%x", markMask);
@@ -489,6 +489,8 @@
return netdutils::statusFromErrno(EINVAL, "Invalid encap type");
}
+ saInfo.netId = underlyingNetId;
+
ret = updateSecurityAssociation(saInfo, sock);
if (!isOk(ret)) {
ALOGD("Failed updating a Security Association, line=%d", __LINE__);
@@ -725,7 +727,6 @@
selector->family = record.addrFamily;
selector->proto = AF_UNSPEC; // TODO: do we need to match the protocol? it's
// possible via the socket
- selector->ifindex = record.netId; // TODO : still need to sort this out
}
netdutils::Status XfrmController::updateSecurityAssociation(const XfrmSaInfo& record,
@@ -735,6 +736,7 @@
nlattr_algo_auth auth{};
nlattr_algo_aead aead{};
nlattr_xfrm_mark xfrmmark{};
+ nlattr_xfrm_output_mark xfrmoutputmark{};
nlattr_encap_tmpl encap{};
enum {
@@ -749,24 +751,28 @@
AEAD_PAD,
MARK,
MARK_PAD,
+ OUTPUT_MARK,
+ OUTPUT_MARK_PAD,
ENCAP,
ENCAP_PAD,
};
std::vector<iovec> iov = {
- {NULL, 0}, // reserved for the eventual addition of a NLMSG_HDR
- {&usersa, 0}, // main usersa_info struct
- {kPadBytes, 0}, // up to NLMSG_ALIGNTO pad bytes of padding
- {&crypt, 0}, // adjust size if crypt algo is present
- {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
- {&auth, 0}, // adjust size if auth algo is present
- {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
- {&aead, 0}, // adjust size if aead algo is present
- {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
- {&xfrmmark, 0}, // adjust size if xfrm mark is present
- {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
- {&encap, 0}, // adjust size if encapsulating
- {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
+ {NULL, 0}, // reserved for the eventual addition of a NLMSG_HDR
+ {&usersa, 0}, // main usersa_info struct
+ {kPadBytes, 0}, // up to NLMSG_ALIGNTO pad bytes of padding
+ {&crypt, 0}, // adjust size if crypt algo is present
+ {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
+ {&auth, 0}, // adjust size if auth algo is present
+ {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
+ {&aead, 0}, // adjust size if aead algo is present
+ {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
+ {&xfrmmark, 0}, // adjust size if xfrm mark is present
+ {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
+ {&xfrmoutputmark, 0}, // adjust size if xfrm output mark is present
+ {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
+ {&encap, 0}, // adjust size if encapsulating
+ {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
};
if (!record.aead.name.empty() && (!record.auth.name.empty() || !record.crypt.name.empty())) {
@@ -796,6 +802,9 @@
len = iov[MARK].iov_len = fillNlAttrXfrmMark(record, &xfrmmark);
iov[MARK_PAD].iov_len = NLA_ALIGN(len) - len;
+ len = iov[OUTPUT_MARK].iov_len = fillNlAttrXfrmOutputMark(record.netId, &xfrmoutputmark);
+ iov[OUTPUT_MARK_PAD].iov_len = NLA_ALIGN(len) - len;
+
len = iov[ENCAP].iov_len = fillNlAttrXfrmEncapTmpl(record, &encap);
iov[ENCAP_PAD].iov_len = NLA_ALIGN(len) - len;
@@ -1101,6 +1110,19 @@
return len;
}
+int XfrmController::fillNlAttrXfrmOutputMark(
+ const __u32 output_mark_value, nlattr_xfrm_output_mark* output_mark) {
+ // Do not set if we were not given an output mark
+ if (output_mark_value == 0) {
+ return 0;
+ }
+
+ output_mark->outputMark = output_mark_value;
+ int len = NLA_HDRLEN + sizeof(__u32);
+ fillXfrmNlaHdr(&output_mark->hdr, XFRMA_OUTPUT_MARK, len);
+ return len;
+}
+
int XfrmController::fillUserPolicyId(const XfrmSaInfo& record, XfrmDirection direction,
xfrm_userpolicy_id* usersp) {
// For DELPOLICY, when index is absent, selector is needed to match the policy
diff --git a/server/XfrmController.h b/server/XfrmController.h
index 9869c67..2dc8406 100644
--- a/server/XfrmController.h
+++ b/server/XfrmController.h
@@ -131,7 +131,7 @@
netdutils::Status ipSecAddSecurityAssociation(
int32_t transformId, int32_t mode, const std::string& sourceAddress,
- const std::string& destinationAddress, int64_t underlyingNetworkHandle, int32_t spi,
+ const std::string& destinationAddress, int32_t underlyingNetId, int32_t spi,
int32_t markValue, int32_t markMask, const std::string& authAlgo,
const std::vector<uint8_t>& authKey, int32_t authTruncBits, const std::string& cryptAlgo,
const std::vector<uint8_t>& cryptKey, int32_t cryptTruncBits, const std::string& aeadAlgo,
@@ -220,6 +220,13 @@
xfrm_mark mark;
};
+ // Container for the content of an XFRMA_OUTPUT_MARK netlink attribute.
+ // Exposed for testing
+ struct nlattr_xfrm_output_mark {
+ nlattr hdr;
+ __u32 outputMark;
+ };
+
private:
/*
* Below is a redefinition of the xfrm_usersa_info struct that is part
@@ -298,6 +305,8 @@
static int fillUserPolicyId(const XfrmSaInfo& record, XfrmDirection direction,
xfrm_userpolicy_id* policy_id);
static int fillNlAttrXfrmMark(const XfrmId& record, nlattr_xfrm_mark* mark);
+ static int fillNlAttrXfrmOutputMark(const __u32 output_mark_value,
+ nlattr_xfrm_output_mark* output_mark);
static netdutils::Status allocateSpi(const XfrmSaInfo& record, uint32_t minSpi, uint32_t maxSpi,
uint32_t* outSpi, const XfrmSocket& sock);
diff --git a/server/XfrmControllerTest.cpp b/server/XfrmControllerTest.cpp
index 46ef6e4..b883dce 100644
--- a/server/XfrmControllerTest.cpp
+++ b/server/XfrmControllerTest.cpp
@@ -102,6 +102,7 @@
static constexpr int DROID_SPI = 0xD1201D;
static constexpr size_t KEY_LENGTH = 32;
static constexpr int NLMSG_DEFAULTSIZE = 8192;
+static constexpr uint32_t TEST_XFRM_OUTPUT_MARK = 0x512;
static constexpr uint32_t TEST_XFRM_MARK = 0x123;
static constexpr uint32_t TEST_XFRM_MASK = 0xFFFFFFFF;
@@ -263,7 +264,7 @@
}
void testIpSecAddSecurityAssociation(int version, const MockSyscalls& mockSyscalls,
- const XfrmMode& mode) {
+ const XfrmMode& mode, __u32 underlying_netid) {
const int family = (version == 6) ? AF_INET6 : AF_INET;
const std::string localAddr = (version == 6) ? LOCALHOST_V6 : LOCALHOST_V4;
const std::string remoteAddr = (version == 6) ? TEST_ADDR_V6 : TEST_ADDR_V4;
@@ -282,6 +283,10 @@
NLA_ALIGN(offsetof(XfrmController::nlattr_algo_auth, key) + KEY_LENGTH) +
NLA_ALIGN(sizeof(XfrmController::nlattr_xfrm_mark));
+ if (underlying_netid) {
+ expectedMsgLength += NLA_ALIGN(sizeof(XfrmController::nlattr_xfrm_output_mark));
+ }
+
std::vector<uint8_t> nlMsgBuf;
EXPECT_CALL(mockSyscalls, writev(_, _))
.WillOnce(DoAll(SaveFlattenedIovecs<1>(&nlMsgBuf), Return(expectedMsgLength)));
@@ -291,10 +296,11 @@
XfrmController ctrl;
Status res = ctrl.ipSecAddSecurityAssociation(
1 /* resourceId */, static_cast<int>(mode), localAddr, remoteAddr,
- 0 /* underlying network */, DROID_SPI, TEST_XFRM_MARK /* mark */, TEST_XFRM_MASK /* mask */,
- "hmac(sha256)" /* auth algo */, authKey, 128 /* auth trunc length */,
- "cbc(aes)" /* encryption algo */, cryptKey, 0 /* crypt trunc length? */, "" /* AEAD algo */,
- {}, 0, static_cast<int>(XfrmEncapType::NONE), 0 /* local port */, 0 /* remote port */);
+ underlying_netid /* underlying netid */, DROID_SPI, TEST_XFRM_MARK /* mark */,
+ TEST_XFRM_MASK /* mask */, "hmac(sha256)" /* auth algo */,
+ authKey, 128 /* auth trunc length */, "cbc(aes)" /* encryption algo */,
+ cryptKey, 0 /* crypt trunc length? */, "" /* AEAD algo */, {}, 0,
+ static_cast<int>(XfrmEncapType::NONE), 0 /* local port */, 0 /* remote port */);
EXPECT_TRUE(isOk(res)) << res;
EXPECT_EQ(expectedMsgLength, nlMsgBuf.size());
@@ -328,8 +334,9 @@
XfrmController::nlattr_algo_crypt encryptAlgo{};
XfrmController::nlattr_algo_auth authAlgo{};
XfrmController::nlattr_xfrm_mark mark{};
- auto attrHandler = [&encryptAlgo, &authAlgo, &mark](const nlattr& attr,
- const Slice& attr_payload) {
+ XfrmController::nlattr_xfrm_output_mark outputmark{};
+ auto attrHandler = [&encryptAlgo, &authAlgo, &mark, &outputmark](const nlattr& attr,
+ const Slice& attr_payload) {
Slice buf = attr_payload;
if (attr.nla_type == XFRMA_ALG_CRYPT) {
encryptAlgo.hdr = attr;
@@ -344,6 +351,9 @@
} else if (attr.nla_type == XFRMA_MARK) {
mark.hdr = attr;
netdutils::extract(buf, mark.mark);
+ } else if (attr.nla_type == XFRMA_OUTPUT_MARK) {
+ mark.hdr = attr;
+ netdutils::extract(buf, outputmark.outputMark);
} else {
FAIL() << "Unexpected nlattr type: " << attr.nla_type;
}
@@ -357,16 +367,25 @@
reinterpret_cast<void*>(&authAlgo.key), KEY_LENGTH));
EXPECT_EQ(TEST_XFRM_MARK, mark.mark.v);
EXPECT_EQ(TEST_XFRM_MASK, mark.mark.m);
+ if (underlying_netid) {
+ EXPECT_EQ(TEST_XFRM_OUTPUT_MARK, outputmark.outputMark);
+ }
}
TEST_P(XfrmControllerParameterizedTest, TestTransportModeIpSecAddSecurityAssociation) {
const int version = GetParam();
- testIpSecAddSecurityAssociation(version, mockSyscalls, XfrmMode::TRANSPORT);
+ testIpSecAddSecurityAssociation(version, mockSyscalls, XfrmMode::TRANSPORT, 0);
}
TEST_P(XfrmControllerParameterizedTest, TestTunnelModeIpSecAddSecurityAssociation) {
const int version = GetParam();
- testIpSecAddSecurityAssociation(version, mockSyscalls, XfrmMode::TUNNEL);
+ testIpSecAddSecurityAssociation(version, mockSyscalls, XfrmMode::TUNNEL, 0);
+}
+
+TEST_P(XfrmControllerParameterizedTest, TestTunnelModeIpSecAddSecurityAssociationWithOutputMark) {
+ const int version = GetParam();
+ testIpSecAddSecurityAssociation(version, mockSyscalls, XfrmMode::TUNNEL,
+ TEST_XFRM_OUTPUT_MARK);
}
TEST_F(XfrmControllerTest, TestIpSecAddSecurityAssociationIPv4Encap) {
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index 1da3339..d9902af 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -345,7 +345,7 @@
* @param mode either Transport or Tunnel mode
* @param sourceAddress InetAddress as string for the sending endpoint
* @param destinationAddress InetAddress as string for the receiving endpoint
- * @param underlyingNetworkHandle the networkHandle of the network to which the SA is applied
+ * @param underlyingNetId the netId of the network to which the SA is applied
* @param spi a 32-bit unique ID allocated to the user
* @param markValue a 32-bit unique ID chosen by the user
* @param markMask a 32-bit mask chosen by the user
@@ -368,7 +368,7 @@
int mode,
in @utf8InCpp String sourceAddress,
in @utf8InCpp String destinationAddress,
- long underlyingNetworkHandle,
+ int underlyingNetId,
int spi,
int markValue,
int markMask,