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 "router.h"
     18 
     19 #include <linux/rtnetlink.h>
     20 #include <stddef.h>
     21 #include <string.h>
     22 
     23 #include "address.h"
     24 #include "log.h"
     25 
     26 template<class Request>
     27 static void addRouterAttribute(Request& r,
     28                                int type,
     29                                const void* data,
     30                                size_t size) {
     31     // Calculate the offset into the character buffer where the RTA data lives
     32     // We use offsetof on the buffer to get it. This avoids undefined behavior
     33     // by casting the buffer (which is safe because it's char) instead of the
     34     // Request struct.(which is undefined because of aliasing)
     35     size_t offset = NLMSG_ALIGN(r.hdr.nlmsg_len) - offsetof(Request, buf);
     36     auto attr = reinterpret_cast<struct rtattr*>(r.buf + offset);
     37     attr->rta_type = type;
     38     attr->rta_len = RTA_LENGTH(size);
     39     memcpy(RTA_DATA(attr), data, size);
     40 
     41     // Update the message length to include the router attribute.
     42     r.hdr.nlmsg_len = NLMSG_ALIGN(r.hdr.nlmsg_len) + RTA_ALIGN(attr->rta_len);
     43 }
     44 
     45 bool Router::init() {
     46     // Create a netlink socket to the router
     47     Result res = mSocket.open(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
     48     if (!res) {
     49         loge("Unable to open netlink socket: %s\n", res.c_str());
     50         return false;
     51     }
     52     return true;
     53 }
     54 
     55 bool Router::addNeighbor(const struct in6_addr& address,
     56                          unsigned int interfaceIndex) {
     57     struct Request {
     58         struct nlmsghdr hdr;
     59         struct ndmsg msg;
     60         char buf[256];
     61     } request;
     62 
     63     memset(&request, 0, sizeof(request));
     64 
     65     unsigned short msgLen = NLMSG_LENGTH(sizeof(request.msg));
     66     // Set up a request to create a new neighbor
     67     request.hdr.nlmsg_len = msgLen;
     68     request.hdr.nlmsg_type = RTM_NEWNEIGH;
     69     request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
     70 
     71     // The neighbor is a permanent IPv6 proxy
     72     request.msg.ndm_family = AF_INET6;
     73     request.msg.ndm_state = NUD_PERMANENT;
     74     request.msg.ndm_flags = NTF_PROXY;
     75     request.msg.ndm_ifindex = interfaceIndex;
     76 
     77     addRouterAttribute(request, NDA_DST, &address, sizeof(address));
     78 
     79     return sendNetlinkMessage(&request, request.hdr.nlmsg_len);
     80 }
     81 
     82 bool Router::addRoute(const struct in6_addr& address,
     83                       uint8_t bits,
     84                       uint32_t ifaceIndex) {
     85     struct Request {
     86         struct nlmsghdr hdr;
     87         struct rtmsg msg;
     88         char buf[256];
     89     } request;
     90 
     91     memset(&request, 0, sizeof(request));
     92 
     93     // Set up a request to create a new route
     94     request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg));
     95     request.hdr.nlmsg_type = RTM_NEWROUTE;
     96     request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
     97 
     98     request.msg.rtm_family = AF_INET6;
     99     request.msg.rtm_dst_len = bits;
    100     request.msg.rtm_table = RT_TABLE_MAIN;
    101     request.msg.rtm_protocol = RTPROT_RA;
    102     request.msg.rtm_scope = RT_SCOPE_UNIVERSE;
    103     request.msg.rtm_type = RTN_UNICAST;
    104 
    105     addRouterAttribute(request, RTA_DST, &address, sizeof(address));
    106     addRouterAttribute(request, RTA_OIF, &ifaceIndex, sizeof(ifaceIndex));
    107 
    108     return sendNetlinkMessage(&request, request.hdr.nlmsg_len);
    109 }
    110 
    111 bool Router::setDefaultGateway(const struct in6_addr& address,
    112                                unsigned int ifaceIndex) {
    113     struct Request {
    114         struct nlmsghdr hdr;
    115         struct rtmsg msg;
    116         char buf[256];
    117     } request;
    118 
    119     memset(&request, 0, sizeof(request));
    120 
    121     // Set up a request to create a new route
    122     request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg));
    123     request.hdr.nlmsg_type = RTM_NEWROUTE;
    124     request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
    125 
    126     request.msg.rtm_family = AF_INET6;
    127     request.msg.rtm_dst_len = 0;
    128     request.msg.rtm_src_len = 0;
    129     request.msg.rtm_table = RT_TABLE_MAIN;
    130     request.msg.rtm_protocol = RTPROT_RA;
    131     request.msg.rtm_scope = RT_SCOPE_UNIVERSE;
    132     request.msg.rtm_type = RTN_UNICAST;
    133 
    134     struct in6_addr anyAddress;
    135     memset(&anyAddress, 0, sizeof(anyAddress));
    136     addRouterAttribute(request, RTA_GATEWAY, &address, sizeof(address));
    137     addRouterAttribute(request, RTA_OIF, &ifaceIndex, sizeof(ifaceIndex));
    138     addRouterAttribute(request, RTA_SRC, &anyAddress, sizeof(anyAddress));
    139 
    140     return sendNetlinkMessage(&request, request.hdr.nlmsg_len);
    141 }
    142 
    143 bool Router::sendNetlinkMessage(const void* data, size_t size) {
    144     struct sockaddr_nl netlinkAddress;
    145     memset(&netlinkAddress, 0, sizeof(netlinkAddress));
    146     netlinkAddress.nl_family = AF_NETLINK;
    147     Result res = mSocket.sendTo(netlinkAddress, data, size);
    148     if (!res) {
    149         loge("Unable to send on netlink socket: %s\n", res.c_str());
    150         return false;
    151     }
    152     return true;
    153 }
    154 
    155