feature: add ipv4 conflict check function
This commit is contained in:
parent
1033455505
commit
2ca22019a8
|
@ -8,6 +8,7 @@ HEADERS += \
|
|||
$$PWD/ksimplenm.h \
|
||||
$$PWD/kylin-dbus-interface.h \
|
||||
$$PWD/kylin-network-interface.h \
|
||||
$$PWD/kylinipv4arping.h \
|
||||
$$PWD/sysdbusregister.h \
|
||||
$$PWD/utils.h \
|
||||
$$PWD/wifi-auth-thread.h
|
||||
|
@ -18,6 +19,9 @@ SOURCES += \
|
|||
$$PWD/ksimplenm.cpp \
|
||||
$$PWD/kylin-dbus-interface.cpp \
|
||||
$$PWD/kylin-network-interface.c \
|
||||
$$PWD/kylinipv4arping.cpp \
|
||||
$$PWD/sysdbusregister.cpp \
|
||||
$$PWD/utils.cpp \
|
||||
$$PWD/wifi-auth-thread.cpp
|
||||
|
||||
DISTFILES +=
|
||||
|
|
|
@ -0,0 +1,426 @@
|
|||
#include "kylinipv4arping.h"
|
||||
|
||||
#include <sys/times.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#define FINAL_PACKS 2
|
||||
|
||||
__attribute__((const)) static inline size_t sll_len(const size_t halen)
|
||||
{
|
||||
struct sockaddr_ll unused;
|
||||
const size_t len = offsetof(struct sockaddr_ll, sll_addr) + halen;
|
||||
|
||||
if (len < sizeof(unused))
|
||||
return sizeof(unused);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
KyIpv4Arping::KyIpv4Arping(QString ifaceName, QString ipAddress, int retryCount, int timeout, QObject *parent) : QObject(parent)
|
||||
{
|
||||
m_ifaceName = ifaceName;
|
||||
m_ipv4Address = ipAddress;
|
||||
m_retryCount = retryCount;
|
||||
m_timeout = timeout;
|
||||
|
||||
memset(&m_srcAddress, 0, sizeof(m_srcAddress));
|
||||
}
|
||||
|
||||
KyIpv4Arping::~KyIpv4Arping()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void KyIpv4Arping::monoGetTime (struct timespec *ts)
|
||||
{
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
if (clock_gettime (CLOCK_MONOTONIC, ts))
|
||||
#endif
|
||||
{
|
||||
static long freq = 0;
|
||||
if (freq == 0)
|
||||
freq = sysconf (_SC_CLK_TCK);
|
||||
|
||||
struct tms dummy;
|
||||
clock_t t = times (&dummy);
|
||||
ts->tv_sec = t / freq;
|
||||
ts->tv_nsec = (t % freq) * (1000000000 / freq);
|
||||
}
|
||||
}
|
||||
|
||||
void KyIpv4Arping::saveMacAddress(const uint8_t *ptr, size_t len)
|
||||
{
|
||||
int index;
|
||||
char macAddress[64] = {0};
|
||||
|
||||
for (index = 0; index < len; index++) {
|
||||
snprintf(&macAddress[strlen(macAddress)], sizeof(macAddress) - strlen(macAddress), "%02X", ptr[index]);
|
||||
if (index != len - 1) {
|
||||
snprintf(&macAddress[strlen(macAddress)], sizeof(macAddress) - strlen(macAddress), "%s", ":");
|
||||
}
|
||||
}
|
||||
|
||||
m_conflictMac = QString(macAddress);
|
||||
return ;
|
||||
}
|
||||
|
||||
void KyIpv4Arping::setConflictFlag(bool isConflict)
|
||||
{
|
||||
m_ipConflict = isConflict;
|
||||
}
|
||||
|
||||
int KyIpv4Arping::sendIpv4Packet()
|
||||
{
|
||||
int err;
|
||||
unsigned char buf[256];
|
||||
struct arphdr *ah = (struct arphdr *)buf;
|
||||
unsigned char *p = (unsigned char *)(ah + 1);
|
||||
struct sockaddr_ll *p_me = (struct sockaddr_ll *)&(m_me);
|
||||
struct sockaddr_ll *p_he = (struct sockaddr_ll *)&(m_he);
|
||||
|
||||
ah->ar_hrd = htons(p_me->sll_hatype);
|
||||
if (ah->ar_hrd == htons(ARPHRD_FDDI))
|
||||
ah->ar_hrd = htons(ARPHRD_ETHER);
|
||||
ah->ar_pro = htons(ETH_P_IP);
|
||||
ah->ar_hln = p_me->sll_halen;
|
||||
ah->ar_pln = 4;
|
||||
ah->ar_op = htons(ARPOP_REQUEST);
|
||||
|
||||
memcpy(p, &p_me->sll_addr, ah->ar_hln);
|
||||
p += p_me->sll_halen;
|
||||
|
||||
qWarning()<<"m_src address:" << inet_ntoa(m_srcAddress);
|
||||
memcpy(p, &m_srcAddress, 4);
|
||||
p += 4;
|
||||
|
||||
memcpy(p, &p_he->sll_addr, ah->ar_hln);
|
||||
p += ah->ar_hln;
|
||||
|
||||
memcpy(p, &m_destAddress, 4);
|
||||
p += 4;
|
||||
|
||||
err = sendto(m_ipv4Socket, buf, p - buf, 0, (struct sockaddr *)p_he, sll_len(ah->ar_hln));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int KyIpv4Arping::ipv4PacketProcess(unsigned char *buf, ssize_t len, struct sockaddr_ll *from)
|
||||
{
|
||||
struct arphdr *ah = (struct arphdr *)buf;
|
||||
unsigned char *p = (unsigned char *)(ah + 1);
|
||||
struct in_addr src_ip, dst_ip;
|
||||
|
||||
/* Filter out wild packets */
|
||||
if (from->sll_pkttype != PACKET_HOST &&
|
||||
from->sll_pkttype != PACKET_BROADCAST &&
|
||||
from->sll_pkttype != PACKET_MULTICAST)
|
||||
return 0;
|
||||
|
||||
/* Only these types are recognised */
|
||||
if (ah->ar_op != htons(ARPOP_REQUEST) &&
|
||||
ah->ar_op != htons(ARPOP_REPLY))
|
||||
return 0;
|
||||
|
||||
/* ARPHRD check and this darned FDDI hack here :-( */
|
||||
if (ah->ar_hrd != htons(from->sll_hatype) &&
|
||||
(from->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
|
||||
return 0;
|
||||
|
||||
/* Protocol must be IP. */
|
||||
if (ah->ar_pro != htons(ETH_P_IP))
|
||||
return 0;
|
||||
if (ah->ar_pln != 4)
|
||||
return 0;
|
||||
if (ah->ar_hln != ((struct sockaddr_ll *)&m_me)->sll_halen)
|
||||
return 0;
|
||||
|
||||
if (len < (ssize_t) sizeof(*ah) + 2 * (4 + ah->ar_hln))
|
||||
return 0;
|
||||
|
||||
memcpy(&src_ip, p + ah->ar_hln, 4);
|
||||
memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4);
|
||||
/*
|
||||
* DAD packet was:
|
||||
* src_ip = 0 (or some src)
|
||||
* src_hw = ME
|
||||
* dst_ip = tested address
|
||||
* dst_hw = <unspec>
|
||||
*
|
||||
* We fail, if receive request/reply with:
|
||||
* src_ip = tested_address
|
||||
* src_hw != ME
|
||||
* if src_ip in request was not zero, check
|
||||
* also that it matches to dst_ip, otherwise
|
||||
* dst_ip/dst_hw do not matter.
|
||||
*/
|
||||
if (src_ip.s_addr != m_destAddress.s_addr)
|
||||
return 0;
|
||||
|
||||
if (memcmp(p, ((struct sockaddr_ll *)&m_me)->sll_addr,
|
||||
((struct sockaddr_ll *)&m_me)->sll_halen) == 0)
|
||||
return 0;
|
||||
|
||||
saveMacAddress(p, ah->ar_hln);
|
||||
setConflictFlag(true);
|
||||
|
||||
return FINAL_PACKS;
|
||||
}
|
||||
|
||||
int KyIpv4Arping::ipv4EventLoop()
|
||||
{
|
||||
int rc = -1;
|
||||
int ret;
|
||||
int index;
|
||||
int exit_loop = 0;
|
||||
ssize_t bytes;
|
||||
|
||||
int tfd;
|
||||
struct pollfd pfds[POLLFD_COUNT];
|
||||
|
||||
struct itimerspec timerfd_vals;
|
||||
timerfd_vals.it_interval.tv_sec = m_timeout,
|
||||
timerfd_vals.it_interval.tv_nsec = 0,
|
||||
timerfd_vals.it_value.tv_sec = m_timeout,
|
||||
timerfd_vals.it_value.tv_nsec = 0;
|
||||
|
||||
uint64_t exp;
|
||||
uint64_t total_expires = 1;
|
||||
|
||||
unsigned char packet[4096];
|
||||
struct sockaddr_storage from = { 0 };
|
||||
socklen_t addr_len = sizeof(from);
|
||||
|
||||
/* timerfd */
|
||||
tfd = timerfd_create(CLOCK_MONOTONIC, 0);
|
||||
if (tfd == -1) {
|
||||
qWarning()<<"[KyIpv4Arping]" << "timerfd_create failed, errno" << errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (timerfd_settime(tfd, 0, &timerfd_vals, NULL)) {
|
||||
close(tfd);
|
||||
qWarning()<<"[KyIpv4Arping]" << "timerfd_settime failed, errno" << errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pfds[POLLFD_TIMER].fd = tfd;
|
||||
pfds[POLLFD_TIMER].events = POLLIN | POLLERR | POLLHUP;
|
||||
|
||||
/* socket */
|
||||
pfds[POLLFD_SOCKET].fd = m_ipv4Socket;
|
||||
pfds[POLLFD_SOCKET].events = POLLIN | POLLERR | POLLHUP;
|
||||
sendIpv4Packet();
|
||||
|
||||
while (!exit_loop) {
|
||||
ret = poll(pfds, POLLFD_COUNT, -1);
|
||||
if (ret <= 0) {
|
||||
if (errno == EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (errno) {
|
||||
qWarning()<<"[KyIpv4Arping]" <<"poll failed, errno" << errno;
|
||||
}
|
||||
|
||||
exit_loop = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (index = 0; index < POLLFD_COUNT; index++) {
|
||||
if (pfds[index].revents == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (index) {
|
||||
case POLLFD_TIMER:
|
||||
bytes = read(tfd, &exp, sizeof(uint64_t));
|
||||
if (bytes != sizeof(uint64_t)) {
|
||||
qWarning() << "could not read timerfd";
|
||||
continue;
|
||||
}
|
||||
|
||||
total_expires += exp;
|
||||
if (0 < m_retryCount && (uint64_t)m_retryCount < total_expires) {
|
||||
exit_loop = 1;
|
||||
rc = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
sendIpv4Packet();
|
||||
break;
|
||||
case POLLFD_SOCKET:
|
||||
bytes = recvfrom(m_ipv4Socket, packet, sizeof(packet), 0,
|
||||
(struct sockaddr *)&from, &addr_len);
|
||||
if (bytes < 0) {
|
||||
qWarning() << "recvfrom function failed, errno" << errno;
|
||||
continue;
|
||||
}
|
||||
if (ipv4PacketProcess(packet, bytes, (struct sockaddr_ll *)&from) == FINAL_PACKS) {
|
||||
exit_loop = 1;
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qWarning()<<"the fd index is undefine" << index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(tfd);
|
||||
freeifaddrs(m_ifa0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int KyIpv4Arping::checkIfflags(unsigned int ifflags)
|
||||
{
|
||||
if (!(ifflags & IFF_UP)) {
|
||||
qWarning()<<"the iface" << m_ifaceName <<" is down.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ifflags & (IFF_NOARP | IFF_LOOPBACK)) {
|
||||
qWarning()<< "Interface" << m_ifaceName << "is not ARPable.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int KyIpv4Arping::checkDevice()
|
||||
{
|
||||
int rc;
|
||||
struct ifaddrs *ifa;
|
||||
int n = 0;
|
||||
|
||||
rc = getifaddrs(&m_ifa0);
|
||||
if (rc < 0) {
|
||||
qWarning()<<"[KyIpv4Arping]" <<"get iface address failed, erron"<< errno;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
for (ifa = m_ifa0; ifa; ifa = ifa->ifa_next) {
|
||||
if (!ifa->ifa_addr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ifa->ifa_addr->sa_family != AF_PACKET) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!m_ifaceName.isEmpty()
|
||||
&& (NULL != ifa->ifa_name)
|
||||
&& strcmp(ifa->ifa_name, m_ifaceName.toUtf8())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (checkIfflags(ifa->ifa_flags) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!((struct sockaddr_ll *)ifa->ifa_addr)->sll_halen) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ifa->ifa_broadaddr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_ifa = ifa;
|
||||
|
||||
if (n++)
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == 1 && m_ifa) {
|
||||
m_ifindex = if_nametoindex(m_ifa->ifa_name);
|
||||
if (!m_ifindex) {
|
||||
qWarning()<<"[KyIpv4Arping]" <<"if_nametoindex is invalid";
|
||||
freeifaddrs(m_ifa0);
|
||||
return -1;
|
||||
}
|
||||
m_ifaceName = m_ifa->ifa_name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
freeifaddrs(m_ifa0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void KyIpv4Arping::findBroadcastAddress()
|
||||
{
|
||||
struct sockaddr_ll *he = (struct sockaddr_ll *)&(m_he);
|
||||
|
||||
if (m_ifa) {
|
||||
struct sockaddr_ll *sll =
|
||||
(struct sockaddr_ll *)m_ifa->ifa_broadaddr;
|
||||
|
||||
if (sll->sll_halen == he->sll_halen) {
|
||||
memcpy(he->sll_addr, sll->sll_addr, he->sll_halen);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
qWarning()<<"[KyIpv4Arping]" <<"using default broadcast address.";
|
||||
|
||||
memset(he->sll_addr, -1, he->sll_halen);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int KyIpv4Arping::ipv4ConflictCheck()
|
||||
{
|
||||
int ret = checkDevice();
|
||||
if (ret < 0) {
|
||||
qWarning()<<"[KyIpv4Arping]"<<"the device is invalid" << m_ifaceName;
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_ipv4Socket = socket(PF_PACKET, SOCK_DGRAM, 0);
|
||||
if (m_ipv4Socket < 0) {
|
||||
qWarning()<<"[KyIpv4Arping]" << "create ipv4 socket failed, errno" << errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
inet_aton(m_ipv4Address.toUtf8(), &m_destAddress);
|
||||
m_destAddressFamily = AF_INET;
|
||||
|
||||
((struct sockaddr_ll *)&m_me)->sll_family = AF_PACKET;
|
||||
((struct sockaddr_ll *)&m_me)->sll_ifindex = m_ifindex;
|
||||
((struct sockaddr_ll *)&m_me)->sll_protocol = htons(ETH_P_ARP);
|
||||
|
||||
ret = bind(m_ipv4Socket, (struct sockaddr *)&m_me, sizeof(m_me));
|
||||
if (ret < 0) {
|
||||
qWarning()<<"[KyIpv4Arping]" <<"ipv4 socket bind failed, errno"<< errno;
|
||||
close(m_ipv4Socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
socklen_t alen = sizeof(m_me);
|
||||
ret = getsockname(m_ipv4Socket, (struct sockaddr *)&m_me, &alen);
|
||||
if (ret < 0) {
|
||||
qWarning()<<"[KyIpv4Arping]" <<"ipv4 get socket name failed, errno" << errno;
|
||||
close(m_ipv4Socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (((struct sockaddr_ll *)&m_me)->sll_halen == 0) {
|
||||
qWarning()<<"[KyIpv4Arping]" <<"the iface"<< m_ifaceName <<" is not suitable for arp";
|
||||
close(m_ipv4Socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_he = m_me;
|
||||
|
||||
findBroadcastAddress();
|
||||
|
||||
ret = ipv4EventLoop();
|
||||
close(m_ipv4Socket);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
#ifndef KYLIN_IPV4_ARPING
|
||||
#define KYLIN_IPV4_ARPING
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <net/if.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
#include <QObject>
|
||||
|
||||
enum {
|
||||
POLLFD_TIMER = 0,
|
||||
POLLFD_SOCKET,
|
||||
POLLFD_COUNT
|
||||
};
|
||||
|
||||
class KyIpv4Arping : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit KyIpv4Arping(QString ifaceName, QString ipAddress, int retryCount=3, int timeout=1, QObject *parent = nullptr);
|
||||
~KyIpv4Arping();
|
||||
|
||||
public:
|
||||
bool ipv4IsConflict() {
|
||||
return m_ipConflict;
|
||||
}
|
||||
|
||||
QString getMacAddress() {
|
||||
return m_conflictMac;
|
||||
}
|
||||
|
||||
int ipv4ConflictCheck();
|
||||
|
||||
private:
|
||||
void monoGetTime(struct timespec *ts);
|
||||
void saveMacAddress(const uint8_t *ptr, size_t len);
|
||||
void findBroadcastAddress();
|
||||
int checkDevice();
|
||||
int checkIfflags(unsigned int ifflags);
|
||||
|
||||
int sendIpv4Packet();
|
||||
int ipv4EventLoop();
|
||||
int ipv4PacketProcess(unsigned char *buf, ssize_t len, struct sockaddr_ll *from);
|
||||
|
||||
void setConflictFlag(bool isConflict);
|
||||
|
||||
private:
|
||||
struct in_addr m_srcAddress;
|
||||
struct in_addr m_destAddress;
|
||||
int m_destAddressFamily;
|
||||
|
||||
struct sockaddr_storage m_me;
|
||||
struct sockaddr_storage m_he;
|
||||
int m_ipv4Socket = 0;
|
||||
|
||||
QString m_ifaceName;
|
||||
int m_ifindex;
|
||||
struct ifaddrs *m_ifa;
|
||||
struct ifaddrs *m_ifa0;
|
||||
|
||||
QString m_ipv4Address;
|
||||
int m_retryCount;
|
||||
int m_timeout;
|
||||
|
||||
bool m_ipConflict = false;
|
||||
QString m_conflictMac = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue