DnsProxyListener.cpp revision 40e0c13d6b77a9260b6da4c9e11cca8a5f994ea2
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 mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, sizeof(rv)); 80 } else { 81 bool success = !mClient->sendCode(ResponseCode::DnsProxyQueryResult); 82 struct addrinfo* ai = result; 83 while (ai && success) { 84 success = sendLenAndData(mClient, sizeof(struct addrinfo), ai) 85 && sendLenAndData(mClient, ai->ai_addrlen, ai->ai_addr) 86 && sendLenAndData(mClient, 87 ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0, 88 ai->ai_canonname); 89 ai = ai->ai_next; 90 } 91 success = success && sendLenAndData(mClient, 0, ""); 92 if (!success) { 93 ALOGW("Error writing DNS result to client"); 94 } 95 } 96 if (result) { 97 freeaddrinfo(result); 98 } 99 mClient->decRef(); 100} 101 102DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd() : 103 NetdCommand("getaddrinfo") { 104} 105 106int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient *cli, 107 int argc, char **argv) { 108 if (DBG) { 109 for (int i = 0; i < argc; i++) { 110 ALOGD("argv[%i]=%s", i, argv[i]); 111 } 112 } 113 if (argc != 7) { 114 char* msg = NULL; 115 asprintf( &msg, "Invalid number of arguments to getaddrinfo: %i", argc); 116 ALOGW("%s", msg); 117 cli->sendMsg(ResponseCode::CommandParameterError, msg, false); 118 free(msg); 119 return -1; 120 } 121 122 char* name = argv[1]; 123 if (strcmp("^", name) == 0) { 124 name = NULL; 125 } else { 126 name = strdup(name); 127 } 128 129 char* service = argv[2]; 130 if (strcmp("^", service) == 0) { 131 service = NULL; 132 } else { 133 service = strdup(service); 134 } 135 136 struct addrinfo* hints = NULL; 137 int ai_flags = atoi(argv[3]); 138 int ai_family = atoi(argv[4]); 139 int ai_socktype = atoi(argv[5]); 140 int ai_protocol = atoi(argv[6]); 141 if (ai_flags != -1 || ai_family != -1 || 142 ai_socktype != -1 || ai_protocol != -1) { 143 hints = (struct addrinfo*) calloc(1, sizeof(struct addrinfo)); 144 hints->ai_flags = ai_flags; 145 hints->ai_family = ai_family; 146 hints->ai_socktype = ai_socktype; 147 hints->ai_protocol = ai_protocol; 148 } 149 150 if (DBG) { 151 ALOGD("GetAddrInfoHandler for %s / %s", 152 name ? name : "[nullhost]", 153 service ? service : "[nullservice]"); 154 } 155 156 cli->incRef(); 157 DnsProxyListener::GetAddrInfoHandler* handler = 158 new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints); 159 handler->start(); 160 161 return 0; 162} 163 164/******************************************************* 165 * GetHostByAddr * 166 *******************************************************/ 167DnsProxyListener::GetHostByAddrCmd::GetHostByAddrCmd() : 168 NetdCommand("gethostbyaddr") { 169} 170 171int DnsProxyListener::GetHostByAddrCmd::runCommand(SocketClient *cli, 172 int argc, char **argv) { 173 if (DBG) { 174 for (int i = 0; i < argc; i++) { 175 ALOGD("argv[%i]=%s", i, argv[i]); 176 } 177 } 178 179 if (argc != 4) { 180 char* msg = NULL; 181 asprintf(&msg, "Invalid number of arguments to gethostbyaddr: %i", argc); 182 ALOGW("%s", msg); 183 cli->sendMsg(ResponseCode::CommandParameterError, msg, false); 184 free(msg); 185 return -1; 186 } 187 188 char* addrStr = argv[1]; 189 int addrLen = atoi(argv[2]); 190 int addrFamily = atoi(argv[3]); 191 192 void* addr = malloc(sizeof(struct in6_addr)); 193 errno = 0; 194 int result = inet_pton(addrFamily, addrStr, addr); 195 if (result <= 0) { 196 char* msg = NULL; 197 asprintf(&msg, "inet_pton(\"%s\") failed %s", addrStr, strerror(errno)); 198 ALOGW("%s", msg); 199 cli->sendMsg(ResponseCode::OperationFailed, msg, false); 200 free(addr); 201 free(msg); 202 return -1; 203 } 204 205 cli->incRef(); 206 DnsProxyListener::GetHostByAddrHandler* handler = 207 new DnsProxyListener::GetHostByAddrHandler(cli, addr, addrLen, addrFamily); 208 handler->start(); 209 210 return 0; 211} 212 213DnsProxyListener::GetHostByAddrHandler::~GetHostByAddrHandler() { 214 free(mAddress); 215} 216 217void DnsProxyListener::GetHostByAddrHandler::start() { 218 pthread_create(&mThread, NULL, 219 DnsProxyListener::GetHostByAddrHandler::threadStart, this); 220} 221 222void* DnsProxyListener::GetHostByAddrHandler::threadStart(void* obj) { 223 GetHostByAddrHandler* handler = reinterpret_cast<GetHostByAddrHandler*>(obj); 224 handler->run(); 225 delete handler; 226 pthread_exit(NULL); 227 return NULL; 228} 229 230void DnsProxyListener::GetHostByAddrHandler::run() { 231 if (DBG) { 232 ALOGD("DnsProxyListener::GetHostByAddrHandler::run\n"); 233 } 234 235 struct hostent* hp; 236 237 // NOTE gethostbyaddr should take a void* but bionic thinks it should be char* 238 hp = gethostbyaddr((char*)mAddress, mAddressLen, mAddressFamily); 239 240 if (DBG) { 241 ALOGD("GetHostByAddrHandler::run gethostbyaddr errno: %s hp->h_name = %s, name_len = %d\n", 242 hp ? "success" : strerror(errno), 243 (hp && hp->h_name) ? hp->h_name: "null", 244 (hp && hp->h_name) ? strlen(hp->h_name)+ 1 : 0); 245 } 246 247 bool failed = true; 248 if (hp) { 249 failed = mClient->sendBinaryMsg(ResponseCode::DnsProxyQueryResult, 250 hp->h_name ? hp->h_name : "", 251 hp->h_name ? strlen(hp->h_name)+ 1 : 0); 252 } else { 253 uint32_t error = h_errno; 254 failed = mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, 255 &error, sizeof(error)); 256 } 257 258 if (failed) { 259 ALOGW("GetHostByAddrHandler: Error writing DNS result to client\n"); 260 } 261 mClient->decRef(); 262} 263