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