#include #include #include #include #include #include #include #include "checkip.h" /* This code is more complicated than strictly necessary for this application because I wanted to mostly reuse burnt-in code from elsewhere (my own SMTP daemon) rather than write new code with new bugs for it. */ static int dns_skip(const void *dbuf, int len, int off) { const unsigned char *d; int i; d = dbuf; while (1) { if (off >= len) return(-1); i = d[off]; switch (i & 0xc0) { case 0: if (i) off += i + 1; else return(off+1); break; case 0xc0: if (off+1 >= len) return(-1); return(off+2); break; default: return(-1); break; } } } static int query_it(const char *name) /* return values */ #define QIR_FAIL 1 /* failure such as SERVAIL or can't-send */ #define QIR_NODATA 2 /* OK but zero answers */ #define QIR_NXDOM 3 /* NXDOMAIN */ #define QIR_SUCCESS 4 /* OK, nonzero answers */ { unsigned char respbuf[8192]; unsigned char compbuf[1024]; unsigned char nbuf[1024]; int rdl; int rl; int n; int i; int x; int nl; int type; int class; static int exp(int inx) { return(dn_expand((const void *)&respbuf[0],(const void *)&respbuf[rl],(const void *)&respbuf[inx],(void *)&compbuf[0],sizeof(compbuf))); } bzero(&respbuf[0],12); /* res_query doesn't check response length (!!) */ rl = res_query(name,C_IN,T_A,(void *)&respbuf[0],sizeof(respbuf)); if (rl <= 0) { switch (h_errno) { case HOST_NOT_FOUND: return(QIR_NXDOM); break; case NO_DATA: return(QIR_NODATA); break; } return(QIR_FAIL); } if (rl < 12) { printf("[%d] `%s' lookup response is too short (%d)\n",(int)getpid(),name,rl); return(QIR_FAIL); } if (respbuf[3] & 2) { printf("[%d] `%s' lookup response is truncated\n",(int)getpid(),name); return(QIR_FAIL); } n = (respbuf[6] * 256) + respbuf[7]; if (n == 0) return(QIR_NODATA); i = (respbuf[4] * 256) + respbuf[5]; x = 12; for (;i>0;i--) { x = dns_skip(&respbuf[0],rl,x); if (x < 0) { printf("[%d] `%s' lookup response includes invalid compressed name\n",(int)getpid(),name); return(QIR_FAIL); } x += 4; if (x >= rl) { printf("[%d] `%s' lookup response queries overflow packet\n",(int)getpid(),name); return(QIR_FAIL); } } for (i=0;i= rl) { printf("[%d] `%s' lookup response answers overflow packet\n",(int)getpid(),name); return(QIR_FAIL); } rdl = (respbuf[x-2] * 256) + respbuf[x-1]; class = (respbuf[x-8] * 256) + respbuf[x-7]; if (class == C_IN) { type = (respbuf[x-10] * 256) + respbuf[x-9]; if (type == T_CNAME) { if (! strcasecmp(&compbuf[0],name)) { nl = exp(x); if (nl < 0) { printf("[%d] `%s' lookup response includes invalid compressed name\n",(int)getpid(),name); return(QIR_FAIL); } if (nl != rdl) { printf("[%d] `%s' lookup response CNAME data length wrong\n",(int)getpid(),name); return(QIR_FAIL); } strcpy(&nbuf[0],&compbuf[0]); name = &nbuf[0]; } } else if (type == T_A) { if (! strcasecmp(&compbuf[0],name)) { if (rdl != 4) { printf("[%d] `%s' lookup data length wrong (%d)\n",(int)getpid(),name,rdl); return(QIR_FAIL); } } } } x += rdl; } return(QIR_SUCCESS); } static int listed(const char *name) #define LIST_YES 1 #define LIST_NO 2 #define LIST_UNK 3 { switch (query_it(name)) { case QIR_FAIL: return(LIST_UNK); break; case QIR_NODATA: return(LIST_NO); break; case QIR_NXDOM: return(LIST_NO); break; case QIR_SUCCESS: return(LIST_YES); break; } printf("[%d] listed: query_it response for %s unrecognized\n",(int)getpid(),name); return(LIST_UNK); } void check_ipv4(const struct in_addr *ip, int *statusp, const char **msgp, const char **tagp) { __label__ ret; unsigned int a; /* fixed buffer sizes OK: limited by length of IPv4 text format */ char txt[20]; char rtxt[20]; static void lookup(const char *list, const char *url, const char *tag) { /* fixed buffer sizes OK: limited by the strings for the lists we query */ char qname[1024]; static char longmsg[1024]; sprintf(&qname[0],"%s.%s",rtxt,list); switch (listed(&qname[0])) { case LIST_YES: *statusp = IPSTAT_BAD; sprintf(&longmsg[0],"Mail from %s rejected -- see %s",&txt[0],url); *msgp = &longmsg[0]; *tagp = tag; goto ret; break; case LIST_NO: break; case LIST_UNK: *statusp = IPSTAT_FAIL; sprintf(&longmsg[0],"Temporary lookup failure of %s at %s",&txt[0],list); *msgp = &longmsg[0]; *tagp = tag; goto ret; break; } } a = ntohl(ip->s_addr); sprintf(&txt[0],"%u.%u.%u.%u",(a>>24)&0xff,(a>>16)&0xff,(a>>8)&0xff,a&0xff); sprintf(&rtxt[0],"%u.%u.%u.%u",a&0xff,(a>>8)&0xff,(a>>16)&0xff,(a>>24)&0xff); lookup("dnsbl.example.net","http://www.example.net/dnsbl/faq/","example"); *statusp = IPSTAT_OK; ret:; }