rtnl_message.cc revision c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5
1//
2// Copyright (C) 2012 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 "shill/net/rtnl_message.h"
18
19#include <linux/netlink.h>
20#include <linux/rtnetlink.h>
21#include <netinet/in.h>
22#include <sys/socket.h>
23
24#include <base/logging.h>
25
26#include "shill/net/ndisc.h"
27
28namespace shill {
29
30struct RTNLHeader {
31  RTNLHeader() {
32    memset(this, 0, sizeof(*this));
33  }
34  struct nlmsghdr hdr;
35  union {
36    struct ifinfomsg ifi;
37    struct ifaddrmsg ifa;
38    struct rtmsg rtm;
39    struct rtgenmsg gen;
40    struct nduseroptmsg nd_user_opt;
41    struct ndmsg ndm;
42  };
43};
44
45RTNLMessage::RTNLMessage()
46    : type_(kTypeUnknown),
47      mode_(kModeUnknown),
48      flags_(0),
49      seq_(0),
50      pid_(0),
51      interface_index_(0),
52      family_(IPAddress::kFamilyUnknown) {}
53
54RTNLMessage::RTNLMessage(Type type,
55                         Mode mode,
56                         unsigned int flags,
57                         uint32_t seq,
58                         uint32_t pid,
59                         int interface_index,
60                         IPAddress::Family family)
61    : type_(type),
62      mode_(mode),
63      flags_(flags),
64      seq_(seq),
65      pid_(pid),
66      interface_index_(interface_index),
67      family_(family) {}
68
69bool RTNLMessage::Decode(const ByteString& msg) {
70  bool ret = DecodeInternal(msg);
71  if (!ret) {
72    Reset();
73  }
74  return ret;
75}
76
77bool RTNLMessage::DecodeInternal(const ByteString& msg) {
78  const RTNLHeader* hdr =
79      reinterpret_cast<const RTNLHeader*>(msg.GetConstData());
80
81  if (msg.GetLength() < sizeof(hdr->hdr) ||
82      msg.GetLength() < hdr->hdr.nlmsg_len)
83    return false;
84
85  Mode mode = kModeUnknown;
86  switch (hdr->hdr.nlmsg_type) {
87  case RTM_NEWLINK:
88  case RTM_NEWADDR:
89  case RTM_NEWROUTE:
90  case RTM_NEWNDUSEROPT:
91  case RTM_NEWNEIGH:
92    mode = kModeAdd;
93    break;
94
95  case RTM_DELLINK:
96  case RTM_DELADDR:
97  case RTM_DELROUTE:
98  case RTM_DELNEIGH:
99    mode = kModeDelete;
100    break;
101
102  default:
103    return false;
104  }
105
106  rtattr* attr_data = nullptr;
107  int attr_length = 0;
108
109  switch (hdr->hdr.nlmsg_type) {
110  case RTM_NEWLINK:
111  case RTM_DELLINK:
112    if (!DecodeLink(hdr, mode, &attr_data, &attr_length))
113      return false;
114    break;
115
116  case RTM_NEWADDR:
117  case RTM_DELADDR:
118    if (!DecodeAddress(hdr, mode, &attr_data, &attr_length))
119      return false;
120    break;
121
122  case RTM_NEWROUTE:
123  case RTM_DELROUTE:
124    if (!DecodeRoute(hdr, mode, &attr_data, &attr_length))
125      return false;
126    break;
127
128  case RTM_NEWNDUSEROPT:
129    if (!DecodeNdUserOption(hdr, mode, &attr_data, &attr_length))
130      return false;
131    break;
132
133  case RTM_NEWNEIGH:
134  case RTM_DELNEIGH:
135    if (!DecodeNeighbor(hdr, mode, &attr_data, &attr_length))
136      return false;
137    break;
138
139  default:
140    NOTREACHED();
141  }
142
143  flags_ = hdr->hdr.nlmsg_flags;
144  seq_ = hdr->hdr.nlmsg_seq;
145  pid_ = hdr->hdr.nlmsg_pid;
146
147  while (attr_data && RTA_OK(attr_data, attr_length)) {
148    SetAttribute(
149        attr_data->rta_type,
150        ByteString(reinterpret_cast<unsigned char*>(RTA_DATA(attr_data)),
151                   RTA_PAYLOAD(attr_data)));
152    attr_data = RTA_NEXT(attr_data, attr_length);
153  }
154
155  if (attr_length) {
156    // We hit a parse error while going through the attributes
157    attributes_.clear();
158    return false;
159  }
160
161  return true;
162}
163
164bool RTNLMessage::DecodeLink(const RTNLHeader* hdr,
165                             Mode mode,
166                             rtattr** attr_data,
167                             int* attr_length) {
168  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifi))) {
169    return false;
170  }
171
172  mode_ = mode;
173  *attr_data = IFLA_RTA(NLMSG_DATA(&hdr->hdr));
174  *attr_length = IFLA_PAYLOAD(&hdr->hdr);
175
176  type_ = kTypeLink;
177  family_ = hdr->ifi.ifi_family;
178  interface_index_ = hdr->ifi.ifi_index;
179  set_link_status(LinkStatus(hdr->ifi.ifi_type,
180                             hdr->ifi.ifi_flags,
181                             hdr->ifi.ifi_change));
182  return true;
183}
184
185bool RTNLMessage::DecodeAddress(const RTNLHeader* hdr,
186                                Mode mode,
187                                rtattr** attr_data,
188                                int* attr_length) {
189  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifa))) {
190    return false;
191  }
192  mode_ = mode;
193  *attr_data = IFA_RTA(NLMSG_DATA(&hdr->hdr));
194  *attr_length = IFA_PAYLOAD(&hdr->hdr);
195
196  type_ = kTypeAddress;
197  family_ = hdr->ifa.ifa_family;
198  interface_index_ = hdr->ifa.ifa_index;
199  set_address_status(AddressStatus(hdr->ifa.ifa_prefixlen,
200                                   hdr->ifa.ifa_flags,
201                                   hdr->ifa.ifa_scope));
202  return true;
203}
204
205bool RTNLMessage::DecodeRoute(const RTNLHeader* hdr,
206                              Mode mode,
207                              rtattr** attr_data,
208                              int* attr_length) {
209  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->rtm))) {
210    return false;
211  }
212  mode_ = mode;
213  *attr_data = RTM_RTA(NLMSG_DATA(&hdr->hdr));
214  *attr_length = RTM_PAYLOAD(&hdr->hdr);
215
216  type_ = kTypeRoute;
217  family_ = hdr->rtm.rtm_family;
218  set_route_status(RouteStatus(hdr->rtm.rtm_dst_len,
219                               hdr->rtm.rtm_src_len,
220                               hdr->rtm.rtm_table,
221                               hdr->rtm.rtm_protocol,
222                               hdr->rtm.rtm_scope,
223                               hdr->rtm.rtm_type,
224                               hdr->rtm.rtm_flags));
225  return true;
226}
227
228bool RTNLMessage::DecodeNdUserOption(const RTNLHeader* hdr,
229                                     Mode mode,
230                                     rtattr** attr_data,
231                                     int* attr_length) {
232  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->nd_user_opt))) {
233    return false;
234  }
235
236  mode_ = mode;
237  interface_index_ = hdr->nd_user_opt.nduseropt_ifindex;
238  family_ = hdr->nd_user_opt.nduseropt_family;
239
240  // Verify IP family.
241  if (family_ != IPAddress::kFamilyIPv6) {
242    return false;
243  }
244  // Verify message must at-least contain the option header.
245  if (hdr->nd_user_opt.nduseropt_opts_len < sizeof(NDUserOptionHeader)) {
246    return false;
247  }
248
249  // Parse the option header.
250  const NDUserOptionHeader* nd_user_option_header =
251      reinterpret_cast<const NDUserOptionHeader*>(
252          reinterpret_cast<const uint8_t*>(&hdr->nd_user_opt) +
253          sizeof(struct nduseroptmsg));
254  uint32_t lifetime = ntohl(nd_user_option_header->lifetime);
255
256  // Verify option length.
257  // The length field in the header is in units of 8 octets.
258  int opt_len = static_cast<int>(nd_user_option_header->length) * 8;
259  if (opt_len != hdr->nd_user_opt.nduseropt_opts_len) {
260    return false;
261  }
262
263  // Determine option data pointer and data length.
264  const uint8_t* option_data =
265      reinterpret_cast<const uint8_t*>(nd_user_option_header + 1);
266  int data_len = opt_len - sizeof(NDUserOptionHeader);
267
268  if (nd_user_option_header->type == ND_OPT_DNSSL) {
269    // TODO(zqiu): Parse DNSSL (DNS Search List) option.
270    type_ = kTypeDnssl;
271    return true;
272  } else if (nd_user_option_header->type == ND_OPT_RDNSS) {
273    // Parse RNDSS (Recursive DNS Server) option.
274    type_ = kTypeRdnss;
275    return ParseRdnssOption(option_data, data_len, lifetime);
276  }
277
278  return false;
279}
280
281bool RTNLMessage::ParseRdnssOption(const uint8_t* data,
282                                   int length,
283                                   uint32_t lifetime) {
284  const int addr_length = IPAddress::GetAddressLength(IPAddress::kFamilyIPv6);
285
286  // Verify data size are multiple of individual address size.
287  if (length % addr_length != 0) {
288    return false;
289  }
290
291  // Parse the DNS server addresses.
292  std::vector<IPAddress> dns_server_addresses;
293  while (length > 0) {
294    dns_server_addresses.push_back(
295        IPAddress(IPAddress::kFamilyIPv6,
296                  ByteString(data, addr_length)));
297    length -= addr_length;
298    data += addr_length;
299  }
300  set_rdnss_option(RdnssOption(lifetime, dns_server_addresses));
301  return true;
302}
303
304bool RTNLMessage::DecodeNeighbor(const RTNLHeader* hdr,
305                                 Mode mode,
306                                 rtattr** attr_data,
307                                 int* attr_length) {
308  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ndm))) {
309    return false;
310  }
311
312  mode_ = mode;
313  interface_index_ = hdr->ndm.ndm_ifindex;
314  family_ = hdr->ndm.ndm_family;
315  type_ = kTypeNeighbor;
316
317  *attr_data = RTM_RTA(NLMSG_DATA(&hdr->hdr));
318  *attr_length = RTM_PAYLOAD(&hdr->hdr);
319
320  set_neighbor_status(NeighborStatus(hdr->ndm.ndm_state,
321                                     hdr->ndm.ndm_flags,
322                                     hdr->ndm.ndm_type));
323  return true;
324}
325
326ByteString RTNLMessage::Encode() const {
327  if (type_ != kTypeLink &&
328      type_ != kTypeAddress &&
329      type_ != kTypeRoute &&
330      type_ != kTypeNeighbor) {
331    return ByteString();
332  }
333
334  RTNLHeader hdr;
335  hdr.hdr.nlmsg_flags = flags_;
336  hdr.hdr.nlmsg_seq = seq_;
337  hdr.hdr.nlmsg_pid = pid_;
338
339  if (mode_ == kModeGet) {
340    if (type_ == kTypeLink) {
341      hdr.hdr.nlmsg_type = RTM_GETLINK;
342    } else if (type_ == kTypeAddress) {
343      hdr.hdr.nlmsg_type = RTM_GETADDR;
344    } else if (type_ == kTypeRoute) {
345      hdr.hdr.nlmsg_type = RTM_GETROUTE;
346    } else if (type_ == kTypeNeighbor) {
347      hdr.hdr.nlmsg_type = RTM_GETNEIGH;
348    } else {
349      NOTIMPLEMENTED();
350      return ByteString();
351    }
352    hdr.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr.gen));
353    hdr.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
354    hdr.gen.rtgen_family = family_;
355  } else {
356    switch (type_) {
357    case kTypeLink:
358      if (!EncodeLink(&hdr)) {
359        return ByteString();
360      }
361      break;
362
363    case kTypeAddress:
364      if (!EncodeAddress(&hdr)) {
365        return ByteString();
366      }
367      break;
368
369    case kTypeRoute:
370      if (!EncodeRoute(&hdr)) {
371        return ByteString();
372      }
373      break;
374
375    case kTypeNeighbor:
376      if (!EncodeNeighbor(&hdr)) {
377        return ByteString();
378      }
379      break;
380
381    default:
382      NOTREACHED();
383    }
384  }
385
386  size_t header_length = hdr.hdr.nlmsg_len;
387  ByteString attributes;
388
389  for (auto attr = attributes_.begin(); attr != attributes_.end(); ++attr) {
390    size_t len = RTA_LENGTH(attr->second.GetLength());
391    hdr.hdr.nlmsg_len = NLMSG_ALIGN(hdr.hdr.nlmsg_len) + RTA_ALIGN(len);
392
393    struct rtattr rt_attr = {
394      static_cast<unsigned short>(len),  // NOLINT(runtime/int)
395      attr->first
396    };
397    ByteString attr_header(reinterpret_cast<unsigned char*>(&rt_attr),
398                           sizeof(rt_attr));
399    attr_header.Resize(RTA_ALIGN(attr_header.GetLength()));
400    attributes.Append(attr_header);
401
402    ByteString attr_data(attr->second);
403    attr_data.Resize(RTA_ALIGN(attr_data.GetLength()));
404    attributes.Append(attr_data);
405  }
406
407  ByteString packet(reinterpret_cast<unsigned char*>(&hdr), header_length);
408  packet.Append(attributes);
409
410  return packet;
411}
412
413bool RTNLMessage::EncodeLink(RTNLHeader* hdr) const {
414  switch (mode_) {
415    case kModeAdd:
416      hdr->hdr.nlmsg_type = RTM_NEWLINK;
417      break;
418    case kModeDelete:
419      hdr->hdr.nlmsg_type = RTM_DELLINK;
420      break;
421    case kModeQuery:
422      hdr->hdr.nlmsg_type = RTM_GETLINK;
423      break;
424    default:
425      NOTIMPLEMENTED();
426      return false;
427  }
428  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifi));
429  hdr->ifi.ifi_family = family_;
430  hdr->ifi.ifi_index = interface_index_;
431  hdr->ifi.ifi_type = link_status_.type;
432  hdr->ifi.ifi_flags = link_status_.flags;
433  hdr->ifi.ifi_change = link_status_.change;
434  return true;
435}
436
437bool RTNLMessage::EncodeAddress(RTNLHeader* hdr) const {
438  switch (mode_) {
439    case kModeAdd:
440      hdr->hdr.nlmsg_type = RTM_NEWADDR;
441      break;
442    case kModeDelete:
443      hdr->hdr.nlmsg_type = RTM_DELADDR;
444      break;
445    case kModeQuery:
446      hdr->hdr.nlmsg_type = RTM_GETADDR;
447      break;
448    default:
449      NOTIMPLEMENTED();
450      return false;
451  }
452  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifa));
453  hdr->ifa.ifa_family = family_;
454  hdr->ifa.ifa_prefixlen = address_status_.prefix_len;
455  hdr->ifa.ifa_flags = address_status_.flags;
456  hdr->ifa.ifa_scope = address_status_.scope;
457  hdr->ifa.ifa_index = interface_index_;
458  return true;
459}
460
461bool RTNLMessage::EncodeRoute(RTNLHeader* hdr) const {
462  switch (mode_) {
463    case kModeAdd:
464      hdr->hdr.nlmsg_type = RTM_NEWROUTE;
465      break;
466    case kModeDelete:
467      hdr->hdr.nlmsg_type = RTM_DELROUTE;
468      break;
469    case kModeQuery:
470      hdr->hdr.nlmsg_type = RTM_GETROUTE;
471      break;
472    default:
473      NOTIMPLEMENTED();
474      return false;
475  }
476  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->rtm));
477  hdr->rtm.rtm_family = family_;
478  hdr->rtm.rtm_dst_len = route_status_.dst_prefix;
479  hdr->rtm.rtm_src_len = route_status_.src_prefix;
480  hdr->rtm.rtm_table = route_status_.table;
481  hdr->rtm.rtm_protocol = route_status_.protocol;
482  hdr->rtm.rtm_scope = route_status_.scope;
483  hdr->rtm.rtm_type = route_status_.type;
484  hdr->rtm.rtm_flags = route_status_.flags;
485  return true;
486}
487
488bool RTNLMessage::EncodeNeighbor(RTNLHeader* hdr) const {
489  switch (mode_) {
490    case kModeAdd:
491      hdr->hdr.nlmsg_type = RTM_NEWNEIGH;
492      break;
493    case kModeDelete:
494      hdr->hdr.nlmsg_type = RTM_DELNEIGH;
495      break;
496    case kModeQuery:
497      hdr->hdr.nlmsg_type = RTM_GETNEIGH;
498      break;
499    default:
500      NOTIMPLEMENTED();
501      return false;
502  }
503  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ndm));
504  hdr->ndm.ndm_family = family_;
505  hdr->ndm.ndm_ifindex = interface_index_;
506  hdr->ndm.ndm_state = neighbor_status_.state;
507  hdr->ndm.ndm_flags = neighbor_status_.flags;
508  hdr->ndm.ndm_type = neighbor_status_.type;
509  return true;
510}
511
512void RTNLMessage::Reset() {
513  mode_ = kModeUnknown;
514  type_ = kTypeUnknown;
515  flags_ = 0;
516  seq_ = 0;
517  pid_ = 0;
518  interface_index_ = 0;
519  family_ = IPAddress::kFamilyUnknown;
520  link_status_ = LinkStatus();
521  address_status_ = AddressStatus();
522  route_status_ = RouteStatus();
523  attributes_.clear();
524}
525
526}  // namespace shill
527