Beispiel #1
0
static uint32_t find_free_or_expired_nip(GDHCPServer *dhcp_server,
					const uint8_t *safe_mac)
{
	uint32_t ip_addr;
	struct dhcp_lease *lease;
	GList *list;
	ip_addr = dhcp_server->start_ip;
	for (; ip_addr <= dhcp_server->end_ip; ip_addr++) {
		/* e.g. 192.168.55.0 */
		if ((ip_addr & 0xff) == 0)
			continue;

		/* e.g. 192.168.55.255 */
		if ((ip_addr & 0xff) == 0xff)
			continue;

		lease = find_lease_by_nip(dhcp_server,
				(uint32_t) htonl(ip_addr));
		if (lease != NULL)
			continue;

		if (arp_check(htonl(ip_addr), safe_mac) == TRUE)
			return htonl(ip_addr);
	}

	/* The last lease is the oldest one */
	list = g_list_last(dhcp_server->lease_list);
	if (list == NULL)
		return 0;

	lease = list->data;
	if (lease == NULL)
		return 0;

	 if (is_expired_lease(lease) == FALSE)
		return 0;

	 if (arp_check(lease->lease_nip, safe_mac) == FALSE)
		return 0;

	return lease->lease_nip;
}
Beispiel #2
0
void net_bridge_wait_ip(Bridge *br) {
	assert(br);
	if (br->configured == 0 || br->arg_ip_none)
		return;

	// wait for the ip address to come up
	int cnt = 0;
	while (cnt < 5) {			  // arp_check has a 1s wait
		if (arp_check(br->dev, br->ipsandbox, br->ip) == 0)
			break;
		cnt++;
	}
}
Beispiel #3
0
// assign a random IP address and check it
// the address needs to be in the range if it --iprange was specified
static uint32_t arp_random(const char *dev, Bridge *br) {
    assert(dev);
    assert(br);
    uint32_t ifip = br->ip;
    uint32_t ifmask = br->mask;
    assert(ifip);
    assert(ifmask);

    if (arg_debug)
        printf("ARP-scan %s, %d.%d.%d.%d/%d\n",
               dev, PRINT_IP(ifip), mask2bits(ifmask));

    // determine the range based on network address
    uint32_t range = ~ifmask + 1; // the number of potential addresses
    // this software is not supported for /31 networks
    if (range < 4)
        return 0; // the user will have to set the IP address manually
    range -= 2; // subtract the network address and the broadcast address
    uint32_t start = (ifip & ifmask) + 1;

    // adjust range based on --iprange params
    if (br->iprange_start && br->iprange_end) {
        start = br->iprange_start;
        range = br->iprange_end - br->iprange_start;
    }

    if (arg_debug)
        printf("IP address range from %d.%d.%d.%d to %d.%d.%d.%d\n",
               PRINT_IP(start), PRINT_IP(start + range));

    // generate a random address - 10 tries
    uint32_t dest = 0;
    int i = 0;
    for (i = 0; i < 10; i++) {
        dest = start + ((uint32_t) rand()) % range;
        if (dest == ifip)	// do not allow the interface address
            continue;		// try again

        // if we've made it up to here, we have a valid address
        break;
    }
    if (i == 10)	// we failed 10 times
        return 0;

    // check address
    uint32_t rv = arp_check(dev, dest, ifip);
    if (!rv)
        return dest;
    return 0;
}
Beispiel #4
0
static void sandbox_if_up(Bridge *br) {
	assert(br);
	if (!br->configured)
		return;
		
	char *dev = br->devsandbox;
	net_if_up(dev);

	if (br->arg_ip_none == 1);	// do nothing
	else if (br->arg_ip_none == 0 && br->macvlan == 0) {
		if (br->ipsandbox == br->ip) {
			fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address.\n", PRINT_IP(br->ipsandbox), br->dev);
			exit(1);
		}
		
		// just assign the address
		assert(br->ipsandbox);
		if (arg_debug)
			printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev);
		net_if_ip(dev, br->ipsandbox, br->mask, br->mtu);
		net_if_up(dev);
	}
	else if (br->arg_ip_none == 0 && br->macvlan == 1) {
		// reassign the macvlan address
		if (br->ipsandbox == 0)
			// ip address assigned by arp-scan for a macvlan device
			br->ipsandbox = arp_assign(dev, br); //br->ip, br->mask);
		else {
			if (br->ipsandbox == br->ip) {
				fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address.\n", PRINT_IP(br->ipsandbox), br->dev);
				exit(1);
			}
			
			uint32_t rv = arp_check(dev, br->ipsandbox, br->ip);
			if (rv) {
				fprintf(stderr, "Error: the address %d.%d.%d.%d is already in use.\n", PRINT_IP(br->ipsandbox));
				exit(1);
			}
		}
			
		if (arg_debug)
			printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev);
		net_if_ip(dev, br->ipsandbox, br->mask, br->mtu);
		net_if_up(dev);
	}
	
	if (br->ip6sandbox)
		 net_if_ip6(dev, br->ip6sandbox);
}
Beispiel #5
0
// go sequentially trough all IP addresses and assign the first one not in use
static uint32_t arp_sequential(const char *dev, Bridge *br) {
    assert(dev);
    assert(br);
    uint32_t ifip = br->ip;
    uint32_t ifmask = br->mask;
    assert(ifip);
    assert(ifmask);

    // range based on network address
    uint32_t range = ~ifmask + 1; // the number of potential addresses
    // this software is not supported for /31 networks
    if (range < 4)
        return 0; // the user will have to set the IP address manually
    range -= 2; // subtract the network address and the broadcast address

    // try all possible ip addresses in ascending order
    // start address
    uint32_t dest = (ifip & ifmask) + 1;
    if (br->iprange_start)
        dest = br->iprange_start;
    // end address
    uint32_t last = dest + range - 1;
    if (br->iprange_end)
        last = br->iprange_end;

    if (arg_debug)
        printf("Trying IP address range from %d.%d.%d.%d to %d.%d.%d.%d\n",
               PRINT_IP(dest), PRINT_IP(last));

    // loop through addresses and stop as soon as you find an unused one
    while (dest <= last) {
        if (dest == ifip) {
            dest++;
            continue;
        }
        uint32_t rv = arp_check(dev, dest, ifip);
        if (!rv)
            return dest;
        dest++;
    }

    return 0;
}
Beispiel #6
0
void net_configure_sandbox_ip(Bridge *br) {
	assert(br);
	if (br->configured == 0)
		return;

	if (br->arg_ip_none)
		br->ipsandbox = 0;
	else if (br->ipsandbox) {
		// check network range
		char *rv = in_netrange(br->ipsandbox, br->ip, br->mask);
		if (rv) {
			fprintf(stderr, "%s", rv);
			exit(1);
		}
		// send an ARP request and check if there is anybody on this IP address
		if (arp_check(br->dev, br->ipsandbox, br->ip)) {
			fprintf(stderr, "Error: IP address %d.%d.%d.%d is already in use\n", PRINT_IP(br->ipsandbox));
			exit(1);
		}
	}
	else
		br->ipsandbox = arp_assign(br->dev, br->ip, br->mask);
}
Beispiel #7
0
/* This state machine is based on the one from udhcpc
   written by Russ Dill */
int dhcp_run (options_t *options)
{
  interface_t *iface;
  int mode = SOCKET_CLOSED;
  int state = STATE_INIT;
  struct timeval tv;
  int xid = 0;
  long timeout = 0;
  fd_set rset;
  int maxfd;
  int retval;
  dhcpmessage_t message;
  dhcp_t *dhcp;
  int type = DHCP_DISCOVER;
  int last_type = DHCP_DISCOVER;
  bool daemonised = false;
  unsigned long start = 0;
  unsigned long last_send = 0;
  int sig;
  unsigned char *buffer = NULL;
  int buffer_len = 0;
  int buffer_pos = 0;

  if (! options || (iface = (read_interface (options->interface,
					     options->metric))) == NULL)
    return -1;

  /* Remove all existing addresses.
     After all, we ARE a DHCP client whose job it is to configure the
     interface. We only do this on start, so persistent addresses can be added
     afterwards by the user if needed. */
  flush_addresses (iface->name);

  dhcp = xmalloc (sizeof (dhcp_t));
  memset (dhcp, 0, sizeof (dhcp_t));

  strcpy (dhcp->classid, options->classid);
  if (options->clientid[0])
    strcpy (dhcp->clientid, options->clientid);
  else
    sprintf (dhcp->clientid, "%s", ether_ntoa (&iface->ethernet_address));

  if (options->requestaddress.s_addr != 0)
    dhcp->address.s_addr = options->requestaddress.s_addr;

  signal_setup ();

  while (1)
    {
      if (timeout > 0 || (options->timeout == 0 &&
			  (state != STATE_INIT || xid)))
	{
	  if (options->timeout == 0 || dhcp->leasetime == -1)
	    {
	      logger (LOG_DEBUG, "waiting on select for infinity");
	      maxfd = signal_fd_set (&rset, iface->fd);
	      retval = select (maxfd + 1, &rset, NULL, NULL, NULL);
	    }
	  else
	    {
	      /* Resend our message if we're getting loads of packets
		 that aren't for us. This mainly happens on Linux as it
		 doesn't have a nice BPF filter. */
	      if (iface->fd > -1 && uptime () - last_send >= TIMEOUT_MINI)
		SEND_MESSAGE (last_type);

	      logger (LOG_DEBUG, "waiting on select for %d seconds",
		      timeout);
	      /* If we're waiting for a reply, then we re-send the last
		 DHCP request periodically in-case of a bad line */
	      retval = 0;
	      while (timeout > 0 && retval == 0)
		{
		  if (iface->fd == -1)
		    tv.tv_sec = SELECT_MAX;
		  else
		    tv.tv_sec = TIMEOUT_MINI;
		  if (timeout < tv.tv_sec)
		    tv.tv_sec = timeout;
		  tv.tv_usec = 0;
		  start = uptime ();
		  maxfd = signal_fd_set (&rset, iface->fd);
		  retval = select (maxfd + 1, &rset, NULL, NULL, &tv);
		  timeout -= uptime () - start;
		  if (retval == 0 && iface->fd != -1 && timeout > 0)
		    SEND_MESSAGE (last_type);
		}
	    }
	}
      else
	retval = 0;

      /* We should always handle our signals first */
      if (retval > 0 && (sig = signal_read (&rset)))
	{
	  switch (sig)
	    {
	    case SIGINT:
	      logger (LOG_INFO, "receieved SIGINT, stopping");
	      retval = 0;
	      goto eexit;

	    case SIGTERM:
	      logger (LOG_INFO, "receieved SIGTERM, stopping");
	      retval = 0;
	      goto eexit;

	    case SIGALRM:

	      logger (LOG_INFO, "receieved SIGALRM, renewing lease");
	      switch (state)
		{
		case STATE_BOUND:
		case STATE_RENEWING:
		case STATE_REBINDING:
		  state = STATE_RENEW_REQUESTED;
		  break;
		case STATE_RENEW_REQUESTED:
		case STATE_REQUESTING:
		case STATE_RELEASED:
		  state = STATE_INIT;
		  break;
		}

	      timeout = 0;
	      xid = 0;
	      break;

	    case SIGHUP:
	      if (state == STATE_BOUND || state == STATE_RENEWING
		  || state == STATE_REBINDING)
		{
		  logger (LOG_INFO, "received SIGHUP, releasing lease");
		  SOCKET_MODE (SOCKET_OPEN);
		  xid = random_xid ();
		  if ((open_socket (iface, false)) >= 0)
		    SEND_MESSAGE (DHCP_RELEASE);
		  SOCKET_MODE (SOCKET_CLOSED);
		  unlink (iface->infofile);
		}
	      else
		logger (LOG_ERR,
			"receieved SIGUP, but no we have lease to release");
	      retval = 0;
	      goto eexit;

	    default:
	      logger (LOG_ERR,
		      "received signal %d, but don't know what to do with it",
		      sig);
	    }
	}
      else if (retval == 0) /* timed out */
	{
	  switch (state)
	    {
	    case STATE_INIT:
	      if (iface->previous_address.s_addr != 0)
		{
		  logger (LOG_ERR, "lost lease");
		  xid = 0;
		  SOCKET_MODE (SOCKET_CLOSED);
		  if (! options->persistent)
		    {
		      free_dhcp (dhcp);
		      memset (dhcp, 0, sizeof (dhcp_t));
		      configure (options, iface, dhcp);
		    }
		  if (! daemonised)
		    {
		      retval = -1;
		      goto eexit;
		    }
		  break;
		}

	      if (xid == 0)
		xid = random_xid ();
	      else
		{
		  logger (LOG_ERR, "timed out");
		  if (! daemonised)
		    {
		      retval = -1;
		      goto eexit;
		    }
		}

	      SOCKET_MODE (SOCKET_OPEN);
	      timeout = options->timeout;
	      iface->start_uptime = uptime ();
	      if (dhcp->address.s_addr == 0)
		{
		  logger (LOG_INFO, "broadcasting for a lease");
		  SEND_MESSAGE (DHCP_DISCOVER);
		}
	      else
		{
		  logger (LOG_INFO, "broadcasting for a lease of %s",
			  inet_ntoa (dhcp->address));
		  SEND_MESSAGE (DHCP_REQUEST);
		  state = STATE_REQUESTING;
		}

	      break;
	    case STATE_BOUND:
	    case STATE_RENEW_REQUESTED:
	      state = STATE_RENEWING;
	      xid = random_xid ();
	    case STATE_RENEWING:
	      iface->start_uptime = uptime ();
	      logger (LOG_INFO, "renewing lease of %s", inet_ntoa
		      (dhcp->address));
	      SOCKET_MODE (SOCKET_OPEN);
	      SEND_MESSAGE (DHCP_REQUEST);
	      timeout = dhcp->rebindtime - dhcp->renewaltime;
	      state = STATE_REBINDING;
	      break;
	    case STATE_REBINDING:
	      logger (LOG_ERR, "lost lease, attemping to rebind");
	      SOCKET_MODE (SOCKET_OPEN);
	      SEND_MESSAGE (DHCP_DISCOVER);
	      timeout = dhcp->leasetime - dhcp->rebindtime;
	      state = STATE_INIT;
	      break;
	    case STATE_REQUESTING:
	      logger (LOG_ERR, "timed out");
	      if (! daemonised)
		goto eexit;

	      state = STATE_INIT;
	      SOCKET_MODE (SOCKET_CLOSED);
	      timeout = 0;
	      xid = 0;
	      free_dhcp (dhcp);
	      memset (dhcp, 0, sizeof (dhcp_t));
	      break;

	    case STATE_RELEASED:
	      dhcp->leasetime = -1;
	      break;
	    }
	}
      else if (retval > 0 && mode != SOCKET_CLOSED && FD_ISSET(iface->fd, &rset))
	{

	  /* Allocate our buffer space for BPF.
	     We cannot do this until we have opened our socket as we don't
	     know how much of a buffer we need until then. */
	  if (! buffer)
	    buffer = xmalloc (iface->buffer_length);
	  buffer_len = iface->buffer_length;
	  buffer_pos = -1;

	  /* We loop through until our buffer is empty.
	     The benefit is that if we get >1 DHCP packet in our buffer and
	     the first one fails for any reason, we can use the next. */

	  memset (&message, 0, sizeof (struct dhcpmessage_t));
	  int valid = 0;
	  struct dhcp_t *new_dhcp;
	  new_dhcp = xmalloc (sizeof (dhcp_t));

	  while (buffer_pos != 0)
	    {
	      if (get_packet (iface, (unsigned char *) &message, buffer,
			      &buffer_len, &buffer_pos) < 0)
		break;

	      if (xid != message.xid)
		{
		  logger (LOG_ERR,
			  "ignoring packet with xid %d as it's not ours (%d)",
			  message.xid, xid);
		  continue;
		}

	      logger (LOG_DEBUG, "got a packet with xid %d", message.xid);
	      memset (new_dhcp, 0, sizeof (dhcp_t));
	      if ((type = parse_dhcpmessage (new_dhcp, &message)) < 0)
		{
		  logger (LOG_ERR, "failed to parse packet");
		  free_dhcp (new_dhcp);
		  continue;
		}

	      /* If we got here then the DHCP packet is valid and appears to
		 be for us, so let's clear the buffer as we don't care about
		 any more DHCP packets at this point. */
	      valid = 1;
	      break;
	    }

	  /* No packets for us, so wait until we get one */
	  if (! valid)
	    {
	      free (new_dhcp);
	      continue;
	    }

	  /* new_dhcp is now our master DHCP message */
	  free_dhcp (dhcp);
	  free (dhcp);
	  dhcp = new_dhcp;
	  new_dhcp = NULL;

	  /* We should restart on a NAK */
	  if (type == DHCP_NAK)
	    {
	      logger (LOG_INFO, "received NAK: %s", dhcp->message);
	      state = STATE_INIT;
	      timeout = 0;
	      xid = 0;
	      free_dhcp (dhcp);
	      memset (dhcp, 0, sizeof (dhcp_t));
	      configure (options, iface, dhcp);
	      continue;
	    }

	  switch (state)
	    {
	    case STATE_INIT:
	      if (type == DHCP_OFFER)
		{
		  logger (LOG_INFO, "offered lease of %s",
			  inet_ntoa (dhcp->address));

		  SEND_MESSAGE (DHCP_REQUEST);
		  state = STATE_REQUESTING;
		}
	      break;

	    case STATE_RENEW_REQUESTED:
	    case STATE_REQUESTING:
	    case STATE_RENEWING:
	    case STATE_REBINDING:
	      if (type == DHCP_ACK)
		{
		  SOCKET_MODE (SOCKET_CLOSED);
		  if (options->doarp && iface->previous_address.s_addr !=
		      dhcp->address.s_addr)
		    {
		      if (arp_check (iface, dhcp->address))
			{
			  SOCKET_MODE (SOCKET_OPEN);
			  SEND_MESSAGE (DHCP_DECLINE);
			  SOCKET_MODE (SOCKET_CLOSED);
			  free_dhcp (dhcp);
			  memset (dhcp, 0, sizeof (dhcp));
			  if (daemonised)
			    configure (options, iface, dhcp);

			  xid = 0;
			  state = STATE_INIT;
			  /* RFC 2131 says that we should wait for 10 seconds
			     before doing anything else */
			  sleep (10);
			  continue;
			}
		    }

		  if (! dhcp->leasetime)
		    {
		      dhcp->leasetime = DEFAULT_TIMEOUT;
		      logger(LOG_INFO,
			     "no lease time supplied, assuming %d seconds",
			     dhcp->leasetime);
		    }

		  if (! dhcp->renewaltime) 
		    {
		      dhcp->renewaltime = dhcp->leasetime / 2;
		      logger (LOG_INFO,
			      "no renewal time supplied, assuming %d seconds",
			      dhcp->renewaltime);
		    }

		  if (! dhcp->rebindtime)
		    {
		      dhcp->rebindtime = (dhcp->leasetime * 0x7) >> 3;
		      logger (LOG_INFO,
			      "no rebind time supplied, assuming %d seconds",
			      dhcp->rebindtime);
		    }

		  if (dhcp->leasetime == -1)
		    logger (LOG_INFO, "leased %s for infinity",
			    inet_ntoa (dhcp->address));
		  else
		    logger (LOG_INFO, "leased %s for %u seconds",
			    inet_ntoa (dhcp->address),
			    dhcp->leasetime, dhcp->renewaltime);

		  state = STATE_BOUND;
		  timeout = dhcp->renewaltime;
		  xid = 0;

		  if (configure (options, iface, dhcp) < 0 && ! daemonised)
		    {
		      retval = -1;
		      goto eexit;
		    }

		  if (! daemonised)
		    {
		      if ((daemonise (options->pidfile)) < 0 )
			{
			  retval = -1;
			  goto eexit;
			}
		      daemonised = true;
		    }
		}
	      else if (type == DHCP_OFFER)
		logger (LOG_INFO, "got subsequent offer of %s, ignoring ",
			inet_ntoa (dhcp->address));
	      else
		logger (LOG_ERR,
			"no idea what to do with DHCP type %d at this point",
			type);
	      break;
	    }