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