mirror of
https://github.com/cmand/yarrp.git
synced 2024-05-11 05:55:06 +00:00
184 lines
5.6 KiB
C++
184 lines
5.6 KiB
C++
/****************************************************************************
|
|
Program: $Id: net.cpp 14 2014-12-30 02:33:44Z laalt $
|
|
Date: $Date: 2014-12-29 18:33:44 -0800 (Mon, 29 Dec 2014) $
|
|
Description: networking routines
|
|
****************************************************************************/
|
|
#include "yarrp.h"
|
|
|
|
char *LLResolv::mac2str(char *mac) {
|
|
static char buf[BUFSIZE];
|
|
snprintf(buf, BUFSIZE, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
|
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
|
return buf;
|
|
}
|
|
|
|
int LLResolv::print_gw() {
|
|
char buf[INET6_ADDRSTRLEN];
|
|
|
|
if (inet_ntop(AF_INET, &(gw.ip), buf, INET6_ADDRSTRLEN) == NULL)
|
|
return -1;
|
|
printf("IPv4 gateway: %s\n", buf);
|
|
printf("IPv4 gateway mac: %s\n", mac2str(gw.mac));
|
|
if (inet_ntop(AF_INET6, &(gw.ip6), buf, INET6_ADDRSTRLEN) == NULL)
|
|
return -1;
|
|
printf("IPv6 gateway: %s\n", buf);
|
|
printf("IPv6 gateway mac: %s\n", mac2str(gw.mac6));
|
|
return 0;
|
|
}
|
|
|
|
void LLResolv::setDstMAC(uint8_t **mac) {
|
|
*mac = (uint8_t *)calloc(6, sizeof(uint8_t));
|
|
memcpy(*mac, gw.mac6, ETH_ALEN);
|
|
}
|
|
|
|
#ifdef _LINUX
|
|
void LLResolv::mine(const char *interface) {
|
|
if ((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
|
|
printf("PF_PACKET error: %s\n", strerror(errno));
|
|
exit(-1);
|
|
}
|
|
memset (&ifr, 0, sizeof (ifr));
|
|
snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
|
|
ioctl (sock, SIOCGIFHWADDR, &ifr);
|
|
close(sock);
|
|
}
|
|
#else
|
|
void LLResolv::mine(const char *interface) {};
|
|
#endif
|
|
|
|
#ifdef _LINUX
|
|
void LLResolv::gateway() {
|
|
char buf[BUFSIZE];
|
|
|
|
if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) <= 0) {
|
|
printf("PF_NETLINK error: %s\n", strerror(errno));
|
|
exit(-1);
|
|
}
|
|
size_t nlseq = send_req(buf, nlseq, RTM_GETROUTE);
|
|
size_t msg_len = read_res(buf, nlseq);
|
|
struct nlmsghdr *nlmsg = reinterpret_cast<struct nlmsghdr *>(buf);
|
|
for (; NLMSG_OK(nlmsg, msg_len); nlmsg = NLMSG_NEXT(nlmsg, msg_len))
|
|
parse_route(nlmsg);
|
|
nlseq = send_req(buf, nlseq, RTM_GETNEIGH);
|
|
msg_len = read_res(buf, nlseq);
|
|
nlmsg = reinterpret_cast<struct nlmsghdr *>(buf);
|
|
for (; NLMSG_OK(nlmsg, msg_len); nlmsg = NLMSG_NEXT(nlmsg, msg_len))
|
|
parse_neigh(nlmsg);
|
|
close(sock);
|
|
}
|
|
#else
|
|
void LLResolv::gateway() {
|
|
fatal("Non-linux IPv6 requires specifying source (-M) and gateway (-G) MAC");
|
|
};
|
|
#endif
|
|
|
|
#ifdef _LINUX
|
|
void LLResolv::setSrcMAC(uint8_t **mac) {
|
|
*mac = (uint8_t *)calloc(6, sizeof(uint8_t));
|
|
memcpy(*mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
|
|
}
|
|
void LLResolv::print_self() {
|
|
printf("Host mac: %s\n", mac2str(ifr.ifr_hwaddr.sa_data));
|
|
}
|
|
#else
|
|
void LLResolv::setSrcMAC(uint8_t **mac) {};
|
|
void LLResolv::print_self() {};
|
|
#endif
|
|
|
|
#ifdef _LINUX
|
|
int LLResolv::send_req(char *buf, size_t nlseq, size_t req_type) {
|
|
memset(buf, 0, BUFSIZE);
|
|
struct nlmsghdr * nlmsg = reinterpret_cast<struct nlmsghdr *>(buf);
|
|
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
|
nlmsg->nlmsg_type = req_type;
|
|
nlmsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
|
|
nlmsg->nlmsg_seq = nlseq++;
|
|
nlmsg->nlmsg_pid = getpid();
|
|
|
|
if (send(sock, buf, nlmsg->nlmsg_len, 0) < 0)
|
|
return -1;
|
|
|
|
return nlseq;
|
|
}
|
|
|
|
int LLResolv::read_res(char *buf, size_t nlseq) {
|
|
struct nlmsghdr *nlmsg;
|
|
int len;
|
|
size_t total_len = 0;
|
|
|
|
do {
|
|
if ((len = recv(sock, buf, BUFSIZE - total_len, 0)) < 0)
|
|
return -1;
|
|
|
|
nlmsg = reinterpret_cast<struct nlmsghdr *>(buf);
|
|
|
|
if (NLMSG_OK(nlmsg, len) == 0)
|
|
return -1;
|
|
if (nlmsg->nlmsg_type == NLMSG_ERROR)
|
|
return -1;
|
|
if (nlmsg->nlmsg_type == NLMSG_DONE)
|
|
break;
|
|
|
|
buf += len;
|
|
total_len += len;
|
|
|
|
if ((nlmsg->nlmsg_flags & NLM_F_MULTI) == 0)
|
|
break;
|
|
|
|
} while (nlmsg->nlmsg_seq != nlseq || nlmsg->nlmsg_pid != getpid());
|
|
|
|
return total_len;
|
|
}
|
|
|
|
void LLResolv::parse_route(struct nlmsghdr *nlmsg) {
|
|
struct gw_info *info = &gw;
|
|
|
|
struct rtmsg *rtmsg = reinterpret_cast<struct rtmsg *>(NLMSG_DATA(nlmsg));
|
|
if (rtmsg->rtm_table != RT_TABLE_MAIN)
|
|
return;
|
|
|
|
struct rtattr *attr = reinterpret_cast<struct rtattr *>(RTM_RTA(rtmsg));
|
|
size_t len = RTM_PAYLOAD(nlmsg);
|
|
|
|
for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
|
|
if (attr->rta_type != RTA_GATEWAY)
|
|
continue;
|
|
if (rtmsg->rtm_family == AF_INET)
|
|
info->ip = *reinterpret_cast<uint32_t *>(RTA_DATA(attr));
|
|
else if (rtmsg->rtm_family == AF_INET6)
|
|
memcpy(info->ip6, RTA_DATA(attr), IPV6SIZE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void LLResolv::parse_neigh(struct nlmsghdr *nlmsg) {
|
|
char mac[ETH_ALEN];
|
|
uint32_t ip = 0;
|
|
char ip6[IPV6SIZE];
|
|
struct gw_info *info = &gw;
|
|
|
|
struct ndmsg *ndmsg = reinterpret_cast<struct ndmsg *>(NLMSG_DATA(nlmsg));
|
|
struct rtattr *attr = reinterpret_cast<struct rtattr *>(RTM_RTA(ndmsg));
|
|
size_t len = RTM_PAYLOAD(nlmsg);
|
|
|
|
for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
|
|
if (attr->rta_type == NDA_LLADDR)
|
|
memcpy(mac, RTA_DATA(attr), ETH_ALEN);
|
|
|
|
if (ndmsg->ndm_family == AF_INET && attr->rta_type == NDA_DST)
|
|
ip = *reinterpret_cast<uint32_t *>(RTA_DATA(attr));
|
|
|
|
if (ndmsg->ndm_family == AF_INET6 && attr->rta_type == NDA_DST)
|
|
memcpy(ip6, RTA_DATA(attr), IPV6SIZE);
|
|
}
|
|
|
|
if (ndmsg->ndm_family == AF_INET && ip && ip == info->ip)
|
|
memcpy(info->mac, mac, ETH_ALEN);
|
|
|
|
if (ndmsg->ndm_family == AF_INET6) {
|
|
if (memcmp(ip6, info->ip6, IPV6SIZE) == 0)
|
|
memcpy(info->mac6, mac, ETH_ALEN);
|
|
}
|
|
}
|
|
#endif
|