blob: cfb2dd199f3989051fb8531b981b4848af40bba5 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright 2008, The Android Open Source Project
3 *
Elliott Hughesdd66bcb2011-04-12 11:28:59 -07004 * 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007 *
Elliott Hughesdd66bcb2011-04-12 11:28:59 -07008 * http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009 *
Elliott Hughesdd66bcb2011-04-12 11:28:59 -070010 * 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014 * limitations under the License.
15 */
16
17#define LOG_TAG "NetUtils"
18
Luke Huang92ae35e2019-01-04 19:46:47 +080019#include <vector>
20
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021#include "jni.h"
Steven Moreland2279b252017-07-19 09:50:45 -070022#include <nativehelper/JNIHelp.h>
Luke Huang92ae35e2019-01-04 19:46:47 +080023#include <nativehelper/ScopedLocalRef.h>
Paul Jensen38764952014-05-20 11:25:35 -040024#include "NetdClient.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025#include <utils/misc.h>
26#include <android_runtime/AndroidRuntime.h>
27#include <utils/Log.h>
28#include <arpa/inet.h>
Lorenzo Colitticbe4f7c2015-03-06 19:57:39 +090029#include <net/if.h>
30#include <linux/filter.h>
Paul Jensen578a76e2016-01-14 14:54:39 -050031#include <linux/if_arp.h>
markchien150e1912018-12-27 22:49:51 +080032#include <linux/tcp.h>
Elliott Hughes7691b782016-05-11 15:18:13 -070033#include <netinet/ether.h>
Paul Jensen578a76e2016-01-14 14:54:39 -050034#include <netinet/icmp6.h>
Lorenzo Colitticbe4f7c2015-03-06 19:57:39 +090035#include <netinet/ip.h>
Paul Jensen578a76e2016-01-14 14:54:39 -050036#include <netinet/ip6.h>
Lorenzo Colitticbe4f7c2015-03-06 19:57:39 +090037#include <netinet/udp.h>
Robert Greenwalt0216e612011-01-14 16:29:58 -080038#include <cutils/properties.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039
Andreas Gampe987f79f2014-11-18 17:29:46 -080040#include "core_jni_helpers.h"
41
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042extern "C" {
Mike Lockwood0900f362009-07-10 17:24:07 -040043int ifc_enable(const char *ifname);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044int ifc_disable(const char *ifname);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045}
46
47#define NETUTILS_PKG_NAME "android/net/NetworkUtils"
48
49namespace android {
50
Erik Kline473355f2016-10-19 17:42:01 +090051static const uint32_t kEtherTypeOffset = offsetof(ether_header, ether_type);
52static const uint32_t kEtherHeaderLen = sizeof(ether_header);
53static const uint32_t kIPv4Protocol = kEtherHeaderLen + offsetof(iphdr, protocol);
54static const uint32_t kIPv4FlagsOffset = kEtherHeaderLen + offsetof(iphdr, frag_off);
55static const uint32_t kIPv6NextHeader = kEtherHeaderLen + offsetof(ip6_hdr, ip6_nxt);
56static const uint32_t kIPv6PayloadStart = kEtherHeaderLen + sizeof(ip6_hdr);
57static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type);
58static const uint32_t kUDPSrcPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, source);
59static const uint32_t kUDPDstPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, dest);
Lorenzo Colitticbe4f7c2015-03-06 19:57:39 +090060static const uint16_t kDhcpClientPort = 68;
61
Luke Huang92ae35e2019-01-04 19:46:47 +080062constexpr int MAXPACKETSIZE = 8 * 1024;
63// FrameworkListener limits the size of commands to 1024 bytes. TODO: fix this.
64constexpr int MAXCMDSIZE = 1024;
65
66static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
67 ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
68 if (detailMessage.get() == NULL) {
69 // Not really much we can do here. We're probably dead in the water,
70 // but let's try to stumble on...
71 env->ExceptionClear();
72 }
73 static jclass errnoExceptionClass =
74 MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/system/ErrnoException"));
75
76 static jmethodID errnoExceptionCtor =
77 GetMethodIDOrDie(env, errnoExceptionClass,
78 "<init>", "(Ljava/lang/String;I)V");
79
80 jobject exception = env->NewObject(errnoExceptionClass,
81 errnoExceptionCtor,
82 detailMessage.get(),
83 error);
84 env->Throw(reinterpret_cast<jthrowable>(exception));
85}
86
Lorenzo Colitticbe4f7c2015-03-06 19:57:39 +090087static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
88{
Lorenzo Colitticbe4f7c2015-03-06 19:57:39 +090089 struct sock_filter filter_code[] = {
90 // Check the protocol is UDP.
Erik Kline473355f2016-10-19 17:42:01 +090091 BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv4Protocol),
Lorenzo Colitticbe4f7c2015-03-06 19:57:39 +090092 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 6),
93
94 // Check this is not a fragment.
Erik Kline473355f2016-10-19 17:42:01 +090095 BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kIPv4FlagsOffset),
96 BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, IP_OFFMASK, 4, 0),
Lorenzo Colitticbe4f7c2015-03-06 19:57:39 +090097
98 // Get the IP header length.
Erik Kline473355f2016-10-19 17:42:01 +090099 BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, kEtherHeaderLen),
Lorenzo Colitticbe4f7c2015-03-06 19:57:39 +0900100
101 // Check the destination port.
Erik Kline473355f2016-10-19 17:42:01 +0900102 BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPDstPortIndirectOffset),
Lorenzo Colitticbe4f7c2015-03-06 19:57:39 +0900103 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 0, 1),
104
105 // Accept or reject.
106 BPF_STMT(BPF_RET | BPF_K, 0xffff),
107 BPF_STMT(BPF_RET | BPF_K, 0)
108 };
109 struct sock_fprog filter = {
110 sizeof(filter_code) / sizeof(filter_code[0]),
111 filter_code,
112 };
113
Paul Jensen578a76e2016-01-14 14:54:39 -0500114 int fd = jniGetFDFromFileDescriptor(env, javaFd);
115 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
116 jniThrowExceptionFmt(env, "java/net/SocketException",
117 "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
118 }
119}
120
121static void android_net_utils_attachRaFilter(JNIEnv *env, jobject clazz, jobject javaFd,
122 jint hardwareAddressType)
123{
124 if (hardwareAddressType != ARPHRD_ETHER) {
125 jniThrowExceptionFmt(env, "java/net/SocketException",
126 "attachRaFilter only supports ARPHRD_ETHER");
127 return;
128 }
129
Paul Jensen578a76e2016-01-14 14:54:39 -0500130 struct sock_filter filter_code[] = {
131 // Check IPv6 Next Header is ICMPv6.
Erik Kline473355f2016-10-19 17:42:01 +0900132 BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeader),
Paul Jensen578a76e2016-01-14 14:54:39 -0500133 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
134
135 // Check ICMPv6 type is Router Advertisement.
Erik Kline473355f2016-10-19 17:42:01 +0900136 BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset),
Paul Jensen578a76e2016-01-14 14:54:39 -0500137 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_ROUTER_ADVERT, 0, 1),
138
139 // Accept or reject.
140 BPF_STMT(BPF_RET | BPF_K, 0xffff),
141 BPF_STMT(BPF_RET | BPF_K, 0)
142 };
143 struct sock_fprog filter = {
144 sizeof(filter_code) / sizeof(filter_code[0]),
145 filter_code,
146 };
147
148 int fd = jniGetFDFromFileDescriptor(env, javaFd);
Lorenzo Colitticbe4f7c2015-03-06 19:57:39 +0900149 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
150 jniThrowExceptionFmt(env, "java/net/SocketException",
151 "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
152 }
153}
154
Erik Kline473355f2016-10-19 17:42:01 +0900155// TODO: Move all this filter code into libnetutils.
156static void android_net_utils_attachControlPacketFilter(
157 JNIEnv *env, jobject clazz, jobject javaFd, jint hardwareAddressType) {
158 if (hardwareAddressType != ARPHRD_ETHER) {
159 jniThrowExceptionFmt(env, "java/net/SocketException",
160 "attachControlPacketFilter only supports ARPHRD_ETHER");
161 return;
162 }
163
164 // Capture all:
165 // - ARPs
166 // - DHCPv4 packets
167 // - Router Advertisements & Solicitations
168 // - Neighbor Advertisements & Solicitations
169 //
170 // tcpdump:
171 // arp or
172 // '(ip and udp port 68)' or
173 // '(icmp6 and ip6[40] >= 133 and ip6[40] <= 136)'
174 struct sock_filter filter_code[] = {
175 // Load the link layer next payload field.
176 BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kEtherTypeOffset),
177
178 // Accept all ARP.
179 // TODO: Figure out how to better filter ARPs on noisy networks.
180 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_ARP, 16, 0),
181
182 // If IPv4:
183 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IP, 0, 9),
184
185 // Check the protocol is UDP.
186 BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv4Protocol),
187 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 14),
188
189 // Check this is not a fragment.
190 BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kIPv4FlagsOffset),
191 BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, IP_OFFMASK, 12, 0),
192
193 // Get the IP header length.
194 BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, kEtherHeaderLen),
195
196 // Check the source port.
197 BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPSrcPortIndirectOffset),
198 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 8, 0),
199
200 // Check the destination port.
201 BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPDstPortIndirectOffset),
202 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 6, 7),
203
204 // IPv6 ...
205 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IPV6, 0, 6),
206 // ... check IPv6 Next Header is ICMPv6 (ignore fragments), ...
207 BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeader),
208 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 4),
209 // ... and check the ICMPv6 type is one of RS/RA/NS/NA.
210 BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset),
211 BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, ND_ROUTER_SOLICIT, 0, 2),
212 BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, ND_NEIGHBOR_ADVERT, 1, 0),
213
214 // Accept or reject.
215 BPF_STMT(BPF_RET | BPF_K, 0xffff),
216 BPF_STMT(BPF_RET | BPF_K, 0)
217 };
218 struct sock_fprog filter = {
219 sizeof(filter_code) / sizeof(filter_code[0]),
220 filter_code,
221 };
222
223 int fd = jniGetFDFromFileDescriptor(env, javaFd);
224 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
225 jniThrowExceptionFmt(env, "java/net/SocketException",
226 "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
227 }
228}
229
markchien150e1912018-12-27 22:49:51 +0800230static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
231{
232 struct sock_filter filter_code[] = {
233 // Reject all.
234 BPF_STMT(BPF_RET | BPF_K, 0)
235 };
236 struct sock_fprog filter = {
237 sizeof(filter_code) / sizeof(filter_code[0]),
238 filter_code,
239 };
240
241 int fd = jniGetFDFromFileDescriptor(env, javaFd);
242 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
243 jniThrowExceptionFmt(env, "java/net/SocketException",
244 "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
245 }
246}
247
248static void android_net_utils_detachBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
249{
250 int dummy = 0;
251 int fd = jniGetFDFromFileDescriptor(env, javaFd);
252 if (setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, &dummy, sizeof(dummy)) != 0) {
253 jniThrowExceptionFmt(env, "java/net/SocketException",
254 "setsockopt(SO_DETACH_FILTER): %s", strerror(errno));
255 }
256
257}
Erik Klinea3ca6bd2016-05-24 20:12:08 +0900258static void android_net_utils_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd,
259 jint ifIndex)
260{
261 static const int kLinkLocalHopLimit = 255;
262
263 int fd = jniGetFDFromFileDescriptor(env, javaFd);
264
265 // Set an ICMPv6 filter that only passes Router Solicitations.
266 struct icmp6_filter rs_only;
267 ICMP6_FILTER_SETBLOCKALL(&rs_only);
268 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &rs_only);
269 socklen_t len = sizeof(rs_only);
270 if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &rs_only, len) != 0) {
271 jniThrowExceptionFmt(env, "java/net/SocketException",
272 "setsockopt(ICMP6_FILTER): %s", strerror(errno));
273 return;
274 }
275
276 // Most/all of the rest of these options can be set via Java code, but
277 // because we're here on account of setting an icmp6_filter go ahead
278 // and do it all natively for now.
279 //
280 // TODO: Consider moving these out to Java.
281
282 // Set the multicast hoplimit to 255 (link-local only).
283 int hops = kLinkLocalHopLimit;
284 len = sizeof(hops);
285 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, len) != 0) {
286 jniThrowExceptionFmt(env, "java/net/SocketException",
287 "setsockopt(IPV6_MULTICAST_HOPS): %s", strerror(errno));
288 return;
289 }
290
291 // Set the unicast hoplimit to 255 (link-local only).
292 hops = kLinkLocalHopLimit;
293 len = sizeof(hops);
294 if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, len) != 0) {
295 jniThrowExceptionFmt(env, "java/net/SocketException",
296 "setsockopt(IPV6_UNICAST_HOPS): %s", strerror(errno));
297 return;
298 }
299
300 // Explicitly disable multicast loopback.
301 int off = 0;
302 len = sizeof(off);
303 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, len) != 0) {
304 jniThrowExceptionFmt(env, "java/net/SocketException",
305 "setsockopt(IPV6_MULTICAST_LOOP): %s", strerror(errno));
306 return;
307 }
308
309 // Specify the IPv6 interface to use for outbound multicast.
310 len = sizeof(ifIndex);
311 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifIndex, len) != 0) {
312 jniThrowExceptionFmt(env, "java/net/SocketException",
313 "setsockopt(IPV6_MULTICAST_IF): %s", strerror(errno));
314 return;
315 }
316
317 // Additional options to be considered:
318 // - IPV6_TCLASS
319 // - IPV6_RECVPKTINFO
320 // - IPV6_RECVHOPLIMIT
321
322 // Bind to [::].
323 const struct sockaddr_in6 sin6 = {
324 .sin6_family = AF_INET6,
325 .sin6_port = 0,
326 .sin6_flowinfo = 0,
327 .sin6_addr = IN6ADDR_ANY_INIT,
328 .sin6_scope_id = 0,
329 };
330 auto sa = reinterpret_cast<const struct sockaddr *>(&sin6);
331 len = sizeof(sin6);
332 if (bind(fd, sa, len) != 0) {
333 jniThrowExceptionFmt(env, "java/net/SocketException",
334 "bind(IN6ADDR_ANY): %s", strerror(errno));
335 return;
336 }
337
338 // Join the all-routers multicast group, ff02::2%index.
339 struct ipv6_mreq all_rtrs = {
340 .ipv6mr_multiaddr = {{{0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2}}},
341 .ipv6mr_interface = ifIndex,
342 };
343 len = sizeof(all_rtrs);
344 if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &all_rtrs, len) != 0) {
345 jniThrowExceptionFmt(env, "java/net/SocketException",
346 "setsockopt(IPV6_JOIN_GROUP): %s", strerror(errno));
347 return;
348 }
349}
350
Paul Jensen32a58f02014-06-20 13:58:14 -0400351static jboolean android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId)
Paul Jensen38764952014-05-20 11:25:35 -0400352{
Paul Jensen32a58f02014-06-20 13:58:14 -0400353 return (jboolean) !setNetworkForProcess(netId);
Paul Jensen38764952014-05-20 11:25:35 -0400354}
355
Paul Jensen72db88e2015-03-10 10:54:12 -0400356static jint android_net_utils_getBoundNetworkForProcess(JNIEnv *env, jobject thiz)
Paul Jensen38764952014-05-20 11:25:35 -0400357{
358 return getNetworkForProcess();
359}
360
Paul Jensen32a58f02014-06-20 13:58:14 -0400361static jboolean android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz,
362 jint netId)
Paul Jensen38764952014-05-20 11:25:35 -0400363{
Paul Jensen32a58f02014-06-20 13:58:14 -0400364 return (jboolean) !setNetworkForResolv(netId);
Paul Jensen38764952014-05-20 11:25:35 -0400365}
366
Lorenzo Colitti9f1274b2014-08-21 11:45:54 -0700367static jint android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jint socket,
Paul Jensen32a58f02014-06-20 13:58:14 -0400368 jint netId)
Paul Jensen38764952014-05-20 11:25:35 -0400369{
Lorenzo Colitti9f1274b2014-08-21 11:45:54 -0700370 return setNetworkForSocket(netId, socket);
Paul Jensen38764952014-05-20 11:25:35 -0400371}
372
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400373static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket)
374{
375 return (jboolean) !protectFromVpn(socket);
376}
377
Paul Jensencee9b512015-05-06 07:32:40 -0400378static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId)
379{
380 return (jboolean) !queryUserAccess(uid, netId);
381}
382
Remi NGUYEN VAN12da4a52018-07-04 11:15:56 +0900383static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* dst)
384{
385 if (env->GetArrayLength(addr) != len) {
386 return false;
387 }
388 env->GetByteArrayRegion(addr, 0, len, reinterpret_cast<jbyte*>(dst));
389 return true;
390}
391
392static void android_net_utils_addArpEntry(JNIEnv *env, jobject thiz, jbyteArray ethAddr,
393 jbyteArray ipv4Addr, jstring ifname, jobject javaFd)
394{
395 struct arpreq req = {};
396 struct sockaddr_in& netAddrStruct = *reinterpret_cast<sockaddr_in*>(&req.arp_pa);
397 struct sockaddr& ethAddrStruct = req.arp_ha;
398
399 ethAddrStruct.sa_family = ARPHRD_ETHER;
400 if (!checkLenAndCopy(env, ethAddr, ETH_ALEN, ethAddrStruct.sa_data)) {
401 jniThrowException(env, "java/io/IOException", "Invalid ethAddr length");
402 return;
403 }
404
405 netAddrStruct.sin_family = AF_INET;
406 if (!checkLenAndCopy(env, ipv4Addr, sizeof(in_addr), &netAddrStruct.sin_addr)) {
407 jniThrowException(env, "java/io/IOException", "Invalid ipv4Addr length");
408 return;
409 }
410
411 int ifLen = env->GetStringLength(ifname);
412 // IFNAMSIZ includes the terminating NULL character
413 if (ifLen >= IFNAMSIZ) {
414 jniThrowException(env, "java/io/IOException", "ifname too long");
415 return;
416 }
417 env->GetStringUTFRegion(ifname, 0, ifLen, req.arp_dev);
418
419 req.arp_flags = ATF_COM; // Completed entry (ha valid)
420 int fd = jniGetFDFromFileDescriptor(env, javaFd);
421 if (fd < 0) {
422 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor");
423 return;
424 }
425 // See also: man 7 arp
426 if (ioctl(fd, SIOCSARP, &req)) {
427 jniThrowExceptionFmt(env, "java/io/IOException", "ioctl error: %s", strerror(errno));
428 return;
429 }
430}
431
Luke Huang92ae35e2019-01-04 19:46:47 +0800432static jobject android_net_utils_resNetworkQuery(JNIEnv *env, jobject thiz, jint netId,
433 jstring dname, jint ns_class, jint ns_type, jint flags) {
434 const jsize javaCharsCount = env->GetStringLength(dname);
435 const jsize byteCountUTF8 = env->GetStringUTFLength(dname);
436
437 // Only allow dname which could be simply formatted to UTF8.
438 // In native layer, res_mkquery would re-format the input char array to packet.
439 std::vector<char> queryname(byteCountUTF8 + 1, 0);
440
441 env->GetStringUTFRegion(dname, 0, javaCharsCount, queryname.data());
442 int fd = resNetworkQuery(netId, queryname.data(), ns_class, ns_type, flags);
443
444 if (fd < 0) {
445 throwErrnoException(env, "resNetworkQuery", -fd);
446 return nullptr;
447 }
448
449 return jniCreateFileDescriptor(env, fd);
450}
451
452static jobject android_net_utils_resNetworkSend(JNIEnv *env, jobject thiz, jint netId,
453 jbyteArray msg, jint msgLen, jint flags) {
454 uint8_t data[MAXCMDSIZE];
455
456 checkLenAndCopy(env, msg, msgLen, data);
457 int fd = resNetworkSend(netId, data, msgLen, flags);
458
459 if (fd < 0) {
460 throwErrnoException(env, "resNetworkSend", -fd);
461 return nullptr;
462 }
463
464 return jniCreateFileDescriptor(env, fd);
465}
466
467static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) {
468 int fd = jniGetFDFromFileDescriptor(env, javaFd);
469 int rcode;
470 std::vector<uint8_t> buf(MAXPACKETSIZE, 0);
471
472 int res = resNetworkResult(fd, &rcode, buf.data(), MAXPACKETSIZE);
473 if (res < 0) {
474 throwErrnoException(env, "resNetworkResult", -res);
475 return nullptr;
476 }
477
478 jbyteArray answer = env->NewByteArray(res);
479 if (answer == nullptr) {
480 throwErrnoException(env, "resNetworkResult", ENOMEM);
481 return nullptr;
482 } else {
483 env->SetByteArrayRegion(answer, 0, res,
484 reinterpret_cast<jbyte*>(buf.data()));
485 }
486
487 return answer;
488}
Lorenzo Colitticbe4f7c2015-03-06 19:57:39 +0900489
markchien150e1912018-12-27 22:49:51 +0800490static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
491 if (javaFd == NULL) {
492 jniThrowNullPointerException(env, NULL);
493 return NULL;
494 }
495
496 int fd = jniGetFDFromFileDescriptor(env, javaFd);
497 struct tcp_repair_window trw = {};
498 socklen_t size = sizeof(trw);
499
500 // Obtain the parameters of the TCP repair window.
501 int rc = getsockopt(fd, IPPROTO_TCP, TCP_REPAIR_WINDOW, &trw, &size);
502 if (rc == -1) {
503 throwErrnoException(env, "getsockopt : TCP_REPAIR_WINDOW", errno);
504 return NULL;
505 }
506
507 struct tcp_info tcpinfo = {};
508 socklen_t tcpinfo_size = sizeof(tcp_info);
509
510 // Obtain the window scale from the tcp info structure. This contains a scale factor that
511 // should be applied to the window size.
512 rc = getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpinfo, &tcpinfo_size);
513 if (rc == -1) {
514 throwErrnoException(env, "getsockopt : TCP_INFO", errno);
515 return NULL;
516 }
517
518 jclass class_TcpRepairWindow = env->FindClass("android/net/TcpRepairWindow");
519 jmethodID ctor = env->GetMethodID(class_TcpRepairWindow, "<init>", "(IIIIII)V");
520
521 return env->NewObject(class_TcpRepairWindow, ctor, trw.snd_wl1, trw.snd_wnd, trw.max_window,
522 trw.rcv_wnd, trw.rcv_wup, tcpinfo.tcpi_rcv_wscale);
523}
524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525// ----------------------------------------------------------------------------
526
527/*
528 * JNI registration.
529 */
Daniel Micay76f6a862015-09-19 17:31:01 -0400530static const JNINativeMethod gNetworkUtilMethods[] = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 /* name, signature, funcPtr */
Paul Jensen32a58f02014-06-20 13:58:14 -0400532 { "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork },
Paul Jensen72db88e2015-03-10 10:54:12 -0400533 { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
Paul Jensen32a58f02014-06-20 13:58:14 -0400534 { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
Lorenzo Colitti9f1274b2014-08-21 11:45:54 -0700535 { "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork },
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400536 { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
Paul Jensencee9b512015-05-06 07:32:40 -0400537 { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
Remi NGUYEN VAN12da4a52018-07-04 11:15:56 +0900538 { "addArpEntry", "([B[BLjava/lang/String;Ljava/io/FileDescriptor;)V", (void*) android_net_utils_addArpEntry },
Lorenzo Colitticbe4f7c2015-03-06 19:57:39 +0900539 { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter },
Paul Jensen578a76e2016-01-14 14:54:39 -0500540 { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachRaFilter },
Erik Kline473355f2016-10-19 17:42:01 +0900541 { "attachControlPacketFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachControlPacketFilter },
markchien150e1912018-12-27 22:49:51 +0800542 { "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
543 { "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
544 { "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow },
Erik Klinea3ca6bd2016-05-24 20:12:08 +0900545 { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_setupRaSocket },
Luke Huang92ae35e2019-01-04 19:46:47 +0800546 { "resNetworkSend", "(I[BII)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkSend },
547 { "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery },
548 { "resNetworkResult", "(Ljava/io/FileDescriptor;)[B", (void*) android_net_utils_resNetworkResult },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549};
550
551int register_android_net_NetworkUtils(JNIEnv* env)
552{
Andreas Gampe987f79f2014-11-18 17:29:46 -0800553 return RegisterMethodsOrDie(env, NETUTILS_PKG_NAME, gNetworkUtilMethods,
554 NELEM(gNetworkUtilMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555}
556
557}; // namespace android