188 lines
3.6 KiB
C++
188 lines
3.6 KiB
C++
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
#include <string.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/socket.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <net/if.h>
|
||
|
#include <netinet/in.h>
|
||
|
#include <arpa/inet.h>
|
||
|
|
||
|
#include "logging.h"
|
||
|
#include "multisock.h"
|
||
|
|
||
|
#define DEFAULT_PORT 7130
|
||
|
|
||
|
#define DEVFILE "/proc/net/dev"
|
||
|
#define BUFSIZE 256
|
||
|
|
||
|
|
||
|
MultiSock::Socket::Socket()
|
||
|
{
|
||
|
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
|
||
|
LogSystem::log(LOG_CRIT, "Socket: socket()");
|
||
|
}
|
||
|
|
||
|
MultiSock::Socket::~Socket()
|
||
|
{
|
||
|
close(fd);
|
||
|
}
|
||
|
|
||
|
bool MultiSock::Socket::bindToDevice(const char* name)
|
||
|
{
|
||
|
strncpy(devname, name, sizeof(devname));
|
||
|
|
||
|
int ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, devname, sizeof(devname));
|
||
|
|
||
|
if (ret < 0) {
|
||
|
LogSystem::log(LOG_WARNING, "Socket: setsockopt(SO_BINDTODEVICE) %s", devname);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool MultiSock::Socket::bindToPort(int port)
|
||
|
{
|
||
|
struct ifreq ifr;
|
||
|
|
||
|
strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name));
|
||
|
|
||
|
if (ioctl(fd, SIOCGIFADDR, &ifr) != 0) {
|
||
|
LogSystem::log(LOG_WARNING, "Socket: ioctl(SIOCGIFADDR) %s", devname);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
memcpy(&addr, &ifr.ifr_addr, sizeof(addr));
|
||
|
addr.sin_port = htons(port);
|
||
|
|
||
|
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||
|
LogSystem::log(LOG_WARNING, "Socket: bind() %s", devname);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
int bcast = 1;
|
||
|
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast))) {
|
||
|
LogSystem::log(LOG_WARNING, "Socket: setsockopt(SO_BROADCAST) %s", devname);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
int MultiSock::Socket::show(char* buf, int size)
|
||
|
{
|
||
|
return snprintf(buf, size, "%s (%s:%d) ", devname,
|
||
|
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
||
|
}
|
||
|
|
||
|
MultiSock::Socket* MultiSock::Socket::createSocket(const char* name, int port)
|
||
|
{
|
||
|
Socket* sock = new Socket();
|
||
|
|
||
|
if (sock->fd < 0) {
|
||
|
delete sock;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
struct ifreq ifr;
|
||
|
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
||
|
|
||
|
if (ioctl(sock->fd, SIOCGIFFLAGS, &ifr) != 0) {
|
||
|
LogSystem::log(LOG_WARNING, "Socket: ioctl(SIOCGIFFLAGS) %s", name);
|
||
|
delete sock;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (!(ifr.ifr_flags & IFF_UP) || (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
|
||
|
delete sock;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
sock->bindToDevice(name);
|
||
|
|
||
|
if (!sock->bindToPort(port)) {
|
||
|
delete sock;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return sock;
|
||
|
}
|
||
|
|
||
|
|
||
|
MultiSock::MultiSock(Config& conf)
|
||
|
{
|
||
|
char* buf = (char*)malloc(BUFSIZE);
|
||
|
if (buf == NULL) {
|
||
|
LogSystem::log(LOG_CRIT, "MultiSock(): out of memory");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
FILE* fp = fopen(DEVFILE, "r");
|
||
|
if (fp == NULL) {
|
||
|
LogSystem::log(LOG_CRIT, "MultiSock(): can not open " DEVFILE);
|
||
|
free(buf);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
fgets(buf, BUFSIZE, fp);
|
||
|
fgets(buf, BUFSIZE, fp);
|
||
|
|
||
|
int port = conf.getInteger("global", "scan_port", DEFAULT_PORT);
|
||
|
FD_ZERO(&fdsel);
|
||
|
|
||
|
while (fgets(buf, BUFSIZE, fp) != NULL) {
|
||
|
char* tok = strtok(buf, " :");
|
||
|
|
||
|
// TODO: check against config list
|
||
|
|
||
|
Socket* sock = Socket::createSocket(tok, port);
|
||
|
if (sock) {
|
||
|
FD_SET(sock->getFD(), &fdsel);
|
||
|
|
||
|
sock->show(buf, BUFSIZE);
|
||
|
LogSystem::log(LOG_NOTICE, "adding Interface %s", buf);
|
||
|
|
||
|
ifaceList.add(sock);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fclose(fp);
|
||
|
free(buf);
|
||
|
}
|
||
|
|
||
|
MultiSock::~MultiSock()
|
||
|
{
|
||
|
while (!ifaceList.isEmpty())
|
||
|
delete ifaceList.get();
|
||
|
}
|
||
|
|
||
|
|
||
|
int MultiSock::getRecvSocket()
|
||
|
{
|
||
|
fd_set fdcpy;
|
||
|
|
||
|
while (1) {
|
||
|
memcpy(&fdcpy, &fdsel, sizeof(fdcpy));
|
||
|
|
||
|
select(FD_SETSIZE, &fdcpy, NULL, NULL, NULL);
|
||
|
|
||
|
Iterator<Socket>* it = ifaceList.createIterator();
|
||
|
while (it->hasNext()) {
|
||
|
Socket* sock = it->next();
|
||
|
if (FD_ISSET(sock->getFD(), &fdcpy)) {
|
||
|
delete it;
|
||
|
return sock->getFD();
|
||
|
}
|
||
|
}
|
||
|
delete it;
|
||
|
|
||
|
LogSystem::log(LOG_ERROR, "getRecvSocket(): select()");
|
||
|
}
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|