1 // Copyright (C) 2011-2021 Internet Systems Consortium, Inc. ("ISC") 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, v. 2.0. If a copy of the MPL was not distributed with this 5 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 7 #ifndef PKT4_H 8 #define PKT4_H 9 10 #include <asiolink/io_address.h> 11 #include <dhcp/duid.h> 12 #include <util/buffer.h> 13 #include <dhcp/option.h> 14 #include <dhcp/classify.h> 15 #include <dhcp/pkt.h> 16 17 #include <boost/shared_ptr.hpp> 18 19 #include <iostream> 20 #include <vector> 21 #include <set> 22 #include <list> 23 24 #include <time.h> 25 26 namespace isc { 27 28 namespace dhcp { 29 30 /// @brief Represents DHCPv4 packet 31 /// 32 /// This class represents a single DHCPv4 packet. It handles both incoming 33 /// and transmitted packets, parsing incoming options, options handling 34 /// (add, get, remove), on-wire assembly, sanity checks and other operations. 35 /// This specific class has several DHCPv4-specific methods, but it uses a lot 36 /// of common operations from its base @c Pkt class that is shared with Pkt6. 37 class Pkt4 : public Pkt { 38 public: 39 40 /// length of the CHADDR field in DHCPv4 message 41 const static size_t MAX_CHADDR_LEN = 16; 42 43 /// length of the SNAME field in DHCPv4 message 44 const static size_t MAX_SNAME_LEN = 64; 45 46 /// length of the FILE field in DHCPv4 message 47 const static size_t MAX_FILE_LEN = 128; 48 49 /// specifies DHCPv4 packet header length (fixed part) 50 const static size_t DHCPV4_PKT_HDR_LEN = 236; 51 52 /// Mask for the value of flags field in the DHCPv4 message 53 /// to check whether client requested broadcast response. 54 const static uint16_t FLAG_BROADCAST_MASK = 0x8000; 55 56 /// Constructor, used in replying to a message. 57 /// 58 /// @param msg_type type of message (e.g. DHCPDISOVER=1) 59 /// @param transid transaction-id 60 Pkt4(uint8_t msg_type, uint32_t transid); 61 62 /// @brief Constructor, used in message reception. 63 /// 64 /// Creates new message. Pkt4 will copy data to bufferIn_ 65 /// buffer on creation. 66 /// 67 /// @param data pointer to received data 68 /// @param len size of buffer to be allocated for this packet. 69 Pkt4(const uint8_t* data, size_t len); 70 71 /// @brief Prepares on-wire format of DHCPv4 packet. 72 /// 73 /// Prepares on-wire format of message and all its options. 74 /// Options must be stored in options_ field. 75 /// Output buffer will be stored in buffer_out_. 76 /// The buffer_out_ is cleared before writing to the buffer. 77 /// 78 /// @throw InvalidOperation if packing fails 79 virtual void pack(); 80 81 /// @brief Parses on-wire form of DHCPv4 packet. 82 /// 83 /// Parses received packet, stored in on-wire format in bufferIn_. 84 /// 85 /// Will create a collection of option objects that will 86 /// be stored in options_ container. 87 /// 88 /// Method with throw exception if packet parsing fails. 89 virtual void unpack(); 90 91 /// @brief Returns text representation of the primary packet identifiers 92 /// 93 /// This method is intended to be used to provide a consistent way to 94 /// identify packets within log statements. It is an instance-level 95 /// wrapper around static makeLabel(). See this method for string 96 /// content. 97 /// 98 /// This method is exception safe. 99 /// 100 /// @return string with text representation 101 std::string getLabel() const; 102 103 /// @brief Returns text representation of the given packet identifiers 104 /// 105 /// @param hwaddr - hardware address to include in the string, it may be 106 /// NULL. 107 /// @param client_id - client id to include in the string, it may be NULL. 108 /// to include in the string 109 /// @param transid - numeric transaction id to include in the string 110 /// 111 /// @return string with text representation 112 static std::string makeLabel(const HWAddrPtr& hwaddr, 113 const ClientIdPtr& client_id, 114 const uint32_t transid); 115 116 /// @brief Returns text representation of the given packet identifiers. 117 /// 118 /// This variant of the method does not include transaction id. 119 /// 120 /// @param hwaddr hardware address to include in the string, it may be 121 /// NULL. 122 /// @param client_id client id to include in the string, it may be NULL. 123 static std::string makeLabel(const HWAddrPtr& hwaddr, const ClientIdPtr& client_id); 124 125 /// @brief Returns text representation of the packet. 126 /// 127 /// This function is useful mainly for debugging. 128 /// 129 /// @return string with text representation 130 std::string toText() const; 131 132 /// @brief Returns the size of the required buffer to build the packet. 133 /// 134 /// Returns the size of the required buffer to build the packet with 135 /// the current set of packet options. 136 /// 137 /// @return number of bytes required to build this packet 138 size_t len(); 139 140 /// @brief Sets hops field. 141 /// 142 /// @param hops value to be set setHops(uint8_t hops)143 void setHops(uint8_t hops) { hops_ = hops; }; 144 145 /// @brief Returns hops field. 146 /// 147 /// @return hops field getHops()148 uint8_t getHops() const { return (hops_); }; 149 150 // Note: There's no need to manipulate OP field directly, 151 // thus no setOp() method. See op_ comment. 152 153 /// @brief Returns op field. 154 /// 155 /// @return op field getOp()156 uint8_t getOp() const { return (op_); }; 157 158 /// @brief Sets secs field. 159 /// 160 /// @param secs value to be set setSecs(uint16_t secs)161 void setSecs(uint16_t secs) { secs_ = secs; }; 162 163 /// @brief Returns secs field. 164 /// 165 /// @return secs field getSecs()166 uint16_t getSecs() const { return (secs_); }; 167 168 /// @brief Sets flags field. 169 /// 170 /// @param flags value to be set setFlags(uint16_t flags)171 void setFlags(uint16_t flags) { flags_ = flags; }; 172 173 /// @brief Returns flags field. 174 /// 175 /// @return flags field getFlags()176 uint16_t getFlags() const { return (flags_); }; 177 178 /// @brief Returns ciaddr field. 179 /// 180 /// @return ciaddr field 181 const isc::asiolink::IOAddress& getCiaddr()182 getCiaddr() const { return (ciaddr_); }; 183 184 /// @brief Sets ciaddr field. 185 /// 186 /// @param ciaddr value to be set 187 void setCiaddr(const isc::asiolink::IOAddress & ciaddr)188 setCiaddr(const isc::asiolink::IOAddress& ciaddr) { ciaddr_ = ciaddr; }; 189 190 /// @brief Returns siaddr field. 191 /// 192 /// @return siaddr field 193 const isc::asiolink::IOAddress& getSiaddr()194 getSiaddr() const { return (siaddr_); }; 195 196 /// @brief Sets siaddr field. 197 /// 198 /// @param siaddr value to be set 199 void setSiaddr(const isc::asiolink::IOAddress & siaddr)200 setSiaddr(const isc::asiolink::IOAddress& siaddr) { siaddr_ = siaddr; }; 201 202 /// @brief Returns yiaddr field. 203 /// 204 /// @return yiaddr field 205 const isc::asiolink::IOAddress& getYiaddr()206 getYiaddr() const { return (yiaddr_); }; 207 208 /// @brief Sets yiaddr field. 209 /// 210 /// @param yiaddr value to be set 211 void setYiaddr(const isc::asiolink::IOAddress & yiaddr)212 setYiaddr(const isc::asiolink::IOAddress& yiaddr) { yiaddr_ = yiaddr; }; 213 214 /// @brief Returns giaddr field. 215 /// 216 /// @return giaddr field 217 const isc::asiolink::IOAddress& getGiaddr()218 getGiaddr() const { return (giaddr_); }; 219 220 /// @brief Sets giaddr field. 221 /// 222 /// @param giaddr value to be set 223 void setGiaddr(const isc::asiolink::IOAddress & giaddr)224 setGiaddr(const isc::asiolink::IOAddress& giaddr) { giaddr_ = giaddr; }; 225 226 /// @brief Returns DHCP message type (e.g. 1 = DHCPDISCOVER). 227 /// 228 /// This method is exception safe. For packets without DHCP Message Type 229 /// option, it returns DHCP_NOTYPE (0). 230 /// 231 /// @return message type 232 uint8_t getType() const; 233 234 /// @brief Sets DHCP message type (e.g. 1 = DHCPDISCOVER). 235 /// 236 /// @param type message type to be set 237 void setType(uint8_t type); 238 239 /// @brief Returns name of the DHCP message for a given type number. 240 /// 241 /// This method is exception safe. For messages without DHCP Message Type 242 /// options, it returns UNKNOWN. 243 /// 244 /// @param type DHCPv4 message type which name should be returned. 245 /// 246 /// @return Pointer to the "const" string containing DHCP message name. 247 /// If the message type is unsupported the "UNKNOWN" is returned. 248 /// The caller must not release the returned pointer. 249 static const char* getName(const uint8_t type); 250 251 /// @brief Returns name of the DHCP message. 252 /// 253 /// @return Pointer to the "const" string containing DHCP message name. 254 /// If the message type is unsupported the "UNKNOWN" is returned. 255 /// The caller must not release the returned pointer. 256 const char* getName() const; 257 258 /// @brief Returns sname field 259 /// 260 /// Note: This is 64 bytes long field. It doesn't have to be 261 /// null-terminated. Do not use strlen() or similar on it. 262 /// 263 /// @return sname field 264 const OptionBuffer getSname()265 getSname() const { return (std::vector<uint8_t>(sname_, &sname_[MAX_SNAME_LEN])); }; 266 267 /// @brief Sets sname field. 268 /// 269 /// @param sname value to be set 270 /// @param sname_len length of the sname buffer (up to MAX_SNAME_LEN) 271 void setSname(const uint8_t* sname, size_t sname_len); 272 273 /// @brief Returns file field 274 /// 275 /// Note: This is 128 bytes long field. It doesn't have to be 276 /// null-terminated. Do not use strlen() or similar on it. 277 /// 278 /// @return pointer to file field 279 const OptionBuffer getFile()280 getFile() const { return (std::vector<uint8_t>(file_, &file_[MAX_FILE_LEN])); }; 281 282 /// Sets file field 283 /// 284 /// @param file value to be set 285 /// @param file_len length of the file buffer (up to MAX_FILE_LEN) 286 void 287 setFile(const uint8_t* file, size_t file_len); 288 289 /// @brief Sets hardware address. 290 /// 291 /// Sets parameters of hardware address. hlen specifies 292 /// length of mac_addr buffer. Content of mac_addr buffer 293 /// will be copied to appropriate field. 294 /// 295 /// Note: mac_addr must be a buffer of at least hlen bytes. 296 /// 297 /// @param htype hardware type (will be sent in htype field) 298 /// @param hlen hardware length (will be sent in hlen field) 299 /// @param mac_addr pointer to hardware address 300 void setHWAddr(uint8_t htype, uint8_t hlen, 301 const std::vector<uint8_t>& mac_addr); 302 303 /// @brief Sets hardware address 304 /// 305 /// Sets hardware address, based on existing HWAddr structure 306 /// @param addr already filled in HWAddr structure 307 /// @throw BadValue if addr is null 308 void setHWAddr(const HWAddrPtr& addr); 309 310 /// Returns htype field 311 /// 312 /// @return hardware type 313 uint8_t 314 getHtype() const; 315 316 /// Returns hlen field 317 /// 318 /// @return hardware address length 319 uint8_t 320 getHlen() const; 321 322 /// @brief returns hardware address information 323 /// @return hardware address structure getHWAddr()324 HWAddrPtr getHWAddr() const { return (hwaddr_); } 325 326 /// @brief Add an option. 327 /// 328 /// @throw BadValue if option with that type is already present. 329 /// 330 /// @param opt option to be added 331 virtual void 332 addOption(const OptionPtr& opt); 333 334 /// @brief Sets local HW address. 335 /// 336 /// Sets the source HW address for the outgoing packet or 337 /// destination HW address for the incoming packet. 338 /// 339 /// @note mac_addr must be a buffer of at least hlen bytes. 340 /// 341 /// @param htype hardware type (will be sent in htype field) 342 /// @param hlen hardware length (will be sent in hlen field) 343 /// @param mac_addr pointer to hardware address 344 void setLocalHWAddr(const uint8_t htype, const uint8_t hlen, 345 const std::vector<uint8_t>& mac_addr); 346 347 /// @brief Sets local HW address. 348 /// 349 /// Sets hardware address from an existing HWAddr structure. 350 /// The local address is a source address for outgoing 351 /// packet and destination address for incoming packet. 352 /// 353 /// @param addr structure representing HW address. 354 /// 355 /// @throw BadValue if addr is null 356 void setLocalHWAddr(const HWAddrPtr& addr); 357 358 /// @brief Returns local HW address. 359 /// 360 /// @return local HW addr. getLocalHWAddr()361 HWAddrPtr getLocalHWAddr() const { 362 return (local_hwaddr_); 363 } 364 365 /// @brief Returns a reference to option codes which unpacking 366 /// will be deferred. 367 /// 368 /// Only options 43 and 224-254 are subject of deferred 369 /// unpacking: when the packet unpacking is performed, each time 370 /// such an option is found, it is unpacked as an unknown option 371 /// and the code added in this list. 372 /// 373 /// @return List of codes of options which unpacking is deferred. getDeferredOptions()374 std::list<uint16_t>& getDeferredOptions() { 375 return (deferred_options_); 376 } 377 378 /// @brief Checks if a DHCPv4 message has been relayed. 379 /// 380 /// This function returns a boolean value which indicates whether a DHCPv4 381 /// message has been relayed (if true is returned) or not (if false). 382 /// 383 /// The message is considered relayed if the giaddr field is non-zero and 384 /// non-broadcast. 385 /// 386 /// @return Boolean value which indicates whether the message is relayed 387 /// (true) or non-relayed (false). 388 bool isRelayed() const; 389 390 /// @brief Checks if a DHCPv4 message has been transported over DHCPv6 391 /// 392 /// @return Boolean value which indicates whether the message is 393 /// transported over DHCPv6 (true) or native DHCPv4 (false) isDhcp4o6()394 virtual bool isDhcp4o6() const { 395 return (false); 396 } 397 398 private: 399 400 /// @brief Generic method that validates and sets HW address. 401 /// 402 /// This is a generic method used by all modifiers of this class 403 /// which set class members representing HW address. 404 /// 405 /// @param htype hardware type. 406 /// @param hlen hardware length. 407 /// @param mac_addr pointer to actual hardware address. 408 /// @param [out] hw_addr pointer to a class member to be modified. 409 /// 410 /// @trow isc::OutOfRange if invalid HW address specified. 411 virtual void setHWAddrMember(const uint8_t htype, const uint8_t hlen, 412 const std::vector<uint8_t>& mac_addr, 413 HWAddrPtr& hw_addr); 414 415 protected: 416 417 /// converts DHCP message type to BOOTP op type 418 /// 419 /// @param dhcpType DHCP message type (e.g. DHCPDISCOVER) 420 /// 421 /// @return BOOTP type (BOOTREQUEST or BOOTREPLY) 422 uint8_t 423 DHCPTypeToBootpType(uint8_t dhcpType); 424 425 /// @brief No-op 426 /// 427 /// This method returns hardware address generated from the IPv6 link-local 428 /// address. As there is no IPv4-equivalent, it always returns NULL. 429 /// We need this stub implementation here, to keep all the get hardware 430 /// address logic in the base class. 431 /// 432 /// @return always NULL getMACFromSrcLinkLocalAddr()433 virtual HWAddrPtr getMACFromSrcLinkLocalAddr() { 434 return (HWAddrPtr()); 435 } 436 437 /// @brief No-op 438 /// 439 /// This method returns hardware address extracted from an IPv6 relay agent. 440 /// option. As there is no IPv4-equivalent, it always returns NULL. 441 /// We need this stub implementation here, to keep all the get hardware 442 /// address logic in the base class. 443 /// 444 /// @return always NULL getMACFromIPv6RelayOpt()445 virtual HWAddrPtr getMACFromIPv6RelayOpt() { 446 return (HWAddrPtr()); 447 } 448 449 /// @brief No-op 450 /// 451 /// This is a DHCPv4 version of the function that attempts to extract 452 /// MAC address from the options inserted by a cable modem. It is currently 453 /// not implemented for v4. 454 /// 455 /// @return always NULL getMACFromDocsisModem()456 virtual HWAddrPtr getMACFromDocsisModem() { 457 return (HWAddrPtr()); 458 } 459 460 /// @brief No-op 461 /// 462 /// This method returns hardware address extracted from DUID. 463 /// Currently it is a no-op, even though there's RFC that defines how to 464 /// use DUID in DHCPv4 (see RFC4361). We may implement it one day. 465 /// 466 /// @return always NULL getMACFromDUID()467 virtual HWAddrPtr getMACFromDUID(){ 468 return (HWAddrPtr()); 469 } 470 471 /// @brief No-op 472 /// 473 /// This is a DHCPv4 version of the function that attempts to extract 474 /// MAC address from the options inserted by a CMTS. It is currently 475 /// not implemented for v4. 476 /// 477 /// @return always NULL getMACFromDocsisCMTS()478 virtual HWAddrPtr getMACFromDocsisCMTS() { 479 return (HWAddrPtr()); 480 } 481 482 /// @brief No-op 483 /// 484 /// This method returns hardware address extracted from remote-id relay option. 485 /// Currently it is a no-op, it always returns NULL. 486 /// 487 /// @return always NULL getMACFromRemoteIdRelayOption()488 virtual HWAddrPtr getMACFromRemoteIdRelayOption(){ 489 return(HWAddrPtr()); 490 } 491 492 /// @brief local HW address (dst if receiving packet, src if sending packet) 493 HWAddrPtr local_hwaddr_; 494 495 // @brief List of deferred option codes 496 std::list<uint16_t> deferred_options_; 497 498 /// @brief message operation code 499 /// 500 /// Note: This is legacy BOOTP field. There's no need to manipulate it 501 /// directly. Its value is set based on DHCP message type. Note that 502 /// DHCPv4 protocol reuses BOOTP message format, so this field is 503 /// kept due to BOOTP format. This is NOT DHCPv4 type (DHCPv4 message 504 /// type is kept in message type option). 505 uint8_t op_; 506 507 /// @brief link-layer address and hardware information 508 /// represents 3 fields: htype (hardware type, 1 byte), hlen (length of the 509 /// hardware address, up to 16) and chaddr (hardware address field, 510 /// 16 bytes) 511 HWAddrPtr hwaddr_; 512 513 /// Number of relay agents traversed 514 uint8_t hops_; 515 516 /// elapsed (number of seconds since beginning of transmission) 517 uint16_t secs_; 518 519 /// flags 520 uint16_t flags_; 521 522 /// ciaddr field (32 bits): Client's IP address 523 isc::asiolink::IOAddress ciaddr_; 524 525 /// yiaddr field (32 bits): Client's IP address ("your"), set by server 526 isc::asiolink::IOAddress yiaddr_; 527 528 /// siaddr field (32 bits): next server IP address in boot process(e.g.TFTP) 529 isc::asiolink::IOAddress siaddr_; 530 531 /// giaddr field (32 bits): Gateway IP address 532 isc::asiolink::IOAddress giaddr_; 533 534 /// sname field (64 bytes) 535 uint8_t sname_[MAX_SNAME_LEN]; 536 537 /// file field (128 bytes) 538 uint8_t file_[MAX_FILE_LEN]; 539 540 // end of real DHCPv4 fields 541 }; // Pkt4 class 542 543 /// @brief A pointer to Pkt4 object. 544 typedef boost::shared_ptr<Pkt4> Pkt4Ptr; 545 546 } // isc::dhcp namespace 547 548 } // isc namespace 549 550 #endif 551