aboutsummaryrefslogtreecommitdiff
path: root/libs/libnet/dns.c
blob: e179bd6fc53e1571cc03bf7ce1f1c0fa20bc7b0c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// MIT License, Copyright (c) 2020 Marvin Borner
// TODO: Less magic, auto xld splitting
// TODO: DNS cache

#include <def.h>
#include <libnet/net.h>
#include <libnet/socket.h>
#include <mem.h>
#include <print.h>
#include <random.h>
#include <str.h>

static u32 dns_ip_addr = ip(1, 1, 1, 1);

struct dns_packet {
	u16 qid;
	u16 flags;
	u16 questions;
	u16 answers;
	u16 authorities;
	u16 additional;
	u8 data[];
} PACKED;

static u32 part_count(const char *name)
{
	u32 cnt = 0;
	for (u32 i = 0; i < strlen(name); i++) {
		if (name[i] == '.')
			cnt++;
	}
	return cnt + 1;
}

static u32 part_len(const char *name, u32 index)
{
	const char *data = name;

	u32 cnt = 0;
	for (u32 i = 0; i < strlen(name); i++) {
		if (cnt == index) {
			data += i;
			break;
		}

		if (name[i] == '.')
			cnt++;
	}

	for (cnt = 0; cnt < strlen(data); cnt++) {
		if (data[cnt] == '.' || data[cnt] == '\0')
			break;
	}

	return cnt;
}

static void dns_make_packet(struct dns_packet *packet, const char *name)
{
	packet->qid = htons(rand());
	packet->flags = htons(0x0100); // Standard query
	packet->questions = htons(1);
	packet->answers = htons(0);
	packet->authorities = htons(0);
	packet->additional = htons(0);

	u8 *data = packet->data;
	u32 cnt = 0;
	for (u32 i = 0; i < part_count(name) * 2; i += 2) {
		data[cnt] = part_len(name, i / 2);
		memcpy(&data[cnt + 1], &name[cnt], data[cnt]);
		cnt += data[cnt] + 1;
	}

	packet->data[cnt + 0] = 0x00; // Name end
	packet->data[cnt + 2] = 0x01; // A
	packet->data[cnt + 4] = 0x01; // IN
}

static u32 dns_handle_packet(struct dns_packet *packet)
{
	u16 flags = htons(packet->flags);
	u8 reply_code = flags & 0xf;
	if (reply_code != DNS_NOERROR) {
		printf("DNS error: %d\n", reply_code);
		return 0;
	}

	u8 *start = &packet->data[1] + strlen((char *)&packet->data[1]);
	printf("TTL of %s: %ds\n", &packet->data[1], (u32)start[14]);
	u8 *ip = &start[17];
	printf("IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
	return ip(ip[0], ip[1], ip[2], ip[3]);
}

u32 dns_request(const char *name)
{
	struct socket *socket = net_open(S_UDP);
	if (!socket || !net_connect(socket, dns_ip_addr, 53, NET_TIMEOUT) || part_count(name) == 1)
		return 0;

	u32 length = sizeof(struct dns_packet) + strlen(name) + part_count(name) + 4;
	struct dns_packet *packet = malloc(length);
	memset(packet, 0, length);
	dns_make_packet(packet, name);
	net_send(socket, packet, length);
	free(packet);

	u8 buf[1024] = { 0 };
	int l = net_receive(socket, buf, 1024, NET_TIMEOUT);
	net_close(socket);
	if (l > 0)
		return dns_handle_packet((void *)buf);
	else
		return 0;
}