/*******************************************************************************/
/* */
/* Copyright 2005 Pascal Gloor <pascal.gloor@spale.com> */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* */
/*******************************************************************************/
#include "defs.h"
#include "lookup.h"
struct {
char *name;
char *opt1;
char *opt2;
char *opt3;
char *path;
regex_t reip;
regex_t retxt;
} prog[3];
char *spath[] = {
"/bin",
"/sbin",
"/usr/bin",
"/usr/sbin",
"/usr/local/sbin",
"/usr/local/bin"
};
int init_resolver(void)
{
char *string;
int id;
id = 2;
prog[id].name = "nslookup";
prog[id].opt1 = "-v";
prog[id].opt2 = "-qt=A";
prog[id].opt3 = "-qt=TXT";
string = "internet address = (127\\.0\\.0\\.[[:digit:]]+)";
if ( regcomp(&prog[id].reip, string, REG_EXTENDED) != 0 )
return -1;
string = "text = \"([^\"]*)\"";
if ( regcomp(&prog[id].retxt, string, REG_EXTENDED) != 0 )
return -1;
id = 1;
prog[id].name = "host";
prog[id].opt1 = "-t";
prog[id].opt2 = "A";
prog[id].opt2 = "TXT";
string = " has address (127\\.0\\.0\\.[[:digit:]]+)";
if ( regcomp(&prog[id].reip, string, REG_EXTENDED) != 0 )
return -1;
string = "descriptive text \"([^\"]*)\"";
if ( regcomp(&prog[id].retxt, string, REG_EXTENDED) != 0 )
return -1;
id = 0;
prog[id].name = "dig";
prog[id].opt1 = "--";
prog[id].opt2 = "A";
prog[id].opt3 = "TXT";
string = " IN +A +(127\\.0\\.0\\.[[:digit:]]+)";
if ( regcomp(&prog[id].reip, string, REG_EXTENDED) != 0 )
return -1;
string = "IN +TXT +\"([^\"]*)\"";
if ( regcomp(&prog[id].retxt, string, REG_EXTENDED) != 0 )
return -1;
return 0;
}
int find_resolver(void)
{
int i,j,k,l;
j = sizeof spath / sizeof spath[0];
l = sizeof prog / sizeof prog[0];
for(k=0; k<l; k++)
for(i=0; i<j; i++)
{
char fullname[MAXPATHLEN];
int fd;
sprintf(fullname,"%s/%s",spath[i],prog[k].name);
if ( ( fd = open(fullname,O_RDONLY) ) >= 0 )
{
close(fd);
prog[k].path = spath[i];
return k;
}
}
return -1;
}
struct blinfo_t *exec_resolver(int prg, uint32_t intip, char *ns)
{
static struct blinfo_t blinfo;
char cmd[MAXPATHLEN];
char newip[256];
struct in_addr addr;
struct in_addr addrrev;
int Afd[2], TXTfd[2], Apid=0, TXTpid=0;
sprintf(cmd,"%s/%s",prog[prg].path,prog[prg].name);
addr.s_addr = intip;
addrrev.s_addr = 0;
addrrev.s_addr |= ( ( addr.s_addr & 0xFF000000 ) >> 24 );
addrrev.s_addr |= ( ( addr.s_addr & 0x00FF0000 ) >> 8 );
addrrev.s_addr |= ( ( addr.s_addr & 0x0000FF00 ) << 8 );
addrrev.s_addr |= ( ( addr.s_addr & 0x000000FF ) << 24 );
sprintf(newip,"%s.%s",inet_ntoa(addrrev),ns);
/*
printf("%s %s %s %s\n",cmd,prog[prg].opt1,prog[prg].opt2,newip);
*/
pipe(Afd);
pipe(TXTfd);
if ( ( Apid = fork() ) == -1 )
{
fprintf(stderr,"cannot fork()\n");
exit(EXIT_FAILURE);
}
else if ( Apid == 0 )
{
dup2(Afd[1], 1);
close(2);
open("/dev/null",O_WRONLY);
execl(cmd, cmd, prog[prg].opt1, prog[prg].opt2, newip, NULL);
exit(EXIT_FAILURE);
}
else
{
if ( ( TXTpid = fork() ) == -1 )
{
fprintf(stderr,"cannot fork()\n");
exit(EXIT_FAILURE);
}
else if ( TXTpid == 0 )
{
dup2(TXTfd[1], 1);
close(2);
open("/dev/null",O_WRONLY);
execl(cmd, cmd, prog[prg].opt1, prog[prg].opt3, newip, NULL);
exit(EXIT_FAILURE);
}
else
{
ssize_t Alen = 65536;
ssize_t TXTlen = 65536;
char Abuf[65536];
char TXTbuf[65536];
int err,i;
fd_set Aset,TXTset;
struct timeval to;
regmatch_t pmatch[2];
FD_ZERO(&Aset);
FD_ZERO(&TXTset);
FD_SET(Afd[0], &Aset);
FD_SET(TXTfd[0], &TXTset);
to.tv_sec = 1;
to.tv_usec = 0;
for(i=0; i<50; ++i)
{
int cexit;
int pid;
if ( ( pid = waitpid(-1, &cexit, WNOHANG) ) == 0 )
{
usleep(100000);
continue;
}
if ( pid == Apid )
{
if ( WIFSIGNALED(cexit) )
{
fprintf(stderr,"child '%d' did not complete.\n",pid);
errno=1;
return NULL;
}
Apid = 0;
}
else if ( pid == TXTpid )
{
if ( WIFSIGNALED(cexit) )
{
fprintf(stderr,"child '%d' did not complete.\n",pid);
errno=1;
return NULL;
}
TXTpid = 0;
}
if ( Apid == 0 && TXTpid == 0 )
break;
}
if ( Apid != 0 )
kill(Apid, SIGKILL);
if ( TXTpid != 0 )
kill(TXTpid, SIGKILL);
if ( select(Afd[0]+1, &Aset, NULL, NULL, &to) != 1 )
{
errno=0;
return NULL;
}
if ( select(TXTfd[0]+1, &TXTset, NULL, NULL, &to) != 1 )
{
errno=0;
return NULL;
}
Alen = read(Afd[0], Abuf, Alen);
TXTlen = read(TXTfd[0], TXTbuf, TXTlen);
close(Afd[0]);
close(Afd[1]);
close(TXTfd[0]);
close(TXTfd[1]);
if ( Alen < 1 )
{
errno=1;
return NULL;
}
if ( TXTlen < 0 )
{
errno=1;
return NULL;
}
Abuf[Alen] = '\0';
TXTbuf[TXTlen] = '\0';
if ( ( err = regexec(&prog[prg].reip, Abuf, 2, pmatch, 0) ) == 0 )
{
int iplen = pmatch[1].rm_eo - pmatch[1].rm_so;
if ( iplen > 1 && iplen < BLLEN )
memcpy(blinfo.ip,Abuf+pmatch[1].rm_so,iplen);
else
iplen = 0;
blinfo.ip[iplen] = '\0';
blinfo.txt[0] = '\0';
if ( TXTlen > 0 && ( err = regexec(&prog[prg].retxt, TXTbuf, 2, pmatch, 0) ) == 0 )
{
int txtlen = pmatch[1].rm_eo - pmatch[1].rm_so;
if ( txtlen > 1 && txtlen < BLLEN )
memcpy(blinfo.txt,TXTbuf+pmatch[1].rm_so,txtlen);
else
txtlen = 0;
blinfo.txt[txtlen] = '\0';
}
/*
else
{
regerror(err, &prog[prg].reip, TXTbuf, 65536);
printf("regerror: %s\n",TXTbuf);
}
*/
return &blinfo;
}
/*
else
{
regerror(err, &prog[prg].reip, Abuf, 65536);
printf("regerror: %s\n",Abuf);
errno=0;
return NULL;
}
*/
}
}
errno=0;
return NULL;
}