Example #1
0
File: net.c Project: emaste/toybox
// Loop forwarding data from in1 to out1 and in2 to out2, handling
// half-connection shutdown. timeouts return if no data for X miliseconds.
// Returns 0: both closed, 1 shutdown_timeout, 2 timeout
int pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_timeout)
{
  struct pollfd pollfds[2];
  int i, pollcount = 2;

  memset(pollfds, 0, 2*sizeof(struct pollfd));
  pollfds[0].events = pollfds[1].events = POLLIN;
  pollfds[0].fd = in1;
  pollfds[1].fd = in2;

  // Poll loop copying data from each fd to the other one.
  for (;;) {
    if (!xpoll(pollfds, pollcount, timeout)) return pollcount;

    for (i=0; i<pollcount; i++) {
      if (pollfds[i].revents & POLLIN) {
        int len = read(pollfds[i].fd, libbuf, sizeof(libbuf));
        if (len<1) pollfds[i].revents = POLLHUP;
        else xwrite(i ? out2 : out1, libbuf, len);
      }
      if (pollfds[i].revents & POLLHUP) {
        // Close half-connection.  This is needed for things like
        // "echo GET / | netcat landley.net 80"
        // Note that in1 closing triggers timeout, in2 returns now.
        if (i) {
          shutdown(pollfds[0].fd, SHUT_WR);
          pollcount--;
          timeout = shutdown_timeout;
        } else return 0;
      }
    }
  }
}
    static VALUE
loop_blocking_poll(void *argp)
{
    lp_arg *args = argp;
    args->result = xpoll(args->fds, args->nfd, args->ts);
    if (args->result < 0) args->lerrno = errno;
    return Qnil;
}
Example #3
0
// Scan stdin for a keypress, parsing known escape sequences
// Returns: 0-255=literal, -1=EOF, -2=NONE, 256-...=index into seq
// scratch space is necessary because last char of !seq could start new seq
// Zero out first byte of scratch before first call to scan_key
// block=0 allows fetching multiple characters before updating display
int scan_key(char *scratch, int block)
{
  // up down right left pgup pgdn home end ins
  char *seqs[] = {"\033[A", "\033[B", "\033[C", "\033[D", "\033[5~", "\033[6~",
                  "\033OH", "\033OF", "\033[2~", 0};
  struct pollfd pfd;
  int maybe, i, j;
  char *test;

  for (;;) {
    pfd.fd = 0;
    pfd.events = POLLIN;
    pfd.revents = 0;

    // check sequences
    maybe = 0;
    if (*scratch) {
      for (i = maybe = 0; (test = seqs[i]); i++) {
        for (j = 0; j<*scratch; j++) if (scratch[j+1] != test[j]) break;
        if (j == *scratch) {
          maybe = 1;
          if (!test[j]) {
            // We recognized current sequence: consume and return
            *scratch = 0;
            return 256+i;
          }
        }
      }
      // If current data can't be a known sequence, return next raw char
      if (!maybe) break;
    }

    // Need more data to decide

    // 30 miliseconds is about the gap between characters at 300 baud 
    if (maybe || !block) if (!xpoll(&pfd, 1, 30*maybe)) break;

    if (1 != read(0, scratch+1+*scratch, 1)) return -1;
    ++*scratch;
  }

  // Was not a sequence
  if (!*scratch) return -2;
  i = scratch[1];
  if (--*scratch) memmove(scratch+1, scratch+2, *scratch);

  return i;
}
Example #4
0
/*
 * Derived from the mcmd() libc call, with modified interface.
 * This version is MT-safe.  Errors are displayed in pdsh-compat format.
 * Connection can time out.
 *      ahost (IN)              target hostname
 *      addr (IN)               4 byte internet address
 *      locuser (IN)            local username
 *      remuser (IN)            remote username
 *      cmd (IN)                remote command to execute under shell
 *      rank (IN)               not used 
 *      fd2p (IN)               if non NULL, return stderr file descriptor here
 *      int (RETURN)            -1 on error, socket for I/O on success
 *
 * Originally by Mike Haskell for mrsh, modified slightly to work with pdsh by:
 * - making mcmd always thread safe
 * - using "err" function output errors.
 * - passing in address as addr intead of calling gethostbyname
 * - using default mshell port instead of calling getservbyname
 * 
 */
static int 
mcmd(char *ahost, char *addr, char *locuser, char *remuser, char *cmd, 
        int rank, int *fd2p, void **argp)
{
    struct sockaddr m_socket;
    struct sockaddr_in *getp;
    struct sockaddr_in sin, from;
    struct sockaddr_storage ss;
    struct in_addr m_in;
    unsigned int rand, randl;
    unsigned char *hptr;
    int s, s2, rv, mcount, lport;
    char c;
    char num[6] = {0};
    char *mptr;
    char *mbuf;
    char *tmbuf;
    char *m;
    char *mpvers;
    char num_seq[12] = {0};
    socklen_t len;
    sigset_t blockme;
    sigset_t oldset;
    char haddrdot[MAXHOSTNAMELEN + MRSH_LOCALHOST_KEYLEN + 1] = {0};
    munge_ctx_t ctx;
    struct xpollfd xpfds[2];

    memset (xpfds, 0, sizeof (xpfds));
    memset (&sin, 0, sizeof (sin));

    sigemptyset(&blockme);
    sigaddset(&blockme, SIGURG);
    sigaddset(&blockme, SIGPIPE);
    SET_PTHREAD();

    /* Convert randy to decimal string, 0 if we dont' want stderr */
    if (fd2p != NULL)
        snprintf(num_seq, sizeof(num_seq),"%d",randy);
    else
        snprintf(num_seq, sizeof(num_seq),"%d",0);

    /*
     * Start setup of the stdin/stdout socket...
     */
    lport = 0;
    len = sizeof(struct sockaddr_in);

    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        err("%p: %S: mcmd: socket call stdout failed: %m\n", ahost);
        EXIT_PTHREAD();
    }

    memset (&ss, '\0', sizeof(ss));
    ss.ss_family = AF_INET;

    if (bind(s, (struct sockaddr *)&ss, len) < 0) {
        err("%p: %S: mcmd: bind failed: %m\n", ahost);
        goto bad;
    }

    sin.sin_family = AF_INET;

    memcpy(&sin.sin_addr.s_addr, addr, IP_ADDR_LEN); 

    sin.sin_port = htons(MRSH_PORT);
    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
        err("%p: %S: mcmd: connect failed: %m\n", ahost);
        goto bad;
    }

    lport = 0;
    s2 = -1;
    if (fd2p != NULL) {
        /*
         * Start the socket setup for the stderr.
         */
        struct sockaddr_in sin2;

        if ((s2 = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            err("%p: %S: mcmd: socket call for stderr failed: %m\n", ahost);
            goto bad;
        }

        memset (&sin2, 0, sizeof(sin2));
        sin2.sin_family = AF_INET;
        sin2.sin_addr.s_addr = htonl(INADDR_ANY);
        sin2.sin_port = 0;
        if (bind(s2,(struct sockaddr *)&sin2, sizeof(sin2)) < 0) {
            err("%p: %S: mcmd: bind failed: %m\n", ahost);
            close(s2);
            goto bad;
        }

        len = sizeof(struct sockaddr);

        /*
         * Retrieve our port number so we can hand it to the server
         * for the return (stderr) connection...
         */

        /* getsockname is thread safe */
        if (getsockname(s2,&m_socket,&len) < 0) {
            err("%p: %S: mcmd: getsockname failed: %m\n", ahost);
            close(s2);
            goto bad;
        }

        getp = (struct sockaddr_in *)&m_socket;
        lport = ntohs(getp->sin_port);

        if (listen(s2, 5) < 0) {
            err("%p: %S: mcmd: listen() failed: %m\n", ahost);
            close(s2);
            goto bad;
        }
    }

    /* put port in buffer. will be 0 if user didn't want stderr */
    snprintf(num,sizeof(num),"%d",lport);

    /* 
     * Use special keyed string if target is localhost, otherwise,
     *  encode the IP addr string.
     */
    if (!encode_localhost_string (ahost, haddrdot, sizeof (haddrdot))) {
        /* inet_ntoa is not thread safe, so we use the following, 
         * which is more or less ripped from glibc
         */
        memcpy(&m_in.s_addr, addr, IP_ADDR_LEN);
        hptr = (unsigned char *)&m_in;
        sprintf(haddrdot, "%u.%u.%u.%u", hptr[0], hptr[1], hptr[2], hptr[3]);
    }

    /*
     * We call munge_encode which will take what we write in and return a
     * pointer to an munged buffer.  What we get back is a null terminated
     * string of encrypted characters.
     * 
     * The format of the unmunged buffer is as follows (each a string terminated 
     * with a '\0' (null):
     *
     * stderr_port_number & /dev/urandom_client_produce_number are 0
     * if user did not request stderr socket
     *                                            SIZE            EXAMPLE
     *                                            ==========      =============
     * remote_user_name                           variable        "mhaskell"
     * '\0'
     * protocol version                           < 12 bytes      "1.2"
     * '\0'
     * dotted_decimal_address_of_this_server      7-15 bytes      "134.9.11.155"
     * '\0'
     * stderr_port_number                         4-8 bytes       "50111"
     * '\0'
     * /dev/urandom_client_produced_number        1-8 bytes       "1f79ca0e"
     * '\0'
     * users_command                              variable        "ls -al"
     * '\0' '\0'
     *
     * (The last extra null is accounted for in the following line's 
     *  last strlen() call.)
     *
     */

    mpvers = MRSH_PROTOCOL_VERSION;

    mcount = ((strlen(remuser)+1) + (strlen(mpvers)+1) + 
              (strlen(haddrdot)+1) + (strlen(num)+1) + 
              (strlen(num_seq)+1) + strlen(cmd)+2);

    tmbuf = mbuf = malloc(mcount);
    if (tmbuf == NULL) {
        err("%p: %S: mcmd: Error from malloc\n", ahost);
        close(s2);
        goto bad;
    }

    /*
     * The following memset() call takes the extra trailing null as
     * part of its count as well.
     */
    memset(mbuf,0,mcount);

    mptr = strcpy(mbuf, remuser);
    mptr += strlen(remuser)+1;
    mptr = strcpy(mptr, mpvers);
    mptr += strlen(mpvers)+1;
    mptr = strcpy(mptr, haddrdot);
    mptr += strlen(haddrdot)+1;
    mptr = strcpy(mptr, num);
    mptr += strlen(num)+1;
    mptr = strcpy(mptr, num_seq);
    mptr += strlen(num_seq)+1;
    mptr = strcpy(mptr, cmd);

    ctx = munge_ctx_create();

    if ((rv = munge_encode(&m,ctx,mbuf,mcount)) != EMUNGE_SUCCESS) {
        err("%p: %S: mcmd: munge_encode: %s\n", ahost, munge_ctx_strerror(ctx));
        munge_ctx_destroy(ctx);
        if (s2 >= 0) 
            close(s2);
        free(tmbuf);
        goto bad;
    }

    munge_ctx_destroy(ctx);

    mcount = (strlen(m)+1);

    /*
     * Write stderr port in the clear in case we can't decode for
     * some reason (i.e. bad credentials).  May be 0 if user 
     * doesn't want stderr
     */
    if (fd2p != NULL) {
        rv = fd_write_n(s, num, strlen(num)+1);
        if (rv != (strlen(num) + 1)) {
            free(m);
            free(tmbuf);
            if (errno == EPIPE)
                err("%p: %S: mcmd: Lost connection (EPIPE): %m", ahost);
            else
                err("%p: %S: mcmd: Write of stderr port failed: %m\n", ahost);
            close(s2);
            goto bad;
        }
    } else {
        write(s, "", 1);
        lport = 0;
    }

    /*
     * Write the munge_encoded blob to the socket.
     */
    rv = fd_write_n(s, m, mcount);
    if (rv != mcount) {
        free(m);
        free(tmbuf);
        if (errno == EPIPE)
            err("%p: %S: mcmd: Lost connection: %m\n", ahost);
        else
            err("%p: %S: mcmd: Write to socket failed: %m\n", ahost);
        close(s2);
        goto bad;
    }

    free(m);
    free(tmbuf);

    if (fd2p != NULL) {
        /*
         * Wait for stderr connection from daemon.
         */
        int s3;

        errno = 0;
        xpfds[0].fd = s;
        xpfds[1].fd = s2;
        xpfds[0].events = xpfds[1].events = XPOLLREAD;
        if (  ((rv = xpoll(xpfds, 2, -1)) < 0) 
            || rv != 1 
            || (xpfds[0].revents > 0)) {
            if (errno != 0)
                err("%p: %S: mcmd: xpoll (setting up stderr): %m\n", ahost);
            else
                err("%p: %S: mcmd: xpoll: protocol failure in circuit setup\n",
                     ahost);
            (void) close(s2);
            goto bad;
        }

        errno = 0;
        len = sizeof(from); /* arg to accept */

        if ((s3 = accept(s2, (struct sockaddr *)&from, &len)) < 0) {
            err("%p: %S: mcmd: accept (stderr) failed: %m\n", ahost);
            close(s2);
            goto bad;
        }

        if (from.sin_family != AF_INET) {
            err("%p: %S: mcmd: bad family type: %d\n", ahost, from.sin_family);
            goto bad2;
        }

        close(s2);

        /*
         * The following fixes a race condition between the daemon
         * and the client.  The daemon is waiting for a null to
         * proceed.  We do this to make sure that we have our
         * socket is up prior to the daemon running the command.
         */
        if (write(s,"",1) < 0) {
            err("%p: %S: mcmd: Could not communicate to daemon to proceed: %m\n", ahost);
            close(s3);
            goto bad;
        }

        /*
         * Read from our stderr.  The server should have placed our
         * random number we generated onto this socket.
         */
        rv = fd_read_n(s3, &rand, sizeof(rand));
        if (rv != (ssize_t) (sizeof(rand))) {
            err("%p: %S: mcmd: Bad read of expected verification "
                    "number off of stderr socket: %m\n", ahost);
            close(s3);
            goto bad;
        }

        randl = ntohl(rand);
        if (randl != randy) {
            char tmpbuf[LINEBUFSIZE] = {0};
            char *tptr = &tmpbuf[0];

            memcpy(tptr,(char *) &rand,sizeof(rand));
            tptr += sizeof(rand);
            if (fd_read_line (s3, tptr, LINEBUFSIZE) < 0)
                err("%p: %S: mcmd: Read error from remote host: %m\n", ahost);
            else
                err("%p: %S: mcmd: Error: %s\n", ahost, &tmpbuf[0]);
            close(s3);
            goto bad;
        }

        /*
         * Set the stderr file descriptor for the user...
         */
        *fd2p = s3;
    }

    if ((rv = read(s, &c, 1)) < 0) {
        err("%p: %S: mcmd: read: protocol failure: %m\n", ahost);
        goto bad2;
    }

    if (rv != 1) {
        err("%p: %S: mcmd: read: protocol failure: invalid response\n", ahost);
        goto bad2;
    }

    if (c != '\0') {
        /* retrieve error string from remote server */
        char tmpbuf[LINEBUFSIZE];

        if (fd_read_line (s, &tmpbuf[0], LINEBUFSIZE) < 0)
            err("%p: %S: mcmd: Error from remote host\n", ahost);
        else
            err("%p: %S: mcmd: Error: %s\n", ahost, tmpbuf);
        goto bad2;
    }
    RESTORE_PTHREAD();

    return (s);

bad2:
    if (lport)
        close(*fd2p);
bad:
    close(s);
    EXIT_PTHREAD();
}
Example #5
0
// Scan stdin for a keypress, parsing known escape sequences
// Blocks for miliwait miliseconds, none 0, forever if -1
// Returns: 0-255=literal, -1=EOF, -2=NONE, 256-...=index into scan_key_list
// >512 is x<<9+y<<21
// scratch space is necessary because last char of !seq could start new seq
// Zero out first byte of scratch before first call to scan_key
// block=0 allows fetching multiple characters before updating display
int scan_key(char *scratch, int miliwait)
{
  struct pollfd pfd;
  int maybe, i, j;
  char *test;

  for (;;) {
    pfd.fd = 0;
    pfd.events = POLLIN;
    pfd.revents = 0;

    maybe = 0;
    if (*scratch) {
      int pos[6];
      unsigned x, y;

      // Check for return from terminal size probe
      memset(pos, 0, 6*sizeof(int));
      scratch[(1+*scratch)&15] = 0;
      sscanf(scratch+1, "\033%n[%n%3u%n;%n%3u%nR%n", pos, pos+1, &y,
             pos+2, pos+3, &x, pos+4, pos+5);
      if (pos[5]) {
        // Recognized X/Y position, consume and return
        *scratch = 0;
        return 512+(x<<10)+(y<<20);
      } else for (i=0; i<6; i++) if (pos[i]==*scratch) maybe = 1;

      // Check sequences
      for (i = 0; i<ARRAY_LEN(scan_key_list); i++) {
        test = scan_key_list[i].seq;
        for (j = 0; j<*scratch; j++) if (scratch[j+1] != test[j]) break;
        if (j == *scratch) {
          maybe = 1;
          if (!test[j]) {
            // We recognized current sequence: consume and return
            *scratch = 0;
            return 256+i;
          }
        }
      }

      // If current data can't be a known sequence, return next raw char
      if (!maybe) break;
    }

    // Need more data to decide

    // 30 miliseconds is about the gap between characters at 300 baud 
    if (maybe || miliwait != -1)
      if (!xpoll(&pfd, 1, maybe ? 30 : miliwait)) break;

    // Read 1 byte so we don't overshoot sequence match. (We can deviate
    // and fail to match, but match consumes entire buffer.)
    if (toys.signal || 1 != read(0, scratch+1+*scratch, 1))
      return toys.signal ? -3 : -1;
    ++*scratch;
  }

  // Was not a sequence
  if (!*scratch) return -2;
  i = scratch[1];
  if (--*scratch) memmove(scratch+1, scratch+2, *scratch);

  return i;
}
    static VALUE
loop_run_poll(VALUE argp)
{
    lp_arg *args = (lp_arg*)argp;
    rb_mt_loop *loop = args->loop;
    hrtime_t now, next_time;

    if (loop->events.count) {
        uint32_t i;
        args->fds = calloc(loop->events.count, sizeof(struct pollfd));
        if (args->fds == NULL) {
            rb_raise(cb_eClientNoMemoryError, "failed to allocate memory for pollfd");
        }
        for(i = 0; i < loop->events.count; i++) {
            rb_mt_socket_list *list = &loop->events.sockets[i];
            args->fds[i].fd = list->socket;
            args->fds[i].events =
                (list->flags & LCB_READ_EVENT ? POLLIN : 0) |
                (list->flags & LCB_WRITE_EVENT ? POLLOUT : 0);
        }
        args->nfd = loop->events.count;
    }

retry:
    next_time = timers_minimum(&loop->timers);
    if (next_time) {
        now = gethrtime();
        args->ts = next_time <= now ? 0 : next_time - now;
    } else {
        args->ts = HRTIME_INFINITY;
    }

#ifdef HAVE_RB_THREAD_BLOCKING_REGION
    rb_thread_blocking_region(loop_blocking_poll, args, RUBY_UBF_PROCESS, NULL);
#else
    if (rb_thread_alone()) {
        TRAP_BEG;
        args->result = xpoll(args->fds, args->nfd, args->ts);
        if (args->result < 0) args->lerrno = errno;
        TRAP_END;
    } else {
        /* 5 millisecond pause */
        hrtime_t mini_pause = 5000000;
        int exact = 0;
        if (args->ts != HRTIME_INFINITY && args->ts < mini_pause) {
            mini_pause = args->ts;
            exact = 1;
        }
        TRAP_BEG;
        args->result = xpoll(args->fds, args->nfd, mini_pause);
        if (args->result < 0) args->lerrno = errno;
        TRAP_END;
        if (args->result == 0 && !exact) {
            args->result = -1;
            args->lerrno = EINTR;
        }
    }
#endif

    if (args->result < 0) {
        errno = args->lerrno;
        switch (errno) {
            case EINTR:
#ifdef ERESTART
            case ERESTART:
#endif
#ifndef HAVE_RB_THREAD_BLOCKING_REGION
                rb_thread_schedule();
#endif
                goto retry;
        }
        rb_sys_fail("poll");
        return Qnil;
    }

    if (next_time) {
        now = gethrtime();
    }

    if (args->result > 0) {
        uint32_t cnt = args->result;
        uint32_t fd_n = 0, ev_n = 0;
        while (cnt && fd_n < args->nfd && ev_n < loop->events.count) {
            struct pollfd *res = args->fds + fd_n;
            rb_mt_socket_list *list = loop->events.sockets + ev_n;
            rb_mt_event *sock = list->first;

            /* if plugin used correctly, this checks are noop */
            if (res->fd < list->socket) {
                fd_n++;
                continue;
            } else if (res->fd > list->socket) {
                ev_n++;
                continue;
            }

            if (res->revents) {
                short flags =
                    ((res->revents & POLLIN_SET) ? LCB_READ_EVENT : 0) |
                    ((res->revents & POLLOUT_SET) ? LCB_WRITE_EVENT : 0);
                cnt--;
                loop_enque_events(&loop->callbacks, sock, flags);
            }
            fd_n++;
            ev_n++;
        }
        callbacks_run(&loop->callbacks);
    }

    if (next_time) {
        timers_run(&loop->timers, now);
    }
    if (loop->events.count == 0 && loop->timers.count == 0) {
        loop->run = 0;
    }
    return Qnil;
}
Example #7
0
/*
 * Derived from the rcmd() libc call, with modified interface.
 * This version is MT-safe.  Errors are displayed in pdsh-compat format.
 * Connection can time out.
 *	ahost (IN)		target hostname
 *	locuser (IN)		local username
 *	remuser (IN)		remote username
 *	cmd (IN)		remote command to execute under shell
 *	nodeid (IN)		node index for this connection
 *	fd2p (IN)		if non NULL, return stderr file descriptor here
 *	int (RETURN)		-1 on error, socket for I/O on success
 */
static int
qcmd(char *ahost, char *addr, char *locuser, char *remuser, char *cmd,
     int nodeid, int *fd2p, void **arg)
{
    struct sockaddr_in sin, from;
    sigset_t oldset, blockme;
    pid_t pid;
    int s, lport, timo, rv;
    char c;
    struct xpollfd xpfds[2];

    pid = getpid();
    sigemptyset(&blockme);
    sigaddset(&blockme, SIGURG);
    pthread_sigmask(SIG_BLOCK, &blockme, &oldset);
    for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
        s = privsep_rresvport(&lport);
        if (s < 0) {
            if (errno == EAGAIN)
                err("%p: %S: qcmd: socket: all ports in use\n", ahost);
            else
                err("%p: %S: qcmd: socket: %m\n", ahost);
            pthread_sigmask(SIG_SETMASK, &oldset, NULL);
            return (-1);
        }
        fcntl(s, F_SETOWN, pid);
        sin.sin_family = AF_INET;
        memcpy(&sin.sin_addr, addr, IP_ADDR_LEN);
        sin.sin_port = htons(QSHELL_PORT);
        rv = connect(s, (struct sockaddr *) &sin, sizeof(sin));
        if (rv >= 0)
            break;
        (void) close(s);
        if (errno == EADDRINUSE) {
            lport--;
            continue;
        }
        if (errno == ECONNREFUSED && timo <= 16) {
            (void) sleep(timo);
            timo *= 2;
            continue;
        }
        if (errno == EINTR)
            err("%p: %S: connect: timed out\n", ahost);
        else
            err("%p: %S: connect: %m\n", ahost);
        pthread_sigmask(SIG_SETMASK, &oldset, NULL);
        return (-1);
    }
    lport--;
    if (fd2p == 0) {
        write(s, "", 1);
        lport = 0;
    } else {
        char num[8];
        int s2 = privsep_rresvport(&lport), s3;
        socklen_t len = sizeof(from);   /* arg to accept */

        if (s2 < 0)
            goto bad;
        listen(s2, 1);
        (void) snprintf(num, sizeof(num), "%d", lport);
        if (write(s, num, strlen(num) + 1) != strlen(num) + 1) {
            err("%p: %S: qcmd: write (setting up stderr): %m\n", ahost);
            (void) close(s2);
            goto bad;
        }
        errno = 0;
        xpfds[0].fd = s;
        xpfds[1].fd = s2;
        xpfds[0].events = xpfds[1].events = XPOLLREAD;
        if (((rv = xpoll(xpfds, 2, -1)) < 0) || rv != 1 || (xpfds[0].revents > 0)) {
          if (errno != 0)
            err("%p: %S: qcmd: xpoll (setting up stderr): %m\n", ahost);
          else
            err("%p: %S: qcmd: xpoll: protocol failure in circuit setup\n", ahost);
          (void) close(s2);
          goto bad;
        }
        s3 = accept(s2, (struct sockaddr *) &from, &len);
        (void) close(s2);
        if (s3 < 0) {
            err("%p: %S: qcmd: accept: %m\n", ahost);
            lport = 0;
            goto bad;
        }
        *fd2p = s3;
        from.sin_port = ntohs((u_short) from.sin_port);
        if (from.sin_family != AF_INET ||
            from.sin_port >= IPPORT_RESERVED ||
            from.sin_port < IPPORT_RESERVED / 2) {
            err("%p: %S: socket: protocol failure in circuit setup\n",
                ahost);
            goto bad2;
        }
    }
    (void) write(s, locuser, strlen(locuser) + 1);
    (void) write(s, remuser, strlen(remuser) + 1);
    (void) write(s, cmd, strlen(cmd) + 1);
    if (_qcmd_send_extra_args(s, nodeid) < 0)
        goto bad2;

    rv = read(s, &c, 1);
    if (rv < 0) {
        if (errno == EINTR)
            err("%p: %S: read: protocol failure: %s\n",
                ahost, "timed out");
        else
            err("%p: %S: read: protocol failure: %m\n", ahost);
        goto bad2;
    } else if (rv != 1) {
        err("%p: %S: read: protocol failure: %s\n",
            ahost, "invalid response");
        goto bad2;
    }
    if (c != 0) {
        /* retrieve error string from remote server */
        char tmpbuf[LINEBUFSIZE];
        char *p = tmpbuf;

        while (read(s, &c, 1) == 1) {
            *p++ = c;
            if (c == '\n')
                break;
        }
        if (c != '\n')
            *p++ = '\n';
        *p++ = '\0';
        err("%S: %s", ahost, tmpbuf);
        goto bad2;
    }
    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
    return (s);
  bad2:
    if (lport)
        (void) close(*fd2p);
  bad:
    (void) close(s);
    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
    return (-1);
}
Example #8
0
void connect_wait(void *pri_work) {
	drone_t *d=NULL;
	xpoll_t spdf[8];
	unsigned int spdf_off=0;
	int pret=0, getret=0;
	uint8_t msg_type=0, status=0;
	size_t msg_len=0;
	uint8_t *ptr=NULL;
	time_t s_time=0, e_time=0;

	VRB(1, "waiting for connections to finish");

	if (s->dlh == NULL || s->dlh->head == NULL) {
		PANIC("waiting for connections with no drones?");
	}

	for (s_time=time(NULL);;) {
		int livesocks=0;

		for (d=s->dlh->head, spdf_off=0; d != NULL; d=d->next, spdf_off++) {
			if (d->s) livesocks++;
			spdf[spdf_off].fd=d->s;
		}

		DBG(M_CON, "polling %d sockets......", livesocks);

		if ((pret=xpoll(&spdf[0], s->dlh->size, 5000)) < 0) {
			ERR("poll drone fd's fail: %s", strerror(errno));
		}

		time(&e_time);

		if ((e_time - s_time) > s->ss->recv_timeout) {
			break;
		}

		for (d=s->dlh->head, spdf_off=0; d != NULL; d=d->next, spdf_off++) {
                        d->s_rw=0;
                        if (d->status != DRONE_STATUS_DEAD && d->status != DRONE_STATUS_DONE) {
                                d->s_rw=spdf[spdf_off].rw;
                        }
                        if (spdf[spdf_off].rw & XPOLL_READABLE) {
                                DBG(M_CON, "socket type %s is readable", strdronetype(d->type));
                        }
                }

		for (d=s->dlh->head; d != NULL; d=d->next) {
			DBG(M_CON, "drone type %s drone status %s", strdronetype(d->type), strdronestatus(d->status));
			if (d->type == DRONE_TYPE_LISTENER && (d->status == DRONE_STATUS_READY || d->status == DRONE_STATUS_WORKING)) {
				/* i just moved this here cause the line above was ugly */
				if ((d->s_rw & XPOLL_READABLE) == XPOLL_READABLE) {
					if (recv_messages(d->s) < 1) {
						ERR("cant recv_messages from ready listener");
						drone_updatestate(d, DRONE_STATUS_DEAD);
						continue;
					}

					while (1) {
						getret=get_message(d->s, &msg_type, &status, &ptr, &msg_len);
						if (getret < 1) {
							break;
						}
						if (msg_type == MSG_ERROR || status != MSG_STATUS_OK) {
							ERR("drone on fd %d is dead, closing socket and marking dead", d->s);
							drone_updatestate(d, DRONE_STATUS_DEAD);
							break;
						}
						else if (msg_type == MSG_OUTPUT) {
							deal_with_output(ptr, msg_len);
						}
						else {
							ERR("unhandled message from Listener drone message type `%s' with status %d", strmsgtype(msg_type), status);
						}
					}
				}
			}
			else if (d->type == DRONE_TYPE_SENDER && d->status == DRONE_STATUS_READY) {
				union {
					uint8_t *pw_ptr;
					void *ptr;
					send_pri_workunit_t *p;
				} pw_u;

				while ((pw_u.ptr=fifo_pop(pri_work)) != NULL) {

					DBG(M_CON, "sending pri work to sender in wait connections");
					if (send_message(
							d->s,
							MSG_WORKUNIT,
							MSG_STATUS_OK,
							pw_u.pw_ptr,
							sizeof(send_pri_workunit_t) + pw_u.p->doff
						) < 0) {
						ERR("cant send priority workunit to sender on fd %d, marking dead", d->s);
						drone_updatestate(d, DRONE_STATUS_DEAD);
						fifo_push(pri_work, pw_u.ptr);
						continue;
					}
					xfree(pw_u.ptr);
				}
			}

			if (s->senders == 0 || s->listeners == 0) {
				PANIC(s->senders == 0 ? "no senders" : "no listeners");
			}
		}

	}

	VRB(1, "connections timeout");
}
Example #9
0
static void
_setup_socket(char *serv)
{
    struct addrinfo hints, *res, *r;
    int *fds, fd, fdlen, saved_errno, count, error, i, opt;
    char *what = NULL;
    xpollfd_t pfd;
    struct sockaddr_storage addr;
    socklen_t addr_size;
    short flags;

    /* get addresses to listen on for this port */
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;
    if ((error = getaddrinfo(NULL, serv, &hints, &res))) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
        exit(1);
    }
    if (res == NULL) {
        fprintf(stderr, "getaddrinfo: no address to bind to\n");
        exit(1);
    }

    /* allocate array of listen fd's */
    fdlen = 0;
    for (r = res; r != NULL; r = r->ai_next)
       fdlen++;
    fds = (int *)xmalloc(sizeof(int) * fdlen);

    /* bind fds to addresses and listen */
    count = 0;
    saved_errno = 0;
    for (r = res, i = 0; r != NULL; r = r->ai_next, i++) {
        fds[i] = -1;
        if ((fd = socket(r->ai_family, r->ai_socktype, 0)) < 0) {
            saved_errno = errno;
            what = "socket";
            continue;
        }
        opt = 1;
        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
            saved_errno = errno;
            what = "setsockopt";
            close(fd);
            continue;
        }
        if (bind(fd, r->ai_addr, r->ai_addrlen) < 0) {
            saved_errno = errno;
            what = "bind";
            close(fd);
            continue;
        }
        if (listen(fd, LISTEN_BACKLOG) < 0) {
            saved_errno = errno;
            what = "listen";
            close(fd);
            continue;
        }
        fds[i] = fd;
        count++;
    }
    freeaddrinfo(res);
    if (count == 0) {
        fprintf(stderr, "%s: %s\n", what, strerror(saved_errno));
        exit(1);
    }

    /* accept a connection on 'fd' */
    pfd = xpollfd_create();
    fd = -1;
    while (fd == -1) {
        xpollfd_zero(pfd);
        for (i = 0; i < fdlen; i++) {
            if (fds[i] != -1)
                xpollfd_set(pfd, fds[i], XPOLLIN);
        }
        if (xpoll(pfd, NULL) < 0) {
            fprintf(stderr, "poll: %s\n", strerror(errno));
            exit(1);
        }
        for (i = 0; i < fdlen; i++) {
            if (fds[i] != -1) {
                flags = xpollfd_revents(pfd, fds[i]);
                if ((flags & (XPOLLERR|XPOLLHUP|XPOLLNVAL))) {
                        fprintf(stderr, "poll: error on fd %d\n", fds[i]);
                        exit(1);
                }
                if ((flags & XPOLLIN)) {
                    addr_size = sizeof(addr);
                    fd = accept(fds[i], (struct sockaddr *)&addr, &addr_size);
                    if (fd < 0) {
                        fprintf(stderr, "accept: %s\n", strerror(errno));
                        exit(1);
                    }
                    break;
                }
            }
        }
    }
    xpollfd_destroy(pfd);
    for (i = 0; i < fdlen; i++) {
        if (fds[i] != -1 && fds[i] != fd)
            close(fds[i]);
    }

    /* dup socket to stdio */
    (void)close(0);
    if (dup2(fd, 0) < 0) {
        fprintf(stderr, "dup2(stdin): %s\n", strerror(errno));
        exit(1);
    }
    (void)close(1);
    if (dup2(fd, 1) < 0) {
        fprintf(stderr, "dup2(stdout): %s\n", strerror(errno));
        exit(1);
    }
}
Example #10
0
/*
 * The rcmd call itself.
 *      ahost (IN)      remote hostname
 *	addr (IN)	IP address
 *      locuser (IN)    local username
 *      remuser (IN)    remote username
 *      cmd (IN)        command to execute
 *       rank (IN)	MPI rank
 *      fd2p (IN/OUT)   if non-NULL, open stderr backchannel on this fd
 *      s (RETURN)      socket for stdout/sdin or -1 on failure
 */
