blob: 021c30496e565715b4679ccf16194d86c1fe2212 [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 III862275a2019-04-22 20:37:08 -070044void mock_clear()
45{
46 mock_ifaddrs = nullptr;
47 ifaddr_count = 0;
48 mock_if_nametoindex.clear();
49 mock_if_indextoname.clear();
50 mock_macs.clear();
51}
52
William A. Kennington IIIcb64b992019-04-21 18:45:07 -070053void mock_addIF(const std::string& name, int idx, const ether_addr& mac)
William A. Kennington IIIebb1ad02019-04-21 18:02:49 -070054{
55 if (idx == 0)
56 {
57 throw std::invalid_argument("Bad interface index");
58 }
59
60 mock_if_nametoindex[name] = idx;
61 mock_if_indextoname[idx] = name;
William A. Kennington IIIcb64b992019-04-21 18:45:07 -070062 mock_macs[name] = mac;
William A. Kennington IIIebb1ad02019-04-21 18:02:49 -070063}
64
Ratan Gupta8ab17922017-05-25 13:07:05 +053065void mock_addIP(const char* name, const char* addr, const char* mask,
66 unsigned int flags)
67{
Gunnar Mills57d9c502018-09-14 14:42:34 -050068 struct ifaddrs* ifaddr = &mock_ifaddr_storage[ifaddr_count].ifaddr;
Ratan Gupta8ab17922017-05-25 13:07:05 +053069
Gunnar Mills57d9c502018-09-14 14:42:34 -050070 struct sockaddr_in* in =
71 reinterpret_cast<sockaddr_in*>(&mock_ifaddr_storage[ifaddr_count].addr);
72 struct sockaddr_in* mask_in =
73 reinterpret_cast<sockaddr_in*>(&mock_ifaddr_storage[ifaddr_count].mask);
Ratan Gupta8ab17922017-05-25 13:07:05 +053074
75 in->sin_family = AF_INET;
76 in->sin_port = 0;
77 in->sin_addr.s_addr = inet_addr(addr);
78
79 mask_in->sin_family = AF_INET;
80 mask_in->sin_port = 0;
81 mask_in->sin_addr.s_addr = inet_addr(mask);
82
83 ifaddr->ifa_next = nullptr;
84 ifaddr->ifa_name = const_cast<char*>(name);
85 ifaddr->ifa_flags = flags;
86 ifaddr->ifa_addr = reinterpret_cast<struct sockaddr*>(in);
87 ifaddr->ifa_netmask = reinterpret_cast<struct sockaddr*>(mask_in);
88 ifaddr->ifa_data = nullptr;
89
90 if (ifaddr_count > 0)
91 mock_ifaddr_storage[ifaddr_count - 1].ifaddr.ifa_next = ifaddr;
92 ifaddr_count++;
93 mock_ifaddrs = &mock_ifaddr_storage[0].ifaddr;
Ratan Gupta8ab17922017-05-25 13:07:05 +053094}
95
William A. Kennington IIIcb64b992019-04-21 18:45:07 -070096extern "C" {
97
Gunnar Mills57d9c502018-09-14 14:42:34 -050098int getifaddrs(ifaddrs** ifap)
Ratan Gupta8ab17922017-05-25 13:07:05 +053099{
100 *ifap = mock_ifaddrs;
101 if (mock_ifaddrs == nullptr)
102 return -1;
103 return (0);
104}
William A. Kennington IIIebb1ad02019-04-21 18:02:49 -0700105
106unsigned if_nametoindex(const char* ifname)
107{
108 auto it = mock_if_nametoindex.find(ifname);
109 if (it == mock_if_nametoindex.end())
110 {
111 errno = ENXIO;
112 return 0;
113 }
114 return it->second;
115}
116
117char* if_indextoname(unsigned ifindex, char* ifname)
118{
119 if (ifindex == 0)
120 {
121 errno = ENXIO;
122 return NULL;
123 }
124 auto it = mock_if_indextoname.find(ifindex);
125 if (it == mock_if_indextoname.end())
126 {
127 // TODO: Return ENXIO once other code is mocked out
128 return std::strcpy(ifname, "invalid");
129 }
130 return std::strcpy(ifname, it->second.c_str());
131}
William A. Kennington IIIcb64b992019-04-21 18:45:07 -0700132
133int ioctl(int fd, unsigned long int request, ...)
134{
135 va_list vl;
136 va_start(vl, request);
137 void* data = va_arg(vl, void*);
138 va_end(vl);
139
140 if (request == SIOCGIFHWADDR)
141 {
142 auto req = reinterpret_cast<ifreq*>(data);
143 auto it = mock_macs.find(req->ifr_name);
144 if (it == mock_macs.end())
145 {
146 errno = ENXIO;
147 return -1;
148 }
149 std::memcpy(req->ifr_hwaddr.sa_data, &it->second, sizeof(it->second));
150 return 0;
151 }
152
153 static auto real_ioctl =
154 reinterpret_cast<decltype(&ioctl)>(dlsym(RTLD_NEXT, "ioctl"));
155 return real_ioctl(fd, request, data);
156}
157
158} // extern "C"