• 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 "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