- 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 double lastClose = 0; /* time of last close operation */
static AsconProtocol *protocols = NULL; static AsconProtocol *protocols = NULL;
long parse_dotted_adr(const char *dottedadr) { static int MakeSocketAdr(
int ip[4]; struct sockaddr *sockaddrPtr, /* socket address */
int i; 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
*/
if (sscanf(dottedadr, "%d.%d.%d.%d", ip, ip+1, ip+2, ip+3) != 4) return 0; struct hostent *hostent; /* Host database entry */
for (i=0; i<3; i++) { struct sockaddr_in *sadr = (struct sockaddr_in *)sockaddrPtr;
if (ip[i] < 0 || ip[i] > 255) return 0;
}
return ip[0] + (ip[1] << 8) + (ip[2] << 16) + (ip[3] << 24);
}
long ns_lookup(char *hostname) {
FILE *fil; FILE *fil;
char line[256]; char line[256];
long ipadr; int l;
ipadr = parse_dotted_adr(hostname); (void) memset(sadr, 0, sizeof(*sadr));
if (ipadr) return ipadr; if (dotted_ip) { /* default value: failure */
snprintf(line, sizeof line, "timeout 1 nslookup %s", hostname); 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;
}
/* 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"); fil = popen(line, "r");
if (fil == NULL) { if (fil != NULL) {
return 0; if (fgets(line, sizeof(line), fil) != NULL) {
} l = strlen(line);
while (fgets(line, sizeof(line), fil) != NULL) { if (line[l-1] <= ' ') line[l-1] = 0; /* strip off newline */
if (strncmp(line, "Address: ", 9) == 0) { /* silently ignore return value, if it fails, we take the cached value */
ipadr = parse_dotted_adr(line+9); inet_pton(AF_INET, line, &sadr->sin_addr);
if (ipadr) {
fclose(fil);
return ipadr;
}
}
} }
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; return 1;
} }
@ -140,7 +127,7 @@ static void AsconConnect(Ascon * a)
/* input state: AsconConnectStart /* input state: AsconConnectStart
output state: AsconFailed or AsconConnecting */ output state: AsconFailed or AsconConnecting */
int ret; int ret;
struct sockaddr_in adr; struct sockaddr adr;
char *colon; char *colon;
int port; int port;
int oldopts; int oldopts;
@ -184,17 +171,15 @@ static void AsconConnect(Ascon * a)
return; return;
} }
*colon = '\0'; *colon = '\0';
ret = MakeSocketAdress(&adr, a->hostport, port); ret = MakeSocketAdr(&adr, a->hostport, port, a->ip);
*colon = ':'; *colon = ':';
if (ret == 0) { if (ret == 0) {
a->ip = 0;
AsconError(a, "bad host specification", 0); AsconError(a, "bad host specification", 0);
return; return;
} }
a->ip = adr.sin_addr.s_addr;
oldopts = fcntl(a->fd, F_GETFL, 0); oldopts = fcntl(a->fd, F_GETFL, 0);
fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK); 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) { if (ret < 0) {
switch (errno) { switch (errno) {
case EINPROGRESS: case EINPROGRESS:
@ -891,10 +876,10 @@ char *AsconHostport(Ascon *a)
return a->hostport; return a->hostport;
} }
unsigned long AsconIP(Ascon *a) char *AsconIP(Ascon *a)
{ {
if (a==NULL) { if (a==NULL) {
return 0; return NULL;
} }
return a->ip; return a->ip;
} }

View File

@ -112,9 +112,9 @@ char *AsconHostport(Ascon *a);
/** /**
* \brief return IP address * \brief return IP address
* \param a The Ascon to query * \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 * \brief set or get timeout

View File

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

View File

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

View File

@ -206,9 +206,9 @@ char *DevHostport(DevSer *devser);
/** /**
* \brief return IP address * \brief return IP address
* \param a The device serializer to query * \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", "") * \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) Hdb * cmdNode, Hdb * par[], int nPar)
{ {
SctController *c; SctController *c;
uint32_t ip;
c = (SctController *) ccmd->pPrivate; c = (SctController *) ccmd->pPrivate;
ip = DevIP(c->devser); SCPrintf(con, eValue, "%s", 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));
return 1; return 1;
} }