示例#1
0
/** Called after the local connection to the mush has established */
void
local_connected(struct conn *c)
{
  char *hostid;
  int len;

#if SSL_DEBUG_LEVEL > 0
  errputs(stdout, "Local connection attempt completed. Setting up pipe.");
#endif
  bufferevent_setcb(c->local_bev, pipe_cb, NULL, ssl_event_cb, c);
  bufferevent_enable(c->local_bev, EV_READ | EV_WRITE);
  bufferevent_setcb(c->remote_bev, pipe_cb, NULL, ssl_event_cb, c);
  bufferevent_enable(c->remote_bev, EV_READ | EV_WRITE);

  c->state = C_ESTABLISHED;

  /* Now pass the remote host and IP to the mush as the very first line it gets */
  len = strlen(c->remote_host) + strlen(c->remote_ip) + 3;
  hostid = malloc(len + 1);
  sprintf(hostid, "%s^%s\r\n", c->remote_ip, c->remote_host);

  if (send_with_creds(bufferevent_getfd(c->local_bev), hostid, len) < 0) {
    penn_perror("send_with_creds");
    delete_conn(c);
  }

  free(hostid);
}
示例#2
0
/** Dump a representation of the memcheck skip list into a file, using the dot language.
 * Use from a debugger:
 * \verbatim
 * (gdb) print memcheck_dump_struct("memcheck.dot")
 * \endverbatim
 * and then turn into an image:
 * \verbatim
 * # dot -Tsvg -o memcheck.svg memcheck.dot
 * \endverbatim
 * (dot is part of the graphviz package)
 * \param filename The output file name.
 */
void
memcheck_dump_struct(const char *filename)
{
  FILE *fp;
  MEM *chk;
  int n;

  fp = fopen(filename, "w");
  if (!fp) {
    penn_perror("fopen");
    return;
  }

  fputs("digraph memcheck_skiplist {\n", fp);
  fputs("rankdir=LR;\n", fp);
  fputs("node [shape=record];\n", fp);
  fputs("head [label=\"<l0>HEAD", fp);
  for (n = 1; n < MAX_LINKS; n += 1) {
    fprintf(fp, "|<l%d>%d", n, n);
    if (!memcheck_head->links[n])
      fputs("\\n(NULL)", fp);
  }
  fputs("\"];\n", fp);

  for (n = 0; n < MAX_LINKS; n += 1) {
    if (memcheck_head->links[n])
      fprintf(fp, "head:l%d -> mc%p:l%d;\n", n,
              (void *) memcheck_head->links[n], n);
  }

  for (chk = memcheck_head->links[0]; chk; chk = chk->links[0]) {
    fprintf(fp, "mc%p [label=\"{<l0>%s|<s0>%d}", (void *) chk, chk->ref_name,
            chk->ref_count);
    for (n = 1; n < chk->link_count; n += 1) {
      fprintf(fp, "|<l%d>", n);
      if (!chk->links[n])
        fputs(" (NULL)", fp);
    }
    fputs("\"];\n", fp);
    if (chk->links[0])
      fprintf(fp, "mc%p:s0 -> mc%p:l0\n", (void *) chk, (void *) chk->links[0]);
    for (n = 1; n < chk->link_count; n += 1) {
      if (chk->links[n])
        fprintf(fp, "mc%p:l%d -> mc%p:l%d;\n", (void *) chk, n,
                (void *) chk->links[n], n);
    }
  }

  fputs("}\n", fp);
  fclose(fp);
}
示例#3
0
static void
send_resp(evutil_socket_t fd, short what
          __attribute__ ((__unused__)), void *arg)
{
  struct is_data *data = arg;
  ssize_t len;

  len = send(fd, &data->resp, sizeof data->resp, 0);
  if (len != (int) sizeof data->resp) {
    penn_perror("error writing packet");
    exit(EXIT_FAILURE);
  }
  event_free(data->ev);
  free(data);
}
示例#4
0
/** Dump a representation of an intmap into a file, using the dot language.
 * Use from a debugger:
 * \verbatim
 * (gdb)print im_dump_graph(queue_map, "queue.dot")
 * \endverbatim
 * and then turn into an image:
 * \verbatim
 * # dot -Tpng -o queue.png queue.dot
 * \endverbatim
 * (dot is part of the graphviz package)
 * \param im the map to print.
 * \param filename The output file name.
 */
void
im_dump_graph(intmap *im, const char *filename)
{
  FILE *fp;

  if (!im || !filename)
    return;

  fp = fopen(filename, "w");

  if (!fp) {
    penn_perror("fopen");
    return;
  }

  fputs("digraph patricia { \n", fp);
  fputs("node [shape=Mrecord, colorscheme=blues3, style=filled];\n", fp);
  pat_list_nodes(im->root, fp);
  pat_list_links(im->root, fp);
  fputs("}\n", fp);
  fclose(fp);
}
bool
make_info_slave(void)
{
  int socks[2];
  pid_t child;
  int n;

  if (info_slave_state != INFO_SLAVE_DOWN) {
    if (info_slave_pid > 0)
      kill_info_slave();
    info_slave_state = INFO_SLAVE_DOWN;
  }

  if (startup_attempts == 0)
    time(&startup_window);

  startup_attempts += 1;

  if (startup_attempts > MAX_ATTEMPTS) {
    time_t now;

    time(&now);
    if (difftime(now, startup_window) <= 60.0) {
      /* Too many failed attempts to start info_slave in 1 minute */
      do_rawlog(LT_ERR, "Disabling info_slave due to too many errors.");
      info_slave_halted = true;
      return false;
    } else {
      /* Reset counter */
      startup_window = now;
      startup_attempts = 0;
    }
  }
#ifndef AF_LOCAL
  /* Use Posix.1g names. */
#define AF_LOCAL AF_UNIX
#endif

#ifdef HAVE_SOCKETPAIR
  if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, socks) < 0) {
    penn_perror("creating slave datagram socketpair");
    return false;
  }
  if (socks[0] >= maxd)
    maxd = socks[0] + 1;
  if (socks[1] >= maxd)
    maxd = socks[1] + 1;
#endif

  child = fork();
  if (child < 0) {
    penn_perror("forking info slave");
#ifdef HAVE_SOCKETPAIR
    closesocket(socks[0]);
    closesocket(socks[1]);
#endif
    return false;
  } else if (child > 0) {
    info_slave_state = INFO_SLAVE_READY;
    info_slave_pid = child;
#ifdef HAVE_SOCKETPAIR
    info_slave = socks[0];
    closesocket(socks[1]);
    do_rawlog(LT_ERR,
              "Spawning info slave, communicating using socketpair, pid %d.",
              child);
#endif
    make_nonblocking(info_slave);
  } else {
    int errfd = fileno(stderr);
    int dupfd;

    /* Close unneeded fds and sockets: Everything but stderr and the
       socket used to talk to the mush */
    for (n = 0; n < maxd; n++) {
      if (n == errfd)
        continue;
#ifdef HAVE_SOCKETPAIR
      if (n == socks[1])
        continue;
#endif
      close(n);
    }
    /* Reuse stdin and stdout for talking to the slave */
    dupfd = dup2(socks[1], 0);
    if (dupfd < 0) {
      penn_perror("dup2() of stdin in info_slave");
      exit(1);
    }

    dupfd = dup2(socks[1], 1);
    if (dupfd < 0) {
      penn_perror("dup2() of stdout in info_slave");
      exit(1);
    }

    close(socks[1]);

    execl("./info_slave", "info_slave", "for", MUDNAME, (char *) NULL);
    penn_perror("execing info slave");
    exit(1);
  }

  if (info_slave >= maxd)
    maxd = info_slave + 1;

  lower_priority_by(info_slave_pid, 4);

  for (n = 0; n < maxd; n++)
    if (FD_ISSET(n, &info_pending))
      query_info_slave(n);

  return true;
}
void
reap_info_slave(void)
{
  struct response_dgram resp;
  ssize_t len;
  char hostname[BUFFER_LEN], *hp;
  int n, count;
  conn_source source;

  if (info_slave_state != INFO_SLAVE_PENDING) {
    if (info_slave_state == INFO_SLAVE_DOWN)
      make_info_slave();
    return;
  }

  len = recv(info_slave, &resp, sizeof resp, 0);
  if (len < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
    return;
  else if (len < 0 || len != (int) sizeof resp) {
    penn_perror("reading info_slave response");
    return;
  }

  /* okay, now we have some info! */
  if (!FD_ISSET(resp.fd, &info_pending)) {
    /* Duplicate or spoof. Ignore. */
    return;
  }

  FD_CLR(resp.fd, &info_pending);

  /* See if we have any other pending queries and change state if not. */
  for (n = 0, count = 0; n < pending_max; n++)
    if (FD_ISSET(n, &info_pending))
      count++;

  if (count == 0) {
    info_slave_state = INFO_SLAVE_READY;
    pending_max = 0;
  }

  hp = hostname;
  if (resp.hostname[0])
    safe_str(resp.hostname, hostname, &hp);
  else
    safe_str(resp.ipaddr, hostname, &hp);
  *hp = '\0';

  if (Forbidden_Site(resp.ipaddr) || Forbidden_Site(hostname)) {
    if (!Deny_Silent_Site(resp.ipaddr, AMBIGUOUS)
        || !Deny_Silent_Site(hostname, AMBIGUOUS)) {
      do_log(LT_CONN, 0, 0, "[%d/%s/%s] Refused connection.", resp.fd,
             hostname, resp.ipaddr);
    }
    shutdown(resp.fd, 2);
    closesocket(resp.fd);
    return;
  }

  if (resp.connected_to == TINYPORT)
    source = CS_IP_SOCKET;
  else if (resp.connected_to == SSLPORT)
    source = CS_OPENSSL_SOCKET;
  else
    source = CS_UNKNOWN;

  do_log(LT_CONN, 0, 0, "[%d/%s/%s] Connection opened from %s.", resp.fd,
         hostname, resp.ipaddr, source_to_s(source));
  set_keepalive(resp.fd, options.keepalive_timeout);


  initializesock(resp.fd, hostname, resp.ipaddr, source);
}
void
query_info_slave(int fd)
{
  struct request_dgram req;
  struct hostname_info *hi;
  char buf[BUFFER_LEN], *bp;
  ssize_t slen;

  FD_SET(fd, &info_pending);
  if (fd > pending_max)
    pending_max = fd + 1;

  info_queue_time = time(NULL);

  if (info_slave_state == INFO_SLAVE_DOWN) {
    if (!make_info_slave()) {
      FD_CLR(fd, &info_pending);
      closesocket(fd);          /* Just drop the connection if the slave gets halted.
                                   A subsequent reconnect will work. */
    }
    return;
  }


  memset(&req, 0, sizeof req);

  req.rlen = MAXSOCKADDR;
  if (getpeername(fd, (struct sockaddr *) req.remote.data, &req.rlen) < 0) {
    penn_perror("socket peer vanished");
    shutdown(fd, 2);
    closesocket(fd);
    FD_CLR(fd, &info_pending);
    return;
  }

  /* Check for forbidden sites before bothering with ident */
  bp = buf;
  hi = ip_convert(&req.remote.addr, req.rlen);
  safe_str(hi ? hi->hostname : "Not found", buf, &bp);
  *bp = '\0';
  if (Forbidden_Site(buf)) {
    char port[NI_MAXSERV];
    if (getnameinfo(&req.remote.addr, req.rlen, NULL, 0, port, sizeof port,
                    NI_NUMERICHOST | NI_NUMERICSERV) != 0)
      penn_perror("getting remote port number");
    else {
      if (!Deny_Silent_Site(buf, AMBIGUOUS)) {
        do_log(LT_CONN, 0, 0, "[%d/%s] Refused connection (remote port %s)",
               fd, buf, port);
      }
    }
    closesocket(fd);
    FD_CLR(fd, &info_pending);
    return;
  }

  req.llen = MAXSOCKADDR;
  if (getsockname(fd, (struct sockaddr *) req.local.data, &req.llen) < 0) {
    penn_perror("socket self vanished");
    closesocket(fd);
    FD_CLR(fd, &info_pending);
    return;
  }

  req.fd = fd;
  req.use_dns = USE_DNS;

  slen = send(info_slave, &req, sizeof req, 0);
  if (slen < 0) {
    penn_perror("info slave query: write error");
    make_info_slave();
    return;
  } else if (slen != (int) sizeof req) {
    /* Shouldn't happen! */
    penn_perror("info slave query: partial packet");
    make_info_slave();
    return;
  }
  info_slave_state = INFO_SLAVE_PENDING;
}
示例#8
0
/** Create a new SSL slave.
 * \param port The port to listen on for SSL connections.
 * \return 0 on success, -1 on failure
 */
int
make_ssl_slave(void)
{
    int fds[2];

    if (ssl_slave_state != SSL_SLAVE_DOWN) {
        do_rawlog(LT_ERR,
                  "Attempt to start ssl slave when a copy is already running.");
        return -1;
    }

    if (ssl_slave_halted) {
        do_rawlog(LT_ERR, "Attempt to start disabled ssl slave.");
        return -1;
    }

    if (startup_attempts == 0)
        time(&startup_window);

    startup_attempts += 1;

    if (startup_attempts > MAX_ATTEMPTS) {
        time_t now;

        time(&now);
        if (difftime(now, startup_window) <= 60.0) {
            do_rawlog(LT_ERR, "Disabling ssl_slave due to too many errors.");
            ssl_slave_halted = true;
            return -1;
        } else {
            /* Reset counter */
            startup_window = now;
            startup_attempts = 0;
        }
    }

    if (pipe(fds) < 0) {
        do_rawlog(LT_ERR, "Unable to create pipe to speak to ssl_slave: %s",
                  strerror(errno));
        return -1;
    }

    if (fds[0] >= maxd)
        maxd = fds[0] + 1;
    if (fds[1] >= maxd)
        maxd = fds[1] + 1;

    if ((ssl_slave_pid = fork()) == 0) {
        /* Set up and exec ssl_slave */
        int n, errfd = -1, connfd = -1;
        struct log_stream *lg;

        /* Close all open files but LT_CONN and LT_ERR, and assign them as
           stdout and stderr, respectively. */

        /* If called on startup, maxd is 0 but log files and such have
           been opened. Use a reasonable max descriptor. If called because
           ssl_slave went down, maxd will be set properly already. */
        if (!maxd)
            maxd = 20;

        lg = lookup_log(LT_ERR);
        if (lg)
            errfd = fileno(lg->fp);

        lg = lookup_log(LT_CONN);
        if (lg)
            connfd = fileno(lg->fp);

        dup2(fds[0], 0);            /* stdin */
        dup2(connfd, 1);            /* stdout */
        dup2(errfd, 2);             /* stderr */

        for (n = 3; n < maxd; n++)
            close(n);

        execl("./ssl_slave", "ssl_slave", "for", MUDNAME, NULL);
        penn_perror("execing ssl slave");
        return EXIT_FAILURE;
    } else if (ssl_slave_pid < 0) {
        do_rawlog(LT_ERR, "Failure to fork ssl_slave: %s", strerror(errno));
        return -1;
    } else {
        struct ssl_slave_config cf;

        ssl_slave_ctl_fd = fds[1];
        close(fds[0]);

        /* Set up arguments to the slave */
        memset(&cf, 0, sizeof cf);
        strcpy(cf.socket_file, options.socket_file);
        strcpy(cf.ssl_ip_addr, SSL_IP_ADDR);
        cf.normal_port = options.port;
        cf.ssl_port = options.ssl_port;
        strcpy(cf.private_key_file, options.ssl_private_key_file);
        strcpy(cf.ca_file, options.ssl_ca_file);
        cf.require_client_cert = options.ssl_require_client_cert;
        cf.keepalive_timeout = options.keepalive_timeout;

        if (write(ssl_slave_ctl_fd, &cf, sizeof cf) < 0) {
            do_rawlog(LT_ERR, "Unable to send ssl_slave config options: %s",
                      strerror(errno));
            return -1;
        }

        ssl_slave_state = SSL_SLAVE_RUNNING;
        do_rawlog(LT_ERR, "Spawning ssl_slave, communicating over %s, pid %d.",
                  options.socket_file, ssl_slave_pid);
        return 0;
    }

    return -1;
}