blob: 3f96e1d4229490b2c31ad401133baf1393334c0b [file] [log] [blame]
Gunnar Mills57d9c502018-09-14 14:42:34 -05001#include <arpa/inet.h>
William A. Kennington IIIcb64b992019-04-21 18:45:07 -07002#include <dlfcn.h>
Gunnar Mills57d9c502018-09-14 14:42:34 -05003#include <ifaddrs.h>
William A. Kennington IIIcb64b992019-04-21 18:45:07 -07004#include <net/ethernet.h>
Ratan Gupta8ab17922017-05-25 13:07:05 +05305#include <net/if.h>
6#include <netinet/in.h>
William A. Kennington IIIcb64b992019-04-21 18:45:07 -07007#include <sys/ioctl.h>
Gunnar Mills57d9c502018-09-14 14:42:34 -05008#include <sys/socket.h>
9#include <sys/types.h>
Ratan Gupta8ab17922017-05-25 13:07:05 +053010
William A. Kennington IIIcb64b992019-04-21 18:45:07 -070011#include <cstdarg>
William A. Kennington IIIebb1ad02019-04-21 18:02:49 -070012#include <cstring>
13#include <map>
14#include <stdexcept>
15#include <string>
16
Ratan Gupta8ab17922017-05-25 13:07:05 +053017#define MAX_IFADDRS 5
18
19int debugging = false;
20
21/* Data for mocking getifaddrs */
Gunnar Mills57d9c502018-09-14 14:42:34 -050022struct ifaddr_storage
23{
Ratan Gupta8ab17922017-05-25 13:07:05 +053024 struct ifaddrs ifaddr;
25 struct sockaddr_storage addr;
26 struct sockaddr_storage mask;
27 struct sockaddr_storage bcast;
28} mock_ifaddr_storage[MAX_IFADDRS];
29
Gunnar Mills57d9c502018-09-14 14:42:34 -050030struct ifaddrs* mock_ifaddrs = nullptr;
Ratan Gupta8ab17922017-05-25 13:07:05 +053031
32int ifaddr_count = 0;
33
34/* Stub library functions */
Gunnar Mills57d9c502018-09-14 14:42:34 -050035void freeifaddrs(ifaddrs* ifp)
Ratan Gupta8ab17922017-05-25 13:07:05 +053036{
Gunnar Mills57d9c502018-09-14 14:42:34 -050037 return;
Ratan Gupta8ab17922017-05-25 13:07:05 +053038}
39
William A. Kennington IIIebb1ad02019-04-21 18:02:49 -070040std::map<std::string, int> mock_if_nametoindex;
41std::map<int, std::string> mock_if_indextoname;
William A. Kennington IIIcb64b992019-04-21 18:45:07 -070042std::map<std::string, ether_addr> mock_macs;
William A. Kennington IIIebb1ad02019-04-21 18:02:49 -070043
William A. Kennington IIIcb64b992019-04-21 18:45:07 -070044void mock_addIF(const std::string& name, int idx, const ether_addr& mac)
William A. Kennington IIIebb1ad02019-04-21 18:02:49 -070045{
46 if (idx == 0)
47 {
48 throw std::invalid_argument("Bad interface index");
49 }
50
51 mock_if_nametoindex[name] = idx;
52 mock_if_indextoname[idx] = name;
William A. Kennington IIIcb64b992019-04-21 18:45:07 -070053 mock_macs[name] = mac;
William A. Kennington IIIebb1ad02019-04-21 18:02:49 -070054}
55
Ratan Gupta8ab17922017-05-25 13:07:05 +053056void mock_addIP(const char* name, const char* addr, const char* mask,
57 unsigned int flags)
58{
Gunnar Mills57d9c502018-09-14 14:42:34 -050059 struct ifaddrs* ifaddr = &mock_ifaddr_storage[ifaddr_count].ifaddr;
Ratan Gupta8ab17922017-05-25 13:07:05 +053060
Gunnar Mills57d9c502018-09-14 14:42:34 -050061 struct sockaddr_in* in =
62 reinterpret_cast<sockaddr_in*>(&mock_ifaddr_storage[ifaddr_count].addr);
63 struct sockaddr_in* mask_in =
64 reinterpret_cast<sockaddr_in*>(&mock_ifaddr_storage[ifaddr_count].mask);
Ratan Gupta8ab17922017-05-25 13:07:05 +053065
66 in->sin_family = AF_INET;
67 in->sin_port = 0;
68 in->sin_addr.s_addr = inet_addr(addr);
69
70 mask_in->sin_family = AF_INET;
71 mask_in->sin_port = 0;
72 mask_in->sin_addr.s_addr = inet_addr(mask);
73
74 ifaddr->ifa_next = nullptr;
75 ifaddr->ifa_name = const_cast<char*>(name);
76 ifaddr->ifa_flags = flags;
77 ifaddr->ifa_addr = reinterpret_cast<struct sockaddr*>(in);
78 ifaddr->ifa_netmask = reinterpret_cast<struct sockaddr*>(mask_in);
79 ifaddr->ifa_data = nullptr;
80
81 if (ifaddr_count > 0)
82 mock_ifaddr_storage[ifaddr_count - 1].ifaddr.ifa_next = ifaddr;
83 ifaddr_count++;
84 mock_ifaddrs = &mock_ifaddr_storage[0].ifaddr;
Ratan Gupta8ab17922017-05-25 13:07:05 +053085}
86
William A. Kennington IIIcb64b992019-04-21 18:45:07 -070087extern "C" {
88
Gunnar Mills57d9c502018-09-14 14:42:34 -050089int getifaddrs(ifaddrs** ifap)
Ratan Gupta8ab17922017-05-25 13:07:05 +053090{
91 *ifap = mock_ifaddrs;
92 if (mock_ifaddrs == nullptr)
93 return -1;
94 return (0);
95}
William A. Kennington IIIebb1ad02019-04-21 18:02:49 -070096
97unsigned if_nametoindex(const char* ifname)
98{
99 auto it = mock_if_nametoindex.find(ifname);
100 if (it == mock_if_nametoindex.end())
101 {
102 errno = ENXIO;
103 return 0;
104 }
105 return it->second;
106}
107
108char* if_indextoname(unsigned ifindex, char* ifname)
109{
110 if (ifindex == 0)
111 {
112 errno = ENXIO;
113 return NULL;
114 }
115 auto it = mock_if_indextoname.find(ifindex);
116 if (it == mock_if_indextoname.end())
117 {
118 // TODO: Return ENXIO once other code is mocked out
119 return std::strcpy(ifname, "invalid");
120 }
121 return std::strcpy(ifname, it->second.c_str());
122}
William A. Kennington IIIcb64b992019-04-21 18:45:07 -0700123
124int ioctl(int fd, unsigned long int request, ...)
125{
126 va_list vl;
127 va_start(vl, request);
128 void* data = va_arg(vl, void*);
129 va_end(vl);
130
131 if (request == SIOCGIFHWADDR)
132 {
133 auto req = reinterpret_cast<ifreq*>(data);
134 auto it = mock_macs.find(req->ifr_name);
135 if (it == mock_macs.end())
136 {
137 errno = ENXIO;
138 return -1;
139 }
140 std::memcpy(req->ifr_hwaddr.sa_data, &it->second, sizeof(it->second));
141 return 0;
142 }
143
144 static auto real_ioctl =
145 reinterpret_cast<decltype(&ioctl)>(dlsym(RTLD_NEXT, "ioctl"));
146 return real_ioctl(fd, request, data);
147}
148
149} // extern "C"