0

I wanted to create a simple program to get the connected clients each moment on my wireless network. For that purposes I use nmap to find the appropriate addresses (MAC of the client, IP) and ncurses library in C.

The bash script that do my job is the following:

nmap -sP ip/24 | awk '/Nmap scan report for/{printf $5;}/MAC Address:/{print " - "$3;}' | sort

The c program is the following:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <ncurses.h>

#define DELAY 30000

int main(int argc, char *argv[]) {
  raw();
  noecho();
  keypad(stdscr, TRUE);
  initscr();

  while (1) {

    clear();
    int  maxRows_y, maxCols_x;
    getmaxyx(stdscr, maxRows_y, maxCols_x);

    FILE *fp;
    char path[1000];

    fp = popen("nmap -sP 192.168.0.1/24 | awk '/Nmap scan report for/{printf $5;}/MAC Address:/{print \" => \"$3;}' | sort", "r");

    while (fgets(path, 1000, fp) != NULL) {
        printw("%s", path);
    }
    pclose(fp);

    refresh();
    usleep(DELAY); // Shorter delay between movements
  }

  endwin();

  return EXIT_SUCCESS;
}

The problem is that the program freezes every time I run the pipe. This cause other problems. For instance, if I want to use a clock to count the elapsed time from the beginning of my program, this won't update every second (1 -> 2 -> 3 -> ..etc) cause we have to wait the pipe to finish. And also if I add other functionalities such as menus, this will cause terrible user experience issues.

I wanted to ask if there is a way to run the pipe on the background and get the results when it finishes the process without interrupting other functionalities of my program. Remember that I have to run the pipe continuously until the program exit.

UPDATE:

This question was the first I show. The problem is that if we change the code to this version, we end up without any output.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <ncurses.h>
#include <fcntl.h>
#include <errno.h>

#define DELAY 30000

int main(int argc, char *argv[]) {
  raw();
  noecho();
  keypad(stdscr, TRUE);
  initscr();


  FILE *f = popen("nmap -sP 192.168.0.1/24 | awk '/Nmap scan report for/{printf $5;}/MAC Address:/{print \" => \"$3;}' | sort", "r");
  int d = fileno(f);
  fcntl(d, F_SETFL, O_NONBLOCK);

  while (1) {

    clear();
    int  maxRows_y, maxCols_x;
    getmaxyx(stdscr, maxRows_y, maxCols_x);

    char path[1000];
    ssize_t r = read(d, path, sizeof(path));
    if (r == -1 && errno == EAGAIN) {
      printw("waiting for data....");
    }
        
    else if (r > 0) {
      printw("%s", path);
      fcntl(d, F_SETFL, O_NONBLOCK);
    }
    else {
      printw("pipe closed");
    }
         

    refresh();
    usleep(DELAY); // Shorter delay between movements
  }

  endwin();

  return EXIT_SUCCESS;
}
Community
  • 1
  • 1

1 Answers1

0

I think the problem might be that the output is flashing by too fast for you to see it.

If you change your code slightly so that you do not clear the screen once you have output (at least for a few seconds), I think you'll see the data.

Here is one version that worked for me. Note that the subnet is different because I was testing on my own network.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <ncurses.h>
#include <fcntl.h>
#include <errno.h>

#define DELAY 30000

int main(int argc, char *argv[]) {
    raw();
    noecho();
    keypad(stdscr, TRUE);
    initscr();


    FILE *f = popen("nmap -sP 10.0.0.13/24", "r");

    int d = fileno(f);
    fcntl(d, F_SETFL, O_NONBLOCK);

    bool processingOutput = false;

    while (1) {
        if (!processingOutput)
            clear();
        int  maxRows_y, maxCols_x;
        getmaxyx(stdscr, maxRows_y, maxCols_x);

        char path[1000];
        ssize_t r = read(d, path, sizeof(path));
        if (r == -1 && errno == EAGAIN && !processingOutput) {
            printw("waiting for data....");
        }
        else if (r > 0) {
            processingOutput = true;
            path[r] = '\0';
            printw("%s", path);
        }
        else {
            printw("pipe closed");
            sleep(10);
            processingOutput = false;
        }


        refresh();
        usleep(DELAY); // Shorter delay between movements
    }
    endwin();
    return EXIT_SUCCESS;
}
merlin2011
  • 71,677
  • 44
  • 195
  • 329