• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "vpn_interface.h"
17 
18 #include <cerrno>
19 #include <fcntl.h>
20 #include <sys/socket.h>
21 #include <sys/types.h>
22 #include <sys/un.h>
23 #include <unistd.h>
24 
25 #include "net_manager_constants.h"
26 #include "netmgr_ext_log_wrapper.h"
27 #include "securec.h"
28 
29 namespace OHOS {
30 namespace NetManagerStandard {
31 
32 namespace {
33 constexpr int32_t CONNECT_TIMEOUT = 1;
34 constexpr int32_t INVALID_FD = -1;
FdReadyHandle(int32_t & sockfd,fd_set & rset,fd_set & wset,uint32_t flags)35 int32_t FdReadyHandle(int32_t &sockfd, fd_set &rset, fd_set &wset, uint32_t flags)
36 {
37     int32_t result = NETMANAGER_EXT_ERR_INTERNAL;
38     socklen_t len = sizeof(result);
39     if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
40         if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &result, &len) < 0) {
41             NETMGR_EXT_LOG_E("getsockopt error: %{public}d", errno);
42             return NETMANAGER_EXT_ERR_INTERNAL;
43         }
44     } else {
45         NETMGR_EXT_LOG_E("select error: sockfd not set");
46         return NETMANAGER_EXT_ERR_INTERNAL;
47     }
48 
49     if (result != NETMANAGER_EXT_SUCCESS) { // connect failed.
50         NETMGR_EXT_LOG_E("connect failed. error: %{public}d", result);
51         return NETMANAGER_EXT_ERR_INTERNAL;
52     } else {                           // connect success.
53         fcntl(sockfd, F_SETFL, flags); /* restore file status flags */
54         NETMGR_EXT_LOG_I("connect success.");
55         return NETMANAGER_EXT_SUCCESS;
56     }
57 }
58 } // namespace
59 
ConnectControl(int32_t sockfd,int32_t nsec)60 int32_t VpnInterface::ConnectControl(int32_t sockfd, int32_t nsec)
61 {
62     uint32_t flags = static_cast<uint32_t>(fcntl(sockfd, F_GETFL, 0));
63     fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
64 
65     /* EINPROGRESS - Indicates that the connection establishment has been started but is not complete */
66     sockaddr_un serverPath = {AF_UNIX, "/dev/unix/socket/tunfd"};
67 #ifdef SUPPORT_SYSVPN
68     if (isSupportMultiVpn_) {
69         serverPath = {AF_UNIX, "/dev/unix/socket/multivpnfd"};
70     }
71 #endif // SUPPORT_SYSVPN
72     int32_t ret = connect(sockfd, reinterpret_cast<const sockaddr *>(&serverPath), sizeof(serverPath));
73     if ((ret < 0) && (errno != EINPROGRESS)) {
74         NETMGR_EXT_LOG_E("connect error: %{public}d", errno);
75         return NETMANAGER_EXT_ERR_INTERNAL;
76     } else if (ret == 0) {
77         /* connect completed immediately, This can happen when the server is on the client's host*/
78         fcntl(sockfd, F_SETFL, flags); /* restore file status flags */
79         NETMGR_EXT_LOG_I("connect success.");
80         return NETMANAGER_EXT_SUCCESS;
81     }
82 
83     fd_set rset;
84     FD_ZERO(&rset);
85     FD_SET(sockfd, &rset);
86     fd_set wset = rset;
87 
88     timeval tval;
89     tval.tv_sec = nsec;
90     tval.tv_usec = 0;
91     ret = select(sockfd + 1, &rset, &wset, NULL, nsec ? &tval : NULL);
92     if (ret < 0) { // select error.
93         NETMGR_EXT_LOG_E("select error: %{public}d", errno);
94         return NETMANAGER_EXT_ERR_INTERNAL;
95     } else if (ret == 0) { // timeout
96         NETMGR_EXT_LOG_E("connect timeout.");
97         return NETMANAGER_EXT_ERR_INTERNAL;
98     } else { // fd ready
99         return FdReadyHandle(sockfd, rset, wset, flags);
100     }
101 }
102 
RecvMsgFromUnixServer(int32_t sockfd)103 int32_t VpnInterface::RecvMsgFromUnixServer(int32_t sockfd)
104 {
105     char buf[1] = {0};
106     iovec iov = {
107         .iov_base = buf,
108         .iov_len = sizeof(buf),
109     };
110     union {
111         cmsghdr align;
112         char cmsg[CMSG_SPACE(sizeof(int32_t))];
113     } cmsgu;
114     if (memset_s(cmsgu.cmsg, sizeof(cmsgu.cmsg), 0, sizeof(cmsgu.cmsg)) != EOK) {
115         NETMGR_EXT_LOG_E("memset_s cmsgu.cmsg failed!");
116         return NETMANAGER_EXT_ERR_INTERNAL;
117     }
118     msghdr message;
119     if (memset_s(&message, sizeof(message), 0, sizeof(message)) != EOK) {
120         NETMGR_EXT_LOG_E("memset_s message failed!");
121         return NETMANAGER_EXT_ERR_INTERNAL;
122     }
123     message.msg_iov = &iov;
124     message.msg_iovlen = 1;
125     message.msg_control = cmsgu.cmsg;
126     message.msg_controllen = sizeof(cmsgu.cmsg);
127     if (recvmsg(sockfd, &message, 0) < 0) {
128         NETMGR_EXT_LOG_E("recvmsg msg error: %{public}d", errno);
129         return NETMANAGER_EXT_ERR_INTERNAL;
130     }
131 
132     cmsghdr *cmsgh = CMSG_FIRSTHDR(&message);
133     if (cmsgh == nullptr) {
134         NETMGR_EXT_LOG_E("cmsgh is nullptr");
135         return NETMANAGER_EXT_ERR_INTERNAL;
136     }
137     if (cmsgh->cmsg_level != SOL_SOCKET || cmsgh->cmsg_type != SCM_RIGHTS ||
138         cmsgh->cmsg_len != CMSG_LEN(sizeof(int32_t))) {
139         NETMGR_EXT_LOG_E("cmsg_level: [%{public}d], cmsg_type: [%{public}d], cmsg_len: [%{public}d]", cmsgh->cmsg_level,
140                          cmsgh->cmsg_type, cmsgh->cmsg_len);
141         return NETMANAGER_EXT_ERR_INTERNAL;
142     }
143 
144     if (memcpy_s(&tunFd_, sizeof(tunFd_), CMSG_DATA(cmsgh), sizeof(tunFd_)) != EOK) {
145         NETMGR_EXT_LOG_E("memcpy_s cmsgu failed!");
146         return NETMANAGER_EXT_ERR_INTERNAL;
147     }
148     return NETMANAGER_EXT_SUCCESS;
149 }
150 
GetVpnInterfaceFd()151 int32_t VpnInterface::GetVpnInterfaceFd()
152 {
153     CloseVpnInterfaceFd();
154     int32_t sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
155     if (sockfd < 0) {
156         NETMGR_EXT_LOG_E("create unix SOCK_STREAM socket error: %{public}d", errno);
157         return INVALID_FD;
158     }
159 
160     if (ConnectControl(sockfd, CONNECT_TIMEOUT) != NETMANAGER_EXT_SUCCESS) {
161         close(sockfd);
162         NETMGR_EXT_LOG_E("connect error: %{public}d", errno);
163         return INVALID_FD;
164     }
165 
166     if (RecvMsgFromUnixServer(sockfd) != NETMANAGER_EXT_SUCCESS) {
167         close(sockfd);
168         return INVALID_FD;
169     }
170 
171     close(sockfd);
172     NETMGR_EXT_LOG_I("receive tun device fd: [%{public}d]", tunFd_.load());
173     return tunFd_;
174 }
175 
CloseVpnInterfaceFd()176 void VpnInterface::CloseVpnInterfaceFd()
177 {
178     if (tunFd_ > 0) {
179         NETMGR_EXT_LOG_I("close tunfd[%{public}d] of vpn interface", tunFd_.load());
180         close(tunFd_);
181         tunFd_ = 0;
182     }
183 }
184 
185 #ifdef SUPPORT_SYSVPN
SetSupportMultiVpn(bool isSupportMultiVpn)186 void VpnInterface::SetSupportMultiVpn(bool isSupportMultiVpn)
187 {
188     isSupportMultiVpn_ = isSupportMultiVpn;
189 }
190 #endif // SUPPORT_SYSVPN
191 
192 } // namespace NetManagerStandard
193 } // namespace OHOS
194