// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- // Copyright (c) 2001-2007 International Computer Science Institute // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software") // to deal in the Software without restriction, subject to the conditions // listed in the XORP LICENSE file. These conditions include: you must // preserve this copyright notice, and you cannot mention the copyright // holders in advertising related to the Software without their permission. // The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This // notice is a summary of the XORP LICENSE file; the license in that file is // legally binding. #ident "$XORP: xorp/libxorp/ipvx.cc,v 1.28 2007/02/16 22:46:20 pavlin Exp $" #include "xorp.h" #include "ipvx.hh" #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif // // Static class members // // Construct an IN_ADDR_ANY address of @family. IPvX::IPvX(int family) throw (InvalidFamily) { if ((family != AF_INET) && (family != AF_INET6)) xorp_throw(InvalidFamily, family); _af = family; memset(_addr, 0, sizeof(_addr)); } // Construct an IPvX address by copying the raw address from @from_uint8 // memory. IPvX::IPvX(int family, const uint8_t *from_uint8) throw (InvalidFamily) { assert(from_uint8 != NULL); _af = family; memset(_addr, 0, sizeof(_addr)); memcpy(_addr, from_uint8, addr_bytelen()); } IPvX::IPvX(const IPv4& ipv4) { static_assert(sizeof(_addr) >= sizeof(IPv4)); static_assert(sizeof(IPv4) == 4); _af = AF_INET; memset(_addr, 0, sizeof(_addr)); memcpy(_addr, &ipv4, 4); } IPvX::IPvX(const IPv6& ipv6) { static_assert(sizeof(_addr) >= sizeof(IPv6)); static_assert(sizeof(IPv6) == 16); _af = AF_INET6; memcpy(_addr, &ipv6, 16); } IPvX::IPvX(const in_addr& from_in_addr) { copy_in(AF_INET, reinterpret_cast(&from_in_addr)); } IPvX::IPvX(const in6_addr& from_in6_addr) { copy_in(AF_INET6, reinterpret_cast(&from_in6_addr)); } IPvX::IPvX(const sockaddr& from_sockaddr) throw (InvalidFamily) { copy_in(from_sockaddr); } IPvX::IPvX(const sockaddr_in& from_sockaddr_in) throw (InvalidFamily) { copy_in(from_sockaddr_in); } IPvX::IPvX(const sockaddr_in6& from_sockaddr_in6) throw (InvalidFamily) { copy_in(from_sockaddr_in6); } IPvX::IPvX(char const *from_cstring) throw (InvalidString) { if (from_cstring == NULL) { xorp_throw(InvalidString, "Null value"); } else if (inet_pton(AF_INET, from_cstring, _addr) > 0) { _af = AF_INET; } else if (inet_pton(AF_INET6, from_cstring, _addr) > 0) { _af = AF_INET6; } else { xorp_throw(InvalidString, c_format("Bad IPvX \"%s\"", from_cstring)); } } // TODO: if this method is used very often, then reimplement it // by directly ~ of r._addr (see IPv6 implementation for details). IPvX IPvX::operator~() const { if (is_ipv4()) { return (~get_ipv4()); // XXX: implicitly create IPvX return object } else { return (~get_ipv6()); // XXX: implicitly create IPvX return object } } IPvX IPvX::operator|(const IPvX& other) const throw (InvalidCast) { if (is_ipv4()) { return get_ipv4() | other.get_ipv4(); } else { return get_ipv6() | other.get_ipv6(); } } IPvX IPvX::operator&(const IPvX& other) const throw (InvalidCast) { if (is_ipv4()) { return get_ipv4() & other.get_ipv4(); } else { return get_ipv6() & other.get_ipv6(); } } IPvX IPvX::operator^(const IPvX& other) const throw (InvalidCast) { if (is_ipv4()) { return get_ipv4() ^ other.get_ipv4(); } else { return get_ipv6() ^ other.get_ipv6(); } } IPvX IPvX::operator<<(uint32_t left_shift) const { if (is_ipv4()) { return get_ipv4() << left_shift; } else { return get_ipv6() << left_shift; } } IPvX IPvX::operator>>(uint32_t right_shift) const { if (is_ipv4()) { return get_ipv4() >> right_shift; } else { return get_ipv6() >> right_shift; } } bool IPvX::operator<(const IPvX& other) const { static_assert(sizeof(_addr) == 16); int i; for (i = 0; i < 3; i++) { // Loop ends intentionally at 3 not 4. if (_addr[i] != other._addr[i]) { break; } } return ntohl(_addr[i]) < ntohl(other._addr[i]); } bool IPvX::operator==(const IPvX& other) const { if (is_ipv4() && other.is_ipv4()) return (get_ipv4() == other.get_ipv4()); else if (is_ipv6() && other.is_ipv6()) return (get_ipv6() == other.get_ipv6()); else return false; } bool IPvX::operator!=(const IPvX& other) const { if (is_ipv4() && other.is_ipv4()) return (get_ipv4() != other.get_ipv4()); else if (is_ipv6() && other.is_ipv6()) return (get_ipv6() != other.get_ipv6()); else return true; } IPvX& IPvX::operator--() { if (is_ipv4()) { *this = --get_ipv4(); } else { *this = --get_ipv6(); } return (*this); } IPvX& IPvX::operator++() { if (is_ipv4()) { *this = ++get_ipv4(); } else { *this = ++get_ipv6(); } return (*this); } IPvX IPvX::make_prefix(int family, uint32_t mask_len) throw (InvalidFamily, InvalidNetmaskLength) { if (family == AF_INET) return IPv4::make_prefix(mask_len); else if (family == AF_INET6) return IPv6::make_prefix(mask_len); else xorp_throw(InvalidFamily, family); return IPvX(0); /* Not Reached */ } IPvX IPvX::mask_by_prefix_len(uint32_t prefix_len) const throw (InvalidNetmaskLength) { if (_af == AF_INET) return get_ipv4().mask_by_prefix_len(prefix_len); else return get_ipv6().mask_by_prefix_len(prefix_len); } string IPvX::str() const { if (_af == AF_INET) return get_ipv4().str(); else return get_ipv6().str(); } uint32_t IPvX::mask_len() const { if (is_ipv4()) return get_ipv4().mask_len(); else return get_ipv6().mask_len(); } /** * Copy the raw address to memory pointed by @to. * @return the number of copied octets. */ size_t IPvX::copy_out(uint8_t *to_uint8) const { memcpy(to_uint8, _addr, addr_bytelen()); return (addr_bytelen()); } /** * Copy the raw address to @in_addr. * @return the number of copied octets. */ size_t IPvX::copy_out(struct in_addr& to_in_addr) const throw (InvalidFamily) { if (_af != AF_INET) xorp_throw(InvalidFamily, _af); return (copy_out((uint8_t *)&to_in_addr)); } /** * Copy the raw address to @in6_addr. * @return the number of copied octets. */ size_t IPvX::copy_out(struct in6_addr& to_in6_addr) const throw (InvalidFamily) { if (_af != AF_INET6) xorp_throw(InvalidFamily, _af); return (copy_out((uint8_t *)&to_in6_addr)); } /** * Copy the raw address to @to_sockaddr, and assign appropriately * the rest of the fields in @to_sockaddr. * @return the number of copied octets. */ size_t IPvX::copy_out(struct sockaddr& to_sockaddr) const throw (InvalidFamily) { return (copy_out(reinterpret_cast(to_sockaddr))); } /** * Copy the raw address to @to_sockaddr_in, and assign appropriately * the rest of the fields in @to_sockaddr_in. * @return the number of copied octets. */ size_t IPvX::copy_out(struct sockaddr_in& to_sockaddr_in) const throw (InvalidFamily) { switch (_af) { case AF_INET: memset(&to_sockaddr_in, 0, sizeof(to_sockaddr_in)); #ifdef HAVE_SIN_LEN to_sockaddr_in.sin_len = sizeof(to_sockaddr_in); #endif to_sockaddr_in.sin_family = _af; to_sockaddr_in.sin_port = 0; // XXX: not used return (copy_out(to_sockaddr_in.sin_addr)); case AF_INET6: return (copy_out(reinterpret_cast(to_sockaddr_in))); default: xorp_throw(InvalidFamily, _af); } return((size_t)-1); } /** * Copy the raw address to @to_sockaddr_in6, and assign appropriately * the rest of the fields in @to_sockaddr_in6. * @return the number of copied octets. */ size_t IPvX::copy_out(struct sockaddr_in6& to_sockaddr_in6) const throw (InvalidFamily) { switch (_af) { case AF_INET: return (copy_out(reinterpret_cast(to_sockaddr_in6))); case AF_INET6: memset(&to_sockaddr_in6, 0, sizeof(to_sockaddr_in6)); #ifdef HAVE_SIN6_LEN to_sockaddr_in6.sin6_len = sizeof(to_sockaddr_in6); #endif to_sockaddr_in6.sin6_family = _af; #ifdef HAVE_SIN6_SCOPE_ID #ifdef IPV6_STACK_KAME // // XXX: In case of KAME the local interface index (also the link-local // scope_id) is encoded in the third and fourth octet of an IPv6 // address (for link-local unicast/multicast addresses or // interface-local multicast addresses only). // if (is_linklocal_unicast() || is_linklocal_multicast() || is_interfacelocal_multicast()) { uint32_t addr0 = ntohl(_addr[0]); uint16_t zoneid = (addr0 & 0xffff); // XXX: 16 bits only to_sockaddr_in6.sin6_scope_id = zoneid; } #endif // IPV6_STACK_KAME #endif // HAVE_SIN6_SCOPE_ID return (copy_out(to_sockaddr_in6.sin6_addr)); default: xorp_throw(InvalidFamily, _af); } return((size_t)-1); } /** * Copy a raw address of family @family from the memory pointed by @from_uint8. * @return the number of copied octets. */ size_t IPvX::copy_in(int family, const uint8_t *from_uint8) throw (InvalidFamily) { _af = family; switch (_af) { case AF_INET: // FALLTHROUGH case AF_INET6: memcpy(_addr, from_uint8, addr_bytelen()); return (addr_bytelen()); default: xorp_throw(InvalidFamily, _af); } return ((size_t)-1); } /** * Copy a raw address of family %AF_INET from @from_in_addr. * @return the number of copied octets. */ size_t IPvX::copy_in(const in_addr& from_in_addr) { return (copy_in(AF_INET, reinterpret_cast(&from_in_addr))); } /** * Copy a raw address of family %AF_INET6 from @from_in6_addr. * @return the number of copied octets. */ size_t IPvX::copy_in(const in6_addr& from_in6_addr) { return (copy_in(AF_INET6, reinterpret_cast(&from_in6_addr))); } /** * Copy a raw address from @from_sockaddr. * @return the number of copied octets. */ size_t IPvX::copy_in(const sockaddr& from_sockaddr) throw (InvalidFamily) { return (copy_in(reinterpret_cast(from_sockaddr))); } /** * Copy a raw address from @from_sockaddr_in. * @return the number of copied octets. */ size_t IPvX::copy_in(const sockaddr_in& from_sockaddr_in) throw (InvalidFamily) { _af = from_sockaddr_in.sin_family; switch (_af) { case AF_INET: return (copy_in(from_sockaddr_in.sin_addr)); case AF_INET6: return (copy_in(reinterpret_cast(from_sockaddr_in))); default: xorp_throw(InvalidFamily, _af); } return((size_t)-1); } /** * Copy a raw address from @from_sockaddr_in6. * @return the number of copied octets. */ size_t IPvX::copy_in(const sockaddr_in6& from_sockaddr_in6) throw (InvalidFamily) { _af = from_sockaddr_in6.sin6_family; switch (_af) { case AF_INET: return (copy_in(reinterpret_cast(from_sockaddr_in6))); case AF_INET6: return (copy_in(from_sockaddr_in6.sin6_addr)); default: xorp_throw(InvalidFamily, _af); } return((size_t)-1); } bool IPvX::is_zero() const { if (_af == AF_INET) return get_ipv4().is_zero(); return get_ipv6().is_zero(); } bool IPvX::is_unicast() const { if (_af == AF_INET) return get_ipv4().is_unicast(); return get_ipv6().is_unicast(); } bool IPvX::is_multicast() const { if (_af == AF_INET) return get_ipv4().is_multicast(); return get_ipv6().is_multicast(); } bool IPvX::is_class_a() const { if (_af == AF_INET) return get_ipv4().is_class_a(); return (false); // XXX: this method applies only for IPv4 } bool IPvX::is_class_b() const { if (_af == AF_INET) return get_ipv4().is_class_b(); return (false); // XXX: this method applies only for IPv4 } bool IPvX::is_class_c() const { if (_af == AF_INET) return get_ipv4().is_class_c(); return (false); // XXX: this method applies only for IPv4 } bool IPvX::is_experimental() const { if (_af == AF_INET) return get_ipv4().is_experimental(); return (false); // XXX: this method applies only for IPv4 } bool IPvX::is_linklocal_unicast() const { if (_af == AF_INET) return get_ipv4().is_linklocal_unicast(); return get_ipv6().is_linklocal_unicast(); } bool IPvX::is_interfacelocal_multicast() const { if (_af == AF_INET) return get_ipv4().is_interfacelocal_multicast(); return get_ipv6().is_interfacelocal_multicast(); } bool IPvX::is_linklocal_multicast() const { if (_af == AF_INET) return get_ipv4().is_linklocal_multicast(); return get_ipv6().is_linklocal_multicast(); } bool IPvX::is_loopback() const { if (_af == AF_INET) return get_ipv4().is_loopback(); return get_ipv6().is_loopback(); } /** * @return IP protocol version. */ uint32_t IPvX::ip_version() const throw (InvalidFamily) { if (_af == AF_INET) return (IPv4::ip_version()); if (_af == AF_INET6) return (IPv6::ip_version()); xorp_throw(InvalidFamily, _af); return ((uint32_t)-1); } /** * @return IP protocol version string. */ const string& IPvX::ip_version_str() const throw (InvalidFamily) { if (_af == AF_INET) return (IPv4::ip_version_str()); if (_af != AF_INET6) xorp_throw(InvalidFamily, _af); return (IPv6::ip_version_str()); } size_t IPvX::addr_bytelen(int family) throw (InvalidFamily) { if (family == AF_INET) return (IPv4::addr_bytelen()); if (family == AF_INET6) return (IPv6::addr_bytelen()); xorp_throw(InvalidFamily, family); return ((size_t)-1); } uint32_t IPvX::ip_multicast_base_address_mask_len(int family) throw (InvalidFamily) { if (family == AF_INET) return (IPv4::ip_multicast_base_address_mask_len()); if (family == AF_INET6) return (IPv6::ip_multicast_base_address_mask_len()); xorp_throw(InvalidFamily, family); return ((uint32_t)-1); } uint32_t IPvX::ip_class_a_base_address_mask_len(int family) throw (InvalidFamily) { if (family == AF_INET) return (IPv4::ip_class_a_base_address_mask_len()); // XXX: this method applies only for IPv4 xorp_throw(InvalidFamily, family); return ((uint32_t)-1); } uint32_t IPvX::ip_class_b_base_address_mask_len(int family) throw (InvalidFamily) { if (family == AF_INET) return (IPv4::ip_class_b_base_address_mask_len()); // XXX: this method applies only for IPv4 xorp_throw(InvalidFamily, family); return ((uint32_t)-1); } uint32_t IPvX::ip_class_c_base_address_mask_len(int family) throw (InvalidFamily) { if (family == AF_INET) return (IPv4::ip_class_c_base_address_mask_len()); // XXX: this method applies only for IPv4 xorp_throw(InvalidFamily, family); return ((uint32_t)-1); } uint32_t IPvX::ip_experimental_base_address_mask_len(int family) throw (InvalidFamily) { if (family == AF_INET) return (IPv4::ip_experimental_base_address_mask_len()); // XXX: this method applies only for IPv4 xorp_throw(InvalidFamily, family); return ((uint32_t)-1); } // // IPvX "Constants" // #define IPVX_CONSTANT_ACCESSOR(name) \ const IPvX& IPvX::name(int family) throw (InvalidFamily) \ { \ static const IPvX c4_##name (IPv4::name()); /* IPv4 constant */ \ static const IPvX c6_##name (IPv6::name()); /* IPv6 constant */ \ if (family == AF_INET) \ return c4_##name; \ if (family == AF_INET6) \ return c6_##name; \ xorp_throw(InvalidFamily, family); \ } // IPvX "Constant" that applies only for IPv4 #define IPVX_CONSTANT_ACCESSOR_IPV4(name) \ const IPvX& IPvX::name(int family) throw (InvalidFamily) \ { \ static const IPvX c4_##name (IPv4::name()); /* IPv4 constant */ \ if (family == AF_INET) \ return c4_##name; \ xorp_throw(InvalidFamily, family); \ } // IPvX "Constant" that applies only for IPv6 #define IPVX_CONSTANT_ACCESSOR_IPV6(name) \ const IPvX& IPvX::name(int family) throw (InvalidFamily) \ { \ static const IPvX c6_##name (IPv6::name()); /* IPv6 constant */ \ if (family == AF_INET6) \ return c6_##name; \ xorp_throw(InvalidFamily, family); \ } IPVX_CONSTANT_ACCESSOR(ZERO); IPVX_CONSTANT_ACCESSOR(ANY); IPVX_CONSTANT_ACCESSOR(ALL_ONES); IPVX_CONSTANT_ACCESSOR(LOOPBACK); IPVX_CONSTANT_ACCESSOR(MULTICAST_BASE); IPVX_CONSTANT_ACCESSOR(MULTICAST_ALL_SYSTEMS); IPVX_CONSTANT_ACCESSOR(MULTICAST_ALL_ROUTERS); IPVX_CONSTANT_ACCESSOR(DVMRP_ROUTERS); IPVX_CONSTANT_ACCESSOR(OSPFIGP_ROUTERS); IPVX_CONSTANT_ACCESSOR(OSPFIGP_DESIGNATED_ROUTERS); IPVX_CONSTANT_ACCESSOR(RIP2_ROUTERS); IPVX_CONSTANT_ACCESSOR(PIM_ROUTERS); IPVX_CONSTANT_ACCESSOR(SSM_ROUTERS); IPVX_CONSTANT_ACCESSOR_IPV4(CLASS_A_BASE); IPVX_CONSTANT_ACCESSOR_IPV4(CLASS_B_BASE); IPVX_CONSTANT_ACCESSOR_IPV4(CLASS_C_BASE); IPVX_CONSTANT_ACCESSOR_IPV4(EXPERIMENTAL_BASE);