static int
k4cmd(char *ahost, char *addr, char *locuser, char *remuser, char *cmd,
      int rank, int *fd2p, void **arg)
{
    KTEXT_ST ticket;            /* kerberos IV context */
    CREDENTIALS cred;
    Key_schedule schedule;
    MSG_DAT msg_data;
    struct sockaddr_in faddr;
    struct sockaddr_in laddr;

    int s, pid;
    sigset_t oldset, blockme;
    struct sockaddr_in sin, from;
    char c;
    int lport = IPPORT_RESERVED - 1;
    unsigned long krb_options = 0L;
    static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
    int status;
    int rc, rv;
    struct xpollfd xpfds[2];

    pid = getpid();

    sigemptyset(&blockme);
    sigaddset(&blockme, SIGURG);
    pthread_sigmask(SIG_BLOCK, &blockme, &oldset);
    for (;;) {
        s = privsep_rresvport(&lport);
        if (s < 0) {
            if (errno == EAGAIN)
                err("%p: %S: socket: All ports in use\n", ahost);
            else
                err("%p: %S: k4cmd: socket: %m\n", ahost);
            pthread_sigmask(SIG_SETMASK, &oldset, NULL);
            return (-1);
        }
        fcntl(s, F_SETOWN, pid);
        sin.sin_family = AF_INET;
        memcpy((caddr_t) & sin.sin_addr, addr, IP_ADDR_LEN);
        sin.sin_port = htons(KCMD_PORT);

        rv = connect(s, (struct sockaddr *) &sin, sizeof(sin));

        if (rv >= 0)
            break;
        (void) close(s);
        if (errno == EADDRINUSE) {
            lport--;
            continue;
        }
        if (errno == EINTR)
            err("%p: %S: connect timed out\n", ahost);
        else
            err("%p: %S: %m\n", ahost);
        pthread_sigmask(SIG_SETMASK, &oldset, NULL);
        return (-1);
    }
    if (fd2p == 0) {
        write(s, "", 1);
        lport = 0;
    } else {
        char num[8];
        int s2, s3;
        socklen_t len = sizeof(from);

        s2 = privsep_rresvport(&lport);
        if (s2 < 0) {
            goto bad;
        }
        listen(s2, 1);
        (void) snprintf(num, sizeof(num), "%d", lport);
        if (write(s, num, strlen(num) + 1) != strlen(num) + 1) {
            err("%p: %S: write: setting up stderr: %m\n", ahost);
            (void) close(s2);
            goto bad;
        }
        errno = 0;
        xpfds[0].fd = s;
        xpfds[1].fd = s2;
        xpfds[0].events = xpfds[1].events = XPOLLREAD;
        if (((rv = xpoll(xpfds, 2, -1)) < 0) || rv != 1 || (xpfds[0].revents > 0)) {
          if (errno != 0)
            err("%p: %S: k4cmd: xpoll (setting up stderr): %m\n", ahost);
          else
            err("%p: %S: k4cmd: xpoll: protocol failure in circuit setup\n", ahost);
          (void) close(s2);
          goto bad;
        }
        s3 = accept(s2, (struct sockaddr *) &from, &len);
        (void) close(s2);
        if (s3 < 0) {
            err("%p: %S: accept: %m\n", ahost);
            lport = 0;
            goto bad;
        }
        *fd2p = s3;
        from.sin_port = ntohs((u_short) from.sin_port);
    }

    /*
     * Kerberos-authenticated service.  Don't have to send locuser, since
     * its already in the ticket, and we'll extract it on the other side. 
     */
    /*krb_options |= KOPT_DONT_CANON; */
    pthread_mutex_lock(&mylock);
    status = krb_sendauth(krb_options, s, &ticket, "rcmd", ahost,
                          NULL, (unsigned long) pid, &msg_data,
                          &cred, schedule, &laddr, &faddr, "KCMDV0.1");

    if (status != KSUCCESS) {
        /*
         * this part involves some very intimate knowledge of a
         * particular sendauth implementation to pry out the old
         * bits. This only catches the case of total failure -- but
         * that's the one where we get useful data from the remote
         * end. If we even get an authenticator back, then the
         * problem gets diagnosed locally anyhow. 
         */
        extern KRB_INT32 __krb_sendauth_hidden_tkt_len;
        char *old_data = (char *) &__krb_sendauth_hidden_tkt_len;
        char tmpbuf[LINEBUFSIZE];
        char *p = tmpbuf;

        if ((status == KFAILURE) && (*old_data == 1)) {
            strncpy(tmpbuf, old_data + 1, 3);
            tmpbuf[3] = '\0';
            err("%p: %S: %s", ahost, tmpbuf);
            *old_data = (-1);
        }
        if ((status == KFAILURE) && (*old_data == (char) -1)) {
            while (read(s, &c, 1) == 1) {
                /*(void) write(2, &c, 1); */
                *p++ = c;
                if (c == '\n')
                    break;
            }
            *p++ = '\0';
            err("%p: %S: %s", ahost, tmpbuf);
            status = -1;
        }
        switch (status) {
        case KDC_PR_UNKNOWN:
            err("%p: %S: not registered for kerberos\n", ahost);
            break;
        case NO_TKT_FIL:
            err("%p: %S: no tickets file found\n", ahost);
            break;
        default:
            err("%p: %S: k4cmd failed: %s\n", ahost,
                (status == -1) ? "k4cmd protocol failure" :
                krb_get_err_text(status));
        }
        pthread_mutex_unlock(&mylock);
        goto bad2;
    }
    pthread_mutex_unlock(&mylock);
    (void) write(s, remuser, strlen(remuser) + 1);
    (void) write(s, cmd, strlen(cmd) + 1);

    if ((rc = read(s, &c, 1)) != 1) {
        if (rc == -1) {
            err("%p: %S: read: %m\n", ahost);
        } else {
            err("%p: %S: k4cmd: bad connection with remote host\n", ahost);
        }
        goto bad2;
    }
    if (c != 0) {
        /* retrieve error string from remote server */
        char tmpbuf[LINEBUFSIZE];
        char *p = tmpbuf;

        while (read(s, &c, 1) == 1) {
            *p++ = c;
            if (c == '\n')
                break;
        }
        if (c != '\n')
            *p++ = '\n';
        *p++ = '\0';
        err("%S: %s", ahost, tmpbuf);
        goto bad2;
    }
    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
    return (s);
  bad2:
    if (lport)
        (void) close(*fd2p);
  bad:
    (void) close(s);
    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
    return (-1);
}
Example #11
0
void recv_packet(void) {
	char errbuf[PCAP_ERRBUF_SIZE], *pfilter=NULL;
	struct bpf_program filter;
	bpf_u_int32 net, mask;
	int ac_s=0, ret=0, worktodo=1;
	uint8_t msg_type=0, status=0, *ptr=NULL;
	size_t msg_len=0;
	xpoll_t spdf[2];
	union {
		recv_workunit_t *r;
		uint8_t *cr;
		uint32_t *magic;
	} wk_u;
	union {
		listener_info_t *l;
		uint8_t *ptr;
	} l_u;
	union {
		drone_version_t *v;
		uint8_t *ptr;
	} d_u;
	drone_version_t dv;
	struct pcap_stat pcs;

	r_queue=fifo_init();

	close_output_modules();
	close_report_modules();
	close_payload_modules();

	DBG(M_IPC, "creating server socket");

	memset(s->ss, 0, sizeof(scan_settings_t));

	memset(&dv, 0, sizeof(dv));
	d_u.v=&dv;
	dv.magic=DRONE_MAGIC;
	dv.maj=DRONE_MAJ;
	dv.min=DRONE_MIN;
	recv_stats_t recv_stats;

	/* heh */
	if ((ac_s=socktrans_bind(s->ipcuri)) < 0) {
		terminate("cant create listener socket");
	}

	DBG(M_IPC, "waiting for main to connect");

	parent_sync();

	lc_s=socktrans_accept(ac_s, DEF_SOCK_TIMEOUT);
	if (lc_s < 0) {
		terminate("main didnt connect, exiting");
	}

	DBG(M_IPC, "got connection");

	if (get_singlemessage(lc_s, &msg_type, &status, &ptr, &msg_len) != 1) {
		terminate("unexpected sequence of messages from parent waiting for ident request, exiting");
	}

	if (msg_type != MSG_IDENT || status != MSG_STATUS_OK) {
		ERR("got an unknown message type `%s' or bad status %d from parent, exiting", strmsgtype(msg_type), status);
	}

	if (send_message(lc_s, MSG_IDENTLISTENER, MSG_STATUS_OK, d_u.ptr, sizeof(drone_version_t)) < 0) {
		terminate("cant send back msgident to parent");
	}

	if (get_singlemessage(lc_s, &msg_type, &status, &ptr, &msg_len) != 1) {
		terminate("cant read ident ack message from parent, exiting");
	}
	if (msg_type != MSG_ACK || status != MSG_STATUS_OK) {
		ERR("got an unknown message type `%s' or bad status %d from parent, exiting", strmsgtype(msg_type), status);
	}

	DBG(M_IPC, "sending ready message to parent");

	l_u.l=(listener_info_t *)xmalloc(sizeof(listener_info_t));

	memcpy(&l_u.l->myaddr, &s->vi[0]->myaddr, sizeof(struct sockaddr_storage));
	memcpy(&l_u.l->mymask, &s->vi[0]->mymask, sizeof(struct sockaddr_storage));
	memcpy(l_u.l->hwaddr, s->vi[0]->hwaddr, THE_ONLY_SUPPORTED_HWADDR_LEN);
	l_u.l->mtu=s->vi[0]->mtu;

	assert(s->interface_str != NULL);

	if (pcap_lookupnet(s->interface_str, &net, &mask, errbuf) < 0) {
		ERR("pcap_lookupnet fails, ignoring: %s", errbuf);
	}

	if (s->pcap_readfile == NULL) {
		pdev=pcap_open_live(s->interface_str, /* XXX haha */ s->vi[0]->mtu + 64, (GET_PROMISC() ? 1 : 0), 0, errbuf);
		if (pdev == NULL) {
			ERR("pcap open live: %s", errbuf);

			DBG(M_IPC, "sending ready error message to parent");
			if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) {
				terminate("cant send message ready error");
			}
			terminate("informed parent, exiting");
		}
	}
	else {
		pdev=pcap_open_offline(s->pcap_readfile, errbuf);
		if (pdev == NULL) {
			ERR("pcap open offline: %s", errbuf);

			DBG(M_IPC, "sending ready error message to parent");
			if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) {
				terminate("cant send message ready error");
			}
			terminate("informed parent, exiting");
		}
	}

	ret=util_getheadersize(pdev, errbuf);
	if (ret < 0 || ret > 0xffff) {
		ERR("error getting link header size: %s", errbuf);

		DBG(M_IPC, "sending ready error message to parent");
		if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) {
			terminate("cant send message ready error");
		}
		terminate("informed parent, exiting");
	}
	s->ss->header_len=(uint16_t)ret;

	if (s->pcap_dumpfile != NULL) {
		VRB(0, "opening `%s' for pcap log", s->pcap_dumpfile);
		pdump=pcap_dump_open(pdev, s->pcap_dumpfile);
		if (pdump == NULL) {
			ERR("cant log to pcap file `%s'", pcap_geterr(pdev));

			DBG(M_IPC, "sending ready error message to parent");
			if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) {
				terminate("cant send message ready error");
			}
			terminate("informed parent, exiting");
		}
	}
	else {
		DBG(M_CLD, "not logging to pcap file");
	}

	if (util_preparepcap(pdev, errbuf) < 0) {
		ERR("cant setup pcap filedesc to immediate mode: %s", errbuf);

		DBG(M_IPC, "sending ready error message to parent");
		if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) {
			terminate("cant send message ready error");
		}
		terminate("informed parent, exiting");
	}

	/* pcap_fd will be -1 for a pcap file */
	pcap_fd=pcap_get_selectable_fd(pdev);

	if (pcap_fd < 0 && s->pcap_readfile == NULL) {
		ERR("cant get selectable fd from pcap device, exiting");

		DBG(M_IPC, "sending ready error message to parent");
		if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) {
			terminate("sant send message ready error");
		}
		terminate("informed parent, exiting");
	}

#ifdef PCAP_D_IN
	if (pcap_setdirection(pdev, PCAP_D_IN) < 0) {
		ERR("cant set pcap direction to in, exiting");

		DBG(M_IPC, "sending ready error message to parent");
		if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) {
			terminate("sant send message ready error");
		}
		terminate("informed parent, exiting");
	}
#endif

	DBG(M_CLD, "listener dropping privs");

	if (drop_privs() < 0) {
		terminate("cant drop privs");
	}

	if (send_message(lc_s, MSG_READY, MSG_STATUS_OK, l_u.ptr, sizeof(listener_info_t)) < 0) {
		terminate("cant send message ready");
	}

	xfree(l_u.l);

	/* XXX */
	s->ss->syn_key=0;

	do {
		if (get_singlemessage(lc_s, &msg_type, &status, &wk_u.cr, &msg_len) != 1) {
			terminate("unexpected sequence of messages from parent looking for a workunit");
		}

		if (status != MSG_STATUS_OK) {
			terminate("bad message status %u", status);
		}

		if (msg_type == MSG_QUIT) {
			worktodo=0;
			break;
		}
		else if (msg_type == MSG_WORKUNIT) {
			;
		}
		else {
			terminate("unexpected message, expecting workunit or quit message");
		}

		if (msg_len < sizeof(uint32_t)) {
			terminate("bad message, too short [" STFMT "]", msg_len);
		}

		if (msg_len < sizeof(recv_workunit_t)) {
			terminate("short workunit");
		}

		worktodo=1;

		DBG(M_WRK, "workunit `%s'", strworkunit(wk_u.cr, msg_len));

		s->ss->recv_timeout=wk_u.r->recv_timeout;
		s->ss->ret_layers=wk_u.r->ret_layers;
		s->recv_opts=wk_u.r->recv_opts;
		s->ss->window_size=wk_u.r->window_size;

		s->ss->syn_key=wk_u.r->syn_key;

		if (wk_u.r->pcap_len) {
			if ((msg_len - sizeof(recv_workunit_t)) == wk_u.r->pcap_len) {
				extract_pcapfilter(wk_u.cr + sizeof(recv_workunit_t), wk_u.r->pcap_len);
			}
			else {
				terminate("pcap option length illegal");
			}
		}

		switch (*wk_u.magic) {
			case UDP_RECV_MAGIC:
				s->ss->mode=MODE_UDPSCAN;
				break;

			case TCP_RECV_MAGIC:
				s->ss->mode=MODE_TCPSCAN;
				break;

			case ARP_RECV_MAGIC:
				s->ss->mode=MODE_ARPSCAN;
				break;

			default:
				terminate("unknown recv workunit type");
				break;
		}

		DBG(M_IPC, "from ipc, got workunit: %s", strworkunit((const void *)wk_u.cr, msg_len));

		if (s->ss->mode == MODE_ARPSCAN) {
			if (s->ss->header_len != 14) {

				DBG(M_IPC, "sending msg error");
				if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) {
					terminate("cant send message ready");
				}
				terminate("wrong linktype for arp scan");
			}
		}

		if (s->ss->ret_layers > 0) {
			DBG(M_CLD, "setting up packet queue");
			p_queue=fifo_init();
		}

		pfilter=get_pcapfilterstr();

		VRB(1, "using pcap filter: `%s'", pfilter);

		memset(&filter, 0, sizeof(filter));
		if (pcap_compile(pdev, &filter, pfilter, 0, net) < 0) {
			ERR("error compiling filter: %s",  pcap_geterr(pdev));

			if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) {
				ERR("cant send message ready error");
			}
			terminate("cant compile pcap filter");
		}

		if (pcap_setfilter(pdev, &filter) < 0) {
			ERR("error setting compiled filter: %s", pcap_geterr(pdev));

			if (send_message(lc_s, MSG_READY, MSG_STATUS_ERROR, NULL, 0) < 0) {
				ERR("cant send message ready error");
			}
			terminate("cant set compiled pcap filter");
		}

		pcap_freecode(&filter);

		if (s->ss->ret_layers > 0) {
			DBG(M_IPC, "returning whole packet via ipc");
		}

		DBG(M_IPC, "sending ready message to parent");

		if (pcap_setnonblock(pdev, 1, errbuf) < 0) {
			terminate("cant set pcap non-blocking mode");
		}

		if (send_message(lc_s, MSG_READY, MSG_STATUS_OK, NULL, 0) < 0) {
			terminate("cant send message ready");
		}

		while (1) {
			spdf[0].fd=lc_s;
			spdf[1].fd=pcap_fd;

			/* if pdev is a socket  ( ! -1 ) */
			if (xpoll(&spdf[0], 2, -1) < 0) {
				ERR("xpoll fails: %s", strerror(errno));
			}

			if (spdf[1].rw & XPOLL_READABLE) {
				pcap_dispatch(pdev, 1, parse_packet, NULL);
			}

			/* no packets, better drain the queue */
			drain_pqueue();

			if (spdf[0].rw & XPOLL_READABLE) {
				if (get_singlemessage(lc_s, &msg_type, &status, &ptr, &msg_len) != 1) {
					ERR("unexpected sequence of messages from parent in main read loop, exiting");
					worktodo=0;
					break;
				}

				if (msg_type == MSG_TERMINATE) {
					DBG(M_IPC, "parent wants me to stop listening, breaking");
					break;
				}
				else if (msg_type == MSG_QUIT) {
					DBG(M_IPC, "Parent wants me to quit, breaking");
					worktodo=0;
					break;
				}
				else {
					ERR("got strange message `%s' from parent, exiting", strmsgtype(msg_type));
					worktodo=0;
					break;
				}
			}
		}

		memset(&recv_stats, 0, sizeof(recv_stats));

		if (pcap_stats(pdev, &pcs) != -1) {

			recv_stats.packets_recv=pcs.ps_recv;
			recv_stats.packets_dropped=pcs.ps_drop;
			recv_stats.packets_dropped=pcs.ps_ifdrop;
		}

		if (send_message(lc_s, MSG_WORKDONE, MSG_STATUS_OK, (void *)&recv_stats, sizeof(recv_stats)) < 0) {
			terminate("cant send workdone message to parent, exiting");
		}

	} while (worktodo);

	pcap_close(pdev);
	if (s->pcap_dumpfile) {
		pcap_dump_close(pdump);
	}


	DBG(M_CLD, "listener exiting");

	shutdown(lc_s, SHUT_RDWR);
	close(lc_s);
 
	uexit(0);
}
Example #12
0
void run_scan(void) {
	uint8_t msg_type=0, status=0, *ptr=NULL;
	size_t wk_len=0, msg_len=0;
	xpoll_t spdf[4]; /* XXX dynamic */
	union {
		uint8_t *cr;
		void *ptr;
	} w_k;
	drone_t *c=NULL;

	rfifo=fifo_init();

	if (GET_DOCONNECT()) {
		pri_work=fifo_init();
		state_tbl=TBLINIT(111);
	}

	if (s->ss->mode == MODE_TCPSCAN) s->ss->syn_key=arc4random();

	for (c=s->dlh->head  ; c != NULL ; c=c->next) {
		if (c->type == DRONE_TYPE_LISTENER && c->status == DRONE_STATUS_READY) {
			if ((w_k.ptr=get_lp_workunit(&wk_len)) != NULL) {
				if (s->verbose > 2) {
					if (s->verbose > 5) {
						MSG(M_DBG2, "Got listener workunit of size %d :]", wk_len);
					}
					MSG(M_DBG1, "sending workunit to listener");
				}

				if (send_message(c->s, MSG_WORKUNIT, MSG_STATUS_OK, w_k.cr, wk_len) < 0) {
					MSG(M_ERR, "Cant Send Workunit to listener on fd %d", c->s);
					mark_dead(c, DRONE_STATUS_DEAD);
				}

				if (c->s == -1) PANIC("WOW!!!!");

				if (get_singlemessage(c->s, &msg_type, &status, &ptr, &msg_len) != 1) {
					MSG(M_ERR, "Unexpected sequence of messages from listener on fd %d, marking dead", c->s);
					mark_dead(c, DRONE_STATUS_DEAD);
				}

				if (status != MSG_STATUS_OK) {
					MSG(M_ERR, "bad status `%d' from listener on fd %d, marking as dead", status, c->s);
					mark_dead(c, DRONE_STATUS_DEAD);
				}

				if (msg_type != MSG_READY) {
					MSG(M_ERR, "bad message `%s' from listener on fd %d, marking as dead", strmsgtype(msg_type), c->s);
					mark_dead(c, DRONE_STATUS_DEAD);
				}

				else if (s->verbose > 3) {
					MSG(M_DBG1, "Sent workunits to listener on fd %d", c->s);
				}
			}
		}
	}

	if (s->listeners == 0) {
		MSG(M_ERR, "Not enough listeners to run scan, bailing out");
		return;
	}

	while (1) {
		int readorwrite=0, breakout=0, pret=0;
		uint32_t d_offset=0;

		c=s->dlh->head;
		assert(s->dlh->size <= sizeof(spdf)); /* XXX */

		/* write loop */
		for (c=s->dlh->head, d_offset=0 ; c != NULL ; c=c->next, d_offset++) {
			if (c->type == DRONE_TYPE_SENDER) {
				void *pw_ptr=NULL;

				if (GET_DOCONNECT()) {
					while ((pw_ptr=fifo_pop(pri_work)) != NULL) {
						if (send_message(c->s, MSG_WORKUNIT, MSG_STATUS_OK, pw_ptr, sizeof(send_pri_workunit_t)) < 0) {
							MSG(M_ERR, "Cant send priority workunit to sender on fd %d, marking dead", c->s);
							mark_dead(c, DRONE_STATUS_DEAD);
						}
					}
				}

				if (c->status == DRONE_STATUS_READY) {
					/* get to work! */
					w_k.cr=NULL;
					if ((w_k.ptr=get_sp_workunit(&wk_len)) != NULL) {
						if (s->verbose > 2) {
							if (s->verbose > 5) {
								MSG(M_DBG2, "Got workunit of size %d :]", wk_len);
							}
							MSG(M_DBG1, "sending workunit to sender");
						}

						if (send_message(c->s, MSG_WORKUNIT, MSG_STATUS_OK, w_k.cr, wk_len) < 0) {
							MSG(M_ERR, "Cant Send Workunit to sender on fd %d", c->s);
							mark_dead(c, DRONE_STATUS_DEAD);
						}
						else if (s->verbose > 3) {
							MSG(M_DBG1, "Sent workunits to senders");
						}
						c->status=DRONE_STATUS_WORKING;
						readorwrite=1;
					}
					else {
						if (s->verbose > 3) MSG(M_DBG1, "Marking sender on fd %d as done, no more workunits to send", c->s);
						send_message(c->s, MSG_QUIT, MSG_STATUS_OK, ptr, 0);
						mark_dead(c, DRONE_STATUS_DONE);
					}
				}
			}
			spdf[d_offset].fd=c->s;
		}
		if (!(s->senders)) {
			breakout++;
			break;
		}

		if ((pret=xpoll(&spdf[0], s->dlh->size, -1)) < 0) {
			MSG(M_ERR, "Poll drone fd's fail: %s", strerror(errno));
		}

		for (c=s->dlh->head, d_offset=0 ; c != NULL ; c=c->next, d_offset++) {
			c->s_rw=0;
			if (c->status != DRONE_STATUS_DEAD && c->status != DRONE_STATUS_DONE) {
				c->s_rw=spdf[d_offset].rw;
			}
			if (spdf[d_offset].rw & XPOLL_READABLE) {
				if (s->verbose > 4) MSG(M_DBG1, "Socket type %s is readable", (c->type == DRONE_TYPE_LISTENER) ? "Listener" : "Sender");
			}
		}

		/* read loop */
		for (c=s->dlh->head, d_offset=0 ; c != NULL ; c=c->next, d_offset++) {
			if (c->status != DRONE_STATUS_DEAD && c->status != DRONE_STATUS_DONE && c->s_rw & XPOLL_READABLE) {
				int getret=0;
				if (s->verbose > 5) MSG(M_DBG2, "Reading file descriptor %d type %s and %d senders left", c->s, (c->type == DRONE_TYPE_SENDER ? "Sender" : "Listener"), s->senders);

				if (recv_messages(c->s) < 0) {
					MSG(M_ERR, "Cant recieve messages from fd %d, marking as dead", c->s);
					mark_dead(c, DRONE_STATUS_DEAD);
					continue;
				}

				while (1) {
					if (c->status == DRONE_STATUS_DONE || c->status == DRONE_STATUS_DEAD) break;
					getret=get_message(c->s, &msg_type, &status, &ptr, &msg_len);
					if (getret < 1) break;
					if (msg_type == MSG_ERROR || status != MSG_STATUS_OK) {
						MSG(M_ERR, "Drone on fd %d is dead, closing socket and marking dead", c->s);
						mark_dead(c, DRONE_STATUS_DEAD);
						break;
					}
					else if (msg_type == MSG_WORKDONE && c->type == DRONE_TYPE_SENDER) {
						if (s->verbose > 5) MSG(M_DBG2, "Setting sender back to ready state after workdone message");
						c->status=DRONE_STATUS_READY;
					}
					else if (msg_type == MSG_OUTPUT && c->type == DRONE_TYPE_LISTENER) {
						if (s->ss->mode == MODE_TCPSCAN || s->ss->mode == MODE_UDPSCAN) {
							if (msg_len < sizeof(ip_report_t)) {
								MSG(M_ERR, "Unknown report format from listener");
							}
							else {
								handle_ipoutput(ptr);
							}
						}
						else if (s->ss->mode == MODE_ARPSCAN) {
							handle_arpoutput(ptr);
						}

					}
					else {
						MSG(M_ERR, "Unhandled message from `%s' drone message type `%s' with status %d", (c->type == DRONE_TYPE_SENDER ? "Sender" : "Listener"), strmsgtype(msg_type), status);
					}
					if (getret == 0) break;
				} /* multiple message read loop */
			} /* readable fd */
		}
		if (breakout) break;
	}

	if (s->verbose > 3) MSG(M_DBG1, "###### Waiting for listener packet timeout %d seconds", s->ss->recv_timeout);

	if (1) {
		unsigned int remain=s->ss->recv_timeout;

		while (1) {
			remain=sleep(remain);
			if (remain == 0) {
				break;
			}
		}
	}

	while (1) {
		uint32_t d_offset=0;
		int pret=0;

		for (c=s->dlh->head ; c != NULL ; c=c->next) {
			if (c->type != DRONE_TYPE_LISTENER) {
				if (s->verbose > 7) MSG(M_DBG2, "skipping drone type %d", c->type);
				continue;
			}
			if (c->status == DRONE_STATUS_DEAD) {
				if (s->verbose > 5) MSG(M_DBG2, "skipping dead drone type %d", c->type);
				continue;
			}

			if (c->status == DRONE_STATUS_READY && !(GET_LISTENDRONE())) {
				if (send_message(c->s, MSG_TERMINATE, MSG_STATUS_OK, NULL, 0) < 0) {
					MSG(M_ERR, "Can't tell listener to quit, this scan is useless");
					mark_dead(c, DRONE_STATUS_DEAD);
					continue;
				}
				if (s->verbose > 6) MSG(M_DBG2, "Told listener on fd %d to go into reporting mode", c->s);
				c->status=DRONE_STATUS_WORKING;
			}
		}

		for (c=s->dlh->head, d_offset=0 ; c != NULL ; c=c->next, d_offset++) {
			spdf[d_offset].fd=c->s;
		}

		if (s->listeners && (pret=xpoll(&spdf[0], s->dlh->size, -1)) < 0) {
			MSG(M_ERR, "Poll drone fd's fail: %s", strerror(errno));
		}

		for (c=s->dlh->head, d_offset=0 ; c != NULL ; c=c->next, d_offset++) {
			c->s_rw=0;
			if (c->status != DRONE_STATUS_DEAD) c->s_rw=spdf[d_offset].rw;
			if (spdf[d_offset].rw & XPOLL_READABLE) {
				if (s->verbose > 7) MSG(M_DBG1, "Socket type %s is readable", (c->type == DRONE_TYPE_LISTENER) ? "Listener" : "Sender");
			}
		}

		for (c=s->dlh->head ; c != NULL ; c=c->next) {
			if (c->status != DRONE_STATUS_DEAD && c->status != DRONE_STATUS_DONE && c->s_rw & XPOLL_READABLE) {
				int getret=0;

				if (recv_messages(c->s) < 0) {
					MSG(M_ERR, "read fd %d fails, marking as dead", c->s);
					mark_dead(c, DRONE_STATUS_DEAD);
					continue;
				}

				while (1) {
					if (c->status == DRONE_STATUS_DONE || c->status == DRONE_STATUS_DEAD) break;
					getret=get_message(c->s, &msg_type, &status, &ptr, &msg_len);
					if (getret < 1) break;
					if (s->verbose > 5) MSG(M_DBG2, "Got message type `%s [%d]' from a Listener Drone with status %d and %p data", strmsgtype(msg_type), msg_type, status, ptr);
					if (msg_type == MSG_ERROR || status != MSG_STATUS_OK) {
						MSG(M_ERR, "Got bad message from listener on fd %d, marking as dead", c->s);
						mark_dead(c, DRONE_STATUS_DEAD);
						continue;
					}
					else if (msg_type == MSG_OUTPUT) {
						if (s->ss->mode == MODE_TCPSCAN || s->ss->mode == MODE_UDPSCAN) {
							if (msg_len < sizeof(ip_report_t)) {
								MSG(M_ERR, "Unknown report format from listener on fd %d", c->s);
							}
							else {
								handle_ipoutput(ptr);
							}
						}
						else if (s->ss->mode == MODE_ARPSCAN) {
							handle_arpoutput(ptr);
						}
					}
					else if (msg_type == MSG_QUIT) {
						mark_dead(c, DRONE_STATUS_DONE);
					}
					else {
						MSG(M_ERR, "Unknown message from listener %d on fd %d, marking as dead", msg_type, c->s);
						/* hrmm, welp i dont get this drone, lets stop talking to him */
						mark_dead(c, DRONE_STATUS_DEAD);
					}
					if (getret == 0) break;
				} /* while messages are read */
			}
		} /* for reading listeners */
		if (s->listeners == 0) break;
	}

	if (s->ss->mode == MODE_UDPSCAN || s->ss->mode == MODE_TCPSCAN) {
		do_report();
	}
	else if (s->ss->mode == MODE_ARPSCAN) {
		do_arpreport();
	}
		
}