1 /*
2 * Copyright (c) 2022-2023 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 <pthread.h>
24 #include <unistd.h>
25
26 #include "fwmark.h"
27 #include "fwmark_command.h"
28 #include "init_socket.h"
29 #include "netnative_log_wrapper.h"
30 #ifdef USE_SELINUX
31 #include "selinux.h"
32 #endif
33 #include "securec.h"
34
35 namespace OHOS {
36 namespace nmd {
37 static constexpr const uint16_t NETID_UNSET = 0;
38 static constexpr const int32_t NO_ERROR_CODE = 0;
39 static constexpr const int32_t ERROR_CODE_RECVMSG_FAILED = -1;
40 static constexpr const int32_t ERROR_CODE_SOCKETFD_INVALID = -2;
41 static constexpr const int32_t ERROR_CODE_WRITE_FAILED = -3;
42 static constexpr const int32_t ERROR_CODE_GETSOCKOPT_FAILED = -4;
43 static constexpr const int32_t ERROR_CODE_SETSOCKOPT_FAILED = -5;
44 static constexpr const int32_t ERROR_CODE_SET_MARK = -6;
45 static constexpr const int32_t MAX_CONCURRENT_CONNECTION_REQUESTS = 10;
46
CloseSocket(int32_t * socket,int32_t ret,int32_t errorCode)47 void CloseSocket(int32_t *socket, int32_t ret, int32_t errorCode)
48 {
49 if (socket == nullptr) {
50 NETNATIVE_LOGE("CloseSocket failed, socket is nullptr");
51 return;
52 }
53 switch (errorCode) {
54 case ERROR_CODE_RECVMSG_FAILED:
55 NETNATIVE_LOGE("recvmsg failed, clientSockfd:%{public}d, ret:%{public}d, errno: %{public}d", *socket, ret,
56 errno);
57 break;
58 case ERROR_CODE_SOCKETFD_INVALID:
59 NETNATIVE_LOGE("socketFd invalid:%{public}d, ret:%{public}d, errno: %{public}d", *socket, ret, errno);
60 break;
61 case ERROR_CODE_WRITE_FAILED:
62 NETNATIVE_LOGE("wirte failed, clientSockfd:%{public}d, ret:%{public}d, errno: %{public}d", *socket, ret,
63 errno);
64 break;
65 case ERROR_CODE_GETSOCKOPT_FAILED:
66 NETNATIVE_LOGE("getsockopt failed, socketFd:%{public}d, ret:%{public}d, errno: %{public}d", *socket, ret,
67 errno);
68 break;
69 case ERROR_CODE_SETSOCKOPT_FAILED:
70 NETNATIVE_LOGE("setsockopt failed socketFd:%{public}d, ret:%{public}d, errno: %{public}d", *socket, ret,
71 errno);
72 break;
73 case ERROR_CODE_SET_MARK:
74 NETNATIVE_LOGE("SetMark failed, clientSockfd:%{public}d, ret:%{public}d, errno: %{public}d", *socket, ret,
75 errno);
76 break;
77 default:
78 NETNATIVE_LOGI("NO_ERROR_CODE CloseSocket socket:%{public}d, ret:%{public}d", *socket, ret);
79 break;
80 }
81 close(*socket);
82 *socket = -1;
83 }
84
SetMark(int32_t * socketFd,FwmarkCommand * command)85 int32_t SetMark(int32_t *socketFd, FwmarkCommand *command)
86 {
87 if (command == nullptr || socketFd == nullptr) {
88 NETNATIVE_LOGE("SetMark failed, command or socketFd is nullptr");
89 return -1;
90 }
91 Fwmark fwmark;
92 socklen_t fwmarkLen = sizeof(fwmark.intValue);
93 int32_t ret = getsockopt(*socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen);
94 if (ret != 0) {
95 CloseSocket(socketFd, ret, ERROR_CODE_GETSOCKOPT_FAILED);
96 return ret;
97 }
98 NETNATIVE_LOGI("FwmarkNetwork: SetMark netId: %{public}d, socketFd:%{public}d, cmd:%{public}d", command->netId,
99 *socketFd, command->cmdId);
100 switch (command->cmdId) {
101 case FwmarkCommand::SELECT_NETWORK: {
102 fwmark.netId = command->netId;
103 if (command->netId == NETID_UNSET) {
104 fwmark.explicitlySelected = false;
105 fwmark.protectedFromVpn = false;
106 fwmark.permission = PERMISSION_NONE;
107 } else {
108 fwmark.explicitlySelected = true;
109 }
110 break;
111 }
112 case FwmarkCommand::PROTECT_FROM_VPN: {
113 fwmark.protectedFromVpn = true;
114 break;
115 }
116 default:
117 break;
118 }
119 ret = setsockopt(*socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, sizeof(fwmark.intValue));
120 if (ret != 0) {
121 CloseSocket(socketFd, ret, ERROR_CODE_SETSOCKOPT_FAILED);
122 return ret;
123 }
124 CloseSocket(socketFd, ret, NO_ERROR_CODE);
125 return ret;
126 }
127
SendMessage(int32_t * serverSockfd)128 void SendMessage(int32_t *serverSockfd)
129 {
130 if (serverSockfd == nullptr) {
131 NETNATIVE_LOGE("SendMessage failed, serverSockfd is nullptr");
132 return;
133 }
134 int32_t clientSockfd;
135 struct sockaddr_un clientAddr;
136 socklen_t len = sizeof(clientAddr);
137 while (true) {
138 clientSockfd = accept(*serverSockfd, reinterpret_cast<struct sockaddr *>(&clientAddr), &len);
139 FwmarkCommand fwmCmd;
140 iovec iov = {.iov_base = &fwmCmd, .iov_len = sizeof(fwmCmd)};
141 int32_t socketFd = -1;
142 union {
143 cmsghdr cmh;
144 char cmsg[CMSG_SPACE(sizeof(socketFd))];
145 } cmsgu;
146 (void)memset_s(cmsgu.cmsg, sizeof(cmsgu.cmsg), 0, sizeof(cmsgu.cmsg));
147 msghdr message;
148 (void)memset_s(&message, sizeof(message), 0, sizeof(message));
149 message = {.msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsgu.cmsg, .msg_controllen = sizeof(cmsgu.cmsg)};
150 int32_t ret = recvmsg(clientSockfd, &message, 0);
151 if (ret < 0) {
152 CloseSocket(&clientSockfd, ret, ERROR_CODE_RECVMSG_FAILED);
153 continue;
154 }
155 cmsghdr *const cmsgh = CMSG_FIRSTHDR(&message);
156 if (cmsgh && cmsgh->cmsg_level == SOL_SOCKET && cmsgh->cmsg_type == SCM_RIGHTS &&
157 cmsgh->cmsg_len == CMSG_LEN(sizeof(socketFd))) {
158 int rst = memcpy_s(&socketFd, sizeof(socketFd), CMSG_DATA(cmsgh), sizeof(socketFd));
159 if (rst != 0) {
160 return;
161 }
162 }
163 if (socketFd < 0) {
164 CloseSocket(&clientSockfd, ret, ERROR_CODE_SOCKETFD_INVALID);
165 continue;
166 }
167 if ((ret = SetMark(&socketFd, &fwmCmd)) != 0) {
168 CloseSocket(&clientSockfd, ret, ERROR_CODE_SET_MARK);
169 continue;
170 }
171 if ((ret = write(clientSockfd, &ret, sizeof(ret))) < 0) {
172 CloseSocket(&clientSockfd, ret, ERROR_CODE_WRITE_FAILED);
173 continue;
174 }
175 CloseSocket(&clientSockfd, ret, NO_ERROR_CODE);
176 }
177 }
178
StartListener()179 void StartListener()
180 {
181 int32_t serverSockfd = GetControlSocket("fwmarkd");
182
183 int32_t result = listen(serverSockfd, MAX_CONCURRENT_CONNECTION_REQUESTS);
184 if (result < 0) {
185 NETNATIVE_LOGE("FwmarkNetwork: listen failed result %{public}d, errno: %{public}d", result, errno);
186 close(serverSockfd);
187 serverSockfd = -1;
188 return;
189 }
190 SendMessage(&serverSockfd);
191 close(serverSockfd);
192 serverSockfd = -1;
193 }
194
FwmarkNetwork()195 FwmarkNetwork::FwmarkNetwork()
196 {
197 ListenerClient();
198 }
199
~FwmarkNetwork()200 FwmarkNetwork::~FwmarkNetwork() {}
201
ListenerClient()202 void FwmarkNetwork::ListenerClient()
203 {
204 std::thread startListener(StartListener);
205 std::string threadName = "FwmarkListen";
206 pthread_setname_np(startListener.native_handle(), threadName.c_str());
207 startListener.detach();
208 NETNATIVE_LOGI("FwmarkNetwork: StartListener");
209 }
210 } // namespace nmd
211 } // namespace OHOS
212