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