| // Copyright 2022 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef PATCHPANEL_FAKE_SYSTEM_H_ | |
| #define PATCHPANEL_FAKE_SYSTEM_H_ | |
| #include <fcntl.h> | |
| #include <linux/if_tun.h> | |
| #include <linux/sockios.h> | |
| #include <string> | |
| #include <string_view> | |
| #include <utility> | |
| #include <vector> | |
| #include <base/files/file_path.h> | |
| #include <base/files/scoped_file.h> | |
| #include <gmock/gmock.h> | |
| #include <gtest/gtest.h> | |
| #include "patchpanel/system.h" | |
| namespace patchpanel { | |
| class FakeSystem : public System { | |
| public: | |
| FakeSystem() = default; | |
| ~FakeSystem() override = default; | |
| // Capture Ioctls operations and arguments. Always succeeds. | |
| int Ioctl(int fd, ioctl_req_t request, const char* argp) override { | |
| ioctl_reqs.push_back(request); | |
| switch (request) { | |
| case SIOCBRADDBR: | |
| case SIOCBRDELBR: { | |
| ioctl_ifreq_args.push_back({std::string(argp), {}}); | |
| break; | |
| } | |
| } | |
| return 0; | |
| } | |
| int Ioctl(int fd, ioctl_req_t request, uint64_t arg) override { | |
| ioctl_reqs.push_back(request); | |
| return 0; | |
| } | |
| int Ioctl(int fd, ioctl_req_t request, struct ifreq* ifr) override { | |
| ioctl_reqs.push_back(request); | |
| switch (request) { | |
| case SIOCBRADDIF: | |
| case TUNSETIFF: | |
| case SIOCSIFADDR: | |
| case SIOCSIFNETMASK: | |
| case SIOCSIFHWADDR: | |
| case SIOCGIFFLAGS: | |
| case SIOCSIFFLAGS: { | |
| ioctl_ifreq_args.push_back({std::string(ifr->ifr_name), *ifr}); | |
| break; | |
| } | |
| } | |
| return 0; | |
| } | |
| int Ioctl(int fd, ioctl_req_t request, struct rtentry* route) override { | |
| ioctl_reqs.push_back(request); | |
| switch (request) { | |
| case SIOCADDRT: | |
| case SIOCDELRT: { | |
| ioctl_rtentry_args.push_back({"", *route}); | |
| // Copy the string pointed by rtentry.rt_dev because Add/DeleteIPv4Route | |
| // pass this value to ioctl() on the stack. | |
| if (route->rt_dev) { | |
| auto& cap = ioctl_rtentry_args.back(); | |
| cap.first = std::string(route->rt_dev); | |
| cap.second.rt_dev = const_cast<char*>(cap.first.c_str()); | |
| } | |
| break; | |
| } | |
| } | |
| return 0; | |
| } | |
| int Ioctl(int fd, ioctl_req_t request, struct in6_rtmsg* route) override { | |
| ioctl_reqs.push_back(request); | |
| return 0; | |
| } | |
| base::ScopedFD OpenTunDev() override { | |
| return base::ScopedFD(open("/dev/null", O_RDONLY | O_CLOEXEC)); | |
| } | |
| MOCK_METHOD(int, SocketPair, (int, int, int, int[2]), (override)); | |
| MOCK_METHOD(bool, | |
| SysNetSet, | |
| (SysNet, std::string_view, std::string_view), | |
| (override)); | |
| MOCK_METHOD(std::string, | |
| SysNetGet, | |
| (SysNet, std::string_view), | |
| (const, override)); | |
| MOCK_METHOD(int, IfNametoindex, (std::string_view), (override)); | |
| MOCK_METHOD(std::string, IfIndextoname, (int), (override)); | |
| MOCK_METHOD(bool, | |
| WriteConfigFile, | |
| (base::FilePath, std::string_view), | |
| (override)); | |
| bool IsEbpfEnabled() const override { return true; } | |
| std::vector<ioctl_req_t> ioctl_reqs; | |
| std::vector<std::pair<std::string, struct rtentry>> ioctl_rtentry_args; | |
| std::vector<std::pair<std::string, struct ifreq>> ioctl_ifreq_args; | |
| }; | |
| } // namespace patchpanel | |
| #endif // PATCHPANEL_FAKE_SYSTEM_H_ |