mirror of
https://github.com/RGBCube/serenity
synced 2025-06-01 07:48:12 +00:00
LibC: Implement gethostbyname() by talking to the DNSLookupServer.
We now talk to the lookup server over a local socket and it does the lookup on our behalf. Including some retry logic, which is nice, because it seems like DNS requests disappear in the ether pretty damn often where I am.
This commit is contained in:
parent
3ecfde193a
commit
0e4a1936ca
7 changed files with 213 additions and 36 deletions
|
@ -85,9 +85,15 @@ VFS* vfs;
|
|||
|
||||
int error;
|
||||
|
||||
auto* dns_lookup_server_process = Process::create_user_process("/bin/DNSLookupServer", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, { }, tty0);
|
||||
if (error != 0) {
|
||||
dbgprintf("error spawning DNSLookupServer: %d\n", error);
|
||||
hang();
|
||||
}
|
||||
|
||||
auto* window_server_process = Process::create_user_process("/bin/WindowServer", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, { }, tty0);
|
||||
if (error != 0) {
|
||||
dbgprintf("error: %d\n", error);
|
||||
dbgprintf("error spawning WindowServer: %d\n", error);
|
||||
hang();
|
||||
}
|
||||
window_server_process->set_priority(Process::HighPriority);
|
||||
|
|
|
@ -77,6 +77,7 @@ cp -v ../Userland/stat mnt/bin/stat
|
|||
cp -v ../Userland/ping mnt/bin/ping
|
||||
cp -v ../Userland/uc mnt/bin/uc
|
||||
cp -v ../Userland/tc mnt/bin/tc
|
||||
cp -v ../Userland/host mnt/bin/host
|
||||
chmod 4755 mnt/bin/su
|
||||
cp -v ../Applications/Terminal/Terminal mnt/bin/Terminal
|
||||
cp -v ../Applications/FontEditor/FontEditor mnt/bin/FontEditor
|
||||
|
|
|
@ -3,29 +3,83 @@
|
|||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/AKString.h>
|
||||
#include <Kernel/IPv4.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
static hostent __gethostbyname_buffer;
|
||||
static char __gethostbyname_name_buffer[512];
|
||||
static in_addr_t __gethostbyname_address;
|
||||
static in_addr_t* __gethostbyname_address_list_buffer[2];
|
||||
|
||||
hostent* gethostbyname(const char* name)
|
||||
{
|
||||
if (!strcmp(name, "boards.4channel.org")) {
|
||||
__gethostbyname_buffer.h_name = "boards.4channel.org";
|
||||
__gethostbyname_buffer.h_aliases = nullptr;
|
||||
__gethostbyname_buffer.h_addrtype = AF_INET;
|
||||
__gethostbyname_address = 0x4b4f1168;
|
||||
__gethostbyname_address_list_buffer[0] = &__gethostbyname_address;
|
||||
__gethostbyname_address_list_buffer[1] = nullptr;
|
||||
__gethostbyname_buffer.h_addr_list = (char**)__gethostbyname_address_list_buffer;
|
||||
__gethostbyname_buffer.h_length = 4;
|
||||
return &__gethostbyname_buffer;
|
||||
int fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (fd < 0) {
|
||||
perror("socket");
|
||||
return nullptr;
|
||||
}
|
||||
dbgprintf("FIXME(LibC): gethostbyname(%s)\n", name);
|
||||
return nullptr;
|
||||
|
||||
sockaddr_un address;
|
||||
address.sun_family = AF_LOCAL;
|
||||
strcpy(address.sun_path, "/tmp/.DNSLookupServer-socket");
|
||||
|
||||
int retries = 3;
|
||||
int rc = 0;
|
||||
while (retries) {
|
||||
rc = connect(fd, (const sockaddr*)&address, sizeof(address));
|
||||
if (rc == 0)
|
||||
break;
|
||||
--retries;
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
close(fd);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto line = String::format("%s\n", name);
|
||||
int nsent = write(fd, line.characters(), line.length());
|
||||
if (nsent < 0) {
|
||||
perror("send");
|
||||
close(fd);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ASSERT(nsent == line.length());
|
||||
|
||||
char buffer[1024];
|
||||
int nrecv = read(fd, buffer, sizeof(buffer) - 1);
|
||||
if (nrecv < 0) {
|
||||
perror("recv");
|
||||
close(fd);
|
||||
return nullptr;
|
||||
}
|
||||
buffer[nrecv] = '\0';
|
||||
close(fd);
|
||||
|
||||
if (!memcmp(buffer, "Not found.", sizeof("Not found.") - 1))
|
||||
return nullptr;
|
||||
|
||||
rc = inet_pton(AF_INET, buffer, &__gethostbyname_address);
|
||||
if (rc < 0)
|
||||
return nullptr;
|
||||
|
||||
strncpy(__gethostbyname_name_buffer, name, strlen(name));
|
||||
|
||||
__gethostbyname_buffer.h_name = __gethostbyname_name_buffer;
|
||||
__gethostbyname_buffer.h_aliases = nullptr;
|
||||
__gethostbyname_buffer.h_addrtype = AF_INET;
|
||||
__gethostbyname_address_list_buffer[0] = &__gethostbyname_address;
|
||||
__gethostbyname_address_list_buffer[1] = nullptr;
|
||||
__gethostbyname_buffer.h_addr_list = (char**)__gethostbyname_address_list_buffer;
|
||||
__gethostbyname_buffer.h_length = 4;
|
||||
|
||||
return &__gethostbyname_buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
@ -22,7 +23,7 @@
|
|||
|
||||
#define C_IN 1
|
||||
|
||||
static Vector<IPv4Address> lookup(const String& hostname);
|
||||
static Vector<IPv4Address> lookup(const String& hostname, bool& did_timeout);
|
||||
static String parse_dns_name(const byte*, int& offset, int max_offset);
|
||||
|
||||
int main(int argc, char**argv)
|
||||
|
@ -30,24 +31,105 @@ int main(int argc, char**argv)
|
|||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
String hostname = "disney.com";
|
||||
|
||||
if (argc == 2) {
|
||||
hostname = argv[1];
|
||||
}
|
||||
unlink("/tmp/.DNSLookupServer-socket");
|
||||
|
||||
HashMap<String, IPv4Address> dns_cache;
|
||||
|
||||
auto ipv4_addresses = lookup(hostname);
|
||||
if (ipv4_addresses.is_empty()) {
|
||||
printf("Lookup failed\n");
|
||||
} else {
|
||||
printf("DNS lookup result:\n");
|
||||
for (auto& ipv4_address : ipv4_addresses) {
|
||||
printf(" '%s' => %s\n", hostname.characters(), ipv4_address.to_string().characters());
|
||||
}
|
||||
int server_fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (server_fd < 0) {
|
||||
perror("socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sockaddr_un address;
|
||||
address.sun_family = AF_LOCAL;
|
||||
strcpy(address.sun_path, "/tmp/.DNSLookupServer-socket");
|
||||
|
||||
int rc = bind(server_fd, (const sockaddr*)&address, sizeof(address));
|
||||
if (rc < 0) {
|
||||
perror("bind");
|
||||
return 1;
|
||||
}
|
||||
rc = listen(server_fd, 5);
|
||||
if (rc < 0) {
|
||||
perror("listen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
fd_set rfds;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(server_fd, &rfds);
|
||||
rc = select(server_fd + 1, &rfds, nullptr, nullptr, nullptr);
|
||||
if (rc < 1) {
|
||||
perror("select");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sockaddr_un client_address;
|
||||
socklen_t client_address_size = sizeof(client_address);
|
||||
int client_fd = accept(server_fd, (sockaddr*)&client_address, &client_address_size);
|
||||
if (client_fd < 0) {
|
||||
perror("accept");
|
||||
continue;
|
||||
}
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(client_fd, &rfds);
|
||||
rc = select(client_fd + 1, &rfds, nullptr, nullptr, nullptr);
|
||||
if (rc < 1) {
|
||||
perror("select");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char client_buffer[1024];
|
||||
int nrecv = read(client_fd, client_buffer, sizeof(client_buffer) - 1);
|
||||
if (nrecv < 0) {
|
||||
perror("recv");
|
||||
close(client_fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
client_buffer[nrecv] = '\0';
|
||||
|
||||
auto hostname = String(client_buffer, nrecv, Chomp);
|
||||
dbgprintf("DNSLookupServer: Got request for '%s'\n", hostname.characters());
|
||||
|
||||
Vector<IPv4Address> addresses;
|
||||
|
||||
if (!hostname.is_empty()) {
|
||||
bool did_timeout;
|
||||
int retries = 3;
|
||||
do {
|
||||
did_timeout = false;
|
||||
addresses = lookup(hostname, did_timeout);
|
||||
if (!did_timeout)
|
||||
break;
|
||||
} while (--retries);
|
||||
if (did_timeout) {
|
||||
fprintf(stderr, "DNSLookupServer: Out of retries :(\n");
|
||||
close(client_fd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (addresses.is_empty()) {
|
||||
int nsent = write(client_fd, "Not found.\n", sizeof("Not found.\n"));
|
||||
if (nsent < 0)
|
||||
perror("write");
|
||||
close(client_fd);
|
||||
continue;
|
||||
}
|
||||
for (auto& address : addresses) {
|
||||
auto line = String::format("%s\n", address.to_string().characters());
|
||||
int nsent = write(client_fd, line.characters(), line.length());
|
||||
if (nsent < 0) {
|
||||
perror("write");
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(client_fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -57,7 +139,7 @@ static word get_next_id()
|
|||
return ++s_next_id;
|
||||
}
|
||||
|
||||
Vector<IPv4Address> lookup(const String& hostname)
|
||||
Vector<IPv4Address> lookup(const String& hostname, bool& did_timeout)
|
||||
{
|
||||
// FIXME: First check if it's an IP address in a string!
|
||||
|
||||
|
@ -91,7 +173,7 @@ Vector<IPv4Address> lookup(const String& hostname)
|
|||
return { };
|
||||
}
|
||||
|
||||
struct timeval timeout { 5, 0 };
|
||||
struct timeval timeout { 1, 0 };
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
if (rc < 0) {
|
||||
perror("setsockopt");
|
||||
|
@ -118,7 +200,11 @@ Vector<IPv4Address> lookup(const String& hostname)
|
|||
byte response_buffer[4096];
|
||||
ssize_t nrecv = recvfrom(fd, response_buffer, sizeof(response_buffer) - 1, 0, (struct sockaddr*)&src_addr, &src_addr_len);
|
||||
if (nrecv < 0) {
|
||||
perror("recvfrom");
|
||||
if (errno == EAGAIN) {
|
||||
did_timeout = true;
|
||||
} else {
|
||||
perror("recvfrom");
|
||||
}
|
||||
close(fd);
|
||||
return { };
|
||||
}
|
||||
|
@ -127,7 +213,7 @@ Vector<IPv4Address> lookup(const String& hostname)
|
|||
response_buffer[nrecv] = '\0';
|
||||
|
||||
if (nrecv < (int)sizeof(DNSPacket)) {
|
||||
printf("Response not big enough (%d) to be a DNS packet :(\n", nrecv);
|
||||
dbgprintf("DNSLookupServer: Response not big enough (%d) to be a DNS packet :(\n", nrecv);
|
||||
return { };
|
||||
}
|
||||
|
||||
|
@ -139,15 +225,15 @@ Vector<IPv4Address> lookup(const String& hostname)
|
|||
//printf("Additional count: %u\n", response_header.additional_count());
|
||||
|
||||
if (response_header.id() != request_header.id()) {
|
||||
printf("ID mismatch (%u vs %u) :(\n", response_header.id(), request_header.id());
|
||||
dbgprintf("DNSLookupServer: ID mismatch (%u vs %u) :(\n", response_header.id(), request_header.id());
|
||||
return { };
|
||||
}
|
||||
if (response_header.question_count() != 1) {
|
||||
printf("Question count (%u vs %u) :(\n", response_header.question_count(), request_header.question_count());
|
||||
dbgprintf("DNSLookupServer: Question count (%u vs %u) :(\n", response_header.question_count(), request_header.question_count());
|
||||
return { };
|
||||
}
|
||||
if (response_header.answer_count() < 1) {
|
||||
printf("Not enough answers (%u) :(\n", response_header.answer_count());
|
||||
dbgprintf("DNSLookupServer: Not enough answers (%u) :(\n", response_header.answer_count());
|
||||
return { };
|
||||
}
|
||||
|
||||
|
@ -160,7 +246,7 @@ Vector<IPv4Address> lookup(const String& hostname)
|
|||
for (word i = 0; i < response_header.answer_count(); ++i) {
|
||||
auto& record = *(const DNSRecord*)(&((const byte*)response_header.payload())[offset]);
|
||||
auto ipv4_address = IPv4Address((const byte*)record.data());
|
||||
printf(" Answer #%u: (question: %s), ttl=%u, length=%u, data=%s\n",
|
||||
dbgprintf("DNSLookupServer: Answer #%u: (question: %s), ttl=%u, length=%u, data=%s\n",
|
||||
i,
|
||||
question.characters(),
|
||||
record.ttl(),
|
||||
|
|
1
Userland/.gitignore
vendored
1
Userland/.gitignore
vendored
|
@ -40,3 +40,4 @@ stat
|
|||
ping
|
||||
uc
|
||||
tc
|
||||
host
|
||||
|
|
|
@ -36,6 +36,7 @@ OBJS = \
|
|||
ping.o \
|
||||
uc.o \
|
||||
tc.o \
|
||||
host.o \
|
||||
rm.o
|
||||
|
||||
APPS = \
|
||||
|
@ -77,6 +78,7 @@ APPS = \
|
|||
ping \
|
||||
uc \
|
||||
tc \
|
||||
host \
|
||||
rm
|
||||
|
||||
ARCH_FLAGS =
|
||||
|
@ -213,6 +215,9 @@ uc: uc.o
|
|||
tc: tc.o
|
||||
$(LD) -o $@ $(LDFLAGS) $< -lc
|
||||
|
||||
host: host.o
|
||||
$(LD) -o $@ $(LDFLAGS) $< -lc
|
||||
|
||||
.cpp.o:
|
||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
||||
|
|
24
Userland/host.cpp
Normal file
24
Userland/host.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
printf("usage: host <hostname>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto* hostent = gethostbyname(argv[1]);
|
||||
if (!hostent) {
|
||||
printf("Lookup failed for '%s'\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char buffer[32];
|
||||
const char* ip_str = inet_ntop(AF_INET, hostent->h_addr_list[0], buffer, sizeof(buffer));
|
||||
|
||||
printf("%s is %s\n", argv[1], ip_str);
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue