home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
-
- #include "vterm.h"
- #include "dnsfn.h"
-
- #include "bbc.h"
-
- static char *type2s[] =
- { "", "A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG",
- "MR", "NULL", "WKS", "PTR", "HINFO", "MINFO", "MX", "TXT" };
-
-
- static char *rcode2s[] =
- { "OK", "BADFORM", "SERVFAIL", "NAMEERR", "NOTIMP", "REFUSED" };
-
-
- static char *strdup(char *s)
- {
- char *p;
- if (p = (char *)malloc(strlen(s)+1), p!=NULL)
- strcpy(p, s);
-
- return p;
- }
-
-
- static void strfree(char *s)
- {
- if (s)
- free(s);
- }
-
-
- static char *skip_name(char *p)
- {
- for (; *p != 0x00 && *p != 0xc0; p++);
- if (*p == 0xC0) p++;
- return ++p;
- }
-
-
- static void put_name(char *buf, char *name)
- {
- int a, b, p, q;
-
- a = 0; p = 0; q = 0;
-
- while (name[p]>=' ')
- {
- b = a+1;
- while (name[p]!='.' && name[p]>=' ')
- {
- buf[b++] = name[p++];
- }
- buf[a] = p-q;
- p += (name[p]=='.');
- q = p;
- a = b;
- }
- buf[a] = 0;
- }
-
- static void put_uint8(char *p, uint8 n)
- {
- p[0] = n;
- }
-
- static void put_uint16(char *p, uint16 n)
- {
- p[0] = (n >> 8) & 0xff;
- p[1] = n & 0xff;
- }
-
- static void put_uint32(char *p, uint32 n)
- {
- p[0] = (n >> 24) & 0xff;
- p[1] = (n >> 16) & 0xff;
- p[2] = (n >> 8) & 0xff;
- p[3] = n & 0xff;
- }
-
-
- static uint8 get_uint8(char *p)
- {
- return p[0];
- }
-
-
- static uint16 get_uint16(char *p)
- {
- return (p[0]<<8) | p[1] ;
- }
-
-
- static uint32 get_uint32(char *p)
- {
- return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3] ;
- }
-
- static void get_name(char *dnsbuf, char *ptr, char *name)
- {
- int n;
- int offset;
-
- while (*ptr != 0)
- {
- if ((*ptr & 0xc0) == 0xc0)
- {
- offset = (int)get_uint16(ptr) & 0x3fff;
- ptr = dnsbuf + offset;
- }
- else
- {
- n = *ptr++;
- while (n-- > 0) *name++ = *ptr++;
- *name++ = '.';
- }
- }
- *name++ = '\0';
- }
-
- static uint32 aton(char *s)
- {
- int i;
- uint32 n;
-
- n = 0;
- for (i=24; i>=0; i -= 8 )
- {
- n |= (uint32)atoi(s) << i;
- if ( (s = strchr(s,'.')) == NULL)
- break;
- s++;
- }
- return n;
- }
-
- /* Address class */
- int ntoclass(uint32 n)
- {
- int c;
-
- while (n & 0x80000000)
- {
- n <<= 1;
- ++ c;
- }
- return c;
- }
-
-
- static char *ntoinarpa(uint32 n, char *buf)
- {
- sprintf(buf, "%d.%d.%d.%d.in-addr.arpa",
- n & 0xff,
- (n >> 8) & 0xff,
- (n >> 16) & 0xff,
- (n >> 24) & 0xff );
-
- return buf;
- }
-
- static char *gntoinarpa(uint32 n, char *buf)
- {
- int c = ntoclass(n);
-
- if (c==0)
- sprintf(buf, "%d.in-addr.arpa",
- (n >> 24) & 0xff );
-
- else if (c==1)
- sprintf(buf, "%d.%d.in-addr.arpa",
- (n >> 16) & 0xff,
- (n >> 24) & 0xff );
-
- else if (c==2)
- sprintf(buf, "%d.%d.%d.in-addr.arpa",
- (n >> 8) & 0xff,
- (n >> 16) & 0xff,
- (n >> 24) & 0xff );
-
- else
- sprintf(buf, "%d.%d.%d.%d.in-addr.arpa",
- n & 0xff,
- (n >> 8) & 0xff,
- (n >> 16) & 0xff,
- (n >> 24) & 0xff );
-
- return buf;
- }
-
- static char *make_query(char *buf, char *name, uint16 qclass, uint16 qtype)
- {
- char *p;
-
- p = buf;
-
- put_name(p, name); p = skip_name(p);
-
- put_uint16(p, qtype); p+=2;
- put_uint16(p, qclass); p+=2;
-
- return p;
- }
-
-
- static char *make_header(char *buf, int rd, uint8 opcode)
- {
- char *p;
- static uint16 id = 1;
-
- p = buf;
-
- rd = (rd!=0);
-
- put_uint16(p, id++); p+=2;
- put_uint16(p, (rd << 8) | (opcode << 11)); p+=2;
- put_uint16(p, 1); p+=2;
- put_uint16(p, 0); p+=2;
- put_uint16(p, 0); p+=2;
- put_uint16(p, 0); p+=2;
- return p;
- }
-
-
- static char *skip_rr(char *p)
- {
- p = skip_name(p)+8;
- return p+get_uint16(p)+2;
- }
-
-
- static rr_str *extract_rr(char *dnsbuf, char *p)
- {
- int i;
- uint16 rdlen;
- char name[256];
- rr_str *rr;
-
- if (rr = (rr_str *)malloc(sizeof(rr_str)), rr==NULL)
- return NULL;
-
- memset(rr, '\0', sizeof(rr_str));
-
- get_name(dnsbuf, p, name); p = skip_name(p);
-
- if (rr->name = strdup(name), rr->name==NULL)
- goto err1;
-
- rr->type = get_uint16(p); p+=2;
- rr->class = get_uint16(p); p+=2;
- rr->ttl = get_uint32(p); p+=4;
- rdlen = get_uint16(p); p+=2;
-
- switch (rr->type)
- {
- case TYPE_NS:
- case TYPE_MD:
- case TYPE_MF:
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_PTR:
- case TYPE_TXT:
- get_name(dnsbuf, p, name); p = skip_name(p);
- rr->rdata.txt.text = strdup(name);
- break;
-
- case TYPE_A:
- rr->rdata.a.addr = get_uint32(p); p+=4;
- break;
-
- case TYPE_SOA:
- get_name(dnsbuf, p, name); p = skip_name(p);
- rr->rdata.soa.mname = strdup(name);
- get_name(dnsbuf, p, name); p = skip_name(p);
- /* Replace 1st '.' in name with '@' to make an email address */
- for (i=0; name[i]!='.' && name[i]!='\0'; i++);
- if (name[i]=='.')
- name[i] = '@';
- rr->rdata.soa.rname = strdup(name);
- rr->rdata.soa.serial = get_uint32(p); p+=4;
- rr->rdata.soa.refresh = get_uint32(p); p+=4;
- rr->rdata.soa.retry = get_uint32(p); p+=4;
- rr->rdata.soa.expire = get_uint32(p); p+=4;
- rr->rdata.soa.minttl = get_uint32(p); p+=4;
- break;
-
- case TYPE_NULL:
- if (rr->rdata.null.data = (char *)malloc(rdlen), rr->rdata.null.data!=NULL)
- {
- rr->rdata.null.len = rdlen;
- memcpy(rr->rdata.null.data, p, rdlen);
- }
- break;
-
- case TYPE_HINFO:
- get_name(dnsbuf, p, name); p = skip_name(p);
- rr->rdata.hinfo.cpu = strdup(name);
- get_name(dnsbuf, p, name); p = skip_name(p);
- rr->rdata.hinfo.os = strdup(name);
- break;
-
- case TYPE_MINFO:
- get_name(dnsbuf, p, name); p = skip_name(p);
- rr->rdata.minfo.rmbx = strdup(name);
- get_name(dnsbuf, p, name); p = skip_name(p);
- rr->rdata.minfo.embx = strdup(name);
- break;
-
- case TYPE_MX:
- rr->rdata.mx.pref = get_uint16(p); p+=2;
- get_name(dnsbuf, p, name); p = skip_name(p);
- rr->rdata.mx.name = strdup(name);
- break;
-
- case TYPE_WKS:
- rr->rdata.wks.addr = get_uint32(p); p+=4;
- rr->rdata.wks.protocol = get_uint8(p); p+=1;
- if (rr->rdata.null.data = (char *)malloc(rdlen-5), rr->rdata.null.data!=NULL)
- {
- rr->rdata.wks.len = rdlen-5;
- memcpy(rr->rdata.null.data, p, rdlen-5);
- }
- break;
- }
-
- return rr;
-
- err2:
- free(rr->name);
- err1:
- free(rr);
- return NULL;
- }
-
-
- static void show_rr(vterm vt, rr_str *rr)
- {
- int i, j, n;
-
- if (!rr)
- return;
-
- if (rr->type<=TYPE_TXT)
- vterm_printf(vt, -1, "%-24s %-5s ", rr->name, type2s[rr->type]);
- else
- vterm_printf(vt, -1, "%-24s %5d ", rr->name, rr->type);
- vterm_printf(vt, -1, "%-8d ", rr->ttl);
-
- switch (rr->type)
- {
- case TYPE_NS:
- case TYPE_MD:
- case TYPE_MF:
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_PTR:
- case TYPE_TXT:
- vterm_printf(vt, -1, "%s\n",rr->rdata.txt.text);
- break;
-
- case TYPE_A:
- vterm_printf(vt, -1, " %d.%d.%d.%d\n",
- (rr->rdata.a.addr >> 24) & 0xff,
- (rr->rdata.a.addr >> 16) & 0xff,
- (rr->rdata.a.addr >> 8) & 0xff,
- rr->rdata.a.addr & 0xff );
- break;
-
- case TYPE_SOA:
- vterm_printf(vt, -1, " %s\n",rr->rdata.soa.mname);
- vterm_printf(vt, -1, " %s\n",rr->rdata.soa.rname);
- vterm_printf(vt, -1, " %10d %10d %10d %10d %10d\n",
- rr->rdata.soa.serial, rr->rdata.soa.refresh, rr->rdata.soa.retry,
- rr->rdata.soa.expire, rr->rdata.soa.minttl );
- break;
-
- case TYPE_NULL:
- for (i = 0; i<rr->rdata.null.len; i+=8)
- {
- vterm_printf(vt, -1, " %.4x: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x ", i,
- rr->rdata.null.data[i+0], rr->rdata.null.data[i+1], rr->rdata.null.data[i+2], rr->rdata.null.data[i+3],
- rr->rdata.null.data[i+4], rr->rdata.null.data[i+5], rr->rdata.null.data[i+6], rr->rdata.null.data[i+7] );
-
- vterm_printf(vt, -1, "%c%c%c%c%c%c%c%c",
- PRASC(rr->rdata.null.data[i+0]), PRASC(rr->rdata.null.data[i+1]),
- PRASC(rr->rdata.null.data[i+2]), PRASC(rr->rdata.null.data[i+3]),
- PRASC(rr->rdata.null.data[i+4]), PRASC(rr->rdata.null.data[i+5]),
- PRASC(rr->rdata.null.data[i+6]), PRASC(rr->rdata.null.data[i+7]) );
- }
- vterm_printf(vt, -1, "\n");
- break;
-
- case TYPE_HINFO:
- vterm_printf(vt, -1, "%s %s\n", rr->rdata.hinfo.cpu, rr->rdata.hinfo.os);
- break;
-
- case TYPE_MINFO:
- vterm_printf(vt, -1, " %s\n", rr->rdata.minfo.rmbx);
- vterm_printf(vt, -1, " %s\n", rr->rdata.minfo.embx);
- break;
-
- case TYPE_MX:
- vterm_printf(vt, -1, "%6d %s\n", rr->rdata.mx.pref, rr->rdata.mx.name);
- break;
-
- case TYPE_WKS:
- vterm_printf(vt, -1, "%d.%d.%d.%d\n",
- (rr->rdata.wks.addr >> 24) & 0xff,
- (rr->rdata.wks.addr >> 16) & 0xff,
- (rr->rdata.wks.addr >> 8) & 0xff,
- rr->rdata.wks.addr & 0xff );
- vterm_printf(vt, -1, " Services available on %d follow:\n", rr->rdata.wks.protocol);
- n = 4;
- for (i = 0; i<rr->rdata.wks.len; i++)
- {
- for (j = 0; j<8; j++)
- {
- if (rr->rdata.wks.data[i] & (2<<j))
- {
- vterm_printf(vt, -1, "%d", i*8+j);
- n += 8;
- }
- if (n>68)
- {
- n = 4;
- vterm_printf(vt, -1, "\n ");
- }
- }
- }
- vterm_printf(vt, -1, "\n");
- break;
-
- default:
- vterm_printf(vt, -1, "\n");
- break;
- }
- }
-
- static void free_rr(rr_str *rr)
- {
- if (!rr)
- return;
-
- switch (rr->type)
- {
- case TYPE_NS:
- case TYPE_MD:
- case TYPE_MF:
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_PTR:
- case TYPE_TXT:
- strfree(rr->rdata.txt.text);
- break;
-
- case TYPE_A:
- break;
-
- case TYPE_SOA:
- strfree(rr->rdata.soa.mname);
- strfree(rr->rdata.soa.rname);
- break;
-
- case TYPE_NULL:
- if (rr->rdata.null.data)
- free(rr->rdata.null.data);
- break;
-
- case TYPE_HINFO:
- strfree(rr->rdata.hinfo.cpu);
- strfree(rr->rdata.hinfo.os);
- break;
-
- case TYPE_MINFO:
- strfree(rr->rdata.minfo.rmbx);
- strfree(rr->rdata.minfo.embx);
- break;
-
- case TYPE_MX:
- strfree(rr->rdata.mx.name);
- break;
-
- case TYPE_WKS:
- if (rr->rdata.null.data)
- free(rr->rdata.null.data);
- break;
- }
-
- free(rr);
- }
-
- static char *skip_query(char *p)
- {
- return skip_name(p) + 4;
- }
-
- char *dns_encode_query(vterm vt, char *host, char *type)
- {
- int n, t;
- FILE *fp;
- char name[256];
- char *p, *query;
-
- n = strlen(type);
-
- if (isdigit(*type))
- t = atoi(type);
- else if (!strncmp(type, "a", n))
- t = TYPE_A;
- else if (!strncmp(type, "ms", n))
- t = TYPE_MX;
- else if (!strncmp(type, "ns", n))
- t = TYPE_NS;
- else if (!strncmp(type, "cname", n))
- t = TYPE_CNAME;
- else if (!strncmp(type, "ptr", n))
- t = TYPE_PTR;
- else if (!strncmp(type, "wks", n))
- t = TYPE_WKS;
- else if (!strncmp(type, "soa", n))
- t = TYPE_SOA;
- else if (!strncmp(type, "txt", n))
- t = TYPE_TXT;
- else
- t = TYPE_ALL;
-
- if (isdigit(*host))
- ntoinarpa(aton(host), name);
- else
- strcpy(name, host);
-
- if (query = malloc(512), query==NULL)
- return NULL;
-
- p = make_header(query+2, 1, OPCODE_STD);
- p = make_query(p, name, CLASS_IN, t);
-
- put_uint16(query, p-(query+2));
-
- return query;
- }
-
- int dns_decode_answer(vterm vt, char *answer, int length)
- {
- int n;
- uint16 id, flags, qdcount, ancount, nscount, arcount;
- int rcode, opcode, qr, aa, tc, rd, ra, z;
- char *p;
- rr_str *rr;
-
- FILE *fp;
-
- char *opcode2s[] = {
- "Standard query", "Inverse Query", "Server status req", "",
- "", "", "", "", "", "", "", "", "", "", "", ""};
-
- char *rcode2s[] = {
- "OK", "Syntax error", "Server failure", "Name unknown",
- "Not implemeted", "Refused", "", "",
- "", "", "", "", "", "", "", ""};
-
- p = answer;
-
- id = get_uint16(p); p+=2;
- flags = get_uint16(p); p+=2;
- qdcount = get_uint16(p); p+=2;
- ancount = get_uint16(p); p+=2;
- nscount = get_uint16(p); p+=2;
- arcount = get_uint16(p); p+=2;
-
- rcode = flags & 0x0f;
- z = (flags >> 4) & 0x07;
- ra = (flags >> 7) & 0x01;
- rd = (flags >> 8) & 0x01;
- tc = (flags >> 9) & 0x01;
- aa = (flags >> 10) & 0x01;
- opcode = (flags >> 11) & 0x0f;
- qr = (flags >> 15) & 0x01;
-
- vterm_printf(vt, -1, "%s", (qr)?((aa)?"Authoritive Answer":"Answer"):"Query");
- if (tc)
- vterm_printf(vt, -1, " (truncated)");
- if (rd)
- vterm_printf(vt, -1, " (recursion wanted)");
- if (rd)
- vterm_printf(vt, -1, " (recursion available)");
-
- vterm_printf(vt, -1, "\n");
-
- vterm_printf(vt, -1, "Op code: %2d (%s)\n", opcode, opcode2s[opcode]);
- vterm_printf(vt, -1, "Response code: %2d (%s)\n", rcode, rcode2s[rcode]);
-
- vterm_printf(vt, -1, "\nReceived:");
- vterm_printf(vt, -1, "%d queries, %d answers, %d name server records\n", qdcount, ancount, nscount);
- vterm_printf(vt, -1, " and %d additional records\n", arcount);
-
- vterm_printf(vt, -1, "\n");
-
- if (qdcount)
- p = skip_query(p);
-
- if (ancount)
- vterm_printf(vt, -1, "Answers:\n");
-
- for (n = 0; n<ancount; n++)
- {
- rr = extract_rr(answer, p);
- p = skip_rr(p);
- show_rr(vt, rr);
- free_rr(rr);
- }
- vterm_printf(vt, -1, "\n");
-
- if (nscount)
- vterm_printf(vt, -1, "Name Servers:\n");
-
- for (n = 0; n<nscount; n++)
- {
- rr = extract_rr(answer, p);
- p = skip_rr(p);
- show_rr(vt, rr);
- free_rr(rr);
- }
- vterm_printf(vt, -1, "\n");
-
- if (arcount)
- vterm_printf(vt, -1, "Additional Records:\n");
-
- for (n = 0; n<arcount; n++)
- {
- rr = extract_rr(answer, p);
- p = skip_rr(p);
- show_rr(vt, rr);
- free_rr(rr);
- }
- vterm_printf(vt, -1, "\n");
-
- return 1; /* Answer received and decoded */
- }
-
- static int vt_handler(void *handle, char *buf, int len)
- {
- vterm vt = (vterm)handle;
-
- if (buf==NULL && len==-1)
- vterm_destroy(vt);
-
- return 1;
- }
-
- void dns_test(void)
- {
- int s;
- FILE *fp;
- vterm vt;
- char *answer;
-
- if (fp = fopen("<TCPIP$Dir>.Answer", "rb"), fp == NULL)
- return;
-
- fseek(fp, 0, SEEK_END);
- s = (int)ftell(fp);
- fseek(fp, 0, SEEK_SET);
-
- if (answer = (char *)malloc(s), answer==NULL)
- {
- fclose(fp);
- return;
- }
-
- fread(answer, 1, s, fp);
- fclose(fp);
-
- vt = vterm_create(VTSW_VIEW|VTSW_NEWLINE);
- vterm_title(vt, "DNS Query Test");
- vterm_resize(vt, 80, 200);
- vterm_visible(vt, 80, 24);
- vterm_register_handler(vt, vt_handler, vt);
-
- dns_decode_answer(vt, answer+2, s-2);
-
- free(answer);
- }
-