1/* 2 * Copyright (C) 2009 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 <string.h> 20#include <errno.h> 21#include <sys/ioctl.h> 22#include <sys/types.h> 23#include <sys/socket.h> 24#include <netinet/in.h> 25#include <arpa/inet.h> 26#include <linux/route.h> 27 28#include <android/log.h> 29#include <cutils/properties.h> 30 31static inline struct in_addr *in_addr(struct sockaddr *sa) 32{ 33 return &((struct sockaddr_in *)sa)->sin_addr; 34} 35 36int main(int argc, char **argv) 37{ 38 struct rtentry route = { 39 .rt_dst = {.sa_family = AF_INET}, 40 .rt_genmask = {.sa_family = AF_INET}, 41 .rt_gateway = {.sa_family = AF_INET}, 42 .rt_flags = RTF_UP | RTF_GATEWAY, 43 }; 44 FILE *f; 45 int s; 46 47 errno = EINVAL; 48 if (argc > 5 && inet_aton(argv[5], in_addr(&route.rt_gateway)) && 49 (f = fopen("/proc/net/route", "r")) != NULL && 50 (s = socket(AF_INET, SOCK_DGRAM, 0)) != -1) { 51 uint32_t *address = &in_addr(&route.rt_dst)->s_addr; 52 uint32_t *netmask = &in_addr(&route.rt_genmask)->s_addr; 53 char device[64]; 54 55 fscanf(f, "%*[^\n]\n"); 56 while (fscanf(f, "%63s%X%*X%*X%*d%*u%*d%X%*d%*u%*u\n", 57 device, address, netmask) == 3) { 58 if (strcmp(argv[1], device)) { 59 uint32_t bit = ntohl(*netmask); 60 bit = htonl(bit ^ (1 << 31 | bit >> 1)); 61 if (bit) { 62 *netmask |= bit; 63 if (ioctl(s, SIOCADDRT, &route) == -1 && errno != EEXIST) { 64 break; 65 } 66 *address ^= bit; 67 if (ioctl(s, SIOCADDRT, &route) == -1 && errno != EEXIST) { 68 break; 69 } 70 errno = 0; 71 } 72 } 73 } 74 } 75 76 if (!errno) { 77 char *dns = getenv("DNS1"); 78 property_set("vpn.dns1", dns ? dns : ""); 79 dns = getenv("DNS2"); 80 property_set("vpn.dns2", dns ? dns : ""); 81 property_set("vpn.status", "ok"); 82 __android_log_print(ANDROID_LOG_INFO, "ip-up-vpn", 83 "All traffic is now redirected to %s", argv[5]); 84 } else { 85 property_set("vpn.status", "error"); 86 __android_log_write(ANDROID_LOG_ERROR, "ip-up-vpn", strerror(errno)); 87 } 88 return errno; 89} 90