📄 dns.c
字号:
/* Copyright (c) 2007 by Errata Security */
#include "protos.h"
#include "netframe.h"
#include "ferret.h"
#include "formats.h"
#include <string.h>
#include <ctype.h>
#ifndef MIN
#define MIN(a,b) ( (a)<(b) ? (a) : (b) )
#endif
struct DNSRECORD
{
unsigned name_offset;
unsigned type;
unsigned clss;
unsigned ttl;
unsigned rdata_offset;
unsigned rdata_length;
};
struct DNS {
unsigned id;
unsigned is_response;
unsigned opcode;
unsigned rcode;
unsigned flags;
unsigned question_count;
unsigned answer_count;
unsigned authority_count;
unsigned additional_count;
struct DNSRECORD records[256];
unsigned record_count;
struct DNSRECORD *questions;
struct DNSRECORD *answers;
struct DNSRECORD *authorities;
struct DNSRECORD *additionals;
};
unsigned dns_extract_name(struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned offset, char *name, unsigned sizeof_name)
{
int recurse_count = 0;
unsigned name_offset = 0;
name[0] = '\0';
while (offset < length) {
if (px[offset] == 0x00) {
break;
} else if (px[offset] & 0xC0) {
if (recurse_count > 100) {
FRAMERR(frame, "dns: name: recursion exceeded %d\n", recurse_count);
break;
}
recurse_count++;
if (offset+2 > length) {
FRAMERR(frame, "dns: name: not enough bytes\n");
strcpy(name, "(err)");
return 5;
}
offset = ex16be(px+offset)&0x3FF;
} else {
unsigned len = px[offset++];
if (offset >= length) {
FRAMERR(frame, "dns: name: not enough bytes\n");
strcpy(name, "(err)");
return 5;
}
if (offset+len > length) {
FRAMERR(frame, "dns: name: not enough bytes\n");
strcpy(name, "(err)");
return 5;
}
if (name_offset > 0) {
if (name_offset+1 >= sizeof_name) {
FRAMERR(frame, "dns: name: too long\n");
strcpy(name, "(err)");
return 5;
}
name[name_offset++] = '.';
}
if (name_offset+len+1 >= sizeof_name) {
FRAMERR(frame, "dns: name: too long\n");
strcpy(name, "(err)");
return 5;
}
memcpy(name+name_offset, px+offset, len);
name_offset += len;
name[name_offset] = '\0';
offset += len;
}
}
return name_offset;
}
static unsigned dns_resolve_alias(struct NetFrame *frame, const unsigned char *px, unsigned length, struct DNS *dns, const char *alias, int depth)
{
unsigned i;
for (i=dns->question_count; i<dns->record_count; i++) {
struct DNSRECORD *rec = &dns->records[i];
char name[256];
unsigned name_length;
name_length = dns_extract_name(frame, px, length, rec->name_offset, name, sizeof(name));
if ((rec->type != 1 && rec->type != 5)|| rec->clss != 1)
continue;
if (stricmp(alias, name) == 0) {
switch (rec->type) {
case 1:
return ex32be(px+rec->rdata_offset);
case 5:
name_length = dns_extract_name(frame, px, length, rec->rdata_offset, name, sizeof(name));
if (depth > 10)
FRAMERR(frame, "dns: too much recursion, alias=\"%s\"\n", alias);
else
return dns_resolve_alias(frame, px, length, dns, name, depth+1);
}
}
}
//FRAMERR(frame, "dns: could not resolve IP for alias=\"%s\"\n", alias);
return 0;
}
static void translate_netbios_name(struct NetFrame *frame, const char *name, char *netbios_name, unsigned sizeof_netbios_name)
{
unsigned j;
unsigned k;
sizeof_netbios_name;
k=0;
for (j=0; name[j] && name[j] != '.'; j++) {
if (name[j] < 'A' || name[j] > 'A'+15)
FRAMERR(frame, "netbios: bad netbios name char %c (0x%02x) \n", name[j], name[j]);
netbios_name[k] = (char)((name[j]-'A')<<4);
j++;
if (name[j] < 'A' || name[j] > 'A'+15)
FRAMERR(frame, "netbios: bad netbios name char %c (0x%02x) \n", name[j], name[j]);
if (name[j] && name[j] != '.')
netbios_name[k++] |= (char)((name[j]-'A')&0x0F);
}
/* handle trailing byte */
if (k && !isprint(netbios_name[k])) {
unsigned code = netbios_name[k];
k--;
while (k && isspace(netbios_name[k-1]))
k--;
netbios_name[k++] = '<';
netbios_name[k++] = "0123456789ABCDEF"[(code>>4)&0x0f];
netbios_name[k++] = "0123456789ABCDEF"[(code>>0)&0x0f];
netbios_name[k++] = '>';
}
while (name[j] && k<sizeof_netbios_name-1)
netbios_name[k++] = name[j++];
netbios_name[k] = '\0';
}
static void cleanse_netbios_name(struct NetFrame *frame, const char *name, char *netbios_name, unsigned sizeof_netbios_name)
{
unsigned j;
unsigned k;
frame;sizeof_netbios_name;
k=0;
for (j=0; j<16; j++) {
netbios_name[k++] = name[j];
}
netbios_name[k] = '\0';
/* handle trailing byte */
if (k && !isprint(netbios_name[k-1])) {
unsigned code = netbios_name[k-1];
k--;
while (k && isspace(netbios_name[k-1]))
k--;
netbios_name[k++] = '<';
netbios_name[k++] = "0123456789ABCDEF"[(code>>4)&0x0f];
netbios_name[k++] = "0123456789ABCDEF"[(code>>0)&0x0f];
netbios_name[k++] = '>';
}
netbios_name[k] = '\0';
}
static void process_request_update(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length, struct DNS *dns)
{
unsigned i;
if (dns->additional_count == 0)
FRAMERR(frame, "dns: corrupt\n");
for (i=0; i<dns->additional_count; i++) {
char name[256];
unsigned name_length;
struct DNSRECORD *rec = &dns->additionals[i];
name_length = dns_extract_name(frame, px, length, rec->name_offset, name, sizeof(name));
switch (rec->type) {
case 0x0020: /*NETBIOS */
switch (rec->clss) {
case 0x0001: /*INTERNET*/
{
unsigned ip_address = ex32be(px+rec->rdata_offset);
char netbios_name[256];
if (rec->rdata_length != 6)
FRAMERR(frame, "dns: data not 4-bytes long, was %d-bytes instead (class=%d, type=%d, name=%s)\n", rec->rdata_length, rec->clss, rec->type, name);
translate_netbios_name(frame, name, netbios_name, sizeof(netbios_name));
process_record(seap,
"proto", REC_SZ, "NETBIOS", -1,
"op", REC_SZ, "register", -1,
"ip.src", REC_FRAMESRC, frame, -1,
"name", REC_PRINTABLE, netbios_name, strlen(netbios_name),
"address", REC_IPv4, &ip_address, sizeof(ip_address),
0);
}
break;
default:
FRAMERR(frame, "dns: unknown class=%d (type=%d, name=%s)\n", rec->clss, rec->type, name);
}
break;
default:
FRAMERR(frame, "dns: unknown type=%d (class=%d, name=%s)\n", rec->type, rec->clss, name);
}
}
}
static void dns_dynamic_update(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length, struct DNS *dns)
{
unsigned i;
for (i=0; i<dns->answer_count; i++) {
char name[256];
unsigned name_length;
unsigned x;
struct DNSRECORD *rec = &dns->answers[i];
name_length = dns_extract_name(frame, px, length, rec->name_offset, name, sizeof(name));
x = rec->clss<<16 | rec->type;
SAMPLE("DynDNS", "Prereq", REC_UNSIGNED, &x, sizeof(x));
switch (rec->type) {
case 0x0001: /*A*/
switch (rec->clss) {
case 0x0001: /*INTERNET*/
{
unsigned ip_address = ex32be(px+rec->rdata_offset);
if (rec->rdata_length != 4)
FRAMERR(frame, "dns: data not 4-bytes long, was %d-bytes instead (class=%d, type=%d, name=%s)\n", rec->rdata_length, rec->clss, rec->type, name);
process_record(seap,
"ID-IP", REC_IPv4, &ip_address, sizeof(ip_address),
"name", REC_PRINTABLE, name, strlen(name),
0);
process_record(seap,
"proto", REC_SZ, "NETBIOS", -1,
"op", REC_SZ, "register", -1,
"ip.src", REC_FRAMESRC, frame, -1,
"name", REC_PRINTABLE, name, strlen(name),
"address", REC_IPv4, &ip_address, sizeof(ip_address),
0);
}
break;
default:
FRAMERR(frame, "dns: unknown class=%d (type=%d, name=%s)\n", rec->clss, rec->type, name);
}
break;
}
}
}
const unsigned char *find_mac(const unsigned char *px, unsigned length, unsigned offset, const unsigned char **r_name, unsigned *r_name_length)
{
unsigned len;
if (offset >= length)
return 0;
len = px[offset];
if (len > 64)
return 0;
offset++;
if (length > offset+len)
length = offset+len;
*r_name = px+offset;
*r_name_length = 0;
while (offset < length && px[offset] != '[') {
(*r_name_length)++;
offset++;
}
while (*r_name_length && isspace((*r_name)[(*r_name_length)-1]))
(*r_name_length)--;
if (offset +19 <= length && px[offset] == '[') {
const unsigned char *result = px+offset;
return result;
}
return 0;
}
static unsigned endsWith(const void *v_basestr, const void *v_pattern)
{
const char *basestr = (const char *)v_basestr;
const char *pattern = (const char *)v_pattern;
unsigned base_length = strlen(basestr);
unsigned pattern_length = strlen(pattern);
if (base_length < pattern_length)
return 0;
return memcmp(basestr+base_length-pattern_length, pattern, pattern_length) == 0;
}
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#define TYPECLASS(n,m) ((n)<<16|(m))
static void skip_name(const unsigned char *px, unsigned length, unsigned *r_offset)
{
while (*r_offset < length) {
if (0xC0 & px[*r_offset]) {
(*r_offset) += 2;
return;
}
if (0x00 == px[*r_offset]) {
(*r_offset) += 1;
return;
}
*r_offset += 1 + px[*r_offset];
}
}
static void DECODEANSWER(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length, struct DNS *dns, struct DNSRECORD *rec, const char *opcode)
{
unsigned ip_address;
char name[256];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -