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 "data_receiver.h"
17 
18 #include <sys/socket.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 
22 #include "netlink_define.h"
23 #include "netnative_log_wrapper.h"
24 #include "wrapper_decoder.h"
25 
26 namespace OHOS {
27 namespace nmd {
28 using namespace NetlinkDefine;
DataReceiver(int32_t socketFd,int32_t format)29 DataReceiver::DataReceiver(int32_t socketFd, int32_t format) : socket_(socketFd), format_(format)
30 {
31     listener_ = std::make_unique<WrapperListener>(socketFd, [this](int32_t socket) { this->StartReceive(socket); });
32 }
33 
RegisterCallback(std::function<void (std::shared_ptr<NetsysEventMessage>)> callback)34 void DataReceiver::RegisterCallback(std::function<void(std::shared_ptr<NetsysEventMessage>)> callback)
35 {
36     callback_ = callback;
37 }
38 
Start()39 int32_t DataReceiver::Start()
40 {
41     return listener_->Start();
42 }
43 
Stop()44 int32_t DataReceiver::Stop()
45 {
46     return listener_->Stop();
47 }
48 
StartReceive(int32_t socket)49 void DataReceiver::StartReceive(int32_t socket)
50 {
51     socket_ = socket;
52     uid_t uid;
53     bool isRepair = format_ == NETLINK_FORMAT_BINARY_UNICAST;
54     ssize_t recvTimes = TEMP_FAILURE_RETRY(ReceiveMessage(isRepair, uid));
55     if (recvTimes < 0) {
56         return;
57     }
58 
59     bool isSuccess = false;
60     std::shared_ptr<NetsysEventMessage> message = std::make_shared<NetsysEventMessage>();
61     std::unique_ptr<WrapperDecoder> decoder = std::make_unique<WrapperDecoder>(message);
62     if (format_ == NETLINK_FORMAT_BINARY || format_ == NETLINK_FORMAT_BINARY_UNICAST) {
63         isSuccess = decoder->DecodeBinary(buffer_, recvTimes);
64     } else {
65         isSuccess = decoder->DecodeAscii(buffer_, recvTimes);
66     }
67     if (isSuccess && callback_) {
68         callback_(message);
69     }
70 }
71 
ReceiveMessage(bool isRepair,uid_t & uid)72 ssize_t DataReceiver::ReceiveMessage(bool isRepair, uid_t &uid)
73 {
74     iovec iov = {buffer_, sizeof(buffer_)};
75     sockaddr_nl addr;
76     char control[CMSG_SPACE(sizeof(ucred))];
77     msghdr hdr;
78     hdr.msg_name = &addr;
79     hdr.msg_namelen = sizeof(addr);
80     hdr.msg_iov = &iov;
81     hdr.msg_iovlen = 1;
82     hdr.msg_control = control;
83     hdr.msg_controllen = sizeof(control);
84     hdr.msg_flags = 0;
85     ssize_t count = TEMP_FAILURE_RETRY(recvmsg(socket_, &hdr, 0));
86     if (count < 0) {
87         NETNATIVE_LOGE("recvmsg message failed %{public}d, %{public}s", errno, strerror(errno));
88         return count;
89     }
90 
91     cmsghdr *cmsgHeader = CMSG_FIRSTHDR(&hdr);
92     if (cmsgHeader == nullptr || cmsgHeader->cmsg_type != SCM_CREDENTIALS) {
93         NETNATIVE_LOGE("cmsg_type is not SCM_CREDENTIALS (%{public}d)", cmsgHeader == nullptr);
94         bzero(buffer_, sizeof(buffer_));
95         errno = EIO;
96         return NetlinkResult::ERROR;
97     }
98 
99     ucred *cred = reinterpret_cast<ucred *>(CMSG_DATA(cmsgHeader));
100     uid = cred->uid;
101     if (addr.nl_pid != 0 || (isRepair && addr.nl_groups == 0)) {
102         bzero(buffer_, sizeof(buffer_));
103         errno = EIO;
104         return NetlinkResult::ERROR;
105     }
106 
107     return count;
108 }
109 } // namespace nmd
110 } // namespace OHOS
111