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