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