diff options
| author | manojboopathi <manojboopathi@google.com> | 2018-01-02 14:45:47 -0800 |
|---|---|---|
| committer | Nathan Harold <nharold@google.com> | 2018-01-24 00:54:34 -0800 |
| commit | 8707f238a1498804aef938ae55b3087d8c8b6d44 (patch) | |
| tree | 21c20672155bfc75d0ea0090a412d12f8d12e230 /server/XfrmController.cpp | |
| parent | 96abf48e015c5ac8422426e26bb482917f2048dc (diff) | |
| download | platform_system_netd-8707f238a1498804aef938ae55b3087d8c8b6d44.tar.gz platform_system_netd-8707f238a1498804aef938ae55b3087d8c8b6d44.tar.bz2 platform_system_netd-8707f238a1498804aef938ae55b3087d8c8b6d44.zip | |
Add VTI Netlink Interface in NetD
Includes the logic to add / update / remove Virtual Tunnel Inteface
in RouteController.
Bug: 63589711
Test: Ran runtest -x "system/netd/tests/netd_integration_test.cpp"
Change-Id: I49a86f2eceecaf34fbb1e5dc05a888447437bef0
Diffstat (limited to 'server/XfrmController.cpp')
| -rw-r--r-- | server/XfrmController.cpp | 247 |
1 files changed, 231 insertions, 16 deletions
diff --git a/server/XfrmController.cpp b/server/XfrmController.cpp index 25d3bad43..cc2c3054a 100644 --- a/server/XfrmController.cpp +++ b/server/XfrmController.cpp @@ -158,6 +158,36 @@ void logIov(const std::vector<iovec>& iov) { } } +size_t fillNlAttr(__u16 nlaType, size_t valueSize, nlattr* nlAttr) { + size_t dataLen = valueSize; + int padLength = NLMSG_ALIGN(dataLen) - dataLen; + nlAttr->nla_len = (__u16)(dataLen + sizeof(nlattr)); + nlAttr->nla_type = nlaType; + return padLength; +} + +size_t fillNlAttrIpAddress(__u16 nlaType, int family, const std::string& value, nlattr* nlAttr, + Slice ipAddress) { + inet_pton(family, value.c_str(), ipAddress.base()); + return fillNlAttr(nlaType, (family == AF_INET) ? sizeof(in_addr) : sizeof(in6_addr), nlAttr); +} + +size_t fillNlAttrU32(__u16 nlaType, int32_t value, nlattr* nlAttr, uint32_t* u32Value) { + *u32Value = htonl(value); + return fillNlAttr(nlaType, sizeof((*u32Value)), nlAttr); +} + +// returns the address family, placing the string in the provided buffer +StatusOr<uint16_t> convertStringAddress(std::string addr, uint8_t* buffer) { + if (inet_pton(AF_INET, addr.c_str(), buffer) == 1) { + return AF_INET; + } else if (inet_pton(AF_INET6, addr.c_str(), buffer) == 1) { + return AF_INET6; + } else { + return Status(EAFNOSUPPORT); + } +} + // TODO: Need to consider a way to refer to the sSycalls instance inline Syscalls& getSyscallInstance() { return netdutils::sSyscalls.get(); } @@ -414,12 +444,11 @@ netdutils::Status XfrmController::ipSecAllocateSpi(int32_t transformId, netdutils::Status XfrmController::ipSecAddSecurityAssociation( int32_t transformId, int32_t mode, const std::string& sourceAddress, - 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, - const std::vector<uint8_t>& aeadKey, int32_t aeadIcvBits, int32_t encapType, - int32_t encapLocalPort, int32_t encapRemotePort) { + 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, const std::vector<uint8_t>& aeadKey, + int32_t aeadIcvBits, int32_t encapType, int32_t encapLocalPort, int32_t encapRemotePort) { ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__); ALOGD("transformId=%d", transformId); ALOGD("mode=%d", mode); @@ -687,8 +716,8 @@ netdutils::Status XfrmController::ipSecDeleteSecurityPolicy(int32_t transformId, const std::string& localAddress, const std::string& remoteAddress, int32_t markValue, int32_t markMask) { - return processSecurityPolicy(transformId, direction, localAddress, remoteAddress, 0, - markValue, markMask, XFRM_MSG_DELPOLICY); + return processSecurityPolicy(transformId, direction, localAddress, remoteAddress, 0, markValue, + markMask, XFRM_MSG_DELPOLICY); } netdutils::Status XfrmController::processSecurityPolicy(int32_t transformId, int32_t direction, @@ -725,8 +754,8 @@ netdutils::Status XfrmController::processSecurityPolicy(int32_t transformId, int void XfrmController::fillXfrmSelector(const XfrmSaInfo& record, xfrm_selector* selector) { selector->family = record.addrFamily; - selector->proto = AF_UNSPEC; // TODO: do we need to match the protocol? it's - // possible via the socket + selector->proto = AF_UNSPEC; // TODO: do we need to match the protocol? it's + // possible via the socket } netdutils::Status XfrmController::updateSecurityAssociation(const XfrmSaInfo& record, @@ -926,8 +955,8 @@ netdutils::Status XfrmController::deleteSecurityAssociation(const XfrmId& record {NULL, 0}, // reserved for the eventual addition of a NLMSG_HDR {&said, 0}, // main usersa_info struct {kPadBytes, 0}, // up to NLMSG_ALIGNTO pad bytes of padding - {&xfrmmark, 0}, // adjust size if xfrm mark 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 }; int len; @@ -1047,8 +1076,8 @@ netdutils::Status XfrmController::deleteTunnelModeSecurityPolicy(const XfrmSaInf {NULL, 0}, // reserved for the eventual addition of a NLMSG_HDR {&policyid, 0}, // main xfrm_userpolicy_id struct {kPadBytes, 0}, // up to NLMSG_ALIGNTO pad bytes of padding - {&xfrmmark, 0}, // adjust size if xfrm mark 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 }; int len = iov[USERPOLICYID].iov_len = fillUserPolicyId(record, direction, &policyid); @@ -1110,8 +1139,8 @@ int XfrmController::fillNlAttrXfrmMark(const XfrmId& record, nlattr_xfrm_mark* m return len; } -int XfrmController::fillNlAttrXfrmOutputMark( - const __u32 output_mark_value, nlattr_xfrm_output_mark* output_mark) { +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; @@ -1131,6 +1160,192 @@ int XfrmController::fillUserPolicyId(const XfrmSaInfo& record, XfrmDirection dir return sizeof(*usersp); } +int XfrmController::addVirtualTunnelInterface(const std::string& deviceName, + const std::string& localAddress, + const std::string& remoteAddress, int32_t ikey, + int32_t okey, bool isUpdate) { + ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__); + ALOGD("deviceName=%s", deviceName.c_str()); + ALOGD("localAddress=%s", localAddress.c_str()); + ALOGD("remoteAddress=%s", remoteAddress.c_str()); + ALOGD("ikey=%0.8x", ikey); + ALOGD("okey=%0.8x", okey); + ALOGD("isUpdate=%d", isUpdate); + + if (deviceName.empty() || localAddress.empty() || remoteAddress.empty()) { + return EINVAL; + } + + const char* INFO_KIND_VTI6 = "vti6"; + const char* INFO_KIND_VTI = "vti"; + uint8_t PADDING_BUFFER[] = {0, 0, 0, 0}; + + // Find address family. + uint8_t remAddr[sizeof(in6_addr)]; + + StatusOr<uint16_t> statusOrRemoteFam = convertStringAddress(remoteAddress, remAddr); + if (!isOk(statusOrRemoteFam)) { + return statusOrRemoteFam.status().code(); + } + + uint8_t locAddr[sizeof(in6_addr)]; + StatusOr<uint16_t> statusOrLocalFam = convertStringAddress(localAddress, locAddr); + if (!isOk(statusOrLocalFam)) { + return statusOrLocalFam.status().code(); + } + + if (statusOrLocalFam.value() != statusOrRemoteFam.value()) { + return EINVAL; + } + + uint16_t family = statusOrLocalFam.value(); + + ifinfomsg ifInfoMsg{}; + + // Construct IFLA_IFNAME + nlattr iflaIfName; + char iflaIfNameStrValue[deviceName.length() + 1]; + size_t iflaIfNameLength = + strlcpy(iflaIfNameStrValue, deviceName.c_str(), sizeof(iflaIfNameStrValue)); + size_t iflaIfNamePad = fillNlAttr(IFLA_IFNAME, iflaIfNameLength, &iflaIfName); + + // Construct IFLA_INFO_KIND + // Constants "vti6" and "vti" enable the kernel to call different code paths, + // (ip_tunnel.c, ip6_tunnel), based on the family. + const std::string infoKindValue = (family == AF_INET6) ? INFO_KIND_VTI6 : INFO_KIND_VTI; + nlattr iflaIfInfoKind; + char infoKindValueStrValue[infoKindValue.length() + 1]; + size_t iflaIfInfoKindLength = + strlcpy(infoKindValueStrValue, infoKindValue.c_str(), sizeof(infoKindValueStrValue)); + size_t iflaIfInfoKindPad = fillNlAttr(IFLA_INFO_KIND, iflaIfInfoKindLength, &iflaIfInfoKind); + + // Construct IFLA_VTI_LOCAL + nlattr iflaVtiLocal; + uint8_t binaryLocalAddress[sizeof(in6_addr)]; + size_t iflaVtiLocalPad = + fillNlAttrIpAddress(IFLA_VTI_LOCAL, family, localAddress, &iflaVtiLocal, + netdutils::makeSlice(binaryLocalAddress)); + + // Construct IFLA_VTI_REMOTE + nlattr iflaVtiRemote; + uint8_t binaryRemoteAddress[sizeof(in6_addr)]; + size_t iflaVtiRemotePad = + fillNlAttrIpAddress(IFLA_VTI_REMOTE, family, remoteAddress, &iflaVtiRemote, + netdutils::makeSlice(binaryRemoteAddress)); + + // Construct IFLA_VTI_OKEY + nlattr iflaVtiIKey; + uint32_t iKeyValue; + size_t iflaVtiIKeyPad = fillNlAttrU32(IFLA_VTI_IKEY, ikey, &iflaVtiIKey, &iKeyValue); + + // Construct IFLA_VTI_IKEY + nlattr iflaVtiOKey; + uint32_t oKeyValue; + size_t iflaVtiOKeyPad = fillNlAttrU32(IFLA_VTI_OKEY, okey, &iflaVtiOKey, &oKeyValue); + + int iflaInfoDataPayloadLength = iflaVtiLocal.nla_len + iflaVtiLocalPad + iflaVtiRemote.nla_len + + iflaVtiRemotePad + iflaVtiIKey.nla_len + iflaVtiIKeyPad + + iflaVtiOKey.nla_len + iflaVtiOKeyPad; + + // Construct IFLA_INFO_DATA + nlattr iflaInfoData; + size_t iflaInfoDataPad = fillNlAttr(IFLA_INFO_DATA, iflaInfoDataPayloadLength, &iflaInfoData); + + // Construct IFLA_LINKINFO + nlattr iflaLinkInfo; + size_t iflaLinkInfoPad = fillNlAttr(IFLA_LINKINFO, + iflaInfoData.nla_len + iflaInfoDataPad + + iflaIfInfoKind.nla_len + iflaIfInfoKindPad, + &iflaLinkInfo); + + iovec iov[] = { + {NULL, 0}, + {&ifInfoMsg, sizeof(ifInfoMsg)}, + + {&iflaIfName, sizeof(iflaIfName)}, + {iflaIfNameStrValue, iflaIfNameLength}, + {&PADDING_BUFFER, iflaIfNamePad}, + + {&iflaLinkInfo, sizeof(iflaLinkInfo)}, + + {&iflaIfInfoKind, sizeof(iflaIfInfoKind)}, + {infoKindValueStrValue, iflaIfInfoKindLength}, + {&PADDING_BUFFER, iflaIfInfoKindPad}, + + {&iflaInfoData, sizeof(iflaInfoData)}, + + {&iflaVtiLocal, sizeof(iflaVtiLocal)}, + {&binaryLocalAddress, (family == AF_INET) ? sizeof(in_addr) : sizeof(in6_addr)}, + {&PADDING_BUFFER, iflaVtiLocalPad}, + + {&iflaVtiRemote, sizeof(iflaVtiRemote)}, + {&binaryRemoteAddress, (family == AF_INET) ? sizeof(in_addr) : sizeof(in6_addr)}, + {&PADDING_BUFFER, iflaVtiRemotePad}, + + {&iflaVtiIKey, sizeof(iflaVtiIKey)}, + {&iKeyValue, sizeof(iKeyValue)}, + {&PADDING_BUFFER, iflaVtiIKeyPad}, + + {&iflaVtiOKey, sizeof(iflaVtiOKey)}, + {&oKeyValue, sizeof(oKeyValue)}, + {&PADDING_BUFFER, iflaVtiOKeyPad}, + + {&PADDING_BUFFER, iflaInfoDataPad}, + + {&PADDING_BUFFER, iflaLinkInfoPad}, + }; + + uint16_t action = RTM_NEWLINK; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + + if (!isUpdate) { + flags |= NLM_F_EXCL | NLM_F_CREATE; + } + + int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr); + if (ret) { + ALOGE("Error in %s virtual tunnel interface. Error Code: %d", + isUpdate ? "updating" : "adding", ret); + } + return ret; +} + +int XfrmController::removeVirtualTunnelInterface(const std::string& deviceName) { + ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__); + ALOGD("deviceName=%s", deviceName.c_str()); + + if (deviceName.empty()) { + return EINVAL; + } + + uint8_t PADDING_BUFFER[] = {0, 0, 0, 0}; + + ifinfomsg ifInfoMsg{}; + nlattr iflaIfName; + char iflaIfNameStrValue[deviceName.length() + 1]; + size_t iflaIfNameLength = + strlcpy(iflaIfNameStrValue, deviceName.c_str(), sizeof(iflaIfNameStrValue)); + size_t iflaIfNamePad = fillNlAttr(IFLA_IFNAME, iflaIfNameLength, &iflaIfName); + + iovec iov[] = { + {NULL, 0}, + {&ifInfoMsg, sizeof(ifInfoMsg)}, + + {&iflaIfName, sizeof(iflaIfName)}, + {iflaIfNameStrValue, iflaIfNameLength}, + {&PADDING_BUFFER, iflaIfNamePad}, + }; + + uint16_t action = RTM_DELLINK; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + + int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr); + if (ret) { + ALOGE("Error in removing virtual tunnel interface %s. Error Code: %d", iflaIfNameStrValue, + ret); + } + return ret; +} } // namespace net } // namespace android |
