📄 gethost.c
字号:
/*
* BSD-like host-entry functions
*
* G. Vanem <giva@bgnett.no>
*
* 18.aug 1996 (GV) - Created
* 02.dec 1997 (GV) - Integrated with resolve()
* 05.jan 1998 (GV) - Added host cache functionality
* 18.may 1999 (GV) - Added timeout of cached values
* 02.may 2000 (GV) - Added function reverse_lookup_myip()
*
* todo: support real host aliases as they come from the name server
* todo: accept "rooted FQDN" strings as normal FQDN strings.
* Note: "domain_name.com" and "domain_name.com." are equivalent
* (both are valid forms of fully qualified domain names (FQDNs);
* with the period, it is referred to as a rooted FQDN). Both forms
* should work with all mail clients and servers. However, using the
* trailing "." is rarely used (except in DNS maintenance).
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <netdb.h>
#include "wattcp.h"
#include "strings.h"
#include "misc.h"
#include "language.h"
#include "pcconfig.h"
#include "pc_cbrk.h"
#include "pcbsd.h"
#include "pctcp.h"
#include "bsdname.h"
#include "udp_dom.h"
typedef struct {
struct dhead h;
char x[50];
} question_t;
typedef struct {
struct dhead h;
char x[500];
} answer_t;
#if defined(USE_BSD_FUNC)
typedef struct _hostent { /* internal hostent structure */
char *h_name; /* official name of host */
char **h_aliases; /* hostname alias list */
u_long h_address; /* IP address (network order) */
time_t h_timeout; /* cached entry expiry time */
struct _hostent *h_next; /* ptr to next entry (or NULL) */
} _hostent;
#define MAX_HOST_ALIASES 5
#define MAX_CACHE_LIFE (15*60)
int h_errno = 0;
int netdbCacheLife = MAX_CACHE_LIFE;
static char *hostFname = NULL;
static FILE *hostFile = NULL;
static BOOL hostClose = 0;
static _hostent *host0 = NULL;
/*
*
*/
static __inline struct hostent *FillHostEnt (const _hostent *h)
{
static struct in_addr adr;
static struct hostent ret;
static char *list[2];
if (!h->h_name)
return (NULL);
adr.s_addr = h->h_address;
list[0] = (char*) &adr;
list[1] = NULL;
ret.h_name = h->h_name;
ret.h_aliases = h->h_aliases;
ret.h_addrtype = AF_INET;
ret.h_length = sizeof (adr.s_addr);
ret.h_addr_list = list;
h_errno = NETDB_SUCCESS;
return (&ret);
}
/*
* Modify an expired cached entry or create a new node to
* the linked list.
*/
static __inline void AddHostEnt (struct _hostent *h,
const char *name,
u_long addr,
BOOL expires)
{
if (h) /* reuse expired entry */
{
if (h->h_name)
free (h->h_name);
}
else /* create a new node */
{
h = calloc (sizeof(*h),1);
if (h)
{
h->h_next = host0;
host0 = h;
}
}
if (h)
{
h->h_name = strdup (name);
h->h_address = addr;
if (netdbCacheLife && expires)
h->h_timeout = time (NULL) + netdbCacheLife;
else h->h_timeout = 0;
}
#ifdef TEST_PROG /* test updated cache */
if (h)
printf ("new entry: h->h_address = %-17.17s h->h_name = %s\n",
inet_ntoa(*(struct in_addr*)&h->h_address), h->h_name);
else printf ("new entry: no mem\n");
#endif
}
/*------------------------------------------------------------------*/
void ReadHostFile (const char *fname)
{
static int been_here = 0;
if (!fname || !*fname)
return;
if (been_here) /* loading multiple hosts files */
{
free (hostFname);
fclose (hostFile);
hostFile = NULL;
}
been_here = 1;
hostFname = strdup (fname);
if (!hostFname)
return;
sethostent (1);
if (!hostFile)
return;
while (1)
{
struct hostent *h = gethostent();
struct _hostent *h2;
if (!h)
break;
h2 = calloc (sizeof(*h2),1);
if (!h2)
{
outsnl (_LANG("Hostfile too big!\7"));
break;
}
h2->h_name = h->h_name;
h2->h_aliases = h->h_aliases;
h2->h_address = *(u_long*) h->h_addr_list[0];
h2->h_timeout = 0; /* don't expire */
h2->h_next = host0;
host0 = h2;
}
rewind (hostFile);
atexit (endhostent);
}
const char *GetHostsFile (void)
{
return (hostFname);
}
/*
* To prevent running out of file-handles, one should close the
* 'hosts' file before spawning a new shell.
*/
void CloseHostFile (void)
{
fclose (hostFile);
hostFile = NULL;
}
void ReopenHostFile (void)
{
ReadHostFile (hostFname);
}
/*
* Return the next (non-commented) line from the host-file
* Format is:
* ip-address [=] host-name [alias..] {\n | # ..}
*/
struct hostent * gethostent (void)
{
static _hostent h;
char *ip, *name, *alias;
char buf[100];
if (!netdb_init() || !hostFile)
return (NULL);
do
{
if (!fgets(buf,sizeof(buf)-1,hostFile))
return (NULL);
}
while (buf[0] == '#' || buf[0] == ';' || buf[0] == '\n');
if (hostClose)
endhostent();
ip = strtok (buf, " \t");
name = strtok (NULL, " \t\n");
if (!strcmp(ip,"0.0.0.0")) /* inet_addr() maps 0 -> INADDR_NONE */
h.h_address = 0;
else h.h_address = inet_addr (ip);
h.h_name = strdup (name);
if (!h.h_name)
return (NULL);
h.h_aliases = NULL;
alias = strtok (NULL, " \t\n");
if (alias && *alias != '#' && *alias != ';')
{
char **alist = calloc ((1+MAX_HOST_ALIASES) * sizeof(char*), 1);
int i = 0;
do
{
if (*alias == '#' || *alias == ';')
break;
if (!alist || (i == MAX_HOST_ALIASES) ||
(alist[i++] = strdup(alias)) == NULL)
break;
alias = strtok (NULL, " \t\n");
}
while (alias);
h.h_aliases = alist;
}
return FillHostEnt (&h);
}
/*------------------------------------------------------------------*/
struct hostent *gethostbyname (const char *name)
{
struct _hostent *h, ret;
struct in_addr addr;
u_long ip;
static char fqdn[MAX_HOSTLEN];
h_errno = HOST_NOT_FOUND;
if (!netdb_init())
return (NULL);
if (inet_aton(name,&addr))
{
ret.h_name = (char*) name; /* !!to-do: should be canonical name */
ret.h_aliases = NULL;
ret.h_address = addr.s_addr;
return FillHostEnt (&ret);
}
for (h = host0; h; h = h->h_next)
{
char **alias;
if (h->h_name && !stricmp(h->h_name,name))
{
/* if cached entry expired, do DNS lookup
*/
if (h->h_timeout && time(NULL) >= h->h_timeout)
goto expired;
if (h->h_address)
return FillHostEnt (h);
return (NULL);
}
for (alias = h->h_aliases; alias && *alias; alias++)
if (!stricmp(name,*alias))
{
if (h->h_timeout && time(NULL) >= h->h_timeout)
goto expired;
if (h->h_address)
return FillHostEnt (h);
return (NULL);
}
}
if (!h)
{
/* Not found in linked list (hosts file or cache). Check name
* against our own host-name (short-name or FQDN)
*/
if (hostname[0] && !stricmp(name,hostname))
{
ret.h_address = gethostid();
ret.h_name = hostname;
return FillHostEnt (&ret);
}
if (!gethostname(fqdn,sizeof(fqdn)) && !stricmp(name,fqdn))
{
ret.h_address = gethostid();
ret.h_name = fqdn;
return FillHostEnt (&ret);
}
}
expired:
if (called_from_resolve) /* prevent recursion */
return (NULL);
/* Not our own host-name; do a full DNS lookup
*/
called_from_ghbn = 1;
ip = htonl (resolve((char*)name)); /* do a normal lookup */
called_from_ghbn = 0;
/* Add the IP to the list even if DNS failed (but not interrupted by
* _resolve_hook() or timedout). Thus the next call to gethostbyxx()
* will return immediately.
*/
if (_resolve_exit || /* interrupted by _resolve_hook() */
_resolve_timeout) /* timed out resolving */
return (NULL);
if (ip) /* successfully resolved */
{
AddHostEnt (h, name, ip, TRUE);
ret.h_address = ip;
ret.h_name = (char*) name; /* !!to-do: should be canonical name */
ret.h_aliases = h ? h->h_aliases : NULL;
return FillHostEnt (&ret);
}
AddHostEnt (h, name, INADDR_ANY, TRUE); /* or INADDR_NONE ? */
return (NULL);
}
/*------------------------------------------------------------------*/
struct hostent *gethostbyaddr (const char *adr_name, int len, int type)
{
_hostent *h, ret;
u_long addr;
static char name [MAX_HOSTLEN];
int rc;
h_errno = HOST_NOT_FOUND;
if (!netdb_init())
return (NULL);
if (type != AF_INET || len < sizeof(addr))
return (NULL);
addr = *(u_long*) adr_name;
if ((addr == INADDR_ANY || /* 0.0.0.0 -> my_ip_addr */
addr == gethostid()) &&
!gethostname(name,sizeof(name)))
{
ret.h_address = gethostid();
ret.h_name = name;
return FillHostEnt (&ret);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -