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