Serenity Operating System
at portability 208 lines 6.7 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/Assertions.h> 28#include <AK/ScopeGuard.h> 29#include <AK/String.h> 30#include <Kernel/Net/IPv4.h> 31#include <arpa/inet.h> 32#include <netdb.h> 33#include <netinet/in.h> 34#include <stdio.h> 35#include <string.h> 36#include <unistd.h> 37 38extern "C" { 39 40int h_errno; 41 42static hostent __gethostbyname_buffer; 43static char __gethostbyname_name_buffer[512]; 44static in_addr_t __gethostbyname_address; 45static in_addr_t* __gethostbyname_address_list_buffer[2]; 46 47static hostent __gethostbyaddr_buffer; 48static char __gethostbyaddr_name_buffer[512]; 49static in_addr_t* __gethostbyaddr_address_list_buffer[2]; 50 51static int connect_to_lookup_server() 52{ 53 int fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); 54 if (fd < 0) { 55 perror("socket"); 56 return -1; 57 } 58 59 sockaddr_un address; 60 address.sun_family = AF_LOCAL; 61 strcpy(address.sun_path, "/tmp/portal/lookup"); 62 63 if (connect(fd, (const sockaddr*)&address, sizeof(address)) < 0) { 64 perror("connect_to_lookup_server"); 65 close(fd); 66 return -1; 67 } 68 return fd; 69} 70 71hostent* gethostbyname(const char* name) 72{ 73 auto ipv4_address = IPv4Address::from_string(name); 74 if (ipv4_address.has_value()) { 75 sprintf(__gethostbyname_name_buffer, "%s", ipv4_address.value().to_string().characters()); 76 __gethostbyname_buffer.h_name = __gethostbyname_name_buffer; 77 __gethostbyname_buffer.h_aliases = nullptr; 78 __gethostbyname_buffer.h_addrtype = AF_INET; 79 new (&__gethostbyname_address) IPv4Address(ipv4_address.value()); 80 __gethostbyname_address_list_buffer[0] = &__gethostbyname_address; 81 __gethostbyname_address_list_buffer[1] = nullptr; 82 __gethostbyname_buffer.h_addr_list = (char**)__gethostbyname_address_list_buffer; 83 __gethostbyname_buffer.h_length = 4; 84 85 return &__gethostbyname_buffer; 86 } 87 88 int fd = connect_to_lookup_server(); 89 if (fd < 0) 90 return nullptr; 91 92 auto close_fd_on_exit = ScopeGuard([fd] { 93 close(fd); 94 }); 95 96 auto line = String::format("L%s\n", name); 97 int nsent = write(fd, line.characters(), line.length()); 98 if (nsent < 0) { 99 perror("write"); 100 return nullptr; 101 } 102 103 ASSERT((size_t)nsent == line.length()); 104 105 char buffer[1024]; 106 int nrecv = read(fd, buffer, sizeof(buffer) - 1); 107 if (nrecv < 0) { 108 perror("recv"); 109 return nullptr; 110 } 111 112 if (!memcmp(buffer, "Not found.", sizeof("Not found.") - 1)) 113 return nullptr; 114 115 auto responses = String(buffer, nrecv).split('\n'); 116 if (responses.is_empty()) 117 return nullptr; 118 119 auto& response = responses[0]; 120 121 int rc = inet_pton(AF_INET, response.characters(), &__gethostbyname_address); 122 if (rc <= 0) 123 return nullptr; 124 125 strncpy(__gethostbyname_name_buffer, name, strlen(name)); 126 127 __gethostbyname_buffer.h_name = __gethostbyname_name_buffer; 128 __gethostbyname_buffer.h_aliases = nullptr; 129 __gethostbyname_buffer.h_addrtype = AF_INET; 130 __gethostbyname_address_list_buffer[0] = &__gethostbyname_address; 131 __gethostbyname_address_list_buffer[1] = nullptr; 132 __gethostbyname_buffer.h_addr_list = (char**)__gethostbyname_address_list_buffer; 133 __gethostbyname_buffer.h_length = 4; 134 135 return &__gethostbyname_buffer; 136} 137 138hostent* gethostbyaddr(const void* addr, socklen_t addr_size, int type) 139{ 140 if (type != AF_INET) { 141 errno = EAFNOSUPPORT; 142 return nullptr; 143 } 144 145 if (addr_size < sizeof(in_addr)) { 146 errno = EINVAL; 147 return nullptr; 148 } 149 150 int fd = connect_to_lookup_server(); 151 if (fd < 0) 152 return nullptr; 153 154 auto close_fd_on_exit = ScopeGuard([fd] { 155 close(fd); 156 }); 157 158 IPv4Address ipv4_address((const u8*)&((const in_addr*)addr)->s_addr); 159 160 auto line = String::format("R%d.%d.%d.%d.in-addr.arpa\n", 161 ipv4_address[3], 162 ipv4_address[2], 163 ipv4_address[1], 164 ipv4_address[0]); 165 int nsent = write(fd, line.characters(), line.length()); 166 if (nsent < 0) { 167 perror("write"); 168 return nullptr; 169 } 170 171 ASSERT((size_t)nsent == line.length()); 172 173 char buffer[1024]; 174 int nrecv = read(fd, buffer, sizeof(buffer) - 1); 175 if (nrecv < 0) { 176 perror("recv"); 177 return nullptr; 178 } 179 180 if (!memcmp(buffer, "Not found.", sizeof("Not found.") - 1)) 181 return nullptr; 182 183 auto responses = String(buffer, nrecv).split('\n'); 184 if (responses.is_empty()) 185 return nullptr; 186 187 auto& response = responses[0]; 188 189 strncpy(__gethostbyaddr_name_buffer, response.characters(), max(sizeof(__gethostbyaddr_name_buffer), response.length())); 190 191 __gethostbyaddr_buffer.h_name = __gethostbyaddr_name_buffer; 192 __gethostbyaddr_buffer.h_aliases = nullptr; 193 __gethostbyaddr_buffer.h_addrtype = AF_INET; 194 // FIXME: Should we populate the hostent's address list here with a sockaddr_in for the provided host? 195 __gethostbyaddr_address_list_buffer[0] = nullptr; 196 __gethostbyaddr_buffer.h_addr_list = (char**)__gethostbyaddr_address_list_buffer; 197 __gethostbyaddr_buffer.h_length = 4; 198 199 return &__gethostbyaddr_buffer; 200} 201 202struct servent* getservbyname(const char* name, const char* protocol) 203{ 204 dbg() << "FIXME: getservbyname(\"" << name << "\", \"" << protocol << "\")"; 205 ASSERT_NOT_REACHED(); 206} 207 208}