Created
August 3, 2018 08:36
-
-
Save incebellipipo/31cee639427182bcfd18d5b5557e7780 to your computer and use it in GitHub Desktop.
Simple c++ code that detects interface changes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Detects interface plug or removal with given name, starts forks wpa_supplicant accordingly | |
* g++ wpa_forker.cpp -std=c++11 -lpthread | |
* | |
*/ | |
#include <iostream> | |
#include <cstdlib> | |
#include <cstdio> | |
#include <csignal> | |
#include <cstring> | |
#include <thread> | |
#include <pthread.h> | |
#include <vector> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <linux/netlink.h> | |
#include <linux/rtnetlink.h> | |
#include <net/if.h> | |
#include <netinet/in.h> | |
#include <sys/ioctl.h> | |
#include <ifaddrs.h> | |
#include <wait.h> | |
#define WPA_PATH "/sbin/wpa_supplicant" | |
#define WPA_CONFIG_PATH "/etc/wpa_supplicant/wpa_supplicant.conf" | |
#define BUF_SIZE 4096 | |
struct wpa_process { | |
char iface_name[IFNAMSIZ]; | |
char iface_hwaddr[IFHWADDRLEN]; | |
pid_t pid = -1; | |
void syscallHwaddr(){ | |
struct ifreq ifr; | |
strncpy(ifr.ifr_name, iface_name, IFNAMSIZ); | |
int sock = socket(AF_INET, SOCK_DGRAM, 0); | |
if(ioctl(sock, SIOCGIFHWADDR, &ifr) == 0){ | |
strncpy(iface_hwaddr, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN); | |
} | |
close(sock); | |
} | |
void run(bool verbose = true){ | |
std::thread th([&](bool verbose, wpa_process* process) { | |
if (process->pid > 0) { | |
return; | |
} | |
if ((process->pid = fork()) == 0) { | |
char *args[] = { | |
(char *) WPA_PATH, // dummpy param to avoid argv[0] | |
(char *) "-i", | |
process->iface_name, | |
(char *) "-c", | |
(char *) WPA_CONFIG_PATH, | |
(char *) (verbose ? "-d" : ""), | |
(char *) nullptr | |
}; | |
execv((char *) WPA_PATH, args); | |
} else if (process->pid > 0) { | |
int status; | |
wait(&status); | |
} else { | |
perror("fork failed"); | |
} | |
},verbose, this); | |
th.detach(); | |
} | |
void stop(){ | |
std::cout << "should stop" << std::endl; | |
kill(pid, SIGINT); | |
pid = -1; | |
} | |
}; | |
struct ifaddrs* get_interfaces(){ | |
struct ifaddrs* addrs; | |
getifaddrs(&addrs); | |
return addrs; | |
} | |
struct wpa_process process; | |
int open_netlink(){ | |
int sock; | |
struct sockaddr_nl addr; | |
memset((void*)&addr, 0, sizeof(addr)); | |
if((sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE))< 0 ){ | |
perror("Can't connect to socket"); | |
return sock; | |
} | |
addr.nl_family = AF_NETLINK; | |
addr.nl_pid = (u_int32_t) getpid(); | |
addr.nl_groups = RTMGRP_LINK; | |
if( bind(sock, (struct sockaddr*) &addr, sizeof(addr)) < 0){ | |
return -1; | |
} | |
return sock; | |
} | |
int read_event(int sockint){ | |
ssize_t status ; | |
int ret =0 ; | |
char buf[BUF_SIZE]; | |
struct iovec iov = { | |
.iov_base = buf, | |
.iov_len = sizeof(buf) | |
}; | |
struct sockaddr_nl snl; | |
struct msghdr msg = { /** @see man recvmsg */ | |
.msg_name = (void*)&snl, | |
.msg_namelen = sizeof(snl), | |
.msg_iov = &iov, | |
.msg_iovlen = 1, | |
.msg_control = nullptr, | |
.msg_controllen = 0, | |
.msg_flags = 0 | |
}; | |
status = recvmsg(sockint , &msg, 0); | |
if(status < 0 ){ | |
if( errno == EWOULDBLOCK || errno == EAGAIN){ | |
return ret; | |
} | |
printf("read_netlink: Error recvmsg: %lu\n", status); | |
perror("read_netlink: Error: "); | |
return (int)status; | |
} | |
if(status == 0) { | |
printf("read_netlink: EOF\n"); | |
} | |
int i = 0; | |
for( | |
auto h = (struct nlmsghdr *) buf; | |
NLMSG_OK(h, (unsigned int)status); | |
h = NLMSG_NEXT(h, status), i++ ) | |
{ | |
if(h->nlmsg_type == NLMSG_DONE){ | |
return ret; | |
} else if ( h->nlmsg_type == NLMSG_ERROR) { | |
printf("read_netlink: Message is an error\n"); | |
return -1; | |
} | |
// Now we can call handler | |
auto ifi = (struct ifinfomsg*) NLMSG_DATA(h); | |
struct ifreq ifr; | |
ifr.ifr_ifindex = ifi->ifi_index; | |
int ifreqsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); | |
ioctl(ifreqsock, SIOCGIFNAME, &ifr); | |
close(ifreqsock); | |
switch(h->nlmsg_type){ | |
case RTM_NEWADDR: | |
break; | |
case RTM_DELADDR: | |
break; | |
case RTM_NEWROUTE: | |
break; | |
case RTM_DELROUTE: | |
break; | |
case RTM_NEWLINK: | |
if(ifi->ifi_change == 0xFFFFFFFF){ | |
std::cout << "=========================================================> " << i << std::endl; | |
std::cout << "INTERFACE ADDED: " << std::string(ifr.ifr_name) << std::endl; | |
if(strcmp(ifr.ifr_name, process.iface_name) == 0){ | |
process.run(false); | |
} | |
} | |
break; | |
case RTM_DELLINK: | |
if(ifi->ifi_change == 0xFFFFFFFF){ | |
std::cout << "=========================================================> " << i << std::endl; | |
std::cout << "INTERFACE REMOVED: " << std::string(ifr.ifr_name)<< std::endl; | |
if(strcmp(ifr.ifr_name, process.iface_name) == 0){ | |
process.stop(); | |
} | |
} | |
break; | |
default: | |
break; | |
} | |
} | |
return 0; | |
} | |
int main(int argc, char* argv[]) { | |
if(argc < 2){ | |
printf("Wrong number of arguments\n"); | |
return EXIT_FAILURE; | |
} | |
strcpy(process.iface_name, argv[1]); | |
process.syscallHwaddr(); | |
struct ifaddrs* addrs; | |
getifaddrs(&addrs); | |
for(;addrs; addrs = addrs->ifa_next){ | |
if(addrs->ifa_addr && addrs->ifa_addr->sa_family == AF_PACKET){ | |
if(strcmp(addrs->ifa_name, process.iface_name) == 0){ | |
process.run(false); | |
} | |
} | |
} | |
int nls = open_netlink(); | |
printf("Started watching: \n"); | |
if( nls < 0 ){ | |
perror("Open Error"); | |
} | |
do{ | |
if( read_event(nls) < 0 ){ | |
break; | |
} | |
} while( true ); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment