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