12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634 |
- /*
- *
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <random>
- #include <string>
- #include <vector>
- #include <ctype.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <getopt.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define __STDC_FORMAT_MACROS
- #include <inttypes.h>
- #include <arpa/inet.h>
- #include <net/if.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <linux/in.h>
- #include <linux/ipsec.h>
- #include <linux/netlink.h>
- #include <linux/xfrm.h>
- #define LOG_TAG "XfrmController"
- #include <android-base/properties.h>
- #include <android-base/stringprintf.h>
- #include <android-base/strings.h>
- #include <android-base/unique_fd.h>
- #include <android/net/INetd.h>
- #include <cutils/properties.h>
- #include <log/log.h>
- #include <log/log_properties.h>
- #include <logwrap/logwrap.h>
- #include "Fwmark.h"
- #include "InterfaceController.h"
- #include "NetdConstants.h"
- #include "NetlinkCommands.h"
- #include "Permission.h"
- #include "XfrmController.h"
- #include "android-base/stringprintf.h"
- #include "android-base/strings.h"
- #include "android-base/unique_fd.h"
- #include "netdutils/DumpWriter.h"
- #include "netdutils/Fd.h"
- #include "netdutils/Slice.h"
- #include "netdutils/Syscalls.h"
- using android::net::INetd;
- using android::netdutils::DumpWriter;
- using android::netdutils::Fd;
- using android::netdutils::ScopedIndent;
- using android::netdutils::Slice;
- using android::netdutils::Status;
- using android::netdutils::StatusOr;
- using android::netdutils::Syscalls;
- namespace android {
- namespace net {
- // Exposed for testing
- constexpr uint32_t ALGO_MASK_AUTH_ALL = ~0;
- // Exposed for testing
- constexpr uint32_t ALGO_MASK_CRYPT_ALL = ~0;
- // Exposed for testing
- constexpr uint32_t ALGO_MASK_AEAD_ALL = ~0;
- // Exposed for testing
- constexpr uint8_t REPLAY_WINDOW_SIZE = 4;
- namespace {
- constexpr uint32_t RAND_SPI_MIN = 256;
- constexpr uint32_t RAND_SPI_MAX = 0xFFFFFFFE;
- constexpr uint32_t INVALID_SPI = 0;
- constexpr const char* INFO_KIND_VTI = "vti";
- constexpr const char* INFO_KIND_VTI6 = "vti6";
- constexpr const char* INFO_KIND_XFRMI = "xfrm";
- constexpr int INFO_KIND_MAX_LEN = 8;
- constexpr int LOOPBACK_IFINDEX = 1;
- bool mIsXfrmIntfSupported = false;
- static inline bool isEngBuild() {
- static const std::string sBuildType = android::base::GetProperty("ro.build.type", "user");
- return sBuildType == "eng";
- }
- #define XFRM_MSG_TRANS(x) \
- case x: \
- return #x;
- const char* xfrmMsgTypeToString(uint16_t msg) {
- switch (msg) {
- XFRM_MSG_TRANS(XFRM_MSG_NEWSA)
- XFRM_MSG_TRANS(XFRM_MSG_DELSA)
- XFRM_MSG_TRANS(XFRM_MSG_GETSA)
- XFRM_MSG_TRANS(XFRM_MSG_NEWPOLICY)
- XFRM_MSG_TRANS(XFRM_MSG_DELPOLICY)
- XFRM_MSG_TRANS(XFRM_MSG_GETPOLICY)
- XFRM_MSG_TRANS(XFRM_MSG_ALLOCSPI)
- XFRM_MSG_TRANS(XFRM_MSG_ACQUIRE)
- XFRM_MSG_TRANS(XFRM_MSG_EXPIRE)
- XFRM_MSG_TRANS(XFRM_MSG_UPDPOLICY)
- XFRM_MSG_TRANS(XFRM_MSG_UPDSA)
- XFRM_MSG_TRANS(XFRM_MSG_POLEXPIRE)
- XFRM_MSG_TRANS(XFRM_MSG_FLUSHSA)
- XFRM_MSG_TRANS(XFRM_MSG_FLUSHPOLICY)
- XFRM_MSG_TRANS(XFRM_MSG_NEWAE)
- XFRM_MSG_TRANS(XFRM_MSG_GETAE)
- XFRM_MSG_TRANS(XFRM_MSG_REPORT)
- XFRM_MSG_TRANS(XFRM_MSG_MIGRATE)
- XFRM_MSG_TRANS(XFRM_MSG_NEWSADINFO)
- XFRM_MSG_TRANS(XFRM_MSG_GETSADINFO)
- XFRM_MSG_TRANS(XFRM_MSG_GETSPDINFO)
- XFRM_MSG_TRANS(XFRM_MSG_NEWSPDINFO)
- XFRM_MSG_TRANS(XFRM_MSG_MAPPING)
- default:
- return "XFRM_MSG UNKNOWN";
- }
- }
- // actually const but cannot be declared as such for reasons
- uint8_t kPadBytesArray[] = {0, 0, 0};
- void* kPadBytes = static_cast<void*>(kPadBytesArray);
- #define LOG_HEX(__desc16__, __buf__, __len__) \
- do { \
- if (isEngBuild()) { \
- logHex(__desc16__, __buf__, __len__); \
- } \
- } while (0)
- #define LOG_IOV(__iov__) \
- do { \
- if (isEngBuild()) { \
- logIov(__iov__); \
- } \
- } while (0)
- void logHex(const char* desc16, const char* buf, size_t len) {
- char* printBuf = new char[len * 2 + 1 + 26]; // len->ascii, +newline, +prefix strlen
- int offset = 0;
- if (desc16) {
- sprintf(printBuf, "{%-16s}", desc16);
- offset += 18; // prefix string length
- }
- sprintf(printBuf + offset, "[%4.4u]: ", (len > 9999) ? 9999 : (unsigned)len);
- offset += 8;
- for (uint32_t j = 0; j < (uint32_t)len; j++) {
- sprintf(&printBuf[j * 2 + offset], "%0.2x", (unsigned char)buf[j]);
- }
- ALOGD("%s", printBuf);
- delete[] printBuf;
- }
- void logIov(const std::vector<iovec>& iov) {
- for (const iovec& row : iov) {
- logHex(nullptr, reinterpret_cast<char*>(row.iov_base), row.iov_len);
- }
- }
- 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, uint32_t value, XfrmController::nlattr_payload_u32* nlAttr) {
- nlAttr->value = value;
- return fillNlAttr(nlaType, sizeof(value), &nlAttr->hdr);
- }
- // returns the address family, placing the string in the provided buffer
- StatusOr<uint16_t> convertStringAddress(const 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(); }
- class XfrmSocketImpl : public XfrmSocket {
- private:
- static constexpr int NLMSG_DEFAULTSIZE = 8192;
- union NetlinkResponse {
- nlmsghdr hdr;
- struct _err_ {
- nlmsghdr hdr;
- nlmsgerr err;
- } err;
- struct _buf_ {
- nlmsghdr hdr;
- char buf[NLMSG_DEFAULTSIZE];
- } buf;
- };
- public:
- netdutils::Status open() override {
- mSock = openNetlinkSocket(NETLINK_XFRM);
- if (mSock < 0) {
- ALOGW("Could not get a new socket, line=%d", __LINE__);
- return netdutils::statusFromErrno(-mSock, "Could not open netlink socket");
- }
- return netdutils::status::ok;
- }
- static netdutils::Status validateResponse(NetlinkResponse response, size_t len) {
- if (len < sizeof(nlmsghdr)) {
- ALOGW("Invalid response message received over netlink");
- return netdutils::statusFromErrno(EBADMSG, "Invalid message");
- }
- switch (response.hdr.nlmsg_type) {
- case NLMSG_NOOP:
- case NLMSG_DONE:
- return netdutils::status::ok;
- case NLMSG_OVERRUN:
- ALOGD("Netlink request overran kernel buffer");
- return netdutils::statusFromErrno(EBADMSG, "Kernel buffer overrun");
- case NLMSG_ERROR:
- if (len < sizeof(NetlinkResponse::_err_)) {
- ALOGD("Netlink message received malformed error response");
- return netdutils::statusFromErrno(EBADMSG, "Malformed error response");
- }
- return netdutils::statusFromErrno(
- -response.err.err.error,
- "Error netlink message"); // Netlink errors are negative errno.
- case XFRM_MSG_NEWSA:
- break;
- }
- if (response.hdr.nlmsg_type < XFRM_MSG_BASE /*== NLMSG_MIN_TYPE*/ ||
- response.hdr.nlmsg_type > XFRM_MSG_MAX) {
- ALOGD("Netlink message responded with an out-of-range message ID");
- return netdutils::statusFromErrno(EBADMSG, "Invalid message ID");
- }
- // TODO Add more message validation here
- return netdutils::status::ok;
- }
- netdutils::Status sendMessage(uint16_t nlMsgType, uint16_t nlMsgFlags, uint16_t nlMsgSeqNum,
- std::vector<iovec>* iovecs) const override {
- nlmsghdr nlMsg = {
- .nlmsg_type = nlMsgType,
- .nlmsg_flags = nlMsgFlags,
- .nlmsg_seq = nlMsgSeqNum,
- };
- (*iovecs)[0].iov_base = &nlMsg;
- (*iovecs)[0].iov_len = NLMSG_HDRLEN;
- for (const iovec& iov : *iovecs) {
- nlMsg.nlmsg_len += iov.iov_len;
- }
- ALOGD("Sending Netlink XFRM Message: %s", xfrmMsgTypeToString(nlMsgType));
- LOG_IOV(*iovecs);
- StatusOr<size_t> writeResult = getSyscallInstance().writev(mSock, *iovecs);
- if (!isOk(writeResult)) {
- ALOGE("netlink socket writev failed (%s)", toString(writeResult).c_str());
- return writeResult;
- }
- if (nlMsg.nlmsg_len != writeResult.value()) {
- ALOGE("Invalid netlink message length sent %d", static_cast<int>(writeResult.value()));
- return netdutils::statusFromErrno(EBADMSG, "Invalid message length");
- }
- NetlinkResponse response = {};
- StatusOr<Slice> readResult =
- getSyscallInstance().read(Fd(mSock), netdutils::makeSlice(response));
- if (!isOk(readResult)) {
- ALOGE("netlink response error (%s)", toString(readResult).c_str());
- return readResult;
- }
- LOG_HEX("netlink msg resp", reinterpret_cast<char*>(readResult.value().base()),
- readResult.value().size());
- Status validateStatus = validateResponse(response, readResult.value().size());
- if (!isOk(validateStatus)) {
- ALOGE("netlink response contains error (%s)", toString(validateStatus).c_str());
- }
- return validateStatus;
- }
- };
- StatusOr<int> convertToXfrmAddr(const std::string& strAddr, xfrm_address_t* xfrmAddr) {
- if (strAddr.length() == 0) {
- memset(xfrmAddr, 0, sizeof(*xfrmAddr));
- return AF_UNSPEC;
- }
- if (inet_pton(AF_INET6, strAddr.c_str(), reinterpret_cast<void*>(xfrmAddr))) {
- return AF_INET6;
- } else if (inet_pton(AF_INET, strAddr.c_str(), reinterpret_cast<void*>(xfrmAddr))) {
- return AF_INET;
- } else {
- return netdutils::statusFromErrno(EAFNOSUPPORT, "Invalid address family");
- }
- }
- void fillXfrmNlaHdr(nlattr* hdr, uint16_t type, uint16_t len) {
- hdr->nla_type = type;
- hdr->nla_len = len;
- }
- void fillXfrmCurLifetimeDefaults(xfrm_lifetime_cur* cur) {
- memset(reinterpret_cast<char*>(cur), 0, sizeof(*cur));
- }
- void fillXfrmLifetimeDefaults(xfrm_lifetime_cfg* cfg) {
- cfg->soft_byte_limit = XFRM_INF;
- cfg->hard_byte_limit = XFRM_INF;
- cfg->soft_packet_limit = XFRM_INF;
- cfg->hard_packet_limit = XFRM_INF;
- }
- /*
- * Allocate SPIs within an (inclusive) range of min-max.
- * returns 0 (INVALID_SPI) once the entire range has been parsed.
- */
- class RandomSpi {
- public:
- RandomSpi(int min, int max) : mMin(min) {
- // Re-seeding should be safe because the seed itself is
- // sufficiently random and we don't need secure random
- std::mt19937 rnd = std::mt19937(std::random_device()());
- mNext = std::uniform_int_distribution<>(1, INT_MAX)(rnd);
- mSize = max - min + 1;
- mCount = mSize;
- }
- uint32_t next() {
- if (!mCount)
- return 0;
- mCount--;
- return (mNext++ % mSize) + mMin;
- }
- private:
- uint32_t mNext;
- uint32_t mSize;
- uint32_t mMin;
- uint32_t mCount;
- };
- } // namespace
- //
- // Begin XfrmController Impl
- //
- //
- XfrmController::XfrmController(void) {}
- // Test-only constructor allowing override of XFRM Interface support checks
- XfrmController::XfrmController(bool xfrmIntfSupport) {
- mIsXfrmIntfSupported = xfrmIntfSupport;
- }
- netdutils::Status XfrmController::Init() {
- RETURN_IF_NOT_OK(flushInterfaces());
- mIsXfrmIntfSupported = isXfrmIntfSupported();
- XfrmSocketImpl sock;
- RETURN_IF_NOT_OK(sock.open());
- RETURN_IF_NOT_OK(flushSaDb(sock));
- return flushPolicyDb(sock);
- }
- netdutils::Status XfrmController::flushInterfaces() {
- const auto& ifaces = InterfaceController::getIfaceNames();
- RETURN_IF_NOT_OK(ifaces);
- const String8 ifPrefix8 = String8(INetd::IPSEC_INTERFACE_PREFIX().string());
- for (const std::string& iface : ifaces.value()) {
- netdutils::Status status;
- // Look for the reserved interface prefix, which must be in the name at position 0
- if (android::base::StartsWith(iface.c_str(), ifPrefix8.c_str())) {
- RETURN_IF_NOT_OK(ipSecRemoveTunnelInterface(iface));
- }
- }
- return netdutils::status::ok;
- }
- netdutils::Status XfrmController::flushSaDb(const XfrmSocket& s) {
- struct xfrm_usersa_flush flushUserSa = {.proto = IPSEC_PROTO_ANY};
- std::vector<iovec> iov = {{nullptr, 0}, // reserved for the eventual addition of a NLMSG_HDR
- {&flushUserSa, sizeof(flushUserSa)}, // xfrm_usersa_flush structure
- {kPadBytes, NLMSG_ALIGN(sizeof(flushUserSa)) - sizeof(flushUserSa)}};
- return s.sendMessage(XFRM_MSG_FLUSHSA, NETLINK_REQUEST_FLAGS, 0, &iov);
- }
- netdutils::Status XfrmController::flushPolicyDb(const XfrmSocket& s) {
- std::vector<iovec> iov = {{nullptr, 0}}; // reserved for the eventual addition of a NLMSG_HDR
- return s.sendMessage(XFRM_MSG_FLUSHPOLICY, NETLINK_REQUEST_FLAGS, 0, &iov);
- }
- bool XfrmController::isXfrmIntfSupported() {
- const char* IPSEC_TEST_INTF_NAME = "ipsec_test";
- const int32_t XFRM_TEST_IF_ID = 0xFFFF;
- bool errored = false;
- errored |=
- ipSecAddXfrmInterface(IPSEC_TEST_INTF_NAME, XFRM_TEST_IF_ID, NETLINK_ROUTE_CREATE_FLAGS)
- .code();
- errored |= ipSecRemoveTunnelInterface(IPSEC_TEST_INTF_NAME).code();
- return !errored;
- }
- netdutils::Status XfrmController::ipSecSetEncapSocketOwner(int socketFd, int newUid,
- uid_t callerUid) {
- ALOGD("XfrmController:%s, line=%d", __FUNCTION__, __LINE__);
- const int fd = socketFd;
- struct stat info;
- if (fstat(fd, &info)) {
- return netdutils::statusFromErrno(errno, "Failed to stat socket file descriptor");
- }
- if (info.st_uid != callerUid) {
- return netdutils::statusFromErrno(EPERM, "fchown disabled for non-owner calls");
- }
- if (S_ISSOCK(info.st_mode) == 0) {
- return netdutils::statusFromErrno(EINVAL, "File descriptor was not a socket");
- }
- int optval;
- socklen_t optlen = sizeof(optval);
- netdutils::Status status =
- getSyscallInstance().getsockopt(Fd(fd), IPPROTO_UDP, UDP_ENCAP, &optval, &optlen);
- if (status != netdutils::status::ok) {
- return status;
- }
- if (optval != UDP_ENCAP_ESPINUDP && optval != UDP_ENCAP_ESPINUDP_NON_IKE) {
- return netdutils::statusFromErrno(EINVAL, "Socket did not have UDP-encap sockopt set");
- }
- if (fchown(fd, newUid, -1)) {
- return netdutils::statusFromErrno(errno, "Failed to fchown socket file descriptor");
- }
- return netdutils::status::ok;
- }
- netdutils::Status XfrmController::ipSecAllocateSpi(int32_t transformId,
- const std::string& sourceAddress,
- const std::string& destinationAddress,
- int32_t inSpi, int32_t* outSpi) {
- ALOGD("XfrmController:%s, line=%d", __FUNCTION__, __LINE__);
- ALOGD("transformId=%d", transformId);
- ALOGD("sourceAddress=%s", sourceAddress.c_str());
- ALOGD("destinationAddress=%s", destinationAddress.c_str());
- ALOGD("inSpi=%0.8x", inSpi);
- XfrmSaInfo saInfo{};
- netdutils::Status ret = fillXfrmCommonInfo(sourceAddress, destinationAddress, INVALID_SPI, 0, 0,
- transformId, 0, &saInfo);
- if (!isOk(ret)) {
- return ret;
- }
- XfrmSocketImpl sock;
- netdutils::Status socketStatus = sock.open();
- if (!isOk(socketStatus)) {
- ALOGD("Sock open failed for XFRM, line=%d", __LINE__);
- return socketStatus;
- }
- int minSpi = RAND_SPI_MIN, maxSpi = RAND_SPI_MAX;
- if (inSpi)
- minSpi = maxSpi = inSpi;
- ret = allocateSpi(saInfo, minSpi, maxSpi, reinterpret_cast<uint32_t*>(outSpi), sock);
- if (!isOk(ret)) {
- // TODO: May want to return a new Status with a modified status string
- ALOGD("Failed to Allocate an SPI, line=%d", __LINE__);
- *outSpi = INVALID_SPI;
- }
- return ret;
- }
- 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, int32_t xfrmInterfaceId) {
- ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
- ALOGD("transformId=%d", transformId);
- ALOGD("mode=%d", mode);
- ALOGD("sourceAddress=%s", sourceAddress.c_str());
- ALOGD("destinationAddress=%s", destinationAddress.c_str());
- ALOGD("underlyingNetworkId=%d", underlyingNetId);
- ALOGD("spi=%0.8x", spi);
- ALOGD("markValue=%x", markValue);
- ALOGD("markMask=%x", markMask);
- ALOGD("authAlgo=%s", authAlgo.c_str());
- ALOGD("authTruncBits=%d", authTruncBits);
- ALOGD("cryptAlgo=%s", cryptAlgo.c_str());
- ALOGD("cryptTruncBits=%d,", cryptTruncBits);
- ALOGD("aeadAlgo=%s", aeadAlgo.c_str());
- ALOGD("aeadIcvBits=%d,", aeadIcvBits);
- ALOGD("encapType=%d", encapType);
- ALOGD("encapLocalPort=%d", encapLocalPort);
- ALOGD("encapRemotePort=%d", encapRemotePort);
- ALOGD("xfrmInterfaceId=%d", xfrmInterfaceId);
- XfrmSaInfo saInfo{};
- netdutils::Status ret = fillXfrmCommonInfo(sourceAddress, destinationAddress, spi, markValue,
- markMask, transformId, xfrmInterfaceId, &saInfo);
- if (!isOk(ret)) {
- return ret;
- }
- saInfo.auth = XfrmAlgo{
- .name = authAlgo, .key = authKey, .truncLenBits = static_cast<uint16_t>(authTruncBits)};
- saInfo.crypt = XfrmAlgo{
- .name = cryptAlgo, .key = cryptKey, .truncLenBits = static_cast<uint16_t>(cryptTruncBits)};
- saInfo.aead = XfrmAlgo{
- .name = aeadAlgo, .key = aeadKey, .truncLenBits = static_cast<uint16_t>(aeadIcvBits)};
- switch (static_cast<XfrmMode>(mode)) {
- case XfrmMode::TRANSPORT:
- case XfrmMode::TUNNEL:
- saInfo.mode = static_cast<XfrmMode>(mode);
- break;
- default:
- return netdutils::statusFromErrno(EINVAL, "Invalid xfrm mode");
- }
- XfrmSocketImpl sock;
- netdutils::Status socketStatus = sock.open();
- if (!isOk(socketStatus)) {
- ALOGD("Sock open failed for XFRM, line=%d", __LINE__);
- return socketStatus;
- }
- switch (static_cast<XfrmEncapType>(encapType)) {
- case XfrmEncapType::ESPINUDP:
- case XfrmEncapType::ESPINUDP_NON_IKE:
- if (saInfo.addrFamily != AF_INET) {
- return netdutils::statusFromErrno(EAFNOSUPPORT, "IPv6 encap not supported");
- }
- // The ports are not used on input SAs, so this is OK to be wrong when
- // direction is ultimately input.
- saInfo.encap.srcPort = encapLocalPort;
- saInfo.encap.dstPort = encapRemotePort;
- [[fallthrough]];
- case XfrmEncapType::NONE:
- saInfo.encap.type = static_cast<XfrmEncapType>(encapType);
- break;
- default:
- 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__);
- }
- return ret;
- }
- netdutils::Status XfrmController::ipSecDeleteSecurityAssociation(
- int32_t transformId, const std::string& sourceAddress,
- const std::string& destinationAddress, int32_t spi, int32_t markValue, int32_t markMask,
- int32_t xfrmInterfaceId) {
- ALOGD("XfrmController:%s, line=%d", __FUNCTION__, __LINE__);
- ALOGD("transformId=%d", transformId);
- ALOGD("sourceAddress=%s", sourceAddress.c_str());
- ALOGD("destinationAddress=%s", destinationAddress.c_str());
- ALOGD("spi=%0.8x", spi);
- ALOGD("markValue=%x", markValue);
- ALOGD("markMask=%x", markMask);
- ALOGD("xfrmInterfaceId=%d", xfrmInterfaceId);
- XfrmSaInfo saInfo{};
- netdutils::Status ret = fillXfrmCommonInfo(sourceAddress, destinationAddress, spi, markValue,
- markMask, transformId, xfrmInterfaceId, &saInfo);
- if (!isOk(ret)) {
- return ret;
- }
- XfrmSocketImpl sock;
- netdutils::Status socketStatus = sock.open();
- if (!isOk(socketStatus)) {
- ALOGD("Sock open failed for XFRM, line=%d", __LINE__);
- return socketStatus;
- }
- ret = deleteSecurityAssociation(saInfo, sock);
- if (!isOk(ret)) {
- ALOGD("Failed to delete Security Association, line=%d", __LINE__);
- }
- return ret;
- }
- netdutils::Status XfrmController::fillXfrmCommonInfo(const std::string& sourceAddress,
- const std::string& destinationAddress,
- int32_t spi, int32_t markValue,
- int32_t markMask, int32_t transformId,
- int32_t xfrmInterfaceId,
- XfrmCommonInfo* info) {
- // Use the addresses to determine the address family and do validation
- xfrm_address_t sourceXfrmAddr{}, destXfrmAddr{};
- StatusOr<int> sourceFamily, destFamily;
- sourceFamily = convertToXfrmAddr(sourceAddress, &sourceXfrmAddr);
- destFamily = convertToXfrmAddr(destinationAddress, &destXfrmAddr);
- if (!isOk(sourceFamily) || !isOk(destFamily)) {
- return netdutils::statusFromErrno(EINVAL, "Invalid address " + sourceAddress + "/" +
- destinationAddress);
- }
- if (destFamily.value() == AF_UNSPEC ||
- (sourceFamily.value() != AF_UNSPEC && sourceFamily.value() != destFamily.value())) {
- ALOGD("Invalid or Mismatched Address Families, %d != %d, line=%d", sourceFamily.value(),
- destFamily.value(), __LINE__);
- return netdutils::statusFromErrno(EINVAL, "Invalid or mismatched address families");
- }
- info->addrFamily = destFamily.value();
- info->dstAddr = destXfrmAddr;
- info->srcAddr = sourceXfrmAddr;
- return fillXfrmCommonInfo(spi, markValue, markMask, transformId, xfrmInterfaceId, info);
- }
- netdutils::Status XfrmController::fillXfrmCommonInfo(int32_t spi, int32_t markValue,
- int32_t markMask, int32_t transformId,
- int32_t xfrmInterfaceId,
- XfrmCommonInfo* info) {
- info->transformId = transformId;
- info->spi = htonl(spi);
- if (mIsXfrmIntfSupported) {
- info->xfrm_if_id = xfrmInterfaceId;
- } else {
- info->mark.v = markValue;
- info->mark.m = markMask;
- }
- return netdutils::status::ok;
- }
- netdutils::Status XfrmController::ipSecApplyTransportModeTransform(
- int socketFd, int32_t transformId, int32_t direction, const std::string& sourceAddress,
- const std::string& destinationAddress, int32_t spi) {
- ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
- ALOGD("transformId=%d", transformId);
- ALOGD("direction=%d", direction);
- ALOGD("sourceAddress=%s", sourceAddress.c_str());
- ALOGD("destinationAddress=%s", destinationAddress.c_str());
- ALOGD("spi=%0.8x", spi);
- StatusOr<sockaddr_storage> ret =
- getSyscallInstance().getsockname<sockaddr_storage>(Fd(socketFd));
- if (!isOk(ret)) {
- ALOGE("Failed to get socket info in %s", __FUNCTION__);
- return ret;
- }
- struct sockaddr_storage saddr = ret.value();
- XfrmSpInfo spInfo{};
- netdutils::Status status = fillXfrmCommonInfo(sourceAddress, destinationAddress, spi, 0, 0,
- transformId, 0, &spInfo);
- if (!isOk(status)) {
- ALOGE("Couldn't build SA ID %s", __FUNCTION__);
- return status;
- }
- spInfo.selAddrFamily = spInfo.addrFamily;
- // Allow dual stack sockets. Dual stack sockets are guaranteed to never have an AF_INET source
- // address; the source address would instead be an IPv4-mapped address. Thus, disallow AF_INET
- // sockets with mismatched address families (All other cases are acceptable).
- if (saddr.ss_family == AF_INET && spInfo.addrFamily != AF_INET) {
- ALOGE("IPV4 socket address family(%d) should match IPV4 Transform "
- "address family(%d)!",
- saddr.ss_family, spInfo.addrFamily);
- return netdutils::statusFromErrno(EINVAL, "Mismatched address family");
- }
- struct {
- xfrm_userpolicy_info info;
- xfrm_user_tmpl tmpl;
- } policy{};
- fillUserSpInfo(spInfo, static_cast<XfrmDirection>(direction), &policy.info);
- fillUserTemplate(spInfo, &policy.tmpl);
- LOG_HEX("XfrmUserPolicy", reinterpret_cast<char*>(&policy), sizeof(policy));
- int sockOpt, sockLayer;
- switch (saddr.ss_family) {
- case AF_INET:
- sockOpt = IP_XFRM_POLICY;
- sockLayer = SOL_IP;
- break;
- case AF_INET6:
- sockOpt = IPV6_XFRM_POLICY;
- sockLayer = SOL_IPV6;
- break;
- default:
- return netdutils::statusFromErrno(EAFNOSUPPORT, "Invalid address family");
- }
- status = getSyscallInstance().setsockopt(Fd(socketFd), sockLayer, sockOpt, policy);
- if (!isOk(status)) {
- ALOGE("Error setting socket option for XFRM! (%s)", toString(status).c_str());
- }
- return status;
- }
- netdutils::Status XfrmController::ipSecRemoveTransportModeTransform(int socketFd) {
- ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
- StatusOr<sockaddr_storage> ret =
- getSyscallInstance().getsockname<sockaddr_storage>(Fd(socketFd));
- if (!isOk(ret)) {
- ALOGE("Failed to get socket info in %s! (%s)", __FUNCTION__, toString(ret).c_str());
- return ret;
- }
- int sockOpt, sockLayer;
- switch (ret.value().ss_family) {
- case AF_INET:
- sockOpt = IP_XFRM_POLICY;
- sockLayer = SOL_IP;
- break;
- case AF_INET6:
- sockOpt = IPV6_XFRM_POLICY;
- sockLayer = SOL_IPV6;
- break;
- default:
- return netdutils::statusFromErrno(EAFNOSUPPORT, "Invalid address family");
- }
- // Kernel will delete the security policy on this socket for both direction
- // if optval is set to NULL and optlen is set to 0.
- netdutils::Status status =
- getSyscallInstance().setsockopt(Fd(socketFd), sockLayer, sockOpt, nullptr, 0);
- if (!isOk(status)) {
- ALOGE("Error removing socket option for XFRM! (%s)", toString(status).c_str());
- }
- return status;
- }
- netdutils::Status XfrmController::ipSecAddSecurityPolicy(
- int32_t transformId, int32_t selAddrFamily, int32_t direction,
- const std::string& tmplSrcAddress, const std::string& tmplDstAddress, int32_t spi,
- int32_t markValue, int32_t markMask, int32_t xfrmInterfaceId) {
- return processSecurityPolicy(transformId, selAddrFamily, direction, tmplSrcAddress,
- tmplDstAddress, spi, markValue, markMask, xfrmInterfaceId,
- XFRM_MSG_NEWPOLICY);
- }
- netdutils::Status XfrmController::ipSecUpdateSecurityPolicy(
- int32_t transformId, int32_t selAddrFamily, int32_t direction,
- const std::string& tmplSrcAddress, const std::string& tmplDstAddress, int32_t spi,
- int32_t markValue, int32_t markMask, int32_t xfrmInterfaceId) {
- return processSecurityPolicy(transformId, selAddrFamily, direction, tmplSrcAddress,
- tmplDstAddress, spi, markValue, markMask, xfrmInterfaceId,
- XFRM_MSG_UPDPOLICY);
- }
- netdutils::Status XfrmController::ipSecDeleteSecurityPolicy(int32_t transformId,
- int32_t selAddrFamily,
- int32_t direction, int32_t markValue,
- int32_t markMask,
- int32_t xfrmInterfaceId) {
- return processSecurityPolicy(transformId, selAddrFamily, direction, "", "", 0, markValue,
- markMask, xfrmInterfaceId, XFRM_MSG_DELPOLICY);
- }
- netdutils::Status XfrmController::processSecurityPolicy(
- int32_t transformId, int32_t selAddrFamily, int32_t direction,
- const std::string& tmplSrcAddress, const std::string& tmplDstAddress, int32_t spi,
- int32_t markValue, int32_t markMask, int32_t xfrmInterfaceId, int32_t msgType) {
- ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
- ALOGD("selAddrFamily=%s", selAddrFamily == AF_INET6 ? "AF_INET6" : "AF_INET");
- ALOGD("transformId=%d", transformId);
- ALOGD("direction=%d", direction);
- ALOGD("tmplSrcAddress=%s", tmplSrcAddress.c_str());
- ALOGD("tmplDstAddress=%s", tmplDstAddress.c_str());
- ALOGD("spi=%0.8x", spi);
- ALOGD("markValue=%d", markValue);
- ALOGD("markMask=%d", markMask);
- ALOGD("msgType=%d", msgType);
- ALOGD("xfrmInterfaceId=%d", xfrmInterfaceId);
- XfrmSpInfo spInfo{};
- spInfo.mode = XfrmMode::TUNNEL;
- XfrmSocketImpl sock;
- RETURN_IF_NOT_OK(sock.open());
- // Set the correct address families. Tunnel mode policies use wildcard selectors, while
- // templates have addresses set. These may be different address families. This method is called
- // separately for IPv4 and IPv6 policies, and thus only need to map a single inner address
- // family to the outer address families.
- spInfo.selAddrFamily = selAddrFamily;
- if (msgType == XFRM_MSG_DELPOLICY) {
- RETURN_IF_NOT_OK(fillXfrmCommonInfo(spi, markValue, markMask, transformId, xfrmInterfaceId,
- &spInfo));
- return deleteTunnelModeSecurityPolicy(spInfo, sock, static_cast<XfrmDirection>(direction));
- } else {
- RETURN_IF_NOT_OK(fillXfrmCommonInfo(tmplSrcAddress, tmplDstAddress, spi, markValue,
- markMask, transformId, xfrmInterfaceId, &spInfo));
- return updateTunnelModeSecurityPolicy(spInfo, sock, static_cast<XfrmDirection>(direction),
- msgType);
- }
- }
- void XfrmController::fillXfrmSelector(const int selAddrFamily, xfrm_selector* selector) {
- selector->family = selAddrFamily;
- 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,
- const XfrmSocket& sock) {
- xfrm_usersa_info usersa{};
- nlattr_algo_crypt crypt{};
- nlattr_algo_auth auth{};
- nlattr_algo_aead aead{};
- nlattr_xfrm_mark xfrmmark{};
- nlattr_xfrm_output_mark xfrmoutputmark{};
- nlattr_encap_tmpl encap{};
- nlattr_xfrm_interface_id xfrm_if_id{};
- enum {
- NLMSG_HDR,
- USERSA,
- USERSA_PAD,
- CRYPT,
- CRYPT_PAD,
- AUTH,
- AUTH_PAD,
- AEAD,
- AEAD_PAD,
- MARK,
- MARK_PAD,
- OUTPUT_MARK,
- OUTPUT_MARK_PAD,
- ENCAP,
- ENCAP_PAD,
- INTF_ID,
- INTF_ID_PAD,
- };
- std::vector<iovec> iov = {
- {nullptr, 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
- {&xfrm_if_id, 0}, // adjust size if interface ID is present
- {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
- };
- if (!record.aead.name.empty() && (!record.auth.name.empty() || !record.crypt.name.empty())) {
- return netdutils::statusFromErrno(EINVAL, "Invalid xfrm algo selection; AEAD is mutually "
- "exclusive with both Authentication and "
- "Encryption");
- }
- if (record.aead.key.size() > MAX_KEY_LENGTH || record.auth.key.size() > MAX_KEY_LENGTH ||
- record.crypt.key.size() > MAX_KEY_LENGTH) {
- return netdutils::statusFromErrno(EINVAL, "Key length invalid; exceeds MAX_KEY_LENGTH");
- }
- if (record.mode != XfrmMode::TUNNEL &&
- (record.xfrm_if_id != 0 || record.netId != 0 || record.mark.v != 0 || record.mark.m != 0)) {
- return netdutils::statusFromErrno(EINVAL,
- "xfrm_if_id, mark and netid parameters invalid "
- "for non tunnel-mode transform");
- } else if (record.mode == XfrmMode::TUNNEL && !mIsXfrmIntfSupported && record.xfrm_if_id != 0) {
- return netdutils::statusFromErrno(EINVAL, "xfrm_if_id set for VTI Security Association");
- }
- int len;
- len = iov[USERSA].iov_len = fillUserSaInfo(record, &usersa);
- iov[USERSA_PAD].iov_len = NLMSG_ALIGN(len) - len;
- len = iov[CRYPT].iov_len = fillNlAttrXfrmAlgoEnc(record.crypt, &crypt);
- iov[CRYPT_PAD].iov_len = NLA_ALIGN(len) - len;
- len = iov[AUTH].iov_len = fillNlAttrXfrmAlgoAuth(record.auth, &auth);
- iov[AUTH_PAD].iov_len = NLA_ALIGN(len) - len;
- len = iov[AEAD].iov_len = fillNlAttrXfrmAlgoAead(record.aead, &aead);
- iov[AEAD_PAD].iov_len = NLA_ALIGN(len) - len;
- 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;
- len = iov[INTF_ID].iov_len = fillNlAttrXfrmIntfId(record.xfrm_if_id, &xfrm_if_id);
- iov[INTF_ID_PAD].iov_len = NLA_ALIGN(len) - len;
- return sock.sendMessage(XFRM_MSG_UPDSA, NETLINK_REQUEST_FLAGS, 0, &iov);
- }
- int XfrmController::fillNlAttrXfrmAlgoEnc(const XfrmAlgo& inAlgo, nlattr_algo_crypt* algo) {
- if (inAlgo.name.empty()) { // Do not fill anything if algorithm not provided
- return 0;
- }
- int len = NLA_HDRLEN + sizeof(xfrm_algo);
- // Kernel always changes last char to null terminator; no safety checks needed.
- strncpy(algo->crypt.alg_name, inAlgo.name.c_str(), sizeof(algo->crypt.alg_name));
- algo->crypt.alg_key_len = inAlgo.key.size() * 8; // bits
- memcpy(algo->key, &inAlgo.key[0], inAlgo.key.size());
- len += inAlgo.key.size();
- fillXfrmNlaHdr(&algo->hdr, XFRMA_ALG_CRYPT, len);
- return len;
- }
- int XfrmController::fillNlAttrXfrmAlgoAuth(const XfrmAlgo& inAlgo, nlattr_algo_auth* algo) {
- if (inAlgo.name.empty()) { // Do not fill anything if algorithm not provided
- return 0;
- }
- int len = NLA_HDRLEN + sizeof(xfrm_algo_auth);
- // Kernel always changes last char to null terminator; no safety checks needed.
- strncpy(algo->auth.alg_name, inAlgo.name.c_str(), sizeof(algo->auth.alg_name));
- algo->auth.alg_key_len = inAlgo.key.size() * 8; // bits
- // This is the extra field for ALG_AUTH_TRUNC
- algo->auth.alg_trunc_len = inAlgo.truncLenBits;
- memcpy(algo->key, &inAlgo.key[0], inAlgo.key.size());
- len += inAlgo.key.size();
- fillXfrmNlaHdr(&algo->hdr, XFRMA_ALG_AUTH_TRUNC, len);
- return len;
- }
- int XfrmController::fillNlAttrXfrmAlgoAead(const XfrmAlgo& inAlgo, nlattr_algo_aead* algo) {
- if (inAlgo.name.empty()) { // Do not fill anything if algorithm not provided
- return 0;
- }
- int len = NLA_HDRLEN + sizeof(xfrm_algo_aead);
- // Kernel always changes last char to null terminator; no safety checks needed.
- strncpy(algo->aead.alg_name, inAlgo.name.c_str(), sizeof(algo->aead.alg_name));
- algo->aead.alg_key_len = inAlgo.key.size() * 8; // bits
- // This is the extra field for ALG_AEAD. ICV length is the same as truncation length
- // for any AEAD algorithm.
- algo->aead.alg_icv_len = inAlgo.truncLenBits;
- memcpy(algo->key, &inAlgo.key[0], inAlgo.key.size());
- len += inAlgo.key.size();
- fillXfrmNlaHdr(&algo->hdr, XFRMA_ALG_AEAD, len);
- return len;
- }
- int XfrmController::fillNlAttrXfrmEncapTmpl(const XfrmSaInfo& record, nlattr_encap_tmpl* tmpl) {
- if (record.encap.type == XfrmEncapType::NONE) {
- return 0;
- }
- int len = NLA_HDRLEN + sizeof(xfrm_encap_tmpl);
- tmpl->tmpl.encap_type = static_cast<uint16_t>(record.encap.type);
- tmpl->tmpl.encap_sport = htons(record.encap.srcPort);
- tmpl->tmpl.encap_dport = htons(record.encap.dstPort);
- fillXfrmNlaHdr(&tmpl->hdr, XFRMA_ENCAP, len);
- return len;
- }
- int XfrmController::fillUserSaInfo(const XfrmSaInfo& record, xfrm_usersa_info* usersa) {
- // Use AF_UNSPEC for all SAs. In transport mode, kernel picks selector family based on
- // usersa->family, while in tunnel mode, the XFRM_STATE_AF_UNSPEC flag allows dual-stack SAs.
- fillXfrmSelector(AF_UNSPEC, &usersa->sel);
- usersa->id.proto = IPPROTO_ESP;
- usersa->id.spi = record.spi;
- usersa->id.daddr = record.dstAddr;
- usersa->saddr = record.srcAddr;
- fillXfrmLifetimeDefaults(&usersa->lft);
- fillXfrmCurLifetimeDefaults(&usersa->curlft);
- memset(&usersa->stats, 0, sizeof(usersa->stats)); // leave stats zeroed out
- usersa->reqid = record.transformId;
- usersa->family = record.addrFamily;
- usersa->mode = static_cast<uint8_t>(record.mode);
- usersa->replay_window = REPLAY_WINDOW_SIZE;
- if (record.mode == XfrmMode::TRANSPORT) {
- usersa->flags = 0; // TODO: should we actually set flags, XFRM_SA_XFLAG_DONT_ENCAP_DSCP?
- } else {
- usersa->flags = XFRM_STATE_AF_UNSPEC;
- }
- return sizeof(*usersa);
- }
- int XfrmController::fillUserSaId(const XfrmCommonInfo& record, xfrm_usersa_id* said) {
- said->daddr = record.dstAddr;
- said->spi = record.spi;
- said->family = record.addrFamily;
- said->proto = IPPROTO_ESP;
- return sizeof(*said);
- }
- netdutils::Status XfrmController::deleteSecurityAssociation(const XfrmCommonInfo& record,
- const XfrmSocket& sock) {
- xfrm_usersa_id said{};
- nlattr_xfrm_mark xfrmmark{};
- nlattr_xfrm_interface_id xfrm_if_id{};
- enum { NLMSG_HDR, USERSAID, USERSAID_PAD, MARK, MARK_PAD, INTF_ID, INTF_ID_PAD };
- std::vector<iovec> iov = {
- {nullptr, 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
- {&xfrm_if_id, 0}, // adjust size if interface ID is present
- {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
- };
- int len;
- len = iov[USERSAID].iov_len = fillUserSaId(record, &said);
- iov[USERSAID_PAD].iov_len = NLMSG_ALIGN(len) - len;
- len = iov[MARK].iov_len = fillNlAttrXfrmMark(record, &xfrmmark);
- iov[MARK_PAD].iov_len = NLA_ALIGN(len) - len;
- len = iov[INTF_ID].iov_len = fillNlAttrXfrmIntfId(record.xfrm_if_id, &xfrm_if_id);
- iov[INTF_ID_PAD].iov_len = NLA_ALIGN(len) - len;
- return sock.sendMessage(XFRM_MSG_DELSA, NETLINK_REQUEST_FLAGS, 0, &iov);
- }
- netdutils::Status XfrmController::allocateSpi(const XfrmSaInfo& record, uint32_t minSpi,
- uint32_t maxSpi, uint32_t* outSpi,
- const XfrmSocket& sock) {
- xfrm_userspi_info spiInfo{};
- enum { NLMSG_HDR, USERSAID, USERSAID_PAD };
- std::vector<iovec> iov = {
- {nullptr, 0}, // reserved for the eventual addition of a NLMSG_HDR
- {&spiInfo, 0}, // main userspi_info struct
- {kPadBytes, 0}, // up to NLMSG_ALIGNTO pad bytes of padding
- };
- int len;
- if (fillUserSaInfo(record, &spiInfo.info) == 0) {
- ALOGE("Failed to fill transport SA Info");
- }
- len = iov[USERSAID].iov_len = sizeof(spiInfo);
- iov[USERSAID_PAD].iov_len = NLMSG_ALIGN(len) - len;
- RandomSpi spiGen = RandomSpi(minSpi, maxSpi);
- int spi;
- netdutils::Status ret;
- while ((spi = spiGen.next()) != INVALID_SPI) {
- spiInfo.min = spi;
- spiInfo.max = spi;
- ret = sock.sendMessage(XFRM_MSG_ALLOCSPI, NETLINK_REQUEST_FLAGS, 0, &iov);
- /* If the SPI is in use, we'll get ENOENT */
- if (netdutils::equalToErrno(ret, ENOENT))
- continue;
- if (isOk(ret)) {
- *outSpi = spi;
- ALOGD("Allocated an SPI: %x", *outSpi);
- } else {
- *outSpi = INVALID_SPI;
- ALOGE("SPI Allocation Failed with error %d", ret.code());
- }
- return ret;
- }
- // Should always be -ENOENT if we get here
- return ret;
- }
- netdutils::Status XfrmController::updateTunnelModeSecurityPolicy(const XfrmSpInfo& record,
- const XfrmSocket& sock,
- XfrmDirection direction,
- uint16_t msgType) {
- xfrm_userpolicy_info userpolicy{};
- nlattr_user_tmpl usertmpl{};
- nlattr_xfrm_mark xfrmmark{};
- nlattr_xfrm_interface_id xfrm_if_id{};
- enum {
- NLMSG_HDR,
- USERPOLICY,
- USERPOLICY_PAD,
- USERTMPL,
- USERTMPL_PAD,
- MARK,
- MARK_PAD,
- INTF_ID,
- INTF_ID_PAD,
- };
- std::vector<iovec> iov = {
- {nullptr, 0}, // reserved for the eventual addition of a NLMSG_HDR
- {&userpolicy, 0}, // main xfrm_userpolicy_info struct
- {kPadBytes, 0}, // up to NLMSG_ALIGNTO pad bytes of padding
- {&usertmpl, 0}, // adjust size if xfrm_user_tmpl struct 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
- {&xfrm_if_id, 0}, // adjust size if interface ID is present
- {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
- };
- int len;
- len = iov[USERPOLICY].iov_len = fillUserSpInfo(record, direction, &userpolicy);
- iov[USERPOLICY_PAD].iov_len = NLMSG_ALIGN(len) - len;
- len = iov[USERTMPL].iov_len = fillNlAttrUserTemplate(record, &usertmpl);
- iov[USERTMPL_PAD].iov_len = NLA_ALIGN(len) - len;
- len = iov[MARK].iov_len = fillNlAttrXfrmMark(record, &xfrmmark);
- iov[MARK_PAD].iov_len = NLA_ALIGN(len) - len;
- len = iov[INTF_ID].iov_len = fillNlAttrXfrmIntfId(record.xfrm_if_id, &xfrm_if_id);
- iov[INTF_ID_PAD].iov_len = NLA_ALIGN(len) - len;
- return sock.sendMessage(msgType, NETLINK_REQUEST_FLAGS, 0, &iov);
- }
- netdutils::Status XfrmController::deleteTunnelModeSecurityPolicy(const XfrmSpInfo& record,
- const XfrmSocket& sock,
- XfrmDirection direction) {
- xfrm_userpolicy_id policyid{};
- nlattr_xfrm_mark xfrmmark{};
- nlattr_xfrm_interface_id xfrm_if_id{};
- enum {
- NLMSG_HDR,
- USERPOLICYID,
- USERPOLICYID_PAD,
- MARK,
- MARK_PAD,
- INTF_ID,
- INTF_ID_PAD,
- };
- std::vector<iovec> iov = {
- {nullptr, 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
- {&xfrm_if_id, 0}, // adjust size if interface ID is present
- {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
- };
- int len = iov[USERPOLICYID].iov_len = fillUserPolicyId(record, direction, &policyid);
- iov[USERPOLICYID_PAD].iov_len = NLMSG_ALIGN(len) - len;
- len = iov[MARK].iov_len = fillNlAttrXfrmMark(record, &xfrmmark);
- iov[MARK_PAD].iov_len = NLA_ALIGN(len) - len;
- len = iov[INTF_ID].iov_len = fillNlAttrXfrmIntfId(record.xfrm_if_id, &xfrm_if_id);
- iov[INTF_ID_PAD].iov_len = NLA_ALIGN(len) - len;
- return sock.sendMessage(XFRM_MSG_DELPOLICY, NETLINK_REQUEST_FLAGS, 0, &iov);
- }
- int XfrmController::fillUserSpInfo(const XfrmSpInfo& record, XfrmDirection direction,
- xfrm_userpolicy_info* usersp) {
- fillXfrmSelector(record.selAddrFamily, &usersp->sel);
- fillXfrmLifetimeDefaults(&usersp->lft);
- fillXfrmCurLifetimeDefaults(&usersp->curlft);
- /* if (index) index & 0x3 == dir -- must be true
- * xfrm_user.c:verify_newpolicy_info() */
- usersp->index = 0;
- usersp->dir = static_cast<uint8_t>(direction);
- usersp->action = XFRM_POLICY_ALLOW;
- usersp->flags = XFRM_POLICY_LOCALOK;
- usersp->share = XFRM_SHARE_UNIQUE;
- return sizeof(*usersp);
- }
- int XfrmController::fillUserTemplate(const XfrmSpInfo& record, xfrm_user_tmpl* tmpl) {
- tmpl->id.daddr = record.dstAddr;
- tmpl->id.spi = record.spi;
- tmpl->id.proto = IPPROTO_ESP;
- tmpl->family = record.addrFamily;
- tmpl->saddr = record.srcAddr;
- tmpl->reqid = record.transformId;
- tmpl->mode = static_cast<uint8_t>(record.mode);
- tmpl->share = XFRM_SHARE_UNIQUE;
- tmpl->optional = 0; // if this is true, then a failed state lookup will be considered OK:
- // http://lxr.free-electrons.com/source/net/xfrm/xfrm_policy.c#L1492
- tmpl->aalgos = ALGO_MASK_AUTH_ALL; // TODO: if there's a bitmask somewhere of
- // algos, we should find it and apply it.
- // I can't find one.
- tmpl->ealgos = ALGO_MASK_CRYPT_ALL; // TODO: if there's a bitmask somewhere...
- return sizeof(xfrm_user_tmpl*);
- }
- int XfrmController::fillNlAttrUserTemplate(const XfrmSpInfo& record, nlattr_user_tmpl* tmpl) {
- fillUserTemplate(record, &tmpl->tmpl);
- int len = NLA_HDRLEN + sizeof(xfrm_user_tmpl);
- fillXfrmNlaHdr(&tmpl->hdr, XFRMA_TMPL, len);
- return len;
- }
- int XfrmController::fillNlAttrXfrmMark(const XfrmCommonInfo& record, nlattr_xfrm_mark* mark) {
- // Do not set if we were not given a mark
- if (record.mark.v == 0 && record.mark.m == 0) {
- return 0;
- }
- mark->mark.v = record.mark.v; // set to 0 if it's not used
- mark->mark.m = record.mark.m; // set to 0 if it's not used
- int len = NLA_HDRLEN + sizeof(xfrm_mark);
- fillXfrmNlaHdr(&mark->hdr, XFRMA_MARK, len);
- return len;
- }
- // This function sets the output mark (or set-mark in newer kernels) to that of the underlying
- // Network's netid. This allows outbound IPsec Tunnel mode packets to be correctly directed to a
- // preselected underlying Network. Packet as marked as protected from VPNs and have a network
- // explicitly selected to prevent interference or routing loops. Also set permission flag to
- // PERMISSION_SYSTEM to ensure we can use background/restricted networks. Permission to use
- // restricted networks is checked in IpSecService.
- int XfrmController::fillNlAttrXfrmOutputMark(const __u32 underlyingNetId,
- nlattr_xfrm_output_mark* output_mark) {
- // Do not set if we were not given an output mark
- if (underlyingNetId == 0) {
- return 0;
- }
- Fwmark fwmark;
- fwmark.netId = underlyingNetId;
- // TODO: Rework this to more accurately follow the underlying network
- fwmark.permission = PERMISSION_SYSTEM;
- fwmark.explicitlySelected = true;
- fwmark.protectedFromVpn = true;
- output_mark->outputMark = fwmark.intValue;
- int len = NLA_HDRLEN + sizeof(__u32);
- fillXfrmNlaHdr(&output_mark->hdr, XFRMA_OUTPUT_MARK, len);
- return len;
- }
- int XfrmController::fillNlAttrXfrmIntfId(const uint32_t intfIdValue,
- nlattr_xfrm_interface_id* intf_id) {
- // Do not set if we were not given an interface id
- if (intfIdValue == 0) {
- return 0;
- }
- intf_id->if_id = intfIdValue;
- int len = NLA_HDRLEN + sizeof(__u32);
- fillXfrmNlaHdr(&intf_id->hdr, XFRMA_IF_ID, len);
- return len;
- }
- int XfrmController::fillUserPolicyId(const XfrmSpInfo& record, XfrmDirection direction,
- xfrm_userpolicy_id* usersp) {
- // For DELPOLICY, when index is absent, selector is needed to match the policy
- fillXfrmSelector(record.selAddrFamily, &usersp->sel);
- usersp->dir = static_cast<uint8_t>(direction);
- return sizeof(*usersp);
- }
- netdutils::Status XfrmController::ipSecAddTunnelInterface(const std::string& deviceName,
- const std::string& localAddress,
- const std::string& remoteAddress,
- int32_t ikey, int32_t okey,
- int32_t interfaceId, 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("interfaceId=%0.8x", interfaceId);
- ALOGD("isUpdate=%d", isUpdate);
- uint16_t flags = isUpdate ? NETLINK_REQUEST_FLAGS : NETLINK_ROUTE_CREATE_FLAGS;
- if (mIsXfrmIntfSupported) {
- return ipSecAddXfrmInterface(deviceName, interfaceId, flags);
- } else {
- return ipSecAddVirtualTunnelInterface(deviceName, localAddress, remoteAddress, ikey, okey,
- flags);
- }
- }
- netdutils::Status XfrmController::ipSecAddXfrmInterface(const std::string& deviceName,
- int32_t interfaceId, uint16_t flags) {
- ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
- if (deviceName.empty()) {
- return netdutils::statusFromErrno(EINVAL, "XFRM Interface deviceName empty");
- }
- ifinfomsg ifInfoMsg{};
- struct XfrmIntfCreateReq {
- nlattr ifNameNla;
- char ifName[IFNAMSIZ]; // Already aligned
- nlattr linkInfoNla;
- struct LinkInfo {
- nlattr infoKindNla;
- char infoKind[INFO_KIND_MAX_LEN]; // Already aligned
- nlattr infoDataNla;
- struct InfoData {
- nlattr xfrmLinkNla;
- uint32_t xfrmLink;
- nlattr xfrmIfIdNla;
- uint32_t xfrmIfId;
- } infoData; // Already aligned
- } linkInfo; // Already aligned
- } xfrmIntfCreateReq{
- .ifNameNla =
- {
- .nla_len = RTA_LENGTH(IFNAMSIZ),
- .nla_type = IFLA_IFNAME,
- },
- // Update .ifName via strlcpy
- .linkInfoNla =
- {
- .nla_len = RTA_LENGTH(sizeof(XfrmIntfCreateReq::LinkInfo)),
- .nla_type = IFLA_LINKINFO,
- },
- .linkInfo = {.infoKindNla =
- {
- .nla_len = RTA_LENGTH(INFO_KIND_MAX_LEN),
- .nla_type = IFLA_INFO_KIND,
- },
- // Update .infoKind via strlcpy
- .infoDataNla =
- {
- .nla_len = RTA_LENGTH(
- sizeof(XfrmIntfCreateReq::LinkInfo::InfoData)),
- .nla_type = IFLA_INFO_DATA,
- },
- .infoData = {
- .xfrmLinkNla =
- {
- .nla_len = RTA_LENGTH(sizeof(uint32_t)),
- .nla_type = IFLA_XFRM_LINK,
- },
- // Always use LOOPBACK_IFINDEX, since we use output marks for
- // route lookup instead. The use case of having a Network with
- // loopback in it is unsupported in tunnel mode.
- .xfrmLink = static_cast<uint32_t>(LOOPBACK_IFINDEX),
- .xfrmIfIdNla =
- {
- .nla_len = RTA_LENGTH(sizeof(uint32_t)),
- .nla_type = IFLA_XFRM_IF_ID,
- },
- .xfrmIfId = static_cast<uint32_t>(interfaceId),
- }}};
- strlcpy(xfrmIntfCreateReq.ifName, deviceName.c_str(), IFNAMSIZ);
- strlcpy(xfrmIntfCreateReq.linkInfo.infoKind, INFO_KIND_XFRMI, INFO_KIND_MAX_LEN);
- iovec iov[] = {
- {NULL, 0}, // reserved for the eventual addition of a NLMSG_HDR
- {&ifInfoMsg, sizeof(ifInfoMsg)},
- {&xfrmIntfCreateReq, sizeof(xfrmIntfCreateReq)},
- };
- // sendNetlinkRequest returns -errno
- int ret = -sendNetlinkRequest(RTM_NEWLINK, flags, iov, ARRAY_SIZE(iov), nullptr);
- return netdutils::statusFromErrno(ret, "Add/update xfrm interface");
- }
- netdutils::Status XfrmController::ipSecAddVirtualTunnelInterface(const std::string& deviceName,
- const std::string& localAddress,
- const std::string& remoteAddress,
- int32_t ikey, int32_t okey,
- uint16_t flags) {
- ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
- if (deviceName.empty() || localAddress.empty() || remoteAddress.empty()) {
- return netdutils::statusFromErrno(EINVAL, "Required VTI creation parameter not provided");
- }
- uint8_t PADDING_BUFFER[] = {0, 0, 0, 0};
- // Find address family.
- uint8_t remAddr[sizeof(in6_addr)];
- StatusOr<uint16_t> statusOrRemoteFam = convertStringAddress(remoteAddress, remAddr);
- RETURN_IF_NOT_OK(statusOrRemoteFam);
- uint8_t locAddr[sizeof(in6_addr)];
- StatusOr<uint16_t> statusOrLocalFam = convertStringAddress(localAddress, locAddr);
- RETURN_IF_NOT_OK(statusOrLocalFam);
- if (statusOrLocalFam.value() != statusOrRemoteFam.value()) {
- return netdutils::statusFromErrno(EINVAL, "Local and remote address families do not match");
- }
- 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_payload_u32 iflaVtiIKey;
- size_t iflaVtiIKeyPad = fillNlAttrU32(IFLA_VTI_IKEY, htonl(ikey), &iflaVtiIKey);
- // Construct IFLA_VTI_IKEY
- nlattr_payload_u32 iflaVtiOKey;
- size_t iflaVtiOKeyPad = fillNlAttrU32(IFLA_VTI_OKEY, htonl(okey), &iflaVtiOKey);
- int iflaInfoDataPayloadLength = iflaVtiLocal.nla_len + iflaVtiLocalPad + iflaVtiRemote.nla_len +
- iflaVtiRemotePad + iflaVtiIKey.hdr.nla_len + iflaVtiIKeyPad +
- iflaVtiOKey.hdr.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[] = {
- {nullptr, 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, iflaVtiIKey.hdr.nla_len},
- {&PADDING_BUFFER, iflaVtiIKeyPad},
- {&iflaVtiOKey, iflaVtiOKey.hdr.nla_len},
- {&PADDING_BUFFER, iflaVtiOKeyPad},
- {&PADDING_BUFFER, iflaInfoDataPad},
- {&PADDING_BUFFER, iflaLinkInfoPad},
- };
- // sendNetlinkRequest returns -errno
- int ret = -1 * sendNetlinkRequest(RTM_NEWLINK, flags, iov, ARRAY_SIZE(iov), nullptr);
- return netdutils::statusFromErrno(ret, "Failed to add/update virtual tunnel interface");
- }
- netdutils::Status XfrmController::ipSecRemoveTunnelInterface(const std::string& deviceName) {
- ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
- ALOGD("deviceName=%s", deviceName.c_str());
- if (deviceName.empty()) {
- return netdutils::statusFromErrno(EINVAL, "Required parameter not provided");
- }
- 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[] = {
- {nullptr, 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;
- // sendNetlinkRequest returns -errno
- int ret = -1 * sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr);
- return netdutils::statusFromErrno(ret, "Error in deleting IpSec interface " + deviceName);
- }
- void XfrmController::dump(DumpWriter& dw) {
- ScopedIndent indentForXfrmController(dw);
- dw.println("XfrmController");
- ScopedIndent indentForXfrmISupport(dw);
- dw.println("XFRM-I support: %d", mIsXfrmIntfSupported);
- }
- } // namespace net
- } // namespace android
|