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 "proxy.h"
18
19 #include <errno.h>
20 #include <linux/if_packet.h>
21 #include <poll.h>
22 #include <signal.h>
23
24 #include "log.h"
25 #include "message.h"
26 #include "packet.h"
27 #include "result.h"
28
29 // The prefix length for an address of a single unique node
30 static const uint8_t kNodePrefixLength = 128;
31 static const size_t kLinkAddressSize = 6;
32
33 // Rewrite the link address of a neighbor discovery option to the link address
34 // of |interface|. This can be either a source or target link address as
35 // specified by |optionType|. The valid values are ND_OPT_TARGET_LINKADDR and
36 // ND_OPT_SOURCE_LINKADDR. This will modify the message data inside |packet|.
rewriteLinkAddressOption(Packet & packet,const Interface & interface,int optionType)37 static void rewriteLinkAddressOption(Packet& packet,
38 const Interface& interface,
39 int optionType) {
40 for (nd_opt_hdr* opt = packet.firstOpt(); opt; opt = packet.nextOpt(opt)) {
41 if (opt->nd_opt_type == optionType) {
42 auto src = interface.linkAddr().get<sockaddr_ll>();
43 auto dest = reinterpret_cast<char*>(opt) + sizeof(nd_opt_hdr);
44 memcpy(dest, src->sll_addr, kLinkAddressSize);
45 }
46 }
47 }
48
run()49 int Proxy::run() {
50 sigset_t blockMask, originalMask;
51 int status = ::sigfillset(&blockMask);
52 if (status != 0) {
53 loge("Unable to fill signal set: %s\n", strerror(errno));
54 return 1;
55 }
56 status = ::sigprocmask(SIG_SETMASK, &blockMask, &originalMask);
57 if (status != 0) {
58 loge("Unable to set signal mask: %s\n", strerror(errno));
59 return 1;
60 }
61 // Init outer interface and router
62 if (!mOuterIf.init() || !mRouter.init()) {
63 return 1;
64 }
65 // Init all inner interfaces
66 for (size_t i = 0; i < mInnerIfs.size(); ++i) {
67 if (!mInnerIfs[i].init()) {
68 return 1;
69 }
70 }
71
72 // Create list of FDs to poll, we're only looking for input (POLLIN)
73 std::vector<pollfd> fds(mInnerIfs.size() + 1);
74 fds[0].fd = mOuterIf.ipSocket().get();
75 fds[0].events = POLLIN;
76 for (size_t i = 0; i < mInnerIfs.size(); ++i) {
77 fds[i + 1].fd = mInnerIfs[i].ipSocket().get();
78 fds[i + 1].events = POLLIN;
79 }
80
81 Message message;
82 while (status >= 0) {
83 status = ::ppoll(fds.data(), fds.size(), nullptr, &originalMask);
84 if (status > 0) {
85 // Something available to read
86 for (const struct pollfd& fd : fds) {
87 if (receiveIfPossible(fd, mOuterIf.ipSocket(), &message)) {
88 // Received a message on the outer interface
89 handleOuterMessage(message);
90 } else {
91 for (auto& inner : mInnerIfs) {
92 if (receiveIfPossible(fd, inner.ipSocket(), &message)) {
93 // Received a message on the inner interface
94 handleInnerMessage(inner, message);
95 }
96 }
97 }
98 }
99 }
100 }
101 loge("Polling failed: %s\n", strerror(errno));
102 return 1;
103 }
104
receiveIfPossible(const pollfd & fd,Socket & socket,Message * message)105 bool Proxy::receiveIfPossible(const pollfd& fd,
106 Socket& socket,
107 Message* message) {
108 // Check if it's actually the socket we're interested in
109 if (fd.fd != socket.get()) {
110 return false;
111 }
112 // Check if there is something to read on this socket
113 if ((fd.revents & POLLIN) == 0) {
114 return false;
115 }
116
117 // Receive the message and place the data in the message parameter
118 Result res = socket.receive(message);
119 if (!res) {
120 loge("Error receiving on socket: %s\n", res.c_str());
121 return false;
122 }
123 return true;
124 }
125
handleOuterMessage(Message & message)126 void Proxy::handleOuterMessage(Message& message) {
127 Packet packet(message);
128 uint32_t options = kForwardOnly;
129 switch (packet.type()) {
130 case Packet::Type::RouterAdvertisement:
131 options = kRewriteSourceLink | kSetDefaultGateway;
132 break;
133 case Packet::Type::NeighborSolicitation:
134 options = kSpoofSource;
135 break;
136 case Packet::Type::NeighborAdvertisement:
137 options = kRewriteTargetLink;
138 break;
139 default:
140 return;
141 }
142 for (auto& inner : mInnerIfs) {
143 forward(mOuterIf, inner, packet, options);
144 }
145 }
146
handleInnerMessage(const Interface & inner,Message & message)147 void Proxy::handleInnerMessage(const Interface& inner, Message& message) {
148 Packet packet(message);
149 uint32_t options = kForwardOnly;
150 switch (packet.type()) {
151 case Packet::Type::RouterSolicitation:
152 options = kSpoofSource;
153 break;
154 case Packet::Type::NeighborSolicitation:
155 options = kSpoofSource | kAddRoute;
156 break;
157 case Packet::Type::NeighborAdvertisement:
158 options = kRewriteTargetLink | kSpoofSource | kAddRoute;
159 break;
160 default:
161 return;
162 }
163 forward(inner, mOuterIf, packet, options);
164 }
165
forward(const Interface & from,Interface & to,Packet & packet,uint32_t options)166 void Proxy::forward(const Interface& from,
167 Interface& to,
168 Packet& packet,
169 uint32_t options) {
170 if (mLogDebug) {
171 logd("Forwarding %s from %s/%s to %s/%s\n",
172 packet.description().c_str(),
173 from.name().c_str(), addrToStr(packet.ip()->ip6_src).c_str(),
174 to.name().c_str(), addrToStr(packet.ip()->ip6_dst).c_str());
175 }
176
177 if (options & kRewriteTargetLink) {
178 rewriteLinkAddressOption(packet, to, ND_OPT_TARGET_LINKADDR);
179 }
180 if (options & kRewriteSourceLink) {
181 rewriteLinkAddressOption(packet, to, ND_OPT_SOURCE_LINKADDR);
182 }
183
184 Result res = Result::success();
185 if (options & kSpoofSource) {
186 // Spoof the source of the packet so that it appears to originate from
187 // the same source that we see.
188 res = to.icmpSocket().sendFrom(packet.ip()->ip6_src,
189 packet.ip()->ip6_dst,
190 packet.icmp(),
191 packet.icmpSize());
192 } else {
193 res = to.icmpSocket().sendTo(packet.ip()->ip6_dst,
194 packet.icmp(),
195 packet.icmpSize());
196 }
197 if (!res) {
198 loge("Failed to forward %s from %s to %s: %s\n",
199 packet.description().c_str(),
200 from.name().c_str(), to.name().c_str(),
201 res.c_str());
202 }
203
204 if (options & kAddRoute) {
205 mRouter.addRoute(packet.ip()->ip6_src, kNodePrefixLength, from.index());
206 }
207 if (packet.type() == Packet::Type::RouterAdvertisement &&
208 options & kSetDefaultGateway) {
209 // Set the default gateway from this router advertisement. This is
210 // needed so that packets that are forwarded as a result of proxying
211 // actually have somewhere to go.
212 if (!mRouter.setDefaultGateway(packet.ip()->ip6_src, from.index())) {
213 loge("Failed to set default gateway %s\n",
214 addrToStr(packet.ip()->ip6_src).c_str());
215 }
216 }
217 }
218
219