|
|
|
extern "C" {
|
|
|
|
#include <netlink/socket.h>
|
|
|
|
#include <linux/netlink.h>
|
|
|
|
#include <netlink/netlink.h>
|
|
|
|
#include <netlink/route/link.h>
|
|
|
|
#include <netlink/route/neighbour.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "neighbor.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include <iostream>
|
|
|
|
#include <QStringList>
|
|
|
|
|
|
|
|
#define BUFLEN 65535
|
|
|
|
#define MACBUFLEN 18
|
|
|
|
#define IPBUFLEN 64
|
|
|
|
#define EMPTY_MAC "00:00:00:00:00:00"
|
|
|
|
|
|
|
|
Neighbor::Neighbor(QString interface) :
|
|
|
|
QObject(0),
|
|
|
|
m_interface(interface)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Neighbor::macOfIP(QString ip) const {
|
|
|
|
struct nl_sock *sock = NULL;
|
|
|
|
struct rtnl_neigh *neigh = NULL;
|
|
|
|
struct nl_cache *neigh_cache, *link_cache = NULL;
|
|
|
|
struct nl_dump_params params;
|
|
|
|
char buf[BUFLEN] = {0};
|
|
|
|
QByteArray ipArray = ip.toLatin1();
|
|
|
|
char *ipAddr = ipArray.data();
|
|
|
|
|
|
|
|
memset(¶ms, 0, sizeof(struct nl_dump_params));
|
|
|
|
|
|
|
|
params.dp_type = NL_DUMP_LINE;
|
|
|
|
params.dp_fd = NULL;
|
|
|
|
params.dp_buf = buf;
|
|
|
|
params.dp_buflen = BUFLEN;
|
|
|
|
|
|
|
|
if(!(sock = Utils::connect())) {
|
|
|
|
return QString(EMPTY_MAC);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!(Utils::alloc_neigh_cache(sock, &neigh_cache))) {
|
|
|
|
nl_socket_free(sock);
|
|
|
|
return QString(EMPTY_MAC);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!(Utils::alloc_link_cache(sock, &link_cache))) {
|
|
|
|
nl_cache_free(neigh_cache);
|
|
|
|
nl_socket_free(sock);
|
|
|
|
return QString(EMPTY_MAC);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!(neigh = rtnl_neigh_alloc())) {
|
|
|
|
nl_cache_free(link_cache);
|
|
|
|
nl_cache_free(neigh_cache);
|
|
|
|
nl_socket_free(sock);
|
|
|
|
return QString(EMPTY_MAC);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!m_interface.isEmpty()) {
|
|
|
|
QByteArray interfaceArray = m_interface.toLatin1();
|
|
|
|
char *interface = interfaceArray.data();
|
|
|
|
|
|
|
|
int ival = 0;
|
|
|
|
|
|
|
|
if(!(ival = rtnl_link_name2i(link_cache, interface))) {
|
|
|
|
std::cerr << "Link " << interface << " does not exist" << std::endl;
|
|
|
|
nl_cache_free(link_cache);
|
|
|
|
nl_cache_free(neigh_cache);
|
|
|
|
rtnl_neigh_put(neigh);
|
|
|
|
nl_socket_free(sock);
|
|
|
|
return QString(EMPTY_MAC);
|
|
|
|
}
|
|
|
|
|
|
|
|
rtnl_neigh_set_ifindex(neigh, ival);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct nl_addr *addr = NULL;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if((err = nl_addr_parse(ipAddr, rtnl_neigh_get_family(neigh), &addr)) < 0) {
|
|
|
|
std::cerr << "Unable to parse address \"" << ipAddr << "\": " << nl_geterror(err) << std::endl;
|
|
|
|
nl_cache_free(link_cache);
|
|
|
|
nl_cache_free(neigh_cache);
|
|
|
|
rtnl_neigh_put(neigh);
|
|
|
|
nl_socket_free(sock);
|
|
|
|
return QString(EMPTY_MAC);
|
|
|
|
}
|
|
|
|
|
|
|
|
if((err = rtnl_neigh_set_dst(neigh, addr)) < 0) {
|
|
|
|
std::cerr << "Unable to set local address \"" << ipAddr << "\": " << nl_geterror(err) << std::endl;
|
|
|
|
nl_addr_put(addr);
|
|
|
|
nl_cache_free(link_cache);
|
|
|
|
nl_cache_free(neigh_cache);
|
|
|
|
rtnl_neigh_put(neigh);
|
|
|
|
nl_socket_free(sock);
|
|
|
|
return QString(EMPTY_MAC);
|
|
|
|
}
|
|
|
|
|
|
|
|
nl_addr_put(addr);
|
|
|
|
|
|
|
|
memset(buf, 0, BUFLEN);
|
|
|
|
|
|
|
|
char mac[MACBUFLEN] = {0};
|
|
|
|
memset(mac, 0, MACBUFLEN);
|
|
|
|
|
|
|
|
nl_cache_dump_filter(neigh_cache, ¶ms, OBJ_CAST(neigh));
|
|
|
|
|
|
|
|
unsigned short count = 0;
|
|
|
|
char *rest = NULL;
|
|
|
|
char *field = strtok_r(buf, " ", &rest);
|
|
|
|
|
|
|
|
while(field != NULL) {
|
|
|
|
++count;
|
|
|
|
|
|
|
|
if(count == 5) {
|
|
|
|
if(strstr(field, ":") != NULL) {
|
|
|
|
memcpy(mac, field, MACBUFLEN - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
field = strtok_r(NULL, " ", &rest);
|
|
|
|
}
|
|
|
|
|
|
|
|
rtnl_neigh_put(neigh);
|
|
|
|
nl_cache_free(link_cache);
|
|
|
|
nl_cache_free(neigh_cache);
|
|
|
|
nl_socket_free(sock);
|
|
|
|
|
|
|
|
if(mac == NULL || count == 0) {
|
|
|
|
return QString(EMPTY_MAC);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString macStr = mac;
|
|
|
|
|
|
|
|
return macStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList Neighbor::list(QString interfaceString) {
|
|
|
|
struct nl_sock *sock = NULL;
|
|
|
|
struct rtnl_neigh *neigh = NULL;
|
|
|
|
struct nl_cache *neigh_cache, *link_cache = NULL;
|
|
|
|
struct nl_dump_params params;
|
|
|
|
char buf[BUFLEN];
|
|
|
|
char ip[IPBUFLEN];
|
|
|
|
QStringList neighborList;
|
|
|
|
|
|
|
|
memset(¶ms, 0, sizeof(struct nl_dump_params));
|
|
|
|
|
|
|
|
params.dp_type = NL_DUMP_LINE;
|
|
|
|
params.dp_fd = NULL;
|
|
|
|
params.dp_buf = buf;
|
|
|
|
params.dp_buflen = BUFLEN;
|
|
|
|
|
|
|
|
if(!(sock = Utils::connect())) {
|
|
|
|
return QStringList();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!(Utils::alloc_link_cache(sock, &link_cache))) {
|
|
|
|
nl_socket_free(sock);
|
|
|
|
return QStringList();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!(Utils::alloc_neigh_cache(sock, &neigh_cache))) {
|
|
|
|
nl_cache_free(link_cache);
|
|
|
|
nl_socket_free(sock);
|
|
|
|
return QStringList();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!(neigh = rtnl_neigh_alloc())) {
|
|
|
|
std::cerr << "could not allocate neighbor" << std::endl;
|
|
|
|
nl_cache_free(neigh_cache);
|
|
|
|
nl_cache_free(link_cache);
|
|
|
|
nl_socket_free(sock);
|
|
|
|
return QStringList();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!interfaceString.isEmpty()) {
|
|
|
|
QByteArray interfaceArray = interfaceString.toLatin1();
|
|
|
|
char *interface = interfaceArray.data();
|
|
|
|
int ival = 0;
|
|
|
|
|
|
|
|
if(!(ival = rtnl_link_name2i(link_cache, interface))) {
|
|
|
|
std::cerr << "Link " << interface << " does not exist" << std::endl;
|
|
|
|
nl_cache_free(link_cache);
|
|
|
|
nl_cache_free(neigh_cache);
|
|
|
|
rtnl_neigh_put(neigh);
|
|
|
|
nl_socket_free(sock);
|
|
|
|
return QStringList();
|
|
|
|
}
|
|
|
|
|
|
|
|
rtnl_neigh_set_ifindex(neigh, ival);
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(buf, 0, BUFLEN);
|
|
|
|
memset(ip, 0, IPBUFLEN);
|
|
|
|
|
|
|
|
nl_cache_dump_filter(neigh_cache, ¶ms, OBJ_CAST(neigh));
|
|
|
|
|
|
|
|
QString bufString = buf;
|
|
|
|
QStringList list = bufString.split('\n');
|
|
|
|
|
|
|
|
foreach(QString neighbor, list) {
|
|
|
|
if(neighbor.isEmpty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList neighborFields = neighbor.split(' ');
|
|
|
|
|
|
|
|
if(neighborFields.count() > 0) {
|
|
|
|
if(neighborFields[0].contains('.') || neighborFields[0].contains(':')) {
|
|
|
|
neighborList << neighborFields[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rtnl_neigh_put(neigh);
|
|
|
|
nl_cache_free(link_cache);
|
|
|
|
nl_cache_free(neigh_cache);
|
|
|
|
nl_socket_free(sock);
|
|
|
|
|
|
|
|
return neighborList;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QString& Neighbor::name() const {
|
|
|
|
return m_interface;
|
|
|
|
}
|