1 /* 2 * Copyright (C) 2011 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 <stdio.h> 18 #include <stdlib.h> 19 #include <stdarg.h> 20 #include <signal.h> 21 #include <poll.h> 22 #include <unistd.h> 23 24 #include "config.h" 25 #include "gcmalloc.h" 26 #include "schedule.h" 27 #include "plog.h" 28 29 #ifdef ANDROID_CHANGES 30 31 #include <openssl/engine.h> 32 33 #include <string.h> 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 #include <sys/ioctl.h> 37 #include <sys/stat.h> 38 #include <fcntl.h> 39 #include <errno.h> 40 #include <linux/if.h> 41 #include <linux/if_tun.h> 42 43 #include <android/log.h> 44 #include <cutils/sockets.h> 45 #include <private/android_filesystem_config.h> 46 47 static void notify_death() 48 { 49 creat("/data/misc/vpn/abort", 0); 50 } 51 52 static int android_get_control_and_arguments(int *argc, char ***argv) 53 { 54 static char *args[32]; 55 int control; 56 int i; 57 58 atexit(notify_death); 59 60 if ((i = android_get_control_socket("racoon")) == -1) { 61 return -1; 62 } 63 do_plog(LLV_DEBUG, "Waiting for control socket"); 64 if (listen(i, 1) == -1 || (control = accept(i, NULL, 0)) == -1) { 65 do_plog(LLV_ERROR, "Cannot get control socket"); 66 exit(1); 67 } 68 close(i); 69 fcntl(control, F_SETFD, FD_CLOEXEC); 70 71 args[0] = (*argv)[0]; 72 for (i = 1; i < 32; ++i) { 73 unsigned char bytes[2]; 74 if (recv(control, &bytes[0], 1, 0) != 1 || 75 recv(control, &bytes[1], 1, 0) != 1) { 76 do_plog(LLV_ERROR, "Cannot get argument length"); 77 exit(1); 78 } else { 79 int length = bytes[0] << 8 | bytes[1]; 80 int offset = 0; 81 82 if (length == 0xFFFF) { 83 break; 84 } 85 args[i] = malloc(length + 1); 86 while (offset < length) { 87 int n = recv(control, &args[i][offset], length - offset, 0); 88 if (n > 0) { 89 offset += n; 90 } else { 91 do_plog(LLV_ERROR, "Cannot get argument value"); 92 exit(1); 93 } 94 } 95 args[i][length] = 0; 96 } 97 } 98 do_plog(LLV_DEBUG, "Received %d arguments", i - 1); 99 100 *argc = i; 101 *argv = args; 102 return control; 103 } 104 105 const char *android_hook(char **envp) 106 { 107 struct ifreq ifr = {.ifr_flags = IFF_TUN}; 108 int tun = open("/dev/tun", 0); 109 110 /* Android does not support INTERNAL_WINS4_LIST, so we just use it. */ 111 while (*envp && strncmp(*envp, "INTERNAL_WINS4_LIST=", 20)) { 112 ++envp; 113 } 114 if (!*envp) { 115 do_plog(LLV_ERROR, "Cannot find environment variable\n"); 116 exit(1); 117 } 118 if (ioctl(tun, TUNSETIFF, &ifr)) { 119 do_plog(LLV_ERROR, "Cannot allocate TUN: %s\n", strerror(errno)); 120 exit(1); 121 } 122 sprintf(*envp, "INTERFACE=%s", ifr.ifr_name); 123 return "/etc/ppp/ip-up-vpn"; 124 } 125 126 #endif 127 128 extern void setup(int argc, char **argv); 129 130 static int monitors; 131 static void (*callbacks[10])(int fd); 132 static struct pollfd pollfds[10]; 133 134 char *pname; 135 136 static void terminate(int signal) 137 { 138 exit(1); 139 } 140 141 static void terminated() 142 { 143 do_plog(LLV_INFO, "Bye\n"); 144 } 145 146 void monitor_fd(int fd, void (*callback)(int)) 147 { 148 if (fd < 0 || monitors == 10) { 149 do_plog(LLV_ERROR, "Cannot monitor fd"); 150 exit(1); 151 } 152 callbacks[monitors] = callback; 153 pollfds[monitors].fd = fd; 154 pollfds[monitors].events = callback ? POLLIN : 0; 155 ++monitors; 156 } 157 158 int main(int argc, char **argv) 159 { 160 #ifdef ANDROID_CHANGES 161 int control = android_get_control_and_arguments(&argc, &argv); 162 ENGINE *e; 163 if (control != -1) { 164 pname = "%p"; 165 monitor_fd(control, NULL); 166 167 ENGINE_load_dynamic(); 168 e = ENGINE_by_id("keystore"); 169 if (!e || !ENGINE_init(e)) { 170 do_plog(LLV_ERROR, "ipsec-tools: cannot load keystore engine"); 171 exit(1); 172 } 173 } 174 #endif 175 176 do_plog(LLV_INFO, "ipsec-tools 0.7.3 (http://ipsec-tools.sf.net)\n"); 177 178 signal(SIGHUP, terminate); 179 signal(SIGINT, terminate); 180 signal(SIGTERM, terminate); 181 signal(SIGPIPE, SIG_IGN); 182 atexit(terminated); 183 184 setup(argc, argv); 185 186 #ifdef ANDROID_CHANGES 187 shutdown(control, SHUT_WR); 188 setuid(AID_VPN); 189 #endif 190 191 while (1) { 192 struct timeval *tv = schedular(); 193 int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000 + 1; 194 195 if (poll(pollfds, monitors, timeout) > 0) { 196 int i; 197 for (i = 0; i < monitors; ++i) { 198 if (pollfds[i].revents & POLLHUP) { 199 do_plog(LLV_INFO, "Connection is closed\n", pollfds[i].fd); 200 /* Wait for few seconds to consume late messages. */ 201 sleep(5); 202 exit(1); 203 } 204 if (pollfds[i].revents & POLLIN) { 205 callbacks[i](pollfds[i].fd); 206 } 207 } 208 } 209 } 210 #ifdef ANDROID_CHANGES 211 if (e) { 212 ENGINE_finish(e); 213 ENGINE_free(e); 214 } 215 #endif 216 return 0; 217 } 218 219 /* plog.h */ 220 221 void do_plog(int level, char *format, ...) 222 { 223 if (level >= 0 && level <= 5) { 224 #ifdef ANDROID_CHANGES 225 static int levels[6] = { 226 ANDROID_LOG_ERROR, ANDROID_LOG_WARN, ANDROID_LOG_INFO, 227 ANDROID_LOG_INFO, ANDROID_LOG_DEBUG, ANDROID_LOG_VERBOSE 228 }; 229 va_list ap; 230 va_start(ap, format); 231 __android_log_vprint(levels[level], "racoon", format, ap); 232 va_end(ap); 233 #else 234 static char *levels = "EWNIDV"; 235 fprintf(stderr, "%c: ", levels[level]); 236 va_list ap; 237 va_start(ap, format); 238 vfprintf(stderr, format, ap); 239 va_end(ap); 240 #endif 241 } 242 } 243 244 char *binsanitize(char *data, size_t length) 245 { 246 char *output = racoon_malloc(length + 1); 247 if (output) { 248 size_t i; 249 for (i = 0; i < length; ++i) { 250 output[i] = (data[i] < ' ' || data[i] > '~') ? '?' : data[i]; 251 } 252 output[length] = '\0'; 253 } 254 return output; 255 } 256