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