1f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran/*
2f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * Copyright (C) 2014 The Android Open Source Project
3f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran *
4f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * Licensed under the Apache License, Version 2.0 (the "License");
5f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * you may not use this file except in compliance with the License.
6f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * You may obtain a copy of the License at
7f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran *
8f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran *      http://www.apache.org/licenses/LICENSE-2.0
9f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran *
10f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * Unless required by applicable law or agreed to in writing, software
11f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * distributed under the License is distributed on an "AS IS" BASIS,
12f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * See the License for the specific language governing permissions and
14f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * limitations under the License.
15f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran */
16f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
17f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran#include "FwmarkClient.h"
18f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
19d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen#include "FwmarkCommand.h"
20d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen
2127aacc0d49dbc5c3721ae5ca6f6033be6537c4c3Elliott Hughes#include <errno.h>
22f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran#include <stdlib.h>
23bb881e28e62bc5048f4a62d21104aa25da13b0f1Elliott Hughes#include <string.h>
24f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran#include <sys/socket.h>
25f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran#include <sys/un.h>
26f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran#include <unistd.h>
27f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
287d374533e2daadee5d7f01dd9aa3c98e42759d50Michal Karpinski#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
297d374533e2daadee5d7f01dd9aa3c98e42759d50Michal Karpinski
30f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandrannamespace {
31f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
32f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandranconst sockaddr_un FWMARK_SERVER_PATH = {AF_UNIX, "/dev/socket/fwmarkd"};
33f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
34e54b21279f58f50da2e42a4c009e467090152aebdimitry#if defined(NETD_CLIENT_DEBUGGABLE_BUILD)
35e54b21279f58f50da2e42a4c009e467090152aebdimitryconstexpr bool isBuildDebuggable = true;
36e54b21279f58f50da2e42a4c009e467090152aebdimitry#else
37e54b21279f58f50da2e42a4c009e467090152aebdimitryconstexpr bool isBuildDebuggable = false;
38e54b21279f58f50da2e42a4c009e467090152aebdimitry#endif
396028b39ef140707c538d66586603f74dd8f222d6Michal Karpinski
406028b39ef140707c538d66586603f74dd8f222d6Michal Karpinskibool isOverriddenBy(const char *name) {
416028b39ef140707c538d66586603f74dd8f222d6Michal Karpinski    return isBuildDebuggable && getenv(name);
426028b39ef140707c538d66586603f74dd8f222d6Michal Karpinski}
436028b39ef140707c538d66586603f74dd8f222d6Michal Karpinski
449944ba87ad061fd6add45521044c3503771e43c2Chenbo Fengbool commandHasFd(int cmdId) {
459944ba87ad061fd6add45521044c3503771e43c2Chenbo Feng    return (cmdId != FwmarkCommand::QUERY_USER_ACCESS) &&
469944ba87ad061fd6add45521044c3503771e43c2Chenbo Feng        (cmdId != FwmarkCommand::SET_COUNTERSET) &&
479944ba87ad061fd6add45521044c3503771e43c2Chenbo Feng        (cmdId != FwmarkCommand::DELETE_TAGDATA);
489944ba87ad061fd6add45521044c3503771e43c2Chenbo Feng}
499944ba87ad061fd6add45521044c3503771e43c2Chenbo Feng
50f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran}  // namespace
51f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
525fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandranbool FwmarkClient::shouldSetFwmark(int family) {
536028b39ef140707c538d66586603f74dd8f222d6Michal Karpinski    if (isOverriddenBy(ANDROID_NO_USE_FWMARK_CLIENT)) {
546028b39ef140707c538d66586603f74dd8f222d6Michal Karpinski        return false;
556028b39ef140707c538d66586603f74dd8f222d6Michal Karpinski    }
566028b39ef140707c538d66586603f74dd8f222d6Michal Karpinski    return family == AF_INET || family == AF_INET6;
572cf561722c2661cc0d4db502a44a3021609f307eRobin Lee}
582cf561722c2661cc0d4db502a44a3021609f307eRobin Lee
592cf561722c2661cc0d4db502a44a3021609f307eRobin Leebool FwmarkClient::shouldReportConnectComplete(int family) {
606028b39ef140707c538d66586603f74dd8f222d6Michal Karpinski    if (isOverriddenBy(ANDROID_FWMARK_METRICS_ONLY)) {
616028b39ef140707c538d66586603f74dd8f222d6Michal Karpinski        return false;
626028b39ef140707c538d66586603f74dd8f222d6Michal Karpinski    }
636028b39ef140707c538d66586603f74dd8f222d6Michal Karpinski    return shouldSetFwmark(family);
64f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran}
65f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
66f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram RamachandranFwmarkClient::FwmarkClient() : mChannel(-1) {
67f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran}
68f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
69f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram RamachandranFwmarkClient::~FwmarkClient() {
70f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    if (mChannel >= 0) {
71f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran        close(mChannel);
72f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    }
73f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran}
74f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
757d374533e2daadee5d7f01dd9aa3c98e42759d50Michal Karpinskiint FwmarkClient::send(FwmarkCommand* data, int fd, FwmarkConnectInfo* connectInfo) {
7653ea9cadf6cc5f8be1c16b5b6b660cd7366fd3f0Nick Kralevich    mChannel = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
77f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    if (mChannel == -1) {
783a069e6a76752a0ee73c60f276ae362d1c01467fSreeram Ramachandran        return -errno;
79f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    }
80f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
81f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    if (TEMP_FAILURE_RETRY(connect(mChannel, reinterpret_cast<const sockaddr*>(&FWMARK_SERVER_PATH),
82f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran                                   sizeof(FWMARK_SERVER_PATH))) == -1) {
83f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran        // If we are unable to connect to the fwmark server, assume there's no error. This protects
84f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran        // against future changes if the fwmark server goes away.
859944ba87ad061fd6add45521044c3503771e43c2Chenbo Feng        // TODO: This means that fd will very likely be misrouted. See if we can delete this in a
869944ba87ad061fd6add45521044c3503771e43c2Chenbo Feng        //       separate CL.
8731f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandran        return 0;
88f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    }
89f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
907d374533e2daadee5d7f01dd9aa3c98e42759d50Michal Karpinski    iovec iov[2] = {
917d374533e2daadee5d7f01dd9aa3c98e42759d50Michal Karpinski        { data, sizeof(*data) },
927d374533e2daadee5d7f01dd9aa3c98e42759d50Michal Karpinski        { connectInfo, (connectInfo ? sizeof(*connectInfo) : 0) },
937d374533e2daadee5d7f01dd9aa3c98e42759d50Michal Karpinski    };
94f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    msghdr message;
95f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    memset(&message, 0, sizeof(message));
967d374533e2daadee5d7f01dd9aa3c98e42759d50Michal Karpinski    message.msg_iov = iov;
977d374533e2daadee5d7f01dd9aa3c98e42759d50Michal Karpinski    message.msg_iovlen = ARRAY_SIZE(iov);
98f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
99f86df5580e86c2405c71c708408eeee57b38c0d3Stephen Hines    union {
100f86df5580e86c2405c71c708408eeee57b38c0d3Stephen Hines        cmsghdr cmh;
101f86df5580e86c2405c71c708408eeee57b38c0d3Stephen Hines        char cmsg[CMSG_SPACE(sizeof(fd))];
102f86df5580e86c2405c71c708408eeee57b38c0d3Stephen Hines    } cmsgu;
103d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen
1049944ba87ad061fd6add45521044c3503771e43c2Chenbo Feng    if (commandHasFd(data->cmdId)) {
105d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen        memset(cmsgu.cmsg, 0, sizeof(cmsgu.cmsg));
106d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen        message.msg_control = cmsgu.cmsg;
107d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen        message.msg_controllen = sizeof(cmsgu.cmsg);
108d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen
109d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen        cmsghdr* const cmsgh = CMSG_FIRSTHDR(&message);
110d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen        cmsgh->cmsg_len = CMSG_LEN(sizeof(fd));
111d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen        cmsgh->cmsg_level = SOL_SOCKET;
112d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen        cmsgh->cmsg_type = SCM_RIGHTS;
113d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen        memcpy(CMSG_DATA(cmsgh), &fd, sizeof(fd));
114d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen    }
115f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
116f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    if (TEMP_FAILURE_RETRY(sendmsg(mChannel, &message, 0)) == -1) {
1173a069e6a76752a0ee73c60f276ae362d1c01467fSreeram Ramachandran        return -errno;
118f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    }
119f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
120f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    int error = 0;
12131f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandran
122f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    if (TEMP_FAILURE_RETRY(recv(mChannel, &error, sizeof(error), 0)) == -1) {
1233a069e6a76752a0ee73c60f276ae362d1c01467fSreeram Ramachandran        return -errno;
124f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    }
125f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
12631f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandran    return error;
127f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran}
128