#include #include #include #include #include #include #include #include #include #include #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* 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; }