⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcdhcp.c

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 *
 *   DHCP - Dynamic Host Configuration Protocol (RFC 1541/2131/2132)
 *
 *   These extensions gets called if "MYIP" is set to "DHCP"
 *
 *   Version
 *
 *   0.5 : Oct 28, 1996 : G. Vanem - implemented from RFC1541 with
 *                                   help from pcbootp.c
 *
 *   0.6 : May 18, 1997 : G. Vanem - added RFC2131 DHCPINFORM message
 */

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

#include "copyrigh.h"
#include "wattcp.h"
#include "wattcpd.h"
#include "strings.h"
#include "language.h"
#include "misc.h"
#include "udp_dom.h"
#include "bsdname.h"
#include "ip_out.h"
#include "syslog2.h"
#include "pctcp.h"
#include "pcbsd.h"
#include "pcsed.h"
#include "pcarp.h"
#include "pcqueue.h"
#include "pcpkt.h"
#include "pcconfig.h"
#include "pcbootp.h"
#include "pcdhcp.h"

#if defined(USE_DHCP)

#if defined(USE_TFTP)
#include "tftp.h"
#endif

/*@-usedef*/

#define BROADCAST_FLAG  1

static DWORD exchange_id;
static DWORD gateway;
static DWORD dhcp_server   = 0;
static DWORD suggestLease  = 0;
static DWORD dhcp_renewal  = 0;
static DWORD dhcp_rebind   = 0;
static DWORD dhcp_iplease  = 0;
static DWORD check_timer   = 0;
static long  renewal_count = 0;
static long  rebind_count  = 0;

static int   bcast_on      = 1;
static int   bcast_flag    = 0;
static int   renewing      = 0;
static int   got_offer     = 0;
static int   configured    = 0;
static int   do_inform     = 0;
static int   arp_check_ip  = 0;

static int   dhcp_timeout  = 10;
static int   max_retries   = 3;

static time_t     start_time;
static sock_type *sock;

static BYTE default_request_list[] = {
            SUBNET_MASK,
            ROUTERS_ON_SNET,
            DNS_SRV,
            COOKIE_SRV,
            LPR_SRV,
            HOST_NAME,
            DOMAIN_NAME,
            IP_DEFAULT_TTL,
            IF_MTU,
            ARP_CACHE_TIMEOUT,
            ETHERNET_ENCAPSULATION,
            TCP_DEFAULT_TTL,
#if defined(USE_BSD_FUNC)
            LOG_SRV,         /* links in syslog2 */
            NBIOS_NAME_SRV,  /* Samba needs this */
#endif
#if defined(USE_TFTP)
            DHCP_TFTP_SERVER,
            DHCP_BOOT_FILENAME
#endif
          };

static struct DHCP_list request_list = {
                        &default_request_list[0],
                        sizeof (default_request_list)
                      };

static struct DHCP_list extra_options = { NULL, 0 };

static void  dhcp_option_add  (BYTE *opt, int max);
static void  dhcp_options_free(void);
static void  dhcp_set_timers  (void);
static void  dhcp_daemon      (void);
static BYTE *put_request_list (BYTE *opt, int filled);

static int  trace_on = 0;

#if defined(USE_DEBUG)
  static char traceBuf [20];
  #define TRACE(fmt,arg)   do { if(trace_on)(*_printf)(fmt,arg); } while(0)
  #define INET_NTOA(x)     _inet_ntoa (traceBuf, x)
#else
  #define TRACE(fmt,arg)   ((void)0)
  #define INET_NTOA(x)     ((void)0)
#endif


/*-------------------------------------------------------------------*/

static void DHCP_bootHeader (struct dhcp *out, BYTE op)
{
  DWORD myip = intel (my_ip_addr);

  memset (out, 0, sizeof(*out));

  _eth_get_hwtype (&out->dh_htype, &out->dh_hlen);

  out->dh_op     = op;
  out->dh_xid    = exchange_id;
  out->dh_secs   = intel16 ((WORD)(time(NULL) - start_time));
  out->dh_flags  = (bcast_on && bcast_flag) ? BROADCAST_FLAG : 0;
  out->dh_yiaddr = myip;
  out->dh_ciaddr = myip;
  out->dh_giaddr = gateway;
  memcpy (&out->dh_chaddr, &_eth_addr, sizeof(eth_address));
  *(DWORD*) &out->dh_opt[0] = DHCP_MAGIC_COOKIE;
}

/*-------------------------------------------------------------------*/

static int DHCP_send (struct dhcp *out, BYTE *end, BOOL full_size)
{
  int len;

  if (full_size)
       len = sizeof (*out);
  else len = end - (BYTE*)out;

  return sock_fastwrite (sock, (BYTE*)out, len);
}

/*-------------------------------------------------------------------*/

static int DHCP_discover (struct dhcp *out)
{
  BYTE *opt   = (BYTE*) &out->dh_opt[4];
  BYTE *start = opt;

  exchange_id = set_timeout (0);       /* random exchange ID */
  DHCP_bootHeader (out, BOOTREQUEST);
  *opt++ = DHCP_MSG_TYPE;
  *opt++ = 1;
  *opt++ = DHCP_DISCOVER;

  *opt++ = DHCP_CLIENT_ID;             /* Client ID option */
  *opt++ = sizeof (_eth_addr) + 1;
  *opt++ = _eth_get_hwtype (NULL, NULL);
  memcpy (opt, &_eth_addr, sizeof(mac_address));
  opt += sizeof (mac_address);

  *opt++ = DHCP_MAX_MSG_SIZE;   /* Maximum DHCP message size */
  *opt++ = 2;
  *(WORD*)opt = intel16 (sizeof(struct dhcp));
  opt += 2;

  if (suggestLease)
  {
    *opt++ = DHCP_IP_ADDR_LEASE_TIME;
    *opt++ = sizeof (suggestLease);
    *(DWORD*)opt = intel (suggestLease);
    opt += sizeof (suggestLease);
  }
  opt = put_request_list (opt, opt-start);
  *opt++ = END_OPT;

  return DHCP_send (out, opt, TRUE);
}

/*-------------------------------------------------------------------*/

static int DHCP_inform (struct dhcp *out)
{
  BYTE *opt   = (BYTE*) &out->dh_opt[4];
  BYTE *start = opt;

  exchange_id = set_timeout (0);     /* random exchange ID */
  DHCP_bootHeader (out, BOOTREQUEST);
  *opt++ = DHCP_MSG_TYPE;
  *opt++ = 1;
  *opt++ = DHCP_INFORM;

  *opt++ = DHCP_CLIENT_ID;           /* Client ID option */
  *opt++ = sizeof (_eth_addr) + 1;
  *opt++ = _eth_get_hwtype (NULL, NULL);
  memcpy (opt, &_eth_addr, sizeof(mac_address));
  opt += sizeof (eth_address);

  opt = put_request_list (opt, opt-start);
  *opt++ = END_OPT;

  return DHCP_send (out, opt, FALSE);
}

/*-------------------------------------------------------------------*/

static int DHCP_request (struct dhcp *out, BOOL renew, DWORD ciaddr)
{
  BYTE *opt = (BYTE*) &out->dh_opt[4];

  DHCP_bootHeader (out, BOOTREQUEST);

  *opt++ = DHCP_MSG_TYPE;
  *opt++ = 1;
  *opt++ = DHCP_REQUEST;

  if (!renew)
  {
    *opt++ = DHCP_SRV_IDENTIFIER;
    *opt++ = sizeof (dhcp_server);
    *(DWORD*)opt = intel (dhcp_server);
    opt += sizeof (dhcp_server);
    *opt++ = DHCP_REQUESTED_IP_ADDR;
    *opt++ = sizeof (ciaddr);
    *(DWORD*)opt = ciaddr;
    opt += sizeof (ciaddr);
  }

  if (dhcp_iplease)
  {
    *opt++ = DHCP_IP_ADDR_LEASE_TIME;
    *opt++ = sizeof (dhcp_iplease);
    *(DWORD*)opt = intel (dhcp_iplease);
    opt += sizeof (dhcp_iplease);
  }
  *opt++ = END_OPT;

  return DHCP_send (out, opt, TRUE);
}

/*-------------------------------------------------------------------*/

static int DHCP_release_decline (struct dhcp *out, int msg_type, const char *msg)
{
  BYTE *opt = (BYTE*) &out->dh_opt[4];

  exchange_id = set_timeout (0);     /* new exchange ID */
  DHCP_bootHeader (out, BOOTREQUEST);
  out->dh_secs = 0;

  *opt++ = DHCP_MSG_TYPE;
  *opt++ = 1;
  *opt++ = msg_type;
  *opt++ = DHCP_SRV_IDENTIFIER;
  *opt++ = sizeof (dhcp_server);
  *(DWORD*)opt = intel (dhcp_server);
  opt += sizeof (dhcp_server);

  if (msg)
  {
    int len = strlen (msg);
    *opt++ = DHCP_MSG;
    *opt++ = len;
    strcpy ((char*)opt, msg);
    opt += len;
  }
  *opt++ = END_OPT;

  return DHCP_send (out, opt, FALSE);
}

/*-------------------------------------------------------------------*/

static int DHCP_process_ack (struct dhcp *out)
{
  DWORD bcast_ip = my_ip_addr | ~sin_mask;

  TRACE ("Got DHCP ack\r\n", 0);

  /* ARP broadcast to announce our new IP
   */
  _arp_reply (NULL, intel(bcast_ip), intel(my_ip_addr));

  if (arp_check_ip)       /* check if IP is used by anybody else */
  {
    TRACE ("Checking ARP..", 0);
    if (_arp_check_own_ip())
    {
      outsnl ("\7Someone has the same IP! Declining..");
      my_ip_addr = 0;     /* decline from 0.0.0.0 */

      DHCP_release_decline (out, DHCP_DECLINE, _LANG("IP is not free"));
      RandomWait (4000, 6000);
      return (0);
    }
    TRACE ("\r\n", 0);
  }
  configured = 1;    /* we are (re)configured */
  return (1);
}

/*-------------------------------------------------------------------*/

static int DHCP_offer (struct dhcp *in)
{
  int    len;
  DWORD  gw, ip;
  BYTE  *opt = (BYTE*) &in->dh_opt[4];

  while (opt < in->dh_opt + sizeof(in->dh_opt))
  {
    switch (*opt)
    {
      case PAD_OPT:
           opt++;
           continue;

      case SUBNET_MASK:
           sin_mask = intel (*(DWORD*)(opt+2));
           TRACE ("Net-mask: %s\r\n", INET_NTOA(sin_mask));
           break;

      case TIME_OFFSET:
#if defined(USE_DEBUG)
           {
             long tofs = *(long*)(opt+2);
             TRACE ("Time-ofs: %.2fh\r\n", (double)tofs/3600.0);
           }
#endif
           break;

      case ROUTERS_ON_SNET:
           {
             static int gw_added = 0;

             if (!gw_added)
                arp_last_gateway = 0; /* delete gateways from cfg-file */
             gw_added = 1;
             gw = intel (*(DWORD*)(opt+2));
             _arp_add_gateway (NULL, gw);
             TRACE ("Gateway:  %s\r\n", INET_NTOA(gw));
           }
           break;

      case DNS_SRV:
           {
             static int dns_added = 0;

             if (!dns_added)
                last_nameserver = 0;  /* delete nameserver from cfg-file */

             for (len = 0; len < *(opt+1); len += sizeof(DWORD))
             {
               ip = intel (*(DWORD*)(opt+2+len));
               /*
                * !!fix-me: Add only first Name-server cause resolve() doesn't
                * handle multiple servers (in different nets) very well
                */
               if (len == 0)
                  _add_server (&last_nameserver,
                               MAX_NAMESERVERS, def_nameservers, ip);
               dns_added = 1;
               TRACE ("DNS:      %s\r\n", INET_NTOA(ip));
             }
           }
           break;

#if defined(USE_BSD_FUNC)
      case LOG_SRV:
           {
             static int srv_added = 0;

             if (!srv_added)        /* only use first log-server */
                break;
             
             ip = intel (*(DWORD*)(opt+2)); /* select 1st host */
             TRACE ("LOG:      %s\r\n", INET_NTOA(ip));

             if (!syslog_hostName &&  /* not in config-file */
                 opt[1] % 4 == 0)     /* length = n * 4 */
             {
               char buf[20];
               syslog_hostName = strdup (_inet_ntoa(buf,ip));
               srv_added = 1;
             }
           }
           break;

      case NBIOS_NAME_SRV:
           ip = intel (*(DWORD*)(opt+2));
           TRACE ("WNS:      %s\r\n", INET_NTOA(ip));
           /* !! to-do: make a hook for Samba */
           break;
#endif

      case HOST_NAME:
          /* Don't use sethostname() because '*(opt+2)' is not a FQDN.
           */
           len = min (opt[1], sizeof(hostname));
           memcpy (hostname, opt+2, len);
           hostname[len] = 0;
           TRACE ("Host name: `%s'\r\n", hostname);
           break;

      case DOMAIN_NAME:
           len = min (opt[1], sizeof(defaultdomain)-1);
           setdomainname ((const char*)(opt+2), len);
           TRACE ("Domain:  `%s'\r\n", def_domain);
           break;

      case IP_DEFAULT_TTL:
      case TCP_DEFAULT_TTL:
           _default_ttl = opt[2];
           break;

      case DHCP_MSG_TYPE:
           if (opt[2] == DHCP_OFFER)
              got_offer = 1;
           break;

      case DHCP_MSG:
           outsn ((const char*)(opt+2), *(opt+1));
           break;

      case DHCP_SRV_IDENTIFIER:
           dhcp_server = intel (*(DWORD*)(opt+2));
           TRACE ("Server:   %s\r\n", INET_NTOA(dhcp_server));
           break;

      case DHCP_IP_ADDR_LEASE_TIME:
           dhcp_iplease = intel (*(DWORD*)(opt+2));
           TRACE ("IP lease: %lu hrs\r\n", dhcp_iplease/3600L);
           break;

      case DHCP_T1_VALUE:
           dhcp_renewal = intel (*(DWORD*)(opt+2));
           TRACE ("Renewal:  %lu hrs\r\n", dhcp_renewal/3600L);
           break;

      case DHCP_T2_VALUE:
           dhcp_rebind = intel (*(DWORD*)(opt+2));
           TRACE ("Rebind:   %lu hrs\r\n", dhcp_rebind/3600L);
           break;

      case TCP_KEEPALIVE_INTERVAL:
           tcp_keepalive = intel (*(DWORD*)(opt+2));
           break;

      case DHCP_OPT_OVERLOAD:
           switch (opt[2])
           {
             case 1:
                  TRACE ("Overload: `dh_file' options\r\n", 0);
                  dhcp_option_add (in->dh_file, sizeof(in->dh_file));
                  break;
             case 2:
                  TRACE ("Overload: `dh_sname' options\r\n", 0);
                  dhcp_option_add (in->dh_sname, sizeof(in->dh_sname));
                  break;
             case 3:
                  TRACE ("Overload: `dh_file/dh_sname' options\r\n", 0);
                  dhcp_option_add (in->dh_file, sizeof(in->dh_file));
                  dhcp_option_add (in->dh_sname, sizeof(in->dh_sname));
                  break;
           }
           break;

#if defined(USE_TFTP)
      case DHCP_TFTP_SERVER:
           {
             char *p = tftp_set_server ((const char*)(opt+2), opt[1]);
             TRACE ("TFTP-serv: `%s'\r\n", p);
           }
           break;

      case DHCP_BOOT_FILENAME:
           {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -