Rabbit Remote Control 0.0.30
Loading...
Searching...
No Matches
Arp.cpp
1// Author: Kang Lin <kl222@126.com>
2#include <QLoggingCategory>
3#include <QMutexLocker>
4
5#ifdef HAVE_PCAPPLUSPLUS
6#include <Packet.h>
7#include <EthLayer.h>
8#include <ArpLayer.h>
9#include <PcapLiveDeviceList.h>
10#include <PcapFilter.h>
11#ifdef _MSC_VER
12#include <SystemUtils.h>
13#include <winsock.h>
14#else
15#include <arpa/inet.h>
16#endif
17#endif
18
19#include "RabbitCommonTools.h"
20
21#include "Arp.h"
22
23static Q_LOGGING_CATEGORY(log, "WOL")
24CArp::CArp(QObject *parent) : QObject(parent)
25{
26 qDebug(log) << Q_FUNC_INFO;
27
28 m_Timer.setInterval(1000);
29 bool check = connect(&m_Timer, SIGNAL(timeout()),
30 this, SLOT(slotProcess()));
31 Q_ASSERT(check);
32}
33
34CArp::~CArp()
35{
36 qDebug(log) << Q_FUNC_INFO;
37#ifdef HAVE_PCAPPLUSPLUS
38 StopCapture();
39#endif
40}
41
42int CArp::WakeOnLan(QSharedPointer<CParameterWakeOnLan> para)
43{
44 int nRet = 0;
45
46 if(!para)
47 return -1;
48
49 if(para->GetMac().isEmpty())
50 {
51 qCritical(log) << "The mac address is empty";
52 return -2;
53 }
54#ifdef HAVE_PCAPPLUSPLUS
55 auto it = m_Para.find(para->m_Net.GetHost().toStdString());
56 if(it != m_Para.end())
57 {
58 if((*it)->bWakeOnLan) {
59 qDebug(log) << "The wake on lan is existed"
60 << (*it)->para->m_Net.GetHost();
61 return 0;
62 }
63 }
64
65 m_Wol.SetBroadcastAddress(para->GetBroadcastAddress());
66 if(para->GetPassword().isEmpty())
67 m_Wol.SendMagicPacket(para->GetMac());
68 else
69 m_Wol.SendSecureMagicPacket(para->GetMac(), para->GetPassword());
70
71#if defined(Q_OS_UNIX)
72 if(RabbitCommon::CTools::HasAdministratorPrivilege())
73 {
74 QSharedPointer<ArpRequest> aq(new ArpRequest(para));
75 if(!aq) {
76 qCritical(log) << "new ArpRequest fail";
77 return -3;
78 }
79 aq->bWakeOnLan = true;
80 nRet = GetMac(para, aq);
81 }
82#else
83 QSharedPointer<ArpRequest> aq(new ArpRequest(para));
84 if(!aq) {
85 qCritical(log) << "new ArpRequest fail";
86 return -3;
87 }
88 aq->bWakeOnLan = true;
89 nRet = GetMac(para, aq);
90#endif
91
92#else
93 qDebug(log) << "There is not pcapplusplus";
94#endif
95 return nRet;
96}
97
98#ifdef HAVE_PCAPPLUSPLUS
99int CArp::StopCapture()
100{
101 const std::vector<pcpp::PcapLiveDevice*>& devList =
102 pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
103
104 qDebug(log) << Q_FUNC_INFO;
105 for (const auto& dev : devList)
106 {
107 if(dev->captureActive())
108 dev->stopCapture();
109 if(dev->isOpened())
110 dev->close();
111 }
112 return 0;
113}
114
115int CArp::SendArpPackage(pcpp::PcapLiveDevice* device,
116 std::string szSourceIp, std::string szTargetIp)
117{
118 pcpp::MacAddress sourceMac;
119 pcpp::IPv4Address sourceIP(szSourceIp);
120 pcpp::IPv4Address targetIP(szTargetIp);
121
122 if(!device || szSourceIp.empty() || szTargetIp.empty())
123 return -1;
124 if(!pcpp::IPv4Address::isValidIPv4Address(szSourceIp))
125 sourceIP = device->getIPv4Address();
126 sourceMac = device->getMacAddress();
127
128 // create an ARP request from sourceMac and sourceIP and ask for target IP
129 pcpp::Packet arpRequest(100);
130 pcpp::MacAddress destMac(0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
131 pcpp::EthLayer ethLayer(sourceMac, destMac);
132 pcpp::ArpLayer arpLayer(pcpp::ARP_REQUEST,
133 sourceMac, destMac, sourceIP, targetIP);
134 if (!arpRequest.addLayer(&ethLayer))
135 {
136 qCritical(log) << "Couldn't build Eth layer for ARP request";
137 return -2;
138 }
139 if (!arpRequest.addLayer(&arpLayer))
140 {
141 qCritical(log) << "Couldn't build ARP layer for ARP request";
142 return -3;
143 }
144 arpRequest.computeCalculateFields();
145 // send the ARP request
146 bool bRet = device->sendPacket(&arpRequest);
147 if(bRet) return 0;
148 return -4;
149}
150
151static void cbArpPacketReceived(pcpp::RawPacket* rawPacket,
152 pcpp::PcapLiveDevice*, void* userCookie)
153{
154 using namespace pcpp;
155
156 // parse the response packet
157 Packet packet(rawPacket);
158
159 // verify that it's an ARP packet
160 // (although it must be because I set an ARP reply filter on the interface)
161 if (!packet.isPacketOfType(ARP))
162 return;
163
164 // extract the ARP layer from the packet
165 ArpLayer* arpReplyLayer = packet.getLayerOfType<ArpLayer>(true); // lookup in reverse order
166 if (arpReplyLayer == nullptr)
167 return;
168
169 // verify it's the right ARP response
170 if (arpReplyLayer->getArpHeader()->hardwareType != htons(1) /* Ethernet */
171 || arpReplyLayer->getArpHeader()->protocolType != htons(PCPP_ETHERTYPE_IP))
172 return;
173
174 // get the data from the main thread
175 CArp* pThis = reinterpret_cast<CArp*>(userCookie);
176 if(!pThis)
177 {
178 qDebug(log) << "The use data is nullptr";
179 return;
180 }
181
182 // verify the ARP response is the response for out request
183 // (and not some arbitrary ARP response)
184 std::string szTarget = arpReplyLayer->getSenderIpAddr().toString();
185 QMutexLocker lock(&pThis->m_Mutex);
186 auto it = pThis->m_Para.find(szTarget);
187 if(pThis->m_Para.end() == it)
188 return;
189
190 auto para = it.value()->para;
191 para->SetMac(arpReplyLayer->getSenderMacAddress().toString().c_str());
192 para->SetHostState(CParameterWakeOnLan::HostState::Online);
193 it.value()->nTimeout = 0;
194}
195
196void CArp::ListInterfaces()
197{
198 const std::vector<pcpp::PcapLiveDevice*>& devList =
199 pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
200
201 qDebug(log) << "Network interfaces:";
202 for (const auto& dev : devList)
203 {
204 qDebug(log) << " -> Name:" << dev->getName().c_str();
205 for(auto addr: dev->getIPAddresses())
206 qDebug(log) << " " << addr.toString().c_str();
207 }
208 return;
209}
210#endif //#ifdef HAVE_PCAPPLUSPLUS
211
212int CArp::GetMac(QSharedPointer<CParameterWakeOnLan> para
213#ifdef HAVE_PCAPPLUSPLUS
214 , QSharedPointer<ArpRequest> ar
215#endif
216 )
217{
218 qDebug(log) << Q_FUNC_INFO << para;
219 int nRet = 0;
220 if(!para) return -1;
221#ifdef HAVE_PCAPPLUSPLUS
222 std::string szSourceIp;
223 if(!para->GetNetworkInterface().isEmpty())
224 szSourceIp = para->GetNetworkInterface().toStdString();
225 std::string szTargetIp;
226 if(!para->m_Net.GetHost().isEmpty())
227 szTargetIp = para->m_Net.GetHost().toStdString();
228
229 pcpp::PcapLiveDevice* device = nullptr;
230
231 try{
232 //ListInterfaces();
233 if(!pcpp::IPv4Address::isValidIPv4Address(szTargetIp)) {
234 qCritical(log) << "Target ip is invalid:" << szTargetIp.c_str();
235 return -1;
236 }
237
238 device = pcpp::PcapLiveDeviceList::getInstance()
239 .getPcapLiveDeviceByIpOrName(szSourceIp);
240 if (device == nullptr) {
241 qCritical(log)
242 << "Couldn't find interface by provided IP address or name"
243 << szSourceIp.c_str();
244 return -2;
245 }
246
247 if(!device->isOpened())
248 if(!device->open()) {
249 qCritical(log) << "Open device fail" << szSourceIp.c_str();
250 return -3;
251 }
252
253 if(!device->captureActive()) {
254 // set a filter for the interface to intercept only ARP response packets
255 pcpp::ArpFilter arpFilter(pcpp::ARP_REPLY);
256 if (!device->setFilter(arpFilter))
257 {
258 qCritical(log) << "Couldn't set ARP filter for device";
259 return -6;
260 }
261 // start capturing. The capture is done on another thread,
262 // hence "arpPacketReceived" is running on that thread
263 device->startCapture(cbArpPacketReceived, this);
264 }
265
266 if(m_Para.end() == m_Para.find(szTargetIp)) {
267 m_Mutex.lock();
268 auto ar = QSharedPointer<ArpRequest>(new ArpRequest(para));
269 m_Para.insert(szTargetIp, ar);
270 m_Mutex.unlock();
271 }
272 nRet = SendArpPackage(device, szSourceIp, szTargetIp);
273 if(!m_Timer.isActive())
274 m_Timer.start();
275
276 return nRet;
277 } catch(std::exception e) {
278 qDebug(log) << "std::exception" << e.what();
279 } catch(...) {
280 qDebug(log) << "Exception";
281 }
282#else
283 qDebug(log) << "There is not pcapplusplus";
284#endif // #ifdef HAVE_PCAPPLUSPLUS
285 return -10;
286}
287
288void CArp::slotProcess()
289{
290 qDebug(log) << Q_FUNC_INFO;
291#ifdef HAVE_PCAPPLUSPLUS
292 m_Mutex.lock();
293 for(auto it = m_Para.begin(); it != m_Para.end();)
294 {
295 auto a = it.value();
296 auto para = a->para;
297
298 // Get mac address fail
299 if(a->tmStart.msecsTo(QTime::currentTime()) > a->nTimeout) {
300 qDebug(log) << "Get mac address fail" << para->m_Net.GetHost()
301 << a->nRepeat;
302 m_Para.erase(it);
303 it = m_Para.begin();
304 if(a->nTimeout)
305 para->SetHostState(CParameterWakeOnLan::HostState::Offline);
306 continue;
307 }
308
309 // Wake on lan
310 if(a->bWakeOnLan && a->nRepeat > 0
311 && a->tmRepeat.msecsTo(QTime::currentTime()) > para->GetInterval())
312 {
313 qDebug(log) << "Repeat wake on lan" << para->m_Net.GetHost()
314 << a->nRepeat;
315 m_Wol.SetBroadcastAddress(para->GetBroadcastAddress());
316 if(para->GetPassword().isEmpty())
317 m_Wol.SendMagicPacket(para->GetMac());
318 else
319 m_Wol.SendSecureMagicPacket(para->GetMac(), para->GetPassword());
320 }
321
322 if(a->nRepeat > 0
323 && a->tmRepeat.msecsTo(QTime::currentTime()) > para->GetInterval())
324 {
325 qDebug(log) << "Repeat get mac address" << para->m_Net.GetHost()
326 << a->nRepeat;
327 GetMac(para);
328 }
329
330 a->tmRepeat = QTime::currentTime();
331 a->nRepeat--;
332 it++;
333 }
334 m_Mutex.unlock();
335 if(m_Para.isEmpty()) {
336 m_Timer.stop();
337 StopCapture();
338 }
339#endif
340}
Definition Arp.h:21
bool SendMagicPacket(const QString &szMac, uint16_t portNum=9)
SendMagicPacket.
bool SendSecureMagicPacket(const QString &szMac, const QString &szPassword, uint16_t portNum=9)
SendSecureMagicPacket.