📄 pcdhcp.c
字号:
/*
*
* 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 + -