DnsProxyListener.cpp revision 6217272e1a41fc9827250c675a0499d2091ec6ac
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#include "ResponseCode.h" 36 37DnsProxyListener::DnsProxyListener() : 38 FrameworkListener("dnsproxyd") { 39 registerCmd(new GetAddrInfoCmd()); 40 registerCmd(new GetHostByAddrCmd()); 41} 42 43DnsProxyListener::GetAddrInfoHandler::~GetAddrInfoHandler() { 44 free(mHost); 45 free(mService); 46 free(mHints); 47} 48 49void DnsProxyListener::GetAddrInfoHandler::start() { 50 pthread_create(&mThread, NULL, 51 DnsProxyListener::GetAddrInfoHandler::threadStart, this); 52} 53 54void* DnsProxyListener::GetAddrInfoHandler::threadStart(void* obj) { 55 GetAddrInfoHandler* handler = reinterpret_cast<GetAddrInfoHandler*>(obj); 56 handler->run(); 57 delete handler; 58 pthread_exit(NULL); 59 return NULL; 60} 61 62// Sends 4 bytes of big-endian length, followed by the data. 63// Returns true on success. 64static bool sendLenAndData(SocketClient *c, const int len, const void* data) { 65 uint32_t len_be = htonl(len); 66 return c->sendData(&len_be, 4) == 0 && 67 (len == 0 || c->sendData(data, len) == 0); 68} 69 70void DnsProxyListener::GetAddrInfoHandler::run() { 71 if (DBG) { 72 ALOGD("GetAddrInfoHandler, now for %s / %s", mHost, mService); 73 } 74 75 struct addrinfo* result = NULL; 76 uint32_t rv = getaddrinfo(mHost, mService, mHints, &result); 77 if (rv) { 78 // getaddrinfo failed 79 // TODO This is temporary. We think there is another bug exposed when we send data here, so 80 // temporarily setting it to 0. 81 mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, 0); 82 } else { 83 bool success = !mClient->sendCode(ResponseCode::DnsProxyQueryResult); 84 struct addrinfo* ai = result; 85 while (ai && success) { 86 success = sendLenAndData(mClient, sizeof(struct addrinfo), ai) 87 && sendLenAndData(mClient, ai->ai_addrlen, ai->ai_addr) 88 && sendLenAndData(mClient, 89 ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0, 90 ai->ai_canonname); 91 ai = ai->ai_next; 92 } 93 success = success && sendLenAndData(mClient, 0, ""); 94 if (!success) { 95 ALOGW("Error writing DNS result to client"); 96 } 97 } 98 if (result) { 99 freeaddrinfo(result); 100 } 101 mClient->decRef(); 102} 103 104DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd() : 105 NetdCommand("getaddrinfo") { 106} 107 108int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient *cli, 109 int argc, char **argv) { 110 if (DBG) { 111 for (int i = 0; i < argc; i++) { 112 ALOGD("argv[%i]=%s", i, argv[i]); 113 } 114 } 115 if (argc != 7) { 116 char* msg = NULL; 117 asprintf( &msg, "Invalid number of arguments to getaddrinfo: %i", argc); 118 ALOGW("%s", msg); 119 cli->sendMsg(ResponseCode::CommandParameterError, msg, false); 120 free(msg); 121 return -1; 122 } 123 124 char* name = argv[1]; 125 if (strcmp("^", name) == 0) { 126 name = NULL; 127 } else { 128 name = strdup(name); 129 } 130 131 char* service = argv[2]; 132 if (strcmp("^", service) == 0) { 133 service = NULL; 134 } else { 135 service = strdup(service); 136 } 137 138 struct addrinfo* hints = NULL; 139 int ai_flags = atoi(argv[3]); 140 int ai_family = atoi(argv[4]); 141 int ai_socktype = atoi(argv[5]); 142 int ai_protocol = atoi(argv[6]); 143 if (ai_flags != -1 || ai_family != -1 || 144 ai_socktype != -1 || ai_protocol != -1) { 145 hints = (struct addrinfo*) calloc(1, sizeof(struct addrinfo)); 146 hints->ai_flags = ai_flags; 147 hints->ai_family = ai_family; 148 hints->ai_socktype = ai_socktype; 149 hints->ai_protocol = ai_protocol; 150 } 151 152 if (DBG) { 153 ALOGD("GetAddrInfoHandler for %s / %s", 154 name ? name : "[nullhost]", 155 service ? service : "[nullservice]"); 156 } 157 158 cli->incRef(); 159 DnsProxyListener::GetAddrInfoHandler* handler = 160 new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints); 161 handler->start(); 162 163 return 0; 164} 165 166/******************************************************* 167 * GetHostByAddr * 168 *******************************************************/ 169DnsProxyListener::GetHostByAddrCmd::GetHostByAddrCmd() : 170 NetdCommand("gethostbyaddr") { 171} 172 173int DnsProxyListener::GetHostByAddrCmd::runCommand(SocketClient *cli, 174 int argc, char **argv) { 175 if (DBG) { 176 for (int i = 0; i < argc; i++) { 177 ALOGD("argv[%i]=%s", i, argv[i]); 178 } 179 } 180 181 if (argc != 4) { 182 char* msg = NULL; 183 asprintf(&msg, "Invalid number of arguments to gethostbyaddr: %i", argc); 184 ALOGW("%s", msg); 185 cli->sendMsg(ResponseCode::CommandParameterError, msg, false); 186 free(msg); 187 return -1; 188 } 189 190 char* addrStr = argv[1]; 191 int addrLen = atoi(argv[2]); 192 int addrFamily = atoi(argv[3]); 193 194 void* addr = malloc(sizeof(struct in6_addr)); 195 errno = 0; 196 int result = inet_pton(addrFamily, addrStr, addr); 197 if (result <= 0) { 198 char* msg = NULL; 199 asprintf(&msg, "inet_pton(\"%s\") failed %s", addrStr, strerror(errno)); 200 ALOGW("%s", msg); 201 cli->sendMsg(ResponseCode::OperationFailed, msg, false); 202 free(addr); 203 free(msg); 204 return -1; 205 } 206 207 cli->incRef(); 208 DnsProxyListener::GetHostByAddrHandler* handler = 209 new DnsProxyListener::GetHostByAddrHandler(cli, addr, addrLen, addrFamily); 210 handler->start(); 211 212 return 0; 213} 214 215DnsProxyListener::GetHostByAddrHandler::~GetHostByAddrHandler() { 216 free(mAddress); 217} 218 219void DnsProxyListener::GetHostByAddrHandler::start() { 220 pthread_create(&mThread, NULL, 221 DnsProxyListener::GetHostByAddrHandler::threadStart, this); 222} 223 224void* DnsProxyListener::GetHostByAddrHandler::threadStart(void* obj) { 225 GetHostByAddrHandler* handler = reinterpret_cast<GetHostByAddrHandler*>(obj); 226 handler->run(); 227 delete handler; 228 pthread_exit(NULL); 229 return NULL; 230} 231 232void DnsProxyListener::GetHostByAddrHandler::run() { 233 if (DBG) { 234 ALOGD("DnsProxyListener::GetHostByAddrHandler::run\n"); 235 } 236 237 struct hostent* hp; 238 239 // NOTE gethostbyaddr should take a void* but bionic thinks it should be char* 240 hp = gethostbyaddr((char*)mAddress, mAddressLen, mAddressFamily); 241 242 if (DBG) { 243 ALOGD("GetHostByAddrHandler::run gethostbyaddr errno: %s hp->h_name = %s, name_len = %d\n", 244 hp ? "success" : strerror(errno), 245 (hp && hp->h_name) ? hp->h_name: "null", 246 (hp && hp->h_name) ? strlen(hp->h_name)+ 1 : 0); 247 } 248 249 bool failed = true; 250 if (hp) { 251 failed = mClient->sendBinaryMsg(ResponseCode::DnsProxyQueryResult, 252 hp->h_name ? hp->h_name : "", 253 hp->h_name ? strlen(hp->h_name)+ 1 : 0); 254 } else { 255 // TODO This is temporary. We think there is another bug exposed when we send data here, so 256 // temporarily setting it to 0. 257 uint32_t error = h_errno; 258 failed = mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, 259 &error, 0); 260 } 261 262 if (failed) { 263 ALOGW("GetHostByAddrHandler: Error writing DNS result to client\n"); 264 } 265 mClient->decRef(); 266} 267