1/* 2 * Copyright 2010, 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#define LOG_TAG "RawSocket" 18 19#include "AsynchronousSocketCloseMonitor.h" 20#include "cutils/log.h" 21#include "JNIHelp.h" 22#include "JniException.h" 23#include "JniConstants.h" 24#include "NetFd.h" 25#include "NetworkUtilities.h" 26#include "ScopedUtfChars.h" 27#include "ScopedPrimitiveArray.h" 28 29#include "jni.h" 30 31#include <sys/types.h> 32#include <sys/socket.h> 33#include <linux/rtnetlink.h> 34#include <net/if.h> 35#include <linux/if_ether.h> 36#include <linux/if_packet.h> 37#include <arpa/inet.h> 38#include <errno.h> 39#include <fcntl.h> 40#include <poll.h> 41#include <netinet/ip.h> 42#include <linux/udp.h> 43 44union sockunion { 45 sockaddr sa; 46 sockaddr_ll sll; 47}; 48 49/* 50 * Creates a socket suitable for raw socket operations. The socket is 51 * bound to the interface specified by the supplied name. The socket 52 * value is placed into the supplied FileDescriptor instance. 53 * 54 * TODO(chesnutt): consider breaking this into pieces: create a 55 * variety of constructors for different socket types, then a generic 56 * setBlocking() method followed by polymorphic bind(). 57 */ 58static void RawSocket_create(JNIEnv* env, jclass, jobject fileDescriptor, 59 jshort protocolType, jstring interfaceName) 60{ 61 62 ScopedUtfChars ifname(env, interfaceName); 63 if (ifname.c_str() == NULL) { 64 return; 65 } 66 67 sockunion su; 68 memset(&su, 0, sizeof(su)); 69 su.sll.sll_family = PF_PACKET; 70 su.sll.sll_protocol = htons(protocolType); 71 su.sll.sll_ifindex = if_nametoindex(ifname.c_str()); 72 int sock = socket(PF_PACKET, SOCK_DGRAM, htons(protocolType)); 73 74 if (sock == -1) { 75 ALOGE("Can't create socket %s", strerror(errno)); 76 jniThrowSocketException(env, errno); 77 return; 78 } 79 80 jniSetFileDescriptorOfFD(env, fileDescriptor, sock); 81 if (!setBlocking(sock, false)) { 82 ALOGE("Can't set non-blocking mode on socket %s", strerror(errno)); 83 jniThrowSocketException(env, errno); 84 return; 85 } 86 87 int err = bind(sock, &su.sa, sizeof(su)); 88 if (err != 0) { 89 ALOGE("Socket bind error %s", strerror(errno)); 90 jniThrowSocketException(env, errno); 91 return; 92 } 93} 94 95/* 96 * Writes the L3 (IP) packet to the raw socket supplied in the 97 * FileDescriptor instance. 98 * 99 * Assumes that the caller has validated the offset & byteCount values. 100 */ 101static int RawSocket_sendPacket(JNIEnv* env, jclass, jobject fileDescriptor, 102 jstring interfaceName, jshort protocolType, jbyteArray destMac, 103 jbyteArray packet, jint offset, jint byteCount) 104{ 105 NetFd fd(env, fileDescriptor); 106 107 if (fd.isClosed()) { 108 return 0; 109 } 110 111 ScopedUtfChars ifname(env, interfaceName); 112 if (ifname.c_str() == NULL) { 113 return 0; 114 } 115 116 ScopedByteArrayRO byteArray(env, packet); 117 if (byteArray.get() == NULL) { 118 return 0; 119 } 120 121 ScopedByteArrayRO mac(env, destMac); 122 if (mac.get() == NULL) { 123 return 0; 124 } 125 126 sockunion su; 127 memset(&su, 0, sizeof(su)); 128 su.sll.sll_hatype = htons(1); // ARPHRD_ETHER 129 su.sll.sll_halen = mac.size(); 130 memcpy(&su.sll.sll_addr, mac.get(), mac.size()); 131 su.sll.sll_family = AF_PACKET; 132 su.sll.sll_protocol = htons(protocolType); 133 su.sll.sll_ifindex = if_nametoindex(ifname.c_str()); 134 135 int err; 136 { 137 int intFd = fd.get(); 138 AsynchronousSocketCloseMonitor monitor(intFd); 139 err = NET_FAILURE_RETRY(fd, sendto(intFd, byteArray.get() + offset, 140 byteCount, 0, &su.sa, sizeof(su))); 141 } 142 143 return err; 144} 145 146/* 147 * Reads a network packet into the user-supplied buffer. Return the 148 * length of the packet, or a 0 if there was a timeout or an 149 * unacceptable packet was acquired. 150 * 151 * Assumes that the caller has validated the offset & byteCount values. 152 */ 153static jint RawSocket_recvPacket(JNIEnv* env, jclass, jobject fileDescriptor, 154 jbyteArray packet, jint offset, jint byteCount, jint port, 155 jint timeout_millis) 156{ 157 NetFd fd(env, fileDescriptor); 158 if (fd.isClosed()) { 159 return 0; 160 } 161 162 ScopedByteArrayRW body(env, packet); 163 jbyte* packetData = body.get(); 164 if (packetData == NULL) { 165 return 0; 166 } 167 168 packetData += offset; 169 170 pollfd fds[1]; 171 fds[0].fd = fd.get(); 172 fds[0].events = POLLIN; 173 int retval = poll(fds, 1, timeout_millis); 174 if (retval <= 0) { 175 return 0; 176 } 177 178 unsigned int size = 0; 179 { 180 int packetSize = byteCount; 181 int intFd = fd.get(); 182 AsynchronousSocketCloseMonitor monitor(intFd); 183 size = NET_FAILURE_RETRY(fd, read(intFd, packetData, packetSize)); 184 } 185 186 if (env->ExceptionOccurred()) { 187 return 0; 188 } 189 190 if (port != -1) { 191 // quick check for UDP type & UDP port 192 // the packet is an IP header, UDP header, and UDP payload 193 if ((size < (sizeof(struct iphdr) + sizeof(struct udphdr)))) { 194 return 0; // runt packet 195 } 196 197 u_int8_t ip_proto = ((iphdr *) packetData)->protocol; 198 if (ip_proto != IPPROTO_UDP) { 199 return 0; // something other than UDP 200 } 201 202 __be16 destPort = htons((reinterpret_cast<udphdr*>(packetData + sizeof(iphdr)))->dest); 203 if (destPort != port) { 204 return 0; // something other than requested port 205 } 206 } 207 208 return size; 209} 210 211static JNINativeMethod gRawMethods[] = { 212 NATIVE_METHOD(RawSocket, create, "(Ljava/io/FileDescriptor;SLjava/lang/String;)V"), 213 NATIVE_METHOD(RawSocket, sendPacket, "(Ljava/io/FileDescriptor;Ljava/lang/String;S[B[BII)I"), 214 NATIVE_METHOD(RawSocket, recvPacket, "(Ljava/io/FileDescriptor;[BIIII)I"), 215}; 216 217void register_libcore_net_RawSocket(JNIEnv* env) { 218 jniRegisterNativeMethods(env, "libcore/net/RawSocket", gRawMethods, NELEM(gRawMethods)); 219} 220