- use dig before gethostbyname to resolve host names

This commit is contained in:
2018-08-09 09:10:10 +02:00
parent 04f9554f3d
commit 8de1fd4183
6 changed files with 59 additions and 80 deletions

119
ascon.c
View File

@ -17,75 +17,62 @@
static double lastClose = 0; /* time of last close operation */
static AsconProtocol *protocols = NULL;
long parse_dotted_adr(const char *dottedadr) {
int ip[4];
int i;
if (sscanf(dottedadr, "%d.%d.%d.%d", ip, ip+1, ip+2, ip+3) != 4) return 0;
for (i=0; i<3; i++) {
if (ip[i] < 0 || ip[i] > 255) return 0;
}
return ip[0] + (ip[1] << 8) + (ip[2] << 16) + (ip[3] << 24);
}
static int MakeSocketAdr(
struct sockaddr *sockaddrPtr, /* socket address */
char *hostname, /* name or ip of host. NULL implies INADDR_ANY */
int port, /* port number */
char dotted_ip[16]) { /* resolved ip adr */
/*
Workaround for the following case:
switching off and on a LakeShore 336 does acquire a new address,
but the value in the cache (for gethostbyname) is not updated.
node: dig seems to be recommended over nslookup
*/
long ns_lookup(char *hostname) {
struct hostent *hostent; /* Host database entry */
struct sockaddr_in *sadr = (struct sockaddr_in *)sockaddrPtr;
FILE *fil;
char line[256];
long ipadr;
int l;
ipadr = parse_dotted_adr(hostname);
if (ipadr) return ipadr;
snprintf(line, sizeof line, "timeout 1 nslookup %s", hostname);
fil = popen(line, "r");
if (fil == NULL) {
(void) memset(sadr, 0, sizeof(*sadr));
if (dotted_ip) { /* default value: failure */
dotted_ip[0] = 0;
}
sadr->sin_family = AF_INET;
sadr->sin_port = htons((unsigned short)port);
if (hostname == NULL) {
/* do not need to copy, as INADDR_ANY is all zero bytes */
return 1;
}
if (inet_pton(AF_INET, hostname, &sadr->sin_addr) == 1) {
/* resolved as dotted numbers notation */
return 1;
}
hostent = gethostbyname(hostname);
if (hostent == 0) {
/* we assume that when gethostname gets no entry, dig will also fail.
That way, dig will not be called repeatedly for no reason */
return 0;
}
while (fgets(line, sizeof(line), fil) != NULL) {
if (strncmp(line, "Address: ", 9) == 0) {
ipadr = parse_dotted_adr(line+9);
if (ipadr) {
fclose(fil);
return ipadr;
}
/* copy the address: in case dig fails, we use the cached value */
memcpy(&sadr->sin_addr, hostent->h_addr_list[0], 4);
/* we use hostent->h_name instead of hostname here, as this has already
the proper domain added */
snprintf(line, sizeof line, "timeout 1 dig +short %s", hostent->h_name);
fil = popen(line, "r");
if (fil != NULL) {
if (fgets(line, sizeof(line), fil) != NULL) {
l = strlen(line);
if (line[l-1] <= ' ') line[l-1] = 0; /* strip off newline */
/* silently ignore return value, if it fails, we take the cached value */
inet_pton(AF_INET, line, &sadr->sin_addr);
}
fclose(fil);
}
fclose(fil);
return 0;
}
/*
Based on CreateSocketAdress from John Ousterhout
Use ns_lookup instead of gethostbyname, as the latter uses a cache, which
is not sufficient in some cases (switching off and on a LakeShore 336 does
acquire a new address, but the value in the cache is not updates)
*/
static int MakeSocketAdress(struct sockaddr_in *sockaddrPtr, /* Socket address */
char *host, /* Host. NULL implies INADDR_ANY */
int port)
{ /* Port number */
struct hostent *hostent; /* Host database entry */
struct in_addr addr; /* For 64/32 bit madness */
(void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in));
sockaddrPtr->sin_family = AF_INET;
sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF));
if (host == NULL) {
addr.s_addr = INADDR_ANY;
} else {
addr.s_addr = ns_lookup(host);
if (addr.s_addr == 0) { /* try gethostbyname only if ns_lookup failed */
hostent = gethostbyname(host);
if (hostent == NULL) return 0; /* error */
memcpy((char *) &addr,
(char *) hostent->h_addr_list[0], (size_t) hostent->h_length);
}
if (dotted_ip) {
inet_ntop(AF_INET, &sadr->sin_addr, dotted_ip, 16);
}
/*
* There is a rumor that this assignment may require care on
* some 64 bit machines, we do not believe it.
*/
sockaddrPtr->sin_addr.s_addr = addr.s_addr;
return 1;
}
@ -140,7 +127,7 @@ static void AsconConnect(Ascon * a)
/* input state: AsconConnectStart
output state: AsconFailed or AsconConnecting */
int ret;
struct sockaddr_in adr;
struct sockaddr adr;
char *colon;
int port;
int oldopts;
@ -184,17 +171,15 @@ static void AsconConnect(Ascon * a)
return;
}
*colon = '\0';
ret = MakeSocketAdress(&adr, a->hostport, port);
ret = MakeSocketAdr(&adr, a->hostport, port, a->ip);
*colon = ':';
if (ret == 0) {
a->ip = 0;
AsconError(a, "bad host specification", 0);
return;
}
a->ip = adr.sin_addr.s_addr;
oldopts = fcntl(a->fd, F_GETFL, 0);
fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK);
ret = connect(a->fd, (struct sockaddr *) &adr, sizeof(struct sockaddr_in));
ret = connect(a->fd, &adr, sizeof(struct sockaddr_in));
if (ret < 0) {
switch (errno) {
case EINPROGRESS:
@ -891,10 +876,10 @@ char *AsconHostport(Ascon *a)
return a->hostport;
}
unsigned long AsconIP(Ascon *a)
char *AsconIP(Ascon *a)
{
if (a==NULL) {
return 0;
return NULL;
}
return a->ip;
}

View File

@ -112,9 +112,9 @@ char *AsconHostport(Ascon *a);
/**
* \brief return IP address
* \param a The Ascon to query
* \return the IP address
* \return the IP address (dotted numbers)
*/
unsigned long AsconIP(Ascon *a);
char *AsconIP(Ascon *a);
/**
* \brief set or get timeout

View File

@ -65,7 +65,7 @@ struct Ascon {
char *sendTerminator; /**< terminator for sending messages */
char *replyTerminator; /**< (std) terminator list for reply. NULL is the special case CR, LF or CR/LF */
char *hostport; /**< host:port to connect */
in_addr_t ip; /**< the ip address */
char ip[16]; /**< the ip address (dotted numbers) */
pDynString errmsg; /**< error message */
double start; /**< unix time when read was started */
int noResponse; /**< no response expected */

View File

@ -580,7 +580,7 @@ char *DevHostport(DevSer *devser) {
return AsconHostport(devser->ascon);
}
unsigned long DevIP(DevSer *devser) {
char *DevIP(DevSer *devser) {
return AsconIP(devser->ascon);
}

View File

@ -206,9 +206,9 @@ char *DevHostport(DevSer *devser);
/**
* \brief return IP address
* \param a The device serializer to query
* \return the IP address
* \return the IP address (dotted numbers)
*/
unsigned long DevIP(DevSer *devser);
char *DevIP(DevSer *devser);
/**
* \brief return status of device server ("offline", "unconnected", "")

View File

@ -1742,15 +1742,9 @@ static int SctIpAddress(pSICSOBJ ccmd, SConnection * con,
Hdb * cmdNode, Hdb * par[], int nPar)
{
SctController *c;
uint32_t ip;
c = (SctController *) ccmd->pPrivate;
ip = DevIP(c->devser);
SCPrintf(con, eValue, "%d.%d.%d.%d",
(int)(ip & 0xff),
(int)((ip >> 8) & 0xff),
(int)((ip >> 16) & 0xff),
(int)((ip >> 24) & 0xff));
SCPrintf(con, eValue, "%s", DevIP(c->devser));
return 1;
}