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