com_android_server_connectivity_Vpn.cpp revision 9c0835fd7262c50cf6a91380df1654daffe2c977
1ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh/*
2ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Copyright (C) 2011 The Android Open Source Project
3ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh *
4ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License");
5ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * you may not use this file except in compliance with the License.
6ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * You may obtain a copy of the License at
7ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh *
8ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh *      http://www.apache.org/licenses/LICENSE-2.0
9ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh *
10ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software
11ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS,
12ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * See the License for the specific language governing permissions and
14ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * limitations under the License.
15ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */
16ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
17ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#define LOG_NDEBUG 0
18ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
19ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#define LOG_TAG "VpnJni"
20ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <cutils/log.h>
21ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <cutils/properties.h>
22ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
23ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <stdio.h>
24ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <string.h>
25ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <sys/ioctl.h>
26ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <sys/types.h>
27ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <sys/stat.h>
28ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <sys/socket.h>
29ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <netinet/in.h>
30ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <arpa/inet.h>
31ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <errno.h>
32ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <fcntl.h>
33ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
34ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <linux/if.h>
35ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <linux/if_tun.h>
36ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <linux/route.h>
37ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include <linux/ipv6_route.h>
38ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
39ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include "jni.h"
40ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#include "JNIHelp.h"
41ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
42ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehnamespace android
43ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
44ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
45f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic int inet4 = -1;
46f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic int inet6 = -1;
47f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh
48ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehstatic inline in_addr_t *as_in_addr(sockaddr *sa) {
49ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return &((sockaddr_in *)sa)->sin_addr.s_addr;
50ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
51ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
52ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh//------------------------------------------------------------------------------
53ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
54ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#define SYSTEM_ERROR -1
55ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh#define BAD_ARGUMENT -2
56ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
57f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic int create_interface(int mtu)
58ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
59f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    int tun = open("/dev/tun", O_RDWR | O_NONBLOCK);
60ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
61ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    ifreq ifr4;
62ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    memset(&ifr4, 0, sizeof(ifr4));
63ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
64ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    // Allocate interface.
656224b5ec3857d78e92bbc21075717eaa228ff891Chia-chi Yeh    ifr4.ifr_flags = IFF_TUN | IFF_NO_PI;
66ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (ioctl(tun, TUNSETIFF, &ifr4)) {
67ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        LOGE("Cannot allocate TUN: %s", strerror(errno));
68ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        goto error;
69ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
70ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
71ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    // Activate interface.
72ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    ifr4.ifr_flags = IFF_UP;
73ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (ioctl(inet4, SIOCSIFFLAGS, &ifr4)) {
74ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        LOGE("Cannot activate %s: %s", ifr4.ifr_name, strerror(errno));
75ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        goto error;
76ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
77ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
783663227a8be5c6c05bf4adadc378fd69b7ae814cChia-chi Yeh    // Set MTU if it is specified.
793663227a8be5c6c05bf4adadc378fd69b7ae814cChia-chi Yeh    ifr4.ifr_mtu = mtu;
803663227a8be5c6c05bf4adadc378fd69b7ae814cChia-chi Yeh    if (mtu > 0 && ioctl(inet4, SIOCSIFMTU, &ifr4)) {
813663227a8be5c6c05bf4adadc378fd69b7ae814cChia-chi Yeh        LOGE("Cannot set MTU on %s: %s", ifr4.ifr_name, strerror(errno));
823663227a8be5c6c05bf4adadc378fd69b7ae814cChia-chi Yeh        goto error;
833663227a8be5c6c05bf4adadc378fd69b7ae814cChia-chi Yeh    }
843663227a8be5c6c05bf4adadc378fd69b7ae814cChia-chi Yeh
85ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return tun;
86ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
87ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeherror:
88ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    close(tun);
89ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return SYSTEM_ERROR;
90ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
91ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
92f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic int get_interface_name(char *name, int tun)
93f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh{
94f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    ifreq ifr4;
95f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (ioctl(tun, TUNGETIFF, &ifr4)) {
96f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        LOGE("Cannot get interface name: %s", strerror(errno));
97f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        return SYSTEM_ERROR;
98f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
99f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    strncpy(name, ifr4.ifr_name, IFNAMSIZ);
100f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    return 0;
101f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh}
102f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh
103f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic int get_interface_index(const char *name)
104f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh{
105f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    ifreq ifr4;
106f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
107f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
108f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        LOGE("Cannot get index of %s: %s", name, strerror(errno));
109f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        return SYSTEM_ERROR;
110f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
111f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    return ifr4.ifr_ifindex;
112f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh}
113f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh
114f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic int set_addresses(const char *name, const char *addresses)
115ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
116f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    int index = get_interface_index(name);
117f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (index < 0) {
118f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        return index;
119f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
120ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
121ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    ifreq ifr4;
122ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    memset(&ifr4, 0, sizeof(ifr4));
123f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
12436673698078cb47e777418cadc4115a65bc5947dChia-chi Yeh    ifr4.ifr_addr.sa_family = AF_INET;
125ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
126ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    in6_ifreq ifr6;
127ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    memset(&ifr6, 0, sizeof(ifr6));
128ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    ifr6.ifr6_ifindex = index;
129ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
130ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    char address[65];
131ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int prefix;
132ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int chars;
133ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int count = 0;
134ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
135ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    while (sscanf(addresses, " %64[^/]/%d %n", address, &prefix, &chars) == 2) {
136ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        addresses += chars;
137ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
138ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        if (strchr(address, ':')) {
139ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            // Add an IPv6 address.
140ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            if (inet_pton(AF_INET6, address, &ifr6.ifr6_addr) != 1 ||
141ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                    prefix < 0 || prefix > 128) {
142ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = BAD_ARGUMENT;
143ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
144ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
145ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
146ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            ifr6.ifr6_prefixlen = prefix;
147ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            if (ioctl(inet6, SIOCSIFADDR, &ifr6)) {
148ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
149ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
150ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
151ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        } else {
152ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            // Add an IPv4 address.
153ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            if (inet_pton(AF_INET, address, as_in_addr(&ifr4.ifr_addr)) != 1 ||
154ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                    prefix < 0 || prefix > 32) {
155ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = BAD_ARGUMENT;
156ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
157ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
158ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
159ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            if (count) {
160ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                sprintf(ifr4.ifr_name, "%s:%d", name, count);
161ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
162ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            if (ioctl(inet4, SIOCSIFADDR, &ifr4)) {
163ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
164ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
165ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
166ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
167ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0;
168ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            *as_in_addr(&ifr4.ifr_addr) = htonl(mask);
169ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) {
170ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
171ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
172ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
173ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        }
174f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        LOGD("Address added on %s: %s/%d", name, address, prefix);
175ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        ++count;
176ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
177ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
178ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (count == BAD_ARGUMENT) {
179ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        LOGE("Invalid address: %s/%d", address, prefix);
180ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    } else if (count == SYSTEM_ERROR) {
181ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        LOGE("Cannot add address: %s/%d: %s", address, prefix, strerror(errno));
182ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    } else if (*addresses) {
183ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        LOGE("Invalid address: %s", addresses);
184ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        count = BAD_ARGUMENT;
185ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
186ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
187ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return count;
188ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
189ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
190f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic int set_routes(const char *name, const char *routes)
191ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
192f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    int index = get_interface_index(name);
193f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (index < 0) {
194f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        return index;
195f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
196ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
197ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    rtentry rt4;
198ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    memset(&rt4, 0, sizeof(rt4));
199ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    rt4.rt_dev = (char *)name;
200ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    rt4.rt_flags = RTF_UP;
20136673698078cb47e777418cadc4115a65bc5947dChia-chi Yeh    rt4.rt_dst.sa_family = AF_INET;
20236673698078cb47e777418cadc4115a65bc5947dChia-chi Yeh    rt4.rt_genmask.sa_family = AF_INET;
203ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
204ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    in6_rtmsg rt6;
205ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    memset(&rt6, 0, sizeof(rt6));
206ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    rt6.rtmsg_ifindex = index;
207ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    rt6.rtmsg_flags = RTF_UP;
208ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
209ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    char address[65];
210ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int prefix;
211ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int chars;
212ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int count = 0;
213ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
2148ea928945b6a594e7e569613742367a91f01e785Chia-chi Yeh    while (sscanf(routes, " %64[^/]/%d %n", address, &prefix, &chars) == 2) {
215ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        routes += chars;
216ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
217ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        if (strchr(address, ':')) {
218ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            // Add an IPv6 route.
2198ea928945b6a594e7e569613742367a91f01e785Chia-chi Yeh            if (inet_pton(AF_INET6, address, &rt6.rtmsg_dst) != 1 ||
220f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                    prefix < 0 || prefix > 128) {
221ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = BAD_ARGUMENT;
222ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
223ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
224ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
225f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh            rt6.rtmsg_dst_len = prefix ? prefix : 1;
22623a5e4bcdcf7d3fef9aaa6c4a20f9f08f22ca9a6Chia-chi Yeh            if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
227ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
228ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
229ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
230f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh
231f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh            if (!prefix) {
232f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                // Split the route instead of replacing the default route.
233f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                rt6.rtmsg_dst.s6_addr[0] ^= 0x80;
234f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
235f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                    count = SYSTEM_ERROR;
236f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                    break;
237f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                }
238f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh            }
239ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        } else {
240ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            // Add an IPv4 route.
2418ea928945b6a594e7e569613742367a91f01e785Chia-chi Yeh            if (inet_pton(AF_INET, address, as_in_addr(&rt4.rt_dst)) != 1 ||
242f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                    prefix < 0 || prefix > 32) {
243ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = BAD_ARGUMENT;
244ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
245ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
246ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
2479c0835fd7262c50cf6a91380df1654daffe2c977Chia-chi Yeh            in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0x80000000;
248ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            *as_in_addr(&rt4.rt_genmask) = htonl(mask);
24923a5e4bcdcf7d3fef9aaa6c4a20f9f08f22ca9a6Chia-chi Yeh            if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
250ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
251ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh                break;
252ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            }
253f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh
254f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh            if (!prefix) {
255f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                // Split the route instead of replacing the default route.
256f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                *as_in_addr(&rt4.rt_dst) ^= htonl(0x80000000);
257f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
258f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                    count = SYSTEM_ERROR;
259f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                    break;
260f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh                }
261f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh            }
262ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        }
263f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        LOGD("Route added on %s: %s/%d", name, address, prefix);
264ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        ++count;
265ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
266ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
267ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (count == BAD_ARGUMENT) {
2688ea928945b6a594e7e569613742367a91f01e785Chia-chi Yeh        LOGE("Invalid route: %s/%d", address, prefix);
269ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    } else if (count == SYSTEM_ERROR) {
2708ea928945b6a594e7e569613742367a91f01e785Chia-chi Yeh        LOGE("Cannot add route: %s/%d: %s",
2718ea928945b6a594e7e569613742367a91f01e785Chia-chi Yeh                address, prefix, strerror(errno));
272ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    } else if (*routes) {
273ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        LOGE("Invalid route: %s", routes);
274ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        count = BAD_ARGUMENT;
275ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
276ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
277ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return count;
278ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
279ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
280ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehstatic int reset_interface(const char *name)
281ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
282ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    ifreq ifr4;
283ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
284f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    ifr4.ifr_flags = 0;
285ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
286ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (ioctl(inet4, SIOCSIFFLAGS, &ifr4) && errno != ENODEV) {
287ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        LOGE("Cannot reset %s: %s", name, strerror(errno));
288ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        return SYSTEM_ERROR;
289ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
290ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return 0;
291ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
292ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
293ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehstatic int check_interface(const char *name)
294ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
295ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    ifreq ifr4;
296ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
2976ddd57491a06da3ee56056b088424500c144063aChia-chi Yeh    ifr4.ifr_flags = 0;
298ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
299ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) {
300ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        LOGE("Cannot check %s: %s", name, strerror(errno));
301ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
302ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return ifr4.ifr_flags;
303ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
304ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
305ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehstatic int bind_to_interface(int fd, const char *name)
306ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
307ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name))) {
308ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        LOGE("Cannot bind socket to %s: %s", name, strerror(errno));
309ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        return SYSTEM_ERROR;
310ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
311ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return 0;
312ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
313ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
314ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh//------------------------------------------------------------------------------
315ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
316ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehstatic void throwException(JNIEnv *env, int error, const char *message)
317ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
318ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (error == SYSTEM_ERROR) {
319ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalStateException", message);
320ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    } else {
321ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        jniThrowException(env, "java/lang/IllegalArgumentException", message);
322ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
323ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
324ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
325f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic jint createInterface(JNIEnv *env, jobject thiz, jint mtu)
326ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
327f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    int tun = create_interface(mtu);
328ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (tun < 0) {
329ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        throwException(env, tun, "Cannot create interface");
33036673698078cb47e777418cadc4115a65bc5947dChia-chi Yeh        return -1;
331ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
332f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    return tun;
333f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh}
334ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
335f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic jstring getInterfaceName(JNIEnv *env, jobject thiz, jint tun)
336f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh{
337f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    char name[IFNAMSIZ];
338f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (get_interface_name(name, tun) < 0) {
339f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        throwException(env, SYSTEM_ERROR, "Cannot get interface name");
340f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        return NULL;
341f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
342f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    return env->NewStringUTF(name);
343f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh}
344ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
345f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic jint setAddresses(JNIEnv *env, jobject thiz, jstring jName,
346f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        jstring jAddresses)
347f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh{
348f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    const char *name = NULL;
349f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    const char *addresses = NULL;
350f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    int count = -1;
351f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh
352f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
353f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (!name) {
354f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        jniThrowNullPointerException(env, "name");
355f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        goto error;
356f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
357ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
358ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (!addresses) {
359f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        jniThrowNullPointerException(env, "addresses");
360ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        goto error;
361ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
362f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    count = set_addresses(name, addresses);
363f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (count < 0) {
364ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        throwException(env, count, "Cannot set address");
365f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        count = -1;
366ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
367ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
368ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeherror:
369f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (name) {
370f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        env->ReleaseStringUTFChars(jName, name);
371f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
372f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (addresses) {
373f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        env->ReleaseStringUTFChars(jAddresses, addresses);
374f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
375f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    return count;
376ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
377ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
378f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic jint setRoutes(JNIEnv *env, jobject thiz, jstring jName,
379f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        jstring jRoutes)
380ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
381f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    const char *name = NULL;
382f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    const char *routes = NULL;
383f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    int count = -1;
384f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh
385f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
386f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (!name) {
387f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        jniThrowNullPointerException(env, "name");
388f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        goto error;
389ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
390f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
391f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (!routes) {
392f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        jniThrowNullPointerException(env, "routes");
393f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        goto error;
394f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
395f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    count = set_routes(name, routes);
396f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (count < 0) {
3979c0835fd7262c50cf6a91380df1654daffe2c977Chia-chi Yeh        throwException(env, count, "Cannot set route");
398f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        count = -1;
399f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
400f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh
401f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeherror:
402f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (name) {
403f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        env->ReleaseStringUTFChars(jName, name);
404f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
405f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (routes) {
406f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        env->ReleaseStringUTFChars(jRoutes, routes);
407f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
408f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    return count;
409ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
410ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
411f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic void resetInterface(JNIEnv *env, jobject thiz, jstring jName)
412ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
413f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
414ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (!name) {
415ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        jniThrowNullPointerException(env, "name");
416ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        return;
417ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
418ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (reset_interface(name) < 0) {
419ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        throwException(env, SYSTEM_ERROR, "Cannot reset interface");
420ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
421ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    env->ReleaseStringUTFChars(jName, name);
422ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
423ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
424f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic jint checkInterface(JNIEnv *env, jobject thiz, jstring jName)
425ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
426f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
427ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (!name) {
428ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        jniThrowNullPointerException(env, "name");
429ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        return 0;
430ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
431ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    int flags = check_interface(name);
432ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    env->ReleaseStringUTFChars(jName, name);
433ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return flags;
434ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
435ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
436f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yehstatic void protectSocket(JNIEnv *env, jobject thiz, jint fd, jstring jName)
437ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
438f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
439ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (!name) {
440ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        jniThrowNullPointerException(env, "name");
441ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        return;
442ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
443ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    if (bind_to_interface(fd, name) < 0) {
444ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh        throwException(env, SYSTEM_ERROR, "Cannot protect socket");
445ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    }
446ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    env->ReleaseStringUTFChars(jName, name);
447ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
448ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
449ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh//------------------------------------------------------------------------------
450ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
451ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehstatic JNINativeMethod gMethods[] = {
452f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    {"jniCreateInterface", "(I)I", (void *)createInterface},
453f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    {"jniGetInterfaceName", "(I)Ljava/lang/String;", (void *)getInterfaceName},
454f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
455f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    {"jniSetRoutes", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setRoutes},
456f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    {"jniResetInterface", "(Ljava/lang/String;)V", (void *)resetInterface},
457f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    {"jniCheckInterface", "(Ljava/lang/String;)I", (void *)checkInterface},
458f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    {"jniProtectSocket", "(ILjava/lang/String;)V", (void *)protectSocket},
459ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh};
460ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
461ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehint register_android_server_connectivity_Vpn(JNIEnv *env)
462ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh{
463f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (inet4 == -1) {
464f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        inet4 = socket(AF_INET, SOCK_DGRAM, 0);
465f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
466f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    if (inet6 == -1) {
467f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh        inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
468f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh    }
469ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh    return jniRegisterNativeMethods(env, "com/android/server/connectivity/Vpn",
470ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh            gMethods, NELEM(gMethods));
471ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh}
472ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh
473ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh};
474