DnsProxyListener.cpp revision 0cdb680c7648b0f48e6513926cb0a06d290a5cbe
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#include <pthread.h> 28 29#define LOG_TAG "DnsProxyListener" 30#define DBG 0 31 32#include <cutils/log.h> 33#include <sysutils/SocketClient.h> 34 35#include "DnsProxyListener.h" 36#include "ResponseCode.h" 37 38DnsProxyListener::DnsProxyListener() : 39 FrameworkListener("dnsproxyd") { 40 registerCmd(new GetAddrInfoCmd()); 41 registerCmd(new GetHostByAddrCmd()); 42} 43 44DnsProxyListener::GetAddrInfoHandler::~GetAddrInfoHandler() { 45 free(mHost); 46 free(mService); 47 free(mHints); 48} 49 50void DnsProxyListener::GetAddrInfoHandler::start() { 51 pthread_t thread; 52 pthread_create(&thread, NULL, 53 DnsProxyListener::GetAddrInfoHandler::threadStart, this); 54} 55 56void* DnsProxyListener::GetAddrInfoHandler::threadStart(void* obj) { 57 GetAddrInfoHandler* handler = reinterpret_cast<GetAddrInfoHandler*>(obj); 58 handler->run(); 59 delete handler; 60 pthread_exit(NULL); 61 return NULL; 62} 63 64// Sends 4 bytes of big-endian length, followed by the data. 65// Returns true on success. 66static bool sendLenAndData(SocketClient *c, const int len, const void* data) { 67 uint32_t len_be = htonl(len); 68 return c->sendData(&len_be, 4) == 0 && 69 (len == 0 || c->sendData(data, len) == 0); 70} 71 72void DnsProxyListener::GetAddrInfoHandler::run() { 73 if (DBG) { 74 ALOGD("GetAddrInfoHandler, now for %s / %s", mHost, mService); 75 } 76 77 struct addrinfo* result = NULL; 78 uint32_t rv = getaddrinfo(mHost, mService, mHints, &result); 79 if (rv) { 80 // getaddrinfo failed 81 mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, sizeof(rv)); 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_t thread; 221 pthread_create(&thread, NULL, 222 DnsProxyListener::GetHostByAddrHandler::threadStart, this); 223} 224 225void* DnsProxyListener::GetHostByAddrHandler::threadStart(void* obj) { 226 GetHostByAddrHandler* handler = reinterpret_cast<GetHostByAddrHandler*>(obj); 227 handler->run(); 228 delete handler; 229 pthread_exit(NULL); 230 return NULL; 231} 232 233void DnsProxyListener::GetHostByAddrHandler::run() { 234 if (DBG) { 235 ALOGD("DnsProxyListener::GetHostByAddrHandler::run\n"); 236 } 237 238 struct hostent* hp; 239 240 // NOTE gethostbyaddr should take a void* but bionic thinks it should be char* 241 hp = gethostbyaddr((char*)mAddress, mAddressLen, mAddressFamily); 242 243 if (DBG) { 244 ALOGD("GetHostByAddrHandler::run gethostbyaddr errno: %s hp->h_name = %s, name_len = %d\n", 245 hp ? "success" : strerror(errno), 246 (hp && hp->h_name) ? hp->h_name: "null", 247 (hp && hp->h_name) ? strlen(hp->h_name)+ 1 : 0); 248 } 249 250 bool failed = true; 251 if (hp) { 252 failed = mClient->sendBinaryMsg(ResponseCode::DnsProxyQueryResult, 253 hp->h_name ? hp->h_name : "", 254 hp->h_name ? strlen(hp->h_name)+ 1 : 0); 255 } else { 256 uint32_t error = h_errno; 257 failed = mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, 258 &error, sizeof(error)); 259 } 260 261 if (failed) { 262 ALOGW("GetHostByAddrHandler: Error writing DNS result to client\n"); 263 } 264 mClient->decRef(); 265} 266