diff --git a/Kernel/init.cpp b/Kernel/init.cpp index a957b112d7..728a72c411 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -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); diff --git a/Kernel/sync.sh b/Kernel/sync.sh index 6836b77478..be6c3bbbfb 100755 --- a/Kernel/sync.sh +++ b/Kernel/sync.sh @@ -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 diff --git a/LibC/netdb.cpp b/LibC/netdb.cpp index 3be3bc868e..a03e34f550 100644 --- a/LibC/netdb.cpp +++ b/LibC/netdb.cpp @@ -3,29 +3,83 @@ #include #include #include +#include +#include +#include +#include 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; } } - diff --git a/Servers/DNSLookupServer/main.cpp b/Servers/DNSLookupServer/main.cpp index 233410a86a..9f280c0f50 100644 --- a/Servers/DNSLookupServer/main.cpp +++ b/Servers/DNSLookupServer/main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -22,7 +23,7 @@ #define C_IN 1 -static Vector lookup(const String& hostname); +static Vector 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 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 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 lookup(const String& hostname) +Vector lookup(const String& hostname, bool& did_timeout) { // FIXME: First check if it's an IP address in a string! @@ -91,7 +173,7 @@ Vector 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 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 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 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 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(), diff --git a/Userland/.gitignore b/Userland/.gitignore index 65bc7283b9..b3e6580898 100644 --- a/Userland/.gitignore +++ b/Userland/.gitignore @@ -40,3 +40,4 @@ stat ping uc tc +host diff --git a/Userland/Makefile b/Userland/Makefile index 84d425e40b..b9e65cb5fa 100644 --- a/Userland/Makefile +++ b/Userland/Makefile @@ -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 $< diff --git a/Userland/host.cpp b/Userland/host.cpp new file mode 100644 index 0000000000..179e5a649e --- /dev/null +++ b/Userland/host.cpp @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + if (argc < 2) { + printf("usage: host \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; +}