Home | History | Annotate | Download | only in ipv6proxy
      1 /*
      2  * Copyright (C) 2017 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 "socket.h"
     18 
     19 #include <errno.h>
     20 #include <string.h>
     21 
     22 #include <linux/in6.h>
     23 #include <net/ethernet.h>
     24 #include <netinet/in.h>
     25 #include <sys/types.h>
     26 #include <sys/socket.h>
     27 #include <unistd.h>
     28 
     29 #include "address.h"
     30 #include "message.h"
     31 
     32 Socket::Socket() : mState(State::New), mSocket(-1) {
     33 }
     34 
     35 Socket::Socket(Socket&& other) : mState(other.mState), mSocket(other.mSocket) {
     36     other.mSocket = -1;
     37     other.mState = State::Moved;
     38 }
     39 
     40 Socket::~Socket() {
     41     if (mSocket != -1) {
     42         close(mSocket);
     43         mSocket = -1;
     44     }
     45     mState = State::Destructed;
     46 }
     47 
     48 Socket& Socket::operator=(Socket&& other) {
     49     if (mSocket != -1) {
     50         close(mSocket);
     51     }
     52     mSocket = other.mSocket;
     53     mState = other.mState;
     54     other.mSocket = -1;
     55     other.mState = State::Moved;
     56 
     57     return *this;
     58 }
     59 
     60 Result Socket::open(int domain, int type, int protocol) {
     61     if (mState != State::New) {
     62         return Result::error("open called on socket in invalid state");
     63     }
     64     mSocket = ::socket(domain, type | SOCK_CLOEXEC, protocol);
     65     if (mSocket == -1) {
     66         return Result::error(strerror(errno));
     67     }
     68     mState = State::Open;
     69     return Result::success();
     70 }
     71 
     72 Result Socket::setInterface(const std::string& interface) {
     73     if (mState != State::Open) {
     74         return Result::error("attempting to set option in invalid state");
     75     }
     76     int res = ::setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE,
     77                            interface.c_str(), interface.size());
     78 
     79     return res == -1 ? Result::error(strerror(errno)) : Result::success();
     80 }
     81 
     82 Result Socket::setMulticastHopLimit(int hopLimit) {
     83     if (mState != State::Open) {
     84         return Result::error("attempting to set option in invalid state");
     85     }
     86     int res = ::setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
     87                            &hopLimit, sizeof(hopLimit));
     88 
     89     return res == -1 ? Result::error(strerror(errno)) : Result::success();
     90 }
     91 
     92 Result Socket::setUnicastHopLimit(int hopLimit) {
     93     if (mState != State::Open) {
     94         return Result::error("attempting to set option in invalid state");
     95     }
     96     int res = ::setsockopt(mSocket, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
     97                            &hopLimit, sizeof(hopLimit));
     98 
     99     return res == -1 ? Result::error(strerror(errno)) : Result::success();
    100 }
    101 
    102 Result Socket::setTransparent(bool transparent) {
    103     if (mState != State::Open) {
    104         return Result::error("attempting to set option in invalid state");
    105     }
    106     int v = transparent ? 1 : 0;
    107     int res = ::setsockopt(mSocket, IPPROTO_IPV6, IPV6_TRANSPARENT,
    108                            &v, sizeof(v));
    109 
    110     return res == -1 ? Result::error(strerror(errno)) : Result::success();
    111 }
    112 
    113 Result Socket::bind(const Address& address) {
    114     if (mState != State::Open) {
    115         return Result::error("bind called on socket in invalid state");
    116     }
    117 
    118     int res = ::bind(mSocket, address.get<sockaddr>(), address.size());
    119     if (res == -1) {
    120         return Result::error(strerror(errno));
    121     }
    122 
    123     mState = State::Bound;
    124     return Result::success();
    125 }
    126 
    127 Result Socket::receive(Message* receivingMessage) {
    128     if (receivingMessage == nullptr) {
    129         return Result::error("No receivingMessage provided");
    130     }
    131     if (mState != State::Bound) {
    132         return Result::error("Attempt to receive on a socket that isn't bound");
    133     }
    134 
    135     ssize_t rxBytes = ::recv(mSocket,
    136                              receivingMessage->data(),
    137                              receivingMessage->capacity(),
    138                              0);
    139     if (rxBytes < 0) {
    140         return Result::error(strerror(errno));
    141     }
    142 
    143     receivingMessage->setSize(static_cast<size_t>(rxBytes));
    144     return Result::success();
    145 }
    146 
    147 Result Socket::receiveFrom(Message* receivingMessage, Address* from) {
    148     if (receivingMessage == nullptr) {
    149         return Result::error("No receivingMessage provided");
    150     }
    151     if (from == nullptr) {
    152         return Result::error("No from address provided");
    153     }
    154     if (mState != State::Bound) {
    155         return Result::error("Attempt to receive on a socket that isn't bound");
    156     }
    157 
    158     from->reset();
    159     sockaddr* source = from->get<sockaddr>();
    160     socklen_t sourceLen = from->size();
    161     ssize_t rxBytes = ::recvfrom(mSocket,
    162                                  receivingMessage->data(),
    163                                  receivingMessage->capacity(),
    164                                  0,
    165                                  source,
    166                                  &sourceLen);
    167     if (rxBytes < 0) {
    168         return Result::error(strerror(errno));
    169     }
    170 
    171     receivingMessage->setSize(static_cast<size_t>(rxBytes));
    172     return Result::success();
    173 }
    174 
    175 Result Socket::send(const void* data, size_t size) {
    176     if (mState != State::Bound && mState != State::Open) {
    177         return Result::error("Attempt to send on a socket in invalid state");
    178     }
    179 
    180     int res = ::send(mSocket, data, size, 0);
    181     if (res == -1) {
    182         return Result::error(strerror(errno));
    183     }
    184     return Result::success();
    185 }
    186 
    187 Result Socket::sendTo(const sockaddr& destination,
    188                       size_t destinationSize,
    189                       const void* data,
    190                       size_t size) {
    191     if (mState != State::Bound && mState != State::Open) {
    192         return Result::error("Attempt to send on a socket in invalid state");
    193     }
    194 
    195     int res = ::sendto(mSocket, data, size, 0, &destination, destinationSize);
    196     if (res == -1) {
    197         return Result::error(strerror(errno));
    198     }
    199     return Result::success();
    200 }
    201 
    202 Result Socket::sendTo(const in6_addr& destination,
    203                       const void* data,
    204                       size_t size) {
    205     sockaddr_in6 addr;
    206     memset(&addr, 0, sizeof(addr));
    207     addr.sin6_family = AF_INET6;
    208     addr.sin6_addr = destination;
    209     return sendTo(*reinterpret_cast<sockaddr*>(&addr),
    210                   sizeof(addr),
    211                   data,
    212                   size);
    213 }
    214 
    215 Result Socket::sendFrom(const struct in6_addr& fromAddress,
    216                         const sockaddr& destination,
    217                         size_t destinationSize,
    218                         const void* data,
    219                         size_t size) {
    220     struct msghdr messageHeader;
    221     memset(&messageHeader, 0, sizeof(messageHeader));
    222     // Even when sending this struct requires a non-const pointer, even when
    223     // it's only going to be read. Do a const_cast instead of creating a
    224     // method signature with illogical const-behavior.
    225     messageHeader.msg_name = const_cast<struct sockaddr*>(&destination);
    226     messageHeader.msg_namelen = destinationSize;
    227 
    228     struct iovec iov;
    229     messageHeader.msg_iov = &iov;
    230     messageHeader.msg_iovlen = 1;
    231 
    232     memset(&iov, 0, sizeof(iov));
    233     iov.iov_base = const_cast<void*>(data);
    234     iov.iov_len = size;
    235 
    236     char control[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
    237     messageHeader.msg_control = control;
    238     messageHeader.msg_controllen = sizeof(control);
    239 
    240     struct cmsghdr* controlHeader = CMSG_FIRSTHDR(&messageHeader);
    241     controlHeader->cmsg_level = IPPROTO_IPV6;
    242     controlHeader->cmsg_type = IPV6_PKTINFO;
    243     controlHeader->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
    244 
    245     auto packetInfoData = CMSG_DATA(controlHeader);
    246     auto packetInfo = reinterpret_cast<struct in6_pktinfo*>(packetInfoData);
    247     packetInfo->ipi6_addr = fromAddress;
    248 
    249     int res = ::sendmsg(mSocket, &messageHeader, 0);
    250     if (res == -1) {
    251         int error = errno;
    252         printf("sendmsg failed: %d\n", error);
    253         return Result::error(strerror(error));
    254     }
    255     return Result::success();
    256 }
    257 
    258 Result Socket::sendFrom(const in6_addr& fromAddress,
    259                         const in6_addr& destination,
    260                         const void* data,
    261                         size_t size) {
    262     sockaddr_in6 addr;
    263     memset(&addr, 0, sizeof(addr));
    264     addr.sin6_family = AF_INET6;
    265     addr.sin6_addr = destination;
    266 
    267     return sendFrom(fromAddress,
    268                     *reinterpret_cast<sockaddr*>(&addr),
    269                     sizeof(addr),
    270                     data,
    271                     size);
    272 }
    273