1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "fwmark_network.h"
17
18 #include <cerrno>
19 #include <sys/socket.h>
20 #include <sys/stat.h>
21 #include <sys/un.h>
22 #include <thread>
23 #include <unistd.h>
24
25 #include "fwmark.h"
26 #include "fwmark_command.h"
27 #include "init_socket.h"
28 #include "netnative_log_wrapper.h"
29 #ifdef USE_SELINUX
30 #include "selinux.h"
31 #endif
32 #include "securec.h"
33
34 namespace OHOS {
35 namespace nmd {
36 static constexpr const uint16_t NETID_UNSET = 0;
37 static constexpr const int32_t NO_ERROR_CODE = 0;
38 static constexpr const int32_t ERROR_CODE_RECVMSG_FAILED = -1;
39 static constexpr const int32_t ERROR_CODE_SOCKETFD_INVALID = -2;
40 static constexpr const int32_t ERROR_CODE_WRITE_FAILED = -3;
41 static constexpr const int32_t ERROR_CODE_GETSOCKOPT_FAILED = -4;
42 static constexpr const int32_t ERROR_CODE_SETSOCKOPT_FAILED = -5;
43 static constexpr const int32_t ERROR_CODE_SET_MARK = -6;
44 static constexpr const int32_t MAX_CONCURRENT_CONNECTION_REQUESTS = 10;
45
CloseSocket(int32_t * socket,int32_t ret,int32_t errorCode)46 void CloseSocket(int32_t *socket, int32_t ret, int32_t errorCode)
47 {
48 if (socket == nullptr) {
49 NETNATIVE_LOGE("CloseSocket failed, socket is nullptr");
50 return;
51 }
52 switch (errorCode) {
53 case ERROR_CODE_RECVMSG_FAILED:
54 NETNATIVE_LOGE("recvmsg failed, clientSockfd:%{public}d, ret:%{public}d, errno: %{public}d", *socket, ret,
55 errno);
56 break;
57 case ERROR_CODE_SOCKETFD_INVALID:
58 NETNATIVE_LOGE("socketFd invalid:%{public}d, ret:%{public}d, errno: %{public}d", *socket, ret, errno);
59 break;
60 case ERROR_CODE_WRITE_FAILED:
61 NETNATIVE_LOGE("wirte failed, clientSockfd:%{public}d, ret:%{public}d, errno: %{public}d", *socket, ret,
62 errno);
63 break;
64 case ERROR_CODE_GETSOCKOPT_FAILED:
65 NETNATIVE_LOGE("getsockopt failed, socketFd:%{public}d, ret:%{public}d, errno: %{public}d", *socket, ret,
66 errno);
67 break;
68 case ERROR_CODE_SETSOCKOPT_FAILED:
69 NETNATIVE_LOGE("setsockopt failed socketFd:%{public}d, ret:%{public}d, errno: %{public}d", *socket, ret,
70 errno);
71 break;
72 case ERROR_CODE_SET_MARK:
73 NETNATIVE_LOGE("SetMark failed, clientSockfd:%{public}d, ret:%{public}d, errno: %{public}d", *socket, ret,
74 errno);
75 break;
76 default:
77 NETNATIVE_LOGI("NO_ERROR_CODE CloseSocket socket:%{public}d, ret:%{public}d", *socket, ret);
78 break;
79 }
80 close(*socket);
81 *socket = -1;
82 }
83
SetMark(int32_t * socketFd,FwmarkCommand * command)84 int32_t SetMark(int32_t *socketFd, FwmarkCommand *command)
85 {
86 if (command == nullptr || socketFd == nullptr) {
87 NETNATIVE_LOGE("SetMark failed, command or socketFd is nullptr");
88 return -1;
89 }
90 Fwmark fwmark;
91 socklen_t fwmarkLen = sizeof(fwmark.intValue);
92 int32_t ret = getsockopt(*socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen);
93 if (ret != 0) {
94 CloseSocket(socketFd, ret, ERROR_CODE_GETSOCKOPT_FAILED);
95 return ret;
96 }
97 fwmark.netId = command->netId;
98 NETNATIVE_LOGI("FwmarkNetwork: SetMark netId: %{public}d, socketFd:%{public}d", command->netId, *socketFd);
99 if (command->netId == NETID_UNSET) {
100 fwmark.explicitlySelected = false;
101 fwmark.protectedFromVpn = false;
102 fwmark.permission = PERMISSION_NONE;
103 } else {
104 fwmark.explicitlySelected = true;
105 }
106 ret = setsockopt(*socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, sizeof(fwmark.intValue));
107 if (ret != 0) {
108 CloseSocket(socketFd, ret, ERROR_CODE_SETSOCKOPT_FAILED);
109 return ret;
110 }
111 CloseSocket(socketFd, ret, NO_ERROR_CODE);
112 return ret;
113 }
114
SendMessage(int32_t * serverSockfd)115 void SendMessage(int32_t *serverSockfd)
116 {
117 if (serverSockfd == nullptr) {
118 NETNATIVE_LOGE("SendMessage failed, serverSockfd is nullptr");
119 return;
120 }
121
122 int32_t clientSockfd;
123 struct sockaddr_un clientAddr;
124 socklen_t len = sizeof(clientAddr);
125 while (true) {
126 clientSockfd = accept(*serverSockfd, reinterpret_cast<struct sockaddr *>(&clientAddr), &len);
127 FwmarkCommand fwmCmd;
128 iovec iov = {
129 .iov_base = &fwmCmd,
130 .iov_len = sizeof(fwmCmd),
131 };
132 int32_t socketFd = -1;
133 union {
134 cmsghdr cmh;
135 char cmsg[CMSG_SPACE(sizeof(socketFd))];
136 } cmsgu;
137 (void)memset_s(cmsgu.cmsg, sizeof(cmsgu.cmsg), 0, sizeof(cmsgu.cmsg));
138 msghdr message;
139 (void)memset_s(&message, sizeof(message), 0, sizeof(message));
140 message = {
141 .msg_iov = &iov,
142 .msg_iovlen = 1,
143 .msg_control = cmsgu.cmsg,
144 .msg_controllen = sizeof(cmsgu.cmsg),
145 };
146 int32_t ret = recvmsg(clientSockfd, &message, 0);
147 if (ret < 0) {
148 CloseSocket(&clientSockfd, ret, ERROR_CODE_RECVMSG_FAILED);
149 continue;
150 }
151 cmsghdr *const cmsgh = CMSG_FIRSTHDR(&message);
152 if (cmsgh && cmsgh->cmsg_level == SOL_SOCKET && cmsgh->cmsg_type == SCM_RIGHTS &&
153 cmsgh->cmsg_len == CMSG_LEN(sizeof(socketFd))) {
154 int rst = memcpy_s(&socketFd, sizeof(socketFd), CMSG_DATA(cmsgh), sizeof(socketFd));
155 if (rst != 0) {
156 return;
157 }
158 }
159 if (socketFd < 0) {
160 CloseSocket(&clientSockfd, ret, ERROR_CODE_SOCKETFD_INVALID);
161 continue;
162 }
163 if ((ret = SetMark(&socketFd, &fwmCmd)) != 0) {
164 CloseSocket(&clientSockfd, ret, ERROR_CODE_SET_MARK);
165 continue;
166 }
167 if ((ret = write(clientSockfd, &ret, sizeof(ret))) < 0) {
168 CloseSocket(&clientSockfd, ret, ERROR_CODE_WRITE_FAILED);
169 continue;
170 }
171 CloseSocket(&clientSockfd, ret, NO_ERROR_CODE);
172 }
173 }
174
StartListener()175 void StartListener()
176 {
177 int32_t serverSockfd = GetControlSocket("fwmarkd");
178
179 int32_t result = listen(serverSockfd, MAX_CONCURRENT_CONNECTION_REQUESTS);
180 if (result < 0) {
181 NETNATIVE_LOGE("FwmarkNetwork: listen failed result %{public}d, errno: %{public}d", result, errno);
182 close(serverSockfd);
183 serverSockfd = -1;
184 return;
185 }
186 SendMessage(&serverSockfd);
187 close(serverSockfd);
188 serverSockfd = -1;
189 }
190
FwmarkNetwork()191 FwmarkNetwork::FwmarkNetwork()
192 {
193 ListenerClient();
194 }
195
~FwmarkNetwork()196 FwmarkNetwork::~FwmarkNetwork() {}
197
ListenerClient()198 void FwmarkNetwork::ListenerClient()
199 {
200 std::thread startListener(StartListener);
201 startListener.detach();
202 NETNATIVE_LOGI("FwmarkNetwork: StartListener");
203 }
204 } // namespace nmd
205 } // namespace OHOS
206