Пример #1
0
/* helper function for reading data from a client */
int client_read_bytes (client_t *client, void *buf, unsigned len)
{
    int (*con_read)(struct connection_tag *handle, void *buf, size_t len) = connection_read;
    int bytes;

    if (len == 0)
        return 0;
    if (client->refbuf && client->pos < client->refbuf->len)
    {
        unsigned remaining = client->refbuf->len - client->pos;
        if (remaining > len)
            remaining = len;
        memcpy (buf, client->refbuf->data + client->pos, remaining);
        client->pos += remaining;
        if (client->pos >= client->refbuf->len)
            client_set_queue (client, NULL);
        return remaining;
    }
#ifdef HAVE_OPENSSL
    if (client->connection.ssl)
        con_read = connection_read_ssl;
#endif
    bytes = con_read (&client->connection, buf, len);

    if (bytes == -1 && client->connection.error)
        DEBUG0 ("reading from connection has failed");

    return bytes;
}
Пример #2
0
int main(int argc, char* argv[]) {
  int opt;
  bool vns_console = false;
  char* command_file = NULL; char* pid_file = NULL;
  int i, ifcount = 0; struct vnlif iflist[vnlif_maxcount];

  int command_fd, command_eth = -1; FILE* pid_fd;
  struct pollfd pollfds[2+2*vnlif_maxcount]; int pollres;
  char buffer[MSGSIZE]; int len;
  char* pktbuffer = buffer + MSGHDRSIZE;
  c_base* vnsbasehdr = (c_base*)buffer;
  c_hwinfo* vnshwinfo = (c_hwinfo*)buffer;
  c_packet_header* vnspkthdr = (c_packet_header*)buffer;

// ---------------- parse command options ----------------
  while ((opt = getopt(argc, argv, "si:c:p:")) != -1) {
    switch (opt) {
    case 's': vns_console = true; break;
    case 'i':
      if (ifcount < vnlif_maxcount) {
        if (!vnlif_parse(iflist + ifcount, optarg)) die("vnlif_parse");
      } else {
        die("cmdline vnlif_maxcount");
      }
      ++ifcount;
      break;
    case 'c': command_file = optarg; break;
    case 'p': pid_file = optarg; break;
    }
  }

  if (ifcount == 0 || command_file == NULL || pid_file == NULL) {
    printf("vnlsvc: Virtual Network Lab Service\nTAP-UDP: vnlsvc -i eth0/tap0/1a:8e:22:b1:da:f1/198.51.100.1#255.255.255.0/192.0.2.1:2001/192.0.2.2:2001/ -c /tmp/command.pipe -p /tmp/vnltun.pid\nVNSconsole-UDP: vnlsvc -s -i eth0//1a:8e:22:b1:da:f1/198.51.100.1#255.255.255.0/192.0.2.1:2001/192.0.2.2:2001/ -c /tmp/command.pipe -p /tmp/vnltun.pid\n");
    exit(1);
  }

// ---------------- open files and sockets ----------------
  command_fd = open(command_file, O_RDONLY | O_NONBLOCK);
  if (command_fd < 0) die("command open");

  pollfds[0].fd = 0; pollfds[0].events = vns_console ? POLLIN : 0;
  pollfds[1].fd = command_fd; pollfds[1].events = POLLIN;
  for (i = 0; i < ifcount; ++i) {
    pollfds[2+i].fd = iflist[i].udp_fd
      = udp_open(&(iflist[i].tip), &(iflist[i].rtip));
    pollfds[2+i].events = POLLIN;
    if (!vns_console) {
      pollfds[2+ifcount+i].fd = iflist[i].tap_fd = tap_open(iflist[i].tapname);
      pollfds[2+ifcount+i].events = POLLIN;
    }
  }
  //pollfds: 0=stdin, 1=command pipe, 2..2+ifcount-1=UDP, 2+ifcount..2+2*ifcount-1=TAP

// ---------------- initialize ----------------
  pid_fd = fopen(pid_file, "w");
  if (pid_fd == NULL) die("pid output");
  fprintf(pid_fd, "%d", getpid());
  fclose(pid_fd);

  srand(time(NULL));

  if (vns_console) {
    con_init();
    vns_wAuthReq(buffer); con_write(buffer);
  }

// ---------------- main poll loop ----------------
  while (1) {
    pollres = poll(pollfds, 2+(vns_console?1:2)*ifcount, -1);
    if (pollres == -1) die("poll");
    else if (pollres == 0) { perror("poll timeout"); continue; }

/*
    for (i = 0; i < 2+(vns_console?1:2)*ifcount; ++i) {
      if (pollfds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
        FILE* dbglog = fopen("/tmp/vnlsvc.debug.log","a");
        fprintf(dbglog,"%d %d %d %x\n",time(NULL),getpid(),i,pollfds[i].revents);
        fclose(dbglog);
      }
    }
*/

// ---------------- VNS protocol, console to UDP ----------------
    if (vns_console && (pollfds[0].revents & POLLIN)) {
      if (con_read(buffer)) {
        switch (vns_getType(buffer)) {
        case VNS_AUTH_REPLY:
          vns_wAuthStatus(buffer); con_write(buffer);
          break;
        case VNSOPEN:
          iflist_hwinfo(vnshwinfo, iflist, ifcount);
          con_write(buffer);
          break;
        case VNSPACKET:
          i = iflist_find(iflist, ifcount, vnspkthdr->mInterfaceName);
          if (i < 0) break;
          len = ntohl(vnspkthdr->mLen) - sizeof(c_packet_header);
          if (lossy_filter(iflist[i].lossy)) {
            udp_write(iflist[i].udp_fd, pktbuffer, len, &(iflist[i].rtip));
          }
          break;
        }
      }
    }
// ---------------- console error ----------------
    if (vns_console && (pollfds[0].revents & (POLLERR | POLLHUP))) {
      die("console error");
    }

// ---------------- setlossy command ----------------
    if (pollfds[1].revents & POLLIN) {
      if (command_eth < 0 && 1 == read(command_fd, buffer, 1)) {
        command_eth = buffer[0];
      }
      if (1 == read(command_fd, buffer, 1) && command_eth < ifcount) {
        iflist[command_eth].lossy = buffer[0];
      }
    }
    if (pollfds[1].revents & POLLHUP) {
      command_eth = -1;
      close(command_fd);
      pollfds[1].fd = command_fd = open(command_file, O_RDONLY | O_NONBLOCK);
      if (command_fd < 0) die("command reopen");
    }

    for (i = 0; i < ifcount; ++i) {
// ---------------- UDP to console/TAP ----------------
      if (pollfds[2+i].revents & POLLIN) {
        len = udp_read(iflist[i].udp_fd, pktbuffer, &(iflist[i].rtip));
        if (len > 0) {
          if (vns_console) {
            vns_wPacketHdr(buffer, len, iflist[i].ifname);
            con_write(buffer);
          } else {
            tap_write(iflist[i].tap_fd, pktbuffer, len);
          }
        }
      }
// ---------------- UDP error ----------------
      if (pollfds[2+i].revents & POLLERR) {
        int sockerror; socklen_t socklen = sizeof(int);
        getsockopt(iflist[i].udp_fd, SOL_SOCKET, SO_ERROR, &sockerror, &socklen);
      }
// ---------------- TAP to UDP ----------------
      if (!vns_console && (pollfds[2+ifcount+i].revents & POLLIN)) {
        len = tap_read(iflist[i].tap_fd, pktbuffer);
        if (len > 0 && lossy_filter(iflist[i].lossy)) {
          udp_write(iflist[i].udp_fd, pktbuffer, len, &(iflist[i].rtip));
        }
      }
    }
  }
}
Пример #3
0
/**
 * @brief	Extract the contents of a literal string and advance the position of the parser stream.
 * @note	This function expects as input a string beginning with '{' and followed by a numerical string, an optional '+', and a closing '}'.
 	 	 	After reading in the numerical size parameter, it then attempts to read in that many bytes of input from the network stream.
 * @param	con		the client IMAP connection passing the literal string as input to the server.
 * @param	output	the address of a managed string that will receive a copy of the literal string's contents on success, or NULL on failure or if it is zero length.
 * @param	start	the address of a pointer to the start of the buffer to be parsed (beginning with '{'), that will also be updated to
 * 					point to the next argument in the sequence on success.
 * @param	length	a pointer to a size_t variable that contains the length of the string to be parsed, and that will be updated to reflect
 * 					the length of the remainder of the input string that follows the parsed literal string.
 * @return	-1 on general or parse error or if an enclosing pair of double quotes was not found, or 1 if the supplied quoted string was valid.
 */
int_t imap_parse_literal(connection_t *con, stringer_t **output, chr_t **start, size_t *length) {

	chr_t *holder;
	int_t plus = 0;
	stringer_t *result;
	size_t characters, left;
	ssize_t nread;
	uint64_t literal, number;

	// Get setup.
	holder = *start;
	left = *length;
	*output = NULL;

	// Skip the opening bracket.
	if (*holder != '{' || !left) {
		return -1;
	}
	else {
		holder++;
		left--;
	}

	// Advance until we have a break character.
	while (left && *holder >= '0' && *holder <= '9') {
		holder++;
		left--;
	}

	// Store the length.
	characters = holder - *start - 1;

	if (left && *holder == '+') {
		plus = 1;
		holder++;
		left--;
	}

	if (*holder != '}' || !characters) {
		return -1;
	}

	// Convert to a number. Make sure the number is positive.
	if (!uint64_conv_bl(*start + 1, characters, &number)) {
		return -1;
	}

	literal = (size_t)number;

	// If the number is larger than 128 megabytes, then reject it.
	if (!plus && number > 134217728) {
		return -1;
	}
	// They client is already transmitting, so read the entire file, then reject it.
	else if (number > 134217728) {

		while (number > 0) {

			// Read the data.
			if ((nread = con_read(con)) <= 0) {
				log_pedantic("The connection was dropped while reading the literal.");
				return -1;
			}

			// Deal with signedness problem.
			characters = nread;

			if (number > (uint64_t)characters) {
				number -= characters;
			}
			else {

				// If we have any extra characters in the buffer, move them to the beginning.
				if ((uint64_t)characters > number) {
					mm_move(st_char_get(con->network.buffer), st_char_get(con->network.buffer) + number, characters - number);
					st_length_set(con->network.buffer, characters - number);
					con->network.line = line_pl_st(con->network.buffer, 0);
				}
				else {
					st_length_set(con->network.buffer, 0);
					con->network.line = pl_null();
				}

				// Make sure we have a full line.
				if (pl_empty(con->network.line) && con_read_line(con, true) <= 0) {
					log_pedantic("The connection was dropped while reading the literal.");
					return -1;
				}

				number = 0;
			}

		}

		return -1;
	}

	// If this is not a plus literal, output the proceed statement.
	if (!plus) {
		con_write_bl(con, "+ GO\r\n", 6);
	}

	// Handle the special case of a zero length literal.
	if (literal == 0) {

		// Read the next line.
		if (con_read_line(con, true) <= 0) {
			log_pedantic("The connection was dropped while reading the literal.");
			return -1;
		}

		*start = st_char_get(con->network.buffer);
		*length = pl_length_get(con->network.line);

		// There should be a space before the next argument.
		if (*length && **start == ' ') {
			(*start)++;
			(*length)--;
		}

		return 1;
	}

	// Allocate a stringer for the buffer.
	if (!(result = st_alloc(literal))) {
		log_pedantic("Unable to allocate a buffer of %lu bytes for the literal argument.", literal);
		return -1;
	}

	// So we know how many more characters to read.
	left = literal;

	// Where we put the data.
	holder = st_char_get(result);

	// Keep looping until we run out of data.
	while (left) {

		// Read the data.
		if ((nread = con_read(con)) <= 0) {
			log_pedantic("The connection was dropped while reading the literal.");
			st_free(result);
			return -1;
		}

		characters = nread;

		// If we have a buffer, copy the data into the buffer.
		mm_copy(holder, st_char_get(con->network.buffer), (left > characters) ? characters : left);

		if (left > characters) {
			holder += characters;
			left -= characters;
		}
		else {
		 	st_length_set(result, literal);

			// If we have any extra characters in the buffer, move them to the beginning.
			if (characters > left) {
				mm_move(st_char_get(con->network.buffer), st_char_get(con->network.buffer) + left, characters - left);
				st_length_set(con->network.buffer, characters - left);
				con->network.line = line_pl_st(con->network.buffer, 0);
			}
			else {
					st_length_set(con->network.buffer, 0);
					con->network.line = pl_null();
			}

			// Make sure we have a full line.
			if (pl_empty(con->network.line) && con_read_line(con, true) <= 0) {
				log_pedantic("The connection was dropped while reading the literal.");
				st_free(result);
				return -1;
			}
			left = 0;
		}
	}

	*start = st_char_get(con->network.buffer);
	*length = pl_length_get(con->network.line);

	// There should be a space before the next argument.
	if (*length && **start == ' ') {
		(*start)++;
		(*length)--;
	}

	if (result != NULL) {
		*output = result;
	}
	else {
		return -1;
	}

	return 1;
}