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