1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <arpa/inet.h> 18 #include <dirent.h> 19 #include <errno.h> 20 #include <linux/if.h> 21 #include <netdb.h> 22 #include <netinet/in.h> 23 #include <stdlib.h> 24 #include <sys/socket.h> 25 #include <sys/types.h> 26 #include <string.h> 27 28 #define LOG_TAG "DnsProxyListener" 29 #define DBG 0 30 31 #include <cutils/log.h> 32 #include <sysutils/SocketClient.h> 33 34 #include "DnsProxyListener.h" 35 36 DnsProxyListener::DnsProxyListener() : 37 FrameworkListener("dnsproxyd") { 38 registerCmd(new GetAddrInfoCmd()); 39 registerCmd(new GetHostByAddrCmd()); 40 } 41 42 DnsProxyListener::GetAddrInfoHandler::~GetAddrInfoHandler() { 43 free(mHost); 44 free(mService); 45 free(mHints); 46 } 47 48 void DnsProxyListener::GetAddrInfoHandler::start() { 49 pthread_create(&mThread, NULL, 50 DnsProxyListener::GetAddrInfoHandler::threadStart, this); 51 } 52 53 void* DnsProxyListener::GetAddrInfoHandler::threadStart(void* obj) { 54 GetAddrInfoHandler* handler = reinterpret_cast<GetAddrInfoHandler*>(obj); 55 handler->run(); 56 delete handler; 57 pthread_exit(NULL); 58 return NULL; 59 } 60 61 // Sends 4 bytes of big-endian length, followed by the data. 62 // Returns true on success. 63 static bool sendLenAndData(SocketClient *c, const int len, const void* data) { 64 uint32_t len_be = htonl(len); 65 return c->sendData(&len_be, 4) == 0 && 66 (len == 0 || c->sendData(data, len) == 0); 67 } 68 69 void DnsProxyListener::GetAddrInfoHandler::run() { 70 if (DBG) { 71 LOGD("GetAddrInfoHandler, now for %s / %s", mHost, mService); 72 } 73 74 struct addrinfo* result = NULL; 75 int rv = getaddrinfo(mHost, mService, mHints, &result); 76 bool success = (mClient->sendData(&rv, sizeof(rv)) == 0); 77 if (rv == 0) { 78 struct addrinfo* ai = result; 79 while (ai && success) { 80 success = sendLenAndData(mClient, sizeof(struct addrinfo), ai) 81 && sendLenAndData(mClient, ai->ai_addrlen, ai->ai_addr) 82 && sendLenAndData(mClient, 83 ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0, 84 ai->ai_canonname); 85 ai = ai->ai_next; 86 } 87 success = success && sendLenAndData(mClient, 0, ""); 88 } 89 if (result) { 90 freeaddrinfo(result); 91 } 92 if (!success) { 93 LOGW("Error writing DNS result to client"); 94 } 95 mClient->decRef(); 96 } 97 98 DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd() : 99 NetdCommand("getaddrinfo") { 100 } 101 102 int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient *cli, 103 int argc, char **argv) { 104 if (DBG) { 105 for (int i = 0; i < argc; i++) { 106 LOGD("argv[%i]=%s", i, argv[i]); 107 } 108 } 109 if (argc != 7) { 110 LOGW("Invalid number of arguments to getaddrinfo: %i", argc); 111 sendLenAndData(cli, 0, NULL); 112 return -1; 113 } 114 115 char* name = argv[1]; 116 if (strcmp("^", name) == 0) { 117 name = NULL; 118 } else { 119 name = strdup(name); 120 } 121 122 char* service = argv[2]; 123 if (strcmp("^", service) == 0) { 124 service = NULL; 125 } else { 126 service = strdup(service); 127 } 128 129 struct addrinfo* hints = NULL; 130 int ai_flags = atoi(argv[3]); 131 int ai_family = atoi(argv[4]); 132 int ai_socktype = atoi(argv[5]); 133 int ai_protocol = atoi(argv[6]); 134 if (ai_flags != -1 || ai_family != -1 || 135 ai_socktype != -1 || ai_protocol != -1) { 136 hints = (struct addrinfo*) calloc(1, sizeof(struct addrinfo)); 137 hints->ai_flags = ai_flags; 138 hints->ai_family = ai_family; 139 hints->ai_socktype = ai_socktype; 140 hints->ai_protocol = ai_protocol; 141 } 142 143 if (DBG) { 144 LOGD("GetAddrInfoHandler for %s / %s", 145 name ? name : "[nullhost]", 146 service ? service : "[nullservice]"); 147 } 148 149 cli->incRef(); 150 DnsProxyListener::GetAddrInfoHandler* handler = 151 new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints); 152 handler->start(); 153 154 return 0; 155 } 156 157 /******************************************************* 158 * GetHostByAddr * 159 *******************************************************/ 160 DnsProxyListener::GetHostByAddrCmd::GetHostByAddrCmd() : 161 NetdCommand("gethostbyaddr") { 162 } 163 164 int DnsProxyListener::GetHostByAddrCmd::runCommand(SocketClient *cli, 165 int argc, char **argv) { 166 if (DBG) { 167 for (int i = 0; i < argc; i++) { 168 LOGD("argv[%i]=%s", i, argv[i]); 169 } 170 } 171 if (argc != 4) { 172 LOGW("Invalid number of arguments to gethostbyaddr: %i", argc); 173 sendLenAndData(cli, 0, NULL); 174 return -1; 175 } 176 177 char* addrStr = argv[1]; 178 int addrLen = atoi(argv[2]); 179 int addrFamily = atoi(argv[3]); 180 181 void* addr = malloc(sizeof(struct in6_addr)); 182 errno = 0; 183 int result = inet_pton(addrFamily, addrStr, addr); 184 if (result <= 0) { 185 LOGW("inet_pton(\"%s\") failed %s", addrStr, strerror(errno)); 186 free(addr); 187 sendLenAndData(cli, 0, NULL); 188 return -1; 189 } 190 191 cli->incRef(); 192 DnsProxyListener::GetHostByAddrHandler* handler = 193 new DnsProxyListener::GetHostByAddrHandler(cli, addr, addrLen, addrFamily); 194 handler->start(); 195 196 return 0; 197 } 198 199 DnsProxyListener::GetHostByAddrHandler::~GetHostByAddrHandler() { 200 free(mAddress); 201 } 202 203 void DnsProxyListener::GetHostByAddrHandler::start() { 204 pthread_create(&mThread, NULL, 205 DnsProxyListener::GetHostByAddrHandler::threadStart, this); 206 } 207 208 void* DnsProxyListener::GetHostByAddrHandler::threadStart(void* obj) { 209 GetHostByAddrHandler* handler = reinterpret_cast<GetHostByAddrHandler*>(obj); 210 handler->run(); 211 delete handler; 212 pthread_exit(NULL); 213 return NULL; 214 } 215 216 void DnsProxyListener::GetHostByAddrHandler::run() { 217 if (DBG) { 218 LOGD("DnsProxyListener::GetHostByAddrHandler::run\n"); 219 } 220 221 struct hostent* hp; 222 223 // NOTE gethostbyaddr should take a void* but bionic thinks it should be char* 224 hp = gethostbyaddr((char*)mAddress, mAddressLen, mAddressFamily); 225 226 if (DBG) { 227 LOGD("GetHostByAddrHandler::run gethostbyaddr errno: %s hp->h_name = %s, name_len = %d\n", 228 hp ? "success" : strerror(errno), 229 (hp && hp->h_name) ? hp->h_name: "null", 230 (hp && hp->h_name) ? strlen(hp->h_name)+ 1 : 0); 231 } 232 233 bool success = sendLenAndData(mClient, (hp && hp->h_name) ? strlen(hp->h_name)+ 1 : 0, 234 (hp && hp->h_name) ? hp->h_name : ""); 235 236 if (!success) { 237 LOGW("GetHostByAddrHandler: Error writing DNS result to client\n"); 238 } 239 mClient->decRef(); 240 } 241