Last active
March 29, 2019 02:51
-
-
Save leandrotsampa/b8fff64c9e1550ca0fd873a20ea68ee2 to your computer and use it in GitHub Desktop.
Created function gethostbyname for Linux Kernel using DNS for resolv URL to IPv4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/module.h> // included for all kernel modules | |
#include <linux/kernel.h> // included for KERN_INFO | |
#include <linux/init.h> // included for __init and __exit macros | |
#include <linux/socket.h> | |
#include <linux/net.h> | |
#include <linux/inet.h> | |
#include <linux/string.h> | |
#include <linux/vmalloc.h> | |
#include <net/sock.h> | |
#define T_A 1 // IPv4 Address | |
#define T_NS 2 // Nameserver | |
#define T_CNAME 5 // Canonical Name | |
#define T_SOA 6 // Start of Authority Zone | |
#define T_PTR 12 // Domain Name Pointer | |
#define T_MX 15 // Mail Server | |
#define DNS_SIZE 65536 | |
unsigned int dns_servers[] = { 0xd043dede, /* 208.67.222.222 - OpenDNS */ | |
0x08080808, /* 8.8.8.8 - Google DNS */ | |
0xd043dcdc, /* 208.67.220.220 - OpenDNS */ | |
0x08080404 }; /* 8.8.4.4 - Google DNS */ | |
struct HOST { | |
char *name; /* Official Name of Host */ | |
struct in_addr addr; /* IPv4 Address */ | |
}; | |
//DNS header structure | |
struct DNS_HEADER { | |
unsigned short id; // identification number | |
unsigned char rd :1; // recursion desired | |
unsigned char tc :1; // truncated message | |
unsigned char aa :1; // authoritive answer | |
unsigned char opcode :4; // purpose of message | |
unsigned char qr :1; // query/response flag | |
unsigned char rcode :4; // response code | |
unsigned char cd :1; // checking disabled | |
unsigned char ad :1; // authenticated data | |
unsigned char z :1; // its z! reserved | |
unsigned char ra :1; // recursion available | |
unsigned short q_count; // number of question entries | |
unsigned short ans_count; // number of answer entries | |
unsigned short auth_count; // number of authority entries | |
unsigned short add_count; // number of resource entries | |
}; | |
//Constant sized fields of query structure | |
struct QUESTION { | |
unsigned short qtype; | |
unsigned short qclass; | |
}; | |
#pragma pack(push, 1) | |
struct R_DATA { | |
unsigned short type; | |
unsigned short _class; | |
unsigned int ttl; | |
unsigned short data_len; | |
}; | |
#pragma pack(pop) | |
//Pointers to resource record contents | |
struct RES_RECORD { | |
unsigned char *name; | |
struct R_DATA *resource; | |
unsigned char *rdata; | |
}; | |
int dns_send(struct socket *sock, void *buf, size_t length, unsigned long flags) { | |
struct msghdr msg; | |
struct kvec vec; | |
msg.msg_name = 0; | |
msg.msg_namelen = 0; | |
msg.msg_control = NULL; | |
msg.msg_controllen = 0; | |
msg.msg_flags = flags; | |
vec.iov_base = buf; | |
vec.iov_len = length; | |
return kernel_sendmsg(sock, &msg, &vec, 1, length); | |
} | |
int dns_recv(struct socket *sock, void *buf, size_t length, unsigned long flags) { | |
struct msghdr msg; | |
struct kvec vec; | |
msg.msg_name = 0; | |
msg.msg_namelen = 0; | |
msg.msg_control = NULL; | |
msg.msg_controllen = 0; | |
msg.msg_flags = flags; | |
vec.iov_base = buf; | |
vec.iov_len = length; | |
return kernel_recvmsg(sock, &msg, &vec, 1, length, flags); | |
} | |
/* | |
* This will extract wwwgooglecom and convert back to www.google.com | |
*/ | |
unsigned char *read_host_name(unsigned char *reader,unsigned char *buffer,int *count) { | |
int i; | |
int j; | |
unsigned int offset; | |
unsigned int p = 0; | |
unsigned int jumped = 0; | |
unsigned char *name = vmalloc(256); | |
*count = 1; | |
name[0] = '\0'; | |
//read the names in wwwgooglecom format | |
while (*reader != 0) { | |
if (*reader >= 192) { | |
offset = (*reader)*256 + *(reader+1) - 49152; //49152 = 11000000 00000000 ;) | |
reader = buffer + offset - 1; | |
jumped = 1; //we have jumped to another location so counting wont go up! | |
} else { | |
name[p++] = *reader; | |
} | |
reader = reader+1; | |
if (jumped == 0) | |
*count = *count + 1; //if we havent jumped to another location then we can count up | |
} | |
name[p] = '\0'; //string complete | |
if (jumped == 1) | |
*count = *count + 1; //number of steps we actually moved forward in the packet | |
// now convert wwwgooglecom to www.google.com | |
for (i = 0; i < (int)strlen((const char*)name); i++) { | |
p = name[i]; | |
for (j = 0; j < (int)p; j++) { | |
name[i] = name[i+1]; | |
i = i + 1; | |
} | |
name[i] = '.'; | |
} | |
if (i > 0) | |
name[i-1] = '\0'; //remove the last dot | |
return name; | |
} | |
/* | |
* This will convert www.google.com to wwwgooglecom | |
*/ | |
void format_to_dns_name(unsigned char *dns,unsigned char *host) { | |
int i; | |
int lock = 0; | |
strcat((char*)host, "."); | |
for (i = 0; i < strlen((char*)host); i++) { | |
if (host[i] == '.') { | |
*dns++ = i-lock; | |
for (; lock < i; lock++) | |
*dns++=host[lock]; | |
lock++; //or lock=i+1; | |
} | |
} | |
*dns++='\0'; | |
} | |
struct HOST *gethostbyname(unsigned char *host) { | |
size_t length; | |
unsigned char *qname; | |
struct sockaddr_in addr; | |
struct RES_RECORD answers[20]; | |
int c_server = 0; | |
struct socket *conn = NULL; | |
struct HOST *hEntry = NULL; | |
struct DNS_HEADER *dns = NULL; | |
struct QUESTION *qinfo = NULL; | |
unsigned char *buf = vmalloc(DNS_SIZE); | |
unsigned int u32TimeOut = 1000; /* Timeout: 1s */ | |
unsigned int u32TimeSpan = 0; | |
if (!buf) | |
return hEntry; | |
// Set the DNS structure to standard queries | |
memset(buf, 0, DNS_SIZE); | |
dns = (struct DNS_HEADER *)&buf[0]; | |
dns->id = (unsigned short)htons(0 /*getpid()*/); | |
dns->qr = 0; // This is a query | |
dns->opcode = 0; // This is a standard query | |
dns->aa = 0; // Not Authoritative | |
dns->tc = 0; // This message is not truncated | |
dns->rd = 1; // Recursion Desired | |
dns->ra = 0; // Recursion not available! hey we dont have it (lol) | |
dns->z = 0; | |
dns->ad = 0; | |
dns->cd = 0; | |
dns->rcode = 0; | |
dns->q_count = htons(1); // We have only 1 question | |
dns->ans_count = 0; | |
dns->auth_count = 0; | |
dns->add_count = 0; | |
// Point to the query portion | |
qname =(unsigned char*)&buf[sizeof(struct DNS_HEADER)]; | |
format_to_dns_name(qname, host); | |
qinfo =(struct QUESTION*)&buf[sizeof(struct DNS_HEADER) + (strlen((const char*)qname) + 1)]; //fill it | |
qinfo->qtype = htons(T_A); // Type of the query , A , MX , CNAME , NS etc | |
qinfo->qclass = htons(1); // It's internet (lol) | |
/* UDP packet for DNS queries */ | |
if (sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &conn) < 0) | |
goto exit; | |
for (; c_server < sizeof(dns_servers) / sizeof(unsigned int); c_server++) { | |
int ret; | |
memset(&addr, 0, sizeof(addr)); | |
addr.sin_family = AF_INET; | |
addr.sin_port = htons(53); | |
addr.sin_addr.s_addr = htonl(dns_servers[c_server]); | |
/* Connect to DNS Server */ | |
ret = conn->ops->connect(conn, (struct sockaddr *)&addr, sizeof(addr), O_RDWR); | |
if (!(ret && (ret != -EINPROGRESS))) | |
break; | |
} | |
length = sizeof(struct DNS_HEADER) + (strlen((const char*)qname)+1) + sizeof(struct QUESTION); | |
if (dns_send(conn, (void *)buf, length, MSG_DONTWAIT) != length) | |
goto exit; | |
while (u32TimeSpan < u32TimeOut) { | |
if (!skb_queue_empty(&conn->sk->sk_receive_queue)) { | |
int i; | |
int j; | |
int recv; | |
int stop = 0; | |
unsigned char *reader = NULL; | |
memset(buf, 0, DNS_SIZE); | |
recv = dns_recv(conn, (void *)buf, DNS_SIZE, MSG_DONTWAIT); | |
if (recv <= 0) | |
break; | |
dns = (struct DNS_HEADER *)&buf[0]; | |
reader = &buf[sizeof(struct DNS_HEADER) + (strlen((const char*)qname)+1) + sizeof(struct QUESTION)]; // move ahead of the dns header and the query field | |
// Start reading answers | |
for (i = 0; i < ntohs(dns->ans_count); i++) { | |
answers[i].name = read_host_name(reader, buf, &stop); | |
reader = reader + stop; | |
answers[i].resource = (struct R_DATA*)(reader); | |
reader = reader + sizeof(struct R_DATA); | |
if (ntohs(answers[i].resource->type) == 1) { // If its an ipv4 address | |
answers[i].rdata = (unsigned char*)vmalloc(ntohs(answers[i].resource->data_len)); | |
for (j = 0; j < ntohs(answers[i].resource->data_len); j++) | |
answers[i].rdata[j]=reader[j]; | |
answers[i].rdata[ntohs(answers[i].resource->data_len)] = '\0'; | |
reader = reader + ntohs(answers[i].resource->data_len); | |
} else { | |
answers[i].rdata = read_host_name(reader, buf, &stop); | |
reader = reader + stop; | |
} | |
} | |
for (i = 0; i < ntohs(dns->ans_count); i++) { | |
if (ntohs(answers[i].resource->type) == T_A) { // IPv4 Address | |
long *p = (long*)answers[i].rdata; | |
if (!(hEntry = vmalloc(sizeof(struct HOST)))) | |
goto exit; | |
hEntry->name = answers[i].name; | |
hEntry->addr.s_addr = (*p); // working without ntohl | |
break; | |
} | |
} | |
break; | |
} else { | |
mdelay(10); | |
u32TimeSpan += 10; | |
} | |
} | |
exit: | |
vfree(buf); | |
return hEntry; | |
} | |
static int __init dns_init(void) { | |
struct HOST *hEntry = gethostbyname("www.google.com"); | |
if (hEntry) | |
printk("[INFO] Host: %s IPv4: %pI4\n", hEntry->name, &hEntry->addr); | |
else | |
printk("[INFO] Host: www.google.com IPv4: UNKNOWN\n"); | |
return 0; | |
} | |
static void __exit dns_exit(void) { | |
} | |
module_init(dns_init); | |
module_exit(dns_exit); | |
MODULE_DESCRIPTION("DNS Module to resolve url to ip."); | |
MODULE_AUTHOR("Leandro Tavares de Melo <[email protected]>"); | |
MODULE_LICENSE("GPL"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment