• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
addRouterAttribute(Request & r,int type,const void * data,size_t size)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 
init()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 
addNeighbor(const struct in6_addr & address,unsigned int interfaceIndex)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 
addRoute(const struct in6_addr & address,uint8_t bits,uint32_t ifaceIndex)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 
setDefaultGateway(const struct in6_addr & address,unsigned int ifaceIndex)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 
sendNetlinkMessage(const void * data,size_t size)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