• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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